diff src/event-msw.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents 1f50e6fe4f3f
children a86b2b5e0111
line wrap: on
line diff
--- a/src/event-msw.c	Mon Aug 13 11:12:06 2007 +0200
+++ b/src/event-msw.c	Mon Aug 13 11:13:30 2007 +0200
@@ -56,6 +56,7 @@
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
+#include "select.h"
 #include "sysproc.h"
 #include "syswait.h"
 #include "systime.h"
@@ -72,6 +73,10 @@
 #include <io.h>
 #include <errno.h>
 
+#if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20)
+typedef NMHDR *LPNMHDR;
+#endif
+
 #ifdef HAVE_MENUBARS
 #define ADJR_MENUFLAG TRUE
 #else
@@ -85,16 +90,10 @@
 /* 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);
+static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
+						  int extendedp);
 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
 static void mswindows_set_chord_timer (HWND hwnd);
 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
@@ -119,6 +118,9 @@
 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
 
+/* For speed: whether there is a WM_PAINT magic message in the system queue */
+static int mswindows_paint_pending = 0;
+
 /* The number of things we can wait on */
 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
 
@@ -129,6 +131,7 @@
 /* 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;
@@ -140,6 +143,7 @@
 
 /* These are Lisp integers; see DEFVARS in this file for description. */
 int mswindows_dynamic_frame_resize;
+int mswindows_meta_activates_menu;
 int mswindows_num_mouse_buttons;
 int mswindows_mouse_button_max_skew_x;
 int mswindows_mouse_button_max_skew_y;
@@ -193,7 +197,7 @@
 };
 
 #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
@@ -265,7 +269,7 @@
 
       /* 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. */
@@ -354,11 +358,11 @@
   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)
@@ -367,7 +371,7 @@
       /* 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);
@@ -418,7 +422,7 @@
 	      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;
@@ -427,11 +431,11 @@
   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 */
@@ -463,7 +467,7 @@
   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	 */
@@ -490,7 +494,7 @@
 
   for (;;)
     {
-      DWORD bytes_written; 
+      DWORD bytes_written;
 
       /* Block on event and wait for a job */
       InterlockedIncrement (&s->idle_p);
@@ -527,7 +531,7 @@
   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);
@@ -556,7 +560,7 @@
 }
 #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);
@@ -665,7 +669,7 @@
     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);
@@ -698,7 +702,7 @@
     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);
@@ -711,8 +715,8 @@
   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);
 
@@ -739,7 +743,7 @@
 
   if (size == 0)
     return 0;
-  
+
   {
     ResetEvent (str->ov.hEvent);
 
@@ -785,7 +789,7 @@
 }
 
 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);
@@ -853,7 +857,7 @@
 /************************************************************************/
 
 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
@@ -861,7 +865,7 @@
 	  || sevt->event_type == misc_user_event);
 }
 
-/* 
+/*
  * Add an emacs event to the proper dispatch queue
  */
 static void
@@ -869,7 +873,7 @@
 {
   int user_p = mswindows_user_event_p (XEVENT(event));
   enqueue_event (event,
-		 user_p ? &mswindows_u_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);
@@ -889,10 +893,11 @@
 				   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;
 
@@ -900,24 +905,24 @@
 }
 
 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);
 
@@ -929,7 +934,7 @@
 }
 
 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
@@ -937,19 +942,19 @@
      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);
@@ -966,7 +971,7 @@
       event->event_type = button_release_event;
       ReleaseCapture ();
     }
-  
+
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
@@ -974,7 +979,7 @@
 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();
@@ -992,16 +997,16 @@
 mswindows_dequeue_dispatch_event ()
 {
   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);
 
@@ -1026,14 +1031,14 @@
  */
 
 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 : 
+  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 : 
+  Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
     			       &mswindows_s_dispatch_event_queue_tail;
 
   assert (match->event_type == timeout_event
@@ -1041,7 +1046,7 @@
 
   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) :
@@ -1056,7 +1061,7 @@
 	      if (EQ (*tail, event))
 		*tail = previous_event;
 	    }
-	  
+
 	  return event;
 	}
       previous_event = event;
