This commit was manufactured by cvs2svn to create branch 'XEmacs-21_4'.
[chise/xemacs-chise.git.1] / src / event-msw.c
index 0dee130..681743e 100644 (file)
@@ -1,7 +1,7 @@
 /* The  mswindows event_stream interface.
    Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 1996 Ben Wing.
+   Copyright (C) 1996, 2000 Ben Wing.
    Copyright (C) 1997 Jonathan Harris.
 
 This file is part of XEmacs.
@@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 #ifdef HAVE_MENUBARS
+# include "menubar.h"
 # include "menubar-msw.h"
 #endif
 
@@ -56,6 +57,7 @@ Boston, MA 02111-1307, USA.  */
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
+#include "select.h"
 #include "sysproc.h"
 #include "syswait.h"
 #include "systime.h"
@@ -72,7 +74,11 @@ typedef unsigned int SOCKET;
 #include <io.h>
 #include <errno.h>
 
-#if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR)
+#if !(defined(__CYGWIN32__) || defined(__MINGW32__))
+# include <shlobj.h>   /* For IShellLink */
+#endif
+
+#if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20)
 typedef NMHDR *LPNMHDR;
 #endif
 
@@ -89,13 +95,6 @@ typedef NMHDR *LPNMHDR;
 /* Timer ID used for button2 emulation */
 #define BUTTON_2_TIMER_ID 1
 
-extern Lisp_Object 
-mswindows_get_toolbar_button_text (struct frame* f, int command_id);
-extern Lisp_Object
-mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
-extern Lisp_Object
-mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
-
 static Lisp_Object mswindows_find_frame (HWND hwnd);
 static Lisp_Object mswindows_find_console (HWND hwnd);
 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
@@ -134,6 +133,7 @@ static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
 /* Number of wait handles */
 static int mswindows_waitable_count=0;
 #endif /* HAVE_MSG_SELECT */
+
 /* Brush for painting widgets */
 static HBRUSH widget_brush = 0;
 static LONG    last_widget_brushed = 0;
@@ -145,7 +145,7 @@ int mswindows_quit_chars_count = 0;
 
 /* These are Lisp integers; see DEFVARS in this file for description. */
 int mswindows_dynamic_frame_resize;
-int mswindows_meta_activates_menu;
+int mswindows_alt_by_itself_activates_menu;
 int mswindows_num_mouse_buttons;
 int mswindows_mouse_button_max_skew_x;
 int mswindows_mouse_button_max_skew_y;
@@ -184,11 +184,11 @@ static int mswindows_pending_timers_count;
 struct ntpipe_slurp_stream_shared_data
 {
   HANDLE hev_thread;   /* Our thread blocks on this, signaled by caller */
-                       /* This is a manual-reset object.                */
+  /* This is a manual-reset object.             */
   HANDLE hev_caller;   /* Caller blocks on this, and we signal it       */
-                       /* This is a manual-reset object.                */
+  /* This is a manual-reset object.             */
   HANDLE hev_unsleep;  /* Pipe read delay is canceled if this is set    */
-                       /* This is a manual-reset object.                */
+  /* This is a manual-reset object.             */
   HANDLE hpipe;                /* Pipe read end handle.                         */
   LONG   die_p;                /* Thread must exit ASAP if non-zero             */
   BOOL   eof_p   : 1;  /* Set when thread saw EOF                       */
@@ -199,7 +199,7 @@ struct ntpipe_slurp_stream_shared_data
 };
 
 #define MAX_SLURP_STREAMS 32
-struct ntpipe_slurp_stream_shared_data 
+struct ntpipe_slurp_stream_shared_data
 shared_data_block[MAX_SLURP_STREAMS]={{0}};
 
 struct ntpipe_slurp_stream
@@ -227,7 +227,7 @@ slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
 }
 
 static struct ntpipe_slurp_stream_shared_data*
-slurper_allocate_shared_data()
+slurper_allocate_shared_data (void)
 {
   int i=0;
   for (i=0; i<MAX_SLURP_STREAMS; i++)
@@ -271,7 +271,7 @@ slurp_thread (LPVOID vparam)
 
       /* Now we got something to notify caller, either a byte or an
         error/eof indication. Before we do, allow internal pipe
-        buffer to accumulate little bit more data. 
+        buffer to accumulate little bit more data.
         Reader function pulses this event before waiting for
         a character, to avoid pipe delay, and to get the byte
         immediately. */
@@ -360,11 +360,11 @@ get_ntpipe_input_stream_waitable (Lstream *stream)
   return s->thread_data->hev_caller;
 }
 
-static int 
+static ssize_t
 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
 {
   /* This function must be called from the main thread only */
-  struct ntpipe_slurp_stream_shared_data* s = 
+  struct ntpipe_slurp_stream_shared_data* s =
     NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
 
   if (!s->die_p)
@@ -373,7 +373,7 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
       /* Disallow pipe read delay for the thread: we need a character
          ASAP */
       SetEvent (s->hev_unsleep);
-  
+
       /* Check if we have a character ready. Give it a short delay,
         for the thread to awake from pipe delay, just ion case*/
       wait_result = WaitForSingleObject (s->hev_caller, 2);
@@ -424,7 +424,7 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
              ReadFile (s->hpipe, data, min (bytes_available, size),
                        &bytes_read, NULL);
          }
-      
+
        /* Now we can unblock thread, so it attempts to read more */
        SetEvent (s->hev_thread);
        return bytes_read + 1;
@@ -433,11 +433,11 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
   return 0;
 }
 
-static int 
+static int
 ntpipe_slurp_closer (Lstream *stream)
 {
   /* This function must be called from the main thread only */
-  struct ntpipe_slurp_stream_shared_data* s = 
+  struct ntpipe_slurp_stream_shared_data* s =
     NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
 
   /* Force thread to stop */
@@ -469,12 +469,12 @@ init_slurp_stream (void)
   LSTREAM_TYPE_DATA (stream, ntpipe_shove)
 
 #define MAX_SHOVE_BUFFER_SIZE 128
-     
+
 struct ntpipe_shove_stream
 {
   LPARAM user_data;    /* Any user data stored in the stream object     */
   HANDLE hev_thread;   /* Our thread blocks on this, signaled by caller */
-                       /* This is an auto-reset object.                 */
+  /* This is an auto-reset object.              */
   HANDLE hpipe;                /* Pipe write end handle.                        */
   HANDLE hthread;      /* Reader thread handle.                         */
   char  buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written          */
@@ -496,7 +496,7 @@ shove_thread (LPVOID vparam)
 
   for (;;)
     {
-      DWORD bytes_written; 
+      DWORD bytes_written;
 
       /* Block on event and wait for a job */
       InterlockedIncrement (&s->idle_p);
@@ -533,7 +533,7 @@ make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
   s->hpipe = hpipe;
   s->user_data = param;
 
-  /* Create reader thread. This could fail, so do not 
+  /* Create reader thread. This could fail, so do not
      create the event until thread is created */
   s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
                             CREATE_SUSPENDED, &thread_id_unused);
@@ -562,7 +562,7 @@ get_ntpipe_output_stream_param (Lstream *stream)
 }
 #endif
 
-static int
+static ssize_t
 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
 {
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
@@ -638,8 +638,8 @@ struct winsock_stream
   SOCKET s;                    /* Socket handle (which is a Win32 handle)   */
   OVERLAPPED ov;               /* Overlapped I/O structure                  */
   void* buffer;                        /* Buffer. Allocated for input stream only   */
-  unsigned int bufsize;                /* Number of bytes last read                 */
-  unsigned int bufpos;         /* Position in buffer for next fetch         */
+  unsigned long bufsize;       /* Number of bytes last read                 */
+  unsigned long bufpos;                /* Position in buffer for next fetch         */
   unsigned int error_p :1;     /* I/O Error seen                            */
   unsigned int eof_p :1;       /* EOF Error seen                            */
   unsigned int pending_p :1;   /* There is a pending I/O operation          */
@@ -671,7 +671,7 @@ winsock_initiate_read (struct winsock_stream *str)
     str->eof_p = 1;
 }
 
-static int
+static ssize_t
 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
@@ -704,7 +704,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
     return 0;
   if (str->error_p)
     return -1;
-  
+
   /* Return as much of buffer as we have */
   size = min (size, (size_t) (str->bufsize - str->bufpos));
   memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
@@ -717,8 +717,8 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
   return size;
 }
 
-static int
-winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
+static ssize_t
+winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
 
@@ -745,7 +745,7 @@ winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
 
   if (size == 0)
     return 0;
-  
+
   {
     ResetEvent (str->ov.hEvent);
 
@@ -791,7 +791,7 @@ winsock_was_blocked_p (Lstream *stream)
 }
 
 static Lisp_Object
-make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
+make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
 {
   Lisp_Object obj;
   Lstream *lstr = Lstream_new (lstream_winsock, mode);
@@ -859,7 +859,7 @@ init_winsock_stream (void)
 /************************************************************************/
 
 static int
-mswindows_user_event_p (struct Lisp_Event* sevt)
+mswindows_user_event_p (Lisp_Event* sevt)
 {
   return (sevt->event_type == key_press_event
          || sevt->event_type == button_press_event
@@ -867,7 +867,7 @@ mswindows_user_event_p (struct Lisp_Event* sevt)
          || sevt->event_type == misc_user_event);
 }
 
-/* 
+/*
  * Add an emacs event to the proper dispatch queue
  */
 static void
@@ -875,10 +875,10 @@ mswindows_enqueue_dispatch_event (Lisp_Object event)
 {
   int user_p = mswindows_user_event_p (XEVENT(event));
   enqueue_event (event,
-                user_p ? &mswindows_u_dispatch_event_queue : 
-                       &mswindows_s_dispatch_event_queue,
+                user_p ? &mswindows_u_dispatch_event_queue :
+                &mswindows_s_dispatch_event_queue,
                 user_p ? &mswindows_u_dispatch_event_queue_tail :
-                       &mswindows_s_dispatch_event_queue_tail);
+                &mswindows_s_dispatch_event_queue_tail);
 
   /* Avoid blocking on WaitMessage */
   PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
@@ -895,10 +895,11 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
                                   Lisp_Object object)
 {
   Lisp_Object event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event* e = XEVENT (event);
+  Lisp_Event* e = XEVENT (event);
 
   e->event_type = misc_user_event;
   e->channel = channel;
+  e->timestamp = GetTickCount ();
   e->event.misc.function = function;
   e->event.misc.object = object;
 
@@ -906,24 +907,24 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
 }
 
 void
