update.
[chise/xemacs-chise.git.1] / src / event-stream.c
index 8871609..de65d4e 100644 (file)
@@ -23,6 +23,20 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Not in FSF. */
 
+/* Authorship:
+
+   Created 1991 by Jamie Zawinski.
+   A great deal of work over the ages by Ben Wing (Mule-ization for 19.12,
+     device abstraction for 19.12/19.13, async timers for 19.14,
+     rewriting of focus code for 19.12, pre-idle hook for 19.12,
+     redoing of signal and quit handling for 19.9 and 19.12,
+     misc-user events to clean up menu/scrollbar handling for 19.11,
+     function-key-map/key-translation-map/keyboard-translate-table for
+     19.13/19.14, open-dribble-file for 19.13, much other cleanup).
+   focus-follows-mouse from Chuck Thompson, 1995.
+   XIM stuff by Martin Buchholz, c. 1996?.
+*/
+
 /* This file has been Mule-ized. */
 
 /*
@@ -38,10 +52,6 @@ Boston, MA 02111-1307, USA.  */
 /* TODO:
    This stuff is way too hard to maintain - needs rework.
 
-   (global-set-key "\C-p" global-map) causes a crash - need recursion check.
-
-   C-x @ h <scrollbar-drag> x causes a crash.
-
    The command builder should deal only with key and button events.
    Other command events should be able to come in the MIDDLE of a key
    sequence, without disturbing the key sequence composition, or the
@@ -62,14 +72,6 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include "lisp.h"
 
-#ifdef HAVE_X_WINDOWS
-#include "console-x.h"         /* for menu accelerators ... */
-#include "gui-x.h"
-#include "../lwlib/lwlib.h"
-#else
-#define lw_menu_active 0
-#endif
-
 #include "blocktype.h"
 #include "buffer.h"
 #include "commands.h"
@@ -81,6 +83,7 @@ Boston, MA 02111-1307, USA.  */
 #include "keymap.h"
 #include "lstream.h"
 #include "macros.h"            /* for defining_keyboard_macro */
+#include "menubar.h"            /* #### for evil kludges. */
 #include "process.h"
 #include "window.h"
 
@@ -97,7 +100,7 @@ Boston, MA 02111-1307, USA.  */
 #include <errno.h>
 
 /* The number of keystrokes between auto-saves. */
-static int auto_save_interval;
+static Fixnum auto_save_interval;
 
 Lisp_Object Qundefined_keystroke_sequence;
 
@@ -107,29 +110,28 @@ Lisp_Object Qcommand_event_p;
 Lisp_Object Vpre_command_hook, Vpost_command_hook;
 Lisp_Object Qpre_command_hook, Qpost_command_hook;
 
+/* See simple.el */
+Lisp_Object Qhandle_pre_motion_command, Qhandle_post_motion_command;
+
 /* Hook run when XEmacs is about to be idle. */
 Lisp_Object Qpre_idle_hook, Vpre_idle_hook;
 
 /* Control gratuitous keyboard focus throwing. */
 int focus_follows_mouse;
 
-#ifdef ILL_CONCEIVED_HOOK
-/* Hook run after a command if there's no more input soon.  */
-Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
-
-/* Delay time in microseconds before running post-command-idle-hook.  */
-int post_command_idle_delay;
-#endif /* ILL_CONCEIVED_HOOK */
+/* When true, modifier keys are sticky. */
+int modifier_keys_are_sticky;
+/* Modifier keys are sticky for this many milliseconds. */
+Lisp_Object Vmodifier_keys_sticky_time;
 
-#ifdef DEFERRED_ACTION_CRAP
-/* List of deferred actions to be performed at a later time.
-   The precise format isn't relevant here; we just check whether it is nil.  */
-Lisp_Object Vdeferred_action_list;
+/* Here FSF Emacs 20.7 defines Vpost_command_idle_hook,
+   post_command_idle_delay, Vdeferred_action_list, and
+   Vdeferred_action_function, but we don't because that stuff is crap,
+   and we're smarter than them, and their momas are fat. */
 
-/* Function to call to handle deferred actions, when there are any.  */
-Lisp_Object Vdeferred_action_function;
-Lisp_Object Qdeferred_action_function;
-#endif /* DEFERRED_ACTION_CRAP */
+/* FSF Emacs 20.7 also defines Vinput_method_function,
+   Qinput_method_exit_on_first_char and Qinput_method_use_echo_area.
+   I don't know this should be imported or not. */
 
 /* Non-nil disable property on a command means
    do not execute it; call disabled-command-hook's value instead. */
@@ -164,13 +166,20 @@ Lisp_Object Vunread_command_event; /* obsoleteness support */
 static Lisp_Object Qunread_command_events, Qunread_command_event;
 
 /* Previous command, represented by a Lisp object.
-   Does not include prefix commands and arg setting commands */
+   Does not include prefix commands and arg setting commands. */
 Lisp_Object Vlast_command;
 
+/* Contents of this-command-properties for the last command. */
+Lisp_Object Vlast_command_properties;
+
 /* If a command sets this, the value goes into
-   previous-command for the next command. */
+   last-command for the next command. */
 Lisp_Object Vthis_command;
 
+/* If a command sets this, the value goes into
+   last-command-properties for the next command. */
+Lisp_Object Vthis_command_properties;
+
 /* The value of point when the last command was executed.  */
 Bufpos last_point_position;
 
@@ -235,37 +244,13 @@ int recent_keys_ring_index;
    recent-keys. */
 int inhibit_input_event_recording;
 
-/* prefix key(s) that must match in order to activate menu.
-   This is ugly.  fix me.
-   */
-Lisp_Object Vmenu_accelerator_prefix;
-
-/* list of modifier keys to match accelerator for top level menus */
-Lisp_Object Vmenu_accelerator_modifiers;
-
-/* whether menu accelerators are enabled */
-Lisp_Object Vmenu_accelerator_enabled;
-
-/* keymap for auxiliary menu accelerator functions */
-Lisp_Object Vmenu_accelerator_map;
-
-Lisp_Object Qmenu_force;
-Lisp_Object Qmenu_fallback;
-Lisp_Object Qmenu_quit;
-Lisp_Object Qmenu_up;
-Lisp_Object Qmenu_down;
-Lisp_Object Qmenu_left;
-Lisp_Object Qmenu_right;
-Lisp_Object Qmenu_select;
-Lisp_Object Qmenu_escape;
-
 Lisp_Object Qself_insert_defer_undo;
 
 /* this is in keymap.c */
 extern Lisp_Object Fmake_keymap (Lisp_Object name);
 
 #ifdef DEBUG_XEMACS
-int debug_emacs_events;
+Fixnum debug_emacs_events;
 
 static void
 external_debugging_print_event (char *event_description, Lisp_Object event)
@@ -288,60 +273,6 @@ external_debugging_print_event (char *event_description, Lisp_Object event)
 /* The callback routines for the window system or terminal driver */
 struct event_stream *event_stream;
 
-/* This structure is what we use to encapsulate the state of a command sequence
-   being composed; key events are executed by adding themselves to the command
-   builder; if the command builder is then complete (does not still represent
-   a prefix key sequence) it executes the corresponding command.
- */
-struct command_builder
-{
-  struct lcrecord_header header;
-  Lisp_Object console; /* back pointer to the console this command
-                         builder is for */
-  /* Qnil, or a Lisp_Event representing the first event read
-   *  after the last command completed.  Threaded. */
-  /* #### NYI */
-  Lisp_Object prefix_events;
-  /* Qnil, or a Lisp_Event representing event in the current
-   *  keymap-lookup sequence.  Subsequent events are threaded via
-   *  the event's next slot */
-  Lisp_Object current_events;
-  /* Last elt of above  */
-  Lisp_Object most_current_event;
-  /* Last elt before function map code took over. What this means is:
-     All prefixes up to (but not including) this event have non-nil
-     bindings, but the prefix including this event has a nil binding.
-     Any events in the chain after this one were read solely because
-     we're part of a possible function key.  If we end up with
-     something that's not part of a possible function key, we have to
-     unread all of those events. */
-  Lisp_Object last_non_munged_event;
-  /* One set of values for function-key-map, one for key-translation-map */
-  struct munging_key_translation
-  {
-    /* First event that can begin a possible function key sequence
-       (to be translated according to function-key-map).  Normally
-       this is the first event in the chain.  However, once we've
-       translated a sequence through function-key-map, this will point
-       to the first event after the translated sequence: we don't ever
-       want to translate any events twice through function-key-map, or
-       things could get really screwed up (e.g. if the user created a
-       translation loop).  If this is nil, then the next-read event is
-       the first that can begin a function key sequence. */
-    Lisp_Object first_mungeable_event;
-  } munge_me[2];
-
-  Bufbyte *echo_buf;
-  Bytecount echo_buf_length;          /* size of echo_buf */
-  Bytecount echo_buf_index;           /* index into echo_buf
-                                      * -1 before doing echoing for new cmd */
-  /* Self-insert-command is magic in that it doesn't always push an undo-
-     boundary: up to 20 consecutive self-inserts can happen before an undo-
-     boundary is pushed.  This variable is that counter.
-     */
-  int self_insert_countdown;
-};
-
 static void echo_key_event (struct command_builder *, Lisp_Object event);
 static void maybe_kbd_translate (Lisp_Object event);
 