@@ -1097,7 +1102,7 @@
   if (ix < 0)
     return;
 
-  mswindows_waitable_handles [ix] = 
+  mswindows_waitable_handles [ix] =
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
 #endif /* HAVE_MSG_SELECT */
@@ -1121,7 +1126,7 @@
 {
   Lisp_Object tmp;
 
-  ++mswindows_in_modal_loop; 
+  ++mswindows_in_modal_loop;
   tmp = condition_case_1 (Qt,
 			  bfun, barg,
 			  mswindows_modal_loop_error_handler, Qnil);
@@ -1145,7 +1150,7 @@
 }
 
 /*
- * 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
@@ -1169,7 +1174,7 @@
 
   Fdeallocate_event (event);
   UNGCPRO;
-  
+
   /* Qt becomes return value of mswindows_pump_outstanding_events
      once we get here */
   return Qt;
@@ -1217,33 +1222,58 @@
   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);
   UNGCPRO;
   return result;
 }
 
-static void 
+/*
+ * 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 ()
 {
   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
+      /* 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 )
+      if (GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD)
 	{
 	  TranslateMessage (&msg);
 	}
+      else if (msg.message == 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 (msg.wParam == 0);
+
+	  if (!mswindows_paint_pending)
+	    {
+	      /* Queue a magic event for handling when safe */
+	      mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
+	      mswindows_paint_pending = 1;
+	    }
+
+	  /* 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
@@ -1276,7 +1306,7 @@
       /* 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);
@@ -1301,10 +1331,6 @@
       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))
     {
@@ -1313,7 +1339,7 @@
       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
@@ -1324,9 +1350,10 @@
 	}
 
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
-      
+
       if (active == 0)
 	{
+	  assert (!badly_p);
 	  return;		/* timeout */
 	}
       else if (active > 0)
@@ -1335,7 +1362,7 @@
 	    {
 	      mswindows_drain_windows_queue ();
 	    }
-#ifdef HAVE_TTY	  
+#ifdef HAVE_TTY
 	  /* Look for a TTY event */
 	  for (i = 0; i < MAXDESC-1; i++)
 	    {
@@ -1346,8 +1373,8 @@
 		{
 		  struct console *c = tty_find_console_from_fd (i);
 		  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-		  struct Lisp_Event* event = XEVENT (emacs_event);
-		  
+		  Lisp_Event* event = XEVENT (emacs_event);
+
 		  assert (c);
 		  if (read_event_from_tty_or_stream_desc (event, c, i))
 		    {
@@ -1364,9 +1391,9 @@
 		{
 		  if (FD_ISSET (i, &process_only_mask))
 		    {
-		      struct Lisp_Process *p =
+		      Lisp_Process *p =
 			get_process_from_usid (FD_TO_USID(i));
-		      
+
 		      mswindows_enqueue_process_event (p);
 		    }
 		  else
@@ -1405,7 +1432,7 @@
     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 */
@@ -1420,7 +1447,7 @@
       {
 	int ix = active - WAIT_OBJECT_0;
 	/* First, try to find which process' output has signaled */
-	struct Lisp_Process *p = 
+	Lisp_Process *p =
 	  get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
 	if (p != NULL)
 	  {
@@ -1448,14 +1475,14 @@
 /*                           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;
@@ -1470,7 +1497,7 @@
   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
@@ -1481,9 +1508,9 @@
 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;
@@ -1500,7 +1527,7 @@
 	  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))
@@ -1513,7 +1540,7 @@
           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';
@@ -1581,16 +1608,64 @@
 	  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
+ */
+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_meta_activates_menu && vkey == VK_MENU)
+    return 1;
+
+  return 0;
+}
+
+/*
  * The windows procedure for the window class XEMACS_CLASS
  */
 LRESULT WINAPI
@@ -1601,12 +1676,19 @@
   Lisp_Object emacs_event = Qnil;
   Lisp_Object fobj = Qnil;
 
-  struct Lisp_Event *event;
+  Lisp_Event *event;
   struct frame *frame;
   struct mswindows_frame* msframe;
 
   switch (message)
   {
+  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;
+
   case WM_ERASEBKGND:
     /* Erase background only during non-dynamic sizing */
     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
@@ -1638,7 +1720,10 @@
 	  SetKeyboardState (keymap);
 	}
     };
-    goto defproc;
+    if (key_needs_default_processing_p (wParam))
+      goto defproc;
+    else
+      break;
 
   case WM_KEYDOWN:
   case WM_SYSKEYDOWN:
@@ -1654,21 +1739,23 @@
       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 those keys for which TranslateMessage won't generate a WM_CHAR */
-      if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
+      /* Handle non-printables */
+      if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
+							 extendedp)))
 	mswindows_enqueue_keypress_event (hwnd, keysym, mods);
