(FRAMEP): Use the second definition whenever HAVE_MOUSE.
[bpt/emacs.git] / src / keyboard.c
index 9e06898..80801cb 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;
@@ -65,9 +72,10 @@ int interrupt_input_blocked;
 int interrupt_input_pending;
 
 
-#ifdef HAVE_X_WINDOWS
-extern Lisp_Object Vmouse_grabbed;
+/* File descriptor to use for input.  */
+extern int input_fd;
 
+#ifdef HAVE_X_WINDOWS
 /* Make all keyboard buffers much bigger when using X windows.  */
 #define KBD_BUFFER_SIZE 4096
 #else  /* No X-windows, character input */
@@ -123,6 +131,9 @@ int waiting_for_input;
 /* True while displaying for echoing.   Delays C-g throwing.  */
 static int echoing;
 
+/* Nonzero means disregard local maps for the menu bar.  */
+static int inhibit_local_menu_bar_menus;
+
 /* Nonzero means C-g should cause immediate error-signal.  */
 int immediate_quit;
 
@@ -162,6 +173,9 @@ extern int minibuf_level;
 /* If non-nil, this is a map that overrides all other local maps.  */
 Lisp_Object Voverriding_local_map;
 
+/* If non-nil, Voverriding_local_map applies to the menu bar.  */
+Lisp_Object Voverriding_local_map_menu_flag;
+
 /* Current depth in recursive edits.  */
 int command_loop_level;
 
@@ -179,7 +193,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;
@@ -232,6 +246,12 @@ Lisp_Object last_command;
    instead of the actual command.  */
 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
@@ -239,12 +259,12 @@ Lisp_Object this_command;
    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.  */
@@ -284,6 +304,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;
 
@@ -337,10 +364,7 @@ static struct input_event *kbd_fetch_ptr;
 /* Pointer to next place to store character in kbd_buffer.  This
    may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
    character should go in kbd_buffer[0].  */
-#ifdef __STDC__
-volatile
-#endif
-static struct input_event *kbd_store_ptr;
+static volatile struct input_event *kbd_store_ptr;
 
 /* The above pair of variables forms a "queue empty" flag.  When we
    enqueue a non-hook event, we increment kbd_write_count.  When we
@@ -351,10 +375,11 @@ static struct input_event *kbd_store_ptr;
    dequeuing functions?  Such a flag could be screwed up by interrupts
    at inopportune times.  */
 
-/* If this flag is non-zero, we check mouse_moved to see when the
-   mouse moves, and motion events will appear in the input stream.  If
-   it is zero, mouse motion is ignored.  */
-static int do_mouse_tracking;
+#ifdef HAVE_MOUSE
+/* If this flag is a frame, we check mouse_moved to see when the
+   mouse moves, and motion events will appear in the input stream.
+   Otherwise, mouse motion is ignored.  */
+static Lisp_Object do_mouse_tracking;
 
 /* The window system handling code should set this if the mouse has
    moved since the last call to the mouse_position_hook.  Calling that
@@ -369,13 +394,20 @@ int mouse_moved;
    is readable input; all the events in the queue might be button-up
    events, and do_mouse_tracking might be off.  */
 #define EVENT_QUEUES_EMPTY \
-  ((kbd_fetch_ptr == kbd_store_ptr) && (!do_mouse_tracking || !mouse_moved))
+  ((kbd_fetch_ptr == kbd_store_ptr) \
+   && (! FRAMEP (do_mouse_tracking) || !mouse_moved))
 
+#else /* Not HAVE_MOUSE.  */
+#define EVENT_QUEUES_EMPTY (kbd_fetch_ptr == kbd_store_ptr)
+#endif /* HAVE_MOUSE.  */
 
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
 Lisp_Object Qscroll_bar_movement;
 Lisp_Object Qswitch_frame;
+Lisp_Object Qdelete_frame;
+Lisp_Object Qiconify_frame;
+Lisp_Object Qmake_frame_visible;
 
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
@@ -413,6 +445,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;
@@ -474,6 +508,14 @@ 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;
+
 #define        min(a,b)        ((a)<(b)?(a):(b))
 #define        max(a,b)        ((a)>(b)?(a):(b))
 
@@ -485,12 +527,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 ();
 }
 
@@ -513,14 +558,14 @@ echo_char (c)
       /* If someone has passed us a composite event, use its head symbol.  */
       c = EVENT_HEAD (c);
 
-      if (XTYPE (c) == Lisp_Int)
+      if (INTEGERP (c))
        {
          if (ptr - echobuf > sizeof echobuf - 6)
            return;
 
          ptr = push_key_description (XINT (c), ptr);
        }
-      else if (XTYPE (c) == Lisp_Symbol)
+      else if (SYMBOLP (c))
        {
          struct Lisp_String *name = XSYMBOL (c)->name;
          if (((ptr - echobuf) + name->size + 4) > sizeof echobuf)
@@ -549,6 +594,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;
@@ -572,7 +620,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 ();
     }
 
@@ -590,6 +644,7 @@ cancel_echoing ()
 {
   immediate_echo = 0;
   echoptr = echobuf;
+  echo_after_prompt = -1;
 }
 
 /* Return the length of the current echo string.  */
@@ -623,8 +678,9 @@ add_command_key (key)
 
   if (this_command_key_count >= size)
     {
-      Lisp_Object new_keys = Fmake_vector (make_number (size * 2), Qnil);
+      Lisp_Object new_keys;
 
+      new_keys = Fmake_vector (make_number (size * 2), Qnil);
       bcopy (XVECTOR (this_command_keys)->contents,
             XVECTOR (new_keys)->contents,
             size * sizeof (Lisp_Object));
@@ -655,10 +711,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\
@@ -698,6 +764,22 @@ recursive_edit_unwind (buffer)
 Lisp_Object
 cmd_error (data)
      Lisp_Object data;
+{
+  Vstandard_output = Qt;
+  Vstandard_input = Qt;
+  Vexecuting_macro = Qnil;
+  cmd_error_internal (data, 0);
+
+  Vquit_flag = Qnil;
+
+  Vinhibit_quit = Qnil;
+
+  return make_number (0);
+}
+
+cmd_error_internal (data, context)
+     Lisp_Object data;
+     char *context;
 {
   Lisp_Object errmsg, tail, errname, file_error;
   Lisp_Object stream;
@@ -706,9 +788,6 @@ cmd_error (data)
 
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
-  Vstandard_output = Qt;
-  Vstandard_input = Qt;
-  Vexecuting_macro = Qnil;
   echo_area_glyphs = 0;
 
   /* If the window system or terminal frame hasn't been initialized
@@ -724,6 +803,9 @@ cmd_error (data)
       stream = Qt;
     }
 
+  if (context != 0)
+    write_string_1 (context, -1, stream);
+
   errname = Fcar (data);
 
   if (EQ (errname, Qerror))
@@ -753,7 +835,7 @@ cmd_error (data)
   if (!NILP (file_error) && !NILP (tail))
     errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
 
-  if (XTYPE (errmsg) == Lisp_String)
+  if (STRINGP (errmsg))
     Fprinc (errmsg, stream);
   else
     write_string_1 ("peculiar error", -1, stream);
@@ -776,11 +858,6 @@ cmd_error (data)
       Fterpri (stream);
       Fkill_emacs (make_number (-1));
     }
-
-  Vquit_flag = Qnil;
-
-  Vinhibit_quit = Qnil;
-  return make_number (0);
 }
 \f
 Lisp_Object command_loop_1 ();
@@ -879,6 +956,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 ()
@@ -898,27 +976,22 @@ command_loop_1 ()
   waiting_for_input = 0;
   cancel_echoing ();
 
-  /* Don't clear out last_command at the beginning of a macro.  */
-  if (XTYPE (Vexecuting_macro) != Lisp_String)
-    last_command = Qt;
-
   nonundocount = 0;
   no_redisplay = 0;
   this_command_key_count = 0;
 
   /* Make sure this hook runs after commands that get errors and
      throw to top level.  */
-  if (!NILP (Vpost_command_hook))
-    {
-      /* 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;
 
   while (1)
     {
@@ -958,7 +1031,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);
            }
        }
 
@@ -973,7 +1046,7 @@ command_loop_1 ()
         switch-frame events will take care of this, but if some lisp
         code swallows a switch-frame event, we'll fix things up here.
         Is this a good idea?  */
-      if (XTYPE (internal_last_event_frame) == Lisp_Frame
+      if (FRAMEP (internal_last_event_frame)
          && XFRAME (internal_last_event_frame) != selected_frame)
        Fselect_frame (internal_last_event_frame, Qnil);
 #endif
@@ -984,35 +1057,6 @@ command_loop_1 ()
          && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
        call0 (Qrecompute_lucid_menubar);
 
-#if 0 /* This is done in xdisp.c now.  */
-#ifdef MULTI_FRAME
-      for (tem = Vframe_list; CONSP (tem); tem = XCONS (tem)->cdr)
-       {
-         struct frame *f = XFRAME (XCONS (tem)->car);
-         struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-
-         /* If the user has switched buffers or windows, we need to
-            recompute to reflect the new bindings.  But we'll
-            recompute when update_mode_lines is set too; that means
-            that people can use force-mode-line-update to request
-            that the menu bar be recomputed.  The adverse effect on
-            the rest of the redisplay algorithm is about the same as
-            windows_or_buffers_changed anyway.  */
-         if (windows_or_buffers_changed
-             || update_mode_lines
-             || (XFASTINT (w->last_modified) < MODIFF
-                 && (XFASTINT (w->last_modified)
-                     <= XBUFFER (w->buffer)->save_modified)))
-           {
-             struct buffer *prev = current_buffer;
-             current_buffer = XBUFFER (w->buffer);
-             FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
-             current_buffer = prev;
-           }
-       }
-#endif /* MULTI_FRAME */
-#endif /* 0 */
-
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
 
@@ -1059,21 +1103,16 @@ command_loop_1 ()
 
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
+      last_point_position = PT;
+      XSETBUFFER (last_point_position_buffer, prev_buffer);
 
       /* Execute the command.  */
 
       this_command = cmd;
-      if (!NILP (Vpre_command_hook))
-       {
-         /* 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))
        {
@@ -1090,20 +1129,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 ()
@@ -1111,20 +1152,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 ()
@@ -1134,12 +1177,13 @@ command_loop_1 ()
                }
              else if (EQ (this_command, Qself_insert_command)
                       /* Try this optimization only on ascii keystrokes.  */
-                      && XTYPE (last_command_char) == Lisp_Int)
+                      && INTEGERP (last_command_char))
                {
                  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)
                        {
@@ -1148,22 +1192,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));
@@ -1171,14 +1216,24 @@ command_loop_1 ()
 
                      if (dp)
                        {
-                         Lisp_Object 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));
+                         Lisp_Object obj;
+
+                         obj = DISP_CHAR_VECTOR (dp, lose);
+                         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 (VECTORP (obj)
+                                  && XVECTOR (obj)->size == 1
+                                  && (obj = XVECTOR (obj)->contents[0],
+                                      INTEGERP (obj))
+                                  /* Insist face not specified in glyph.  */
+                                  && (XINT (obj) & ((-1) << 8)) == 0)
+                           no_redisplay
+                             = direct_output_for_insert (XINT (obj));
                        }
                      else
                        {
@@ -1200,8 +1255,13 @@ command_loop_1 ()
        }
     directly_done: ;
 
