diff src/event-msw.c @ 1268:fffe735e63ee

[xemacs-hg @ 2003-02-07 11:50:50 by ben] fixes for menu crashes + better preemption behavior This contains two related changes: (1) Fix problems with reentrant calling of lwlib and associated crashes when selecting menu items. (2) Improve redisplay handling of preemption. Turn on lazy lock and hold down page-down or page-up and you'll see what I mean. They are related because they both touch on the code that retrieves events and handles the internal queues. console-msw.h, event-msw.c, event-stream.c, events.h, menubar-msw.c, menubar-x.c, menubar.h: mswindows_protect_modal_loop() has been generalized to event_stream_protect_modal_loop(), and moved to event-stream.c. mswindows_in_modal_loop ->in_modal_loop likewise. Changes in event-msw.c and menubar-msw.c for the new names and calling format (use structures instead of static variables in menubar-msw.c). Delete former in_menu_callback and use in_modal_loop in its place. Remove emacs_mswindows_quit_check_disallowed_p(), superseded by in_modal_loop. Use event_stream_protect_modal_loop() in pre_activate_callback() so that we get no lwlib reentrancy. Rearrange some of the code in event-msw.c to be grouped better. Make mswindows_drain_windows_queue() respect in_modal_loop and do nothing if so. cmdloop.c, event-stream.c: Don't conditionalize on LWLIB_MENUBARS_LUCID when giving error when in_modal_loop, and give better error. event-Xt.c, event-gtk.c: If in_modal_loop, only retrieve process and timeout events. Don't retrieve any X events because processing them can lead to reentrancy in lwlib -> death. event-stream.c: Remove unused parameter to check_event_stream_ok() and change all callers. lisp.h, event-stream.c: Rearrange some functions for increased clarity -- in particular, group all the input-pending/QUIT-related stuff together, and put right next to next-event stuff, to which it's related. Add the concept of "HOW_MANY" -- when asking whether user input is pending, you can ask if at least HOW_MANY events are pending, not just if any are. Add parameter to detect_input_pending() for this. Change recursive_sit_for from a Lisp_Object (which could only be Qt or Qnil) to an int, like it should be. event-Xt.c, event-gtk.c, event-xlike-inc.c: New file. Abstract out similar code in event_{Xt/gtk}_pending_p() and write only once, using include-file tricks. Rewrite this function to implement HOW_MANY and only process events when not in_modal_loop. event-msw.c: Implement HOW_MANY and only process events when not in_modal_loop. event-tty.c: Implement HOW_MANY. redisplay.c: Add var `max-preempts' to control maximum number of preempts. (#### perhaps not useful) Rewrite preemption check so that, rather than preempting when any user events are available, only preempt when a certain number (currently 4) of them are backed up. This effectively allows redisplay to proceed to completion in the presence of a fast auto-repeat (usually the auto-repeating is generated dynamically as necessary), and you get much better display behavior with lazy-lock active. event-unixoid.c: Comment changes. event-stream.c: Rewrite discard-input much more simply and safely using the drain-queue functions. I think the old version might loop forever if called when in_modal_loop. SEMI-UNRELATED CHANGES: ----------------------- event-stream.c: Turn QUIT-checking back on when running the pre-idle hook so it can be quit out of. indent.c: Document exact functioning of `vertical-motion' better, and its differences from GNU Emacs.
author ben
date Fri, 07 Feb 2003 11:50:54 +0000
parents f0af455e89d9
children cd0abfdb9e9d
line wrap: on
line diff
--- a/src/event-msw.c	Fri Feb 07 01:43:07 2003 +0000
+++ b/src/event-msw.c	Fri Feb 07 11:50:54 2003 +0000
@@ -1,7 +1,7 @@
 /* The mswindows event_stream interface.
    Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 1996, 2000, 2001, 2002 Ben Wing.
+   Copyright (C) 1996, 2000, 2001, 2002, 2003 Ben Wing.
    Copyright (C) 1997 Jonathan Harris.
 
 This file is part of XEmacs.
@@ -169,7 +169,6 @@
 /* This is the event signaled by the event pump.
    See mswindows_pump_outstanding_events for comments */
 static int mswindows_error_caught_in_modal_loop;
-static int mswindows_in_modal_loop;
 
 /* Count of wound timers */
 static int mswindows_pending_timers_count;
@@ -1129,43 +1128,6 @@
   return !ascii_strcasecmp (class_name_buf, XEMACS_CLASS);
 }
 