-      else
+      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;
@@ -1680,9 +1767,9 @@
 	   * 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 [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+	    keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
 	  else if (wParam == VK_MENU)
-	    keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
+	    keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
 
 	  memcpy (keymap_orig, keymap, 256);
 
@@ -1692,7 +1779,8 @@
 	  /* 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))
+	  if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80)
+	      || !(keymap [VK_RMENU] & 0x80))
 	    {
 	      keymap [VK_LCONTROL] = 0;
 	      keymap [VK_CONTROL] = 0;
@@ -1728,10 +1816,10 @@
 	  SetKeyboardState (keymap_orig);
 	} /* else */
     }
-    /* F10 causes menu activation by default. We do not want this */
-    if (wParam != VK_F10)
+    if (key_needs_default_processing_p (wParam))
       goto defproc;
-    break;
+    else
+      break;
 
   case WM_MBUTTONDOWN:
   case WM_MBUTTONUP:
@@ -1741,7 +1829,7 @@
     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();
@@ -1863,7 +1951,7 @@
       }
     msframe->last_click_time =  GetMessageTime();
     break;
-	
+
   case WM_TIMER:
     if (wParam == BUTTON_2_TIMER_ID)
       {
@@ -1912,7 +2000,7 @@
       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;
@@ -1925,18 +2013,21 @@
 				       Qcancel_mode_internal, Qnil);
     break;
 
-#ifdef HAVE_TOOLBARS
   case WM_NOTIFY:
     {
-      LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
-      Lisp_Object btext;
-      if (tttext->hdr.code ==  TTN_NEEDTEXT)    
+      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, 
-						      tttext->hdr.idFrom );
-	  
+	  btext = mswindows_get_toolbar_button_text ( frame,
+						      nmhdr->idFrom );
+
 	  tttext->lpszText = NULL;
 	  tttext->hinst = NULL;
 
@@ -1944,29 +2035,44 @@
 	    {
 	      /* 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);
+	      TO_EXTERNAL_FORMAT (LISP_STRING, btext,
+				  C_STRING_ALLOCA, tttext->lpszText,
+				  Qnative);
 	    }
-#if 0
-	  tttext->uFlags |= TTF_DI_SETITEM;
 #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;
-#endif
-    
+
   case WM_PAINT:
-    {
-      PAINTSTRUCT paintStruct;
-      
-      frame = XFRAME (mswindows_find_frame (hwnd));
-
-      BeginPaint (hwnd, &paintStruct);
-      mswindows_redraw_exposed_area (frame,
-			paintStruct.rcPaint.left, paintStruct.rcPaint.top,
-			paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
-      EndPaint (hwnd, &paintStruct);
-    }
+    /* 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:
@@ -2008,8 +2114,8 @@
 	  if (FRAME_MSWINDOWS_TARGET_RECT (frame))
 	    {
 	      /* Yes, we have to size again */
-	      mswindows_size_frame_internal ( frame, 
-					      FRAME_MSWINDOWS_TARGET_RECT 
+	      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. */
@@ -2024,7 +2130,7 @@
 	      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 ();
 	    }
@@ -2115,7 +2221,24 @@
 	  SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
 	}
       UNGCPRO;
-      break;     
+      break;
+    }
+
+  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;
     }
 #endif
 
@@ -2189,10 +2312,8 @@
 	  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)))