-mswindows_enqueue_magic_event (HWND hwnd, UINT message)
+mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
 {
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event* event = XEVENT (emacs_event);
+  Lisp_Event* event = XEVENT (emacs_event);
 
   event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
   event->timestamp = GetMessageTime();
   event->event_type = magic_event;
-  EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
+  EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
 
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
 static void
-mswindows_enqueue_process_event (struct Lisp_Process* p)
+mswindows_enqueue_process_event (Lisp_Process* p)
 {
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event* event = XEVENT (emacs_event);
+  Lisp_Event* event = XEVENT (emacs_event);
   Lisp_Object process;
   XSETPROCESS (process, p);
 
@@ -935,7 +936,7 @@ mswindows_enqueue_process_event (struct Lisp_Process* p)
 }
 
 static void
-mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
+mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when)
 {
 
   /* We always use last message time, because mouse button
@@ -943,19 +944,19 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO
      recognition will fail */
 
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event* event = XEVENT(emacs_event);
+  Lisp_Event* event = XEVENT(emacs_event);
 
   event->channel = mswindows_find_frame(hwnd);
   event->timestamp = when;
   event->event.button.button =
-    (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
-    ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
+    (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
+    ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
   event->event.button.x = where.x;
   event->event.button.y = where.y;
   event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
-      
-  if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
-      message==WM_RBUTTONDOWN)
+
+  if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN ||
+      msg==WM_RBUTTONDOWN)
     {
       event->event_type = button_press_event;
       SetCapture (hwnd);
@@ -972,7 +973,7 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO
       event->event_type = button_release_event;
       ReleaseCapture ();
     }
-  
+
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
@@ -980,7 +981,7 @@ static void
 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
 {
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event* event = XEVENT(emacs_event);
+  Lisp_Event* event = XEVENT(emacs_event);
 
   event->channel = mswindows_find_console(hwnd);
   event->timestamp = GetMessageTime();
@@ -995,19 +996,19 @@ mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
  * Give a preference to user events over non-user ones.
  */
 static Lisp_Object
-mswindows_dequeue_dispatch_event ()
+mswindows_dequeue_dispatch_event (void)
 {
   Lisp_Object event;
-  struct Lisp_Event* sevt;
+  Lisp_Event* sevt;
 
   assert (!NILP(mswindows_u_dispatch_event_queue) ||
          !NILP(mswindows_s_dispatch_event_queue));
 
   event = dequeue_event (
-                NILP(mswindows_u_dispatch_event_queue) ? 
-                        &mswindows_s_dispatch_event_queue : 
+                        NILP(mswindows_u_dispatch_event_queue) ?
+                        &mswindows_s_dispatch_event_queue :
                         &mswindows_u_dispatch_event_queue,
-                NILP(mswindows_u_dispatch_event_queue) ? 
+                        NILP(mswindows_u_dispatch_event_queue) ?
                         &mswindows_s_dispatch_event_queue_tail :
                         &mswindows_u_dispatch_event_queue_tail);
 
@@ -1032,22 +1033,22 @@ mswindows_dequeue_dispatch_event ()
  */
 
 Lisp_Object
-mswindows_cancel_dispatch_event (struct Lisp_Event *match)
+mswindows_cancel_dispatch_event (Lisp_Event *match)
 {
   Lisp_Object event;
   Lisp_Object previous_event = Qnil;
   int user_p = mswindows_user_event_p (match);
-  Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : 
-                              &mswindows_s_dispatch_event_queue;
-  Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : 
-                              &mswindows_s_dispatch_event_queue_tail;
+  Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
+    &mswindows_s_dispatch_event_queue;
+  Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
+    &mswindows_s_dispatch_event_queue_tail;
 
   assert (match->event_type == timeout_event
          || match->event_type == key_press_event);
 
   EVENT_CHAIN_LOOP (event, *head)
     {
-      struct Lisp_Event *e = XEVENT (event);
+      Lisp_Event *e = XEVENT (event);
       if ((e->event_type == match->event_type) &&
          ((e->event_type == timeout_event) ?
           (e->event.timeout.interval_id == match->event.timeout.interval_id) :
@@ -1062,7 +1063,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event *match)
              if (EQ (*tail, event))
                *tail = previous_event;
            }
-         
+
          return event;
        }
       previous_event = event;
@@ -1103,7 +1104,7 @@ remove_waitable_handle (HANDLE h)
   if (ix < 0)
     return;
 
-  mswindows_waitable_handles [ix] = 
+  mswindows_waitable_handles [ix] =
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
 #endif /* HAVE_MSG_SELECT */
@@ -1127,7 +1128,7 @@ mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
 {
   Lisp_Object tmp;
 
-  ++mswindows_in_modal_loop; 
+  ++mswindows_in_modal_loop;
   tmp = condition_case_1 (Qt,
                          bfun, barg,
                          mswindows_modal_loop_error_handler, Qnil);
@@ -1151,7 +1152,7 @@ mswindows_unmodalize_signal_maybe (void)
 }
 
 /*
- * This is an unsafe part of event pump, guarded by 
+ * This is an unsafe part of event pump, guarded by
  * condition_case. See mswindows_pump_outstanding_events
  */
 static Lisp_Object
@@ -1175,7 +1176,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
 
   Fdeallocate_event (event);
   UNGCPRO;
-  
+
   /* Qt becomes return value of mswindows_pump_outstanding_events
      once we get here */
   return Qt;
@@ -1223,33 +1224,63 @@ mswindows_pump_outstanding_events (void)
   Lisp_Object result = Qt;
   struct gcpro gcpro1;
   GCPRO1 (result);
-  
+
   if (NILP(mswindows_error_caught_in_modal_loop))
-      result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
+    result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
   UNGCPRO;
   return result;
 }
 
-static void 
-mswindows_drain_windows_queue ()
+/*
+ * KEYBOARD_ONLY_P is set to non-zero when we are called from
+ * QUITP, and are interesting in keyboard messages only.
+ */
+static void
+mswindows_drain_windows_queue (void)
 {
   MSG msg;
+
+  /* should call mswindows_need_event_in_modal_loop() if in modal loop */
+  assert (!mswindows_in_modal_loop);
+
   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
     {
-      /* we have to translate messages that are not sent to the main
-         window. this is so that key presses work ok in things like
-         edit fields. however, we *musn't* translate message for the
-         main window as this is handled in the wnd proc. */
-      if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
+      /* We have to translate messages that are not sent to the main
+         window. This is so that key presses work ok in things like
+         edit fields. However, we *musn't* translate message for the
+         main window as this is handled in the wnd proc.
+         We also have to avoid generating paint magic events for windows
+        that aren't XEmacs frames */
+      if (GetWindowLong (msg.hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP))
        {
          TranslateMessage (&msg);
        }
+      else if (msg.message == WM_PAINT)
+       {
+         struct mswindows_frame* msframe;
+         
+         /* hdc will be NULL unless this is a subwindow - in which case we
+            shouldn't have received a paint message for it here. */
+         assert (msg.wParam == 0);
+
+         /* Queue a magic event for handling when safe */
+         msframe = FRAME_MSWINDOWS_DATA (
+                                         XFRAME (mswindows_find_frame (msg.hwnd)));
+         if (!msframe->paint_pending)
+           {
+             msframe->paint_pending = 1;
+             mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
+           }
+         /* Don't dispatch. WM_PAINT is always the last message in the
+            queue so it's OK to just return. */
+         return;
+       }
       DispatchMessage (&msg);
       mswindows_unmodalize_signal_maybe ();
     }
 }
 
-/* 
+/*
  * This is a special flavor of the mswindows_need_event function,
  * used while in event pump. Actually, there is only kind of events
  * allowed while in event pump: a timer.  An attempt to fetch any
@@ -1282,7 +1313,7 @@ mswindows_need_event_in_modal_loop (int badly_p)
       /* We'll deadlock if go waiting */
       if (mswindows_pending_timers_count == 0)
        error ("Deadlock due to an attempt to call next-event in a wrong context");
-      
+
       /* Fetch and dispatch any pending timers */
       GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
       DispatchMessage (&msg);
@@ -1307,10 +1338,6 @@ mswindows_need_event (int badly_p)
       return;
     }
 
-  /* Have to drain Windows message queue first, otherwise, we may miss
-     quit char when called from quit_p */
-  mswindows_drain_windows_queue ();
-
   while (NILP (mswindows_u_dispatch_event_queue)
         && NILP (mswindows_s_dispatch_event_queue))
     {
@@ -1319,7 +1346,7 @@ mswindows_need_event (int badly_p)
       SELECT_TYPE temp_mask = input_wait_mask;
       EMACS_TIME sometime;
       EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
-      
+
       if (badly_p)
        pointer_to_this = 0;
       else
@@ -1330,7 +1357,7 @@ mswindows_need_event (int badly_p)
        }
 
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
-      
+
       if (active == 0)
        {
          assert (!badly_p);
@@ -1342,48 +1369,51 @@ mswindows_need_event (int badly_p)
            {
              mswindows_drain_windows_queue ();
            }
-#ifdef HAVE_TTY          
-         /* Look for a TTY event */
-         for (i = 0; i < MAXDESC-1; i++)
+         else 
            {
-             /* To avoid race conditions (among other things, an infinite
-                loop when called from Fdiscard_input()), we must return
-                user events ahead of process events. */
-             if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
+#ifdef HAVE_TTY
+             /* Look for a TTY event */
+             for (i = 0; i < MAXDESC-1; i++)
                {
-                 struct console *c = tty_find_console_from_fd (i);
-                 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-                 struct Lisp_Event* event = XEVENT (emacs_event);
-                 
-                 assert (c);
-                 if (read_event_from_tty_or_stream_desc (event, c, i))
+                 /* To avoid race conditions (among other things, an infinite
+                    loop when called from Fdiscard_input()), we must return
+                    user events ahead of process events. */
+                 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
                    {
-                     mswindows_enqueue_dispatch_event (emacs_event);
-                     return;
+                     struct console *c = tty_find_console_from_fd (i);
+                     Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+                     Lisp_Event* event = XEVENT (emacs_event);
+                     
+                     assert (c);
+                     if (read_event_from_tty_or_stream_desc (event, c, i))
+                       {
+                         mswindows_enqueue_dispatch_event (emacs_event);
+                         return;
+                       }
                    }
                }
-           }
 #endif
-         /* Look for a process event */
-         for (i = 0; i < MAXDESC-1; i++)
-           {
-             if (FD_ISSET (i, &temp_mask))
+             /* Look for a process event */
+             for (i = 0; i < MAXDESC-1; i++)
                {
-                 if (FD_ISSET (i, &process_only_mask))
-                   {
-                     struct Lisp_Process *p =
-                       get_process_from_usid (FD_TO_USID(i));
-                     
-                     mswindows_enqueue_process_event (p);
-                   }
-                 else
+                 if (FD_ISSET (i, &temp_mask))
                    {
-                     /* We might get here when a fake event came
-                         through a signal. Return a dummy event, so
-                         that a cycle of the command loop will
-                         occur. */
-                     drain_signal_event_pipe ();
-                     mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
+                     if (FD_ISSET (i, &process_only_mask))
+                       {
+                         Lisp_Process *p =
+                           get_process_from_usid (FD_TO_USID(i));
+                         
+                         mswindows_enqueue_process_event (p);
+                       }
+                     else
+                       {
+                         /* We might get here when a fake event came
+                            through a signal. Return a dummy event, so
+                            that a cycle of the command loop will
+                            occur. */
+                         drain_signal_event_pipe ();
+                         mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
+                       }
                    }
                }
            }
@@ -1402,67 +1432,67 @@ mswindows_need_event (int badly_p)
        }
 #else
       /* Now try getting a message or process event */
-    active = MsgWaitForMultipleObjects (mswindows_waitable_count,
-                                       mswindows_waitable_handles,
-                                       FALSE, badly_p ? INFINITE : 0,
-                                       QS_ALLINPUT);
-
-    /* This will assert if handle being waited for becomes abandoned.
-       Not the case currently tho */
-    assert ((!badly_p && active == WAIT_TIMEOUT) ||
-           (active >= WAIT_OBJECT_0 &&
-            active <= WAIT_OBJECT_0 + mswindows_waitable_count));
-    
-    if (active == WAIT_TIMEOUT)
-      {
-       /* No luck trying - just return what we've already got */
-       return;
-      }
-    else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
-      {
-       /* Got your message, thanks */
-       mswindows_drain_windows_queue ();
-      }
-    else
-      {
-       int ix = active - WAIT_OBJECT_0;
-       /* First, try to find which process' output has signaled */
-       struct Lisp_Process *p = 
-         get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
-       if (p != NULL)
-         {
-           /* Found a signaled process input handle */
-           mswindows_enqueue_process_event (p);
-         }
-       else
-         {
-           /* None. This means that the process handle itself has signaled.
-              Remove the handle from the wait vector, and make status_notify
-              note the exited process */
-           mswindows_waitable_handles [ix] =
-             mswindows_waitable_handles [--mswindows_waitable_count];
-           kick_status_notify ();
-           /* Have to return something: there may be no accompanying
-              process event */
-           mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
-         }
-      }
+      active = MsgWaitForMultipleObjects (mswindows_waitable_count,
+                                         mswindows_waitable_handles,
+                                         FALSE, badly_p ? INFINITE : 0,
+                                         QS_ALLINPUT);
+
+      /* This will assert if handle being waited for becomes abandoned.
+        Not the case currently tho */
+      assert ((!badly_p && active == WAIT_TIMEOUT) ||
+             (active >= WAIT_OBJECT_0 &&
+              active <= WAIT_OBJECT_0 + mswindows_waitable_count));
+
+      if (active == WAIT_TIMEOUT)
+       {
+         /* No luck trying - just return what we've already got */
+         return;
+       }
+      else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
+       {
+         /* Got your message, thanks */
+         mswindows_drain_windows_queue ();
+       }
+      else
+       {
+         int ix = active - WAIT_OBJECT_0;
+         /* First, try to find which process' output has signaled */
+         Lisp_Process *p =
+           get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
+         if (p != NULL)
+           {
+             /* Found a signaled process input handle */
+             mswindows_enqueue_process_event (p);
+           }
+         else
+           {
+             /* None. This means that the process handle itself has signaled.
+                Remove the handle from the wait vector, and make status_notify
+                note the exited process */
+             mswindows_waitable_handles [ix] =
+               mswindows_waitable_handles [--mswindows_waitable_count];
+             kick_status_notify ();
+             /* Have to return something: there may be no accompanying
+                process event */
+             mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
+           }
+       }
 #endif
-  } /* while */
+    } /* while */
 }
 
 /************************************************************************/
 /*                           Event generators                           */
 /************************************************************************/
 