-      if (!NILP (Vpost_command_hook))
-       call1 (Vrun_hooks, Qpost_command_hook);
+      /* 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);
+
+      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''
@@ -1219,7 +1279,7 @@ command_loop_1 ()
          this_command_key_count = 0;
        }
 
-      if (!NILP (current_buffer->mark_active))
+      if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
            {
@@ -1231,6 +1291,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;
@@ -1238,9 +1319,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.  */
 
@@ -1275,6 +1358,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 ()
@@ -1312,6 +1407,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
@@ -1356,6 +1470,7 @@ make_ctrl_char (c)
 
 Lisp_Object print_help ();
 static Lisp_Object kbd_buffer_get_event ();
+static void record_char ();
 
 /* read a character from the keyboard; call the redisplay if needed */
 /* commandflag 0 means do not do auto-saving, but do do redisplay.
@@ -1385,11 +1500,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   register Lisp_Object c;
   int count;
   jmp_buf save_jump;
+  int key_already_recorded = 0;
+  Lisp_Object also_record;
+  also_record = Qnil;
 
-  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;
@@ -1399,7 +1517,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (unread_command_char != -1)
     {
-      XSET (c, Lisp_Int, unread_command_char);
+      XSETINT (c, unread_command_char);
       unread_command_char = -1;
 
       if (this_command_key_count == 0)
@@ -1430,14 +1548,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (EQ (Vexecuting_macro, Qt)
          || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
        {
-         XSET (c, Lisp_Int, -1);
+         XSETINT (c, -1);
          return c;
        }
       
       c = Faref (Vexecuting_macro, make_number (executing_macro_index));
-      if (XTYPE (Vexecuting_macro) == Lisp_String
+      if (STRINGP (Vexecuting_macro)
          && (XINT (c) & 0x80))
-       XFASTINT (c) = CHAR_META | (XINT (c) & ~0x80);
+       XSETFASTINT (c, CHAR_META | (XINT (c) & ~0x80));
 
       executing_macro_index++;
 
@@ -1454,7 +1572,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.  */
@@ -1467,9 +1588,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (_setjmp (getcjmp))
     {
-      XSET (c, Lisp_Int, quit_char);
+      XSETINT (c, quit_char);
 #ifdef MULTI_FRAME
-      XSET (internal_last_event_frame, Lisp_Frame, selected_frame);
+      XSETFRAME (internal_last_event_frame, selected_frame);
       Vlast_event_frame = internal_last_event_frame;
 #endif
       /* If we report the quit char as an event,
@@ -1493,11 +1614,19 @@ 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))
+       {
+         key_already_recorded = 1;
+         goto non_reread;
+       }
     }
 
   /* If in middle of key sequence and minibuffer not active,
@@ -1536,11 +1665,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,
@@ -1562,7 +1694,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Auto save if enough time goes by without input.  */
       if (commandflag != 0
          && num_nonmacro_input_chars > last_auto_save
-         && XTYPE (Vauto_save_timeout) == Lisp_Int
+         && INTEGERP (Vauto_save_timeout)
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
@@ -1597,14 +1729,17 @@ 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.  */
-  if (noninteractive && XTYPE (c) == Lisp_Int && XINT (c) < 0)
+  if (noninteractive && INTEGERP (c) && XINT (c) < 0)
     Fkill_emacs (make_number (1));
 
-  if (XTYPE (c) == Lisp_Int)
+  if (INTEGERP (c))
     {
       /* Add in any extra modifiers, where appropriate.  */
       if ((extra_keyboard_modifiers & CHAR_CTL)
@@ -1624,68 +1759,74 @@ 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 (BUFFERP (c))
+    return c;
+
+  if (key_already_recorded)
+    return c;
+
+  /* Wipe the echo area.  */
   echo_area_glyphs = 0;
 
   /* Handle things that only apply to characters.  */
-  if (XTYPE (c) == Lisp_Int)
+  if (INTEGERP (c))
     {
       /* If kbd_buffer_get_event gave us an EOF, return that.  */
       if (XINT (c) == -1)
        return c;
 
-      if (XTYPE (Vkeyboard_translate_table) == Lisp_String
+      if (STRINGP (Vkeyboard_translate_table)
          && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
        XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
     }
 
-  total_keys++;
-  XVECTOR (recent_keys)->contents[recent_keys_index] = c;
-  if (++recent_keys_index >= NUM_RECENT_KEYS)
-    recent_keys_index = 0;
-
-  /* Write c to the dribble file.  If c is a lispy event, write
-     the event's symbol to the dribble file, in <brackets>.  Bleaugh.
-     If you, dear reader, have a better idea, you've got the source.  :-) */
-  if (dribble)
+  /* If this event is a mouse click in the menu bar,
+     return just menu-bar for now.  Modify the mouse click event
+     so we won't do this twice, then queue it up.  */
+  if (EVENT_HAS_PARAMETERS (c)
+      && CONSP (XCONS (c)->cdr)
+      && CONSP (EVENT_START (c))
+      && CONSP (XCONS (EVENT_START (c))->cdr))
     {
-      if (XTYPE (c) == Lisp_Int)
-       putc (XINT (c), dribble);
-      else
-       {
-         Lisp_Object dribblee = c;
+      Lisp_Object posn;
 
-         /* If it's a structured event, take the event header.  */
-         dribblee = EVENT_HEAD (dribblee);
+      posn = POSN_BUFFER_POSN (EVENT_START (c));
+      /* Handle menu-bar events:
+        insert the dummy prefix event `menu-bar'.  */
+      if (EQ (posn, Qmenu_bar))
+       {
+         /* Change menu-bar to (menu-bar) as the event "position".  */
+         POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
 
-         if (XTYPE (dribblee) == Lisp_Symbol)
-           {
-             putc ('<', dribble);
-             fwrite (XSYMBOL (dribblee)->name->data, sizeof (char),
-                     XSYMBOL (dribblee)->name->size,
-                     dribble);
-             putc ('>', dribble);
-           }
+         also_record = c;
+         Vunread_command_events = Fcons (c, Vunread_command_events);
+         c = posn;
        }
-
-      fflush (dribble);
     }
 
-  store_kbd_macro_char (c);
-
-  num_nonmacro_input_chars++;
+  record_char (c);
+  if (! NILP (also_record))
+    record_char (also_record);
 
  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);
+      if (! NILP (also_record))
+       echo_char (also_record);
     }
 
+  /* Record this character as part of the current key.  */
+  add_command_key (c);
+  if (! NILP (also_record))
+    add_command_key (also_record);
+
   /* Re-reading in the middle of a command */
  reread:
   last_input_char = c;
@@ -1701,13 +1842,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
                             Fcurrent_window_configuration (Qnil));
 
       tem0 = Feval (Vhelp_form);
-      if (XTYPE (tem0) == Lisp_String)
+      if (STRINGP (tem0))
        internal_with_output_to_temp_buffer ("*Help*", print_help, tem0);
 
       cancel_echoing ();
       do
        c = read_char (0, 0, 0, Qnil, 0);
-      while (XTYPE (c) == Lisp_Buffer);
+      while (BUFFERP (c));
       /* Remove the help from the frame */
       unbind_to (count, Qnil);
       prepare_menu_bars ();
@@ -1717,18 +1858,70 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          cancel_echoing ();
          do
            c = read_char (0, 0, 0, Qnil, 0);
-         while (XTYPE (c) == Lisp_Buffer);
+         while (BUFFERP (c));
        }
     }
 
   return c;
 }
 
+/* Record the input event C in various ways.  */
+
+static void
+record_char (c)
+     Lisp_Object c;
+{
+  total_keys++;
+  XVECTOR (recent_keys)->contents[recent_keys_index] = c;
+  if (++recent_keys_index >= NUM_RECENT_KEYS)
+    recent_keys_index = 0;
+
+  /* Write c to the dribble file.  If c is a lispy event, write
+     the event's symbol to the dribble file, in <brackets>.  Bleaugh.
+     If you, dear reader, have a better idea, you've got the source.  :-) */
+  if (dribble)
+    {
+      if (INTEGERP (c))
+       {
+         if (XUINT (c) < 0x100)
+           putc (XINT (c), dribble);
+         else
+           fprintf (dribble, " 0x%x", XUINT (c));
+       }
+      else
+       {
+         Lisp_Object dribblee;
+
+         /* If it's a structured event, take the event header.  */
+         dribblee = EVENT_HEAD (c);
+
+         if (SYMBOLP (dribblee))
+           {
+             putc ('<', dribble);
+             fwrite (XSYMBOL (dribblee)->name->data, sizeof (char),
+                     XSYMBOL (dribblee)->name->size,
+                     dribble);
+             putc ('>', dribble);
+           }
+       }
+
+      fflush (dribble);
+    }
+
+  store_kbd_macro_char (c);
+
+  num_nonmacro_input_chars++;
+}
+
 Lisp_Object
 print_help (object)
      Lisp_Object object;
 {
+  struct buffer *old = current_buffer;
   Fprinc (object, Qnil);
+  set_buffer_internal (XBUFFER (Vstandard_output));
+  call0 (intern ("help-mode"));
+  set_buffer_internal (old);
   return Qnil;
 }
 
@@ -1750,15 +1943,18 @@ restore_getcjmp (temp)
 }
 
 \f
+#ifdef HAVE_MOUSE
+
 /* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
    of this function.  */
