XEmacs 21.2.28 "Hermes".
[chise/xemacs-chise.git.1] / src / event-msw.c
index f31da31..c5c3d2f 100644 (file)
@@ -28,6 +28,7 @@ Boston, MA 02111-1307, USA.  */
    Ultimately based on FSF.
    Rewritten by Ben Wing.
    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
    Ultimately based on FSF.
    Rewritten by Ben Wing.
    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
+   Subprocess and modal loop support by Kirill M. Katsnelson.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
@@ -50,23 +51,32 @@ Boston, MA 02111-1307, USA.  */
 #include "device.h"
 #include "events.h"
 #include "frame.h"
 #include "device.h"
 #include "events.h"
 #include "frame.h"
+#include "buffer.h"
+#include "faces.h"
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
 #include "lstream.h"
 #include "process.h"
 #include "redisplay.h"
+#include "select.h"
 #include "sysproc.h"
 #include "syswait.h"
 #include "systime.h"
 #include "sysdep.h"
 #include "sysproc.h"
 #include "syswait.h"
 #include "systime.h"
 #include "sysdep.h"
+#include "objects-msw.h"
 
 #include "events-mod.h"
 #ifdef HAVE_MSG_SELECT
 #include "sysfile.h"
 
 #include "events-mod.h"
 #ifdef HAVE_MSG_SELECT
 #include "sysfile.h"
+#include "console-tty.h"
 #elif defined(__CYGWIN32__)
 typedef unsigned int SOCKET;
 #endif
 #include <io.h>
 #include <errno.h>
 
 #elif defined(__CYGWIN32__)
 typedef unsigned int SOCKET;
 #endif
 #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
 #ifdef HAVE_MENUBARS
 #define ADJR_MENUFLAG TRUE
 #else
@@ -80,14 +90,10 @@ typedef unsigned int SOCKET;
 /* Timer ID used for button2 emulation */
 #define BUTTON_2_TIMER_ID 1
 
 /* 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);
-
 static Lisp_Object mswindows_find_frame (HWND hwnd);
 static Lisp_Object mswindows_find_console (HWND hwnd);
 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);
 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);
@@ -115,11 +121,16 @@ static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_
 /* The number of things we can wait on */
 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
 
 /* The number of things we can wait on */
 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
 
+#ifndef HAVE_MSG_SELECT
 /* List of mswindows waitable handles. */
 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
 
 /* Number of wait handles */
 static int mswindows_waitable_count=0;
 /* List of mswindows waitable handles. */
 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;
 
 /* Count of quit chars currently in the queue */
 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
 
 /* Count of quit chars currently in the queue */
 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
@@ -128,6 +139,7 @@ int mswindows_quit_chars_count = 0;
 
 /* These are Lisp integers; see DEFVARS in this file for description. */
 int mswindows_dynamic_frame_resize;
 
 /* 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;
 int mswindows_num_mouse_buttons;
 int mswindows_mouse_button_max_skew_x;
 int mswindows_mouse_button_max_skew_y;
@@ -155,7 +167,7 @@ static int mswindows_pending_timers_count;
 /* This structure is allocated by the main thread, and is deallocated
    in the thread upon exit.  There are situations when a thread
    remains blocked for a long time, much longer than the lstream
 /* This structure is allocated by the main thread, and is deallocated
    in the thread upon exit.  There are situations when a thread
    remains blocked for a long time, much longer than the lstream
-   exists. For exmaple, "start notepad" command is issued from the
+   exists. For example, "start notepad" command is issued from the
    shell, then the shell is closed by C-c C-d. Although the shell
    process exits, its output pipe will not get closed until the
    notepad process exits also, because it inherits the pipe form the
    shell, then the shell is closed by C-c C-d. Although the shell
    process exits, its output pipe will not get closed until the
    notepad process exits also, because it inherits the pipe form the
@@ -181,7 +193,7 @@ struct ntpipe_slurp_stream_shared_data
 };
 
 #define MAX_SLURP_STREAMS 32
 };
 
 #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
 shared_data_block[MAX_SLURP_STREAMS]={{0}};
 
 struct ntpipe_slurp_stream
@@ -194,7 +206,7 @@ DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
                               sizeof (struct ntpipe_slurp_stream));
 
 /* This function is thread-safe, and is called from either thread
                               sizeof (struct ntpipe_slurp_stream));
 
 /* This function is thread-safe, and is called from either thread
-   context. It serializes freeing shared dtata structure */
+   context. It serializes freeing shared data structure */
 static void
 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
 {
 static void
 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
 {
@@ -253,7 +265,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
 
       /* 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. */
         Reader function pulses this event before waiting for
         a character, to avoid pipe delay, and to get the byte
         immediately. */
@@ -268,7 +280,7 @@ slurp_thread (LPVOID vparam)
       if (s->die_p)
        break;
 
       if (s->die_p)
        break;
 
-      /* Block until the client finishes with retireving the rest of
+      /* Block until the client finishes with retrieving the rest of
         pipe data */
       WaitForSingleObject (s->hev_thread, INFINITE);
     }
         pipe data */
       WaitForSingleObject (s->hev_thread, INFINITE);
     }