-/* 
+/*
  * Callback procedure for synchronous timer messages
  */
 static void CALLBACK
 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
 {
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-  struct Lisp_Event *event = XEVENT (emacs_event);
+  Lisp_Event *event = XEVENT (emacs_event);
 
   if (KillTimer (NULL, id_timer))
     --mswindows_pending_timers_count;
@@ -1477,7 +1507,7 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
-/* 
+/*
  * Callback procedure for dde messages
  *
  * We execute a dde Open("file") by simulating a file drop, so dde support
@@ -1488,9 +1518,9 @@ HDDEDATA CALLBACK
 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
                        HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
                        DWORD dwData1, DWORD dwData2)
-{ 
+{
   switch (uType)
-    { 
+    {
     case XTYP_CONNECT:
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        return (HDDEDATA)TRUE;
@@ -1503,24 +1533,24 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
 
        if (!(hszItem  || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
-           !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
+           !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
          return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
                                       sizeof (pairs), 0L, 0, uFmt, 0));
       }
-      return (HDDEDATA)NULL; 
+      return (HDDEDATA)NULL;
 
     case XTYP_EXECUTE:
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        {
          DWORD len = DdeGetData (hdata, NULL, 0, 0);
-         char *cmd = alloca (len+1);
+         LPBYTE cmd = (LPBYTE) alloca (len+1);
          char *end;
          char *filename;
          struct gcpro gcpro1, gcpro2;
           Lisp_Object l_dndlist = Qnil;
          Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
          Lisp_Object frmcons, devcons, concons;
-         struct Lisp_Event *event = XEVENT (emacs_event);
+         Lisp_Event *event = XEVENT (emacs_event);
 
          DdeGetData (hdata, cmd, len, 0);
          cmd[len] = '\0';
@@ -1588,16 +1618,64 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          UNGCPRO;
          return (HDDEDATA) DDE_FACK;
        }
-      DdeFreeDataHandle (hdata); 
+      DdeFreeDataHandle (hdata);
       return (HDDEDATA) DDE_FNOTPROCESSED;
 
-    default: 
-      return (HDDEDATA) NULL; 
-    } 
+    default:
+      return (HDDEDATA) NULL;
+    }
 }
 #endif
 
 /*
+ * Helper to do repainting - repaints can happen both from the windows
+ * procedure and from magic events
+ */
+static void
+mswindows_handle_paint (struct frame *frame)
+{
+  HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
+
+  /* According to the docs we need to check GetUpdateRect() before
+     actually doing a WM_PAINT */
+  if (GetUpdateRect (hwnd, NULL, FALSE))
+    {
+      PAINTSTRUCT paintStruct;
+      int x, y, width, height;
+
+      BeginPaint (hwnd, &paintStruct);
+      x = paintStruct.rcPaint.left;
+      y = paintStruct.rcPaint.top;
+      width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
+      height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
+      /* Normally we want to ignore expose events when child
+        windows are unmapped, however once we are in the guts of
+        WM_PAINT we need to make sure that we don't register
+        unmaps then because they will not actually occur. */
+      if (!check_for_ignored_expose (frame, x, y, width, height))
+       {
+         hold_ignored_expose_registration = 1;
+         mswindows_redraw_exposed_area (frame, x, y, width, height);
+         hold_ignored_expose_registration = 0;
+       }
+      EndPaint (hwnd, &paintStruct);
+    }
+}
+
+/*
+ * Returns 1 if a key is a real modifier or special key, which 
+ * is better handled by DefWindowProc
+ */
+static int
+key_needs_default_processing_p (UINT vkey)
+{
+  if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU)
+    return 1;
+
+  return 0;
+}
+
+/*
  * The windows procedure for the window class XEMACS_CLASS
  */
 LRESULT WINAPI
@@ -1608,759 +1686,825 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   Lisp_Object emacs_event = Qnil;
   Lisp_Object fobj = Qnil;
 
-  struct Lisp_Event *event;
+  Lisp_Event *event;
   struct frame *frame;
   struct mswindows_frame* msframe;
 
+  assert (!GetWindowLong (hwnd, GWL_USERDATA));
   switch (message)