+
 static Lisp_Object
 tracking_off (old_value)
      Lisp_Object old_value;
 {
   if (! XFASTINT (old_value))
     {
-      do_mouse_tracking = 0;
+      do_mouse_tracking = Qnil;
 
       /* Redisplay may have been preempted because there was input
         available, and it assumes it will be called again after the
@@ -1785,14 +1981,18 @@ Normally, mouse motion is ignored.")
   int count = specpdl_ptr - specpdl;
   Lisp_Object val;
 
-  XSET (val, Lisp_Int, do_mouse_tracking);
-  record_unwind_protect (tracking_off, val);
+  record_unwind_protect (tracking_off, do_mouse_tracking);
 
-  do_mouse_tracking = 1;
+  if (!input_pending && !detect_input_pending ())
+    prepare_menu_bars ();
+
+  XSETFRAME (do_mouse_tracking, selected_frame);
   
   val = Fprogn (args);
   return unbind_to (count, val);
 }
+
+#endif /* HAVE_MOUSE */
 \f
 /* Low level keyboard/mouse input.
    kbd_buffer_store_event places events in kbd_buffer, and
@@ -1841,9 +2041,9 @@ kbd_buffer_store_event (event)
             get returned to Emacs as an event, the next event read
             will set Vlast_event_frame again, so this is safe to do.  */
          {
-           Lisp_Object focus
-             = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
+           Lisp_Object focus;
 
+           focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
            if (NILP (focus))
              internal_last_event_frame = event->frame_or_window;
            else
@@ -1914,7 +2114,7 @@ kbd_buffer_get_event ()
   if (noninteractive)
     {
       c = getchar ();
-      XSET (obj, Lisp_Int, c);
+      XSETINT (obj, c);
       return obj;
     }
 
@@ -1943,7 +2143,7 @@ kbd_buffer_get_event ()
        {
          Lisp_Object minus_one;
 
-         XSET (minus_one, Lisp_Int, -1);
+         XSETINT (minus_one, -1);
          wait_reading_process_input (0, 0, minus_one, 1);
 
          if (!interrupt_input && EVENT_QUEUES_EMPTY)
@@ -1997,28 +2197,38 @@ kbd_buffer_get_event ()
 #ifdef HAVE_X11
       else if (event->kind == delete_window_event)
        {
-         Lisp_Object tail, frame;
-         struct frame *f;
-       
-         /* If the user destroys the only frame, Emacs should exit.
-            Count visible frames and iconified frames.  */
-         for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
-           {
-             frame = XCONS (tail)->car;
-             if (XTYPE (frame) != Lisp_Frame || EQ (frame, event->frame_or_window))
-               continue;
-             f = XFRAME (frame);
-             if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
-               break;
-           }
-
-         if (! CONSP (tail))
-           Fkill_emacs (Qnil);
-
-         Fdelete_frame (event->frame_or_window, Qt);
+         /* Make an event (delete-frame (FRAME)).  */
+         obj = Fcons (event->frame_or_window, Qnil);
+         obj = Fcons (Qdelete_frame, Fcons (obj, Qnil));
+         kbd_fetch_ptr = event + 1;
+       }
+      else if (event->kind == iconify_event)
+       {
+         /* Make an event (iconify-frame (FRAME)).  */
+         obj = Fcons (event->frame_or_window, Qnil);
+         obj = Fcons (Qiconify_frame, Fcons (obj, Qnil));
+         kbd_fetch_ptr = event + 1;
+       }
+      else if (event->kind == deiconify_event)
+       {
+         /* Make an event (make-frame-visible (FRAME)).  */
+         obj = Fcons (event->frame_or_window, Qnil);
+         obj = Fcons (Qmake_frame_visible, Fcons (obj, Qnil));
          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.  */
+         XSETBUFFER (obj, current_buffer);
+         kbd_fetch_ptr = event + 1;
+       }
       /* Just discard these, by returning nil.
         (They shouldn't be found in the buffer,
         but on some machines it appears they do show up.)  */
@@ -2030,10 +2240,11 @@ kbd_buffer_get_event ()
       else
        {
 #ifdef MULTI_FRAME
-         Lisp_Object frame = event->frame_or_window;
+         Lisp_Object frame;
          Lisp_Object focus;
 
-         if (XTYPE (frame) == Lisp_Window)
+         frame = event->frame_or_window;
+         if (WINDOWP (frame))
            frame = WINDOW_FRAME (XWINDOW (frame));
 
          focus = FRAME_FOCUS_FRAME (XFRAME (frame));
@@ -2062,15 +2273,20 @@ kbd_buffer_get_event ()
            }
        }
     }
+#ifdef HAVE_MOUSE
   /* Try generating a mouse motion event.  */
-  else if (do_mouse_tracking && mouse_moved)
+  else if (FRAMEP (do_mouse_tracking) && mouse_moved)
     {
-      FRAME_PTR f = 0;
+      FRAME_PTR f = XFRAME (do_mouse_tracking);
       Lisp_Object bar_window;
       enum scroll_bar_part part;
       Lisp_Object x, y;
       unsigned long time;
 
+      /* Note that this uses F to determine which display to look at.
+        If there is no valid info, it does not store anything
+        so x remains nil.  */
+      x = Qnil;
       (*mouse_position_hook) (&f, &bar_window, &part, &x, &y, &time);
 
       obj = Qnil;
@@ -2079,12 +2295,13 @@ kbd_buffer_get_event ()
       /* Decide if we should generate a switch-frame event.  Don't
         generate switch-frame events for motion outside of all Emacs
         frames.  */
-      if (f)
+      if (!NILP (x) && f)
        {
-         Lisp_Object frame = FRAME_FOCUS_FRAME (f);
+         Lisp_Object frame;
 
+         frame = FRAME_FOCUS_FRAME (f);
          if (NILP (frame))
-           XSET (frame, Lisp_Frame, f);
+           XSETFRAME (frame, f);
 
          if (! EQ (frame, internal_last_event_frame)
              && XFRAME (frame) != selected_frame)
@@ -2095,9 +2312,10 @@ kbd_buffer_get_event ()
 
       /* If we didn't decide to make a switch-frame event, go ahead and 
         return a mouse-motion event.  */
-      if (NILP (obj))
+      if (!NILP (x) && NILP (obj))
        obj = make_lispy_movement (f, bar_window, part, x, y, time);
-     }
+    }
+#endif /* HAVE_MOUSE */
   else
     /* We were promised by the above while loop that there was
        something for us to read!  */
@@ -2162,11 +2380,11 @@ swallow_events ()
 \f
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
-static Lisp_Object vendor_key_syms;
+static Lisp_Object system_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
 
-Lisp_Object Vvendor_key_alist;
+Lisp_Object Vsystem_key_alist;
 
 /* This is a list of keysym codes for special "accent" characters.
    It parallels lispy_accent_keys.  */
@@ -2307,7 +2525,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 */
@@ -2320,8 +2538,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",
@@ -2416,6 +2645,7 @@ make_lispy_event (event)
       /* A simple keystroke.  */
     case ascii_keystroke:
       {
+       Lisp_Object lispy_c;
        int c = event->code & 0377;
        /* Turn ASCII characters into control characters
           when proper.  */
@@ -2429,7 +2659,8 @@ make_lispy_event (event)
              & (meta_modifier | alt_modifier
                 | hyper_modifier | super_modifier));
        button_down_time = 0;
-       return c;
+       XSETFASTINT (lispy_c, c);
+       return lispy_c;
       }
 
       /* A function key.  The symbol may need to have modifier prefixes
@@ -2446,17 +2677,17 @@ make_lispy_event (event)
                                      (sizeof (lispy_accent_keys)
                                       / sizeof (lispy_accent_keys[0])));
 
-      /* Handle vendor-specific keysyms.  */
+      /* Handle system-specific keysyms.  */
       if (event->code & (1 << 28))
        {
          /* We need to use an alist rather than a vector as the cache
             since we can't make a vector long enuf.  */
-         if (NILP (vendor_key_syms))
-           vendor_key_syms = Fcons (Qnil, Qnil);
+         if (NILP (system_key_syms))
+           system_key_syms = Fcons (Qnil, Qnil);
          return modify_event_symbol (event->code & 0xffffff,
                                      event->modifiers,
-                                     Qfunction_key, Vvendor_key_alist,
-                                     0, &vendor_key_syms, 0xffffff);
+                                     Qfunction_key, Vsystem_key_alist,
+                                     0, &system_key_syms, 0xffffff);
        }
 
       return modify_event_symbol (event->code - 0xff00,
@@ -2467,6 +2698,7 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
+#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:
@@ -2486,36 +2718,53 @@ make_lispy_event (event)
          {
            int part;
            FRAME_PTR f = XFRAME (event->frame_or_window);
-           Lisp_Object window
-             = window_from_coordinates (f, XINT (event->x), XINT (event->y),
-                                        &part);
+           Lisp_Object window;
            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);
 
 #ifdef USE_X_TOOLKIT
            if (FRAME_EXTERNAL_MENU_BAR (f) && XINT (event->y) == -1)
 #else
-           if (XINT (event->y) < FRAME_MENU_BAR_LINES (f))
+           if (row < FRAME_MENU_BAR_LINES (f))
 #endif
              {
-#ifdef USE_X_TOOLKIT
-               /* The click happened in the menubar.
-                  Look for the menu item selected.  */
-               Lisp_Object items = map_event_to_object(event, f);
-               XFASTINT (event->y) = 1;
-#else /* not USE_X_TOOLKIT  */
+               Lisp_Object items, item;
                int hpos;
-               Lisp_Object items;
+               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;
+
+#ifndef USE_X_TOOLKIT
+               item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
-               for (; CONSP (items); items = XCONS (items)->cdr)
+               for (i = 0; i < XVECTOR (items)->size; i += 3)
                  {
                    Lisp_Object pos, string;
-                   pos = Fcdr (Fcdr (Fcar (items)));
-                   string = Fcar (Fcdr (Fcar (items)));
-                   if (XINT (event->x) >= XINT (pos)
-                       && XINT (event->x) < XINT (pos) + XSTRING (string)->size)
+                   string = XVECTOR (items)->contents[i + 1];
+                   pos = XVECTOR (items)->contents[i + 2];
+                   if (NILP (string))
                      break;
+                   if (column >= XINT (pos)
+                       && column < XINT (pos) + XSTRING (string)->size)
+                     {
+                       item = XVECTOR (items)->contents[i];
+                       break;
+                     }
                  }
 #endif /* not USE_X_TOOLKIT  */
+
                position
                  = Fcons (event->frame_or_window,
                           Fcons (Qmenu_bar,
@@ -2523,30 +2772,33 @@ make_lispy_event (event)
                                         Fcons (make_number (event->timestamp),
                                                Qnil))));
 
-               if (CONSP (items))
-                 return Fcons (Fcar (Fcar (items)),
-                               Fcons (position, Qnil));
-               else
-                 return Fcons (Qnil, Fcons (position, Qnil));
+               return Fcons (item, Fcons (position, Qnil));
+             }
+
+           window = window_from_coordinates (f, column, row, &part);
+
+           if (!WINDOWP (window))
+             {
+               window = event->frame_or_window;
+               posn = Qnil;
              }