@@ -492,7 +423,7 @@ check_event_stream_ok (enum event_stream_operation op)
        case EVENT_STREAM_READ:
          error ("Can't read events in -batch mode");
        default:
-         abort ();
+         ABORT ();
        }
     }
   else if (!event_stream)
@@ -507,6 +438,13 @@ event_stream_event_pending_p (int user)
   return event_stream && event_stream->event_pending_p (user);
 }
 
+static void
+event_stream_force_event_pending (struct frame* f)
+{
+  if (event_stream->force_event_pending)
+    event_stream->force_event_pending (f);
+}
+
 static int
 maybe_read_quit_event (Lisp_Event *event)
 {
@@ -558,15 +496,7 @@ event_stream_next_event (Lisp_Event *event)
      Let's hope it doesn't.  I think the code here is fairly
      clean and doesn't do this. */
   emacs_is_blocking = 1;
-#if 0
-  /* Do this if the poll-for-quit timer seems to be taking too
-     much CPU time when idle ... */
-  reset_poll_for_quit ();
-#endif
   event_stream->next_event_cb (event);
-#if 0
-  init_poll_for_quit ();
-#endif
   emacs_is_blocking = 0;
 
 #ifdef DEBUG_XEMACS
@@ -666,6 +596,14 @@ event_stream_quit_p (void)
     event_stream->quit_p_cb ();
 }
 
+static int
+event_stream_current_event_timestamp (struct console *c)
+{
+  if (event_stream && event_stream->current_event_timestamp_cb)
+    return event_stream->current_event_timestamp_cb (c);
+  else
+    return 0;
+}
 
 \f
 /**********************************************************************/
@@ -734,7 +672,10 @@ maybe_echo_keys (struct command_builder *command_builder, int no_snooze)
 
   if (minibuf_level == 0
       && echo_keystrokes > 0.0
-      && !lw_menu_active)
+#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID)
+      && !x_kludge_lw_menu_active ()
+#endif
+      )
     {
       if (!no_snooze)
        {
@@ -760,7 +701,8 @@ reset_key_echo (struct command_builder *command_builder,
   /* This function can GC */
   struct frame *f = selected_frame ();
 
-  command_builder->echo_buf_index = -1;
+  if (command_builder)
+    command_builder->echo_buf_index = -1;
 
   if (remove_echo_area_echo)
     clear_echo_area (f, Qcommand, 0);
@@ -804,7 +746,7 @@ maybe_kbd_translate (Lisp_Object event)
             This way is safer. */
          zero_event (&ev2);
          character_to_event (XCHAR (traduit), &ev2,
-                             XCONSOLE (EVENT_CHANNEL (XEVENT (event))), 1, 1);
+                             XCONSOLE (EVENT_CHANNEL (XEVENT (event))), 0, 1);
          XEVENT (event)->event.key.keysym = ev2.event.key.keysym;
          XEVENT (event)->event.key.modifiers = ev2.event.key.modifiers;
          did_translate = 1;
@@ -820,6 +762,17 @@ maybe_kbd_translate (Lisp_Object event)
          XEVENT (event)->event.key.keysym = traduit;
          did_translate = 1;
        }
+      else if (CHARP (traduit))
+       {
+         Lisp_Event ev2;
+
+         zero_event (&ev2);
+         character_to_event (XCHAR (traduit), &ev2,
+                             XCONSOLE (EVENT_CHANNEL (XEVENT (event))), 0, 1);
+         XEVENT (event)->event.key.keysym = ev2.event.key.keysym;
+         XEVENT (event)->event.key.modifiers |= ev2.event.key.modifiers;
+         did_translate = 1;
+       }
     }
 
 #ifdef DEBUG_XEMACS
@@ -832,7 +785,8 @@ maybe_kbd_translate (Lisp_Object event)
    keystrokes_since_auto_save is equivalent to the difference between
    num_nonmacro_input_chars and last_auto_save. */
 
-/* When an auto-save happens, record the "time", and don't do again soon.  */
+/* When an auto-save happens, record the number of keystrokes, and
+   don't do again soon.  */
 
 void
 record_auto_save (void)
@@ -846,10 +800,6 @@ void
 force_auto_save_soon (void)
 {
   keystrokes_since_auto_save = 1 + max (auto_save_interval, 20);
-
-#if 0 /* FSFmacs */
-  record_asynch_buffer_change ();
-#endif
 }
 
 static void
@@ -1437,7 +1387,7 @@ is a race condition.  That's why the RESIGNAL argument exists.
   Lisp_Object lid;
   id = event_stream_generate_wakeup (msecs, msecs2, function, object, 0);
   lid = make_int (id);
-  if (id != XINT (lid)) abort ();
+  if (id != XINT (lid)) ABORT ();
   return lid;
 }
 
@@ -1516,7 +1466,7 @@ is a race condition.  That's why the RESIGNAL argument exists.
   Lisp_Object lid;
   id = event_stream_generate_wakeup (msecs, msecs2, function, object, 1);
   lid = make_int (id);
-  if (id != XINT (lid)) abort ();
+  if (id != XINT (lid)) ABORT ();
   return lid;
 }
 
@@ -1729,19 +1679,6 @@ run_select_frame_hook (void)
 static void
 run_deselect_frame_hook (void)
 {
-#if 0 /* unclean!  FSF calls this at all sorts of random places,
-         including a bunch of places in their mouse.el.  If this
-         is implemented, it has to be done cleanly. */
-  run_hook (Qmouse_leave_buffer_hook); /* #### Correct?  It's also
-                                         called in `call-interactively'.
-                                         Does this mean it will be
-                                         called twice?  Oh well, FSF
-                                         bug -- FSF calls it in
-                                         `handle-switch-frame',
-                                         which is approximately the
-                                         same as the caller of this
-                                         function. */
-#endif
   run_hook (Qdeselect_frame_hook);
 }
 
@@ -1871,7 +1808,8 @@ emacs_handle_focus_change_preliminary (Lisp_Object frame_inp_and_dev)
        MARK_WINDOWS_CHANGED (w);
       }
 
