]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(record_asynch_buffer_change): Don't test
[gnu-emacs] / src / keyboard.c
index dd21b63cfdd65e33dea2875aa9b9e6536d2a2006..96f0c651658c3dd0bf123c59db4b3bbb06e25ca4 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -51,6 +51,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "syssignal.h"
 #include "systty.h"
+
+/* This is to get the definitions of the XK_ symbols.  */
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif
+
+/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
 #include "systime.h"
 
 extern int errno;
@@ -179,7 +186,7 @@ Lisp_Object last_nonmenu_event;
 Lisp_Object last_input_char;
 
 /* If not Qnil, a list of objects to be read as subsequent command input.  */
-Lisp_Object unread_command_events;
+Lisp_Object Vunread_command_events;
 
 /* If not -1, an event to be read as subsequent command input.  */
 int unread_command_char;
@@ -235,6 +242,9 @@ Lisp_Object this_command;
 /* The value of point when the last command was executed.  */
 int last_point_position;
 
+/* The buffer that was current when the last command was started.  */
+Lisp_Object last_point_position_buffer;
+
 #ifdef MULTI_FRAME
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
@@ -242,12 +252,12 @@ int last_point_position;
    like Fselect_frame, to make sure that a switch-frame event is
    generated by the next character.  */
 Lisp_Object internal_last_event_frame;
+#endif
 
 /* A user-visible version of the above, intended to allow users to
    figure out where the last event came from, if the event doesn't
    carry that information itself (i.e. if it was a character).  */
 Lisp_Object Vlast_event_frame;
-#endif
 
 /* The timestamp of the last input event we received from the X server.
    X Windows wants this for selection ownership.  */
@@ -287,6 +297,13 @@ Lisp_Object Qpre_command_hook, Qpost_command_hook;
 Lisp_Object Vpre_command_hook, Vpost_command_hook;
 Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
 
+/* 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;
+
 /* File in which we write all commands we read.  */
 FILE *dribble;
 
@@ -416,6 +433,8 @@ Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
 
+Lisp_Object Qpolling_period;
+
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
    happens.  */
 EMACS_TIME *input_available_clear_time;
@@ -477,6 +496,10 @@ static char echobuf[300];
 /* Where to append more text to echobuf if we want to.  */
 static char *echoptr;
 
+/* If we have echoed a prompt string specified by the user,
+   this is its length.  Otherwise this is -1.  */
+static int echo_after_prompt;
+
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
@@ -492,12 +515,15 @@ echo_prompt (str)
      char *str;
 {
   int len = strlen (str);
+
   if (len > sizeof echobuf - 4)
     len = sizeof echobuf - 4;
   bcopy (str, echobuf, len);
   echoptr = echobuf + len;
   *echoptr = '\0';
 
+  echo_after_prompt = len;
+
   echo ();
 }
 
@@ -556,6 +582,9 @@ echo_dash ()
 {
   if (!immediate_echo && echoptr == echobuf)
     return;
+  /* Do nothing if we just printed a prompt.  */
+  if (echo_after_prompt == echoptr - echobuf)
+    return;
   /* Do nothing if not echoing at all.  */
   if (echoptr == 0)
     return;
@@ -579,7 +608,13 @@ echo ()
       immediate_echo = 1;
 
       for (i = 0; i < this_command_key_count; i++)
-       echo_char (XVECTOR (this_command_keys)->contents[i]);
+       {
+         Lisp_Object c;
+         c = XVECTOR (this_command_keys)->contents[i];
+         if (! (EVENT_HAS_PARAMETERS (c)
+                && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+           echo_char (c);
+       }
       echo_dash ();
     }
 
@@ -597,6 +632,7 @@ cancel_echoing ()
 {
   immediate_echo = 0;
   echoptr = echobuf;
+  echo_after_prompt = -1;
 }
 
 /* Return the length of the current echo string.  */
@@ -663,10 +699,20 @@ recursive_edit_1 ()
 }
 
 /* When an auto-save happens, record the "time", and don't do again soon.  */
+
 record_auto_save ()
 {
   last_auto_save = num_nonmacro_input_chars;
 }
+
+/* Make an auto save happen as soon as possible at command level.  */
+
+force_auto_save_soon ()
+{
+  last_auto_save = - auto_save_interval - 1;
+
+  record_asynch_buffer_change ();
+}
 \f
 DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
   "Invoke the editor command loop recursively.\n\
@@ -887,6 +933,7 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 
 Lisp_Object Fcommand_execute ();
 static int read_key_sequence ();
+static void safe_run_hooks ();
 
 Lisp_Object
 command_loop_1 ()
@@ -912,17 +959,13 @@ command_loop_1 ()
 
   /* Make sure this hook runs after commands that get errors and
      throw to top level.  */
-  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-    {
-      /* If we get an error during the post-command-hook,
-        cause post-command-hook to be nil.  */
-      Vcommand_hook_internal = Vpost_command_hook;
-      Vpost_command_hook = Qnil;
+  /* Note that the value cell will never directly contain nil
+     if the symbol is a local variable.  */
+  if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+    safe_run_hooks (Qpost_command_hook);
 
-      call1 (Vrun_hooks, Qcommand_hook_internal);
-      
-      Vpost_command_hook = Vcommand_hook_internal;
-    }
+  if (!NILP (Vdeferred_action_list))
+    call0 (Vdeferred_action_function);
 
   /* Do this after running Vpost_command_hook, for consistency.  */
   last_command = this_command;
@@ -965,7 +1008,7 @@ command_loop_1 ()
          if (!NILP (Vquit_flag))
            {
              Vquit_flag = Qnil;
-             unread_command_events = Fcons (make_number (quit_char), Qnil);
+             Vunread_command_events = Fcons (make_number (quit_char), Qnil);
            }
        }
 