-           else if (XTYPE (window) != Lisp_Window)
-             posn = Qnil;
            else
              {
-               XSETINT (event->x, 
-                        (XINT (event->x) - XINT (XWINDOW (window)->left)));
-               XSETINT (event->y,
-                        (XINT (event->y) - XINT (XWINDOW (window)->top)));
+               int pixcolumn, pixrow;
+               column -= XINT (XWINDOW (window)->left);
+               row -= XINT (XWINDOW (window)->top);
+               glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+               XSETINT (event->x, pixcolumn);
+               XSETINT (event->y, pixrow);
 
                if (part == 1)
                  posn = Qmode_line;
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSET (posn, Lisp_Int,
-                       buffer_posn_from_coords (XWINDOW (window),
-                                                XINT (event->x),
-                                                XINT (event->y)));
+                 XSETINT (posn,
+                          buffer_posn_from_coords (XWINDOW (window),
+                                                   column, row));
              }
 
            position
@@ -2558,17 +2810,20 @@ make_lispy_event (event)
          }
        else
          {
-           Lisp_Object window = event->frame_or_window;
-           Lisp_Object portion_whole = Fcons (event->x, event->y);
-           Lisp_Object part = *scroll_bar_parts[(int) event->part];
+           Lisp_Object window;
+           Lisp_Object portion_whole;
+           Lisp_Object part;
+
+           window = event->frame_or_window;
+           portion_whole = Fcons (event->x, event->y);
+           part = *scroll_bar_parts[(int) event->part];
 
            position =
              Fcons (window,
                     Fcons (Qvertical_scroll_bar,
                            Fcons (portion_whole,
                                   Fcons (make_number (event->timestamp),
-                                         Fcons (part,
-                                                Qnil)))));
+                                         Fcons (part, Qnil)))));
          }
 
        start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
@@ -2616,35 +2871,37 @@ make_lispy_event (event)
               of the button that chose the menu item
               as a separate event.  */
 
-           if (XTYPE (start_pos) != Lisp_Cons)
+           if (!CONSP (start_pos))
              return Qnil;
 
            event->modifiers &= ~up_modifier;
 #if 0 /* Formerly we treated an up with no down as a click event.  */
-           if (XTYPE (start_pos) != Lisp_Cons)
+           if (!CONSP (start_pos))
              event->modifiers |= click_modifier;
            else
 #endif
              {
                /* The third element of every position should be the (x,y)
                   pair.  */
-               Lisp_Object down = Fnth (make_number (2), start_pos);
+               Lisp_Object down;
 
+               down = Fnth (make_number (2), start_pos);
                if (EQ (event->x, XCONS (down)->car)
                    && EQ (event->y, XCONS (down)->cdr))
                  {
-                   if (is_double && double_click_count > 1)
-                     event->modifiers |= ((double_click_count > 2)
-                                          ? triple_modifier
-                                          : double_modifier);
-                   else
-                     event->modifiers |= click_modifier;
+                   event->modifiers |= click_modifier;
                  }
                else
                  {
                    button_down_time = 0;
                    event->modifiers |= drag_modifier;
                  }
+               /* Don't check is_double; treat this as multiple
+                  if the down-event was multiple.  */
+               if (double_click_count > 1)
+                 event->modifiers |= ((double_click_count > 2)
+                                      ? triple_modifier
+                                      : double_modifier);
              }
          }
        else
@@ -2654,14 +2911,14 @@ make_lispy_event (event)
 
        {
          /* Get the symbol we should use for the mouse click.  */
-         Lisp_Object head
-           = modify_event_symbol (button,
-                                  event->modifiers,
-                                  Qmouse_click, Qnil,
-                                  lispy_mouse_names, &mouse_syms,
-                                  (sizeof (lispy_mouse_names)
-                                   / sizeof (lispy_mouse_names[0])));
-         
+         Lisp_Object head;
+
+         head = modify_event_symbol (button,
+                                     event->modifiers,
+                                     Qmouse_click, Qnil,
+                                     lispy_mouse_names, &mouse_syms,
+                                     (sizeof (lispy_mouse_names)
+                                      / sizeof (lispy_mouse_names[0])));
          if (event->modifiers & drag_modifier)
            return Fcons (head,
                          Fcons (start_pos,
@@ -2678,6 +2935,7 @@ make_lispy_event (event)
                                 Qnil));
        }
       }
+#endif /* MULTI_FRAME or HAVE_MOUSE */
 
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
@@ -2685,6 +2943,8 @@ make_lispy_event (event)
     }
 }
 
+#if defined (MULTI_FRAME) || defined (HAVE_MOUSE)
+
 static Lisp_Object
 make_lispy_movement (frame, bar_window, part, x, y, time)
      FRAME_PTR frame;
@@ -2693,11 +2953,13 @@ 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))
     {
-      Lisp_Object part_sym = *scroll_bar_parts[(int) part];
+      Lisp_Object part_sym;
 
+      part_sym = *scroll_bar_parts[(int) part];
       return Fcons (Qscroll_bar_movement,
                    (Fcons (Fcons (bar_window,
                                   Fcons (Qvertical_scroll_bar,
@@ -2710,39 +2972,56 @@ 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 =
-       (frame
-        ? window_from_coordinates (frame, XINT (x), XINT (y), &area)
-        : Qnil);
+      Lisp_Object window;
       Lisp_Object posn;
+      int column, row;
+
+#ifdef MULTI_FRAME
+      if (frame)
+#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;
 
-      if (XTYPE (window) == Lisp_Window)
+      if (WINDOWP (window))
        {
-         XSETINT (x, XINT (x) - XINT (XWINDOW (window)->left));
-         XSETINT (y, XINT (y) - XINT (XWINDOW (window)->top));
+         int pixcolumn, pixrow;
+         column -= XINT (XWINDOW (window)->left);
+         row -= XINT (XWINDOW (window)->top);
+         glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
+         XSETINT (x, pixcolumn);
+         XSETINT (y, pixrow);
 
          if (area == 1)
            posn = Qmode_line;
          else if (area == 2)
            posn = Qvertical_line;
          else
-           XSET (posn, Lisp_Int,
-                 buffer_posn_from_coords (XWINDOW (window),
-                                          XINT (x), XINT (y)));
+           XSETINT (posn,
+                    buffer_posn_from_coords (XWINDOW (window), column, row));
        }
+#ifdef MULTI_FRAME
       else if (frame != 0)
        {
-         XSET (window, Lisp_Frame, frame);
+         XSETFRAME (window, frame);
          posn = Qnil;
        }
+#endif
       else
        {
          window = Qnil;
          posn = Qnil;
-         XFASTINT (x) = 0;
-         XFASTINT (y) = 0;
+         XSETFASTINT (x, 0);
+         XSETFASTINT (y, 0);
        }
 
       return Fcons (Qmouse_movement,
@@ -2755,6 +3034,8 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
     }
 }
 
+#endif /* neither MULTI_FRAME nor HAVE_MOUSE */
+
 /* Construct a switch frame event.  */
 static Lisp_Object
 make_lispy_switch_frame (frame)
@@ -2919,8 +3200,9 @@ apply_modifiers_uncached (modifiers, base, base_len)
   }
 
   {
-    Lisp_Object new_name = make_uninit_string (mod_len + base_len);
+    Lisp_Object new_name;
     
+    new_name = make_uninit_string (mod_len + base_len);
     bcopy (new_mods, XSTRING (new_name)->data,        mod_len);
     bcopy (base,     XSTRING (new_name)->data + mod_len, base_len);
 
@@ -2967,23 +3249,25 @@ static Lisp_Object
 parse_modifiers (symbol)
      Lisp_Object symbol;
 {
-  Lisp_Object elements = Fget (symbol, Qevent_symbol_element_mask);
+  Lisp_Object elements;
 
+  elements = Fget (symbol, Qevent_symbol_element_mask);
   if (CONSP (elements))
     return elements;
   else
     {
       int end;
       int modifiers = parse_modifiers_uncached (symbol, &end);
-      Lisp_Object unmodified
-       = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
-                               XSYMBOL (symbol)->name->size - end),
-                  Qnil);
+      Lisp_Object unmodified;
       Lisp_Object mask;
 
+      unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
+                                        XSYMBOL (symbol)->name->size - end),
+                           Qnil);
+
       if (modifiers & ~((1<<VALBITS) - 1))
        abort ();
-      XFASTINT (mask) = modifiers;
+      XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
 
       /* Cache the parsing results on SYMBOL.  */
@@ -3022,8 +3306,8 @@ 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);
+  XSETFASTINT (index, (modifiers & ~click_modifier));
+  entry = assq_no_quit (index, cache);
 
   if (CONSP (entry))
     new_symbol = XCONS (entry)->cdr;
@@ -3039,7 +3323,7 @@ apply_modifiers (modifiers, base)
       Fput (base, Qmodifier_cache, Fcons (entry, cache));
 
       /* We have the parsing info now for free, so add it to the caches.  */
-      XFASTINT (index) = modifiers;
+      XSETFASTINT (index, modifiers);
       Fput (new_symbol, Qevent_symbol_element_mask,
            Fcons (base, Fcons (index, Qnil)));
       Fput (new_symbol, Qevent_symbol_elements,
@@ -3055,8 +3339,9 @@ apply_modifiers (modifiers, base)
      Qevent_kind set right as well.  */
   if (NILP (Fget (new_symbol, Qevent_kind)))
     {
-      Lisp_Object kind = Fget (base, Qevent_kind);
+      Lisp_Object kind;
 
+      kind = Fget (base, Qevent_kind);
       if (! NILP (kind))
        Fput (new_symbol, Qevent_kind, kind);
     }
@@ -3079,8 +3364,9 @@ reorder_modifiers (symbol)
 {
   /* It's hopefully okay to write the code this way, since everything
      will soon be in caches, and no consing will be done at all.  */
-  Lisp_Object parsed = parse_modifiers (symbol);
+  Lisp_Object parsed;
 
+  parsed = parse_modifiers (symbol);
   return apply_modifiers (XCONS (XCONS (parsed)->cdr)->car,
                          XCONS (parsed)->car);
 }
@@ -3129,11 +3415,11 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
   Lisp_Object value;
   Lisp_Object symbol_int;
 
-  XSET (symbol_int, Lisp_Int, symbol_num);
+  XSETINT (symbol_int, symbol_num);
 
   /* 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));
@@ -3149,7 +3435,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
        {
          Lisp_Object size;
 
-         XFASTINT (size) = table_size;
+         XSETFASTINT (size, table_size);
          *symbol_table = Fmake_vector (size, Qnil);
        }
 
@@ -3161,10 +3447,11 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
     {
       /* No; let's create it.  */
       if (!NILP (name_alist))
-       value = Fassq (symbol_int, name_alist);
+       value = Fcdr_safe (Fassq (symbol_int, name_alist));
       else if (name_table[symbol_num])
        value = intern (name_table[symbol_num]);
-      else
+
+      if (NILP (value))
        {
          char buf[20];
          sprintf (buf, "key-%d", symbol_num);
@@ -3209,7 +3496,7 @@ get_input_pending (addr)
   *addr = !NILP (Vquit_flag) || readable_events ();
 }
 
-/* Interface to read_avail_input, blocking SIGIO if necessary.  */
+/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
 
 int
 gobble_input (expected)
@@ -3225,10 +3512,62 @@ gobble_input (expected)
       sigsetmask (mask);
     }
   else
+#ifdef POLL_FOR_INPUT
+  if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
+    {
+      SIGMASKTYPE mask;
+      mask = sigblockx (SIGALRM);
+      read_avail_input (expected);
+      sigsetmask (mask);
+    }
+  else
+#endif
 #endif
     read_avail_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;
+
+#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
 
@@ -3254,21 +3593,28 @@ read_avail_input (expected)
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (0, buf, KBD_BUFFER_SIZE, expected, expected);
+    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE,
+                                expected, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
         the kbd_buffer can really hold.  That may prevent loss
         of characters on some systems when input is stuffed at us.  */
       unsigned char cbuf[KBD_BUFFER_SIZE - 1];
+      int n_to_read;
 
+      /* Determine how many characters we should *try* to read.  */
+#ifdef WINDOWSNT
+      return 0;
+#else /* not WINDOWSNT */
 #ifdef MSDOS
-      nread = dos_keysns ();
-      if (nread == 0) return 0;
-#else */ not MSDOS */
+      n_to_read = dos_keysns ();
+      if (n_to_read == 0)
+       return 0;
+#else /* not MSDOS */
 #ifdef FIONREAD
       /* Find out how much input is available.  */
-      if (ioctl (0, FIONREAD, &nread) < 0)
+      if (ioctl (input_fd, FIONREAD, &n_to_read) < 0)
        /* Formerly simply reported no input, but that sometimes led to
           a failure of Emacs to terminate.
           SIGHUP seems appropriate if we can't reach the terminal.  */
@@ -3276,31 +3622,33 @@ read_avail_input (expected)
           rather than to the whole process group?
           Perhaps on systems with FIONREAD Emacs is alone in its group.  */
        kill (getpid (), SIGHUP);
-      if (nread == 0)
+      if (n_to_read == 0)
        return 0;
-      if (nread > sizeof cbuf)
-       nread = sizeof cbuf;
+      if (n_to_read > sizeof cbuf)
+       n_to_read = sizeof cbuf;
 #else /* no FIONREAD */
 #if defined(USG) || defined(DGUX)
       /* Read some input if available, but don't wait.  */
-      nread = sizeof cbuf;
-      fcntl (fileno (stdin), F_SETFL, O_NDELAY);
+      n_to_read = sizeof cbuf;
+      fcntl (input_fd, F_SETFL, O_NDELAY);
 #else
       you lose;
 #endif
 #endif
 #endif /* not MSDOS */
+#endif /* not WINDOWSNT */
 
-      /* Now read; for one reason or another, this will not block.  */
-      while (1)
+      /* Now read; for one reason or another, this will not block.
+        NREAD is set to the number of chars read.  */
+      do
        {
 #ifdef MSDOS
          cbuf[0] = dos_keyread();
          nread = 1;
 #else
-         nread = read (fileno (stdin), cbuf, nread);
+         nread = read (input_fd, cbuf, n_to_read);
 #endif
-#ifdef AIX
+#if defined (AIX) && (! defined (aix386) && defined (_BSD))
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
             This looks incorrect, but it isn't, because _BSD causes
             O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
@@ -3308,25 +3656,29 @@ read_avail_input (expected)
          if (nread == 0)
            kill (0, SIGHUP);
 #endif
-         /* This code is wrong, but at least it gets the right results.
-            Fix it for 19.23.  */
-         /* Retry the read if it is interrupted.  */
-         if (nread >= 0
+       }
+      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 == EAGAIN || errno == EFAULT
-#else
-             || ! (errno == EAGAIN 
+                          || errno == EFAULT
 #endif
 #ifdef EBADSLT
-                   || errno == EBADSLT
+                          || errno == EBADSLT
 #endif
-                   ))
-           break;
-       }
+                          )
+#else
+            0
+#endif
+            );
 
 #ifndef FIONREAD
 #if defined (USG) || defined (DGUX)
