changeset 23950:d8f8533db4cc

(w32_msg_pump): Ignore WM_NULL message posted to thread by complete_deferred_msg. (post_character_message): Cancel all deferred messages when quit_char is typed, in order to break out of potential deadlocks. (cancel_all_deferred_msgs): New function. (complete_deferred_msg): Don't abort if msg not found; may have been cancelled. (Fw32_reconstruct_hot_key): Use pre-interned symbols. (Fw32_send_sys_command): Wait for system command to complete before returning.
author Andrew Innes <andrewi@gnu.org>
date Mon, 28 Dec 1998 19:42:26 +0000
parents 9f8417cca07b
children ef1cba882819
files src/w32fns.c
diffstat 1 files changed, 90 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32fns.c	Mon Dec 28 19:33:57 1998 +0000
+++ b/src/w32fns.c	Mon Dec 28 19:42:26 1998 +0000
@@ -3355,45 +3355,6 @@
     }
 }
 
-static void
-post_character_message (hwnd, msg, wParam, lParam, modifiers)
-     HWND hwnd;
-     UINT msg;
-     WPARAM wParam;
-     LPARAM lParam;
-     DWORD  modifiers;
-
-{
-  W32Msg wmsg;
-
-  wmsg.dwModifiers = modifiers;
-
-  /* Detect quit_char and set quit-flag directly.  Note that we
-     still need to post a message to ensure the main thread will be
-     woken up if blocked in sys_select(), but we do NOT want to post
-     the quit_char message itself (because it will usually be as if
-     the user had typed quit_char twice).  Instead, we post a dummy
-     message that has no particular effect. */
-  {
-    int c = wParam;
-    if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
-      c = make_ctrl_char (c) & 0377;
-    if (c == quit_char)
-      {
-	Vquit_flag = Qt;
-
-	/* The choice of message is somewhat arbitrary, as long as
-	   the main thread handler just ignores it. */
-	msg = WM_NULL;
-
-	/* Interrupt any blocking system calls.  */
-	signal_quit ();
-      }
-  }
-
-  my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
-}
-
 /* Main message dispatch loop. */
 
 static void
@@ -3411,6 +3372,9 @@
 	{
 	  switch (msg.message)
 	    {
+	    case WM_NULL:
+	      /* Produced by complete_deferred_msg; just ignore.  */
+	      break;
 	    case WM_EMACS_CREATEWINDOW:
 	      w32_createwindow ((struct frame *) msg.wParam);
 	      if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
@@ -3560,7 +3524,8 @@
   deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
 
   if (msg_buf == NULL)
-    abort ();
+    /* Message may have been cancelled, so don't abort().  */
+    return;
 
   msg_buf->result = result;
   msg_buf->completed = 1;
@@ -3569,6 +3534,26 @@
   PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
 }
 
+void
+cancel_all_deferred_msgs ()
+{
+  deferred_msg * item;
+
+  /* Don't actually need synchronization for read access, since
+     modification of single pointer is always atomic.  */
+  /* enter_crit (); */
+
+  for (item = deferred_msg_head; item != NULL; item = item->next)
+    {
+      item->result = 0;
+      item->completed = 1;
+    }
+
+  /* leave_crit (); */
+
+  /* Ensure input thread is woken so it notices the completion.  */
+  PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
+}
 
 DWORD 
 w32_msg_worker (dw)
@@ -3595,6 +3580,66 @@
   return 0;
 }
 
+static void
+post_character_message (hwnd, msg, wParam, lParam, modifiers)
+     HWND hwnd;
+     UINT msg;
+     WPARAM wParam;
+     LPARAM lParam;
+     DWORD  modifiers;
+
+{
+  W32Msg wmsg;
+
+  wmsg.dwModifiers = modifiers;
+
+  /* Detect quit_char and set quit-flag directly.  Note that we
+     still need to post a message to ensure the main thread will be
+     woken up if blocked in sys_select(), but we do NOT want to post
+     the quit_char message itself (because it will usually be as if
+     the user had typed quit_char twice).  Instead, we post a dummy
+     message that has no particular effect. */
+  {
+    int c = wParam;
+    if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
+      c = make_ctrl_char (c) & 0377;
+    if (c == quit_char)
+      {
+	Vquit_flag = Qt;
+
+	/* The choice of message is somewhat arbitrary, as long as
+	   the main thread handler just ignores it. */
+	msg = WM_NULL;
+
+	/* Interrupt any blocking system calls.  */
+	signal_quit ();
+
+	/* As a safety precaution, forcibly complete any deferred
+           messages.  This is a kludge, but I don't see any particularly
+           clean way to handle the situation where a deferred message is
+           "dropped" in the lisp thread, and will thus never be
+           completed, eg. by the user trying to activate the menubar
+           when the lisp thread is busy, and then typing C-g when the
+           menubar doesn't open promptly (with the result that the
+           menubar never responds at all because the deferred
+           WM_INITMENU message is never completed).  Another problem
+           situation is when the lisp thread calls SendMessage (to send
+           a window manager command) when a message has been deferred;
+           the lisp thread gets blocked indefinitely waiting for the
+           deferred message to be completed, which itself is waiting for
+           the lisp thread to respond.
+
+	   Note that we don't want to block the input thread waiting for
+	   a reponse from the lisp thread (although that would at least
+	   solve the deadlock problem above), because we want to be able
+	   to receive C-g to interrupt the lisp thread.  */
+	cancel_all_deferred_msgs ();
+      }
+  }
+
+  my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+}
+
 /* Main window procedure */
 
 LRESULT CALLBACK 
@@ -6524,7 +6569,7 @@
 
   CHECK_NUMBER (command, 0);
 
-  PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
+  SendMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
 
   return Qnil;
 }
@@ -6700,13 +6745,13 @@
 
   key = Fcons (key, Qnil);
   if (w32_modifiers & MOD_SHIFT)
-    key = Fcons (intern ("shift"), key);
+    key = Fcons (Qshift, key);
   if (w32_modifiers & MOD_CONTROL)
-    key = Fcons (intern ("control"), key);
+    key = Fcons (Qctrl, key);
   if (w32_modifiers & MOD_ALT)
-    key = Fcons (intern (NILP (Vw32_alt_is_meta) ? "alt" : "meta"), key);
+    key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
   if (w32_modifiers & MOD_WIN)
-    key = Fcons (intern ("hyper"), key);
+    key = Fcons (Qhyper, key);
 
   return key;
 }