@@ -1038,21 +1081,15 @@ command_loop_1 ()
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
+      XSET (last_point_position_buffer, Lisp_Buffer, prev_buffer);
 
       /* Execute the command.  */
 
       this_command = cmd;
-      if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
-       {
-         /* If we get an error during the pre-command-hook,
-            cause pre-command-hook to be nil.  */
-         Vcommand_hook_internal = Vpre_command_hook;
-         Vpre_command_hook = Qnil;
-
-         call1 (Vrun_hooks, Qcommand_hook_internal);
-
-         Vpre_command_hook = Vcommand_hook_internal;
-       }
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpre_command_hook);
 
       if (NILP (this_command))
        {
@@ -1069,20 +1106,22 @@ command_loop_1 ()
            {
              /* Recognize some common commands in common situations and
                 do them directly.  */
-             if (EQ (this_command, Qforward_char) && point < ZV)
+             if (EQ (this_command, Qforward_char) && PT < ZV)
                {
                   struct Lisp_Vector *dp
                    = window_display_table (XWINDOW (selected_window));
-                 lose = FETCH_CHAR (point);
-                 SET_PT (point + 1);
+                 lose = FETCH_CHAR (PT);
+                 SET_PT (PT + 1);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
-                         && XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1)
+                         ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
+                          : (NILP (DISP_CHAR_VECTOR (dp, lose))
+                             && (lose >= 0x20 && lose < 0x7f)))
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
-                         == point - 1)
+                         == PT - 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
@@ -1090,20 +1129,22 @@ command_loop_1 ()
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
                }
-             else if (EQ (this_command, Qbackward_char) && point > BEGV)
+             else if (EQ (this_command, Qbackward_char) && PT > BEGV)
                {
                   struct Lisp_Vector *dp
                    = window_display_table (XWINDOW (selected_window));
-                 SET_PT (point - 1);
-                 lose = FETCH_CHAR (point);
+                 SET_PT (PT - 1);
+                 lose = FETCH_CHAR (PT);
                  if ((dp
-                      ? (XTYPE (DISP_CHAR_VECTOR (dp, lose)) != Lisp_Vector
-                         && XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1)
+                      ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
+                         ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
+                          : (NILP (DISP_CHAR_VECTOR (dp, lose))
+                             && (lose >= 0x20 && lose < 0x7f)))
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
-                         == point + 1)
+                         == PT + 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
@@ -1116,9 +1157,10 @@ command_loop_1 ()
                       && XTYPE (last_command_char) == Lisp_Int)
                {
                  unsigned char c = XINT (last_command_char);
+                 int value;
 
-                 if (NILP (Vexecuting_macro) &&
-                     !EQ (minibuf_window, selected_window))
+                 if (NILP (Vexecuting_macro)
+                     && !EQ (minibuf_window, selected_window))
                    {
                      if (!nonundocount || nonundocount >= 20)
                        {
@@ -1127,22 +1169,23 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
-                 lose = (XFASTINT (XWINDOW (selected_window)->last_modified)
-                         < MODIFF)
-                   || (XFASTINT (XWINDOW (selected_window)->last_point)
-                         != point)
-                   || MODIFF <= current_buffer->save_modified
-                   || windows_or_buffers_changed
-                   || !EQ (current_buffer->selective_display, Qnil)
-                   || detect_input_pending ()
-                   || !NILP (Vexecuting_macro);
-                 if (internal_self_insert (c, 0))
-                   {
-                     lose = 1;
-                     nonundocount = 0;
-                   }
-                 if (!lose &&
-                     (point == ZV || FETCH_CHAR (point) == '\n'))
+                 lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
+                          < MODIFF)
+                         || (XFASTINT (XWINDOW (selected_window)->last_point)
+                             != PT)
+                         || MODIFF <= current_buffer->save_modified
+                         || windows_or_buffers_changed
+                         || !EQ (current_buffer->selective_display, Qnil)
+                         || detect_input_pending ()
+                         || !NILP (Vexecuting_macro));
+                 value = internal_self_insert (c, 0);
+                 if (value)
+                   lose = 1;
+                 if (value == 2)
+                   nonundocount = 0;
+
+                 if (!lose
+                     && (PT == ZV || FETCH_CHAR (PT) == '\n'))
                    {
                      struct Lisp_Vector *dp
                        = window_display_table (XWINDOW (selected_window));
@@ -1153,12 +1196,21 @@ command_loop_1 ()
                          Lisp_Object obj;
 
                          obj = DISP_CHAR_VECTOR (dp, lose);
-                         if (XTYPE (obj) == Lisp_Vector
-                             && XVECTOR (obj)->size == 1
-                             && (XTYPE (obj = XVECTOR (obj)->contents[0])
-                                 == Lisp_Int))
-                           no_redisplay =
-                             direct_output_for_insert (XINT (obj));
+                         if (NILP (obj))
+                           {
+                             /* Do it only for char codes
+                                that by default display as themselves.  */
+                             if (lose >= 0x20 && lose <= 0x7e)
+                               no_redisplay = direct_output_for_insert (lose);
+                           }
+                         else if (XTYPE (obj) == Lisp_Vector
+                                  && XVECTOR (obj)->size == 1
+                                  && (XTYPE (obj = XVECTOR (obj)->contents[0])
+                                      == Lisp_Int)
+                                  /* Insist face not specified in glyph.  */
+                                  && (XINT (obj) & ((-1) << 8)) == 0)
+                           no_redisplay
+                             = direct_output_for_insert (XINT (obj));
                        }
                      else
                        {
@@ -1180,17 +1232,13 @@ command_loop_1 ()
        }
     directly_done: ;
 
-      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-       {
-         /* If we get an error during the post-command-hook,
-            cause post-command-hook to be nil.  */
-         Vcommand_hook_internal = Vpost_command_hook;
-         Vpost_command_hook = Qnil;
-
-         call1 (Vrun_hooks, Qcommand_hook_internal);
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpost_command_hook);
 
-         Vpost_command_hook = Vcommand_hook_internal;
-       }
+      if (!NILP (Vdeferred_action_list))
+       call0 (Vdeferred_action_function);
 
       /* If there is a prefix argument,
         1) We don't want last_command to be ``universal-argument''
@@ -1220,6 +1268,27 @@ command_loop_1 ()
        }
     }
 }
+
+/* If we get an error while running the hook, cause the hook variable
+   to be nil.  Also inhibit quits, so that C-g won't cause the hook
+   to mysteriously evaporate.  */
+static void
+safe_run_hooks (hook)
+     Lisp_Object hook;
+{
+  Lisp_Object value;
+  int count = specpdl_ptr - specpdl;
+  specbind (Qinhibit_quit, Qt);
+
+  /* We read and set the variable with functions,
+     in case it's buffer-local.  */
+  value = Vcommand_hook_internal = Fsymbol_value (hook);
+  Fset (hook, Qnil);
+  call1 (Vrun_hooks, Qcommand_hook_internal);
+  Fset (hook, value);
+
+  unbind_to (count, Qnil);
+}
 \f
 /* Number of seconds between polling for input.  */
 int polling_period;