-  {
-  case WM_ERASEBKGND:
-    /* Erase background only during non-dynamic sizing */
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    if (msframe->sizing && !mswindows_dynamic_frame_resize)
-      goto defproc;
-    return 1;
-
-  case WM_CLOSE:
-    fobj = mswindows_find_frame (hwnd);
-    mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
-    break;
-
-  case WM_KEYUP:
-  case WM_SYSKEYUP:
-    /* See Win95 comment under WM_KEYDOWN */
-    {
-      BYTE keymap[256];
-
-      if (wParam == VK_CONTROL)
-        {
-         GetKeyboardState (keymap);
-         keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
-         SetKeyboardState (keymap);
-       }
-      else if (wParam == VK_MENU)
-       {
-         GetKeyboardState (keymap);
-         keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
-         SetKeyboardState (keymap);
-       }
-    };
-    goto defproc;
-
-  case WM_KEYDOWN:
-  case WM_SYSKEYDOWN:
-    /* In some locales the right-hand Alt key is labelled AltGr. This key
-     * should produce alternative charcaters when combined with another key.
-     * eg on a German keyboard pressing AltGr+q should produce '@'.
-     * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
-     * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
-     * it translates as if AltGr were down.
-     * We get round this by removing all modifiers from the keymap before
-     * calling TranslateMessage() unless AltGr is *really* down. */
     {
-      BYTE keymap[256];
-      int has_AltGr = mswindows_current_layout_has_AltGr ();
-      int mods;
-      int extendedp = lParam & 0x1000000;
-      Lisp_Object keysym;
-
-      GetKeyboardState (keymap);
-      mods = mswindows_modifier_state (keymap, has_AltGr);
-
-      /* Handle non-printables */
-      if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
-                                                        extendedp)))
-       mswindows_enqueue_keypress_event (hwnd, keysym, mods);
-      else     /* Normal keys & modifiers */
-       {
-         int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
-         BYTE keymap_orig[256];
-         POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
-         MSG msg;
-         
-         msg.hwnd = hwnd;
-         msg.message = message;
-         msg.wParam = wParam;
-         msg.lParam = lParam;
-         msg.time = GetMessageTime();
-         msg.pt = pnt;
-
-         /* GetKeyboardState() does not work as documented on Win95. We have
-          * to loosely track Left and Right modifiers on behalf of the OS,
-          * without screwing up Windows NT which tracks them properly. */
-         if (wParam == VK_CONTROL)
-           keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
-         else if (wParam == VK_MENU)
-           keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
-
-         memcpy (keymap_orig, keymap, 256);
-
-         /* Remove shift modifier from an ascii character */
-         mods &= ~MOD_SHIFT;
-
-         /* Clear control and alt modifiers unless AltGr is pressed */
-         keymap [VK_RCONTROL] = 0;
-         keymap [VK_LMENU] = 0;
-         if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
-           {
-             keymap [VK_LCONTROL] = 0;
-             keymap [VK_CONTROL] = 0;
-             keymap [VK_RMENU] = 0;
-             keymap [VK_MENU] = 0;
-           }
-         SetKeyboardState (keymap);
+    case WM_DESTROYCLIPBOARD:
+      /* We own the clipboard and someone else wants it.  Delete our
+        cached copy of the clipboard contents so we'll ask for it from
+        Windows again when someone does a paste. */
+      handle_selection_clear(QCLIPBOARD);
+      break;
 
-         /* Maybe generate some WM_[SYS]CHARs in the queue */
-         TranslateMessage (&msg);
+    case WM_ERASEBKGND:
+      /* Erase background only during non-dynamic sizing */
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      if (msframe->sizing && !mswindows_dynamic_frame_resize)
+       goto defproc;
+      return 1;
 
-         while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
-                || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
-           {
-             int mods1 = mods;
-             WPARAM ch = msg.wParam;
-
-             /* If a quit char with no modifiers other than control and
-                shift, then mark it with a fake modifier, which is removed
-                upon dequeueing the event */
-             /* #### This might also not withstand localization, if
-                quit character is not a latin-1 symbol */
-             if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
-                  || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
-                 && ((mods  & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
-               {
-                 mods1 |= FAKE_MOD_QUIT;
-                 ++mswindows_quit_chars_count;
-               }
+    case WM_CLOSE:
+      fobj = mswindows_find_frame (hwnd);
+      mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
+      break;
 
-             mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
-           } /* while */
-         SetKeyboardState (keymap_orig);
-       } /* else */
-    }
-    /* F10 causes menu activation by default. We do not want this */
-    if (wParam != VK_F10 && (mswindows_meta_activates_menu || wParam != VK_MENU))
-      goto defproc;
-    break;
-
-  case WM_MBUTTONDOWN:
-  case WM_MBUTTONUP:
-    /* Real middle mouse button has nothing to do with emulated one:
-       if one wants to exercise fingers playing chords on the mouse,
-       he is allowed to do that! */
-    mswindows_enqueue_mouse_button_event (hwnd, message,
-                                         MAKEPOINTS (lParam), GetMessageTime());
-    break;
-    
-  case WM_LBUTTONUP:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    msframe->last_click_time =  GetMessageTime();
-
-    KillTimer (hwnd, BUTTON_2_TIMER_ID);
-    msframe->button2_need_lbutton = 0;
-    if (msframe->ignore_next_lbutton_up)
-      {
-       msframe->ignore_next_lbutton_up = 0;
-      }
-    else if (msframe->button2_is_down)
+    case WM_KEYUP:
+    case WM_SYSKEYUP:
+      /* See Win95 comment under WM_KEYDOWN */
       {
-       msframe->button2_is_down = 0;
-       msframe->ignore_next_rbutton_up = 1;
-       mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
-                                             MAKEPOINTS (lParam), GetMessageTime());
-      }
-    else
-      {
-       if (msframe->button2_need_rbutton)
+       BYTE keymap[256];
+       int should_set_keymap = 0;
+
+       if (wParam == VK_CONTROL)
          {
-           msframe->button2_need_rbutton = 0;
-           mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
+           GetKeyboardState (keymap);
+           keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
+           should_set_keymap = 1;
          }
-       mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
-                                             MAKEPOINTS (lParam), GetMessageTime());
-      }
-    break;
-
-  case WM_RBUTTONUP:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    msframe->last_click_time =  GetMessageTime();
-
-    KillTimer (hwnd, BUTTON_2_TIMER_ID);
-    msframe->button2_need_rbutton = 0;
-    if (msframe->ignore_next_rbutton_up)
-      {
-       msframe->ignore_next_rbutton_up = 0;
-      }
-    else if (msframe->button2_is_down)
-      {
-       msframe->button2_is_down = 0;
-       msframe->ignore_next_lbutton_up = 1;
-       mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
-                                             MAKEPOINTS (lParam), GetMessageTime());
-      }
-    else
-      {
-       if (msframe->button2_need_lbutton)
+       else if (wParam == VK_MENU)
          {
-           msframe->button2_need_lbutton = 0;
-           mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
+           GetKeyboardState (keymap);
+           keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
+           should_set_keymap = 1;
          }
-       mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
-                                             MAKEPOINTS (lParam), GetMessageTime());
-      }
-    break;
 
-  case WM_LBUTTONDOWN:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+       if (should_set_keymap
+           && (message != WM_SYSKEYUP
+               || NILP (Vmenu_accelerator_enabled)))
+         SetKeyboardState (keymap);
 
-    if (msframe->button2_need_lbutton)
-      {
-       KillTimer (hwnd, BUTTON_2_TIMER_ID);
-       msframe->button2_need_lbutton = 0;
-       msframe->button2_need_rbutton = 0;
-       if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
-         {
-           mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
-           msframe->button2_is_down = 1;
-         }
-       else
-         {
-           mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
-                       msframe->last_click_point, msframe->last_click_time);
-           mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
-         }
-      }
-    else
-      {
-       mswindows_set_chord_timer (hwnd);
-       msframe->button2_need_rbutton = 1;
-       msframe->last_click_point = MAKEPOINTS (lParam);
       }
-    msframe->last_click_time =  GetMessageTime();
-    break;
-
-  case WM_RBUTTONDOWN:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      if (key_needs_default_processing_p (wParam))
+       goto defproc;
+      else
+       break;
 
-    if (msframe->button2_need_rbutton)
+    case WM_KEYDOWN:
+    case WM_SYSKEYDOWN:
+      /* In some locales the right-hand Alt key is labelled AltGr. This key
+       * should produce alternative charcaters when combined with another key.
+       * eg on a German keyboard pressing AltGr+q should produce '@'.
+       * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
+       * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
+       * it translates as if AltGr were down.
+       * We get round this by removing all modifiers from the keymap before
+       * calling TranslateMessage() unless AltGr is *really* down. */
       {
-       KillTimer (hwnd, BUTTON_2_TIMER_ID);
-       msframe->button2_need_lbutton = 0;
-       msframe->button2_need_rbutton = 0;
-       if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
-         {
-           mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
-           msframe->button2_is_down = 1;
-         }
-       else
+       BYTE keymap[256];
+       int has_AltGr = mswindows_current_layout_has_AltGr ();
+       int mods;
+       int extendedp = lParam & 0x1000000;
+       Lisp_Object keysym;
+
+       frame = XFRAME (mswindows_find_frame (hwnd));
+       GetKeyboardState (keymap);
+       mods = mswindows_modifier_state (keymap, has_AltGr);
+
+       /* Handle non-printables */
+       if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
+                                                          extendedp)))
+         mswindows_enqueue_keypress_event (hwnd, keysym, mods);
+       else    /* Normal keys & modifiers */
          {
-           mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
-                               msframe->last_click_point, msframe->last_click_time);
-           mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
-                                                 MAKEPOINTS (lParam), GetMessageTime());
-         }
-      }
-    else
-      {
-       mswindows_set_chord_timer (hwnd);
-       msframe->button2_need_lbutton = 1;
-       msframe->last_click_point = MAKEPOINTS (lParam);
+           Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
+           BYTE keymap_orig[256];
+           POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
+           MSG msg, tranmsg;
+           int potential_accelerator = 0;
+           int got_accelerator = 0;
+         
+           msg.hwnd = hwnd;
+           msg.message = message;
+           msg.wParam = wParam;
+           msg.lParam = lParam;
+           msg.time = GetMessageTime();
+           msg.pt = pnt;
+
+           /* GetKeyboardState() does not work as documented on Win95. We have
+            * to loosely track Left and Right modifiers on behalf of the OS,
+            * without screwing up Windows NT which tracks them properly. */
+           if (wParam == VK_CONTROL)
+             keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+           else if (wParam == VK_MENU)
+             keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
+
+           memcpy (keymap_orig, keymap, 256);
+
+           if (!NILP (Vmenu_accelerator_enabled) &&
+               !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN)
+             potential_accelerator = 1;
+
+           /* Remove shift modifier from an ascii character */
+           mods &= ~XEMACS_MOD_SHIFT;
+
+           /* Clear control and alt modifiers unless AltGr is pressed */
+           keymap [VK_RCONTROL] = 0;
+           keymap [VK_LMENU] = 0;
+           if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80)
+               || !(keymap [VK_RMENU] & 0x80))
+             {
+               keymap [VK_LCONTROL] = 0;
+               keymap [VK_CONTROL] = 0;
+               keymap [VK_RMENU] = 0;
+               keymap [VK_MENU] = 0;
+             }
+           SetKeyboardState (keymap);
+
+           /* Maybe generate some WM_[SYS]CHARs in the queue */
+           TranslateMessage (&msg);
+
+           while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
+                  || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
+             {
+               int mods1 = mods;
+               WPARAM ch = tranmsg.wParam;
+
+               /* If a quit char with no modifiers other than control and
+                  shift, then mark it with a fake modifier, which is removed
+                  upon dequeueing the event */
+               /* #### This might also not withstand localization, if
+                  quit character is not a latin-1 symbol */
+               if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
+                    || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch))
+                   && ((mods  & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0))
+                 {
+                   mods1 |= FAKE_MOD_QUIT;
+                   ++mswindows_quit_chars_count;
+                 }
+               else if (potential_accelerator && !got_accelerator &&
+                        msw_char_is_accelerator (frame, ch))
+                 {
+                   got_accelerator = 1;
+                   break;
+                 }
+               mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
+             } /* while */
+           SetKeyboardState (keymap_orig);
+           /* This generates WM_SYSCHAR messages, which are interpreted
+              by DefWindowProc as the menu selections. */
+           if (got_accelerator)
+             { 
+               TranslateMessage (&msg);
+               goto defproc;
+             }
+         } /* else */
       }
-    msframe->last_click_time =  GetMessageTime();
-    break;
-       
-  case WM_TIMER:
-    if (wParam == BUTTON_2_TIMER_ID)
-      {
-       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-       KillTimer (hwnd, BUTTON_2_TIMER_ID);
+      if (key_needs_default_processing_p (wParam))
+       goto defproc;
+      else
+       break;
 
-       if (msframe->button2_need_lbutton)
-         {
-           msframe->button2_need_lbutton = 0;
-           mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
-                               msframe->last_click_point, msframe->last_click_time);
-         }
-       else if (msframe->button2_need_rbutton)
-         {
-           msframe->button2_need_rbutton = 0;
-           mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
-                               msframe->last_click_point, msframe->last_click_time);
-         }
-      }
-    else
-      assert ("Spurious timer fired" == 0);
-    break;
+    case WM_MBUTTONDOWN:
+    case WM_MBUTTONUP:
+      /* Real middle mouse button has nothing to do with emulated one:
+        if one wants to exercise fingers playing chords on the mouse,
+        he is allowed to do that! */
+      mswindows_enqueue_mouse_button_event (hwnd, message,
+                                           MAKEPOINTS (lParam), GetMessageTime());
+      break;
 