@@ -342,11 +354,11 @@ get_ntpipe_input_stream_waitable (Lstream *stream)
   return s->thread_data->hev_caller;
 }
 
   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 */
 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)
     NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
 
   if (!s->die_p)
@@ -355,7 +367,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);
       /* 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);
       /* 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);
@@ -406,7 +418,7 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
              ReadFile (s->hpipe, data, min (bytes_available, size),
                        &bytes_read, NULL);
          }
              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;
        /* Now we can unblock thread, so it attempts to read more */
        SetEvent (s->hev_thread);
        return bytes_read + 1;
@@ -415,11 +427,11 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
   return 0;
 }
 
   return 0;
 }
 
-static int 
+static int
 ntpipe_slurp_closer (Lstream *stream)
 {
   /* This function must be called from the main thread only */
 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 */
     NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
 
   /* Force thread to stop */
@@ -451,7 +463,7 @@ init_slurp_stream (void)
   LSTREAM_TYPE_DATA (stream, ntpipe_shove)
 
 #define MAX_SHOVE_BUFFER_SIZE 128
   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     */
 struct ntpipe_shove_stream
 {
   LPARAM user_data;    /* Any user data stored in the stream object     */
@@ -470,6 +482,7 @@ struct ntpipe_shove_stream
 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
                               sizeof (struct ntpipe_shove_stream));
 
 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
                               sizeof (struct ntpipe_shove_stream));
 
+#ifndef HAVE_MSG_SELECT
 static DWORD WINAPI
 shove_thread (LPVOID vparam)
 {
 static DWORD WINAPI
 shove_thread (LPVOID vparam)
 {
@@ -477,7 +490,7 @@ shove_thread (LPVOID vparam)
 
   for (;;)
     {
 
   for (;;)
     {
-      DWORD bytes_written; 
+      DWORD bytes_written;
 
       /* Block on event and wait for a job */
       InterlockedIncrement (&s->idle_p);
 
       /* Block on event and wait for a job */
       InterlockedIncrement (&s->idle_p);
@@ -514,7 +527,7 @@ make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
   s->hpipe = hpipe;
   s->user_data = 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);
      create the event until thread is created */
   s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
                             CREATE_SUSPENDED, &thread_id_unused);
@@ -541,8 +554,9 @@ get_ntpipe_output_stream_param (Lstream *stream)
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
   return s->user_data;
 }
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
   return s->user_data;
 }
+#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);
 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
 {
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
@@ -619,7 +633,7 @@ struct winsock_stream
   OVERLAPPED ov;               /* Overlapped I/O structure                  */
   void* buffer;                        /* Buffer. Allocated for input stream only   */
   unsigned int bufsize;                /* Number of bytes last read                 */
   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;         /* Psition in buffer for next fetch          */
+  unsigned int 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          */
   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          */
@@ -651,7 +665,7 @@ winsock_initiate_read (struct winsock_stream *str)
     str->eof_p = 1;
 }
 
     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);
 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
@@ -684,7 +698,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
     return 0;
   if (str->error_p)
     return -1;
     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);
   /* 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);
@@ -697,7 +711,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
   return size;
 }
 
   return size;
 }
 
-static int
+static ssize_t
 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
@@ -725,7 +739,7 @@ winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
 
   if (size == 0)
     return 0;
 
   if (size == 0)
     return 0;
-  
+
   {
     ResetEvent (str->ov.hEvent);
 
   {
     ResetEvent (str->ov.hEvent);
 
@@ -839,7 +853,7 @@ init_winsock_stream (void)
 /************************************************************************/
 
 static int
 /************************************************************************/
 
 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
 {
   return (sevt->event_type == key_press_event
          || sevt->event_type == button_press_event
@@ -847,7 +861,7 @@ mswindows_user_event_p (struct Lisp_Event* sevt)
          || sevt->event_type == misc_user_event);
 }
 
          || sevt->event_type == misc_user_event);
 }
 
-/* 
+/*
  * Add an emacs event to the proper dispatch queue
  */
 static void
  * Add an emacs event to the proper dispatch queue
  */
 static void
@@ -855,7 +869,7 @@ mswindows_enqueue_dispatch_event (Lisp_Object event)
 {
   int user_p = mswindows_user_event_p (XEVENT(event));
   enqueue_event (event,
 {
   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);
                        &mswindows_s_dispatch_event_queue,
                 user_p ? &mswindows_u_dispatch_event_queue_tail :
                        &mswindows_s_dispatch_event_queue_tail);
@@ -875,10 +889,11 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
                                   Lisp_Object object)
 {
   Lisp_Object event = Fmake_event (Qnil, Qnil);
                                   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->event_type = misc_user_event;
   e->channel = channel;
+  e->timestamp = GetTickCount ();
   e->event.misc.function = function;
   e->event.misc.object = object;
 
   e->event.misc.function = function;
   e->event.misc.object = object;
 
@@ -886,24 +901,24 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
 }
 
 void
 }
 
 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);
 {
   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->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_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);
 {
   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);
 
   Lisp_Object process;
   XSETPROCESS (process, p);
 