@@ -1227,9 +1296,11 @@ int polling_period;
 /* Nonzero means polling for input is temporarily suppressed.  */
 int poll_suppress_count;
 
-#ifdef POLL_FOR_INPUT
+/* Nonzero if polling_for_input is actually being used.  */
 int polling_for_input;
 
+#ifdef POLL_FOR_INPUT
+
 /* Handle an alarm once each second and read pending input
    so as to handle a C-g if it comces in.  */
 
@@ -1264,6 +1335,18 @@ start_polling ()
 #endif
 }
 
+/* Nonzero if we are using polling to handle input asynchronously.  */
+
+int
+input_polling_used ()
+{
+#ifdef POLL_FOR_INPUT
+  return read_socket_hook && !interrupt_input;
+#else
+  return 0;
+#endif
+}
+
 /* Turn off polling.  */
 
 stop_polling ()
@@ -1301,6 +1384,25 @@ set_poll_suppress_count (count)
   poll_suppress_count = count;
 #endif
 }
+
+/* Bind polling_period to a value at least N.
+   But don't decrease it.  */
+
+bind_polling_period (n)
+     int n;
+{
+#ifdef POLL_FOR_INPUT
+  int new = polling_period;
+
+  if (n > new)
+    new = n;
+
+  stop_polling ();
+  specbind (Qpolling_period, make_number (new));
+  /* Start a new alarm with the new period.  */
+  start_polling ();
+#endif
+}
 \f
 /* Applying the control modifier to CHARACTER.  */
 int
@@ -1375,10 +1477,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   int count;
   jmp_buf save_jump;
 
-  if (CONSP (unread_command_events))
+  if (CONSP (Vunread_command_events))
     {
-      c = XCONS (unread_command_events)->car;
-      unread_command_events = XCONS (unread_command_events)->cdr;
+      c = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
 
       if (this_command_key_count == 0)
        goto reread_first;
@@ -1443,7 +1545,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto reread_first;
     }
 
-  if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+  /* Don't bother updating menu bars while doing mouse tracking.
+     We get events very rapidly then, and the menu bar won't be changing.
+     We do update the menu bar once on entry to Ftrack_mouse.  */
+  if (commandflag > 0 && !input_pending && !detect_input_pending ())
     prepare_menu_bars ();
 
   /* Save outer setjmp data, in case called recursively.  */
@@ -1482,11 +1587,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      menu prompting. If EVENT_HAS_PARAMETERS then we are reading
      after a mouse event so don't try a minibuf menu. */
   c = Qnil;
-  if (nmaps > 0 && INTERACTIVE && 
-      !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event))
+  if (nmaps > 0 && INTERACTIVE
+      && !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event)
+      /* Don't bring up a menu if we already have another event.  */
+      && NILP (Vunread_command_events)
+      && unread_command_char < 0
+      && !detect_input_pending ())
     {
       c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
-      if ( ! NILP(c) ) return c ;
+      if (! NILP (c))
+       goto non_reread;
     }
 
   /* If in middle of key sequence and minibuffer not active,
@@ -1525,11 +1635,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Try reading using an X menu.
-     This is never confused with reading using the minibuf because the recursive
-     call of read_char in read_char_minibuf_menu_prompt does not pass on
-     any keys maps */
-  if (nmaps > 0 && INTERACTIVE &&
-      !NILP (prev_event) && EVENT_HAS_PARAMETERS (prev_event))
+     This is never confused with reading using the minibuf
+     because the recursive call of read_char in read_char_minibuf_menu_prompt
+     does not pass on any keymaps.  */
+  if (nmaps > 0 && INTERACTIVE
+      && !NILP (prev_event) && EVENT_HAS_PARAMETERS (prev_event)
+      /* Don't bring up a menu if we already have another event.  */
+      && NILP (Vunread_command_events)
+      && unread_command_char < 0)
     c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
 
   /* Slow down auto saves logarithmically in size of current buffer,
@@ -1586,7 +1699,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (!NILP (c))
        break;
       if (commandflag >= 0 && !input_pending && !detect_input_pending ())
-       redisplay ();
+       {
+         prepare_menu_bars ();
+         redisplay ();
+       }
     }
 
   /* Terminate Emacs in batch mode if at eof.  */
@@ -1613,6 +1729,12 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   start_polling ();
 