-  case WM_MOUSEMOVE:
-    /* Optimization: don't report mouse movement while size is changing */
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    if (!msframe->sizing)
-    {
-      /* When waiting for the second mouse button to finish
-        button2 emulation, and have moved too far, just pretend
-        as if timer has expired. This improves drag-select feedback */
-      if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
-         && !mswindows_button2_near_enough (msframe->last_click_point,
-                                            MAKEPOINTS (lParam)))
+    case WM_LBUTTONUP:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      msframe->last_click_time =  GetMessageTime();
+
+      KillTimer (hwnd, BUTTON_2_TIMER_ID);
+      msframe->button2_need_lbutton = 0;
+      if (msframe->ignore_next_lbutton_up)
        {
-         KillTimer (hwnd, BUTTON_2_TIMER_ID);
-         SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
+         msframe->ignore_next_lbutton_up = 0;
+       }
+      else if (msframe->button2_is_down)
+       {
+         msframe->button2_is_down = 0;
+         msframe->ignore_next_rbutton_up = 1;
+         mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
+                                               MAKEPOINTS (lParam), GetMessageTime());
        }
+      else
+       {
+         if (msframe->button2_need_rbutton)
+           {
+             msframe->button2_need_rbutton = 0;
+             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
+           }
+         mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
+                                               MAKEPOINTS (lParam), GetMessageTime());
+       }
+      break;
 
-      emacs_event = Fmake_event (Qnil, Qnil);
-      event = XEVENT(emacs_event);
-
-      event->channel = mswindows_find_frame(hwnd);
-      event->timestamp = GetMessageTime();
-      event->event_type = pointer_motion_event;
-      event->event.motion.x = MAKEPOINTS(lParam).x;
-      event->event.motion.y = MAKEPOINTS(lParam).y;
-      event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
-      
-      mswindows_enqueue_dispatch_event (emacs_event);
-    }
-    break;
+    case WM_RBUTTONUP:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      msframe->last_click_time =  GetMessageTime();
 
-  case WM_CANCELMODE:
-    ReleaseCapture ();
-    /* Queue a `cancel-mode-internal' misc user event, so mouse
-       selection would be canceled if any */
-    mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
-                                      Qcancel_mode_internal, Qnil);
-    break;
+      KillTimer (hwnd, BUTTON_2_TIMER_ID);
+      msframe->button2_need_rbutton = 0;
+      if (msframe->ignore_next_rbutton_up)
+       {
+         msframe->ignore_next_rbutton_up = 0;
+       }
+      else if (msframe->button2_is_down)
+       {
+         msframe->button2_is_down = 0;
+         msframe->ignore_next_lbutton_up = 1;
+         mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
+                                               MAKEPOINTS (lParam), GetMessageTime());
+       }
+      else
+       {
+         if (msframe->button2_need_lbutton)
+           {
+             msframe->button2_need_lbutton = 0;
+             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
+           }
+         mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
+                                               MAKEPOINTS (lParam), GetMessageTime());
+       }
+      break;
 
-  case WM_NOTIFY:
-    {
-      LPNMHDR nmhdr = (LPNMHDR)lParam;
+    case WM_LBUTTONDOWN:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
 
-      if (nmhdr->code ==  TTN_NEEDTEXT)
+      if (msframe->button2_need_lbutton)
        {
-#ifdef HAVE_TOOLBARS
-         LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
-         Lisp_Object btext;
+         KillTimer (hwnd, BUTTON_2_TIMER_ID);
+         msframe->button2_need_lbutton = 0;
+         msframe->button2_need_rbutton = 0;
+         if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
+           {
+             mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
+             msframe->button2_is_down = 1;
+           }
+         else
+           {
+             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+                                                   msframe->last_click_point, msframe->last_click_time);
+             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
+           }
+       }
+      else
+       {
+         mswindows_set_chord_timer (hwnd);
+         msframe->button2_need_rbutton = 1;
+         msframe->last_click_point = MAKEPOINTS (lParam);
+       }
+      msframe->last_click_time =  GetMessageTime();
+      break;
 
-         /* find out which toolbar */
-         frame = XFRAME (mswindows_find_frame (hwnd));
-         btext = mswindows_get_toolbar_button_text ( frame, 
-                                                     nmhdr->idFrom );
-         
-         tttext->lpszText = NULL;
-         tttext->hinst = NULL;
+    case WM_RBUTTONDOWN:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
 
-         if (!NILP(btext))
+      if (msframe->button2_need_rbutton)
+       {
+         KillTimer (hwnd, BUTTON_2_TIMER_ID);
+         msframe->button2_need_lbutton = 0;
+         msframe->button2_need_rbutton = 0;
+         if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
            {
-             /* I think this is safe since the text will only go away
-                 when the toolbar does...*/
-             GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS, 
-                                           tttext->lpszText);
+             mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
+             msframe->button2_is_down = 1;
+           }
+         else
+           {
+             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+                                                   msframe->last_click_point, msframe->last_click_time);
+             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+                                                   MAKEPOINTS (lParam), GetMessageTime());
            }
-#endif
        }
-      /* handle tree view callbacks */
-      else if (nmhdr->code == TVN_SELCHANGED)
+      else
        {
-         NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
-         frame = XFRAME (mswindows_find_frame (hwnd));
-         mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
+         mswindows_set_chord_timer (hwnd);
+         msframe->button2_need_lbutton = 1;
+         msframe->last_click_point = MAKEPOINTS (lParam);
        }
-      /* handle tab control callbacks */
-      else if (nmhdr->code == TCN_SELCHANGE)
-       {
-         TC_ITEM item;
-         int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
-         frame = XFRAME (mswindows_find_frame (hwnd));
+      msframe->last_click_time =  GetMessageTime();
+      break;
 
-         item.mask = TCIF_PARAM;
-         SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
-                      (LPARAM)&item);
-         
-         mswindows_handle_gui_wm_command (frame, 0, item.lParam);
-       }
-    }
-    break;
-    
-  case WM_PAINT:
-    {
-      /* According to the docs we need to check GetUpdateRect() before
-         actually doing a WM_PAINT */
-      if (GetUpdateRect (hwnd, NULL, FALSE))
+    case WM_TIMER:
+      if (wParam == BUTTON_2_TIMER_ID)
        {
-         PAINTSTRUCT paintStruct;
-         int x, y, width, height;
+         msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+         KillTimer (hwnd, BUTTON_2_TIMER_ID);
 
-         frame = XFRAME (mswindows_find_frame (hwnd));
-         
-         BeginPaint (hwnd, &paintStruct);
-         x = paintStruct.rcPaint.left;
-         y = paintStruct.rcPaint.top;
-         width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
-         height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
-         /* Normally we want to ignore expose events when child
-            windows are unmapped, however once we are in the guts of
-            WM_PAINT we need to make sure that we don't register
-            unmaps then because they will not actually occur. */
-         if (!check_for_ignored_expose (frame, x, y, width, height))
+         if (msframe->button2_need_lbutton)
            {
-             hold_ignored_expose_registration = 1;
-             mswindows_redraw_exposed_area (frame, x, y, width, height);
-             hold_ignored_expose_registration = 0;
+             msframe->button2_need_lbutton = 0;
+             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
+                                                   msframe->last_click_point, msframe->last_click_time);
+           }
+         else if (msframe->button2_need_rbutton)
+           {
+             msframe->button2_need_rbutton = 0;
+             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
+                                                   msframe->last_click_point, msframe->last_click_time);
            }
-
-         EndPaint (hwnd, &paintStruct);
        }
       else
-       goto defproc;
-    }
-    break;
+       assert ("Spurious timer fired" == 0);
+      break;
 