-      fcntl (fileno (stdin), F_SETFL, 0);
+      fcntl (input_fd, F_SETFL, 0);
 #endif /* USG or DGUX */
 #endif /* no FIONREAD */
       for (i = 0; i < nread; i++)
@@ -3337,10 +3689,10 @@ read_avail_input (expected)
            buf[i].modifiers = meta_modifier;
          if (meta_key != 2)
            cbuf[i] &= ~0x80;
-           
-         XSET (buf[i].code,            Lisp_Int,   cbuf[i]);
+
+         buf[i].code = cbuf[i];
 #ifdef MULTI_FRAME
-         XSET (buf[i].frame_or_window, Lisp_Frame, selected_frame);
+         XSETFRAME (buf[i].frame_or_window, selected_frame);
 #else
          buf[i].frame_or_window = Qnil;
 #endif
@@ -3354,7 +3706,7 @@ read_avail_input (expected)
       /* Don't look at input that follows a C-g too closely.
         This reduces lossage due to autorepeat on C-g.  */
       if (buf[i].kind == ascii_keystroke
-         && XINT(buf[i].code) == quit_char)
+         && buf[i].code == quit_char)
        break;
     }
 
@@ -3438,22 +3790,31 @@ map_prompt (map)
     {
       register Lisp_Object tem;
       tem = Fcar (map);
-      if (XTYPE (tem) == Lisp_String)
+      if (STRINGP (tem))
        return tem;
       map = Fcdr (map);
     }
   return Qnil;
 }
 
-static Lisp_Object menu_bar_item ();
-static Lisp_Object menu_bar_one_keymap ();
+static void menu_bar_item ();
+static void menu_bar_one_keymap ();
+
+/* These variables hold the vector under construction within
+   menu_bar_items and its subroutines, and the current index
+   for storing into that vector.  */
+static Lisp_Object menu_bar_items_vector;
+static int menu_bar_items_index;
 
-/* Return a list of menu items for a menu bar, appropriate
-   to the current buffer.
-   The elements have the form (KEY STRING . nil).  */
+/* 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 MAPLIST.
+
+   OLD is an old vector we can optionally reuse, or nil.  */
 
 Lisp_Object
-menu_bar_items ()
+menu_bar_items (old)
+     Lisp_Object old;
 {
   /* The number of keymaps we're scanning right now, and the number of
      keymaps we have allocated space for.  */
@@ -3470,6 +3831,10 @@ menu_bar_items ()
   int mapno;
   Lisp_Object oquit;
 
+  int i;
+
+  struct gcpro gcpro1;
+
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -3479,6 +3844,14 @@ menu_bar_items ()
   oquit = Vinhibit_quit;
   Vinhibit_quit = Qt; 
 
+  if (!NILP (old))
+    menu_bar_items_vector = old;
+  else
+    menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
+  menu_bar_items_index = 0;
+
+  GCPRO1 (menu_bar_items_vector);
+
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -3487,14 +3860,26 @@ menu_bar_items ()
   { 
     Lisp_Object *tmaps;
 
-    if (!NILP (Voverriding_local_map))
+    /* Should overriding-local-map apply, here?  */
+    if (!NILP (Voverriding_local_map_menu_flag))
       {
-       nmaps = 2;
-       maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-       maps[0] = Voverriding_local_map;
+       if (NILP (Voverriding_local_map))
+         {
+           /* Yes, and it is nil.  Use just global map.  */
+           nmaps = 1;
+           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+         }
+       else
+         {
+           /* Yes, and it is non-nil.  Use it and the global map.  */
+           nmaps = 2;
+           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+           maps[0] = Voverriding_local_map;
+         }
       }
     else
       {
+       /* No, so use major and minor mode keymaps.  */
        nmaps = current_minor_maps (0, &tmaps) + 2;
        maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
        bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
@@ -3520,52 +3905,85 @@ menu_bar_items ()
 
       tem = Fkeymapp (def);
       if (!NILP (tem))
-       result = menu_bar_one_keymap (def, result);
+       menu_bar_one_keymap (def);
     }
 
+  /* Move to the end those items that should be at the end.  */
+
   for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCONS (tail)->cdr)
     {
-      Lisp_Object elt;
+      int i;
+      int end = menu_bar_items_index;
 
-      elt = Fassq (XCONS (tail)->car, result);
-      if (!NILP (elt))
-       result = Fcons (elt, Fdelq (elt, result));
+      for (i = 0; i < end; i += 3)
+       if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
+         {
+           Lisp_Object tem0, tem1, tem2;
+           /* Move the item at index I to the end,
+              shifting all the others forward.  */
+           tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
+           tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
+           tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+           if (end > i + 3)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+                    &XVECTOR (menu_bar_items_vector)->contents[i],
+                    (end - i - 3) * sizeof (Lisp_Object));
+           XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem0;
+           XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem1;
+           XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem2;
+           break;
+         }
+    }
+
+  /* Add nil, nil, nil at the end.  */
+  i = menu_bar_items_index;
+  if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+    {
+      Lisp_Object tem;
+      int newsize = 2 * i;
+      tem = Fmake_vector (make_number (2 * i), Qnil);
+      bcopy (XVECTOR (menu_bar_items_vector)->contents,
+            XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+      menu_bar_items_vector = tem;
     }
+  /* Add this item.  */
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  menu_bar_items_index = i;
 
-  result = Fnreverse (result);
   Vinhibit_quit = oquit;
-  return result;
+  UNGCPRO;
+  return menu_bar_items_vector;
 }
 \f
 /* Scan one map KEYMAP, accumulating any menu items it defines
-   that have not yet been seen in RESULT.  Return the updated RESULT.  */
+   in menu_bar_items_vector.  */
 