+  /* Buffer switch events are only for internal wakeups
+     so don't show them to the user.  */
+  if (XTYPE (c) == Lisp_Buffer)
+    return c;
+
+  /* Wipe the echo area.  */
   echo_area_glyphs = 0;
 
   /* Handle things that only apply to characters.  */
@@ -1638,7 +1760,12 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (dribble)
     {
       if (XTYPE (c) == Lisp_Int)
-       putc (XINT (c), dribble);
+       {
+         if (XUINT (c) < 0x100)
+           putc (XINT (c), dribble);
+         else
+           fprintf (dribble, " 0x%x", XUINT (c));
+       }
       else
        {
          Lisp_Object dribblee;
@@ -1666,14 +1793,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
  from_macro:
  reread_first:
 
-  /* Record this character as part of the current key.
-     Don't record mouse motion; it should never matter.  */
+  /* Don't echo mouse motion events.  */
   if (! (EVENT_HAS_PARAMETERS (c)
         && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
-    {
-      echo_char (c);
-      add_command_key (c);
-    }
+    echo_char (c);
+
+  /* Record this character as part of the current key.  */
+  add_command_key (c);
 
   /* Re-reading in the middle of a command */
  reread:
@@ -1777,6 +1903,9 @@ Normally, mouse motion is ignored.")
   XSET (val, Lisp_Int, do_mouse_tracking);
   record_unwind_protect (tracking_off, val);
 
+  if (!input_pending && !detect_input_pending ())
+    prepare_menu_bars ();
+
   do_mouse_tracking = 1;
   
   val = Fprogn (args);
@@ -2008,6 +2137,12 @@ kbd_buffer_get_event ()
          kbd_fetch_ptr = event + 1;
        }
 #endif
+      else if (event->kind == menu_bar_event)
+       {
+         /* The event value is in the frame_or_window slot.  */
+         obj = event->frame_or_window;
+         kbd_fetch_ptr = event + 1;
+       }
       else if (event->kind == buffer_switch_event)
        {
          /* The value doesn't matter here; only the type is tested.  */
@@ -2088,7 +2223,9 @@ kbd_buffer_get_event ()
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
+#endif
 
+#if defined(MULTI_FRAME) || defined(HAVE_MOUSE)
       /* If we didn't decide to make a switch-frame event, go ahead and 
         return a mouse-motion event.  */
       if (NILP (obj))
@@ -2304,7 +2441,7 @@ static char *lispy_function_keys[] =
     "help",
     "break",                   /* 0xff6b */
 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, "backtab", 0,
     0,                         /* 0xff76 */
     0, 0, 0, 0, 0, 0, 0, 0, "kp-numlock",      /* 0xff7f */
     "kp-space",                        /* 0xff80 */    /* IsKeypadKey */
@@ -2317,8 +2454,19 @@ static char *lispy_function_keys[] =
     "kp-f2",
     "kp-f3",
     "kp-f4",
-    0,         /* 0xff95 */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    "kp-home",                 /* 0xff95 */
+    "kp-left",
+    "kp-up",
+    "kp-right",
+    "kp-down",
+    "kp-prior",                        /* kp-page-up */
+    "kp-next",                 /* kp-page-down */
+    "kp-end",
+    "kp-begin",
+    "kp-insert",
+    "kp-delete",
+    0,                         /* 0xffa0 */
+    0, 0, 0, 0, 0, 0, 0, 0, 0,
     "kp-multiply",             /* 0xffaa */
     "kp-add",
     "kp-separator",
@@ -2464,7 +2612,7 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
-#ifdef MULTI_FRAME
+#if defined(MULTI_FRAME) || defined(HAVE_MOUSE)
       /* A mouse click.  Figure out where it is, decide whether it's 
          a press, click or drag, and build the appropriate structure.  */
     case mouse_click:
@@ -2488,6 +2636,11 @@ make_lispy_event (event)
            Lisp_Object posn;
            int row, column;
 
+           /* Ignore mouse events that were made on frame that
+              have been deleted.  */
+           if (! FRAME_LIVE_P (f))
+             return Qnil;
+
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                                   &column, &row, 0, 0);
 
@@ -2498,6 +2651,14 @@ make_lispy_event (event)
 #endif
              {
                Lisp_Object items, item;
+               int hpos;
+               int i;
+
+               /* Activate the menu bar on the down event.  If the
+                  up event comes in before the menu code can deal with it,
+                  just ignore it.  */
+               if (! (event->modifiers & down_modifier))
+                 return Qnil;
 
 #ifdef USE_X_TOOLKIT
                /* The click happened in the menubar.
@@ -2506,9 +2667,6 @@ make_lispy_event (event)
 
                XFASTINT (event->y) = 1;
 #else /* not USE_X_TOOLKIT  */
-               int hpos;
-               int i;
-
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
                for (i = 0; i < XVECTOR (items)->size; i += 3)
@@ -2540,7 +2698,10 @@ make_lispy_event (event)
            window = window_from_coordinates (f, column, row, &part);
 
            if (XTYPE (window) != Lisp_Window)
-             posn = Qnil;
+             {
+               window = event->frame_or_window;
+               posn = Qnil;
+             }
            else
              {
                int pixcolumn, pixrow;
@@ -2693,7 +2854,7 @@ make_lispy_event (event)
                                 Qnil));
        }
       }
-#endif /* MULTI_FRAME */
+#endif /* MULTI_FRAME or HAVE_MOUSE */
 
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
@@ -2701,7 +2862,7 @@ make_lispy_event (event)
     }
 }
 
-#ifdef MULTI_FRAME
+#if defined(MULTI_FRAME) || defined(HAVE_MOUSE)
 
 static Lisp_Object
 make_lispy_movement (frame, bar_window, part, x, y, time)