-  case WM_SIZE:
-    /* We only care about this message if our size has really changed */
-    if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
-    {
-      RECT rect;
-      int columns, rows;
+    case WM_MOUSEMOVE:
+      /* Optimization: don't report mouse movement while size is changing */
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      if (!msframe->sizing)
+       {
+         /* When waiting for the second mouse button to finish
+            button2 emulation, and have moved too far, just pretend
+            as if timer has expired. This improves drag-select feedback */
+         if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
+             && !mswindows_button2_near_enough (msframe->last_click_point,
+                                                MAKEPOINTS (lParam)))
+           {
+             KillTimer (hwnd, BUTTON_2_TIMER_ID);
+             SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
+           }
 
-      fobj = mswindows_find_frame (hwnd);
-      frame = XFRAME (fobj);
-      msframe  = FRAME_MSWINDOWS_DATA (frame);
+         emacs_event = Fmake_event (Qnil, Qnil);
+         event = XEVENT(emacs_event);
 
-      /* We cannot handle frame map and unmap hooks right in
-        this routine, because these may throw. We queue
-        magic events to run these hooks instead - kkm */
+         event->channel = mswindows_find_frame(hwnd);
+         event->timestamp = GetMessageTime();
+         event->event_type = pointer_motion_event;
+         event->event.motion.x = MAKEPOINTS(lParam).x;
+         event->event.motion.y = MAKEPOINTS(lParam).y;
+         event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
 
-      if (wParam==SIZE_MINIMIZED)
-       {
-         /* Iconified */
-         FRAME_VISIBLE_P (frame) = 0;
-         mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
+         mswindows_enqueue_dispatch_event (emacs_event);
        }
-      else
+      break;
+
+    case WM_CANCELMODE:
+      ReleaseCapture ();
+      /* Queue a `cancel-mode-internal' misc user event, so mouse
+        selection would be canceled if any */
+      mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
+                                        Qcancel_mode_internal, Qnil);
+      break;
+
+    case WM_NOTIFY:
+      {
+       LPNMHDR nmhdr = (LPNMHDR)lParam;
+
+       if (nmhdr->code ==  TTN_NEEDTEXT)
+         {
+#ifdef HAVE_TOOLBARS
+           LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
+           Lisp_Object btext;
+
+           /* find out which toolbar */
+           frame = XFRAME (mswindows_find_frame (hwnd));
+           btext = mswindows_get_toolbar_button_text ( frame,
+                                                       nmhdr->idFrom );
+
+           tttext->lpszText = NULL;
+           tttext->hinst = NULL;
+
+           if (!NILP(btext))
+             {
+               /* I think this is safe since the text will only go away
+                  when the toolbar does...*/
+               TO_EXTERNAL_FORMAT (LISP_STRING, btext,
+                                   C_STRING_ALLOCA, tttext->lpszText,
+                                   Qnative);
+             }
+#endif
+         }
+       /* handle tree view callbacks */
+       else if (nmhdr->code == TVN_SELCHANGED)
+         {
+           NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
+           frame = XFRAME (mswindows_find_frame (hwnd));
+           mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
+         }
+       /* handle tab control callbacks */
+       else if (nmhdr->code == TCN_SELCHANGE)
+         {
+           TC_ITEM item;
+           int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
+           frame = XFRAME (mswindows_find_frame (hwnd));
+
+           item.mask = TCIF_PARAM;
+           SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
+                        (LPARAM)&item);
+
+           mswindows_handle_gui_wm_command (frame, 0, item.lParam);
+         }
+      }
+      break;
+
+    case WM_PAINT:
+      /* hdc will be NULL unless this is a subwindow - in which case we
+        shouldn't have received a paint message for it here. */
+      assert (wParam == 0);
+
+      /* Can't queue a magic event because windows goes modal and sends paint 
+        messages directly to the windows procedure when doing solid drags
+        and the message queue doesn't get processed. */
+      mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
+      break;
+
+    case WM_SIZE:
+      /* We only care about this message if our size has really changed */
+      if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
        {
-         GetClientRect(hwnd, &rect);
-         FRAME_PIXWIDTH(frame) = rect.right;
-         FRAME_PIXHEIGHT(frame) = rect.bottom;
+         RECT rect;
+         int columns, rows;
 
-         pixel_to_real_char_size (frame, rect.right, rect.bottom,
-                                  &FRAME_MSWINDOWS_CHARWIDTH (frame),
-                                  &FRAME_MSWINDOWS_CHARHEIGHT (frame));
+         fobj = mswindows_find_frame (hwnd);
+         frame = XFRAME (fobj);
+         msframe  = FRAME_MSWINDOWS_DATA (frame);
 
-         pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
-         change_frame_size (frame, rows, columns, 1);
+         /* We cannot handle frame map and unmap hooks right in
+            this routine, because these may throw. We queue
+            magic events to run these hooks instead - kkm */
 
-         /* If we are inside frame creation, we have to apply geometric
-            properties now. */
-         if (FRAME_MSWINDOWS_TARGET_RECT (frame))
+         if (wParam==SIZE_MINIMIZED)
            {
-             /* Yes, we have to size again */
-             mswindows_size_frame_internal ( frame, 
-                                             FRAME_MSWINDOWS_TARGET_RECT 
-                                             (frame));
-             /* Reset so we do not get here again. The SetWindowPos call in
-              * mswindows_size_frame_internal can cause recursion here. */
-             if (FRAME_MSWINDOWS_TARGET_RECT (frame))
-               {
-                 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
-                 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
-               }
+             /* Iconified */
+             FRAME_VISIBLE_P (frame) = 0;
+             mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
            }
          else
            {
-             if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
-               mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
-             FRAME_VISIBLE_P (frame) = 1;
-             
-             if (!msframe->sizing || mswindows_dynamic_frame_resize)
-               redisplay ();
+             GetClientRect(hwnd, &rect);
+             FRAME_PIXWIDTH(frame) = rect.right;
+             FRAME_PIXHEIGHT(frame) = rect.bottom;
+
+             pixel_to_real_char_size (frame, rect.right, rect.bottom,
+                                      &FRAME_MSWINDOWS_CHARWIDTH (frame),
+                                      &FRAME_MSWINDOWS_CHARHEIGHT (frame));
+
+             pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
+             change_frame_size (frame, rows, columns, 1);
+
+             /* If we are inside frame creation, we have to apply geometric
+                properties now. */
+             if (FRAME_MSWINDOWS_TARGET_RECT (frame))
+               {
+                 /* Yes, we have to size again */
+                 mswindows_size_frame_internal ( frame,
+                                                 FRAME_MSWINDOWS_TARGET_RECT
+                                                 (frame));
+                 /* Reset so we do not get here again. The SetWindowPos call in
+                  * mswindows_size_frame_internal can cause recursion here. */
+                 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
+                   {
+                     xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
+                     FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
+                   }
+               }
+             else
+               {
+                 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
+                   mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
+                 FRAME_VISIBLE_P (frame) = 1;
+
+                 if (!msframe->sizing || mswindows_dynamic_frame_resize)
+                   redisplay ();
+               }
            }
        }
-    }
-    break;
+      break;
 
-  /* Misc magic events which only require that the frame be identified */
-  case WM_SETFOCUS:
-  case WM_KILLFOCUS:
-    mswindows_enqueue_magic_event (hwnd, message);
-    break;
+    case WM_DISPLAYCHANGE:
+      {
+       struct device *d;
 
-  case WM_WINDOWPOSCHANGING:
-    {
-      WINDOWPOS *wp = (LPWINDOWPOS) lParam;
-      WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
-      GetWindowPlacement(hwnd, &wpl);
-
-      /* Only interested if size is changing and we're not being iconified */
-      if (wpl.showCmd != SW_SHOWMINIMIZED
-         && wpl.showCmd != SW_SHOWMAXIMIZED
-         && !(wp->flags & SWP_NOSIZE))
+       fobj = mswindows_find_frame (hwnd);
+       frame = XFRAME (fobj);
+       d = XDEVICE (FRAME_DEVICE (frame));
+
+       DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam);
+       DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam);
+       DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam;
+       break;
+      }
+
+      /* Misc magic events which only require that the frame be identified */
+    case WM_SETFOCUS:
+    case WM_KILLFOCUS:
+      mswindows_enqueue_magic_event (hwnd, message);
+      break;
+
+    case WM_WINDOWPOSCHANGING:
       {
-       RECT ncsize = { 0, 0, 0, 0 };
-       int pixwidth, pixheight;
-       AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
-                           GetMenu(hwnd) != NULL,
-                           GetWindowLong (hwnd, GWL_EXSTYLE));
-
-       round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
-                                wp->cx - (ncsize.right - ncsize.left),
-                                wp->cy - (ncsize.bottom - ncsize.top),
-                                &pixwidth, &pixheight);
-
-       /* Convert client sizes to window sizes */
-       pixwidth += (ncsize.right - ncsize.left);
-       pixheight += (ncsize.bottom - ncsize.top);
-
-       if (wpl.showCmd != SW_SHOWMAXIMIZED)
+       WINDOWPOS *wp = (LPWINDOWPOS) lParam;
+       WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
+       GetWindowPlacement(hwnd, &wpl);
+
+       /* Only interested if size is changing and we're not being iconified */
+       if (wpl.showCmd != SW_SHOWMINIMIZED
+           && wpl.showCmd != SW_SHOWMAXIMIZED
+           && !(wp->flags & SWP_NOSIZE))
          {
-           /* Adjust so that the bottom or right doesn't move if it's
-            * the top or left that's being changed */
-           RECT rect;
-           GetWindowRect (hwnd, &rect);
-
-           if (rect.left != wp->x)
-             wp->x += wp->cx - pixwidth;
-           if (rect.top != wp->y)
-             wp->y += wp->cy - pixheight;
+           RECT ncsize = { 0, 0, 0, 0 };
+           int pixwidth, pixheight;
+           AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
+                               GetMenu(hwnd) != NULL,
+                               GetWindowLong (hwnd, GWL_EXSTYLE));
+
+           round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
+                                    wp->cx - (ncsize.right - ncsize.left),
+                                    wp->cy - (ncsize.bottom - ncsize.top),
+                                    &pixwidth, &pixheight);
+
+           /* Convert client sizes to window sizes */
+           pixwidth += (ncsize.right - ncsize.left);
+           pixheight += (ncsize.bottom - ncsize.top);
+
+           if (wpl.showCmd != SW_SHOWMAXIMIZED)
+             {
+               /* Adjust so that the bottom or right doesn't move if it's
+                * the top or left that's being changed */
+               RECT rect;
+               GetWindowRect (hwnd, &rect);
+
+               if (rect.left != wp->x)
+                 wp->x += wp->cx - pixwidth;
+               if (rect.top != wp->y)
+                 wp->y += wp->cy - pixheight;
+             }
+
+           wp->cx = pixwidth;
+           wp->cy = pixheight;
          }
-
-       wp->cx = pixwidth;
-       wp->cy = pixheight;
+       /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
+          window position if the user tries to track window too small */
       }
-      /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
-        window position if the user tries to track window too small */
-    }
-    goto defproc;
+      goto defproc;
 
-  case WM_ENTERSIZEMOVE:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    msframe->sizing = 1;
-    return 0;
+    case WM_ENTERSIZEMOVE:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      msframe->sizing = 1;
+      return 0;
 
-  case WM_EXITSIZEMOVE:
-    msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
-    msframe->sizing = 0;
-    /* Queue noop event */
-    mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
-    return 0;
+    case WM_EXITSIZEMOVE:
+      msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
+      msframe->sizing = 0;
+      /* Queue noop event */
+      mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
+      return 0;
 
 #ifdef HAVE_SCROLLBARS
-  case WM_VSCROLL:
-  case WM_HSCROLL:
-    {
-      /* Direction of scroll is determined by scrollbar instance. */
-      int code = (int) LOWORD(wParam);
-      int pos = (short int) HIWORD(wParam);
-      HWND hwndScrollBar = (HWND) lParam;
-      struct gcpro gcpro1, gcpro2;
-
-      mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
-      GCPRO2 (emacs_event, fobj);
-      if (UNBOUNDP(mswindows_pump_outstanding_events()))       /* Can GC */
-       {
-         /* Error during event pumping - cancel scroll */
-         SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
-       }
-      UNGCPRO;
-      break;     
-    }
+    case WM_VSCROLL:
+    case WM_HSCROLL:
+      {
+       /* Direction of scroll is determined by scrollbar instance. */
+       int code = (int) LOWORD(wParam);
+       int pos = (short int) HIWORD(wParam);
+       HWND hwndScrollBar = (HWND) lParam;
+       struct gcpro gcpro1, gcpro2;
+
+       mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
+       GCPRO2 (emacs_event, fobj);
+       if (UNBOUNDP(mswindows_pump_outstanding_events()))      /* Can GC */
+         {
+           /* Error during event pumping - cancel scroll */
+           SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
+         }
+       UNGCPRO;
+       break;
+      }
 
-  case WM_MOUSEWHEEL:
-    {
-      int keys = LOWORD (wParam); /* Modifier key flags */
-      int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
-      struct gcpro gcpro1, gcpro2;
+    case WM_MOUSEWHEEL:
+      {
+       int keys = LOWORD (wParam); /* Modifier key flags */
+       int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
+       struct gcpro gcpro1, gcpro2;
 
-      if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys,  delta))
-       {
-         GCPRO2 (emacs_event, fobj);
-         mswindows_pump_outstanding_events (); /* Can GC */
-         UNGCPRO;
-       }
-      else
-       goto defproc;
-      break;     
-    }
+       if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys,  delta))
+         {
+           GCPRO2 (emacs_event, fobj);
+           mswindows_pump_outstanding_events ();       /* Can GC */
+           UNGCPRO;
+         }
+       else
+         goto defproc;
+       break;
+      }
 #endif
 
 #ifdef HAVE_MENUBARS
