XEmacs 21.4.6 "Common Lisp".
[chise/xemacs-chise.git.1] / src / event-msw.c
index f098d73..e4e1be5 100644 (file)
@@ -49,31 +49,31 @@ Boston, MA 02111-1307, USA.  */
 # include "dragdrop.h"
 #endif
 
+#include "buffer.h"
 #include "device.h"
 #include "events.h"
-#include "frame.h"
-#include "buffer.h"
 #include "faces.h"
+#include "frame.h"
 #include "lstream.h"
+#include "objects-msw.h"
 #include "process.h"
 #include "redisplay.h"
 #include "select.h"
+#include "sysdep.h"
 #include "window.h"
+
+#include "sysfile.h"
 #include "sysproc.h"
-#include "syswait.h"
 #include "systime.h"
-#include "sysdep.h"
-#include "objects-msw.h"
+#include "syswait.h"
 
 #include "events-mod.h"
+
 #ifdef HAVE_MSG_SELECT
-#include "sysfile.h"
 #include "console-tty.h"
 #elif defined(CYGWIN)
 typedef unsigned int SOCKET;
 #endif
-#include <io.h>
-#include <errno.h>
 
 #if !(defined(CYGWIN) || defined(MINGW))
 # include <shlobj.h>   /* For IShellLink */
@@ -87,12 +87,13 @@ typedef unsigned int SOCKET;
 
 /* Fake key modifier which is attached to a quit char event.
    Removed upon dequeueing an event */
-#define FAKE_MOD_QUIT  0x80
+#define FAKE_MOD_QUIT (1 << 20)
+#define FAKE_MOD_QUIT_CRITICAL (1 << 21)
 
 /* Timer ID used for button2 emulation */
 #define BUTTON_2_TIMER_ID 1
 
-static Lisp_Object mswindows_find_frame (HWND hwnd);
+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,
                                                  int extendedp);
@@ -153,6 +154,9 @@ Fixnum mswindows_mouse_button_tolerance;
 
 #ifdef DEBUG_XEMACS
 Fixnum debug_mswindows_events;
+
+static void debug_output_mswin_message (HWND hwnd, UINT message_,
+                                       WPARAM wParam, LPARAM lParam);
 #endif
 
 /* This is the event signaled by the event pump.
@@ -228,6 +232,7 @@ slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
       CloseHandle (s->hev_thread);
       CloseHandle (s->hev_caller);
       CloseHandle (s->hev_unsleep);
+      CloseHandle (s->hpipe);
       s->inuse_p = 0;
     }
 }
@@ -366,8 +371,9 @@ get_ntpipe_input_stream_waitable (Lstream *stream)
   return s->thread_data->hev_caller;
 }
 
-static ssize_t
-ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
+static Lstream_data_count
+ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
+                    Lstream_data_count size)
 {
   /* This function must be called from the main thread only */
   struct ntpipe_slurp_stream_shared_data* s =
@@ -580,8 +586,9 @@ get_ntpipe_output_stream_param (Lstream *stream)
 }
 #endif
 
-static ssize_t
-ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
+static Lstream_data_count
+ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
+                    Lstream_data_count size)
 {
   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
 
@@ -663,7 +670,7 @@ struct winsock_stream
   LPARAM user_data;            /* Any user data stored in the stream object */
   SOCKET s;                    /* Socket handle (which is a Win32 handle)   */
   OVERLAPPED ov;               /* Overlapped I/O structure                  */
-  void* buffer;                        /* Buffer. Allocated for input stream only   */
+  void* buffer;                        /* Buffer.                                   */
   unsigned long bufsize;       /* Number of bytes last read                 */
   unsigned long bufpos;                /* Position in buffer for next fetch         */
   unsigned int error_p :1;     /* I/O Error seen                            */
@@ -697,8 +704,8 @@ winsock_initiate_read (struct winsock_stream *str)
     str->eof_p = 1;
 }
 
-static ssize_t
-winsock_reader (Lstream *stream, unsigned char *data, size_t size)
+static Lstream_data_count
+winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
 
@@ -732,7 +739,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
     return -1;
 
   /* Return as much of buffer as we have */
-  size = min (size, (size_t) (str->bufsize - str->bufpos));
+  size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
   memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
   str->bufpos += size;
 
@@ -743,8 +750,9 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size)
   return size;
 }
 