+	      IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
 	    {
 	      /* set colors for the buttons */
 	      HDC hdc = (HDC)wParam;
@@ -2200,27 +2321,27 @@
 		{
 		  if (widget_brush)
 		    DeleteObject (widget_brush);
-		  widget_brush = CreateSolidBrush 
-		    (COLOR_INSTANCE_MSWINDOWS_COLOR 
-		     (XCOLOR_INSTANCE 
-		      (FACE_BACKGROUND 
+		  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 
+		 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 
+		 COLOR_INSTANCE_MSWINDOWS_COLOR
+		 (XCOLOR_INSTANCE
+		  (FACE_BACKGROUND
 		   (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
 		    XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
 	      return (LRESULT)widget_brush;
@@ -2392,67 +2513,100 @@
  * Only returns non-Qnil for keys that don't generate WM_CHAR messages
  * or whose ASCII codes (like space) xemacs doesn't like.
  * Virtual key values are defined in winresrc.h
- * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
  */
-Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
+Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
+					   int extendedp)
 {
-  switch (mswindows_key)
-  {
-  /* First the predefined ones */
-  case VK_BACK:		return QKbackspace;
-  case VK_TAB:		return QKtab;
-  case '\n':		return QKlinefeed;  /* No VK_LINEFEED in winresrc.h */
-  case VK_RETURN:	return QKreturn;
-  case VK_ESCAPE:	return QKescape;
-  case VK_SPACE:	return QKspace;
-  case VK_DELETE:	return QKdelete;
-
-  /* The rest */
-  case VK_CLEAR:	return KEYSYM ("clear");  /* Should do ^L ? */
-  case VK_PRIOR:	return KEYSYM ("prior");
-  case VK_NEXT:		return KEYSYM ("next");
-  case VK_END:		return KEYSYM ("end");
-  case VK_HOME:		return KEYSYM ("home");
-  case VK_LEFT:		return KEYSYM ("left");
-  case VK_UP:		return KEYSYM ("up");
-  case VK_RIGHT:	return KEYSYM ("right");
-  case VK_DOWN:		return KEYSYM ("down");
-  case VK_SELECT:	return KEYSYM ("select");
-  case VK_PRINT:	return KEYSYM ("print");
-  case VK_EXECUTE:	return KEYSYM ("execute");
-  case VK_SNAPSHOT:	return KEYSYM ("print");
-  case VK_INSERT:	return KEYSYM ("insert");
-  case VK_HELP:		return KEYSYM ("help");
-#if 0	/* XXX What are these supposed to do? */
-  case VK_LWIN		return KEYSYM ("");
-  case VK_RWIN		return KEYSYM ("");
+  if (extendedp)	/* Keys not present on a 82 key keyboard */
+    {
+      switch (mswindows_key)
+        {
+	case VK_RETURN:		return KEYSYM ("kp-enter");
+	case VK_PRIOR:		return KEYSYM ("prior");
+	case VK_NEXT:		return KEYSYM ("next");
+	case VK_END:		return KEYSYM ("end");
+	case VK_HOME:		return KEYSYM ("home");
+	case VK_LEFT:		return KEYSYM ("left");
+	case VK_UP:		return KEYSYM ("up");
+	case VK_RIGHT:		return KEYSYM ("right");
+	case VK_DOWN:		return KEYSYM ("down");
+	case VK_INSERT:		return KEYSYM ("insert");
+	case VK_DELETE:		return QKdelete;
+	}
+    }
+  else
+    {
+      switch (mswindows_key)
+	{
+	case VK_BACK:		return QKbackspace;
+	case VK_TAB:		return QKtab;
+	case '\n':		return QKlinefeed;
+	case VK_CLEAR:		return KEYSYM ("clear");
+	case VK_RETURN:		return QKreturn;
+	case VK_ESCAPE:		return QKescape;
+	case VK_SPACE:		return QKspace;
+	case VK_PRIOR:		return KEYSYM ("kp-prior");
+	case VK_NEXT:		return KEYSYM ("kp-next");
+	case VK_END:		return KEYSYM ("kp-end");
+	case VK_HOME:		return KEYSYM ("kp-home");
+	case VK_LEFT:		return KEYSYM ("kp-left");
+	case VK_UP:		return KEYSYM ("kp-up");
+	case VK_RIGHT:		return KEYSYM ("kp-right");
+	case VK_DOWN:		return KEYSYM ("kp-down");
+	case VK_SELECT:		return KEYSYM ("select");
+	case VK_PRINT:		return KEYSYM ("print");
+	case VK_EXECUTE:	return KEYSYM ("execute");
+	case VK_SNAPSHOT:	return KEYSYM ("print");
+	case VK_INSERT:		return KEYSYM ("kp-insert");
+	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 ("");
 #endif
-  case VK_APPS:		return KEYSYM ("menu");
-  case VK_F1:		return KEYSYM ("f1");
-  case VK_F2:		return KEYSYM ("f2");
-  case VK_F3:		return KEYSYM ("f3");
-  case VK_F4:		return KEYSYM ("f4");
-  case VK_F5:		return KEYSYM ("f5");
-  case VK_F6:		return KEYSYM ("f6");
-  case VK_F7:		return KEYSYM ("f7");
-  case VK_F8:		return KEYSYM ("f8");
-  case VK_F9:		return KEYSYM ("f9");
-  case VK_F10:		return KEYSYM ("f10");
-  case VK_F11:		return KEYSYM ("f11");
-  case VK_F12:		return KEYSYM ("f12");
-  case VK_F13:		return KEYSYM ("f13");
-  case VK_F14:		return KEYSYM ("f14");
-  case VK_F15:		return KEYSYM ("f15");
-  case VK_F16:		return KEYSYM ("f16");
-  case VK_F17:		return KEYSYM ("f17");
-  case VK_F18:		return KEYSYM ("f18");
-  case VK_F19:		return KEYSYM ("f19");
-  case VK_F20:		return KEYSYM ("f20");
-  case VK_F21:		return KEYSYM ("f21");
-  case VK_F22:		return KEYSYM ("f22");
-  case VK_F23:		return KEYSYM ("f23");
-  case VK_F24:		return KEYSYM ("f24");
-  }
+	case VK_APPS:		return KEYSYM ("menu");
+	case VK_NUMPAD0:	return KEYSYM ("kp-0");
+	case VK_NUMPAD1:	return KEYSYM ("kp-1");
+	case VK_NUMPAD2:	return KEYSYM ("kp-2");
+	case VK_NUMPAD3:	return KEYSYM ("kp-3");
+	case VK_NUMPAD4:	return KEYSYM ("kp-4");
+	case VK_NUMPAD5:	return KEYSYM ("kp-5");
+	case VK_NUMPAD6:	return KEYSYM ("kp-6");
+	case VK_NUMPAD7:	return KEYSYM ("kp-7");
+	case VK_NUMPAD8:	return KEYSYM ("kp-8");
+	case VK_NUMPAD9:	return KEYSYM ("kp-9");
+	case VK_MULTIPLY:	return KEYSYM ("kp-multiply");
+	case VK_ADD:		return KEYSYM ("kp-add");
+	case VK_SEPARATOR:	return KEYSYM ("kp-separator");
+	case VK_SUBTRACT:	return KEYSYM ("kp-subtract");
+	case VK_DECIMAL:	return KEYSYM ("kp-decimal");
+	case VK_DIVIDE:		return KEYSYM ("kp-divide");
+	case VK_F1:		return KEYSYM ("f1");
+	case VK_F2:		return KEYSYM ("f2");
+	case VK_F3:		return KEYSYM ("f3");
+	case VK_F4:		return KEYSYM ("f4");
+	case VK_F5:		return KEYSYM ("f5");
+	case VK_F6:		return KEYSYM ("f6");
+	case VK_F7:		return KEYSYM ("f7");
+	case VK_F8:		return KEYSYM ("f8");
+	case VK_F9:		return KEYSYM ("f9");
+	case VK_F10:		return KEYSYM ("f10");
+	case VK_F11:		return KEYSYM ("f11");
+	case VK_F12:		return KEYSYM ("f12");
+	case VK_F13:		return KEYSYM ("f13");
+	case VK_F14:		return KEYSYM ("f14");
+	case VK_F15:		return KEYSYM ("f15");
+	case VK_F16:		return KEYSYM ("f16");
+	case VK_F17:		return KEYSYM ("f17");
+	case VK_F18:		return KEYSYM ("f18");
+	case VK_F19:		return KEYSYM ("f19");
+	case VK_F20:		return KEYSYM ("f20");
+	case VK_F21:		return KEYSYM ("f21");
+	case VK_F22:		return KEYSYM ("f22");
+	case VK_F23:		return KEYSYM ("f23");
+	case VK_F24:		return KEYSYM ("f24");
+	}
+    }
   return Qnil;
 }
 
@@ -2510,7 +2664,7 @@
 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))
@@ -2546,13 +2700,13 @@
  * 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;
 
   mswindows_need_event (1);
 
-  event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
+  event = mswindows_dequeue_dispatch_event ();
   XSETEVENT (event2, emacs_event);
   Fcopy_event (event, event2);
   Fdeallocate_event (event);
@@ -2562,13 +2716,18 @@
  * 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:
+      mswindows_handle_paint (XFRAME (EVENT_CHANNEL (emacs_event)));
+      mswindows_paint_pending = 0;
+      break;
+
     case WM_SETFOCUS:
     case WM_KILLFOCUS:
       {
@@ -2596,13 +2755,13 @@
     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 :
@@ -2616,7 +2775,7 @@
 
 #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);
@@ -2632,7 +2791,7 @@
 }
 
 static void
-emacs_mswindows_select_process (struct Lisp_Process *process)
+emacs_mswindows_select_process (Lisp_Process *process)
 {
   HANDLE hev = get_process_input_waitable (process);
 
@@ -2657,7 +2816,7 @@
 }
 
 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 */
@@ -2691,38 +2850,37 @@
 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));
-
-      Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
-		    ? Qcritical : Qt);
-
-      Fdeallocate_event(emacs_event);
-      --mswindows_quit_chars_count;
+      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 & MOD_SHIFT)
+	    critical_p = 1;
+
+	  Fdeallocate_event(emacs_event);
+	}
+
+      Vquit_flag = critical_p ? Qcritical : Qt;
     }
 }
 