@@ -2711,6 +2872,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
      Lisp_Object x, y;
      unsigned long time;
 {
+#ifdef MULTI_FRAME
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
@@ -2729,16 +2891,23 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 
   /* Or is it an ordinary mouse movement?  */
   else
+#endif /* MULTI_FRAME */
     {
       int area;
       Lisp_Object window;
       Lisp_Object posn;
       int column, row;
 
-      pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
-
+#ifdef MULTI_FRAME
       if (frame)
-       window = window_from_coordinates (frame, column, row, &area);
+#else
+      if (1)
+#endif
+       {
+         /* It's in a frame; which window on that frame?  */
+         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
+         window = window_from_coordinates (frame, column, row, &area);
+       }
       else
        window = Qnil;
 
@@ -2759,11 +2928,13 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
            XSET (posn, Lisp_Int,
                  buffer_posn_from_coords (XWINDOW (window), column, row));
        }
+#ifdef MULTI_FRAME
       else if (frame != 0)
        {
          XSET (window, Lisp_Frame, frame);
          posn = Qnil;
        }
+#endif
       else
        {
          window = Qnil;
@@ -2782,7 +2953,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
     }
 }
 
-#endif /* MULTI_FRAME */
+#endif /* neither MULTI_FRAME nor HAVE_MOUSE */
 
 /* Construct a switch frame event.  */
 static Lisp_Object
@@ -3055,7 +3226,7 @@ apply_modifiers (modifiers, base)
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
   XFASTINT (index) = (modifiers & ~click_modifier);
-  entry = Fassq (index, cache);
+  entry = assq_no_quit (index, cache);
 
   if (CONSP (entry))
     new_symbol = XCONS (entry)->cdr;
@@ -3167,7 +3338,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
 
   /* Is this a request for a valid symbol?  */
   if (symbol_num < 0 || symbol_num >= table_size)
-    abort ();
+    return Qnil;
 
   if (CONSP (*symbol_table))
     value = Fcdr (assq_no_quit (symbol_int, *symbol_table));
@@ -3265,12 +3436,46 @@ gobble_input (expected)
 #endif
 }
 
+/* Put a buffer_switch_event in the buffer
+   so that read_key_sequence will notice the new current buffer.  */
+
 record_asynch_buffer_change ()
 {
   struct input_event event;
+  Lisp_Object tem;
+
   event.kind = buffer_switch_event;
   event.frame_or_window = Qnil;
-  kbd_buffer_store_event (&event);
+
+#ifdef subprocesses
+  /* We don't need a buffer-switch event unless Emacs is waiting for input.
+     The purpose of the event is to make read_key_sequence look up the
+     keymaps again.  If we aren't in read_key_sequence, we don't need one,
+     and the event could cause trouble by messing up (input-pending-p).  */
+  tem = Fwaiting_for_user_input_p ();
+  if (NILP (tem))
+    return;
+#else
+  /* We never need these events if we have no asynchronous subprocesses.  */
+  return;
+#endif
+
+  /* Make sure no interrupt happens while storing the event.  */
+#ifdef SIGIO
+  if (interrupt_input)
+    {
+      SIGMASKTYPE mask;
+      mask = sigblockx (SIGIO);
+      kbd_buffer_store_event (&event);
+      sigsetmask (mask);
+    }
+  else
+#endif
+    {
+      stop_polling ();
+      kbd_buffer_store_event (&event);
+      start_polling ();
+    }
 }
 \f
 #ifndef VMS
@@ -3355,16 +3560,25 @@ read_avail_input (expected)
          if (nread == 0)
            kill (0, SIGHUP);
 #endif
-         /* Retry the read if it was interrupted.  */
        }
-      while (nread < 0 && (errno == EINTR
+      while (
+            /* We used to retry the read if it was interrupted.
+               But this does the wrong thing when O_NDELAY causes
+               an EAGAIN error.  Does anybody know of a situation
+               where a retry is actually needed?  */
+#if 0
+            nread < 0 && (errno == EAGAIN
 #ifdef EFAULT
                           || errno == EFAULT
 #endif
 #ifdef EBADSLT
                           || errno == EBADSLT
 #endif
-                          ));
+                          )
+#else
+            0
+#endif
+            );
 
 #ifndef FIONREAD
 #if defined (USG) || defined (DGUX)
@@ -3498,7 +3712,7 @@ static Lisp_Object menu_bar_items_index;
 
 /* Return a vector of menu items for a menu bar, appropriate
    to the current buffer.  Each item has three elements in the vector:
-   KEY STRING nil.
+   KEY STRING MAPLIST.
 
    OLD is an old vector we can optionally reuse, or nil.  */
 
@@ -3636,9 +3850,7 @@ menu_bar_items (old)
 }
 \f
 /* Scan one map KEYMAP, accumulating any menu items it defines
-   that have not yet been seen in RESULT.  Return the updated RESULT.
-   *OLD is the frame's old menu bar list; we swipe elts from that
-   to avoid consing.  */
+   in menu_bar_items_vector.  */
 
 static void
 menu_bar_one_keymap (keymap)
@@ -3661,7 +3873,7 @@ menu_bar_one_keymap (keymap)
                menu_bar_item (key, item_string, Fcdr (binding));
            }
          else if (EQ (binding, Qundefined))
-           menu_bar_item (key, item_string, binding);
+           menu_bar_item (key, Qnil, binding);
        }
       else if (XTYPE (item) == Lisp_Vector)
        {
@@ -3680,7 +3892,7 @@ menu_bar_one_keymap (keymap)
                    menu_bar_item (key, item_string, Fcdr (binding));
                }
              else if (EQ (binding, Qundefined))
-               menu_bar_item (key, item_string, binding);
+               menu_bar_item (key, Qnil, binding);
            }
        }
     }