-static ssize_t
-winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
+static Lstream_data_count
+winsock_writer (Lstream *stream, const unsigned char *data,
+               Lstream_data_count size)
 {
   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
 
@@ -772,18 +780,24 @@ winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
   if (size == 0)
     return 0;
 
-  {
-    ResetEvent (str->ov.hEvent);
-
-    /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
-     * an overlapped operation. This fails on Win95 with winsock 1.x so we
-     * supply a spare address which is ignored by Win95 anyway. Sheesh. */
-    if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
-       || GetLastError() == ERROR_IO_PENDING)
-      str->pending_p = 1;
-    else
-      str->error_p = 1;
-  }
+  ResetEvent (str->ov.hEvent);
+
+  /* According to WriteFile docs, we must hold onto the data we pass to it
+     and not make any changes until it finishes -- which may not be until
+     the next time we get here, since we use asynchronous I/O.  We have
+     in fact seen data loss as a result of not doing this. */
+  str->buffer = xrealloc (str->buffer, size);
+  memcpy (str->buffer, data, size);
+
+  /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL
+     on Win95 even when doing an overlapped operation, as we are, where
+     the return value through that parameter is not meaningful. */
+  if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize,
+                &str->ov)
+      || GetLastError() == ERROR_IO_PENDING)
+    str->pending_p = 1;
+  else
+    str->error_p = 1;
 
   return str->error_p ? -1 : size;
 }
@@ -802,8 +816,11 @@ winsock_closer (Lstream *lstr)
   if (str->pending_p)
     WaitForSingleObject (str->ov.hEvent, INFINITE);
 
-  if (lstr->flags & LSTREAM_FL_READ)
-    xfree (str->buffer);
+  if (str->buffer)
+    {
+      xfree (str->buffer);
+      str->buffer = 0;
+    }
 
   CloseHandle (str->ov.hEvent);
   return 0;
@@ -823,14 +840,10 @@ make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
   Lstream *lstr = Lstream_new (lstream_winsock, mode);
   struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
 
+  xzero (*str);
   str->s = s;
-  str->blocking_p = 0;
-  str->error_p = 0;
-  str->eof_p = 0;
-  str->pending_p = 0;
   str->user_data = param;
 
-  xzero (str->ov);
   str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
 
   if (lstr->flags & LSTREAM_FL_READ)
@@ -1041,13 +1054,11 @@ mswindows_dequeue_dispatch_event (void)
                         &mswindows_s_dispatch_event_queue_tail :
                         &mswindows_u_dispatch_event_queue_tail);
 
-  sevt = XEVENT(event);
+  sevt = XEVENT (event);
   if (sevt->event_type == key_press_event
       && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
-    {
-      sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
-      --mswindows_quit_chars_count;
-    }
+    sevt->event.key.modifiers &=
+      ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
 
   return event;
 }
@@ -1337,6 +1348,10 @@ mswindows_drain_windows_queue (void)
  * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
  * which will never come when there are no pending timers, which leads
  * to deadlock, we simply signal an error.
+ *
+ * It might be possible to combine this with mswindows_drain_windows_queue
+ * which fetches events when not in a modal loop.  It's not clear
+ * whether the result would be more complex than is justified.
  */
 static void
 mswindows_need_event_in_modal_loop (int badly_p)
@@ -1360,8 +1375,8 @@ mswindows_need_event_in_modal_loop (int badly_p)
        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);
+      if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
+       DispatchMessage (&msg);
     }
 }
 