-  case WM_INITMENU:
-    if (UNBOUNDP (mswindows_handle_wm_initmenu (
-                       (HMENU) wParam,
-                       XFRAME (mswindows_find_frame (hwnd)))))
-      SendMessage (hwnd, WM_CANCELMODE, 0, 0);
-    break;
-
-  case WM_INITMENUPOPUP:
-    if (!HIWORD(lParam))
-      {
-       if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
-                       (HMENU) wParam,
-                        XFRAME (mswindows_find_frame (hwnd)))))
-         SendMessage (hwnd, WM_CANCELMODE, 0, 0);
-      }
-    break;
+    case WM_INITMENU:
+      if (UNBOUNDP (mswindows_handle_wm_initmenu (
+                                                 (HMENU) wParam,
+                                                 XFRAME (mswindows_find_frame (hwnd)))))
+       SendMessage (hwnd, WM_CANCELMODE, 0, 0);
+      break;
+
+    case WM_INITMENUPOPUP:
+      if (!HIWORD(lParam))
+       {
+         if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
+                                                          (HMENU) wParam,
+                                                          XFRAME (mswindows_find_frame (hwnd)))))
+           SendMessage (hwnd, WM_CANCELMODE, 0, 0);
+       }
+      break;
 
 #endif /* HAVE_MENUBARS */
 
-  case WM_COMMAND:
-    {
-      WORD id = LOWORD (wParam);
-      WORD nid = HIWORD (wParam);
-      HWND cid = (HWND)lParam;
-      frame = XFRAME (mswindows_find_frame (hwnd));
+    case WM_COMMAND:
+      {
+       WORD id = LOWORD (wParam);
+       WORD nid = HIWORD (wParam);
+       HWND cid = (HWND)lParam;
+       frame = XFRAME (mswindows_find_frame (hwnd));
 
 #ifdef HAVE_TOOLBARS
-      if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
-       break;
+       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
+         break;
 #endif
-      /* widgets in a buffer only eval a callback for suitable events.*/
-      switch (nid)
-       {
-       case BN_CLICKED:
-       case EN_CHANGE:
-       case CBN_EDITCHANGE:
-       case CBN_SELCHANGE:
-         if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
-           return 0;
-       }
-      /* menubars always must come last since the hashtables do not
-         always exist*/
+       /* widgets in a buffer only eval a callback for suitable events.*/
+       switch (nid)
+         {
+         case BN_CLICKED:
+         case EN_CHANGE:
+         case CBN_EDITCHANGE:
+         case CBN_SELCHANGE:
+           if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
+             return 0;
+         }
+       /* menubars always must come last since the hashtables do not
+          always exist*/
 #ifdef HAVE_MENUBARS
-      if (!NILP (mswindows_handle_wm_command (frame, id)))
-       break;
+       if (!NILP (mswindows_handle_wm_command (frame, id)))
+         break;
 #endif
 
-      return DefWindowProc (hwnd, message, wParam, lParam);
-      /* Bite me - a spurious command. This used to not be able to
-         happen but with the introduction of widgets its now
-         possible. */
-    }
-  break;
+       return DefWindowProc (hwnd, message, wParam, lParam);
+       /* Bite me - a spurious command. This used to not be able to
+          happen but with the introduction of widgets its now
+          possible. */
+      }
+      break;
 