@@ -915,7 +930,7 @@ mswindows_enqueue_process_event (struct Lisp_Process* p)
 }
 
 static void
 }
 
 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
 {
 
   /* We always use last message time, because mouse button
@@ -923,29 +938,36 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO
      recognition will fail */
 
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
      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 =
 
   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);
   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);
     {
       event->event_type = button_press_event;
       SetCapture (hwnd);
+      /* we need this to make sure the main window regains the focus
+         from control subwindows */
+      if (GetFocus() != hwnd)
+       {
+         SetFocus (hwnd);
+         mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
+       }
     }
   else
     {
       event->event_type = button_release_event;
       ReleaseCapture ();
     }
     }
   else
     {
       event->event_type = button_release_event;
       ReleaseCapture ();
     }
-  
+
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
@@ -953,7 +975,7 @@ static void
 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
 {
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
 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();
 
   event->channel = mswindows_find_console(hwnd);
   event->timestamp = GetMessageTime();
@@ -971,16 +993,16 @@ static Lisp_Object
 mswindows_dequeue_dispatch_event ()
 {
   Lisp_Object event;
 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 (
 
   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,
                         &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);
 
                         &mswindows_s_dispatch_event_queue_tail :
                         &mswindows_u_dispatch_event_queue_tail);
 
@@ -997,22 +1019,22 @@ mswindows_dequeue_dispatch_event ()
 
 /*
  * Remove and return the first emacs event on the dispatch queue that matches
 
 /*
  * Remove and return the first emacs event on the dispatch queue that matches
- * the supplied event
- * Timeout event matches if interval_id equals to that of the given event.
+ * the supplied event.
+ * Timeout event matches if interval_id is equal to that of the given event.
  * Keypress event matches if logical AND between modifiers bitmask of the
  * Keypress event matches if logical AND between modifiers bitmask of the
- * event in the queue and that of the given event is non-zero
- * For all other event types, this function asserts.
+ * event in the queue and that of the given event is non-zero.
+ * For all other event types, this function aborts.
  */
 
 Lisp_Object
  */
 
 Lisp_Object
-mswindows_cancel_dispatch_event (struct Lisp_Event* match)
+mswindows_cancel_dispatch_event (Lisp_Event *match)
 {
   Lisp_Object event;
 {
   Lisp_Object event;
-  Lisp_Object previous_event=Qnil;
+  Lisp_Object previous_event = Qnil;
   int user_p = mswindows_user_event_p (match);
   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;
                               &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
                               &mswindows_s_dispatch_event_queue_tail;
 
   assert (match->event_type == timeout_event
@@ -1020,19 +1042,12 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match)
 
   EVENT_CHAIN_LOOP (event, *head)
     {
 
   EVENT_CHAIN_LOOP (event, *head)
     {
-      int found = 1;
-      if (XEVENT_TYPE (event) != match->event_type)
-       found = 0;
-      if (found && match->event_type == timeout_event
-         && (XEVENT(event)->event.timeout.interval_id !=
-             match->event.timeout.interval_id))
-       found = 0;
-      if (found && match->event_type == key_press_event
-         && ((XEVENT(event)->event.key.modifiers &
-             match->event.key.modifiers) == 0))
-       found = 0;
-
-      if (found)
+      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) :
+          /* Must be key_press_event */
+          ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
        {
          if (NILP (previous_event))
            dequeue_event (head, tail);
        {
          if (NILP (previous_event))
            dequeue_event (head, tail);
@@ -1042,7 +1057,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match)
              if (EQ (*tail, event))
                *tail = previous_event;
            }
              if (EQ (*tail, event))
                *tail = previous_event;
            }
-         
+
          return event;
        }
       previous_event = event;
          return event;
        }
       previous_event = event;
@@ -1050,6 +1065,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match)
   return Qnil;
 }
 \f
   return Qnil;
 }
 \f
+#ifndef HAVE_MSG_SELECT
 /************************************************************************/
 /*                     Waitable handles manipulation                    */
 /************************************************************************/
 /************************************************************************/
 /*                     Waitable handles manipulation                    */
 /************************************************************************/
@@ -1082,9 +1098,10 @@ remove_waitable_handle (HANDLE h)
   if (ix < 0)
     return;
 
   if (ix < 0)
     return;
 
-  mswindows_waitable_handles [ix] = 
+  mswindows_waitable_handles [ix] =
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
     mswindows_waitable_handles [--mswindows_waitable_count];
 }