@@ -2834,7 +2992,7 @@
    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;
@@ -2852,20 +3010,10 @@
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
- 
+
 void
-vars_of_event_mswindows (void)
+reinit_vars_of_event_mswindows (void)
 {
-  mswindows_u_dispatch_event_queue = Qnil;
-  staticpro (&mswindows_u_dispatch_event_queue);
-  mswindows_u_dispatch_event_queue_tail = Qnil;
-
-  mswindows_s_dispatch_event_queue = Qnil;
-  staticpro (&mswindows_s_dispatch_event_queue);
-  mswindows_s_dispatch_event_queue_tail = Qnil;
-
-  mswindows_error_caught_in_modal_loop = Qnil;
-  staticpro (&mswindows_error_caught_in_modal_loop);
   mswindows_in_modal_loop = 0;
   mswindows_pending_timers_count = 0;
 
@@ -2880,10 +3028,10 @@
   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
@@ -2892,6 +3040,31 @@
   mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
   mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
 #endif
+}
+
+void
+vars_of_event_mswindows (void)
+{
+  reinit_vars_of_event_mswindows ();
+
+  mswindows_u_dispatch_event_queue = Qnil;
+  staticpro (&mswindows_u_dispatch_event_queue);
+  mswindows_u_dispatch_event_queue_tail = Qnil;
+  pdump_wire (&mswindows_u_dispatch_event_queue_tail);
+
+  mswindows_s_dispatch_event_queue = Qnil;
+  staticpro (&mswindows_s_dispatch_event_queue);
+  mswindows_s_dispatch_event_queue_tail = Qnil;
+  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.
+Default is t.
+*/ );
 
   DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
 *Controls redrawing frame contents during mouse-drag or keyboard resize
@@ -2937,6 +3110,7 @@
   mswindows_mouse_button_max_skew_x = 0;
   mswindows_mouse_button_max_skew_y = 0;
   mswindows_mouse_button_tolerance = 0;
+  mswindows_meta_activates_menu = 1;
 }
 
 void