@@ -1377,12 +1392,6 @@ mswindows_need_event (int badly_p)
 {
   int active;
 
-  if (mswindows_in_modal_loop)
-    {
-      mswindows_need_event_in_modal_loop (badly_p);
-      return;
-    }
-
   while (NILP (mswindows_u_dispatch_event_queue)
         && NILP (mswindows_s_dispatch_event_queue))
     {
@@ -1399,6 +1408,10 @@ mswindows_need_event (int badly_p)
          EMACS_SET_SECS_USECS (sometime, 0, 0);
          EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
          pointer_to_this = &select_time_to_block;
+         if (mswindows_in_modal_loop)
+           /* In modal loop with badly_p false, don't care about
+              Windows events. */
+           FD_CLR (windows_fd, &temp_mask);
        }
 
       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
@@ -1412,7 +1425,10 @@ mswindows_need_event (int badly_p)
        {
          if (FD_ISSET (windows_fd, &temp_mask))
            {
-             mswindows_drain_windows_queue ();
+             if (mswindows_in_modal_loop)
+               mswindows_need_event_in_modal_loop (badly_p);
+             else
+               mswindows_drain_windows_queue ();
            }
          else
            {
@@ -1477,10 +1493,24 @@ mswindows_need_event (int badly_p)
        }
 #else
       /* Now try getting a message or process event */
+      DWORD what_events;
+      if (mswindows_in_modal_loop)
+       /* In a modal loop, only look for timer events, and only if
+          we really need one. */
+       {
+         if (badly_p)
+           what_events = QS_TIMER;
+         else
+           what_events = 0;
+       }
+      else
+       /* Look for any event */
+       what_events = QS_ALLINPUT;
+
       active = MsgWaitForMultipleObjects (mswindows_waitable_count,
                                          mswindows_waitable_handles,
                                          FALSE, badly_p ? INFINITE : 0,
-                                         QS_ALLINPUT);
+                                         what_events);
 
       /* This will assert if handle being waited for becomes abandoned.
         Not the case currently tho */
@@ -1496,7 +1526,10 @@ mswindows_need_event (int badly_p)
       else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
        {
          /* Got your message, thanks */
-         mswindows_drain_windows_queue ();
+         if (mswindows_in_modal_loop)
+           mswindows_need_event_in_modal_loop (badly_p);
+         else
+           mswindows_drain_windows_queue ();
        }
       else
        {
@@ -1513,7 +1546,12 @@ mswindows_need_event (int badly_p)
            {
              /* None. This means that the process handle itself has signaled.
                 Remove the handle from the wait vector, and make status_notify
-                note the exited process */
+                note the exited process.  First find the process object if
+                possible. */
+             LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
+               if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
+                   mswindows_waitable_handles [ix])
+                 break;
              mswindows_waitable_handles [ix] =
                mswindows_waitable_handles [--mswindows_waitable_count];
              kick_status_notify ();
@@ -1522,10 +1560,12 @@ mswindows_need_event (int badly_p)
                 process, and (2) status notifications will happen in
                 accept-process-output, sleep-for, and sit-for. */
              /* #### horrible kludge till my real process fixes go in.
+                #### Replaced with a slightly less horrible kluge that
+                     at least finds the right process instead of axing the
+                     first one on the list.
               */
-             if (!NILP (Vprocess_list))
+             if (!NILP (vproctail))
                {
-                 Lisp_Object vaffanculo = XCAR (Vprocess_list);
                  mswindows_enqueue_process_event (XPROCESS (vaffanculo));
                }
              else /* trash me soon. */
@@ -1571,6 +1611,8 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
  * depends on dnd support.
  */
 #ifdef HAVE_DRAGNDROP
+extern int mswindows_dde_enable;
+
 HDDEDATA CALLBACK
 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
                        HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
@@ -1597,6 +1639,9 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
       return (HDDEDATA)NULL;
 
     case XTYP_EXECUTE:
+      if (!mswindows_dde_enable)
+       return (HDDEDATA) DDE_FBUSY;
+
       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
        {
          DWORD len = DdeGetData (hdata, NULL, 0, 0);
@@ -1604,7 +1649,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
          char *end;
          char *filename;
          struct gcpro gcpro1, gcpro2;
-          Lisp_Object l_dndlist = Qnil;
+         Lisp_Object l_dndlist = Qnil;
          Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
          Lisp_Object frmcons, devcons, concons;
          Lisp_Event *event = XEVENT (emacs_event);
@@ -1640,9 +1685,9 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
            return DDE_FNOTPROCESSED;
 
 #ifdef CYGWIN
-         filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
+         filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
          strcpy (filename, "file:");
-         cygwin32_win32_to_posix_path_list (cmd, filename+5);
+         cygwin_win32_to_posix_path_list (cmd, filename+5);
 #else
          dostounix_filename (cmd);
          filename = alloca (strlen (cmd)+6);
@@ -2025,10 +2070,14 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
   struct frame *frame;
   struct mswindows_frame* msframe;
 
-  /* Not perfect but avoids crashes. There is potential for wierd
-     behavior here. */
-  if (gc_in_progress)
-    goto defproc;
+  /* If you hit this, rewrite the offending API call to occur after GC,
+     using register_post_gc_action(). */
+  assert (!gc_in_progress);
+
+#ifdef DEBUG_XEMACS
+  if (debug_mswindows_events)
+    debug_output_mswin_message (hwnd, message_, wParam, lParam);
+#endif /* DEBUG_XEMACS */
 
   assert (!GetWindowLong (hwnd, GWL_USERDATA));
   switch (message_)
@@ -2064,13 +2113,8 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
        int should_set_keymap = 0;
 
 #ifdef DEBUG_XEMACS
-       if (debug_mswindows_events)
-         {
-           stderr_out ("%s wparam=%d lparam=%d\n",
-                       message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
-                       wParam, (int)lParam);
-           output_alt_keyboard_state ();
-         }
+       if (debug_mswindows_events > 2)
+         output_alt_keyboard_state ();
 #endif /* DEBUG_XEMACS */
 
        mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
@@ -2115,19 +2159,14 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
        BYTE keymap_orig[256];
        BYTE keymap_sticky[256];
        int has_AltGr = mswindows_current_layout_has_AltGr ();
-       int mods = 0;
+       int mods = 0, mods_with_shift = 0;
        int extendedp = lParam & 0x1000000;
        Lisp_Object keysym;
        int sticky_changed;
 
 #ifdef DEBUG_XEMACS
-       if (debug_mswindows_events)
-         {
-           stderr_out ("%s wparam=%d lparam=%d\n",
-                       message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
-                       wParam, (int)lParam);
-           output_alt_keyboard_state ();
-         }
+       if (debug_mswindows_events > 2)
+         output_alt_keyboard_state ();
 #endif /* DEBUG_XEMACS */
 
        GetKeyboardState (keymap_orig);
@@ -2150,6 +2189,7 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
          memcpy (keymap_sticky, keymap_orig, 256);
 
        mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
+       mods_with_shift = mods;
 
        /* Handle non-printables */
        if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
@@ -2218,23 +2258,38 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
                   || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
                                   PM_REMOVE))
              {
-               int mods1 = mods;
+               int mods_with_quit = mods;
                WPARAM ch = tranmsg.wParam;
 
+#ifdef DEBUG_XEMACS
+               if (debug_mswindows_events)
+                 {
+                   stderr_out ("-> ");
+                   debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
+                                               tranmsg.wParam,
+                                               tranmsg.lParam);
+                 }
+#endif /* DEBUG_XEMACS */
+
                /* If a quit char with no modifiers other than control and
                   shift, then mark it with a fake modifier, which is removed
                   upon dequeueing the event */
-               /* #### This might also not withstand localization, if
-                  quit character is not a latin-1 symbol */
+               /* !!#### Fix this in my mule ws -- replace current_buffer
+                  with 0 */
                if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
-                     && quit_ch + 'a' - 1 == ch)
+                     && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
+                     DOWNCASE (current_buffer, ch))
                     || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
