(A-IWDSU+7375): New abstract node.
[chise/xemacs-chise.git.1] / src / event-stream.c
index 0d09051..de65d4e 100644 (file)
@@ -52,8 +52,6 @@ Boston, MA 02111-1307, USA.  */
 /* TODO:
    This stuff is way too hard to maintain - needs rework.
 
 /* TODO:
    This stuff is way too hard to maintain - needs rework.
 
-   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
    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
@@ -102,7 +100,7 @@ Boston, MA 02111-1307, USA.  */
 #include <errno.h>
 
 /* The number of keystrokes between auto-saves. */
 #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;
 
 
 Lisp_Object Qundefined_keystroke_sequence;
 
@@ -121,23 +119,19 @@ Lisp_Object Qpre_idle_hook, Vpre_idle_hook;
 /* Control gratuitous keyboard focus throwing. */
 int focus_follows_mouse;
 
 /* Control gratuitous keyboard focus throwing. */
 int focus_follows_mouse;
 
+/* When true, modifier keys are sticky. */
 int modifier_keys_are_sticky;
 int modifier_keys_are_sticky;
+/* Modifier keys are sticky for this many milliseconds. */
+Lisp_Object Vmodifier_keys_sticky_time;
 
 
-#if 0 /* FSF Emacs crap */
-/* 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;
+/* 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. */
 
 
-/* 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;
-
-/* Function to call to handle deferred actions, when there are any.  */
-Lisp_Object Vdeferred_action_function;
-Lisp_Object Qdeferred_action_function;
-#endif /* FSF Emacs 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. */
 
 /* Non-nil disable property on a command means
    do not execute it; call disabled-command-hook's value instead. */
@@ -256,7 +250,7 @@ Lisp_Object Qself_insert_defer_undo;
 extern Lisp_Object Fmake_keymap (Lisp_Object name);
 
 #ifdef DEBUG_XEMACS
 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)
 
 static void
 external_debugging_print_event (char *event_description, Lisp_Object event)
@@ -429,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:
        case EVENT_STREAM_READ:
          error ("Can't read events in -batch mode");
        default:
-         abort ();
+         ABORT ();
        }
     }
   else if (!event_stream)
        }
     }
   else if (!event_stream)
@@ -502,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;
      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);
   event_stream->next_event_cb (event);
-#if 0
-  init_poll_for_quit ();
-#endif
   emacs_is_blocking = 0;
 
 #ifdef DEBUG_XEMACS
   emacs_is_blocking = 0;
 
 #ifdef DEBUG_XEMACS
@@ -715,7 +701,8 @@ reset_key_echo (struct command_builder *command_builder,
   /* This function can GC */
   struct frame *f = selected_frame ();
 
   /* 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);
 
   if (remove_echo_area_echo)
     clear_echo_area (f, Qcommand, 0);
@@ -759,7 +746,7 @@ maybe_kbd_translate (Lisp_Object event)
             This way is safer. */
          zero_event (&ev2);
          character_to_event (XCHAR (traduit), &ev2,
             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;
          XEVENT (event)->event.key.keysym = ev2.event.key.keysym;
          XEVENT (event)->event.key.modifiers = ev2.event.key.modifiers;
          did_translate = 1;
@@ -781,7 +768,7 @@ maybe_kbd_translate (Lisp_Object event)
 
          zero_event (&ev2);
          character_to_event (XCHAR (traduit), &ev2,
 
          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;
          XEVENT (event)->event.key.keysym = ev2.event.key.keysym;
          XEVENT (event)->event.key.modifiers |= ev2.event.key.modifiers;
          did_translate = 1;
@@ -798,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. */
 
    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)
 
 void
 record_auto_save (void)
@@ -812,10 +800,6 @@ void
 force_auto_save_soon (void)
 {
   keystrokes_since_auto_save = 1 + max (auto_save_interval, 20);
 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
 }
 
 static void
@@ -1403,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);
   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;
 }
 
   return lid;
 }
 