+#endif /* HAVE_MSG_SELECT */
 
 \f
 /************************************************************************/
 
 \f
 /************************************************************************/
@@ -1105,7 +1122,7 @@ mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
 {
   Lisp_Object tmp;
 
 {
   Lisp_Object tmp;
 
-  ++mswindows_in_modal_loop; 
+  ++mswindows_in_modal_loop;
   tmp = condition_case_1 (Qt,
                          bfun, barg,
                          mswindows_modal_loop_error_handler, Qnil);
   tmp = condition_case_1 (Qt,
                          bfun, barg,
                          mswindows_modal_loop_error_handler, Qnil);
@@ -1129,7 +1146,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
  * condition_case. See mswindows_pump_outstanding_events
  */
 static Lisp_Object
@@ -1153,7 +1170,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
 
   Fdeallocate_event (event);
   UNGCPRO;
 
   Fdeallocate_event (event);
   UNGCPRO;
-  
+
   /* Qt becomes return value of mswindows_pump_outstanding_events
      once we get here */
   return Qt;
   /* Qt becomes return value of mswindows_pump_outstanding_events
      once we get here */
   return Qt;
@@ -1168,7 +1185,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
  * neither are waitable handles checked. The function pumps
  * thus only dispatch events already queued, as well as those
  * resulted in dispatching thereof. This is done by setting
  * neither are waitable handles checked. The function pumps
  * thus only dispatch events already queued, as well as those
  * resulted in dispatching thereof. This is done by setting
- * module local variable mswidows_in_modal_loop to nonzero.
+ * module local variable mswindows_in_modal_loop to nonzero.
  *
  * Return value is Qt if no errors was trapped, or Qunbound if
  * there was an error.
  *
  * Return value is Qt if no errors was trapped, or Qunbound if
  * there was an error.
@@ -1186,7 +1203,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
  * If the value of mswindows_error_caught_in_modal_loop is not
  * nil already upon entry, the function just returns non-nil.
  * This situation means that a new event has been queued while
  * If the value of mswindows_error_caught_in_modal_loop is not
  * nil already upon entry, the function just returns non-nil.
  * This situation means that a new event has been queued while
- * cancleng mode. The event will be dequeued on the next regular
+ * in cancel mode. The event will be dequeued on the next regular
  * call of next-event; the pump is off since error is caught.
  * The caller must *unconditionally* cancel modal loop if the
  * value returned by this function is nil. Otherwise, everything
  * call of next-event; the pump is off since error is caught.
  * The caller must *unconditionally* cancel modal loop if the
  * value returned by this function is nil. Otherwise, everything
@@ -1201,29 +1218,49 @@ mswindows_pump_outstanding_events (void)
   Lisp_Object result = Qt;
   struct gcpro gcpro1;
   GCPRO1 (result);
   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;
 }
 
   if (NILP(mswindows_error_caught_in_modal_loop))
       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 (int keyboard_only_till_quit_char_p)
 {
   MSG msg;
 {
   MSG msg;
-  while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+
+  /* Minimize the hassle of misordered events by not fetching
+     past quit char if called from QUITP; */
+  while (!(keyboard_only_till_quit_char_p &&
+          mswindows_quit_chars_count > 0) &&
+        PeekMessage (&msg, NULL,
+                     keyboard_only_till_quit_char_p ? WM_KEYFIRST : 0,
+                     keyboard_only_till_quit_char_p ? WM_KEYLAST : 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)
+       {
+         TranslateMessage (&msg);
+       }
       DispatchMessage (&msg);
       mswindows_unmodalize_signal_maybe ();
     }
 }
 
       DispatchMessage (&msg);
       mswindows_unmodalize_signal_maybe ();
     }
 }
 
-/* 
- * This is a special flavour of the mswindows_need_event function,
+/*
+ * 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
  * used while in event pump. Actually, there is only kind of events
  * allowed while in event pump: a timer.  An attempt to fetch any
- * other event leads to a dealock, as there's no source of user input
+ * other event leads to a deadlock, as there's no source of user input
  * ('cause event pump mirrors windows modal loop, which is a sole
  * owner of thread message queue).
  *
  * ('cause event pump mirrors windows modal loop, which is a sole
  * owner of thread message queue).
  *
@@ -1252,7 +1289,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");
       /* 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);
       /* Fetch and dispatch any pending timers */
       GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
       DispatchMessage (&msg);
@@ -1277,9 +1314,13 @@ mswindows_need_event (int badly_p)
       return;
     }
 
       return;
     }
 
+#if 0
   /* Have to drain Windows message queue first, otherwise, we may miss
      quit char when called from quit_p */
   /* Have to drain Windows message queue first, otherwise, we may miss
      quit char when called from quit_p */