@@ -3695,6 +3907,9 @@ menu_bar_item_1 (arg)
   return Qnil;
 }
 
+/* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
+   If there's already an item for KEY, add this DEF to it.  */
+
 static void
 menu_bar_item (key, item_string, def)
      Lisp_Object key, item_string, def;
@@ -3705,7 +3920,7 @@ menu_bar_item (key, item_string, def)
 
   if (EQ (def, Qundefined))
     {
-      /* If a map has an explicit nil as definition,
+      /* If a map has an explicit `undefined' as definition,
         discard any previously made menu bar item.  */
 
       for (i = 0; i < menu_bar_items_index; i += 3)
@@ -3718,6 +3933,10 @@ menu_bar_item (key, item_string, def)
            menu_bar_items_index -= 3;
            return;
          }
+
+      /* If there's no definition for this key yet,
+        just ignore `undefined'.  */
+      return;
     }
 
   /* See if this entry is enabled.  */
@@ -3739,12 +3958,12 @@ menu_bar_item (key, item_string, def)
   if (NILP (enabled))
     return;
 
-  /* If there's already such an item, don't make another.  */
+  /* Find any existing item for this KEY.  */
   for (i = 0; i < menu_bar_items_index; i += 3)
     if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
       break;
 
-  /* If we did not find this item, add it at the end.  */
+  /* If we did not find this KEY, add it at the end.  */
   if (i == menu_bar_items_index)
     {
       /* If vector is too small, get a bigger one.  */
@@ -3760,9 +3979,16 @@ menu_bar_item (key, item_string, def)
       /* Add this item.  */
       XVECTOR (menu_bar_items_vector)->contents[i++] = key;
       XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
-      XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
       menu_bar_items_index = i;
     }
+  /* We did find an item for this KEY.  Add DEF to its list of maps.  */
+  else
+    {
+      Lisp_Object old;
+      old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (def, old);
+    }
 }
 \f
 /* Read a character using menus based on maps in the array MAPS.
@@ -3839,8 +4065,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
          /* If we got more than one event, put all but the first
             onto this list to be read later.
             Return just the first event now.  */
-         unread_command_events
-           = nconc2 (XCONS (value)->cdr, unread_command_events);
+         Vunread_command_events
+           = nconc2 (XCONS (value)->cdr, Vunread_command_events);
          value = XCONS (value)->car;
        }
       else if (NILP (value))
@@ -3855,7 +4081,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
 }
 
 static Lisp_Object
-read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
+read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
      int commandflag ;
      int nmaps;
      Lisp_Object *maps;
@@ -3866,7 +4092,7 @@ read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
   int width = FRAME_WIDTH (selected_frame) - 4;
   char *menu = (char *) alloca (width + 4);
   int idx = -1;
-  int nobindings ;
+  int nobindings = 1;
   Lisp_Object rest, vector;
 
   if (! menu_prompting)
@@ -4033,23 +4259,16 @@ read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
    CURRENT with non-prefix bindings for meta-prefix-char become nil in
    NEXT.
 
-   When KEY is not defined in any of the keymaps, if it is an upper
-   case letter and there are bindings for the corresponding lower-case
-   letter, return the bindings for the lower-case letter.
-   We store 1 in *CASE_CONVERTED in this case.
-   Otherwise, we don't change *CASE_CONVERTED.
-
    If KEY has no bindings in any of the CURRENT maps, NEXT is left
    unmodified.
 
    NEXT may == CURRENT.  */
 
 static int
-follow_key (key, nmaps, current, defs, next, case_converted)
+follow_key (key, nmaps, current, defs, next)
      Lisp_Object key;
      Lisp_Object *current, *defs, *next;
      int nmaps;
-     int *case_converted;
 {
   int i, first_binding;
 
@@ -4088,38 +4307,6 @@ follow_key (key, nmaps, current, defs, next, case_converted)
        defs[i] = Qnil;
     }
 
-  /* When KEY is not defined in any of the keymaps, if it is an upper
-     case letter and there are bindings for the corresponding
-     lower-case letter, return the bindings for the lower-case letter.  */
-  if (first_binding == nmaps
-      && XTYPE (key) == Lisp_Int
-      && ((((XINT (key) & 0x3ffff)
-           < XSTRING (current_buffer->downcase_table)->size)
-          && UPPERCASEP (XINT (key) & 0x3ffff))
-         || (XINT (key) & shift_modifier)))
-    {
-      if (XINT (key) & shift_modifier)
-       XSETINT (key, XINT (key) & ~shift_modifier);
-      else
-       XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
-                      | (XINT (key) & ~0x3ffff)));
-
-      first_binding = nmaps;
-      for (i = nmaps - 1; i >= 0; i--)
-       {
-         if (! NILP (current[i]))
-           {
-             defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
-             if (! NILP (defs[i]))
-               first_binding = i;
-           }
-         else
-           defs[i] = Qnil;
-       }
-      if (first_binding  != nmaps)
-       *case_converted = 1;
-    }
-
   /* Given the set of bindings we've found, produce the next set of maps.  */
   if (first_binding < nmaps)
     for (i = 0; i < nmaps; i++)
@@ -4237,10 +4424,6 @@ read_key_sequence (keybuf, bufsize, prompt)
 
   struct buffer *starting_buffer;
 
-  /* Nonzero if we found the binding for one of the chars
-     in this key sequence by downcasing it.  */
-  int case_converted = 0;
-
   /* Nonzero if we seem to have got the beginning of a binding
      in function_key_map.  */
   int function_key_possible = 0;