@@ -1482,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);
   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;
 }
 
   return lid;
 }
 
@@ -1695,19 +1679,6 @@ run_select_frame_hook (void)
 static void
 run_deselect_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);
 }
 
   run_hook (Qdeselect_frame_hook);
 }
 
@@ -1837,7 +1808,8 @@ emacs_handle_focus_change_preliminary (Lisp_Object frame_inp_and_dev)
        MARK_WINDOWS_CHANGED (w);
       }
 
        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;
        {
          /* Oops, we missed a focus-out event. */
          DEVICE_FRAME_WITH_FOCUS_REAL (d) = Qnil;
@@ -2039,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 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.
 
 DEFUN ("next-event", Fnext_event, 0, 2, 0, /*
 Return the next available event.
@@ -2231,8 +2204,6 @@ The returned event will be one of the following types:
 
   switch (XEVENT_TYPE (event))
     {
 
   switch (XEVENT_TYPE (event))
     {
-    default:
-      goto RETURN;
     case button_release_event:
     case misc_user_event:
       /* don't echo menu accelerator keys */
     case button_release_event:
     case misc_user_event:
       /* don't echo menu accelerator keys */
@@ -2242,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;
       goto STORE_AND_EXECUTE_KEY;
     case key_press_event:         /* any key input can trigger autosave */
       break;
+    default:
+      goto RETURN;
     }
 
   maybe_do_auto_save ();
     }
 
   maybe_do_auto_save ();
@@ -2299,7 +2272,9 @@ The returned event will be one of the following types:
      */
   if (store_this_key)
     {
      */
   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);
       if (!inhibit_input_event_recording)
        push_recent_keys (event);
       dribble_out_event (event);
@@ -2491,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))
     }
 
   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.
 
   /* 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.
@@ -2684,11 +2659,11 @@ Return non-nil iff we received any output before the timeout expired.
 }
 
 DEFUN ("sleep-for", Fsleep_for, 1, 1, 0, /*
 }
 
 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
 
 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))
 {
 */
        (seconds))
 {
@@ -2751,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, /*
 }
 
 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.
 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.
@@ -3066,7 +3041,7 @@ execute_internal_event (Lisp_Object event)
        return;
       }
     default:
        return;
       }
     default:
-      abort ();
+      ABORT ();
     }
 }
 
     }
 }
 
@@ -3402,7 +3377,7 @@ modify them.
     {
       Vrecent_keys_ring = make_vector (recent_keys_ring_size, Qnil);
       /* And return nothing in particular. */
     {
       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]))
     }
 
   if (NILP (XVECTOR_DATA (Vrecent_keys_ring)[recent_keys_ring_index]))
@@ -3434,7 +3409,7 @@ modify them.
     Lisp_Object e = XVECTOR_DATA (Vrecent_keys_ring)[j];
 
     if (NILP (e))
     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;
     XVECTOR_DATA (val)[i] = Fcopy_event (e, Qnil);
     if (++j >= recent_keys_ring_size)
       j = 0;
@@ -3460,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;
   Lisp_Object new_vector = Qnil;
   int i, j, nkeys, start, min;
   struct gcpro gcpro1;
-  GCPRO1 (new_vector);
 
   CHECK_INT (size);
   if (XINT (size) <= 0)
 
   CHECK_INT (size);
   if (XINT (size) <= 0)
@@ -3468,12 +3442,13 @@ Set the maximum number of events to be stored internally.
   if (XINT (size) == recent_keys_ring_size)
     return size;
 
   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;
   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]))
     }
 
   if (NILP (XVECTOR_DATA (Vrecent_keys_ring)[recent_keys_ring_index]))
@@ -3530,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)
 {
 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;
 
   deallocate_event_chain (Vthis_command_keys);
   Vthis_command_keys = Qnil;
   Vthis_command_keys_tail = Qnil;
-
-  reset_current_events (command_builder);
 }
 
 static void
 }
 
 static void