-      if (FRAMEP (focus_frame) && !EQ (frame, focus_frame))
+      if (FRAMEP (focus_frame) && FRAME_LIVE_P (XFRAME (focus_frame))
+         && !EQ (frame, focus_frame))
        {
          /* Oops, we missed a focus-out event. */
          DEVICE_FRAME_WITH_FOCUS_REAL (d) = Qnil;
@@ -2073,6 +2011,7 @@ static void push_this_command_keys (Lisp_Object event);
 static void push_recent_keys (Lisp_Object event);
 static void dribble_out_event (Lisp_Object event);
 static void execute_internal_event (Lisp_Object event);
+static int is_scrollbar_event (Lisp_Object event);
 
 DEFUN ("next-event", Fnext_event, 0, 2, 0, /*
 Return the next available event.
@@ -2090,7 +2029,12 @@ The next available event will be
 
 -- any events in `unread-command-events' or `unread-command-event'; else
 -- the next event in the currently executing keyboard macro, if any; else
--- an event queued by `enqueue-eval-event', if any; else
+-- an event queued by `enqueue-eval-event', if any, or any similar event
+   queued internally, such as a misc-user event. (For example, when an item
+   is selected from a menu or from a `question'-type dialog box, the item's
+   callback is not immediately executed, but instead a misc-user event
+   is generated and placed onto this queue; when it is dispatched, the
+   callback is executed.) Else
 -- the next available event from the window system or terminal driver.
 
 In the last case, this function will block until an event is available.
@@ -2123,9 +2067,6 @@ The returned event will be one of the following types:
     XCOMMAND_BUILDER (con->command_builder);
   int store_this_key = 0;
   struct gcpro gcpro1;
-#ifdef LWLIB_MENUBARS_LUCID
-  extern int in_menu_callback;  /* defined in menubar-x.c */
-#endif /* LWLIB_MENUBARS_LUCID */
 
   GCPRO1 (event);
   /* DO NOT do QUIT anywhere within this function or the functions it calls.
@@ -2263,8 +2204,6 @@ The returned event will be one of the following types:
 
   switch (XEVENT_TYPE (event))
     {
-    default:
-      goto RETURN;
     case button_release_event:
     case misc_user_event:
       /* don't echo menu accelerator keys */
@@ -2274,6 +2213,8 @@ The returned event will be one of the following types:
       goto STORE_AND_EXECUTE_KEY;
     case key_press_event:         /* any key input can trigger autosave */
       break;
+    default:
+      goto RETURN;
     }
 
   maybe_do_auto_save ();
@@ -2331,7 +2272,9 @@ The returned event will be one of the following types:
      */
   if (store_this_key)
     {
-      push_this_command_keys (event);
+      if (!is_scrollbar_event (event)) /* #### not quite right, see
+                                         comment in execute_command_event */
+       push_this_command_keys (event);
       if (!inhibit_input_event_recording)
        push_recent_keys (event);
       dribble_out_event (event);
@@ -2401,6 +2344,56 @@ but it also makes a provision for displaying keystrokes in the echo area.
   return event;
 }
 
+DEFUN ("dispatch-non-command-events", Fdispatch_non_command_events, 0, 0, 0, /*
+Dispatch any pending "magic" events.
+
+This function is useful for forcing the redisplay of native
+widgets. Normally these are redisplayed through a native window-system
+event encoded as magic event, rather than by the redisplay code.  This
+function does not call redisplay or do any of the other things that
+`next-event' does.
+*/
+       ())
+{
+  /* This function can GC */
+  Lisp_Object event = Qnil;
+  struct gcpro gcpro1;
+  GCPRO1 (event);
+  event = Fmake_event (Qnil, Qnil);
+
+  /* Make sure that there will be something in the native event queue
+     so that externally managed things (e.g. widgets) get some CPU
+     time. */
+  event_stream_force_event_pending (selected_frame ());
+
+  while (event_stream_event_pending_p (0))
+    {
+      QUIT; /* next_event_internal() does not QUIT. */
+
+      /* We're a generator of the command_event_queue, so we can't be a
+        consumer as well.  Also, we have no reason to consult the
+        command_event_queue; there are only user and eval-events there,
+        and we'd just have to put them back anyway.
+       */
+      next_event_internal (event, 0); /* blocks */
+      /* See the comment in accept-process-output about Vquit_flag */
+      if (XEVENT_TYPE (event) == magic_event ||
+         XEVENT_TYPE (event) == timeout_event ||
+         XEVENT_TYPE (event) == process_event ||
+         XEVENT_TYPE (event) == pointer_motion_event)
+       execute_internal_event (event);
+      else
+       {
+         enqueue_command_event_1 (event);
+         break;
+       }
+    }
+
+  Fdeallocate_event (event);
+  UNGCPRO;
+  return Qnil;
+}
+
 static void
 reset_current_events (struct command_builder *command_builder)
 {
@@ -2473,7 +2466,7 @@ A user event is a key press, button press, button release, or
     }
 
   if (!NILP (command_event_queue) || !NILP (command_event_queue_tail))
-    abort ();
+    ABORT ();
 
   /* Now tack our chain of events back on to the front of the queue.
      Actually, since the queue is now drained, we can just replace it.
@@ -2666,11 +2659,11 @@ Return non-nil iff we received any output before the timeout expired.
 }
 
 DEFUN ("sleep-for", Fsleep_for, 1, 1, 0, /*
-Pause, without updating display, for ARG seconds.
-ARG may be a float, meaning pause for some fractional part of a second.
+Pause, without updating display, for SECONDS seconds.
+SECONDS may be a float, allowing pauses for fractional parts of a second.
 
 It is recommended that you never call sleep-for from inside of a process
- filter function or timer event (either synchronous or asynchronous).
+filter function or timer event (either synchronous or asynchronous).
 */
        (seconds))
 {
@@ -2733,9 +2726,9 @@ It is recommended that you never call sleep-for from inside of a process
 }
 
 DEFUN ("sit-for", Fsit_for, 1, 2, 0, /*
-Perform redisplay, then wait ARG seconds or until user input is available.
-ARG may be a float, meaning a fractional part of a second.
-Optional second arg non-nil means don't redisplay, just wait for input.
+Perform redisplay, then wait SECONDS seconds or until user input is available.
+SECONDS may be a float, meaning a fractional part of a second.
+Optional second arg NODISPLAY non-nil means don't redisplay; just wait.
 Redisplay is preempted as always if user input arrives, and does not
  happen if input is available before it starts.
 Value is t if waited the full time with no input arriving.
@@ -2881,10 +2874,8 @@ If sit-for is called from within a process filter function or timer
   return result;
 }
 
-/* This handy little function is used by xselect.c and energize.c to
-   wait for replies from processes that aren't really processes (that is,
-   the X server and the Energize server).
- */
+/* This handy little function is used by select-x.c to wait for replies
+   from processes that aren't really processes (e.g. the X server) */
 void
 wait_delaying_user_input (int (*predicate) (void *arg), void *predicate_arg)
 {
@@ -3050,7 +3041,7 @@ execute_internal_event (Lisp_Object event)
        return;
       }
     default:
-      abort ();
+      ABORT ();
     }
 }
 
@@ -3096,502 +3087,6 @@ command_builder_find_leaf_1 (struct command_builder *builder)
   return event_binding (event0, 1);
 }
 