-static Lisp_Object
-menu_bar_one_keymap (keymap, result)
-     Lisp_Object keymap, result;
+static void
+menu_bar_one_keymap (keymap)
+     Lisp_Object keymap;
 {
   Lisp_Object tail, item, key, binding, item_string, table;
 
   /* Loop over all keymap entries that have menu strings.  */
-  for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
+  for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
     {
       item = XCONS (tail)->car;
-      if (XTYPE (item) == Lisp_Cons)
+      if (CONSP (item))
        {
          key = XCONS (item)->car;
          binding = XCONS (item)->cdr;
-         if (XTYPE (binding) == Lisp_Cons)
+         if (CONSP (binding))
            {
              item_string = XCONS (binding)->car;
-             if (XTYPE (item_string) == Lisp_String)
-               result = menu_bar_item (key, item_string,
-                                       Fcdr (binding), result);
+             if (STRINGP (item_string))
+               menu_bar_item (key, item_string, Fcdr (binding));
            }
          else if (EQ (binding, Qundefined))
-           result = menu_bar_item (key, item_string,
-                                   binding, result);
+           menu_bar_item (key, Qnil, binding);
        }
-      else if (XTYPE (item) == Lisp_Vector)
+      else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
          int len = XVECTOR (item)->size;
@@ -3573,23 +3991,19 @@ menu_bar_one_keymap (keymap, result)
          for (c = 0; c < len; c++)
            {
              Lisp_Object character;
-             XFASTINT (character) = c;
+             XSETFASTINT (character, c);
              binding = XVECTOR (item)->contents[c];
-             if (XTYPE (binding) == Lisp_Cons)
+             if (CONSP (binding))
                {
                  item_string = XCONS (binding)->car;
-                 if (XTYPE (item_string) == Lisp_String)
-                   result = menu_bar_item (key, item_string,
-                                           Fcdr (binding), result);
+                 if (STRINGP (item_string))
+                   menu_bar_item (key, item_string, Fcdr (binding));
                }
              else if (EQ (binding, Qundefined))
-               result = menu_bar_item (key, item_string,
-                                       binding, result);
+               menu_bar_item (key, Qnil, binding);
            }
        }
     }
-
-  return result;
 }
 
 /* This is used as the handler when calling internal_condition_case_1.  */
@@ -3601,25 +4015,42 @@ menu_bar_item_1 (arg)
   return Qnil;
 }
 
-static Lisp_Object
-menu_bar_item (key, item_string, def, result)
-     Lisp_Object key, item_string, def, result;
+/* 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;
 {
   Lisp_Object tem;
   Lisp_Object enabled;
+  int i;
 
   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.  */
-      tem = Fassq (key, result);
-      return Fdelq (tem, result);
+
+      for (i = 0; i < menu_bar_items_index; i += 3)
+       if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+         {
+           if (menu_bar_items_index > i + 3)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+                    &XVECTOR (menu_bar_items_vector)->contents[i],
+                    (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
+           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.  */
   enabled = Qt;
 
-  if (XTYPE (def) == Lisp_Symbol)
+  if (SYMBOLP (def))
     {
       /* No property, or nil, means enable.
         Otherwise, enable if value is not nil.  */
@@ -3631,13 +4062,41 @@ menu_bar_item (key, item_string, def, result)
                                             menu_bar_item_1);
     }
 
-  /* Add an entry for this key and string
-     if there is none yet.  */
-  tem = Fassq (key, result);
-  if (!NILP (enabled) && NILP (tem))
-    result = Fcons (Fcons (key, Fcons (item_string, Qnil)), result);
+  /* Ignore this item if it's not enabled.  */
+  if (NILP (enabled))
+    return;
+
+  /* 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;
 
-  return result;
+  /* 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.  */
+      if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+       {
+         Lisp_Object tem;
+         int newsize = 2 * i;
+         tem = Fmake_vector (make_number (2 * i), Qnil);
+         bcopy (XVECTOR (menu_bar_items_vector)->contents,
+                XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+         menu_bar_items_vector = tem;
+       }
+      /* 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++] = 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.
@@ -3679,6 +4138,13 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   if (! menu_prompting)
     return Qnil;
 
+  /* Optionally disregard all but the global map.  */
+  if (inhibit_local_menu_bar_menus)
+    {
+      maps += (nmaps - 1);
+      nmaps = 1;
+    }
+
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
@@ -3691,8 +4157,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   if (mapno >= nmaps)
     return Qnil;
 
-#ifdef HAVE_X_WINDOWS
-#ifdef HAVE_X_MENU
+#if (defined (HAVE_X_WINDOWS) && defined (HAVE_X_MENU)) || defined (MSDOS)
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
   if (EVENT_HAS_PARAMETERS (prev_event))
@@ -3714,23 +4179,22 @@ 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;
        }
-      if (NILP (value))
+      else if (NILP (value))
        value = Qt;
       if (used_mouse_menu)
        *used_mouse_menu = 1;
       return value;
     }
-#endif /* HAVE_X_MENU */
-#endif /* HAVE_X_WINDOWS */
+#endif /* (HAVE_X_WINDOWS && HAVE_X_MENU) || MSDOS */
   return Qnil ;
 }
 
 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;
@@ -3741,7 +4205,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)
@@ -3804,7 +4268,7 @@ read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
          else
            elt = Fcar_safe (rest);
 
-         if (idx < 0 && XTYPE (elt) == Lisp_Vector)
+         if (idx < 0 && VECTORP (elt))
            {
              /* If we found a dense table in the keymap,
                 advanced past it, but start scanning its contents.  */
@@ -3819,7 +4283,7 @@ read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
                s = Fcar_safe (Fcdr_safe (elt));        /* alist */
              else
                s = Fcar_safe(elt);                     /* vector */
-             if (XTYPE (s) != Lisp_String)
+             if (!STRINGP (s))
                /* Ignore the element if it has no prompt string.  */
                ;
              /* If we have room for the prompt string, add it to this line.
@@ -3876,16 +4340,16 @@ read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
       defining_kbd_macro = 0 ;
       do
        obj = read_char (commandflag, 0, 0, Qnil, 0);
-      while (XTYPE (obj) == Lisp_Buffer);
+      while (BUFFERP (obj));
       defining_kbd_macro = orig_defn_macro ;
 
-      if (XTYPE (obj) != Lisp_Int)
+      if (!INTEGERP (obj))
        return obj;
       else
        ch = XINT (obj);
 
       if (! EQ (obj, menu_prompt_more_char)
-         && (XTYPE (menu_prompt_more_char) != Lisp_Int
+         && (!INTEGERP (menu_prompt_more_char)
              || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char))))))
        {
          if ( defining_kbd_macro )
@@ -3908,29 +4372,22 @@ 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;
 
   /* If KEY is a meta ASCII character, treat it like meta-prefix-char
      followed by the corresponding non-meta character.  */
-  if (XTYPE (key) == Lisp_Int && (XINT (key) & CHAR_META))
+  if (INTEGERP (key) && (XINT (key) & CHAR_META))
     {
       for (i = 0; i < nmaps; i++)
        if (! NILP (current[i]))
@@ -3947,7 +4404,7 @@ follow_key (key, nmaps, current, defs, next, case_converted)
          next[i] = Qnil;
 
       current = next;
-      XSET (key, Lisp_Int, XFASTINT (key) & ~CHAR_META);
+      XSETINT (key, XFASTINT (key) & ~CHAR_META);
     }
 
   first_binding = nmaps;
@@ -3963,38 +4420,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++)
@@ -4110,15 +4535,15 @@ read_key_sequence (keybuf, bufsize, prompt)
   Lisp_Object first_event;
 #endif
 
-  struct buffer *starting_buffer;
+  /* Gets around Microsoft compiler limitations.  */
+  int dummyFlag = 0;
 
-  /* Nonzero if we found the binding for one of the chars
-     in this key sequence by downcasing it.  */
-  int case_converted = 0;
+  struct buffer *starting_buffer;
 
   /* Nonzero if we seem to have got the beginning of a binding
      in function_key_map.  */
   int function_key_possible = 0;
+  int key_translation_possible = 0;
 
   int junk;
 
@@ -4140,7 +4565,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 ();
@@ -4169,8 +4594,8 @@ read_key_sequence (keybuf, bufsize, prompt)
  replay_sequence:
 
   starting_buffer = current_buffer;
-  case_converted = 0;
   function_key_possible = 0;
+  key_translation_possible = 0;
 
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
@@ -4232,16 +4657,13 @@ read_key_sequence (keybuf, bufsize, prompt)
             && fkey_start < t
             /* mock input is never part of a function key's sequence.  */
             && mock_input <= fkey_start)
-        || (first_binding >= nmaps
-            && keytran_start < t
-            /* mock input is never part of a function key's sequence.  */
-            && mock_input <= keytran_start)
+        || (keytran_start < t && key_translation_possible)
         /* Don't return in the middle of a possible function key sequence,
            if the only bindings we found were via case conversion.
            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;
@@ -4285,7 +4707,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.  */
@@ -4304,15 +4727,18 @@ read_key_sequence (keybuf, bufsize, prompt)
          /* read_char returns -1 at the end of a macro.
             Emacs 18 handles this by returning immediately with a
             zero, so that's what we'll do.  */
-         if (XTYPE (key) == Lisp_Int && XINT (key) == -1)
+         if (INTEGERP (key) && XINT (key) == -1)
            {
              t = 0;
-             goto done;
+             /* The Microsoft C compiler can't handle the goto that
+                would go here.  */
+             dummyFlag = 1;
+             break;
            }
          
          /* If the current buffer has been changed from under us, the
             keymap may have changed, so replay the sequence.  */