@@ -4265,7 +4448,7 @@ read_key_sequence (keybuf, bufsize, prompt)
     {
       if (!NILP (prompt))
        echo_prompt (XSTRING (prompt)->data);
-      else if (cursor_in_echo_area)
+      else if (cursor_in_echo_area && echo_keystrokes)
        /* This doesn't put in a dash if the echo buffer is empty, so
           you don't always see a dash hanging out in the minibuffer.  */
        echo_dash ();
@@ -4294,7 +4477,6 @@ read_key_sequence (keybuf, bufsize, prompt)
  replay_sequence:
 
   starting_buffer = current_buffer;
-  case_converted = 0;
   function_key_possible = 0;
 
   /* Build our list of keymaps.
@@ -4366,7 +4548,7 @@ read_key_sequence (keybuf, bufsize, prompt)
            Thus, if ESC O a has a function-key-map translation
            and ESC o has a binding, don't return after ESC O,
            so that we can translate ESC O plus the next character.  */
-        || (function_key_possible && case_converted))
+        )
     {
       Lisp_Object key;
       int used_mouse_menu = 0;
@@ -4410,7 +4592,8 @@ read_key_sequence (keybuf, bufsize, prompt)
        {
          key = keybuf[t];
          add_command_key (key);
-         echo_char (key);
+         if (echo_keystrokes)
+           echo_char (key);
        }
 
       /* If not, we should actually read a character.  */
@@ -4547,7 +4730,9 @@ read_key_sequence (keybuf, bufsize, prompt)
                  goto replay_key;
                }
            }
-         else
+         else if (CONSP (XCONS (key)->cdr)
+                  && CONSP (EVENT_START (key))
+                  && CONSP (XCONS (EVENT_START (key))->cdr))
            {
              Lisp_Object posn;
 
@@ -4593,8 +4778,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                                   nmaps   - first_binding,
                                   submaps + first_binding,
                                   defs    + first_binding,
-                                  submaps + first_binding,
-                                  &case_converted)
+                                  submaps + first_binding)
                       + first_binding);
 
       /* If KEY wasn't bound, we'll try some fallbacks.  */
@@ -4696,8 +4880,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                                       nmaps   - local_first_binding,
                                       submaps + local_first_binding,
                                       defs    + local_first_binding,
-                                      submaps + local_first_binding,
-                                      &case_converted)
+                                      submaps + local_first_binding)
                           + local_first_binding);
 
                      /* If that click is bound, go for it.  */
@@ -4724,7 +4907,7 @@ read_key_sequence (keybuf, bufsize, prompt)
         off the end of it.  We only want to scan real keyboard input
         for function key sequences, so if mock_input says that we're
         re-reading old events, don't examine it.  */
-      if ((first_binding >= nmaps || case_converted)
+      if (first_binding >= nmaps
          && t >= mock_input)
        {
          Lisp_Object fkey_next;
@@ -4754,6 +4937,14 @@ read_key_sequence (keybuf, bufsize, prompt)
              fkey_next
                = get_keyelt (access_keymap (fkey_next, key, 1, 0));
 
+#if 0 /* I didn't turn this on, because it might cause trouble
+        for the mapping of return into C-m and tab into C-i.  */
+             /* Optionally don't map function keys into other things.
+                This enables the user to redefine kp- keys easily.  */
+             if (SYMBOLP (key) && !NILP (Vinhibit_function_key_mapping))
+               fkey_next = Qnil;
+#endif
+
              /* If the function key map gives a function, not an
                 array, then call the function with no args and use
                 its value instead.  */
@@ -4915,6 +5106,28 @@ read_key_sequence (keybuf, bufsize, prompt)
              }
          }
       }