@@ -3570,7 +3553,7 @@ extract_this_command_keys_nth_mouse_event (int n)
        {
          if (!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
              if (!NILP (XEVENT_NEXT (event)))
                 return Fcopy_event (event, Qnil);
              else
@@ -3701,7 +3684,7 @@ lookup_command_event (struct command_builder *command_builder,
                 || e->event_type == button_release_event)
          e->event.button.modifiers |= XEMACS_MOD_META;
        else
                 || e->event_type == button_release_event)
          e->event.button.modifiers |= XEMACS_MOD_META;
        else
-         abort ();
+         ABORT ();
 
        {
          int tckn = event_chain_count (Vthis_command_keys);
 
        {
          int tckn = event_chain_count (Vthis_command_keys);
@@ -3786,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)
 static void
 execute_command_event (struct command_builder *command_builder,
                        Lisp_Object event)
@@ -3795,7 +3807,59 @@ execute_command_event (struct command_builder *command_builder,
   struct gcpro gcpro1;
 
   GCPRO1 (event); /* event may be freshly created */
   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)
     {
 
   switch (XEVENT (event)->event_type)
     {
@@ -3862,17 +3926,16 @@ execute_command_event (struct command_builder *command_builder,
 
     post_command_hook ();
 
 
     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
       {
        /* 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);
        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
 
        /* If we're recording a keyboard macro, and the last command
           executed set a prefix argument, then decrement the pointer to
@@ -3891,7 +3954,10 @@ execute_command_event (struct command_builder *command_builder,
 
        /* Emacs 18 doesn't unconditionally clear the echoed keystrokes,
           so we don't either */
 
        /* 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);
       }
   }
 
       }
   }
 
@@ -3955,34 +4021,6 @@ post_command_hook (void)
     ("Error in `post-command-hook' (setting hook to nil)",
      Qpost_command_hook, 1);
 
     ("Error in `post-command-hook' (setting hook to nil)",
      Qpost_command_hook, 1);
 
-#if 0 /* FSF Emacs crap */
-  if (!NILP (Vdeferred_action_list))
-    call0 (Vdeferred_action_function);
-
-  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 /* FSF Emacs crap */
-
-#if 0 /* FSF Emacs */
-  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 /* FSF Emacs */
-
   /* #### 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. */
   /* #### 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. */
@@ -3991,7 +4029,7 @@ post_command_hook (void)
 
 \f
 DEFUN ("dispatch-event", Fdispatch_event, 1, 1, 0, /*
 
 \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,
 
 Key-press, button-press, and button-release events get accumulated
 until a complete key sequence (see `read-key-sequence') is reached,
@@ -4161,13 +4199,6 @@ Magic events are handled as necessary.
              command_builder->self_insert_countdown = 0;
            if (NILP (XCONSOLE (console)->prefix_arg)
                && NILP (Vexecuting_macro)
              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 ();
 
                && command_builder->self_insert_countdown == 0)
              Fundo_boundary ();
 
@@ -4178,13 +4209,13 @@ Magic events are handled as necessary.
              }
            execute_command_event
               (command_builder,
              }
            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. */
                ? 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;
       }
          }
        break;
       }
@@ -4239,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
 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
 by subsequent calls to this function).
 
 The sequence read is sufficient to specify a non-prefix command starting
@@ -4247,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.
 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.
 
 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.
@@ -4267,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
 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))
 {
 */
        (prompt, continue_echo, dont_downcase_last))
 {
@@ -4285,6 +4314,7 @@ sequences, where they wouldn't conflict with ordinary bindings.  See
   struct gcpro gcpro1;
   GCPRO1 (event);
 
   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 */
   if (!NILP (prompt))
     CHECK_STRING (prompt);
   /* else prompt = Fkeymap_prompt (current_buffer->keymap); may GC */
@@ -4404,10 +4434,10 @@ dribble_out_event (Lisp_Object event)
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, 1, 1,
        "FOpen dribble file: ", /*
 
 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. */
 {
   /* This function can GC */
   /* XEmacs change: always close existing dribble file. */
@@ -4417,12 +4447,12 @@ If FILE is nil, close any open dribble file.
       Lstream_close (XLSTREAM (Vdribble_file));
       Vdribble_file = Qnil;
     }
       Lstream_close (XLSTREAM (Vdribble_file));
       Vdribble_file = Qnil;
     }
-  if (!NILP (file))
+  if (!NILP (filename))
     {
       int fd;
 
     {
       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)
                 O_WRONLY | O_TRUNC | O_CREAT | OPEN_BINARY,
                 CREAT_MODE);
       if (fd < 0)
@@ -4451,7 +4481,7 @@ CONSOLE defaults to the selected console if omitted.
   /* This junk is so that timestamps don't get to be negative, but contain
      as many bits as this particular emacs will allow.
    */
   /* 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 (((1L << (VALBITS - 1)) - 1) & tiempo);
+  return make_int (EMACS_INT_MAX & tiempo);
 }
 
 \f
 }
 
 \f
@@ -4500,10 +4530,6 @@ syms_of_event_stream (void)
   defsymbol (&Qpre_idle_hook, "pre-idle-hook");
   defsymbol (&Qhandle_pre_motion_command, "handle-pre-motion-command");
   defsymbol (&Qhandle_post_motion_command, "handle-post-motion-command");
   defsymbol (&Qpre_idle_hook, "pre-idle-hook");
   defsymbol (&Qhandle_pre_motion_command, "handle-pre-motion-command");
   defsymbol (&Qhandle_post_motion_command, "handle-post-motion-command");
-#if 0 /* FSF Emacs crap */
-  defsymbol (&Qpost_command_idle_hook, "post-command-idle-hook");
-  defsymbol (&Qdeferred_action_function, "deferred-action-function");
-#endif
   defsymbol (&Qretry_undefined_key_binding_unshifted,
             "retry-undefined-key-binding-unshifted");
   defsymbol (&Qauto_show_make_point_visible,
   defsymbol (&Qretry_undefined_key_binding_unshifted,
             "retry-undefined-key-binding-unshifted");
   defsymbol (&Qauto_show_make_point_visible,
@@ -4538,12 +4564,12 @@ vars_of_event_stream (void)
   Vthis_command_keys = Qnil;
   staticpro (&Vthis_command_keys);
   Vthis_command_keys_tail = Qnil;
   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;
 
   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);
 
   Vlast_selected_frame = Qnil;
   staticpro (&Vlast_selected_frame);
@@ -4602,41 +4628,6 @@ used by the window manager, so it is up to the user to set it.
 */ );
   focus_follows_mouse = 0;
 
 */ );
   focus_follows_mouse = 0;
 
-#if 0 /* FSF Emacs crap */
-  /* 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;
-
-  /* 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 /* FSF Emacs 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
   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
@@ -4815,9 +4806,22 @@ 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.
 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;
 
 */ );
   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 /*
 #ifdef HAVE_XIM
   DEFVAR_LISP ("composed-character-default-binding",
                &Vcomposed_character_default_binding /*
@@ -4900,6 +4904,11 @@ init_event_stream (void)
        init_event_Xt_late ();
       else
 #endif
        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 ();
 #ifdef HAVE_MS_WINDOWS
       if (!strcmp (display_use, "mswindows"))
        init_event_mswindows_late ();
@@ -4936,20 +4945,23 @@ useful testcases for v18/v19 compatibility:
 (global-set-key "\^Q" 'foo)
 
 without the read-key-sequence:
 (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:
 
 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.
 
 ;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
 
 ;also do this: make two frames, one viewing "*scratch*", the other "foo".
 ;in *scratch*, type (sit-for 20)^J
@@ -4969,9 +4981,9 @@ with the read-key-sequence:
          (quit c))
        (read-char)))
 
          (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)
 
 ; with sit-for only do the 2nd test.
 ; Do all 3 tests with (accept-process-output nil 20)