-                        && quit_ch == ch))
-                   && ((mods  & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
+                        && DOWNCASE (current_buffer, quit_ch) ==
+                        DOWNCASE (current_buffer, ch)))
+                   && ((mods_with_shift &
+                        ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
                        == 0))
                  {
-                   mods1 |= FAKE_MOD_QUIT;
-                   ++mswindows_quit_chars_count;
+                   mods_with_quit |= FAKE_MOD_QUIT;
+                   if (mods_with_shift & XEMACS_MOD_SHIFT)
+                     mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
+                   mswindows_quit_chars_count++;
                  }
                else if (potential_accelerator && !got_accelerator &&
                         mswindows_char_is_accelerator (frame, ch))
@@ -2242,7 +2297,8 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
                    got_accelerator = 1;
                    break;
                  }
-               mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
+               mswindows_enqueue_keypress_event (hwnd, make_char (ch),
+                                                 mods_with_quit);
              } /* while */
 
            /* This generates WM_SYSCHAR messages, which are interpreted
@@ -2563,6 +2619,33 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
       mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
       break;
 
+    case WM_WINDOWPOSCHANGED:
+      /* This is sent before WM_SIZE; in fact, the processing of this
+        by DefWindowProc() sends WM_SIZE.  But WM_SIZE is not sent when
+        a window is hidden (make-frame-invisible), so we need to process
+        this and update the state flags. */
+      {
+       fobj = mswindows_find_frame (hwnd);
+       frame = XFRAME (fobj);
+       if (IsIconic (hwnd))
+         {
+           FRAME_VISIBLE_P (frame) = 0;
+           FRAME_ICONIFIED_P (frame) = 1;
+         }
+       else if (IsWindowVisible (hwnd))
+         {
+           FRAME_VISIBLE_P (frame) = 1;
+           FRAME_ICONIFIED_P (frame) = 0;
+         }
+       else
+         {
+           FRAME_VISIBLE_P (frame) = 0;
+           FRAME_ICONIFIED_P (frame) = 0;
+         }         
+
+       return DefWindowProc (hwnd, message_, wParam, lParam);
+      }
+
     case WM_SIZE:
       /* We only care about this message if our size has really changed */
       if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