+
+      /* If KEY is not defined in any of the keymaps,
+        and cannot be part of a function key or translation,
+        and is an upper case letter
+        use the corresponding lower-case letter instead.  */
+      if (first_binding == nmaps && ! function_key_possible
+         && XTYPE (key) == Lisp_Int
+         && ((((XINT (key) & 0x3ffff)
+               < XSTRING (current_buffer->downcase_table)->size)
+              && UPPERCASEP (XINT (key) & 0x3ffff))
+             || (XINT (key) & shift_modifier)))
+       {
+         if (XINT (key) & shift_modifier)
+           XSETINT (key, XINT (key) & ~shift_modifier);
+         else
+           XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
+                          | (XINT (key) & ~0x3ffff)));
+
+         keybuf[t - 1] = key;
+         mock_input = t;
+         goto replay_sequence;
+       }
     }
 
   read_key_sequence_cmd = (first_binding < nmaps
@@ -4936,7 +5149,8 @@ read_key_sequence (keybuf, bufsize, prompt)
      Better ideas?  */
   for (; t < mock_input; t++)
     {
-      echo_char (keybuf[t]);
+      if (echo_keystrokes)
+       echo_char (keybuf[t]);
       add_command_key (keybuf[t]);
     }
 
@@ -5174,7 +5388,7 @@ DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
 Actually, the value is nil only if we can be sure that no input is available.")
   ()
 {
-  if (!NILP (unread_command_events) || unread_command_char != -1)
+  if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
   return detect_input_pending () ? Qt : Qnil;
@@ -5248,7 +5462,7 @@ Also cancel any kbd macro being defined.")
   defining_kbd_macro = 0;
   update_mode_lines++;
 
-  unread_command_events = Qnil;
+  Vunread_command_events = Qnil;
   unread_command_char = -1;
 
   discard_tty_input ();
@@ -5402,10 +5616,13 @@ interrupt_signal ()
   int old_errno = errno;
 
 #ifdef USG
-  /* USG systems forget handlers when they are used;
-     must reestablish each time */
-  signal (SIGINT, interrupt_signal);
-  signal (SIGQUIT, interrupt_signal);
+  if (!read_socket_hook && NILP (Vwindow_system))
+    {
+      /* USG systems forget handlers when they are used;
+        must reestablish each time */
+      signal (SIGINT, interrupt_signal);
+      signal (SIGQUIT, interrupt_signal);
+    }
 #endif /* USG */
 
   cancel_echoing ();
@@ -5509,7 +5726,7 @@ quit_throw_to_read_char ()
   clear_waiting_for_input ();
   input_pending = 0;
 
-  unread_command_events = Qnil;
+  Vunread_command_events = Qnil;
   unread_command_char = -1;
 
 #ifdef POLL_FOR_INPUT
@@ -5618,7 +5835,7 @@ init_keyboard ()
   command_loop_level = -1;
   immediate_quit = 0;
   quit_char = Ctl ('g');
-  unread_command_events = Qnil;
+  Vunread_command_events = Qnil;
   unread_command_char = -1;
   total_keys = 0;
   recent_keys_index = 0;
@@ -5643,7 +5860,7 @@ init_keyboard ()
   if (initialized)
     Ffillarray (kbd_buffer_frame_or_window, Qnil);
 
-  if (!noninteractive)
+  if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
     {
       signal (SIGINT, interrupt_signal);
 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
@@ -5651,11 +5868,12 @@ init_keyboard ()
         SIGQUIT and we can't tell which one it will give us.  */
       signal (SIGQUIT, interrupt_signal);
 #endif /* HAVE_TERMIO */
+    }
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 #ifdef SIGIO
-      signal (SIGIO, input_available_signal);
+  if (!noninteractive)
+    signal (SIGIO, input_available_signal);
 #endif /* SIGIO */
-    }
 
 /* Use interrupt input by default, if it works and noninterrupt input
    has deficiencies.  */
@@ -5764,6 +5982,9 @@ syms_of_keyboard ()
   Qactivate_menubar_hook = intern ("activate-menubar-hook");
   staticpro (&Qactivate_menubar_hook);
 
+  Qpolling_period = intern ("polling-period");
+  staticpro (&Qpolling_period);
+
   {
     struct event_head *p;
 
@@ -5806,6 +6027,9 @@ syms_of_keyboard ()
     = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
   staticpro (&kbd_buffer_frame_or_window);
 
+  accent_key_syms = Qnil;
+  staticpro (&accent_key_syms);
+
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
@@ -5839,7 +6063,7 @@ syms_of_keyboard ()
   DEFVAR_LISP ("last-command-char", &last_command_char,
     "Last input event that was part of a command.");
 
-  DEFVAR_LISP ("last-command-event", &last_command_char,
+  DEFVAR_LISP_NOPRO ("last-command-event", &last_command_char,
     "Last input event that was part of a command.");
 
   DEFVAR_LISP ("last-nonmenu-event", &last_nonmenu_event,
@@ -5851,10 +6075,10 @@ so that you can determine whether the command was run by mouse or not.");
   DEFVAR_LISP ("last-input-char", &last_input_char,
     "Last input event.");
 
-  DEFVAR_LISP ("last-input-event", &last_input_char,
+  DEFVAR_LISP_NOPRO ("last-input-event", &last_input_char,
     "Last input event.");
 
-  DEFVAR_LISP ("unread-command-events", &unread_command_events,
+  DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
     "List of objects to be read as next command input events.");
 
   DEFVAR_INT ("unread-command-char", &unread_command_char,
@@ -5911,12 +6135,10 @@ by position only.");
     "*Number of complete keys read from the keyboard so far.");
   num_input_keys = 0;
 
-#ifdef MULTI_FRAME
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
     "*The frame in which the most recently read event occurred.\n\
 If the last event came from a keyboard macro, this is set to `macro'.");
   Vlast_event_frame = Qnil;
-#endif
 
   DEFVAR_LISP ("help-char", &Vhelp_char,
     "Character to recognize as meaning Help.\n\
@@ -5998,11 +6220,21 @@ Buffer modification stores t in this variable.");
   Vcommand_hook_internal = Qnil;
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
-    "Normal hook run before each command is executed.");
+    "Normal hook run before each command is executed.\n\
+While the hook is run, its value is temporarily set to nil\n\
+to avoid an unbreakable infinite loop if a hook function gets an error.\n\
+As a result, a hook function cannot straightforwardly alter the value of\n\
+`pre-command-hook'.  See the Emacs Lisp manual for a way of\n\
+implementing hook functions that alter the set of hook functions.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
-    "Normal hook run after each command is executed.");
+    "Normal hook run after each command is executed.\n\
+While the hook is run, its value is temporarily set to nil\n\
+to avoid an unbreakable infinite loop if a hook function gets an error.\n\
+As a result, a hook function cannot straightforwardly alter the value of\n\
+`post-command-hook'.  See the Emacs Lisp manual for a way of\n\
+implementing hook functions that alter the set of hook functions.");
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
@@ -6028,7 +6260,18 @@ buffer's local map, and the minor mode keymaps and text property keymaps.");
 Each element should have the form (N . SYMBOL) where N is the\n\
 numeric keysym code (sans the \"system-specific\" bit 1<<28)\n\
 and SYMBOL is its name.");
-  Vmenu_bar_final_items = Qnil;
+  Vsystem_key_alist = Qnil;
+
+  DEFVAR_LISP ("deferred-action-list", &Vdeferred_action_list,
+    "List of deferred actions to be performed at a later time.\n\
+The precise format isn't relevant here; we just check whether it is nil.");
+  Vdeferred_action_list = Qnil;
+
+  DEFVAR_LISP ("deferred-action-function", &Vdeferred_action_function,
+    "Function to call to handle deferred actions, after each command.\n\
+This function is called with no arguments after each command\n\
+whenever `deferred-action-list' is non-nil.");
+  Vdeferred_action_function = Qnil;
 }
 
 keys_of_keyboard ()