-struct mswindows_protect_modal_loop
-{
-  Lisp_Object (*bfun) (Lisp_Object barg);
-  Lisp_Object barg;
-};
-
-static Lisp_Object
-mswindows_protect_modal_loop_1 (void *gack)
-{
-  struct mswindows_protect_modal_loop *gata =
-    (struct mswindows_protect_modal_loop *) gack;
-
-  return (gata->bfun) (gata->barg);
-}
-
-Lisp_Object
-mswindows_protect_modal_loop (const char *error_string,
-			      Lisp_Object (*bfun) (Lisp_Object barg),
-			      Lisp_Object barg, int flags)
-{
-  Lisp_Object tmp;
-  struct mswindows_protect_modal_loop bluh;
-
-  bluh.bfun = bfun;
-  bluh.barg = barg;
-
-  ++mswindows_in_modal_loop;
-  tmp = call_trapping_problems (Qevent, error_string,
-				flags, 0,
-				mswindows_protect_modal_loop_1, &bluh);
-  if (UNBOUNDP (tmp))
-    mswindows_error_caught_in_modal_loop = 1;
-  --mswindows_in_modal_loop;
-
-  return tmp;
-}
-
 void
 mswindows_unmodalize_signal_maybe (void)
 {
@@ -1177,7 +1139,7 @@
  * condition_case. See mswindows_pump_outstanding_events
  */
 static Lisp_Object
-mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
+mswindows_unsafe_pump_events (void *arg)
 {
   /* This function can call lisp */
   Lisp_Object event = Fmake_event (Qnil, Qnil);
@@ -1185,7 +1147,7 @@
   int do_redisplay = 0;
   GCPRO1 (event);
 
-  while (detect_input_pending ())
+  while (detect_input_pending (1))
     {
       Fnext_event (event, Qnil);
       Fdispatch_event (event);
@@ -1212,7 +1174,7 @@
  * 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 mswindows_in_modal_loop to nonzero.
+ * in_modal_loop to nonzero.
  *
  * Return value is Qt if no errors was trapped, or Qunbound if
  * there was an error.
@@ -1244,88 +1206,15 @@
   GCPRO1 (result);
 
   if (!mswindows_error_caught_in_modal_loop)
-    result = mswindows_protect_modal_loop
-      ("Error during event handling", mswindows_unsafe_pump_events, Qnil, 0);
+    result = event_stream_protect_modal_loop
+      ("Error during event handling", mswindows_unsafe_pump_events, 0, 0);
   UNGCPRO;
+  if (UNBOUNDP (result))
+    mswindows_error_caught_in_modal_loop = 1;
   return result;
 }
 
 /*
- * KEYBOARD_ONLY_P is set to non-zero when we are called from
- * QUITP, and are interesting in keyboard messages only.
- */
-static void
-mswindows_drain_windows_queue (void)
-{
-  MSG msg;
-
-  /* should call mswindows_need_event_in_modal_loop() if in modal loop */
-  assert (!mswindows_in_modal_loop);
-
-  while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
-    {
-#ifdef HAVE_DIALOGS
-      /* Don't translate messages destined for a dialog box, this
-	 makes keyboard traversal work. I think?? */
-      if (mswindows_is_dialog_msg (&msg))
-	{
-	  mswindows_unmodalize_signal_maybe ();
-	  continue;
-	}
-#endif /* HAVE_DIALOGS */
-
-      /* We have to translate messages that are not sent to an XEmacs
-         frame. This is so that key presses work ok in things like
-         edit fields. However, we *musn't* translate message for XEmacs
-         frames as this is handled in the wnd proc.
-         We also have to avoid generating paint magic events for windows
-	 that aren't XEmacs frames */
-
-      if (!mswindows_window_is_xemacs (msg.hwnd))
-	TranslateMessage (&msg);
-      else if (msg.message == WM_PAINT)
-	{
-	  struct mswindows_frame *msframe;
-	  
-	  /* hdc will be NULL unless this is a subwindow - in which case we
-	     shouldn't have received a paint message for it here. */
-	  assert (msg.wParam == 0);
-
-	  /* Queue a magic event for handling when safe */
-	  msframe =
-	    FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
-	  if (!msframe->paint_pending)
-	    {
-	      msframe->paint_pending = 1;
-	      mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
-	    }
-	  /* Don't dispatch. WM_PAINT is always the last message in the
-	     queue so it's OK to just return. */
-	  return;
-	}
-      qxeDispatchMessage (&msg);
-      mswindows_unmodalize_signal_maybe ();
-    }
-}
-
-static void
-emacs_mswindows_drain_queue (void)
-{
-  mswindows_drain_windows_queue ();
-#ifdef HAVE_TTY
-  drain_tty_devices ();
-#endif
-}
-
-static int
-emacs_mswindows_quit_check_disallowed_p (void)
-{
-  /* Quit cannot happen in modal loop: all program
-     input is dedicated to Windows. */
-  return mswindows_in_modal_loop;
-}
-
-/*
  * 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
@@ -1371,6 +1260,73 @@
     }
 }
 
+/* BADLY_P non-zero means we were called from mswindows_need_event(1).  It
+   only matters when we are in a modal loop, and causes us to fetch timer
+   events (the only kinds we can fetch in such a case).
+ */
+static void
+mswindows_drain_windows_queue (int badly_p)
+{
+  MSG msg;
+
+  if (in_modal_loop)
+    mswindows_need_event_in_modal_loop (badly_p);
+  else
+    while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+      {
+#ifdef HAVE_DIALOGS
+	/* Don't translate messages destined for a dialog box, this
+	   makes keyboard traversal work. I think?? */
+	if (mswindows_is_dialog_msg (&msg))
+	  {
+	    mswindows_unmodalize_signal_maybe ();
+	    continue;
+	  }
+#endif /* HAVE_DIALOGS */
+
+	/* We have to translate messages that are not sent to an XEmacs
+	   frame. This is so that key presses work ok in things like
+	   edit fields. However, we *musn't* translate message for XEmacs
+	   frames as this is handled in the wnd proc.
+	   We also have to avoid generating paint magic events for windows
+	   that aren't XEmacs frames */
+
+	if (!mswindows_window_is_xemacs (msg.hwnd))
+	  TranslateMessage (&msg);
+	else if (msg.message == WM_PAINT)
+	  {
+	    struct mswindows_frame *msframe;
+	    
+	    /* hdc will be NULL unless this is a subwindow - in which case we
+	       shouldn't have received a paint message for it here. */
+	    assert (msg.wParam == 0);
+
+	    /* Queue a magic event for handling when safe */
+	    msframe =
+	      FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
+	    if (!msframe->paint_pending)
+	      {
+		msframe->paint_pending = 1;
+		mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
+	      }
+	    /* Don't dispatch. WM_PAINT is always the last message in the
+	       queue so it's OK to just return. */
+	    return;
+	  }
+	qxeDispatchMessage (&msg);
+	mswindows_unmodalize_signal_maybe ();
+      }
+}
+
+static void
+emacs_mswindows_drain_queue (void)
+{
+  mswindows_drain_windows_queue (0);
+#ifdef HAVE_TTY
+  drain_tty_devices ();
+#endif
+}
+
 /*
  * This drains the event queue and fills up two internal queues until
  * an event of a type specified by USER_P is retrieved.
@@ -1398,7 +1354,7 @@
 	  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)
+	  if (in_modal_loop)
 	    /* In modal loop with badly_p false, don't care about 
 	       Windows events. */
 	    FD_CLR (windows_fd, &temp_mask);
@@ -1414,12 +1370,7 @@
       else if (active > 0)
 	{
 	  if (FD_ISSET (windows_fd, &temp_mask))
-	    {
-	      if (mswindows_in_modal_loop)
-		mswindows_need_event_in_modal_loop (badly_p);
-	      else
-		mswindows_drain_windows_queue ();
-	    }
+ 	    mswindows_drain_windows_queue (badly_p);
 	  else
 	    {
 #ifdef HAVE_TTY
@@ -1486,7 +1437,7 @@
       /* Now try getting a message or process event */
       DWORD active;
       DWORD what_events;
-      if (mswindows_in_modal_loop)
+      if (in_modal_loop)
 	/* In a modal loop, only look for timer events, and only if
 	   we really need one. */
 	{
@@ -1607,13 +1558,7 @@
 	  return;
 	}
       else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
-	{
-	  /* Got your message, thanks */
-	  if (mswindows_in_modal_loop)
-	    mswindows_need_event_in_modal_loop (badly_p);
-	  else
-	    mswindows_drain_windows_queue ();
-	}
+	mswindows_drain_windows_queue (badly_p);
       else
 	{
 	  int ix = active - WAIT_OBJECT_0;
@@ -4384,11 +4329,32 @@
  * emacs_mswindows_next_event() would not block.
  */
 static int
-emacs_mswindows_event_pending_p (int user_p)
+emacs_mswindows_event_pending_p (int how_many)
 {
-  mswindows_need_event (0);
-  return (!NILP (dispatch_event_queue)
-	  || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
+  if (!how_many)
+    {
+      mswindows_need_event (0);
+      return (!NILP (dispatch_event_queue)
+	      || !NILP (mswindows_s_dispatch_event_queue));
+    }
+  else
+    {
+      Lisp_Object event;
+      int count = 0;
+
+      EVENT_CHAIN_LOOP (event, dispatch_event_queue)
+	count++;
+
+      if (count >= how_many)
+	return 1;
+
+      emacs_mswindows_drain_queue ();
+
+      EVENT_CHAIN_LOOP (event, dispatch_event_queue)
+	count++;
+
+      return count >= how_many;
+    }
 }
 
 /*
@@ -5145,7 +5111,6 @@
 void
 reinit_vars_of_event_mswindows (void)
 {
-  mswindows_in_modal_loop = 0;
   mswindows_pending_timers_count = 0;
 
   mswindows_event_stream = xnew_and_zero (struct event_stream);
@@ -5159,7 +5124,6 @@
   mswindows_event_stream->add_timeout_cb 	= emacs_mswindows_add_timeout;
   mswindows_event_stream->remove_timeout_cb 	= emacs_mswindows_remove_timeout;
   mswindows_event_stream->drain_queue_cb	= emacs_mswindows_drain_queue;
-  mswindows_event_stream->quit_check_disallowed_p_cb = emacs_mswindows_quit_check_disallowed_p;
   mswindows_event_stream->select_console_cb 	= emacs_mswindows_select_console;
   mswindows_event_stream->unselect_console_cb	= emacs_mswindows_unselect_console;
   mswindows_event_stream->select_process_cb 	= emacs_mswindows_select_process;