-#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-static void
-menu_move_up (void)
-{
-  widget_value *current = lw_get_entries (False);
-  widget_value *entries = lw_get_entries (True);
-  widget_value *prev    = NULL;
-
-  while (entries != current)
-    {
-      if (entries->name /*&& entries->enabled*/) prev = entries;
-      entries = entries->next;
-      assert (entries);
-    }
-
-  if (!prev)
-    /* move to last item */
-    {
-      while (entries->next)
-       {
-         if (entries->name /*&& entries->enabled*/) prev = entries;
-         entries = entries->next;
-       }
-      if (prev)
-       {
-         if (entries->name /*&& entries->enabled*/)
-           prev = entries;
-       }
-      else
-       {
-         /* no selectable items in this menu, pop up to previous level */
-         lw_pop_menu ();
-         return;
-       }
-    }
-  lw_set_item (prev);
-}
-
-static void
-menu_move_down (void)
-{
-  widget_value *current = lw_get_entries (False);
-  widget_value *new = current;
-
-  while (new->next)
-    {
-      new = new->next;
-      if (new->name /*&& new->enabled*/) break;
-    }
-
-  if (new==current||!(new->name/*||new->enabled*/))
-    {
-      new = lw_get_entries (True);
-      while (new!=current)
-       {
-         if (new->name /*&& new->enabled*/) break;
-         new = new->next;
-       }
-      if (new==current&&!(new->name /*|| new->enabled*/))
-       {
-         lw_pop_menu ();
-         return;
-       }
-    }
-
-  lw_set_item (new);
-}
-
-static void
-menu_move_left (void)
-{
-  int level = lw_menu_level ();
-  int l = level;
-  widget_value *current;
-
-  while (level-- >= 3)
-    lw_pop_menu ();
-
-  menu_move_up ();
-  current = lw_get_entries (False);
-  if (l > 2 && current->contents)
-    lw_push_menu (current->contents);
-}
-
-static void
-menu_move_right (void)
-{
-  int level = lw_menu_level ();
-  int l = level;
-  widget_value *current;
-
-  while (level-- >= 3)
-    lw_pop_menu ();
-
-  menu_move_down ();
-  current = lw_get_entries (False);
-  if (l > 2 && current->contents)
-    lw_push_menu (current->contents);
-}
-
-static void
-menu_select_item (widget_value *val)
-{
-  if (val == NULL)
-    val = lw_get_entries (False);
-
-  /* is match a submenu? */
-
-  if (val->contents)
-    {
-      /* enter the submenu */
-
-      lw_set_item (val);
-      lw_push_menu (val->contents);
-    }
-  else
-    {
-      /* Execute the menu entry by calling the menu's `select'
-        callback function
-        */
-      lw_kill_menus (val);
-    }
-}
-
-static Lisp_Object
-command_builder_operate_menu_accelerator (struct command_builder *builder)
-{
-  /* this function can GC */
-
-  struct console *con = XCONSOLE (Vselected_console);
-  Lisp_Object evee = builder->most_current_event;
-  Lisp_Object binding;
-  widget_value *entries;
-
-  extern int lw_menu_accelerate; /* lwlib.c */
-
-#if 0
-  {
-    int i;
-    Lisp_Object t;
-    char buf[50];
-
-    t = builder->current_events;
-    i = 0;
-    while (!NILP (t))
-      {
-       i++;
-       sprintf (buf,"OPERATE (%d): ",i);
-       write_c_string (buf, Qexternal_debugging_output);
-       print_internal (t, Qexternal_debugging_output, 1);
-       write_c_string ("\n", Qexternal_debugging_output);
-       t = XEVENT_NEXT (t);
-      }
-  }
-#endif /* 0 */
-
-  /* menu accelerator keys don't go into keyboard macros */
-  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-    con->kbd_macro_ptr = con->kbd_macro_end;
-
-  /* don't echo menu accelerator keys */
-  /*reset_key_echo (builder, 1);*/
-
-  if (!lw_menu_accelerate)
-    {
-      /* `convert' mouse display to keyboard display
-        by entering the open submenu
-        */
-      entries = lw_get_entries (False);
-      if (entries->contents)
-       {
-         lw_push_menu (entries->contents);
-         lw_display_menu (CurrentTime);
-       }
-    }
-
-  /* compare event to the current menu accelerators */
-
-  entries=lw_get_entries (True);
-
-  while (entries)
-    {
-      Lisp_Object accel;
-      VOID_TO_LISP (accel, entries->accel);
-      if (entries->name && !NILP (accel))
-       {
-         if (event_matches_key_specifier_p (XEVENT (evee), accel))
-           {
-             /* a match! */
-
-             menu_select_item (entries);
-
-             if (lw_menu_active) lw_display_menu (CurrentTime);
-
-             reset_this_command_keys (Vselected_console, 1);
-             /*reset_command_builder_event_chain (builder);*/
-             return Vmenu_accelerator_map;
-           }
-       }
-      entries = entries->next;
-    }
-
-  /* try to look up event in menu-accelerator-map */
-
-  binding = event_binding_in (evee, Vmenu_accelerator_map, 1);
-
-  if (NILP (binding))
-    {
-      /* beep at user for undefined key */
-      return Qnil;
-    }
-  else
-    {
-      if (EQ (binding, Qmenu_quit))
-       {
-         /* turn off menus and set quit flag */
-         lw_kill_menus (NULL);
-         Vquit_flag = Qt;
-       }
-      else if (EQ (binding, Qmenu_up))
-       {
-         int level = lw_menu_level ();
-         if (level > 2)
-           menu_move_up ();
-       }
-      else if (EQ (binding, Qmenu_down))
-       {
-         int level = lw_menu_level ();
-         if (level > 2)
-           menu_move_down ();
-         else
-           menu_select_item (NULL);
-       }
-      else if (EQ (binding, Qmenu_left))
-       {
-         int level = lw_menu_level ();
-         if (level > 3)
-           {
-             lw_pop_menu ();
-             lw_display_menu (CurrentTime);
-           }
-         else
-           menu_move_left ();
-       }
-      else if (EQ (binding, Qmenu_right))
-       {
-         int level = lw_menu_level ();
-         if (level > 2 &&
-             lw_get_entries (False)->contents)
-           {
-             widget_value *current = lw_get_entries (False);
-             if (current->contents)
-               menu_select_item (NULL);
-           }
-         else
-           menu_move_right ();
-       }
-      else if (EQ (binding, Qmenu_select))
-       menu_select_item (NULL);
-      else if (EQ (binding, Qmenu_escape))
-       {
-         int level = lw_menu_level ();
-
-         if (level > 2)
-           {
-             lw_pop_menu ();
-             lw_display_menu (CurrentTime);
-           }
-         else
-           {
-             /* turn off menus quietly */
-             lw_kill_menus (NULL);
-           }
-       }
-      else if (KEYMAPP (binding))
-       {
-         /* prefix key */
-         reset_this_command_keys (Vselected_console, 1);
-         /*reset_command_builder_event_chain (builder);*/
-         return binding;
-       }
-      else
-       {
-         /* turn off menus and execute binding */
-         lw_kill_menus (NULL);
-         reset_this_command_keys (Vselected_console, 1);
-         /*reset_command_builder_event_chain (builder);*/
-         return binding;
-       }
-    }
-
-  if (lw_menu_active) lw_display_menu (CurrentTime);
-
-  reset_this_command_keys (Vselected_console, 1);
-  /*reset_command_builder_event_chain (builder);*/
-
-  return Vmenu_accelerator_map;
-}
-
-static Lisp_Object
-menu_accelerator_junk_on_error (Lisp_Object errordata, Lisp_Object ignored)
-{
-  Vmenu_accelerator_prefix    = Qnil;
-  Vmenu_accelerator_modifiers = Qnil;
-  Vmenu_accelerator_enabled   = Qnil;
-  if (!NILP (errordata))
-    {
-      Lisp_Object args[2];
-
-      args[0] = build_string ("Error in menu accelerators (setting to nil)");
-      /* #### This should call
-        (with-output-to-string (display-error errordata))
-        but that stuff is all in Lisp currently. */
-      args[1] = errordata;
-      warn_when_safe_lispobj
-       (Qerror, Qwarning,
-        emacs_doprnt_string_lisp ((const Bufbyte *) "%s: %s",
-                                  Qnil, -1, 2, args));
-    }
-
-  return Qnil;
-}
-
-static Lisp_Object
-menu_accelerator_safe_compare (Lisp_Object event0)
-{
-  if (CONSP (Vmenu_accelerator_prefix))
-    {
-      Lisp_Object t;
-      t=Vmenu_accelerator_prefix;
-      while (!NILP (t)
-            && !NILP (event0)
-            && event_matches_key_specifier_p (XEVENT (event0), Fcar (t)))
-       {
-         t = Fcdr (t);
-         event0 = XEVENT_NEXT (event0);
-       }
-      if (!NILP (t))
-       return Qnil;
-    }
-  else if (NILP (event0))
-    return Qnil;
-  else if (event_matches_key_specifier_p (XEVENT (event0), Vmenu_accelerator_prefix))
-    event0 = XEVENT_NEXT (event0);
-  else
-    return Qnil;
-  return event0;
-}
-
-static Lisp_Object
-menu_accelerator_safe_mod_compare (Lisp_Object cons)
-{
-  return (event_matches_key_specifier_p (XEVENT (XCAR (cons)), XCDR (cons))
-         ? Qt
-         : Qnil);
-}
-
-static Lisp_Object
-command_builder_find_menu_accelerator (struct command_builder *builder)
-{
-  /* this function can GC */
-  Lisp_Object event0 = builder->current_events;
-  struct console *con = XCONSOLE (Vselected_console);
-  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
-  Widget menubar_widget;
-
-  /* compare entries in event0 against the menu prefix */
-
-  if ((!CONSOLE_X_P (XCONSOLE (builder->console))) || NILP (event0) ||
-      XEVENT (event0)->event_type != key_press_event)
-    return Qnil;
-
-  if (!NILP (Vmenu_accelerator_prefix))
-    {
-      event0 = condition_case_1 (Qerror,
-                                menu_accelerator_safe_compare,
-                                event0,
-                                menu_accelerator_junk_on_error,
-                                Qnil);
-    }
-
-  if (NILP (event0))
-    return Qnil;
-
-  menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
-  if (menubar_widget
-      && CONSP (Vmenu_accelerator_modifiers))
-    {
-      Lisp_Object fake;
-      Lisp_Object last = Qnil;
-      struct gcpro gcpro1;
-      Lisp_Object matchp;
-
-      widget_value *val;
-      LWLIB_ID id = XPOPUP_DATA (f->menubar_data)->id;
-
-      val = lw_get_all_values (id);
-      if (val)
-       {
-         val = val->contents;
-
-         fake = Fcopy_sequence (Vmenu_accelerator_modifiers);
-         last = fake;
-
-         while (!NILP (Fcdr (last)))
-           last = Fcdr (last);
-
-         Fsetcdr (last, Fcons (Qnil, Qnil));
-         last = Fcdr (last);
-       }
-
-      fake = Fcons (Qnil, fake);
-
-      GCPRO1 (fake);
-
-      while (val)
-       {
-         Lisp_Object accel;
-         VOID_TO_LISP (accel, val->accel);
-         if (val->name && !NILP (accel))
-           {
-             Fsetcar (last, accel);
-             Fsetcar (fake, event0);
-             matchp = condition_case_1 (Qerror,
-                                        menu_accelerator_safe_mod_compare,
-                                        fake,
-                                        menu_accelerator_junk_on_error,
-                                        Qnil);
-             if (!NILP (matchp))
-               {
-                 /* we found one! */
-
-                 lw_set_menu (menubar_widget, val);
-                 /* yah - yet another hack.
-                    pretend emacs timestamp is the same as an X timestamp,
-                    which for the moment it is.  (read events.h)
-                    */
-                 lw_map_menu (XEVENT (event0)->timestamp);
-
-                 if (val->contents)
-                   lw_push_menu (val->contents);
-
-                 lw_display_menu (CurrentTime);
-
-                 /* menu accelerator keys don't go into keyboard macros */
-                 if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-                   con->kbd_macro_ptr = con->kbd_macro_end;
-
-                 /* don't echo menu accelerator keys */
-                 /*reset_key_echo (builder, 1);*/
-                 reset_this_command_keys (Vselected_console, 1);
-                 UNGCPRO;
-
-                 return Vmenu_accelerator_map;
-               }
-           }
-
-         val = val->next;
-       }
-
-      UNGCPRO;
-    }
-  return Qnil;
-}
-
-
-DEFUN ("accelerate-menu", Faccelerate_menu, 0, 0, "_", /*
-Make the menubar active.  Menu items can be selected using menu accelerators
-or by actions defined in menu-accelerator-map.
-*/
-       ())
-{
-  struct console *con = XCONSOLE (Vselected_console);
-  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
-  LWLIB_ID id;
-  widget_value *val;
-
-  if (NILP (f->menubar_data))
-    error ("Frame has no menubar.");
-
-  id = XPOPUP_DATA (f->menubar_data)->id;
-  val = lw_get_all_values (id);
-  val = val->contents;
-  lw_set_menu (FRAME_X_MENUBAR_WIDGET (f), val);
-  lw_map_menu (CurrentTime);
-
-  lw_display_menu (CurrentTime);
-
-  /* menu accelerator keys don't go into keyboard macros */
-  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-    con->kbd_macro_ptr = con->kbd_macro_end;
-
-  return Qnil;
-}
-#endif /* HAVE_X_WINDOWS && HAVE_MENUBARS */
-
 /* See if we can do function-key-map or key-translation-map translation
    on the current events in the command builder.  If so, do this, and
    return the resulting binding, if any. */
@@ -3713,9 +3208,11 @@ command_builder_find_leaf (struct command_builder *builder,
        return Qnil;
     }
 
-  /* if we're currently in a menu accelerator, check there for further events */
+  /* if we're currently in a menu accelerator, check there for further
+     events */
+  /* #### fuck me!  who wrote this crap?  think "abstraction", baby. */
 #if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-  if (lw_menu_active)
+  if (x_kludge_lw_menu_active ())
     {
       return command_builder_operate_menu_accelerator (builder);
     }