+  /* #### This is, ehm, not quite true -- this function is not
+     called from quit_p. --kkm */
   mswindows_drain_windows_queue ();
   mswindows_drain_windows_queue ();
+#endif
 
   while (NILP (mswindows_u_dispatch_event_queue)
         && NILP (mswindows_s_dispatch_event_queue))
 
   while (NILP (mswindows_u_dispatch_event_queue)
         && NILP (mswindows_s_dispatch_event_queue))
@@ -1289,7 +1330,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;
       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
       if (badly_p)
        pointer_to_this = 0;
       else
@@ -1299,41 +1340,41 @@ mswindows_need_event (int badly_p)
          pointer_to_this = &select_time_to_block;
        }
 
          pointer_to_this = &select_time_to_block;
        }
 
-      /* select() is slow and buggy so if we don't have any processes
-         just wait as normal */
-      if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
-       {
-         /* Now try getting a message or process event */
-         active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
-                                             FALSE, badly_p ? INFINITE : 0,
-                                             QS_ALLINPUT);
-         
-         if (active == WAIT_TIMEOUT)
-           {
-             /* No luck trying - just return what we've already got */
-             return;
-           }
-         else if (active == WAIT_OBJECT_0)
-           {
-             /* Got your message, thanks */
-             mswindows_drain_windows_queue ();
-             continue;
-           }
-       }
-
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
-      
+
       if (active == 0)
        {
       if (active == 0)
        {
+         assert (!badly_p);
          return;               /* timeout */
        }
       else if (active > 0)
        {
          if (FD_ISSET (windows_fd, &temp_mask))
            {
          return;               /* timeout */
        }
       else if (active > 0)
        {
          if (FD_ISSET (windows_fd, &temp_mask))
            {
-             mswindows_drain_windows_queue ();
+             mswindows_drain_windows_queue (0);
            }
            }
-         
+#ifdef HAVE_TTY
+         /* Look for a TTY event */
+         for (i = 0; i < MAXDESC-1; 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))
+               {
+                 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++)
            {
          /* Look for a process event */
          for (i = 0; i < MAXDESC-1; i++)
            {
@@ -1341,16 +1382,11 @@ mswindows_need_event (int badly_p)
                {
                  if (FD_ISSET (i, &process_only_mask))
                    {
                {
                  if (FD_ISSET (i, &process_only_mask))
                    {
-                     struct Lisp_Process *p =
+                     Lisp_Process *p =
                        get_process_from_usid (FD_TO_USID(i));
                        get_process_from_usid (FD_TO_USID(i));
-                     
+
                      mswindows_enqueue_process_event (p);
                    }
                      mswindows_enqueue_process_event (p);
                    }
-                 else if (FD_ISSET (i, &tty_only_mask))
-                   {
-                               /* do we care about tty events? Do we
-                                   ever get tty events? */
-                   }
                  else
                    {
                      /* We might get here when a fake event came
                  else
                    {
                      /* We might get here when a fake event came
@@ -1367,7 +1403,7 @@ mswindows_need_event (int badly_p)
        {
          if (errno != EINTR)
            {
        {
          if (errno != EINTR)
            {
-             /* something bad happended */
+             /* something bad happened */
              assert(0);
            }
        }
              assert(0);
            }
        }
@@ -1387,7 +1423,7 @@ mswindows_need_event (int badly_p)
     assert ((!badly_p && active == WAIT_TIMEOUT) ||
            (active >= WAIT_OBJECT_0 &&
             active <= WAIT_OBJECT_0 + mswindows_waitable_count));
     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 */
     if (active == WAIT_TIMEOUT)
       {
        /* No luck trying - just return what we've already got */
@@ -1396,13 +1432,13 @@ mswindows_need_event (int badly_p)
     else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
       {
        /* Got your message, thanks */
     else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
       {
        /* Got your message, thanks */
-       mswindows_drain_windows_queue ();
+       mswindows_drain_windows_queue (0);
       }
     else
       {
        int ix = active - WAIT_OBJECT_0;
       }
     else
       {
        int ix = active - WAIT_OBJECT_0;
-       /* First, try to find which process' ouptut has signaled */
-       struct Lisp_Process *p = 
+       /* 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)
          {
          get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
        if (p != NULL)
          {
@@ -1412,7 +1448,7 @@ mswindows_need_event (int badly_p)
        else
          {
            /* None. This means that the process handle itself has signaled.
        else
          {
            /* None. This means that the process handle itself has signaled.
-              Remove the handle from the wait vector, and make status_ntoify
+              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];
               note the exited process */
            mswindows_waitable_handles [ix] =
              mswindows_waitable_handles [--mswindows_waitable_count];
@@ -1430,14 +1466,14 @@ mswindows_need_event (int badly_p)
 /*                           Event generators                           */
 /************************************************************************/
 
 /*                           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);
  * 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;
 
   if (KillTimer (NULL, id_timer))
     --mswindows_pending_timers_count;
@@ -1446,11 +1482,13 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
   event->timestamp = dwtime;
   event->event_type = timeout_event;
   event->event.timeout.interval_id = id_timer;
   event->timestamp = dwtime;
   event->event_type = timeout_event;
   event->event.timeout.interval_id = id_timer;
+  event->event.timeout.function = Qnil;
+  event->event.timeout.object = Qnil;
 
   mswindows_enqueue_dispatch_event (emacs_event);
 }
 
 
   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
  * Callback procedure for dde messages
  *
  * We execute a dde Open("file") by simulating a file drop, so dde support
@@ -1461,9 +1499,9 @@ HDDEDATA CALLBACK
 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
                        HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
                        DWORD dwData1, DWORD dwData2)
 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
                        HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
                        DWORD dwData1, DWORD dwData2)
-{ 
+{
   switch (uType)
   switch (uType)
-    { 
+    {
     case XTYP_CONNECT:
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        return (HDDEDATA)TRUE;
     case XTYP_CONNECT:
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        return (HDDEDATA)TRUE;
@@ -1480,7 +1518,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
                                       sizeof (pairs), 0L, 0, uFmt, 0));
       }
          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))
 
     case XTYP_EXECUTE:
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
@@ -1493,7 +1531,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
           Lisp_Object l_dndlist = Qnil;
          Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
          Lisp_Object frmcons, devcons, concons;
           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';
 
          DdeGetData (hdata, cmd, len, 0);
          cmd[len] = '\0';
@@ -1561,32 +1599,52 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          UNGCPRO;
          return (HDDEDATA) DDE_FACK;
        }
          UNGCPRO;
          return (HDDEDATA) DDE_FACK;
        }
-      DdeFreeDataHandle (hdata); 
+      DdeFreeDataHandle (hdata);
       return (HDDEDATA) DDE_FNOTPROCESSED;
 
       return (HDDEDATA) DDE_FNOTPROCESSED;
 
-    default: 
-      return (HDDEDATA) NULL; 
-    } 
+    default:
+      return (HDDEDATA) NULL;
+    }
 }
 #endif
 
 /*
 }
 #endif
 
 /*
+ * 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
 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
  * The windows procedure for the window class XEMACS_CLASS
  */
 LRESULT WINAPI
 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-  /* Note: Remember to initialise emacs_event and event before use.
+  /* Note: Remember to initialize emacs_event and event before use.
      This code calls code that can GC. You must GCPRO before calling such code. */
   Lisp_Object emacs_event = Qnil;
   Lisp_Object fobj = Qnil;
 
      This code calls code that can GC. You must GCPRO before calling such code. */
   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)
   {
   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)));
   case WM_ERASEBKGND:
     /* Erase background only during non-dynamic sizing */
     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
@@ -1618,7 +1676,10 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          SetKeyboardState (keymap);
        }
     };
          SetKeyboardState (keymap);
        }
     };