-  case WM_CTLCOLORBTN:
-  case WM_CTLCOLORLISTBOX:
-  case WM_CTLCOLOREDIT:
-  case WM_CTLCOLORSTATIC:
-  case WM_CTLCOLORSCROLLBAR:
-    {
-      /* if we get an opportunity to paint a widget then do so if
-         there is an appropriate face */
-      HWND crtlwnd = (HWND)lParam;
-      LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
-      if (ii)
-       {
-         Lisp_Object image_instance;
-         VOID_TO_LISP (image_instance, ii);
-         if (IMAGE_INSTANCEP (image_instance)
-             && 
-             IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
-             &&
-             !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
-           {
-             /* set colors for the buttons */
-             HDC hdc = (HDC)wParam;
-             if (last_widget_brushed != ii)
-               {
-                 if (widget_brush)
-                   DeleteObject (widget_brush);
-                 widget_brush = CreateSolidBrush 
-                   (COLOR_INSTANCE_MSWINDOWS_COLOR 
-                    (XCOLOR_INSTANCE 
-                     (FACE_BACKGROUND 
-                      (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
-                       XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
-               }
-             last_widget_brushed = ii;
-             SetTextColor
-               (hdc,
-                COLOR_INSTANCE_MSWINDOWS_COLOR 
-                (XCOLOR_INSTANCE 
-                 (FACE_FOREGROUND 
-                  (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
-                   XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
-             SetBkMode (hdc, OPAQUE);
-             SetBkColor
-               (hdc,
-                COLOR_INSTANCE_MSWINDOWS_COLOR 
-                (XCOLOR_INSTANCE 
-                 (FACE_BACKGROUND 
-                  (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
-                   XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
-             return (LRESULT)widget_brush;
-           }
-       }
-    }
-    goto defproc;
+    case WM_CTLCOLORBTN:
+    case WM_CTLCOLORLISTBOX:
+    case WM_CTLCOLOREDIT:
+    case WM_CTLCOLORSTATIC:
+    case WM_CTLCOLORSCROLLBAR:
+      {
+       /* if we get an opportunity to paint a widget then do so if
+          there is an appropriate face */
+       HWND crtlwnd = (HWND)lParam;
+       LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
+       if (ii)
+         {
+           Lisp_Object image_instance;
+           VOID_TO_LISP (image_instance, ii);
+           if (IMAGE_INSTANCEP (image_instance)
+               &&
+               IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
+             {
+               /* set colors for the buttons */
+               HDC hdc = (HDC)wParam;
+               if (last_widget_brushed != ii)
+                 {
+                   if (widget_brush)
+                     DeleteObject (widget_brush);
+                   widget_brush = CreateSolidBrush
+                     (COLOR_INSTANCE_MSWINDOWS_COLOR
+                      (XCOLOR_INSTANCE
+                       (FACE_BACKGROUND
+                        (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                         XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+                 }
+               last_widget_brushed = ii;
+               SetTextColor
+                 (hdc,
+                  COLOR_INSTANCE_MSWINDOWS_COLOR
+                  (XCOLOR_INSTANCE
+                   (FACE_FOREGROUND
+                    (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                     XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+               SetBkMode (hdc, OPAQUE);
+               SetBkColor
+                 (hdc,
+                  COLOR_INSTANCE_MSWINDOWS_COLOR
+                  (XCOLOR_INSTANCE
+                   (FACE_BACKGROUND
+                    (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
+                     XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
+               return (LRESULT)widget_brush;
+             }
+         }
+      }
+      goto defproc;
 
 #ifdef HAVE_DRAGNDROP
-  case WM_DROPFILES:   /* implementation ripped-off from event-Xt.c */
-    {
-      UINT filecount, i, len;
-      POINT point;
-      char* filename;
-#ifdef __CYGWIN32__
-      char* fname;
-#endif
-      Lisp_Object l_dndlist = Qnil, l_item = Qnil;
-      struct gcpro gcpro1, gcpro2, gcpro3;
+    case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
+      {
+       UINT filecount, i, len;
+       POINT point;
+       char* filename;
+       char* fname;
 
-      emacs_event = Fmake_event (Qnil, Qnil);
-      event = XEVENT(emacs_event);
+       Lisp_Object l_dndlist = Qnil, l_item = Qnil;
+       struct gcpro gcpro1, gcpro2, gcpro3;
 
-      GCPRO3 (emacs_event, l_dndlist, l_item);
+       emacs_event = Fmake_event (Qnil, Qnil);
+       event = XEVENT(emacs_event);
 
-      if (!DragQueryPoint ((HANDLE) wParam, &point))
-       point.x = point.y = -1;         /* outside client area */
+       GCPRO3 (emacs_event, l_dndlist, l_item);
 
-      event->event_type = misc_user_event;
-      event->channel = mswindows_find_frame(hwnd);
-      event->timestamp = GetMessageTime();
-      event->event.misc.button = 1;            /* #### Should try harder */
-      event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
-      event->event.misc.x = point.x;
-      event->event.misc.y = point.y;
-      event->event.misc.function = Qdragdrop_drop_dispatch;
+       if (!DragQueryPoint ((HDROP) wParam, &point))
+         point.x = point.y = -1;               /* outside client area */
+
+       event->event_type = misc_user_event;
+       event->channel = mswindows_find_frame(hwnd);
+       event->timestamp = GetMessageTime();
+       event->event.misc.button = 1;           /* #### Should try harder */
+       event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
+       event->event.misc.x = point.x;
+       event->event.misc.y = point.y;
+       event->event.misc.function = Qdragdrop_drop_dispatch;
+
+       filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
+       for (i=0; i<filecount; i++)
+         {
+           len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
+           /* The URLs that we make here aren't correct according to section
+            * 3.10 of rfc1738 because they're missing the //<host>/ part and
+            * because they may contain reserved characters. But that's OK -
+            * they just need to be good enough to keep dragdrop.el happy. */
+           fname = (char *)xmalloc (len+1);
+           DragQueryFile ((HANDLE) wParam, i, fname, len+1);
+
+           /* May be a shell link aka "shortcut" - replace fname if so */
+#if !(defined(__CYGWIN32__) || defined(__MINGW32__))
+           /* cygwin doesn't define this COM stuff */
+           if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
+             {
+               IShellLink* psl;
+
+               if (CoCreateInstance (&CLSID_ShellLink, NULL,
+                                     CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
+                 { 
+                   IPersistFile* ppf;
+
+                   if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
+                                                    &ppf) == S_OK)
+                     {
+                       WORD wsz[MAX_PATH];
+                       WIN32_FIND_DATA wfd;
+                       LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
+
+                       MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
+
+                       if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
+                           (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
+                                                  &wfd, 0)==S_OK))
+                         {
+                           xfree (fname);
+                           fname = resolved;
+                           len = strlen (fname);
+                         }
+
+                       ppf->lpVtbl->Release (ppf);
+                     }
+
+                   psl->lpVtbl->Release (psl);
+                 }
+             }
+#endif
 
-      filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
-      for (i=0; i<filecount; i++)
-       {
-         len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
-         /* The URLs that we make here aren't correct according to section
-          * 3.10 of rfc1738 because they're missing the //<host>/ part and
-          * because they may contain reserved characters. But that's OK. */
 #ifdef __CYGWIN32__
-         fname = (char *)xmalloc (len+1);
-         DragQueryFile ((HANDLE) wParam, i, fname, len+1);
-         filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
-         strcpy (filename, "file:");
-         cygwin32_win32_to_posix_path_list (fname, filename+5);
-         xfree (fname);
+           filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
+           strcpy (filename, "file:");
+           cygwin32_win32_to_posix_path_list (fname, filename+5);
 #else
-         filename = (char *)xmalloc (len+6);
-         strcpy (filename, "file:");
-         DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
-         dostounix_filename (filename+5);
+           filename = (char *)xmalloc (len+6);
+           strcat (strcpy (filename, "file:"), fname);
+           dostounix_filename (filename+5);
 #endif
-         l_item = make_string (filename, strlen (filename));
-         l_dndlist = Fcons (l_item, l_dndlist);
-         xfree (filename);
-       }
-      DragFinish ((HANDLE) wParam);
+           xfree (fname);
+           l_item = make_string (filename, strlen (filename));
+           l_dndlist = Fcons (l_item, l_dndlist);
+           xfree (filename);
+         }
+       DragFinish ((HDROP) wParam);
 
-      event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
-      mswindows_enqueue_dispatch_event (emacs_event);
-      UNGCPRO;
-    }
-  break;
+       event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
+       mswindows_enqueue_dispatch_event (emacs_event);
+       UNGCPRO;
+      }
+      break;
 #endif
 
-  defproc:
-  default:
-    return DefWindowProc (hwnd, message, wParam, lParam);
-  }
+    defproc:
+    default:
+      return DefWindowProc (hwnd, message, wParam, lParam);
+    }
   return (0);
 }
 
@@ -2439,16 +2583,16 @@ int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
 
   if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
     {
-      mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
-      mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
+      mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
+      mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
     }
   else
     {
-      mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
-      mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
+      mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
+      mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
     }
 
-  mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
+  mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0;
 
   return mods;
 }
@@ -2506,8 +2650,8 @@ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
        case VK_DELETE:         return KEYSYM ("kp-delete");
        case VK_HELP:           return KEYSYM ("help");
 #if 0  /* FSF Emacs allows these to return configurable syms/mods */
-       case VK_LWIN            return KEYSYM ("");
-       case VK_RWIN            return KEYSYM ("");
+         case VK_LWIN          return KEYSYM ("");
+         case VK_RWIN          return KEYSYM ("");
 #endif
        case VK_APPS:           return KEYSYM ("menu");
        case VK_NUMPAD0:        return KEYSYM ("kp-0");
@@ -2609,7 +2753,7 @@ emacs_mswindows_add_timeout (EMACS_TIME thyme)
 static void
 emacs_mswindows_remove_timeout (int id)
 {
-  struct Lisp_Event match_against;
+  Lisp_Event match_against;
   Lisp_Object emacs_event;
 
   if (KillTimer (NULL, id))
@@ -2645,7 +2789,7 @@ emacs_mswindows_event_pending_p (int user_p)
  * Return the next event
  */
 static void
-emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
+emacs_mswindows_next_event (Lisp_Event *emacs_event)
 {
   Lisp_Object event, event2;
 
@@ -2661,13 +2805,21 @@ emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
  * Handle a magic event off the dispatch queue.
  */
 static void
-emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
+emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
 {
   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
     {
     case XM_BUMPQUEUE:
       break;
-    
+
+    case WM_PAINT:
+      {
+       struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
+       mswindows_handle_paint (f);
+       (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
+      }
+      break;
+
     case WM_SETFOCUS:
     case WM_KILLFOCUS:
       {
@@ -2695,13 +2847,13 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
     case XM_UNMAPFRAME:
       {
        Lisp_Object frame = EVENT_CHANNEL (emacs_event);
-       va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) 
+       va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
                               == XM_MAPFRAME ?
-                              Qmap_frame_hook : Qunmap_frame_hook, 
+                              Qmap_frame_hook : Qunmap_frame_hook,
                               1, frame);
       }
       break;
-                           
+
       /* #### What about Enter & Leave */
 #if 0
       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
@@ -2715,7 +2867,7 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
 
 #ifndef HAVE_MSG_SELECT
 static HANDLE
-get_process_input_waitable (struct Lisp_Process *process)
+get_process_input_waitable (Lisp_Process *process)
 {
   Lisp_Object instr, outstr, p;
   XSETPROCESS (p, process);
@@ -2726,12 +2878,12 @@ get_process_input_waitable (struct Lisp_Process *process)
          ? get_winsock_stream_waitable (XLSTREAM (instr))
          : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
 #else
-    return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
+  return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
 #endif
 }
 
 static void
-emacs_mswindows_select_process (struct Lisp_Process *process)
+emacs_mswindows_select_process (Lisp_Process *process)
 {
   HANDLE hev = get_process_input_waitable (process);
 
@@ -2756,7 +2908,7 @@ emacs_mswindows_select_process (struct Lisp_Process *process)
 }
 
 static void
-emacs_mswindows_unselect_process (struct Lisp_Process *process)
+emacs_mswindows_unselect_process (Lisp_Process *process)
 {
   /* Process handle is removed in the event loop as soon
      as it is signaled, so don't bother here about it */
@@ -2790,38 +2942,37 @@ emacs_mswindows_unselect_console (struct console *con)
 static void
 emacs_mswindows_quit_p (void)
 {
-  MSG msg;
-
   /* Quit cannot happen in modal loop: all program
      input is dedicated to Windows. */
   if (mswindows_in_modal_loop)
     return;
 
-  /* Drain windows queue. This sets up number of quit characters in the queue
-   * (and also processes wm focus change, move, resize, etc messages).
-   * We don't want to process WM_PAINT messages because this function can be
-   * called from almost anywhere and the windows' states may be changing. */
-  while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
-        PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
-      DispatchMessage (&msg);
+  /* Drain windows queue. This sets up number of quit characters in
+     the queue */
+  mswindows_drain_windows_queue ();
 
   if (mswindows_quit_chars_count > 0)
     {
       /* Yes there's a hidden one... Throw it away */
-      struct Lisp_Event match_against;
+      Lisp_Event match_against;
       Lisp_Object emacs_event;
+      int critical_p = 0;
 
       match_against.event_type = key_press_event;
       match_against.event.key.modifiers = FAKE_MOD_QUIT;
 
-      emacs_event = mswindows_cancel_dispatch_event (&match_against);
-      assert (!NILP (emacs_event));
+      while (mswindows_quit_chars_count-- > 0)
+       {
+         emacs_event = mswindows_cancel_dispatch_event (&match_against);
+         assert (!NILP (emacs_event));
+         
+         if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
+           critical_p = 1;
 
-      Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
-                   ? Qcritical : Qt);
+         Fdeallocate_event(emacs_event);
+       }
 
-      Fdeallocate_event(emacs_event);
-      --mswindows_quit_chars_count;
+      Vquit_flag = critical_p ? Qcritical : Qt;
     }
 }
 
@@ -2899,7 +3050,7 @@ emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
 
 USID
 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
-                                        Lisp_Object outstream)
+                                   Lisp_Object outstream)
 {
   /* Oh nothing special here for Win32 at all */
 #if defined (HAVE_UNIX_PROCESSES)
@@ -2933,7 +3084,7 @@ emacs_mswindows_delete_stream_pair (Lisp_Object instream,
    If we've still got pointers to it in this file, we're gonna lose hard.
  */
 void
-debug_process_finalization (struct Lisp_Process *p)
+debug_process_finalization (Lisp_Process *p)
 {
 #if 0 /* #### */
   Lisp_Object instr, outstr;
@@ -2961,6 +3112,7 @@ reinit_vars_of_event_mswindows (void)
   mswindows_event_stream = xnew (struct event_stream);
 
   mswindows_event_stream->event_pending_p      = emacs_mswindows_event_pending_p;
+  mswindows_event_stream->force_event_pending = 0;
   mswindows_event_stream->next_event_cb                = emacs_mswindows_next_event;
   mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
   mswindows_event_stream->add_timeout_cb       = emacs_mswindows_add_timeout;
@@ -2969,10 +3121,10 @@ reinit_vars_of_event_mswindows (void)
   mswindows_event_stream->select_console_cb    = emacs_mswindows_select_console;
   mswindows_event_stream->unselect_console_cb  = emacs_mswindows_unselect_console;
 #ifdef HAVE_MSG_SELECT
-  mswindows_event_stream->select_process_cb    = 
-    (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
-  mswindows_event_stream->unselect_process_cb  = 
-    (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
+  mswindows_event_stream->select_process_cb    =
+    (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
+  mswindows_event_stream->unselect_process_cb  =
+    (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
   mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
   mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
 #else
@@ -2996,18 +3148,21 @@ vars_of_event_mswindows (void)
   mswindows_s_dispatch_event_queue = Qnil;
   staticpro (&mswindows_s_dispatch_event_queue);
   mswindows_s_dispatch_event_queue_tail = Qnil;
-  pdump_wire (&mswindows_u_dispatch_event_queue_tail);
+  pdump_wire (&mswindows_s_dispatch_event_queue_tail);
 
   mswindows_error_caught_in_modal_loop = Qnil;
   staticpro (&mswindows_error_caught_in_modal_loop);
 
-  DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /*
-*Controls whether pressing and releasing the Meta (Alt) key should
-activate the menubar.
+  DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
+              &mswindows_alt_by_itself_activates_menu /*
+*Controls whether pressing and releasing the Alt key activates the menubar.
+This applies only if no intervening key was pressed.  See also
+`menu-accelerator-enabled', which is probably the behavior you actually want.
 Default is t.
 */ );
 
-  DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
+  DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
+              &mswindows_dynamic_frame_resize /*
 *Controls redrawing frame contents during mouse-drag or keyboard resize
 operation. When non-nil, the frame is redrawn while being resized. When
 nil, frame is not redrawn, and exposed areas are filled with default
@@ -3017,8 +3172,8 @@ settings.
 Default is t on fast machines, nil on slow.
 */ );
 
-/* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
-  DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
+  DEFVAR_INT ("mswindows-mouse-button-tolerance",
+             &mswindows_mouse_button_tolerance /*
 *Analogue of double click interval for faking middle mouse events.
 The value is the minimum time in milliseconds that must elapse between
 left/right button down events before they are considered distinct events.
@@ -3027,12 +3182,12 @@ button down event is generated instead.
 If negative or zero, currently set system default is used instead.
 */ );
 
-/* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
   DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
 Number of physical mouse buttons.
 */ );
 
-  DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
+  DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
+             &mswindows_mouse_button_max_skew_x /*
 *Maximum horizontal distance in pixels between points in which left and
 right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
@@ -3040,7 +3195,8 @@ by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
 */ );
 
-  DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
+  DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
+             &mswindows_mouse_button_max_skew_y /*
 *Maximum vertical distance in pixels between points in which left and
 right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
@@ -3051,7 +3207,7 @@ If negative or zero, currently set system default is used instead.
   mswindows_mouse_button_max_skew_x = 0;
   mswindows_mouse_button_max_skew_y = 0;
   mswindows_mouse_button_tolerance = 0;
-  mswindows_meta_activates_menu = 1;
+  mswindows_alt_by_itself_activates_menu = 1;
 }
 
 void