@@ -3766,14 +3263,14 @@ command_builder_find_leaf (struct command_builder *builder,
       Lisp_Object terminal = builder->most_current_event;
       struct key_data* key = & XEVENT (terminal)->event.key;
       Emchar c = 0;
-      if ((key->modifiers & MOD_SHIFT)
+      if ((key->modifiers & XEMACS_MOD_SHIFT)
           || (CHAR_OR_CHAR_INTP (key->keysym)
               && ((c = XCHAR_OR_CHAR_INT (key->keysym)), c >= 'A' && c <= 'Z')))
         {
           Lisp_Event terminal_copy = *XEVENT (terminal);
 
-          if (key->modifiers & MOD_SHIFT)
-            key->modifiers &= (~ MOD_SHIFT);
+          if (key->modifiers & XEMACS_MOD_SHIFT)
+            key->modifiers &= (~ XEMACS_MOD_SHIFT);
           else
             key->keysym = make_char (c + 'a' - 'A');
 
@@ -3880,7 +3377,7 @@ modify them.
     {
       Vrecent_keys_ring = make_vector (recent_keys_ring_size, Qnil);
       /* And return nothing in particular. */
-      return make_vector (0, Qnil);
+      RETURN_UNGCPRO (make_vector (0, Qnil));
     }
 
   if (NILP (XVECTOR_DATA (Vrecent_keys_ring)[recent_keys_ring_index]))
@@ -3912,7 +3409,7 @@ modify them.
     Lisp_Object e = XVECTOR_DATA (Vrecent_keys_ring)[j];
 
     if (NILP (e))
-      abort ();
+      ABORT ();
     XVECTOR_DATA (val)[i] = Fcopy_event (e, Qnil);
     if (++j >= recent_keys_ring_size)
       j = 0;
@@ -3938,7 +3435,6 @@ Set the maximum number of events to be stored internally.
   Lisp_Object new_vector = Qnil;
   int i, j, nkeys, start, min;
   struct gcpro gcpro1;
-  GCPRO1 (new_vector);
 
   CHECK_INT (size);
   if (XINT (size) <= 0)
@@ -3946,12 +3442,13 @@ Set the maximum number of events to be stored internally.
   if (XINT (size) == recent_keys_ring_size)
     return size;
 
+  GCPRO1 (new_vector);
   new_vector = make_vector (XINT (size), Qnil);
 
   if (NILP (Vrecent_keys_ring))
     {
       Vrecent_keys_ring = new_vector;
-      return size;
+      RETURN_UNGCPRO (size);
     }
 
   if (NILP (XVECTOR_DATA (Vrecent_keys_ring)[recent_keys_ring_index]))
@@ -4008,16 +3505,24 @@ Set the maximum number of events to be stored internally.
 void
 reset_this_command_keys (Lisp_Object console, int clear_echo_area_p)
 {
-  struct command_builder *command_builder =
-    XCOMMAND_BUILDER (XCONSOLE (console)->command_builder);
-
-  reset_key_echo (command_builder, clear_echo_area_p);
+  if (!NILP (console))
+    {
+      /* console is nil if we just deleted the console as a result of C-x 5
+        0.  Unfortunately things are currently in a messy situation where
+        some stuff is console-local and other stuff isn't, so we need to
+        do everything that's not console-local. */
+      struct command_builder *command_builder =
+       XCOMMAND_BUILDER (XCONSOLE (console)->command_builder);
+
+      reset_key_echo (command_builder, clear_echo_area_p);
+      reset_current_events (command_builder);
+    }
+  else
+    reset_key_echo (0, clear_echo_area_p);
 
   deallocate_event_chain (Vthis_command_keys);
   Vthis_command_keys = Qnil;
   Vthis_command_keys_tail = Qnil;
-
-  reset_current_events (command_builder);
 }
 
 static void
@@ -4048,7 +3553,7 @@ extract_this_command_keys_nth_mouse_event (int n)
        {
          if (!n)
            {
-             /* must copy to avoid an abort() in next_event_internal() */
+             /* must copy to avoid an ABORT() in next_event_internal() */
              if (!NILP (XEVENT_NEXT (event)))
                 return Fcopy_event (event, Qnil);
              else
@@ -4174,12 +3679,12 @@ lookup_command_event (struct command_builder *command_builder,
        Fcopy_event (event, recent);
        e = XEVENT (recent);
        if (e->event_type == key_press_event)
-         e->event.key.modifiers |= MOD_META;
+         e->event.key.modifiers |= XEMACS_MOD_META;
        else if (e->event_type == button_press_event
                 || e->event_type == button_release_event)
-         e->event.button.modifiers |= MOD_META;
+         e->event.button.modifiers |= XEMACS_MOD_META;
        else
-         abort ();
+         ABORT ();
 
        {
          int tckn = event_chain_count (Vthis_command_keys);
@@ -4208,7 +3713,11 @@ lookup_command_event (struct command_builder *command_builder,
 
     if (KEYMAPP (leaf))
       {
-       if (!lw_menu_active)
+#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID)
+        if (!x_kludge_lw_menu_active ())
+#else
+       if (1)
+#endif
          {
            Lisp_Object prompt = Fkeymap_prompt (leaf, Qt);
            if (STRINGP (prompt))
@@ -4228,19 +3737,20 @@ lookup_command_event (struct command_builder *command_builder,
            else
              maybe_echo_keys (command_builder, 0);
          }
-       else if (!NILP (Vquit_flag)) {
-         Lisp_Object quit_event = Fmake_event(Qnil, Qnil);
-         Lisp_Event *e = XEVENT (quit_event);
-         /* if quit happened during menu acceleration, pretend we read it */
-         struct console *con = XCONSOLE (Fselected_console ());
-         int ch = CONSOLE_QUIT_CHAR (con);
-
-         character_to_event (ch, e, con, 1, 1);
-         e->channel = make_console (con);
-
-         enqueue_command_event (quit_event);
-         Vquit_flag = Qnil;
-       }
+       else if (!NILP (Vquit_flag))
+         {
+           Lisp_Object quit_event = Fmake_event (Qnil, Qnil);
+           Lisp_Event *e = XEVENT (quit_event);
+           /* if quit happened during menu acceleration, pretend we read it */
+           struct console *con = XCONSOLE (Fselected_console ());
+           int ch = CONSOLE_QUIT_CHAR (con);
+
+           character_to_event (ch, e, con, 1, 1);
+           e->channel = make_console (con);
+
+           enqueue_command_event (quit_event);
+           Vquit_flag = Qnil;
+         }
       }
     else if (!NILP (leaf))
       {
@@ -4259,6 +3769,35 @@ lookup_command_event (struct command_builder *command_builder,
   }
 }
 
+static int
+is_scrollbar_event (Lisp_Object event)
+{
+#ifdef HAVE_SCROLLBARS
+  Lisp_Object fun;
+
+  if (XEVENT (event)->event_type != misc_user_event)
+    return 0;
+  fun = XEVENT (event)->event.misc.function;
+
+  return (EQ (fun, Qscrollbar_line_up) ||
+         EQ (fun, Qscrollbar_line_down) ||
+         EQ (fun, Qscrollbar_page_up) ||
+         EQ (fun, Qscrollbar_page_down) ||
+         EQ (fun, Qscrollbar_to_top) ||
+         EQ (fun, Qscrollbar_to_bottom) ||
+         EQ (fun, Qscrollbar_vertical_drag) ||
+         EQ (fun, Qscrollbar_char_left) ||
+         EQ (fun, Qscrollbar_char_right) ||
+         EQ (fun, Qscrollbar_page_left) ||
+         EQ (fun, Qscrollbar_page_right) ||
+         EQ (fun, Qscrollbar_to_left) ||
+         EQ (fun, Qscrollbar_to_right) ||
+         EQ (fun, Qscrollbar_horizontal_drag));
+#else
+  return 0;
+#endif /* HAVE_SCROLLBARS */
+}
+
 static void
 execute_command_event (struct command_builder *command_builder,
                        Lisp_Object event)
@@ -4268,7 +3807,59 @@ execute_command_event (struct command_builder *command_builder,
   struct gcpro gcpro1;
 
   GCPRO1 (event); /* event may be freshly created */
-  reset_current_events (command_builder);
+
+  /* #### This call to is_scrollbar_event() isn't quite right, but
+     fixing properly it requires more work than can go into 21.4.
+     (We really need to split out menu, scrollbar, dialog, and other
+     types of events from misc-user, and put the remaining ones in a
+     new `user-eval' type that behaves like an eval event but is a
+     user event and thus has all of its semantics -- e.g. being
+     delayed during `accept-process-output' and similar wait states.)
+
+     The real issue here is that "user events" and "command events"
+     are not the same thing, but are very much confused in
+     event-stream.c.  User events are, essentially, any event that
+     should be delayed by accept-process-output, should terminate a
+     sit-for, etc. -- basically, any event that needs to be processed
+     synchronously with key and mouse events.  Command events are
+     those that participate in command building; scrollbar events
+     clearly don't belong because they should be transparent in a
+     sequence like C-x @ h <scrollbar-drag> x, which used to cause a
+     crash before checks similar to the is_scrollbar_event() call were
+     added.  Do other events belong with scrollbar events?  I'm not
+     sure; we need to categorize all misc-user events and see what
+     their semantics are.
+
+     (You might ask, why do scrollbar events need to be user events?
+     That's a good question.  The answer seems to be that they can
+     change point, and having this happen asynchronously would be a
+     very bad idea.  According to the "proper" functioning of
+     scrollbars, this should not happen, but XEmacs does not allow
+     point to go outside of the window.)
+
+     Scrollbar events and similar non-command events should obviously
+     not be recorded in this-command-keys, so we need to check for
+     this in next-event.
+
+     #### We call reset_current_events() twice in this function --
+     #### here, and later as a result of reset_this_command_keys().
+     #### This is almost certainly wrong; need to figure out what's
+     #### correct.
+
+     #### We need to figure out what's really correct w.r.t. scrollbar
+     #### events.  With these new fixes in, it actually works to do
+     #### C-x <scrollbar-drag> 5 2, but the key echo gets messed up
+     #### (starts over at 5).  We really need to be special-casing
+     #### scrollbar events at a lower level, and not really passing
+     #### them through the command builder at all.  (e.g. do scrollbar
+     #### events belong in macros???  doubtful; probably only the
+     #### point movement, if any, belongs, special-cased as a
+     #### pseudo-issued M-x goto-char command).  #### Need more work
+     #### here.  Do this when separating out scrollbar events.
+  */
+
+  if (!is_scrollbar_event (event))
+    reset_current_events (command_builder);
 
   switch (XEVENT (event)->event_type)
     {
@@ -4335,17 +3926,16 @@ execute_command_event (struct command_builder *command_builder,
 
     post_command_hook ();
 
-#if 0 /* #### here was an attempted fix that didn't work */
-    if (XEVENT (event)->event_type == misc_user_event)
-      ;
-    else
-#endif
-    if (!NILP (con->prefix_arg))
+    /* Console might have been deleted by command */
+    if (CONSOLE_LIVE_P (con) && !NILP (con->prefix_arg))
       {
        /* Commands that set the prefix arg don't update last-command, don't
           reset the echoing state, and don't go into keyboard macros unless
-          followed by another command. */
+          followed by another command.  Also don't quit here.  */
+       int speccount = specpdl_depth ();
+       specbind (Qinhibit_quit, Qt);
        maybe_echo_keys (command_builder, 0);
+       unbind_to (speccount, Qnil);
 
        /* If we're recording a keyboard macro, and the last command
           executed set a prefix argument, then decrement the pointer to
@@ -4359,9 +3949,15 @@ execute_command_event (struct command_builder *command_builder,
       {
        /* Start a new command next time */
        Vlast_command = Vthis_command;
+       Vlast_command_properties = Vthis_command_properties;
+       Vthis_command_properties = Qnil;
+
        /* Emacs 18 doesn't unconditionally clear the echoed keystrokes,
           so we don't either */
-       reset_this_command_keys (make_console (con), 0);
+
+       if (!is_scrollbar_event (event))
+         reset_this_command_keys (CONSOLE_LIVE_P (con) ? make_console (con)
+                                  : Qnil, 0);
       }
   }
 
@@ -4379,6 +3975,9 @@ pre_command_hook (void)
   safe_run_hook_trapping_errors
     ("Error in `pre-command-hook' (setting hook to nil)",
      Qpre_command_hook, 1);
+
+  /* This is a kludge, but necessary; see simple.el */
+  call0 (Qhandle_pre_motion_command);
 }
 
 /* Run the post command hook. */
@@ -4398,14 +3997,18 @@ post_command_hook (void)
 
   Lisp_Object win = Fselected_window (Qnil);
 
-#if 0
   /* If the last command deleted the frame, `win' might be nil.
      It seems safest to do nothing in this case. */
+  /* Note: Someone added the following comment and put #if 0's around
+     this code, not realizing that doing this invites a crash in the
+     line after. */
   /* #### This doesn't really fix the problem,
      if delete-frame is called by some hook */
   if (NILP (win))
     return;
-#endif
+
+  /* This is a kludge, but necessary; see simple.el */
+  call0 (Qhandle_post_motion_command);
 
   if (! zmacs_region_stays
       && (!MINI_WINDOW_P (XWINDOW (win))
@@ -4418,36 +4021,6 @@ post_command_hook (void)
     ("Error in `post-command-hook' (setting hook to nil)",
      Qpost_command_hook, 1);
 
-#ifdef DEFERRED_ACTION_CRAP
-  if (!NILP (Vdeferred_action_list))
-    call0 (Vdeferred_action_function);
-#endif
-
-#ifdef ILL_CONCEIVED_HOOK
-  if (NILP (Vunread_command_events)
-      && NILP (Vexecuting_macro)
-      && !NILP (Vpost_command_idle_hook)
-      && !NILP (Fsit_for (make_float ((double) post_command_idle_delay
-                                     / 1000000), Qnil)))
-  safe_run_hook_trapping_errors
-    ("Error in `post-command-idle-hook' (setting hook to nil)",
-     Qpost_command_idle_hook, 1);
-#endif
-
-#if 0 /* FSFmacs */
-  if (!NILP (current_buffer->mark_active))
-    {
-      if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
-        {
-          current_buffer->mark_active = Qnil;
-         run_hook (intern ("deactivate-mark-hook"));
-        }
-      else if (current_buffer != prev_buffer ||
-              BUF_MODIFF (current_buffer) != prev_modiff)
-       run_hook (intern ("activate-mark-hook"));
-    }
-#endif /* FSFmacs */
-
   /* #### Kludge!!! This is necessary to make sure that things
      are properly positioned even if post-command-hook moves point.
      #### There should be a cleaner way of handling this. */
@@ -4456,7 +4029,7 @@ post_command_hook (void)
 
 \f
 DEFUN ("dispatch-event", Fdispatch_event, 1, 1, 0, /*
-Given an event object as returned by `next-event', execute it.
+Given an event object EVENT as returned by `next-event', execute it.
 
 Key-press, button-press, and button-release events get accumulated
 until a complete key sequence (see `read-key-sequence') is reached,
@@ -4606,10 +4179,10 @@ Magic events are handled as necessary.
               be done without an undo boundary.  This counter is reset as
               soon as a command other than self-insert-command is executed.
 
-              Programmers can also use the `self-insert-undo-magic'
-              property to install that behaviour on functions other
+              Programmers can also use the `self-insert-defer-undo'
+              property to install that behavior on functions other
               than `self-insert-command', or to change the magic
-              number 20 to something else.  */
+              number 20 to something else.  #### DOCUMENT THIS!  */
 
            if (SYMBOLP (leaf))
              {
@@ -4626,13 +4199,6 @@ Magic events are handled as necessary.
              command_builder->self_insert_countdown = 0;
            if (NILP (XCONSOLE (console)->prefix_arg)
                && NILP (Vexecuting_macro)
-#if 0
-               /* This was done in the days when there was no undo
-                  in the minibuffer.  If we don't disable this code,
-                  then each instance of "undo" undoes everything in
-                  the minibuffer. */
-               && !EQ (minibuf_window, Fselected_window (Qnil))
-#endif
                && command_builder->self_insert_countdown == 0)
              Fundo_boundary ();
 
@@ -4643,13 +4209,13 @@ Magic events are handled as necessary.
              }
            execute_command_event
               (command_builder,
-              internal_equal (event, command_builder-> most_current_event, 0)
+              internal_equal (event, command_builder->most_current_event, 0)
                ? event
                /* Use the translated event that was most recently seen.
                   This way, last-command-event becomes f1 instead of
                   the P from ESC O P.  But we must copy it, else we'll
                   lose when the command-builder events are deallocated. */
-               : Fcopy_event (command_builder-> most_current_event, Qnil));
+               : Fcopy_event (command_builder->most_current_event, Qnil));
          }
        break;
       }
@@ -4704,7 +4270,7 @@ Magic events are handled as necessary.
 DEFUN ("read-key-sequence", Fread_key_sequence, 1, 3, 0, /*
 Read a sequence of keystrokes or mouse clicks.
 Returns a vector of the event objects read.  The vector and the event
-objects it contains are freshly created (and will not be side-effected
+objects it contains are freshly created (and so will not be side-effected
 by subsequent calls to this function).
 
 The sequence read is sufficient to specify a non-prefix command starting
@@ -4712,19 +4278,17 @@ from the current local and global keymaps.  A C-g typed while in this
 function is treated like any other character, and `quit-flag' is not set.
 
 First arg PROMPT is a prompt string.  If nil, do not prompt specially.
-Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echoes
-as a continuation of the previous key.
 
-The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
-convert the last event to lower case.  (Normally any upper case event
-is converted to lower case if the original event is undefined and the lower
-case equivalent is defined.) This argument is provided mostly for
-FSF compatibility; the equivalent effect can be achieved more generally
-by binding `retry-undefined-key-binding-unshifted' to nil around the
-call to `read-key-sequence'.
+Second optional arg CONTINUE-ECHO non-nil means this key echoes as a
+continuation of the previous key.
 
-A C-g typed while in this function is treated like any other character,
-and `quit-flag' is not set.
+Third optional arg DONT-DOWNCASE-LAST non-nil means do not convert the
+last event to lower case.  (Normally any upper case event is converted
+to lower case if the original event is undefined and the lower case
+equivalent is defined.) This argument is provided mostly for FSF
+compatibility; the equivalent effect can be achieved more generally by
+binding `retry-undefined-key-binding-unshifted' to nil around the call
+to `read-key-sequence'.
 
 If the user selects a menu item while we are prompting for a key-sequence,
 the returned value will be a vector of a single menu-selection event.
@@ -4732,8 +4296,8 @@ An error will be signalled if you pass this value to `lookup-key' or a
 related function.
 
 `read-key-sequence' checks `function-key-map' for function key
-sequences, where they wouldn't conflict with ordinary bindings.  See
-`function-key-map' for more details.
+sequences, where they wouldn't conflict with ordinary bindings.
+See `function-key-map' for more details.
 */
        (prompt, continue_echo, dont_downcase_last))
 {
@@ -4750,6 +4314,7 @@ sequences, where they wouldn't conflict with ordinary bindings.  See
   struct gcpro gcpro1;
   GCPRO1 (event);
 
+  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
   if (!NILP (prompt))
     CHECK_STRING (prompt);
   /* else prompt = Fkeymap_prompt (current_buffer->keymap); may GC */
@@ -4869,10 +4434,10 @@ dribble_out_event (Lisp_Object event)
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, 1, 1,
        "FOpen dribble file: ", /*
-Start writing all keyboard characters to a dribble file called FILE.
-If FILE is nil, close any open dribble file.
+Start writing all keyboard characters to a dribble file called FILENAME.
+If FILENAME is nil, close any open dribble file.
 */
-       (file))
+       (filename))
 {
   /* This function can GC */
   /* XEmacs change: always close existing dribble file. */
@@ -4882,12 +4447,12 @@ If FILE is nil, close any open dribble file.
       Lstream_close (XLSTREAM (Vdribble_file));
       Vdribble_file = Qnil;
     }
-  if (!NILP (file))
+  if (!NILP (filename))
     {
       int fd;
 
-      file = Fexpand_file_name (file, Qnil);
-      fd = open ((char*) XSTRING_DATA (file),
+      filename = Fexpand_file_name (filename, Qnil);
+      fd = open ((char*) XSTRING_DATA (filename),
                 O_WRONLY | O_TRUNC | O_CREAT | OPEN_BINARY,
                 CREAT_MODE);
       if (fd < 0)
@@ -4903,6 +4468,23 @@ If FILE is nil, close any open dribble file.
 }
 
 \f
+
+DEFUN ("current-event-timestamp", Fcurrent_event_timestamp, 0, 1, 0, /*
+Return the current event timestamp of the window system associated with CONSOLE.
+CONSOLE defaults to the selected console if omitted.
+*/
+       (console))
+{
+  struct console *c = decode_console (console);
+  int tiempo = event_stream_current_event_timestamp (c);
+
+  /* This junk is so that timestamps don't get to be negative, but contain
+     as many bits as this particular emacs will allow.
+   */
+  return make_int (EMACS_INT_MAX & tiempo);
+}
+
+\f
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
@@ -4916,8 +4498,7 @@ syms_of_event_stream (void)
   defsymbol (&Qdisabled, "disabled");
   defsymbol (&Qcommand_event_p, "command-event-p");
 
-  deferror (&Qundefined_keystroke_sequence, "undefined-keystroke-sequence",
-            "Undefined keystroke sequence", Qerror);
+  DEFERROR_STANDARD (Qundefined_keystroke_sequence, Qinvalid_argument);
 
   DEFSUBR (Frecent_keys);
   DEFSUBR (Frecent_keys_ring_size);
@@ -4935,41 +4516,25 @@ syms_of_event_stream (void)
   DEFSUBR (Fadd_async_timeout);
   DEFSUBR (Fdisable_async_timeout);
   DEFSUBR (Fdispatch_event);
+  DEFSUBR (Fdispatch_non_command_events);
   DEFSUBR (Fread_key_sequence);
   DEFSUBR (Fthis_command_keys);
   DEFSUBR (Freset_this_command_lengths);
   DEFSUBR (Fopen_dribble_file);
-#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-  DEFSUBR (Faccelerate_menu);
-#endif
+  DEFSUBR (Fcurrent_event_timestamp);
 
   defsymbol (&Qpre_command_hook, "pre-command-hook");
   defsymbol (&Qpost_command_hook, "post-command-hook");
   defsymbol (&Qunread_command_events, "unread-command-events");
   defsymbol (&Qunread_command_event, "unread-command-event");
   defsymbol (&Qpre_idle_hook, "pre-idle-hook");
-#ifdef ILL_CONCEIVED_HOOK
-  defsymbol (&Qpost_command_idle_hook, "post-command-idle-hook");
-#endif
-#ifdef DEFERRED_ACTION_CRAP
-  defsymbol (&Qdeferred_action_function, "deferred-action-function");
-#endif
+  defsymbol (&Qhandle_pre_motion_command, "handle-pre-motion-command");
+  defsymbol (&Qhandle_post_motion_command, "handle-post-motion-command");
   defsymbol (&Qretry_undefined_key_binding_unshifted,
             "retry-undefined-key-binding-unshifted");
   defsymbol (&Qauto_show_make_point_visible,
             "auto-show-make-point-visible");
 
-  defsymbol (&Qmenu_force, "menu-force");
-  defsymbol (&Qmenu_fallback, "menu-fallback");
-
-  defsymbol (&Qmenu_quit, "menu-quit");
-  defsymbol (&Qmenu_up, "menu-up");
-  defsymbol (&Qmenu_down, "menu-down");
-  defsymbol (&Qmenu_left, "menu-left");
-  defsymbol (&Qmenu_right, "menu-right");
-  defsymbol (&Qmenu_select, "menu-select");
-  defsymbol (&Qmenu_escape, "menu-escape");
-
   defsymbol (&Qself_insert_defer_undo, "self-insert-defer-undo");
   defsymbol (&Qcancel_mode_internal, "cancel-mode-internal");
 }
@@ -4999,12 +4564,12 @@ vars_of_event_stream (void)
   Vthis_command_keys = Qnil;
   staticpro (&Vthis_command_keys);
   Vthis_command_keys_tail = Qnil;
-  pdump_wire (&Vthis_command_keys_tail);
+  dump_add_root_object (&Vthis_command_keys_tail);
 
   command_event_queue = Qnil;
   staticpro (&command_event_queue);
   command_event_queue_tail = Qnil;
-  pdump_wire (&command_event_queue_tail);
+  dump_add_root_object (&command_event_queue_tail);
 
   Vlast_selected_frame = Qnil;
   staticpro (&Vlast_selected_frame);
@@ -5050,7 +4615,7 @@ Normal hook run when XEmacs it about to be idle.
 This occurs whenever it is going to block, waiting for an event.
 This generally happens as a result of a call to `next-event',
 `next-command-event', `sit-for', `sleep-for', `accept-process-output',
-`x-get-selection', or various Energize-specific commands.
+or `x-get-selection'.
 Errors running the hook are caught and ignored.
 */ );
   Vpre_idle_hook = Qnil;
@@ -5063,43 +4628,6 @@ used by the window manager, so it is up to the user to set it.
 */ );
   focus_follows_mouse = 0;
 
-#ifdef ILL_CONCEIVED_HOOK
-  /* Ill-conceived because it's not run in all sorts of cases
-     where XEmacs is blocking.  That's what `pre-idle-hook'
-     is designed to solve. */
-  xxDEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook /*
-Normal hook run after each command is executed, if idle.
-`post-command-idle-delay' specifies a time in microseconds that XEmacs
-must be idle for in order for the functions on this hook to be called.
-Errors running the hook are caught and ignored.
-*/ );
-  Vpost_command_idle_hook = Qnil;
-
-  xxDEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay /*
-Delay time before running `post-command-idle-hook'.
-This is measured in microseconds.
-*/ );
-  post_command_idle_delay = 5000;
-#endif /* ILL_CONCEIVED_HOOK */
-
-#ifdef DEFERRED_ACTION_CRAP
-  /* Random FSFmacs crap.  There is absolutely nothing to gain,
-     and a great deal to lose, in using this in place of just
-     setting `post-command-hook'. */
-  xxDEFVAR_LISP ("deferred-action-list", &Vdeferred_action_list /*
-List of deferred actions to be performed at a later time.
-The precise format isn't relevant here; we just check whether it is nil.
-*/ );
-  Vdeferred_action_list = Qnil;
-
-  xxDEFVAR_LISP ("deferred-action-function", &Vdeferred_action_function /*
-Function to call to handle deferred actions, after each command.
-This function is called with no arguments after each command
-whenever `deferred-action-list' is non-nil.
-*/ );
-  Vdeferred_action_function = Qnil;
-#endif /* DEFERRED_ACTION_CRAP */
-
   DEFVAR_LISP ("last-command-event", &Vlast_command_event /*
 Last keyboard or mouse button event that was part of a command.  This
 variable is off limits: you may not set its value or modify the event that
@@ -5188,6 +4716,23 @@ will be in `last-command' during the following command.
 */ );
   Vthis_command = Qnil;
 
+  DEFVAR_LISP ("last-command-properties", &Vlast_command_properties /*
+Value of `this-command-properties' for the last command.
+Used by commands to help synchronize consecutive commands, in preference
+to looking at `last-command' directly.
+*/ );
+  Vlast_command_properties = Qnil;
+
+  DEFVAR_LISP ("this-command-properties", &Vthis_command_properties /*
+Properties set by the current command.
+At the beginning of each command, the current value of this variable is
+copied to `last-command-properties', and then it is set to nil.  Use `putf'
+to add properties to this variable.  Commands should use this to communicate
+with pre/post-command hooks, subsequent commands, wrapping commands, etc.
+in preference to looking at and/or setting `this-command'.
+*/ );
+  Vthis_command_properties = Qnil;
+
   DEFVAR_LISP ("help-char", &Vhelp_char /*
 Character to recognize as meaning Help.
 When it is read, do `(eval help-form)', and display result if it's a string.
@@ -5221,6 +4766,10 @@ Each key-press event is looked up in this table as follows:
    keysym changed and its modifiers left alone.  This is useful for
    dealing with non-standard X keyboards, such as the grievous damage
    that Sun has inflicted upon the world.
+-- If an entry maps a symbol to a character, then a key-press event
+   whose keysym is the former symbol (with any modifiers at all) gets
+   changed into a key-press event matching the latter character, and the
+   resulting modifiers are the union of the original and new modifiers.
 -- If an entry maps a character to a character, then a key-press event
    matching the former character gets converted to a key-press event
    matching the latter character.  This is useful on ASCII terminals
@@ -5229,6 +4778,16 @@ Each key-press event is looked up in this table as follows:
 -- If an entry maps a character to a symbol, then a key-press event
    matching the character gets converted to a key-press event whose
    keysym is the given symbol and which has no modifiers.
+
+Here's an example: This makes typing parens and braces easier by rerouting
+their positions to eliminate the need to use the Shift key.
+
+  (keyboard-translate ?[ ?()
+  (keyboard-translate ?] ?))
+  (keyboard-translate ?{ ?[)
+  (keyboard-translate ?} ?])
+  (keyboard-translate 'f11 ?{)
+  (keyboard-translate 'f12 ?})
 */ );
 
   DEFVAR_LISP ("retry-undefined-key-binding-unshifted",
@@ -5241,6 +4800,28 @@ you should *bind* this, not set it.
 */ );
     Vretry_undefined_key_binding_unshifted = Qt;
 
+  DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /*
+*Non-nil makes modifier keys sticky.
+This means that you can release the modifier key before pressing down
+the key that you wish to be modified.  Although this is non-standard
+behavior, it is recommended because it reduces the strain on your hand,
+thus reducing the incidence of the dreaded Emacs-pinky syndrome.
+
+Modifier keys are sticky within the inverval specified by
+`modifier-keys-sticky-time'.
+*/ );
+  modifier_keys_are_sticky = 0;
+
+  DEFVAR_LISP ("modifier-keys-sticky-time", &Vmodifier_keys_sticky_time /*
+*Modifier keys are sticky within this many milliseconds.
+If you don't want modifier keys sticking to be bounded, set this to
+non-integer value.
+
+This variable has no effect when `modifier-keys-are-sticky' is nil.
+Currently only implemented under X Window System.
+*/ );
+  Vmodifier_keys_sticky_time = make_int (500);
+
 #ifdef HAVE_XIM
   DEFVAR_LISP ("composed-character-default-binding",
                &Vcomposed_character_default_binding /*
@@ -5301,41 +4882,6 @@ and is one of the following:
 Non-nil inhibits recording of input-events to recent-keys ring.
 */ );
   inhibit_input_event_recording = 0;
-
-  DEFVAR_LISP("menu-accelerator-prefix", &Vmenu_accelerator_prefix /*
-Prefix key(s) that must be typed before menu accelerators will be activated.
-Set this to a value acceptable by define-key.
-*/ );
-  Vmenu_accelerator_prefix = Qnil;
-
-  DEFVAR_LISP ("menu-accelerator-modifiers", &Vmenu_accelerator_modifiers /*
-Modifier keys which must be pressed to get to the top level menu accelerators.
-This is a list of modifier key symbols.  All modifier keys must be held down
-while a valid menu accelerator key is pressed in order for the top level
-menu to become active.
-
-See also menu-accelerator-enabled and menu-accelerator-prefix.
-*/ );
-  Vmenu_accelerator_modifiers = list1 (Qmeta);
-
-  DEFVAR_LISP ("menu-accelerator-enabled", &Vmenu_accelerator_enabled /*
-Whether menu accelerator keys can cause the menubar to become active.
-If 'menu-force or 'menu-fallback, then menu accelerator keys can
-be used to activate the top level menu.  Once the menubar becomes active, the
-accelerator keys can be used regardless of the value of this variable.
-
-menu-force is used to indicate that the menu accelerator key takes
-precedence over bindings in the current keymap(s).  menu-fallback means
-that bindings in the current keymap take precedence over menu accelerator keys.
-Thus a top level menu with an accelerator of "T" would be activated on a
-keypress of Meta-t if menu-accelerator-enabled is menu-force.
-However, if menu-accelerator-enabled is menu-fallback, then
-Meta-t will not activate the menubar and will instead run the function
-transpose-words, to which it is normally bound.
-
-See also menu-accelerator-modifiers and menu-accelerator-prefix.
-*/ );
-  Vmenu_accelerator_enabled = Qnil;
 }
 
 void
@@ -5343,41 +4889,6 @@ complex_vars_of_event_stream (void)
 {
   Vkeyboard_translate_table =
     make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
-
-  DEFVAR_LISP ("menu-accelerator-map", &Vmenu_accelerator_map /*
-Keymap for use when the menubar is active.
-The actions menu-quit, menu-up, menu-down, menu-left, menu-right,
-menu-select and menu-escape can be mapped to keys in this map.
-
-menu-quit    Immediately deactivate the menubar and any open submenus without
-             selecting an item.
-menu-up      Move the menu cursor up one row in the current menu.  If the
-             move extends past the top of the menu, wrap around to the bottom.
-menu-down    Move the menu cursor down one row in the current menu.  If the
-             move extends past the bottom of the menu, wrap around to the top.
-             If executed while the cursor is in the top level menu, move down
-             into the selected menu.
-menu-left    Move the cursor from a submenu into the parent menu.  If executed
-             while the cursor is in the top level menu, move the cursor to the
-             left.  If the move extends past the left edge of the menu, wrap
-             around to the right edge.
-menu-right   Move the cursor into a submenu.  If the cursor is located in the
-             top level menu or is not currently on a submenu heading, then move
-             the cursor to the next top level menu entry.  If the move extends
-             past the right edge of the menu, wrap around to the left edge.
-menu-select  Activate the item under the cursor.  If the cursor is located on
-             a submenu heading, then move the cursor into the submenu.
-menu-escape  Pop up to the next level of menus.  Moves from a submenu into its
-             parent menu.  From the top level menu, this deactivates the
-             menubar.
-
-This keymap can also contain normal key-command bindings, in which case the
-menubar is deactivated and the corresponding command is executed.
-
-The action bindings used by the menu accelerator code are designed to mimic
-the actions of menu traversal keys in a commonly used PC operating system.
-*/ );
-  Vmenu_accelerator_map = Fmake_keymap(Qnil);
 }
 
 void
@@ -5393,6 +4904,11 @@ init_event_stream (void)
        init_event_Xt_late ();
       else
 #endif
+#ifdef HAVE_GTK
+      if (!strcmp (display_use, "gtk"))
+       init_event_gtk_late ();
+      else
+#endif
 #ifdef HAVE_MS_WINDOWS
       if (!strcmp (display_use, "mswindows"))
        init_event_mswindows_late ();
@@ -5429,20 +4945,23 @@ useful testcases for v18/v19 compatibility:
 (global-set-key "\^Q" 'foo)
 
 without the read-key-sequence:
-  ^Q           ==>  (65 17 65 [... ^Q] [^Q])
-  ^U^U^Q       ==>  (65 17 65 [... ^U ^U ^Q] [^U ^U ^Q])
-  ^U^U^U^G^Q   ==>  (65 17 65 [... ^U ^U ^U ^G ^Q] [^Q])
+  ^Q           ==>  (?A ?\^Q ?A [... ^Q] [^Q])
+  ^U^U^Q       ==>  (?A ?\^Q ?A [... ^U ^U ^Q] [^U ^U ^Q])
+  ^U^U^U^G^Q   ==>  (?A ?\^Q ?A [... ^U ^U ^U ^G ^Q] [^Q])
 
 with the read-key-sequence:
-  ^Qb          ==>  (65 [b] 17 98 [... ^Q b] [b])
-  ^U^U^Qb      ==>  (65 [b] 17 98 [... ^U ^U ^Q b] [b])
-  ^U^U^U^G^Qb  ==>  (65 [b] 17 98 [... ^U ^U ^U ^G ^Q b] [b])
+  ^Qb          ==>  (?A [b] ?\^Q ?b [... ^Q b] [b])
+  ^U^U^Qb      ==>  (?A [b] ?\^Q ?b [... ^U ^U ^Q b] [b])
+  ^U^U^U^G^Qb  ==>  (?A [b] ?\^Q ?b [... ^U ^U ^U ^G ^Q b] [b])
 
 ;the evi-mode command "4dlj.j.j.j.j.j." is also a good testcase (gag)
 
 ;(setq x (list (read-char) quit-flag))^J^G
 ;(let ((inhibit-quit t)) (setq x (list (read-char) quit-flag)))^J^G
 ;for BOTH, x should get set to (7 t), but no result should be printed.
+;; #### According to the doc of quit-flag, second test should return
+;; (?\^G nil).  Accidentaly XEmacs returns correct value.  However,
+;; XEmacs 21.1.12 and 21.2.36 both fails on first test.
 
 ;also do this: make two frames, one viewing "*scratch*", the other "foo".
 ;in *scratch*, type (sit-for 20)^J
@@ -5462,9 +4981,9 @@ with the read-key-sequence:
          (quit c))
        (read-char)))
 
- (tst)^Ja^G    ==>  ((quit) 97) with no signal
- (tst)^J^Ga    ==>  ((quit) 97) with no signal
- (tst)^Jabc^G  ==>  ((quit) 97) with no signal, and "bc" inserted in buffer
+ (tst)^Ja^G    ==>  ((quit) ?a) with no signal
+ (tst)^J^Ga    ==>  ((quit) ?a) with no signal
+ (tst)^Jabc^G  ==>  ((quit) ?a) with no signal, and "bc" inserted in buffer
 
 ; with sit-for only do the 2nd test.
 ; Do all 3 tests with (accept-process-output nil 20)