-    goto defproc;
+    if (key_needs_default_processing_p (wParam))
+      goto defproc;
+    else
+      break;
 
   case WM_KEYDOWN:
   case WM_SYSKEYDOWN:
 
   case WM_KEYDOWN:
   case WM_SYSKEYDOWN:
@@ -1634,27 +1695,37 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       BYTE keymap[256];
       int has_AltGr = mswindows_current_layout_has_AltGr ();
       int mods;
       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);
 
       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);
        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];
        {
          int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
          BYTE keymap_orig[256];
-         MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
+         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)
 
          /* 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 [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
+           keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
          else if (wParam == VK_MENU)
          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);
 
 
          memcpy (keymap_orig, keymap, 256);
 
@@ -1664,7 +1735,8 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          /* Clear control and alt modifiers unless AltGr is pressed */
          keymap [VK_RCONTROL] = 0;
          keymap [VK_LMENU] = 0;
          /* 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;
            {
              keymap [VK_LCONTROL] = 0;
              keymap [VK_CONTROL] = 0;
@@ -1700,10 +1772,10 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          SetKeyboardState (keymap_orig);
        } /* else */
     }
          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;
       goto defproc;
-    break;
+    else
+      break;
 
   case WM_MBUTTONDOWN:
   case WM_MBUTTONUP:
 
   case WM_MBUTTONDOWN:
   case WM_MBUTTONUP:
@@ -1713,7 +1785,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     mswindows_enqueue_mouse_button_event (hwnd, message,
                                          MAKEPOINTS (lParam), GetMessageTime());
     break;
     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();
   case WM_LBUTTONUP:
     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
     msframe->last_click_time =  GetMessageTime();
@@ -1835,7 +1907,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }
     msframe->last_click_time =  GetMessageTime();
     break;
       }
     msframe->last_click_time =  GetMessageTime();
     break;