@@ -2581,7 +2664,6 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
          if (wParam==SIZE_MINIMIZED)
            {
              /* Iconified */
-             FRAME_VISIBLE_P (frame) = 0;
              mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
            }
          else
@@ -2617,7 +2699,6 @@ 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 || mswindows_dynamic_frame_resize)
                    redisplay ();
@@ -2742,10 +2823,13 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
        int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
        struct gcpro gcpro1, gcpro2;
 
-       if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys,  delta))
+       if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
+                                              keys, delta,
+                                              MAKEPOINTS (lParam)))
          {
            GCPRO2 (emacs_event, fobj);
-           mswindows_pump_outstanding_events ();       /* Can GC */
+           if (UNBOUNDP(mswindows_pump_outstanding_events ())) /* Can GC */
+             SendMessage (hwnd, WM_CANCELMODE, 0, 0);
            UNGCPRO;
          }
        else
@@ -2917,14 +3001,14 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
                    if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
                                                     &ppf) == S_OK)
                      {
-                       WORD wsz[MAX_PATH];
+                       OLECHAR wsz[PATH_MAX];
                        WIN32_FIND_DATA wfd;
-                       LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
+                       LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
 
-                       MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
+                       MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
 
                        if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
-                           (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
+                           (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
                                                   &wfd, 0)==S_OK))
                          {
                            xfree (fname);
@@ -2941,9 +3025,9 @@ mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
 #endif
 
 #ifdef CYGWIN
-           filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
+           filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
            strcpy (filename, "file:");
-           cygwin32_win32_to_posix_path_list (fname, filename+5);
+           cygwin_win32_to_posix_path_list (fname, filename+5);
 #else
            filename = (char *)xmalloc (len+6);
            strcat (strcpy (filename, "file:"), fname);
@@ -3194,7 +3278,7 @@ mswindows_find_console (HWND hwnd)
 /*
  * Find the frame that matches the supplied mswindows window handle
  */
-static Lisp_Object
+Lisp_Object
 mswindows_find_frame (HWND hwnd)
 {
   LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
@@ -3430,8 +3514,9 @@ emacs_mswindows_quit_p (void)
   if (mswindows_in_modal_loop)
     return;
 
-  /* Drain windows queue. This sets up number of quit characters in
-     the queue */
+  mswindows_quit_chars_count = 0;
+  /* Drain windows queue.  This sets up number of quit characters in
+     the queue. */
   mswindows_drain_windows_queue ();
 
   if (mswindows_quit_chars_count > 0)
@@ -3444,15 +3529,17 @@ emacs_mswindows_quit_p (void)
       match_against.event_type = key_press_event;
       match_against.event.key.modifiers = FAKE_MOD_QUIT;
 
-      while (mswindows_quit_chars_count-- > 0)
+      while (mswindows_quit_chars_count > 0)
        {
          emacs_event = mswindows_cancel_dispatch_event (&match_against);
          assert (!NILP (emacs_event));
 
-         if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
+         if (XEVENT (emacs_event)->event.key.modifiers &
+             FAKE_MOD_QUIT_CRITICAL)
            critical_p = 1;
 
-         Fdeallocate_event(emacs_event);
+         Fdeallocate_event (emacs_event);
+         mswindows_quit_chars_count--;
        }
 
       Vquit_flag = critical_p ? Qcritical : Qt;
@@ -3588,6 +3675,322 @@ debug_process_finalization (Lisp_Process *p)
 }
 #endif
 
+#ifdef DEBUG_XEMACS
+
+struct mswin_message_debug
+{
+  int mess;
+  char *string;
+};
+
+#define FROB(val) { val, #val, },
+
+struct mswin_message_debug debug_mswin_messages[] =
+{
+FROB (WM_NULL)
+FROB (WM_CREATE)
+FROB (WM_DESTROY)
+FROB (WM_MOVE)
+FROB (WM_SIZE)
+
+FROB (WM_ACTIVATE)
+
+FROB (WM_SETFOCUS)
+FROB (WM_KILLFOCUS)
+FROB (WM_ENABLE)
+FROB (WM_SETREDRAW)
+FROB (WM_SETTEXT)
+FROB (WM_GETTEXT)
+FROB (WM_GETTEXTLENGTH)
+FROB (WM_PAINT)
+FROB (WM_CLOSE)
+FROB (WM_QUERYENDSESSION)
+FROB (WM_QUIT)
+FROB (WM_QUERYOPEN)
+FROB (WM_ERASEBKGND)
+FROB (WM_SYSCOLORCHANGE)
+FROB (WM_ENDSESSION)
+FROB (WM_SHOWWINDOW)
+FROB (WM_WININICHANGE)
+#if(WINVER >= 0x0400)
+FROB (WM_SETTINGCHANGE)
+#endif /* WINVER >= 0x0400 */
+
+FROB (WM_DEVMODECHANGE)
+FROB (WM_ACTIVATEAPP)
+FROB (WM_FONTCHANGE)
+FROB (WM_TIMECHANGE)
+FROB (WM_CANCELMODE)
+FROB (WM_SETCURSOR)
+FROB (WM_MOUSEACTIVATE)
+FROB (WM_CHILDACTIVATE)
+FROB (WM_QUEUESYNC)
+
+FROB (WM_GETMINMAXINFO)
+
+FROB (WM_PAINTICON)
+FROB (WM_ICONERASEBKGND)
+FROB (WM_NEXTDLGCTL)
+FROB (WM_SPOOLERSTATUS)
+FROB (WM_DRAWITEM)
+FROB (WM_MEASUREITEM)
+FROB (WM_DELETEITEM)
+FROB (WM_VKEYTOITEM)
+FROB (WM_CHARTOITEM)
+FROB (WM_SETFONT)
+FROB (WM_GETFONT)
+FROB (WM_SETHOTKEY)
+FROB (WM_GETHOTKEY)
+FROB (WM_QUERYDRAGICON)
+FROB (WM_COMPAREITEM)
+#if(WINVER >= 0x0500)
+FROB (WM_GETOBJECT)
+#endif /* WINVER >= 0x0500 */
+FROB (WM_COMPACTING)
+FROB (WM_COMMNOTIFY)
+FROB (WM_WINDOWPOSCHANGING)
+FROB (WM_WINDOWPOSCHANGED)
+
+FROB (WM_POWER)
+
+FROB (WM_COPYDATA)
+FROB (WM_CANCELJOURNAL)
+
+#if(WINVER >= 0x0400)
+FROB (WM_NOTIFY)
+FROB (WM_INPUTLANGCHANGEREQUEST)
+FROB (WM_INPUTLANGCHANGE)
+FROB (WM_TCARD)
+FROB (WM_HELP)
+FROB (WM_USERCHANGED)
+FROB (WM_NOTIFYFORMAT)
+
+FROB (WM_CONTEXTMENU)
+FROB (WM_STYLECHANGING)
+FROB (WM_STYLECHANGED)
+FROB (WM_DISPLAYCHANGE)
+FROB (WM_GETICON)
+FROB (WM_SETICON)
+#endif /* WINVER >= 0x0400 */
+
+FROB (WM_NCCREATE)
+FROB (WM_NCDESTROY)
+FROB (WM_NCCALCSIZE)
+FROB (WM_NCHITTEST)
+FROB (WM_NCPAINT)
+FROB (WM_NCACTIVATE)
+FROB (WM_GETDLGCODE)
+#ifdef WM_SYNCPAINT /* not in VC 5 */
+FROB (WM_SYNCPAINT)
+#endif /* WM_SYNCPAINT */
+FROB (WM_NCMOUSEMOVE)
+FROB (WM_NCLBUTTONDOWN)
+FROB (WM_NCLBUTTONUP)
+FROB (WM_NCLBUTTONDBLCLK)
+FROB (WM_NCRBUTTONDOWN)
+FROB (WM_NCRBUTTONUP)
+FROB (WM_NCRBUTTONDBLCLK)
+FROB (WM_NCMBUTTONDOWN)
+FROB (WM_NCMBUTTONUP)
+FROB (WM_NCMBUTTONDBLCLK)
+
+/* FROB (WM_KEYFIRST) */
+FROB (WM_KEYDOWN)
+FROB (WM_KEYUP)
+FROB (WM_CHAR)
+FROB (WM_DEADCHAR)
+FROB (WM_SYSKEYDOWN)
+FROB (WM_SYSKEYUP)
+FROB (WM_SYSCHAR)
+FROB (WM_SYSDEADCHAR)
+FROB (WM_KEYLAST)
+
+#if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
+FROB (WM_IME_STARTCOMPOSITION)
+FROB (WM_IME_ENDCOMPOSITION)
+FROB (WM_IME_COMPOSITION)
+FROB (WM_IME_KEYLAST)
+#endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
+
+FROB (WM_INITDIALOG)
+FROB (WM_COMMAND)
+FROB (WM_SYSCOMMAND)
+FROB (WM_TIMER)
+FROB (WM_HSCROLL)
+FROB (WM_VSCROLL)
+FROB (WM_INITMENU)
+FROB (WM_INITMENUPOPUP)
+FROB (WM_MENUSELECT)
+FROB (WM_MENUCHAR)
+FROB (WM_ENTERIDLE)
+#if(WINVER >= 0x0500)
+FROB (WM_MENURBUTTONUP)
+FROB (WM_MENUDRAG)
+FROB (WM_MENUGETOBJECT)
+FROB (WM_UNINITMENUPOPUP)
+FROB (WM_MENUCOMMAND)
+#endif /* WINVER >= 0x0500 */
+
+
+FROB (WM_CTLCOLORMSGBOX)
+FROB (WM_CTLCOLOREDIT)
+FROB (WM_CTLCOLORLISTBOX)
+FROB (WM_CTLCOLORBTN)
+FROB (WM_CTLCOLORDLG)
+FROB (WM_CTLCOLORSCROLLBAR)
+FROB (WM_CTLCOLORSTATIC)
+
+
+/* FROB (WM_MOUSEFIRST) */
+FROB (WM_MOUSEMOVE)
+FROB (WM_LBUTTONDOWN)
+FROB (WM_LBUTTONUP)
+FROB (WM_LBUTTONDBLCLK)
+FROB (WM_RBUTTONDOWN)
+FROB (WM_RBUTTONUP)
+FROB (WM_RBUTTONDBLCLK)
+FROB (WM_MBUTTONDOWN)
+FROB (WM_MBUTTONUP)
+FROB (WM_MBUTTONDBLCLK)
+
+#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
+FROB (WM_MOUSEWHEEL)
+FROB (WM_MOUSELAST)
+#else
+FROB (WM_MOUSELAST)
+#endif /* if (_WIN32_WINNT < 0x0400) */
+
+FROB (WM_PARENTNOTIFY)
+FROB (WM_ENTERMENULOOP)
+FROB (WM_EXITMENULOOP)
+
+#if(WINVER >= 0x0400)
+FROB (WM_NEXTMENU)
+
+FROB (WM_SIZING)
+FROB (WM_CAPTURECHANGED)
+FROB (WM_MOVING)
+FROB (WM_POWERBROADCAST)
+
+FROB (WM_DEVICECHANGE)
+
+#endif /* WINVER >= 0x0400 */
+
+FROB (WM_MDICREATE)
+FROB (WM_MDIDESTROY)
+FROB (WM_MDIACTIVATE)
+FROB (WM_MDIRESTORE)
+FROB (WM_MDINEXT)
+FROB (WM_MDIMAXIMIZE)
+FROB (WM_MDITILE)
+FROB (WM_MDICASCADE)
+FROB (WM_MDIICONARRANGE)
+FROB (WM_MDIGETACTIVE)
+
+
+FROB (WM_MDISETMENU)
+FROB (WM_ENTERSIZEMOVE)
+FROB (WM_EXITSIZEMOVE)
+FROB (WM_DROPFILES)
+FROB (WM_MDIREFRESHMENU)
+
+#ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
+
+#if(WINVER >= 0x0400) && !defined(CYGWIN)
+FROB (WM_IME_SETCONTEXT)
+FROB (WM_IME_NOTIFY)
+FROB (WM_IME_CONTROL)
+FROB (WM_IME_COMPOSITIONFULL)
+FROB (WM_IME_SELECT)
+FROB (WM_IME_CHAR)
+#endif /* WINVER >= 0x0400 */
+#if(WINVER >= 0x0500)
+FROB (WM_IME_REQUEST)
+#endif /* WINVER >= 0x0500 */
+#if(WINVER >= 0x0400) && !defined(CYGWIN)
+FROB (WM_IME_KEYDOWN)
+FROB (WM_IME_KEYUP)
+#endif /* WINVER >= 0x0400 */
+
+#endif /* WM_IME_SETCONTEXT */
+
+#if(_WIN32_WINNT >= 0x0400)
+FROB (WM_MOUSEHOVER)
+FROB (WM_MOUSELEAVE)
+#endif /* _WIN32_WINNT >= 0x0400 */
+
+FROB (WM_CUT)
+FROB (WM_COPY)
+FROB (WM_PASTE)
+FROB (WM_CLEAR)
+FROB (WM_UNDO)
+FROB (WM_RENDERFORMAT)
+FROB (WM_RENDERALLFORMATS)
+FROB (WM_DESTROYCLIPBOARD)
+FROB (WM_DRAWCLIPBOARD)
+FROB (WM_PAINTCLIPBOARD)
+FROB (WM_VSCROLLCLIPBOARD)
+FROB (WM_SIZECLIPBOARD)
+FROB (WM_ASKCBFORMATNAME)
+FROB (WM_CHANGECBCHAIN)
+FROB (WM_HSCROLLCLIPBOARD)
+FROB (WM_QUERYNEWPALETTE)
+FROB (WM_PALETTEISCHANGING)
+FROB (WM_PALETTECHANGED)
+FROB (WM_HOTKEY)
+
+#if(WINVER >= 0x0400)
+FROB (WM_PRINT)
+FROB (WM_PRINTCLIENT)
+
+FROB (WM_HANDHELDFIRST)
+FROB (WM_HANDHELDLAST)
+
+FROB (WM_AFXFIRST)
+FROB (WM_AFXLAST)
+#endif /* WINVER >= 0x0400 */
+
+FROB (WM_PENWINFIRST)
+FROB (WM_PENWINLAST)
+};
+
+#undef FROB
+
+static void
+debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
+                           LPARAM lParam)
+{
+  Lisp_Object frame = mswindows_find_frame (hwnd);
+  int i;
+  char *str = 0;
+  /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
+
+  for (i = 0; i < countof (debug_mswin_messages); i++)
+    {
+      if (debug_mswin_messages[i].mess == message_)
+       {
+         str = debug_mswin_messages[i].string;
+         break;
+       }
+    }
+
+  if (str)
+    stderr_out ("%s", str);
+  else
+    stderr_out ("%x", message_);
+
+  if (debug_mswindows_events > 1)
+    {
+      stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
+                 wParam, (int) lParam, (unsigned int) hwnd);
+      debug_print (frame);
+    }
+  else
+    stderr_out ("\n");
+}
+
+#endif /* DEBUG_XEMACS */
+
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
@@ -3647,13 +4050,12 @@ vars_of_event_mswindows (void)
 
 #ifdef DEBUG_XEMACS
   DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
-If non-zero, display debug information about Windows events that XEmacs sees.
+If non-zero, display debug information about Windows messages that XEmacs sees.
 Information is displayed in a console window.  Currently defined values are:
 
-1 == non-verbose output
-2 == verbose output
-
-#### Unfortunately, not yet implemented.
+1 == non-verbose output (just the message name)
+2 == verbose output (all parameters)
+3 == even more verbose output (extra debugging info)
 */ );
   debug_mswindows_events = 0;
 #endif
@@ -3725,7 +4127,7 @@ lstream_type_create_mswindows_selectable (void)
 {
   init_slurp_stream ();
   init_shove_stream ();
-#if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
+#if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
   init_winsock_stream ();
 #endif
 }