-         if (XTYPE (key) == Lisp_Buffer)
+         if (BUFFERP (key))
            {
              mock_input = t;
              goto replay_sequence;
@@ -4321,7 +4747,7 @@ read_key_sequence (keybuf, bufsize, prompt)
          /* If we have a quit that was typed in another frame, and
             quit_throw_to_read_char switched buffers,
             replay to get the right keymap.  */
-         if (EQ (key, quit_char) && current_buffer != starting_buffer)
+         if (XINT (key) == quit_char && current_buffer != starting_buffer)
            {
              keybuf[t++] = key;
              mock_input = t;
@@ -4348,14 +4774,16 @@ read_key_sequence (keybuf, bufsize, prompt)
         or when user programs play with this-command-keys.  */
       if (EVENT_HAS_PARAMETERS (key))
        {
-         Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+         Lisp_Object kind;
 
+         kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
            {
-             Lisp_Object window = POSN_WINDOW      (EVENT_START (key));
-             Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             Lisp_Object window, posn;
 
-             if (XTYPE (posn) == Lisp_Cons)
+             window = POSN_WINDOW      (EVENT_START (key));
+             posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             if (CONSP (posn))
                {
                  /* We're looking at the second event of a
                     sequence which we expanded before.  Set
@@ -4369,8 +4797,8 @@ read_key_sequence (keybuf, bufsize, prompt)
                 not the current buffer.  If we're at the
                 beginning of a key sequence, switch buffers.  */
              if (last_real_key_start == 0
-                 && XTYPE (window) == Lisp_Window
-                 && XTYPE (XWINDOW (window)->buffer) == Lisp_Buffer
+                 && WINDOWP (window)
+                 && BUFFERP (XWINDOW (window)->buffer)
                  && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
                {
                  keybuf[t] = key;
@@ -4391,7 +4819,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                  set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
                  goto replay_sequence;
                }
-             else if (XTYPE (posn) == Lisp_Symbol)
+             else if (SYMBOLP (posn))
                {
                  /* Expand mode-line and scroll-bar events into two events:
                     use posn as a fake prefix key.  */
@@ -4420,10 +4848,13 @@ 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   = POSN_BUFFER_POSN (EVENT_START (key));
+             Lisp_Object posn;
 
+             posn = POSN_BUFFER_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
              if (EQ (posn, Qmenu_bar))
@@ -4431,7 +4862,8 @@ read_key_sequence (keybuf, bufsize, prompt)
                  if (t + 1 >= bufsize)
                    error ("key sequence too long");
                  /* Run the Lucid hook.  */
-                 call1 (Vrun_hooks, Qactivate_menubar_hook);
+                 if (!NILP (Vrun_hooks))
+                   call1 (Vrun_hooks, Qactivate_menubar_hook);
                  /* If it has changed current-menubar from previous value,
                     really recompute the menubar from the value.  */
                  if (! NILP (Vlucid_menu_bar_dirty_flag))
@@ -4447,7 +4879,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                  mock_input = t + 2;
                  goto replay_sequence;
                }
-             else if (XTYPE (posn) == Lisp_Cons)
+             else if (CONSP (posn))
                {
                  /* We're looking at the second event of a
                     sequence which we expanded before.  Set
@@ -4464,28 +4896,32 @@ 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.  */
       if (first_binding >= nmaps)
        {
-         Lisp_Object head = EVENT_HEAD (key);
+         Lisp_Object head;
 
+         head = EVENT_HEAD (key);
          if (EQ (head, Vhelp_char))
            {
              read_key_sequence_cmd = Vprefix_help_command;
              keybuf[t++] = key;
              last_nonmenu_event = key;
-             goto done;
+             /* The Microsoft C compiler can't handle the goto that
+                would go here.  */
+             dummyFlag = 1;
            }
 
-         if (XTYPE (head) == Lisp_Symbol)
+         if (SYMBOLP (head))
            {
-             Lisp_Object breakdown = parse_modifiers (head);
-             int modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+             Lisp_Object breakdown;
+             int modifiers;
 
+             breakdown = parse_modifiers (head);
+             modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
              /* Attempt to reduce an unbound mouse event to a simpler
                 event that is bound:
                   Drags reduce to clicks.
@@ -4504,8 +4940,10 @@ read_key_sequence (keybuf, bufsize, prompt)
                      Lisp_Object new_head, new_click;
                      if (modifiers & triple_modifier)
                        modifiers ^= (double_modifier | triple_modifier);
-                     else if (modifiers & (drag_modifier | double_modifier))
-                       modifiers &= ~(drag_modifier | double_modifier);
+                     else if (modifiers & double_modifier)
+                       modifiers &= ~double_modifier;
+                     else if (modifiers & drag_modifier)
+                       modifiers &= ~drag_modifier;
                      else
                        {
                          /* Dispose of this `down' event by simply jumping
@@ -4564,8 +5002,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.  */
@@ -4592,7 +5029,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;
@@ -4607,14 +5044,14 @@ read_key_sequence (keybuf, bufsize, prompt)
              key = keybuf[fkey_end++];
              /* Look up meta-characters by prefixing them
                 with meta_prefix_char.  I hate this.  */
-             if (XTYPE (key) == Lisp_Int && XINT (key) & meta_modifier)
+             if (INTEGERP (key) && XINT (key) & meta_modifier)
                {
                  fkey_next
                    = get_keymap_1
                      (get_keyelt
                       (access_keymap (fkey_map, meta_prefix_char, 1, 0)),
                       0, 1);
-                 XFASTINT (key) = XFASTINT (key) & ~meta_modifier;
+                 XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
                }
              else
                fkey_next = fkey_map;
@@ -4622,6 +5059,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.  */
@@ -4667,14 +5112,18 @@ read_key_sequence (keybuf, bufsize, prompt)
                      int i;
 
                      for (i = 0; i < len; i++)
-                       XFASTINT (keybuf[fkey_start + i])
-                         = XSTRING (fkey_next)->data[i];
+                       XSETFASTINT (keybuf[fkey_start + i],
+                                    XSTRING (fkey_next)->data[i]);
                    }
                  
                  mock_input = t;
                  fkey_start = fkey_end = t;
                  fkey_map = Vfunction_key_map;
 
+                 /* Do pass the results through key-translation-map.  */
+                 keytran_start = keytran_end = 0;
+                 keytran_map = Vkey_translation_map;
+
                  goto replay_sequence;
                }
              
@@ -4703,14 +5152,14 @@ read_key_sequence (keybuf, bufsize, prompt)
            key = keybuf[keytran_end++];
            /* Look up meta-characters by prefixing them
               with meta_prefix_char.  I hate this.  */
-           if (XTYPE (key) == Lisp_Int && XINT (key) & meta_modifier)
+           if (INTEGERP (key) && XINT (key) & meta_modifier)
              {
                keytran_next
                  = get_keymap_1
                    (get_keyelt
                     (access_keymap (keytran_map, meta_prefix_char, 1, 0)),
                     0, 1);
-               XFASTINT (key) = XFASTINT (key) & ~meta_modifier;
+               XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
              }
            else
              keytran_next = keytran_map;
@@ -4739,6 +5188,8 @@ read_key_sequence (keybuf, bufsize, prompt)
                  error ("Function in key-translation-map returns invalid key sequence");
              }
 
+           key_translation_possible = ! NILP (keytran_next);
+
            /* If keybuf[keytran_start..keytran_end] is bound in the
               key translation map and it's a suffix of the current
               sequence (i.e. keytran_end == t), replace it with
@@ -4761,14 +5212,19 @@ read_key_sequence (keybuf, bufsize, prompt)
                    int i;
 
                    for (i = 0; i < len; i++)
-                     XFASTINT (keybuf[keytran_start + i])
-                       = XSTRING (keytran_next)->data[i];
+                     XSETFASTINT (keybuf[keytran_start + i],
+                                  XSTRING (keytran_next)->data[i]);
                  }
 
                mock_input = t;
                keytran_start = keytran_end = t;
                keytran_map = Vkey_translation_map;
 
+               /* Don't pass the results of key-translation-map
+                  through function-key-map.  */
+               fkey_start = fkey_end = t;
+               fkey_map = Vkey_translation_map;
+
                goto replay_sequence;
              }
 
@@ -4780,16 +5236,40 @@ read_key_sequence (keybuf, bufsize, prompt)
              {
                keytran_end = ++keytran_start;
                keytran_map = Vkey_translation_map;
+               key_translation_possible = 0;
              }
          }
       }
+
+      /* 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
+         && ! key_translation_possible
+         && INTEGERP (key)
+         && ((((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
-                          ? defs[first_binding]
-                          : Qnil);
+  if (!dummyFlag)
+    read_key_sequence_cmd = (first_binding < nmaps
+                            ? defs[first_binding]
+                            : Qnil);
 
- done:
   unread_switch_frame = delayed_switch_frame;
   unbind_to (count, Qnil);
 
@@ -4804,7 +5284,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]);
     }
 
@@ -4899,10 +5380,10 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
   Vcurrent_prefix_arg = prefixarg;
   debug_on_next_call = 0;
 
-  if (XTYPE (cmd) == Lisp_Symbol)
+  if (SYMBOLP (cmd))
     {
       tem = Fget (cmd, Qdisabled);
-      if (!NILP (tem))
+      if (!NILP (tem) && !NILP (Vrun_hooks))
        return call1 (Vrun_hooks, Qdisabled_command_hook);
     }
 
@@ -4916,8 +5397,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
        break;
     }
 
-  if (XTYPE (final) == Lisp_String
-      || XTYPE (final) == Lisp_Vector)
+  if (STRINGP (final) || VECTORP (final))
     {
       /* If requested, place the macro in the command history.  For
         other sorts of commands, call-interactively takes care of
@@ -4930,8 +5410,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
 
       return Fexecute_kbd_macro (final, prefixarg);
     }
-  if (CONSP (final) || XTYPE (final) == Lisp_Subr
-      || XTYPE (final) == Lisp_Compiled)
+  if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
     {
       backtrace.next = backtrace_list;
       backtrace_list = &backtrace;
@@ -4959,7 +5438,8 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object saved_keys;
   struct gcpro gcpro1;
 
-  saved_keys = Fthis_command_keys ();
+  saved_keys = Fvector (this_command_key_count,
+                       XVECTOR (this_command_keys)->contents);
   buf[0] = 0;
   GCPRO1 (saved_keys);
 
@@ -4967,9 +5447,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     strcpy (buf, "- ");
   else if (CONSP (prefixarg) && XINT (XCONS (prefixarg)->car) == 4)
     strcpy (buf, "C-u ");
-  else if (CONSP (prefixarg) && XTYPE (XCONS (prefixarg)->car) == Lisp_Int)
+  else if (CONSP (prefixarg) && INTEGERP (XCONS (prefixarg)->car))
     sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car));
-  else if (XTYPE (prefixarg) == Lisp_Int)
+  else if (INTEGERP (prefixarg))
     sprintf (buf, "%d ", XINT (prefixarg));
 
   /* This isn't strictly correct if execute-extended-command
@@ -4989,26 +5469,24 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
      function, followed by a RET.  */
   {
     struct Lisp_String *str;
+    Lisp_Object *keys;
     int i;
     Lisp_Object tem;
 
     this_command_key_count = 0;
 
-    str = XSTRING (saved_keys);
-    for (i = 0; i < str->size; i++)
-      {
-       XFASTINT (tem) = str->data[i];
-       add_command_key (tem);
-      }
+    keys = XVECTOR (saved_keys)->contents;
+    for (i = 0; i < XVECTOR (saved_keys)->size; i++)
+      add_command_key (keys[i]);
 
     str = XSTRING (function);
     for (i = 0; i < str->size; i++)
       {
-       XFASTINT (tem) = str->data[i];
+       XSETFASTINT (tem, str->data[i]);
        add_command_key (tem);
       }
 
-    XFASTINT (tem) = '\015';
+    XSETFASTINT (tem, '\015');
     add_command_key (tem);
   }
 
@@ -5043,7 +5521,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;
@@ -5085,7 +5563,7 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
   ()
 {
   Lisp_Object temp;
-  XFASTINT (temp) = command_loop_level + minibuf_level;
+  XSETFASTINT (temp, command_loop_level + minibuf_level);
   return temp;
 }
 
@@ -5117,7 +5595,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 ();
@@ -5134,14 +5612,13 @@ Also cancel any kbd macro being defined.")
 \f
 DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
   "Stop Emacs and return to superior process.  You can resume later.\n\
-On systems that don't have job control, run a subshell instead.\n\n\
+If `cannot-suspend' is non-nil, or if the system doesn't support job\n\
+control, run a subshell instead.\n\n\
 If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
 to be read as terminal input by Emacs's parent, after suspension.\n\
 \n\
-Before suspending, call the functions in `suspend-hook' with no args.\n\
-If any of them returns nil, don't call the rest and don't suspend.\n\
-Otherwise, suspend normally and after resumption run the normal hook\n\
-`suspend-resume-hook' if that is bound and non-nil.\n\
+Before suspending, run the normal hook `suspend-hook'.\n\
+After resumption run the normal hook `suspend-resume-hook'.\n\
 \n\
 Some operating systems cannot stop the Emacs process and resume it later.\n\
 On such systems, Emacs starts a subshell instead of suspending.")
@@ -5169,7 +5646,10 @@ On such systems, Emacs starts a subshell instead of suspending.")
      and the system resources aren't available for that.  */
   record_unwind_protect (init_sys_modes, 0);
   stuff_buffered_input (stuffstring);
-  sys_suspend ();
+  if (cannot_suspend)
+    sys_subshell ();
+  else
+    sys_suspend ();
   unbind_to (count, Qnil);
 
   /* Check if terminal/window size has changed.
@@ -5198,7 +5678,7 @@ stuff_buffered_input (stuffstring)
 /* stuff_char works only in BSD, versions 4.2 and up.  */
 #ifdef BSD
 #ifndef BSD4_1
-  if (XTYPE (stuffstring) == Lisp_String)
+  if (STRINGP (stuffstring))
     {
       register int count;
 
@@ -5267,10 +5747,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 ();
@@ -5374,7 +5857,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
@@ -5383,7 +5866,7 @@ quit_throw_to_read_char ()
     abort ();
 #endif
 #ifdef MULTI_FRAME
-  if (XTYPE (internal_last_event_frame) == Lisp_Frame
+  if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
     Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
 #endif
@@ -5406,8 +5889,7 @@ See also `current-input-mode'.")
      Lisp_Object interrupt, flow, meta, quit;
 {
   if (!NILP (quit)
-      && (XTYPE (quit) != Lisp_Int
-         || XINT (quit) < 0 || XINT (quit) > 0400))
+      && (!INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400))
     error ("set-input-mode: QUIT must be an ASCII character");
 
 #ifdef POLL_FOR_INPUT
@@ -5471,7 +5953,7 @@ The elements of this list correspond to the arguments of\n\
   val[0] = interrupt_input ? Qt : Qnil;
   val[1] = flow_control ? Qt : Qnil;
   val[2] = meta_key == 2 ? make_number (0) : meta_key == 1 ? Qt : Qnil;
-  XFASTINT (val[3]) = quit_char;
+  XSETFASTINT (val[3], quit_char);
 
   return Flist (sizeof (val) / sizeof (val[0]), val);
 }
@@ -5483,13 +5965,15 @@ 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;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  do_mouse_tracking = 0;
+#ifdef HAVE_MOUSE
+  do_mouse_tracking = Qnil;
+#endif
   input_pending = 0;
 
 #ifdef MULTI_FRAME
@@ -5508,7 +5992,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)
@@ -5516,11 +6000,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.  */
@@ -5560,6 +6045,9 @@ struct event_head head_table[] = {
   &Qmouse_movement,    "mouse-movement",       &Qmouse_movement,
   &Qscroll_bar_movement, "scroll-bar-movement",        &Qmouse_movement,
   &Qswitch_frame,      "switch-frame",         &Qswitch_frame,
+  &Qdelete_frame,      "delete-frame",         &Qdelete_frame,
+  &Qiconify_frame,     "iconify-frame",        &Qiconify_frame,
+  &Qmake_frame_visible,        "make-frame-visible",   &Qmake_frame_visible,
 };
 
 syms_of_keyboard ()
@@ -5629,6 +6117,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;
 
@@ -5671,9 +6162,15 @@ 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);
 
+  system_key_syms = Qnil;
+  staticpro (&system_key_syms);
+
   mouse_syms = Qnil;
   staticpro (&mouse_syms);
 
@@ -5682,7 +6179,9 @@ syms_of_keyboard ()
 
   defsubr (&Sread_key_sequence);
   defsubr (&Srecursive_edit);
+#ifdef HAVE_MOUSE
   defsubr (&Strack_mouse);
+#endif
   defsubr (&Sinput_pending_p);
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
@@ -5701,7 +6200,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,
@@ -5713,10 +6212,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,
@@ -5725,7 +6224,7 @@ so that you can determine whether the command was run by mouse or not.");
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
     "Meta-prefix character code.  Meta-foo as command input\n\
 turns into this character followed by foo.");
-  XSET (meta_prefix_char, Lisp_Int, 033);
+  XSETINT (meta_prefix_char, 033);
 
   DEFVAR_LISP ("last-command", &last_command,
     "The last command executed.  Normally a symbol with a function definition,\n\
@@ -5749,7 +6248,7 @@ Zero means disable autosaving due to number of characters typed.");
 Zero or nil means disable auto-saving due to idleness.\n\
 After auto-saving due to this many seconds of idle time,\n\
 Emacs also does a garbage collection if that seems to be warranted.");
-  XFASTINT (Vauto_save_timeout) = 30;
+  XSETFASTINT (Vauto_save_timeout, 30);
 
   DEFVAR_INT ("echo-keystrokes", &echo_keystrokes,
     "*Nonzero means echo unfinished commands after this many seconds of pause.");
@@ -5769,22 +6268,24 @@ t means double-clicks have no time limit and are detected\n\
 by position only.");
   Vdouble_click_time = make_number (500);
 
+  DEFVAR_BOOL ("inhibit-local-menu-bar-menus", &inhibit_local_menu_bar_menus,
+    "*Non-nil means inhibit local map menu bar menus.");
+  inhibit_local_menu_bar_menus = 0;
+
   DEFVAR_INT ("num-input-keys", &num_input_keys,
     "*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\
 When it is read, do `(eval help-form)', and display result if it's a string.\n\
 If the value of `help-form' is nil, this char can be read normally.");
-  XSET (Vhelp_char, Lisp_Int, Ctl ('H'));
+  XSETINT (Vhelp_char, Ctl ('H'));
 
   DEFVAR_LISP ("help-form", &Vhelp_form,
     "Form to execute when character `help-char' is read.\n\
@@ -5815,6 +6316,11 @@ This keymap works like `function-key-map', but comes after that,\n\
 and applies even for keys that have ordinary bindings.");
   Vkey_translation_map = Qnil;
 
+  DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
+    "Non-nil means to always spawn a subshell instead of suspending,\n\
+even if the operating system has support for stopping a process.");
+  cannot_suspend = 0;
+
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
     "Non-nil means prompt with menus when appropriate.\n\
 This is done when reading from a keymap that has a prompt string,\n\
@@ -5828,7 +6334,7 @@ Otherwise, menu prompting uses the echo area.");
   DEFVAR_LISP ("menu-prompt-more-char", &menu_prompt_more_char,
     "Character to see next line of menu prompt.\n\
 Type this character while in a menu prompt to rotate around the lines of it.");
-  XSET (menu_prompt_more_char, Lisp_Int, ' ');
+  XSETINT (menu_prompt_more_char, ' ');
 
   DEFVAR_INT ("extra-keyboard-modifiers", &extra_keyboard_modifiers,
     "A mask of additional modifier keys to use with every keyboard character.\n\
@@ -5850,12 +6356,26 @@ and tests the value when the command returns.\n\
 Buffer modification stores t in this variable.");
   Vdeactivate_mark = Qnil;
 
+  DEFVAR_LISP ("command-hook-internal", &Vcommand_hook_internal,
+    "Temporary storage of pre-command-hook or post-command-hook.");
+  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,
@@ -5873,15 +6393,34 @@ If this variable is non-nil, it is used as a keymap instead of the\n\
 buffer's local map, and the minor mode keymaps and text property keymaps.");
   Voverriding_local_map = Qnil;
 
+  DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
+    "Non-nil means `overriding-local-map' applies to the menu bar.\n\
+Otherwise, the menu bar continues to reflect the buffer's local map\n\
+and the minor mode maps regardless of `overriding-local-map'.");
+  Voverriding_local_map_menu_flag = Qnil;
+
+#ifdef HAVE_MOUSE
   DEFVAR_BOOL ("track-mouse", &do_mouse_tracking,
               "*Non-nil means generate motion events for mouse motion.");
+#endif
 
-  DEFVAR_LISP ("vendor-key-alist", &Vvendor_key_alist,
-    "Alist of vendor-specific X windows key symbols.\n\
+  DEFVAR_LISP ("system-key-alist", &Vsystem_key_alist,
+    "Alist of system-specific X windows key symbols.\n\
 Each element should have the form (N . SYMBOL) where N is the\n\
-numeric keysym code (sans the \"vendor-specific\" bit 1<<28)\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 ()