-       
+
   case WM_TIMER:
     if (wParam == BUTTON_2_TIMER_ID)
       {
   case WM_TIMER:
     if (wParam == BUTTON_2_TIMER_ID)
       {
@@ -1860,13 +1932,13 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     break;
 
   case WM_MOUSEMOVE:
     break;
 
   case WM_MOUSEMOVE:
-    /* Optimization: don't report mouse movement while size is changind */
+    /* 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
     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 impoves drag-select feedback */
+        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)))
       if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
          && !mswindows_button2_near_enough (msframe->last_click_point,
                                             MAKEPOINTS (lParam)))
@@ -1884,7 +1956,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       event->event.motion.x = MAKEPOINTS(lParam).x;
       event->event.motion.y = MAKEPOINTS(lParam).y;
       event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
       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;
       mswindows_enqueue_dispatch_event (emacs_event);
     }
     break;
@@ -1897,18 +1969,21 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                                       Qcancel_mode_internal, Qnil);
     break;
 
                                       Qcancel_mode_internal, Qnil);
     break;
 
-#ifdef HAVE_TOOLBARS
   case WM_NOTIFY:
     {
   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));
          /* 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;
 
          tttext->lpszText = NULL;
          tttext->hinst = NULL;
 
@@ -1916,27 +1991,66 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
              /* I think this is safe since the text will only go away
                  when the toolbar does...*/
            {
              /* I think this is safe since the text will only go away
                  when the toolbar does...*/
-             tttext->lpszText=XSTRING_DATA (btext);
+             TO_EXTERNAL_FORMAT (LISP_STRING, btext,
+                                 C_STRING_ALLOCA, tttext->lpszText,
+                                 Qnative);
            }
            }
-#if 0
-         tttext->uFlags |= TTF_DI_SETITEM;
 #endif
 #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;
     }
     break;
-#endif
-    
+
   case WM_PAINT:
     {
   case WM_PAINT:
     {
-      PAINTSTRUCT paintStruct;
-      
-      frame = XFRAME (mswindows_find_frame (hwnd));
+      /* 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;
+
+         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);
+         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);
+       }
+      else
+       goto defproc;
     }
     break;
 
     }
     break;
 
@@ -1979,8 +2093,8 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          if (FRAME_MSWINDOWS_TARGET_RECT (frame))
            {
              /* Yes, we have to size again */
          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. */
                                              (frame));
              /* Reset so we do not get here again. The SetWindowPos call in
               * mswindows_size_frame_internal can cause recursion here. */
@@ -1995,7 +2109,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
              if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
                mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
              FRAME_VISIBLE_P (frame) = 1;
              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 ();
            }
              if (!msframe->sizing || mswindows_dynamic_frame_resize)
                redisplay ();
            }
@@ -2086,7 +2200,24 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
          SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
        }
       UNGCPRO;
          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
 
     }
 #endif
 
@@ -2113,6 +2244,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND:
     {
       WORD id = LOWORD (wParam);
   case WM_COMMAND:
     {
       WORD id = LOWORD (wParam);
+      WORD nid = HIWORD (wParam);
       HWND cid = (HWND)lParam;
       frame = XFRAME (mswindows_find_frame (hwnd));
 
       HWND cid = (HWND)lParam;
       frame = XFRAME (mswindows_find_frame (hwnd));
 
@@ -2120,17 +2252,83 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
        break;
 #endif
       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*/
 #ifdef HAVE_MENUBARS
       if (!NILP (mswindows_handle_wm_command (frame, id)))
        break;
 #endif
 
 #ifdef HAVE_MENUBARS
       if (!NILP (mswindows_handle_wm_command (frame, id)))
        break;
 #endif
 
-      /* Bite me - a spurious command. This cannot happen. */
-      error ("XEMACS BUG: Cannot decode command message");
+      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;
 
     }
   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))
+           {
+             /* 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 */
     {
 #ifdef HAVE_DRAGNDROP
   case WM_DROPFILES:   /* implementation ripped-off from event-Xt.c */
     {
@@ -2294,67 +2492,100 @@ int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
  * 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
  * 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
 #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;
 }
 
   return Qnil;
 }
 
@@ -2412,7 +2643,7 @@ emacs_mswindows_add_timeout (EMACS_TIME thyme)
 static void
 emacs_mswindows_remove_timeout (int id)
 {
 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))
   Lisp_Object emacs_event;
 
   if (KillTimer (NULL, id))
@@ -2448,13 +2679,13 @@ emacs_mswindows_event_pending_p (int user_p)
  * Return the next event
  */
 static void
  * 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);
 
 {
   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);
   XSETEVENT (event2, emacs_event);
   Fcopy_event (event, event2);
   Fdeallocate_event (event);
@@ -2464,13 +2695,13 @@ emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
  * Handle a magic event off the dispatch queue.
  */
 static void
  * 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;
 {
   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
     {
     case XM_BUMPQUEUE:
       break;
-    
+
     case WM_SETFOCUS:
     case WM_KILLFOCUS:
       {
     case WM_SETFOCUS:
     case WM_KILLFOCUS:
       {
@@ -2498,13 +2729,13 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
     case XM_UNMAPFRAME:
       {
        Lisp_Object frame = EVENT_CHANNEL (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 ?
                               == XM_MAPFRAME ?
-                              Qmap_frame_hook : Qunmap_frame_hook, 
+                              Qmap_frame_hook : Qunmap_frame_hook,
                               1, frame);
       }
       break;
                               1, frame);
       }
       break;
-                           
+
       /* #### What about Enter & Leave */
 #if 0
       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
       /* #### What about Enter & Leave */
 #if 0
       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
@@ -2516,8 +2747,9 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
     }
 }
 
     }
 }
 
+#ifndef HAVE_MSG_SELECT
 static HANDLE
 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);
 {
   Lisp_Object instr, outstr, p;
   XSETPROCESS (p, process);
@@ -2533,7 +2765,7 @@ get_process_input_waitable (struct Lisp_Process *process)
 }
 
 static void
 }
 
 static void
-emacs_mswindows_select_process (struct Lisp_Process *process)
+emacs_mswindows_select_process (Lisp_Process *process)
 {
   HANDLE hev = get_process_input_waitable (process);
 
 {
   HANDLE hev = get_process_input_waitable (process);
 
@@ -2558,22 +2790,35 @@ emacs_mswindows_select_process (struct Lisp_Process *process)
 }
 
 static void
 }
 
 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 */
   HANDLE hev = get_process_input_waitable (process);
   remove_waitable_handle (hev);
 }
 {
   /* Process handle is removed in the event loop as soon
      as it is signaled, so don't bother here about it */
   HANDLE hev = get_process_input_waitable (process);
   remove_waitable_handle (hev);
 }
+#endif /* HAVE_MSG_SELECT */
 
 static void
 emacs_mswindows_select_console (struct console *con)
 {
 
 static void
 emacs_mswindows_select_console (struct console *con)
 {
+#ifdef HAVE_MSG_SELECT
+  if (CONSOLE_MSWINDOWS_P (con))
+    return; /* mswindows consoles are automatically selected */
+
+  event_stream_unixoid_select_console (con);
+#endif
 }
 
 static void
 emacs_mswindows_unselect_console (struct console *con)
 {
 }
 
 static void
 emacs_mswindows_unselect_console (struct console *con)
 {
+#ifdef HAVE_MSG_SELECT
+  if (CONSOLE_MSWINDOWS_P (con))
+    return; /* mswindows consoles are automatically selected */
+
+  event_stream_unixoid_unselect_console (con);
+#endif
 }
 
 static void
 }
 
 static void
@@ -2584,27 +2829,32 @@ emacs_mswindows_quit_p (void)
   if (mswindows_in_modal_loop)
     return;
 
   if (mswindows_in_modal_loop)
     return;
 
-  /* Drain windows queue. This sets up number of quit
-     characters in in the queue */
-  mswindows_drain_windows_queue ();
+  /* Drain windows queue. This sets up number of quit characters in
+     the queue */
+  mswindows_drain_windows_queue (1);
 
   if (mswindows_quit_chars_count > 0)
     {
       /* Yes there's a hidden one... Throw it away */
 
   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;
       Lisp_Object emacs_event;
+      int critical_p = 0;
 
       match_against.event_type = key_press_event;
       match_against.event.key.modifiers = FAKE_MOD_QUIT;
 
 
       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 & 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;
     }
 }
 
     }
 }
 
@@ -2716,7 +2966,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
    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;
 {
 #if 0 /* #### */
   Lisp_Object instr, outstr;
@@ -2734,20 +2984,10 @@ debug_process_finalization (struct Lisp_Process *p)
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
+
 void
 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;
 
   mswindows_in_modal_loop = 0;
   mswindows_pending_timers_count = 0;
 
@@ -2762,10 +3002,10 @@ 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_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
   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
@@ -2774,6 +3014,31 @@ vars_of_event_mswindows (void)
   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
   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
 
   DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
 *Controls redrawing frame contents during mouse-drag or keyboard resize
@@ -2802,7 +3067,7 @@ Number of physical mouse buttons.
 
   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
 
   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 occured for them to be translated into single
+right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
@@ -2810,7 +3075,7 @@ 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 /*
 *Maximum vertical distance in pixels between points in which left and
 
   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 occured for them to be translated into single
+right button clicks occurred for them to be translated into single
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
 middle button event. Clicks must occur in time not longer than defined
 by the variable `mswindows-mouse-button-tolerance'.
 If negative or zero, currently set system default is used instead.
@@ -2819,6 +3084,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_mouse_button_max_skew_x = 0;
   mswindows_mouse_button_max_skew_y = 0;
   mswindows_mouse_button_tolerance = 0;
+  mswindows_meta_activates_menu = 1;
 }
 
 void
 }
 
 void