(display_locked): New var to indicate when we're in the run state.
[bpt/emacs.git] / src / keyboard.c
index affd373..5680040 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,95 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -22,7 +22,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <config.h>
 #include <stdio.h>
-#undef NULL
 #include "termchar.h"
 #include "termopts.h"
 #include "lisp.h"
@@ -51,6 +50,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 +71,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 */
@@ -87,6 +94,14 @@ struct backtrace
     char evalargs;
   };
 
+#ifdef MULTI_PERDISPLAY
+PERDISPLAY *current_perdisplay;
+PERDISPLAY *all_perdisplays;
+int display_locked;
+#else
+PERDISPLAY the_only_perdisplay;
+#endif
+
 /* Non-nil disable property on a command means
    do not execute it; call disabled-command-hook's value instead.  */
 Lisp_Object Qdisabled, Qdisabled_command_hook;
@@ -123,6 +138,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 +180,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 +200,7 @@ Lisp_Object last_nonmenu_event;
 Lisp_Object last_input_char;
 
 /* If not Qnil, a list of objects to be read as subsequent command input.  */
-Lisp_Object unread_command_events;
+Lisp_Object Vunread_command_events;
 
 /* If not -1, an event to be read as subsequent command input.  */
 int unread_command_char;
@@ -235,19 +256,8 @@ Lisp_Object this_command;
 /* The value of point when the last command was executed.  */
 int last_point_position;
 
-#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
-   generate switch-frame events.  This may be cleared by functions
-   like Fselect_frame, to make sure that a switch-frame event is
-   generated by the next character.  */
-Lisp_Object internal_last_event_frame;
-
-/* 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 buffer that was current when the last command was started.  */
+Lisp_Object last_point_position_buffer;
 
 /* The timestamp of the last input event we received from the X server.
    X Windows wants this for selection ownership.  */
@@ -287,6 +297,14 @@ 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;
+Lisp_Object Qdeferred_action_function;
+
 /* File in which we write all commands we read.  */
 FILE *dribble;
 
@@ -340,24 +358,22 @@ 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
-   dequeue a non-hook event, we increment kbd_read_count.  We say that
-   there is input available iff the two counters are not equal.
+   enqueue a non-hook event, we increment kbd_store_ptr.  When we
+   dequeue a non-hook event, we increment kbd_fetch_ptr.  We say that
+   there is input available iff the two pointers are not equal.
 
    Why not just have a flag set and cleared by the enqueuing and
    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
@@ -365,20 +381,15 @@ static int do_mouse_tracking;
    call mouse_position_hook to get the promised position, so don't set
    it unless you're prepared to substantiate the claim!  */
 int mouse_moved;
-
-/* True iff there is an event in kbd_buffer, or if mouse tracking is
-   enabled and there is a new mouse position in the mouse movement
-   buffer.  Note that if this is false, that doesn't mean that there
-   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))
-
+#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;
@@ -416,6 +427,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;
@@ -467,16 +480,6 @@ static Lisp_Object make_lispy_switch_frame ();
 /* > 0 if we are to echo keystrokes.  */
 static int echo_keystrokes;
 
-/* Nonzero means echo each character as typed.  */
-static int immediate_echo;
-
-/* The text we're echoing in the modeline - partial key sequences,
-   usually.  '\0'-terminated.  This really shouldn't have a fixed size.  */
-static char echobuf[300];
-
-/* Where to append more text to echobuf if we want to.  */
-static char *echoptr;
-
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
@@ -492,11 +495,14 @@ 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';
+
+  if (len > ECHOBUFSIZE - 4)
+    len = ECHOBUFSIZE - 4;
+  bcopy (str, current_perdisplay->echobuf, len);
+  current_perdisplay->echoptr = current_perdisplay->echobuf + len;
+  *current_perdisplay->echoptr = '\0';
+
+  current_perdisplay->echo_after_prompt = len;
 
   echo ();
 }
@@ -510,40 +516,42 @@ echo_char (c)
 {
   extern char *push_key_description ();
 
-  if (immediate_echo)
+  if (current_perdisplay->immediate_echo)
     {
-      char *ptr = echoptr;
+      char *ptr = current_perdisplay->echoptr;
       
-      if (ptr != echobuf)
+      if (ptr != current_perdisplay->echobuf)
        *ptr++ = ' ';
 
       /* 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)
+         if (ptr - current_perdisplay->echobuf > ECHOBUFSIZE - 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)
+         if (((ptr - current_perdisplay->echobuf) + name->size + 4)
+             > ECHOBUFSIZE)
            return;
          bcopy (name->data, ptr, name->size);
          ptr += name->size;
        }
 
-      if (echoptr == echobuf && EQ (c, Vhelp_char))
+      if (current_perdisplay->echoptr == current_perdisplay->echobuf
+         && EQ (c, Vhelp_char))
        {
          strcpy (ptr, " (Type ? for further options)");
          ptr += strlen (ptr);
        }
 
       *ptr = 0;
-      echoptr = ptr;
+      current_perdisplay->echoptr = ptr;
 
       echo ();
     }
@@ -554,16 +562,21 @@ echo_char (c)
 
 echo_dash ()
 {
-  if (!immediate_echo && echoptr == echobuf)
+  if (!current_perdisplay->immediate_echo
+      && current_perdisplay->echoptr == current_perdisplay->echobuf)
+    return;
+  /* Do nothing if we just printed a prompt.  */
+  if (current_perdisplay->echo_after_prompt
+      == current_perdisplay->echoptr - current_perdisplay->echobuf)
     return;
   /* Do nothing if not echoing at all.  */
-  if (echoptr == 0)
+  if (current_perdisplay->echoptr == 0)
     return;
 
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
-  echoptr[0] = '-';
-  echoptr[1] = 0;
+  current_perdisplay->echoptr[0] = '-';
+  current_perdisplay->echoptr[1] = 0;
 
   echo ();
 }
@@ -573,18 +586,24 @@ echo_dash ()
 
 echo ()
 {
-  if (!immediate_echo)
+  if (!current_perdisplay->immediate_echo)
     {
       int i;
-      immediate_echo = 1;
+      current_perdisplay->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 ();
     }
 
   echoing = 1;
-  message1 (echobuf);
+  message1_nolog (current_perdisplay->echobuf);
   echoing = 0;
 
   if (waiting_for_input && !NILP (Vquit_flag))
@@ -595,8 +614,9 @@ echo ()
 
 cancel_echoing ()
 {
-  immediate_echo = 0;
-  echoptr = echobuf;
+  current_perdisplay->immediate_echo = 0;
+  current_perdisplay->echoptr = current_perdisplay->echobuf;
+  current_perdisplay->echo_after_prompt = -1;
 }
 
 /* Return the length of the current echo string.  */
@@ -604,7 +624,7 @@ cancel_echoing ()
 static int
 echo_length ()
 {
-  return echoptr - echobuf;
+  return current_perdisplay->echoptr - current_perdisplay->echobuf;
 }
 
 /* Truncate the current echo message to its first LEN chars.
@@ -615,8 +635,8 @@ static void
 echo_truncate (len)
      int len;
 {
-  echobuf[len] = '\0';
-  echoptr = echobuf + len;
+  current_perdisplay->echobuf[len] = '\0';
+  current_perdisplay->echoptr = current_perdisplay->echobuf + len;
   truncate_echo_area (len);
 }
 
@@ -663,10 +683,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\
@@ -706,6 +736,30 @@ recursive_edit_unwind (buffer)
 Lisp_Object
 cmd_error (data)
      Lisp_Object data;
+{
+  Vstandard_output = Qt;
+  Vstandard_input = Qt;
+  Vexecuting_macro = Qnil;
+  if (!current_perdisplay)
+    abort ();
+  current_perdisplay->Vprefix_arg = Qnil;
+  cancel_echoing ();
+  cmd_error_internal (data, 0);
+
+  Vquit_flag = Qnil;
+
+  Vinhibit_quit = Qnil;
+#ifdef MULTI_PERDISPLAY
+  current_perdisplay = 0;
+  display_locked = 0;
+#endif
+
+  return make_number (0);
+}
+
+cmd_error_internal (data, context)
+     Lisp_Object data;
+     char *context;
 {
   Lisp_Object errmsg, tail, errname, file_error;
   Lisp_Object stream;
@@ -714,9 +768,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
@@ -732,6 +783,9 @@ cmd_error (data)
       stream = Qt;
     }
 
+  if (context != 0)
+    write_string_1 (context, -1, stream);
+
   errname = Fcar (data);
 
   if (EQ (errname, Qerror))
@@ -761,7 +815,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);
@@ -784,11 +838,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 ();
@@ -887,6 +936,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 ()
@@ -900,11 +950,14 @@ command_loop_1 ()
   int no_direct;
   int prev_modiff;
   struct buffer *prev_buffer;
+#ifdef MULTI_PERDISPLAY
+  PERDISPLAY *outer_perdisplay = current_perdisplay;
+#endif
 
-  Vprefix_arg = Qnil;
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
-  cancel_echoing ();
+  if (current_perdisplay)
+    cancel_echoing ();
 
   nonundocount = 0;
   no_redisplay = 0;
@@ -912,28 +965,19 @@ command_loop_1 ()
 
   /* Make sure this hook runs after commands that get errors and
      throw to top level.  */
-  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-    {
-      /* If we get an error during the post-command-hook,
-        cause post-command-hook to be nil.  */
-      Vcommand_hook_internal = Vpost_command_hook;
-      Vpost_command_hook = Qnil;
+  /* Note that the value cell will never directly contain nil
+     if the symbol is a local variable.  */
+  if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+    safe_run_hooks (Qpost_command_hook);
 
-      call1 (Vrun_hooks, Qcommand_hook_internal);
-      
-      Vpost_command_hook = Vcommand_hook_internal;
-    }
+  if (!NILP (Vdeferred_action_list))
+    call0 (Vdeferred_action_function);
 
   /* Do this after running Vpost_command_hook, for consistency.  */
   last_command = this_command;
 
   while (1)
     {
-      /* Install chars successfully executed in kbd macro.  */
-
-      if (defining_kbd_macro && NILP (Vprefix_arg))
-       finalize_kbd_macro_chars ();
-
       /* Make sure the current window's buffer is selected.  */
       if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
        set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
@@ -965,12 +1009,12 @@ 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);
            }
        }
 
 #ifdef C_ALLOCA
-         alloca (0);           /* Cause a garbage collection now */
+      alloca (0);              /* Cause a garbage collection now */
                                /* Since we can free the most stuff here.  */
 #endif /* C_ALLOCA */
 
@@ -980,7 +1024,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
@@ -992,7 +1036,7 @@ command_loop_1 ()
        call0 (Qrecompute_lucid_menubar);
 
       /* Read next key sequence; i gets its length.  */
-      i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
+      i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0], Qnil, 0);
 
       ++num_input_keys;
 
@@ -1007,7 +1051,7 @@ command_loop_1 ()
        {
          cancel_echoing ();
          this_command_key_count = 0;
-         continue;
+         goto finalize;
        }
 
       last_command_char = keybuf[i - 1];
@@ -1032,27 +1076,21 @@ command_loop_1 ()
         cases identified below that set no_redisplay to 1.
         (actually, there's currently no way to prevent the redisplay,
         and no_redisplay is ignored.
-        Perhaps someday we will really implement it.  */
+        Perhaps someday we will really implement it.)  */
       no_redisplay = 0;
 
       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) && !NILP (Vrun_hooks))
-       {
-         /* If we get an error during the pre-command-hook,
-            cause pre-command-hook to be nil.  */
-         Vcommand_hook_internal = Vpre_command_hook;
-         Vpre_command_hook = Qnil;
-
-         call1 (Vrun_hooks, Qcommand_hook_internal);
-
-         Vpre_command_hook = Vcommand_hook_internal;
-       }
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpre_command_hook);
 
       if (NILP (this_command))
        {
@@ -1060,29 +1098,31 @@ command_loop_1 ()
          bitch_at_user ();
          defining_kbd_macro = 0;
          update_mode_lines = 1;
-         Vprefix_arg = Qnil;
+         current_perdisplay->Vprefix_arg = Qnil;
 
        }
       else
        {
-         if (NILP (Vprefix_arg) && ! no_direct)
+         if (NILP (current_perdisplay->Vprefix_arg) && ! no_direct)
            {
              /* Recognize some common commands in common situations and
                 do them directly.  */
-             if (EQ (this_command, Qforward_char) && point < ZV)
+             if (EQ (this_command, Qforward_char) && PT < ZV)
                {
                   struct Lisp_Vector *dp
                    = window_display_table (XWINDOW (selected_window));
-                 lose = FETCH_CHAR (point);
-                 SET_PT (point + 1);
+                 lose = FETCH_CHAR (PT);
+                 SET_PT (PT + 1);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
-                         && XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1)
+                         ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
+                          : (NILP (DISP_CHAR_VECTOR (dp, lose))
+                             && (lose >= 0x20 && lose < 0x7f)))
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
-                         == point - 1)
+                         == PT - 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
@@ -1090,20 +1130,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 ()
@@ -1113,12 +1155,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)
                        {
@@ -1127,22 +1170,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 <= SAVE_MODIFF
+                         || windows_or_buffers_changed
+                         || !EQ (current_buffer->selective_display, Qnil)
+                         || detect_input_pending ()
+                         || !NILP (Vexecuting_macro));
+                 value = internal_self_insert (c, 0);
+                 if (value)
+                   lose = 1;
+                 if (value == 2)
+                   nonundocount = 0;
+
+                 if (!lose
+                     && (PT == ZV || FETCH_CHAR (PT) == '\n'))
                    {
                      struct Lisp_Vector *dp
                        = window_display_table (XWINDOW (selected_window));
@@ -1153,12 +1197,21 @@ command_loop_1 ()
                          Lisp_Object obj;
 
                          obj = DISP_CHAR_VECTOR (dp, lose);
-                         if (XTYPE (obj) == Lisp_Vector
-                             && XVECTOR (obj)->size == 1
-                             && (XTYPE (obj = XVECTOR (obj)->contents[0])
-                                 == Lisp_Int))
-                           no_redisplay =
-                             direct_output_for_insert (XINT (obj));
+                         if (NILP (obj))
+                           {
+                             /* Do it only for char codes
+                                that by default display as themselves.  */
+                             if (lose >= 0x20 && lose <= 0x7e)
+                               no_redisplay = direct_output_for_insert (lose);
+                           }
+                         else if (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
                        {
@@ -1173,24 +1226,20 @@ command_loop_1 ()
          /* Here for a command that isn't executed directly */
 
          nonundocount = 0;
-         if (NILP (Vprefix_arg))
+         if (NILP (current_perdisplay->Vprefix_arg))
            Fundo_boundary ();
          Fcommand_execute (this_command, Qnil);
 
        }
     directly_done: ;
 
-      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-       {
-         /* If we get an error during the post-command-hook,
-            cause post-command-hook to be nil.  */
-         Vcommand_hook_internal = Vpost_command_hook;
-         Vpost_command_hook = Qnil;
+      /* 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))
+       safe_run_hooks (Qdeferred_action_function);
 
       /* If there is a prefix argument,
         1) We don't want last_command to be ``universal-argument''
@@ -1201,7 +1250,7 @@ command_loop_1 ()
         3) we want to leave this_command_key_count non-zero, so that
         read_char will realize that it is re-reading a character, and
         not echo it a second time.  */
-      if (NILP (Vprefix_arg))
+      if (NILP (current_perdisplay->Vprefix_arg))
        {
          last_command = this_command;
          cancel_echoing ();
@@ -1218,8 +1267,40 @@ command_loop_1 ()
          else if (current_buffer != prev_buffer || MODIFF != prev_modiff)
            call1 (Vrun_hooks, intern ("activate-mark-hook"));
        }
+
+    finalize:
+      /* Install chars successfully executed in kbd macro.  */
+
+      if (defining_kbd_macro && NILP (current_perdisplay->Vprefix_arg))
+       finalize_kbd_macro_chars ();
+
+#ifdef MULTI_PERDISPLAY
+      current_perdisplay = outer_perdisplay;
+      display_locked = (current_perdisplay != 0);
+#endif
     }
 }
+
+/* If we get an error while running the hook, cause the hook variable
+   to be nil.  Also inhibit quits, so that C-g won't cause the hook
+   to mysteriously evaporate.  */
+static void
+safe_run_hooks (hook)
+     Lisp_Object hook;
+{
+  Lisp_Object value;
+  int count = specpdl_ptr - specpdl;
+  specbind (Qinhibit_quit, Qt);
+
+  /* We read and set the variable with functions,
+     in case it's buffer-local.  */
+  value = Vcommand_hook_internal = Fsymbol_value (hook);
+  Fset (hook, Qnil);
+  call1 (Vrun_hooks, Qcommand_hook_internal);
+  Fset (hook, value);
+
+  unbind_to (count, Qnil);
+}
 \f
 /* Number of seconds between polling for input.  */
 int polling_period;
@@ -1227,14 +1308,17 @@ 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.  */
 
 SIGTYPE
-input_poll_signal ()
+input_poll_signal (signalnum)  /* If we don't have an argument, */
+     int signalnum;            /* some compilers complain in signal calls. */
 {
   if (interrupt_input_blocked == 0
       && !waiting_for_input)
@@ -1264,6 +1348,18 @@ start_polling ()
 #endif
 }
 
+/* Nonzero if we are using polling to handle input asynchronously.  */
+
+int
+input_polling_used ()
+{
+#ifdef POLL_FOR_INPUT
+  return read_socket_hook && !interrupt_input;
+#else
+  return 0;
+#endif
+}
+
 /* Turn off polling.  */
 
 stop_polling ()
@@ -1301,6 +1397,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
@@ -1345,6 +1460,11 @@ make_ctrl_char (c)
 
 Lisp_Object print_help ();
 static Lisp_Object kbd_buffer_get_event ();
+static void record_char ();
+
+#ifdef MULTI_PERDISPLAY
+static jmp_buf wrong_display_jmpbuf;
+#endif
 
 /* read a character from the keyboard; call the redisplay if needed */
 /* commandflag 0 means do not do auto-saving, but do do redisplay.
@@ -1374,11 +1494,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;
@@ -1388,7 +1511,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)
@@ -1410,7 +1533,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         internal_last_event_frame after each command is read, but
         events read from a macro should never cause a new frame to be
         selected. */
-      Vlast_event_frame = internal_last_event_frame = Qmacro;
+      if (!current_perdisplay)
+       abort ();
+      current_perdisplay->internal_last_event_frame = Qmacro;
+      current_perdisplay->Vlast_event_frame = Qmacro;
 #endif
 
       /* Exit the macro if we are at the end.
@@ -1419,14 +1545,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++;
 
@@ -1443,7 +1569,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.  */
@@ -1456,10 +1585,12 @@ 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);
-      Vlast_event_frame = internal_last_event_frame;
+      XSETFRAME (current_perdisplay->internal_last_event_frame,
+                selected_frame);
+      current_perdisplay->Vlast_event_frame
+       = current_perdisplay->internal_last_event_frame;
 #endif
       /* If we report the quit char as an event,
         don't do so more than once.  */
@@ -1470,7 +1601,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
-  if (echo_area_glyphs && *echo_area_glyphs && echo_area_glyphs != echobuf)
+  if (echo_area_glyphs && *echo_area_glyphs
+      && echo_area_glyphs != current_perdisplay->echobuf)
     cancel_echoing ();
   else
     /* If already echoing, continue.  */
@@ -1482,16 +1614,25 @@ 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,
      start echoing if enough time elapses.  */
-  if (minibuf_level == 0 && !immediate_echo && this_command_key_count > 0
+  if (minibuf_level == 0 && !current_perdisplay->immediate_echo
+      && this_command_key_count > 0
       && ! noninteractive
       && echo_keystrokes > 0
       && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
@@ -1521,15 +1662,20 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       jmp_buf temp;
       save_getcjmp (temp);
       Fdo_auto_save (Qnil, Qnil);
+      /* Hooks can actually change some buffers in auto save.  */
+      redisplay ();
       restore_getcjmp (temp);
     }
 
   /* 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,
@@ -1551,7 +1697,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;
@@ -1569,31 +1715,83 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
                 consing going on to make it worthwhile.  */
              if (!detect_input_pending ()
                  && consing_since_gc > gc_cons_threshold / 2)
-               {
-                 Fgarbage_collect ();
-                 /* prepare_menu_bars isn't safe here, but it should
-                    also be unnecessary.  */
-                 redisplay ();
-               }
+               Fgarbage_collect ();
+             /* prepare_menu_bars isn't safe here, but it should
+                also be unnecessary.  */
+             redisplay ();
            }
        }
     }
 
-  /* Actually read a character, waiting if necessary.  */
-  while (NILP (c))
+  if (NILP (c))
     {
-      c = kbd_buffer_get_event ();
-      if (!NILP (c))
-       break;
-      if (commandflag >= 0 && !input_pending && !detect_input_pending ())
-       redisplay ();
-    }
+      PERDISPLAY *perd;
+      /* Check for something on one of the side queues.  Give priority to
+        the current display, but if we're not locked, then check the other
+        displays as well.  */
+      if (current_perdisplay && CONSP (current_perdisplay->kbd_queue))
+       perd = current_perdisplay;
+      else if (!display_locked)
+       {
+         for (perd = all_perdisplays; perd; perd = perd->next_perdisplay)
+           if (CONSP (perd->kbd_queue))
+             break;
+       }
+      else
+       perd = 0;
 
+      /* If we found something on a side queue, use that.
+        Otherwise, read from the main queue, and if that gives us
+        something we can't use yet, put it on the side queue and
+        try again.  */
+      if (perd)
+       {
+         c = XCONS (perd->kbd_queue)->car;
+         perd->kbd_queue = XCONS (perd->kbd_queue)->cdr;
+       }
+      else
+       {
+       wrong_display:
+         /* Actually read a character, waiting if necessary.  */
+         while (c = kbd_buffer_get_event (&perd), NILP (c))
+           {
+             if (commandflag >= 0
+                 && !input_pending && !detect_input_pending ())
+               {
+                 prepare_menu_bars ();
+                 redisplay ();
+               }
+           }
+         if (display_locked && perd != current_perdisplay)
+           {
+             Lisp_Object *tailp = &perd->kbd_queue;
+             while (CONSP (*tailp))
+               tailp = &XCONS (*tailp)->cdr;
+             if (!NILP (*tailp))
+               abort ();
+             *tailp = Fcons (c, Qnil);
+             goto wrong_display;
+           }
+       }
+#ifdef MULTI_PERDISPLAY
+      if (!current_perdisplay)
+       current_perdisplay = perd;
+      if (perd != current_perdisplay)
+       {
+         /* We shouldn't get here if we were locked onto one display!  */
+         if (display_locked)
+           abort ();
+         perd->kbd_queue = Fcons (c, perd->kbd_queue);
+         current_perdisplay = perd;
+         longjmp (wrong_display_jmpbuf, 1);
+       }
+#endif
+    }
   /* 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)
@@ -1613,68 +1811,75 @@ 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;
+      Lisp_Object posn;
 
-         /* If it's a structured event, take the event header.  */
-         dribblee = EVENT_HEAD (c);
+      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.  */
-  if (! (EVENT_HAS_PARAMETERS (c)
-        && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+  /* Don't echo mouse motion events.  */
+  if (echo_keystrokes
+      && ! (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;
@@ -1690,13 +1895,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 ();
@@ -1706,18 +1911,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;
 }
 
@@ -1739,16 +1996,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 = old_value;
+  if (NILP (old_value))
     {
-      do_mouse_tracking = 0;
-
       /* Redisplay may have been preempted because there was input
         available, and it assumes it will be called again after the
         input has been processed.  If the only input available was
@@ -1774,14 +2033,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
@@ -1794,7 +2057,13 @@ Normally, mouse motion is ignored.")
 static int
 readable_events ()
 {
-  return ! EVENT_QUEUES_EMPTY;
+  if (kbd_fetch_ptr != kbd_store_ptr)
+    return 1;
+#ifdef HAVE_MOUSE
+  if (FRAMEP (do_mouse_tracking) && mouse_moved)
+    return 1;
+#endif
+  return 0;
 }
 
 /* Set this for debugging, to have a way to get out */
@@ -1831,13 +2100,14 @@ kbd_buffer_store_event (event)
             will set Vlast_event_frame again, so this is safe to do.  */
          {
            Lisp_Object focus;
+           PERDISPLAY *perd;
 
            focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
            if (NILP (focus))
-             internal_last_event_frame = event->frame_or_window;
-           else
-             internal_last_event_frame = focus;
-           Vlast_event_frame = internal_last_event_frame;
+             focus = event->frame_or_window;
+           perd = get_perdisplay (XFRAME (focus));
+           perd->internal_last_event_frame = focus;
+           perd->Vlast_event_frame = focus;
          }
 #endif
 
@@ -1862,23 +2132,24 @@ kbd_buffer_store_event (event)
      Discard the event if it would fill the last slot.  */
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
-      kbd_store_ptr->kind = event->kind;
+      volatile struct input_event *sp = kbd_store_ptr;
+      sp->kind = event->kind;
       if (event->kind == selection_request_event)
        {
          /* We must not use the ordinary copying code for this case,
             since `part' is an enum and copying it might not copy enough
             in this case.  */
-         bcopy (event, kbd_store_ptr, sizeof (*event));
+         bcopy (event, (char *) sp, sizeof (*event));
        }
       else
        {
-         kbd_store_ptr->code = event->code;
-         kbd_store_ptr->part = event->part;
-         kbd_store_ptr->frame_or_window = event->frame_or_window;
-         kbd_store_ptr->modifiers = event->modifiers;
-         kbd_store_ptr->x = event->x;
-         kbd_store_ptr->y = event->y;
-         kbd_store_ptr->timestamp = event->timestamp;
+         sp->code = event->code;
+         sp->part = event->part;
+         sp->frame_or_window = event->frame_or_window;
+         sp->modifiers = event->modifiers;
+         sp->x = event->x;
+         sp->y = event->y;
+         sp->timestamp = event->timestamp;
        }
       (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_store_ptr
                                                      - kbd_buffer]
@@ -1895,7 +2166,7 @@ kbd_buffer_store_event (event)
    We always read and discard one event.  */
 
 static Lisp_Object
-kbd_buffer_get_event ()
+kbd_buffer_get_event (PERDISPLAY **perdp)
 {
   register int c;
   Lisp_Object obj;
@@ -1903,15 +2174,20 @@ kbd_buffer_get_event ()
   if (noninteractive)
     {
       c = getchar ();
-      XSET (obj, Lisp_Int, c);
+      XSETINT (obj, c);
+      *perdp = all_perdisplays;  /* There'd better be exactly one!  */
       return obj;
     }
 
   /* Wait until there is input available.  */
   for (;;)
     {
-      if (!EVENT_QUEUES_EMPTY)
+      if (kbd_fetch_ptr != kbd_store_ptr)
        break;
+#ifdef HAVE_MOUSE
+      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+       break;
+#endif
 
       /* If the quit flag is set, then read_char will return
         quit_char, so that counts as "available input."  */
@@ -1928,17 +2204,22 @@ kbd_buffer_get_event ()
 #ifdef SIGIO
       gobble_input (0);
 #endif /* SIGIO */
-      if (EVENT_QUEUES_EMPTY)
-       {
-         Lisp_Object minus_one;
+      if (kbd_fetch_ptr != kbd_store_ptr)
+       break;
+#ifdef HAVE_MOUSE
+      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+       break;
+#endif
+      {
+       Lisp_Object minus_one;
 
-         XSET (minus_one, Lisp_Int, -1);
-         wait_reading_process_input (0, 0, minus_one, 1);
+       XSETINT (minus_one, -1);
+       wait_reading_process_input (0, 0, minus_one, 1);
 
-         if (!interrupt_input && EVENT_QUEUES_EMPTY)
-           /* Pass 1 for EXPECT since we just waited to have input.  */
-           read_avail_input (1);
-       }
+       if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
+         /* Pass 1 for EXPECT since we just waited to have input.  */
+         read_avail_input (1);
+      }
 #endif /* not VMS */
     }
 
@@ -1955,6 +2236,18 @@ kbd_buffer_get_event ()
 
       last_event_timestamp = event->timestamp;
 
+      {
+       Lisp_Object frame;
+       frame = event->frame_or_window;
+       if (CONSP (frame))
+         frame = XCONS (frame)->car;
+       else if (WINDOWP (frame))
+         frame = WINDOW_FRAME (XWINDOW (frame));
+       if (!FRAMEP (frame))
+         abort ();
+       *perdp = get_perdisplay (XFRAME (frame));
+      }
+
       obj = Qnil;
 
       /* These two kinds of events get special handling
@@ -1963,8 +2256,12 @@ kbd_buffer_get_event ()
       if (event->kind == selection_request_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_request (event);
+         struct input_event copy = *event;
+         /* Remove it from the buffer before processing it,
+            since otherwise swallow_events will see it
+            and process it again.  */
          kbd_fetch_ptr = event + 1;
+         x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -1986,32 +2283,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 cdr of the frame_or_window slot.  */
+         if (!CONSP (event->frame_or_window))
+           abort ();
+         obj = XCONS (event->frame_or_window)->cdr;
+         kbd_fetch_ptr = event + 1;
+       }
       else if (event->kind == buffer_switch_event)
        {
          /* The value doesn't matter here; only the type is tested.  */
-         XSET (obj, Lisp_Buffer, current_buffer);
+         XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
       /* Just discard these, by returning nil.
@@ -2029,17 +2332,17 @@ kbd_buffer_get_event ()
          Lisp_Object focus;
 
          frame = event->frame_or_window;
-         if (XTYPE (frame) == Lisp_Window)
+         if (WINDOWP (frame))
            frame = WINDOW_FRAME (XWINDOW (frame));
 
          focus = FRAME_FOCUS_FRAME (XFRAME (frame));
          if (! NILP (focus))
            frame = focus;
 
-         if (! EQ (frame, internal_last_event_frame)
+         if (! EQ (frame, (*perdp)->internal_last_event_frame)
              && XFRAME (frame) != selected_frame)
            obj = make_lispy_switch_frame (frame);
-         internal_last_event_frame = frame;
+         (*perdp)->internal_last_event_frame = frame;
 #endif /* MULTI_FRAME */
 
          /* If we didn't decide to make a switch-frame event, go ahead
@@ -2051,22 +2354,30 @@ kbd_buffer_get_event ()
 
              /* Wipe out this event, to catch bugs.  */
              event->kind = no_event;
-             (XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer]
-              = Qnil);
+             XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer] = Qnil;
 
              kbd_fetch_ptr = event + 1;
            }
        }
     }
+#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;
 
+      if (!current_perdisplay)
+       abort ();
+
+      *perdp = current_perdisplay;
+      /* 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;
@@ -2075,26 +2386,27 @@ 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 = FRAME_FOCUS_FRAME (f);
          if (NILP (frame))
-           XSET (frame, Lisp_Frame, f);
+           XSETFRAME (frame, f);
 
-         if (! EQ (frame, internal_last_event_frame)
+         if (! EQ (frame, (*perdp)->internal_last_event_frame)
              && XFRAME (frame) != selected_frame)
            obj = make_lispy_switch_frame (frame);
-         internal_last_event_frame = frame;
+         (*perdp)->internal_last_event_frame = frame;
        }
+#endif
 
       /* 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
     }
+#endif /* HAVE_MOUSE */
   else
     /* We were promised by the above while loop that there was
        something for us to read!  */
@@ -2103,7 +2415,7 @@ kbd_buffer_get_event ()
   input_pending = readable_events ();
 
 #ifdef MULTI_FRAME
-  Vlast_event_frame = internal_last_event_frame;
+  (*perdp)->Vlast_event_frame = (*perdp)->internal_last_event_frame;
 #endif
 
   return (obj);
@@ -2130,8 +2442,10 @@ swallow_events ()
       if (event->kind == selection_request_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_request (event);
+         struct input_event copy;
+         copy = *event;
          kbd_fetch_ptr = event + 1;
+         x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -2304,7 +2618,7 @@ static char *lispy_function_keys[] =
     "help",
     "break",                   /* 0xff6b */
 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, "backtab", 0,
     0,                         /* 0xff76 */
     0, 0, 0, 0, 0, 0, 0, 0, "kp-numlock",      /* 0xff7f */
     "kp-space",                        /* 0xff80 */    /* IsKeypadKey */
@@ -2317,8 +2631,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",
@@ -2404,15 +2729,12 @@ make_lispy_event (event)
 {
   int i;
 
-#ifdef SWITCH_ENUM_BUG
-  switch ((int) event->kind)
-#else
-  switch (event->kind)
-#endif
+  switch (SWITCH_ENUM_CAST (event->kind))
     {
       /* A simple keystroke.  */
     case ascii_keystroke:
       {
+       Lisp_Object lispy_c;
        int c = event->code & 0377;
        /* Turn ASCII characters into control characters
           when proper.  */
@@ -2426,7 +2748,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
@@ -2464,7 +2787,7 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
-#ifdef MULTI_FRAME
+#if defined (MULTI_FRAME) || defined (HAVE_MOUSE)
       /* A mouse click.  Figure out where it is, decide whether it's 
          a press, click or drag, and build the appropriate structure.  */
     case mouse_click:
@@ -2488,27 +2811,34 @@ make_lispy_event (event)
            Lisp_Object posn;
            int row, column;
 
+           /* Ignore mouse events that were made on frame that
+              have been deleted.  */
+           if (! FRAME_LIVE_P (f))
+             return Qnil;
+
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                                  &column, &row, 0, 0);
+                                  &column, &row, 0, 1);
 
-#ifdef USE_X_TOOLKIT
-           if (FRAME_EXTERNAL_MENU_BAR (f) && XINT (event->y) == -1)
-#else
-           if (row < FRAME_MENU_BAR_LINES (f))
-#endif
+#ifndef USE_X_TOOLKIT
+           /* In the non-toolkit version, clicks on the menu bar
+              are ordinary button events in the event buffer.
+              Distinguish them, and invoke the menu.
+
+              (In the toolkit version, the toolkit handles the menu bar
+              and Emacs doesn't know about it until after the user
+              makes a selection.)  */
+           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
              {
                Lisp_Object items, item;
-
-#ifdef USE_X_TOOLKIT
-               /* The click happened in the menubar.
-                  Look for the menu item selected.  */
-               item = map_event_to_object (event, f);
-
-               XFASTINT (event->y) = 1;
-#else /* not USE_X_TOOLKIT  */
                int hpos;
                int i;
 
+               /* Activate the menu bar on the down event.  If the
+                  up event comes in before the menu code can deal with it,
+                  just ignore it.  */
+               if (! (event->modifiers & down_modifier))
+                 return Qnil;
+
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
                for (i = 0; i < XVECTOR (items)->size; i += 3)
@@ -2525,7 +2855,6 @@ make_lispy_event (event)
                        break;
                      }
                  }
-#endif /* not USE_X_TOOLKIT  */
 
                position
                  = Fcons (event->frame_or_window,
@@ -2536,11 +2865,15 @@ make_lispy_event (event)
 
                return Fcons (item, Fcons (position, Qnil));
              }
+#endif /* not USE_X_TOOLKIT */
 
            window = window_from_coordinates (f, column, row, &part);
 
-           if (XTYPE (window) != Lisp_Window)
-             posn = Qnil;
+           if (!WINDOWP (window))
+             {
+               window = event->frame_or_window;
+               posn = Qnil;
+             }
            else
              {
                int pixcolumn, pixrow;
@@ -2555,9 +2888,9 @@ make_lispy_event (event)
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSET (posn, Lisp_Int,
-                       buffer_posn_from_coords (XWINDOW (window),
-                                                column, row));
+                 XSETINT (posn,
+                          buffer_posn_from_coords (XWINDOW (window),
+                                                   column, row));
              }
 
            position
@@ -2630,12 +2963,12 @@ 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
@@ -2648,18 +2981,19 @@ make_lispy_event (event)
                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
@@ -2693,7 +3027,7 @@ make_lispy_event (event)
                                 Qnil));
        }
       }
-#endif /* MULTI_FRAME */
+#endif /* MULTI_FRAME or HAVE_MOUSE */
 
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
@@ -2701,7 +3035,7 @@ make_lispy_event (event)
     }
 }
 
-#ifdef MULTI_FRAME
+#if defined (MULTI_FRAME) || defined (HAVE_MOUSE)
 
 static Lisp_Object
 make_lispy_movement (frame, bar_window, part, x, y, time)
@@ -2711,6 +3045,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
      Lisp_Object x, y;
      unsigned long time;
 {
+#ifdef MULTI_FRAME
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
@@ -2729,20 +3064,27 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 
   /* Or is it an ordinary mouse movement?  */
   else
+#endif /* MULTI_FRAME */
     {
       int area;
       Lisp_Object window;
       Lisp_Object posn;
       int column, row;
 
-      pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
-
+#ifdef MULTI_FRAME
       if (frame)
-       window = window_from_coordinates (frame, column, row, &area);
+#else
+      if (1)
+#endif
+       {
+         /* It's in a frame; which window on that frame?  */
+         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
+         window = window_from_coordinates (frame, column, row, &area);
+       }
       else
        window = Qnil;
 
-      if (XTYPE (window) == Lisp_Window)
+      if (WINDOWP (window))
        {
          int pixcolumn, pixrow;
          column -= XINT (XWINDOW (window)->left);
@@ -2756,20 +3098,22 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
          else if (area == 2)
            posn = Qvertical_line;
          else
-           XSET (posn, Lisp_Int,
-                 buffer_posn_from_coords (XWINDOW (window), column, row));
+           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,
@@ -2782,7 +3126,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
     }
 }
 
-#endif /* MULTI_FRAME */
+#endif /* neither MULTI_FRAME nor HAVE_MOUSE */
 
 /* Construct a switch frame event.  */
 static Lisp_Object
@@ -3015,7 +3359,7 @@ parse_modifiers (symbol)
 
       if (modifiers & ~((1<<VALBITS) - 1))
        abort ();
-      XFASTINT (mask) = modifiers;
+      XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
 
       /* Cache the parsing results on SYMBOL.  */
@@ -3054,8 +3398,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;
@@ -3071,7 +3415,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,
@@ -3163,11 +3507,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));
@@ -3183,7 +3527,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);
        }
 
@@ -3244,7 +3588,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)
@@ -3260,17 +3604,61 @@ 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;
-  kbd_buffer_store_event (&event);
+
+#ifdef subprocesses
+  /* We don't need a buffer-switch event unless Emacs is waiting for input.
+     The purpose of the event is to make read_key_sequence look up the
+     keymaps again.  If we aren't in read_key_sequence, we don't need one,
+     and the event could cause trouble by messing up (input-pending-p).  */
+  tem = Fwaiting_for_user_input_p ();
+  if (NILP (tem))
+    return;
+#else
+  /* We never need these events if we have no asynchronous subprocesses.  */
+  return;
+#endif
+
+  /* Make sure no interrupt happens while storing the event.  */
+#ifdef SIGIO
+  if (interrupt_input)
+    {
+      SIGMASKTYPE mask;
+      mask = sigblockx (SIGIO);
+      kbd_buffer_store_event (&event);
+      sigsetmask (mask);
+    }
+  else
+#endif
+    {
+      stop_polling ();
+      kbd_buffer_store_event (&event);
+      start_polling ();
+    }
 }
 \f
 #ifndef VMS
@@ -3297,7 +3685,8 @@ 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
@@ -3307,6 +3696,9 @@ read_avail_input (expected)
       int n_to_read;
 
       /* Determine how many characters we should *try* to read.  */
+#ifdef WINDOWSNT
+      return 0;
+#else /* not WINDOWSNT */
 #ifdef MSDOS
       n_to_read = dos_keysns ();
       if (n_to_read == 0)
@@ -3314,7 +3706,7 @@ read_avail_input (expected)
 #else /* not MSDOS */
 #ifdef FIONREAD
       /* Find out how much input is available.  */
-      if (ioctl (0, FIONREAD, &n_to_read) < 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.  */
@@ -3330,12 +3722,13 @@ read_avail_input (expected)
 #if defined(USG) || defined(DGUX)
       /* Read some input if available, but don't wait.  */
       n_to_read = sizeof cbuf;
-      fcntl (fileno (stdin), F_SETFL, O_NDELAY);
+      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.
         NREAD is set to the number of chars read.  */
@@ -3345,7 +3738,7 @@ read_avail_input (expected)
          cbuf[0] = dos_keyread();
          nread = 1;
 #else
-         nread = read (fileno (stdin), cbuf, n_to_read);
+         nread = read (input_fd, cbuf, n_to_read);
 #endif
 #if defined (AIX) && (! defined (aix386) && defined (_BSD))
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
@@ -3355,20 +3748,29 @@ read_avail_input (expected)
          if (nread == 0)
            kill (0, SIGHUP);
 #endif
-         /* Retry the read if it was interrupted.  */
        }
-      while (nread < 0 && (errno == EAGAIN 
+      while (
+            /* We used to retry the read if it was interrupted.
+               But this does the wrong thing when O_NDELAY causes
+               an EAGAIN error.  Does anybody know of a situation
+               where a retry is actually needed?  */
+#if 0
+            nread < 0 && (errno == EAGAIN
 #ifdef EFAULT
                           || errno == EFAULT
 #endif
 #ifdef EBADSLT
                           || errno == EBADSLT
 #endif
-                          ));
+                          )
+#else
+            0
+#endif
+            );
 
 #ifndef FIONREAD
 #if defined (USG) || defined (DGUX)
-      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++)
@@ -3379,10 +3781,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
@@ -3396,7 +3798,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;
     }
 
@@ -3480,7 +3882,7 @@ map_prompt (map)
     {
       register Lisp_Object tem;
       tem = Fcar (map);
-      if (XTYPE (tem) == Lisp_String)
+      if (STRINGP (tem))
        return tem;
       map = Fcdr (map);
     }
@@ -3494,11 +3896,11 @@ static void menu_bar_one_keymap ();
    menu_bar_items and its subroutines, and the current index
    for storing into that vector.  */
 static Lisp_Object menu_bar_items_vector;
-static Lisp_Object menu_bar_items_index;
+static int menu_bar_items_index;
 
 /* Return a vector of menu items for a menu bar, appropriate
    to the current buffer.  Each item has three elements in the vector:
-   KEY STRING nil.
+   KEY STRING MAPLIST.
 
    OLD is an old vector we can optionally reuse, or nil.  */
 
@@ -3550,14 +3952,26 @@ menu_bar_items (old)
   { 
     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]));
@@ -3636,9 +4050,7 @@ menu_bar_items (old)
 }
 \f
 /* Scan one map KEYMAP, accumulating any menu items it defines
-   that have not yet been seen in RESULT.  Return the updated RESULT.
-   *OLD is the frame's old menu bar list; we swipe elts from that
-   to avoid consing.  */
+   in menu_bar_items_vector.  */
 
 static void
 menu_bar_one_keymap (keymap)
@@ -3647,23 +4059,23 @@ menu_bar_one_keymap (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)
+             if (STRINGP (item_string))
                menu_bar_item (key, item_string, Fcdr (binding));
            }
          else if (EQ (binding, Qundefined))
-           menu_bar_item (key, item_string, binding);
+           menu_bar_item (key, Qnil, binding);
        }
-      else if (XTYPE (item) == Lisp_Vector)
+      else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
          int len = XVECTOR (item)->size;
@@ -3671,16 +4083,16 @@ menu_bar_one_keymap (keymap)
          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)
+                 if (STRINGP (item_string))
                    menu_bar_item (key, item_string, Fcdr (binding));
                }
              else if (EQ (binding, Qundefined))
-               menu_bar_item (key, item_string, binding);
+               menu_bar_item (key, Qnil, binding);
            }
        }
     }
@@ -3695,6 +4107,9 @@ menu_bar_item_1 (arg)
   return Qnil;
 }
 
+/* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
+   If there's already an item for KEY, add this DEF to it.  */
+
 static void
 menu_bar_item (key, item_string, def)
      Lisp_Object key, item_string, def;
@@ -3705,7 +4120,7 @@ menu_bar_item (key, item_string, def)
 
   if (EQ (def, Qundefined))
     {
-      /* If a map has an explicit nil as definition,
+      /* If a map has an explicit `undefined' as definition,
         discard any previously made menu bar item.  */
 
       for (i = 0; i < menu_bar_items_index; i += 3)
@@ -3718,12 +4133,16 @@ menu_bar_item (key, item_string, def)
            menu_bar_items_index -= 3;
            return;
          }
+
+      /* If there's no definition for this key yet,
+        just ignore `undefined'.  */
+      return;
     }
 
   /* See if this entry is enabled.  */
   enabled = Qt;
 
-  if (XTYPE (def) == Lisp_Symbol)
+  if (SYMBOLP (def))
     {
       /* No property, or nil, means enable.
         Otherwise, enable if value is not nil.  */
@@ -3739,12 +4158,12 @@ menu_bar_item (key, item_string, def)
   if (NILP (enabled))
     return;
 
-  /* If there's already such an item, don't make another.  */
+  /* Find any existing item for this KEY.  */
   for (i = 0; i < menu_bar_items_index; i += 3)
     if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
       break;
 
-  /* If we did not find this item, add it at the end.  */
+  /* If we did not find this KEY, add it at the end.  */
   if (i == menu_bar_items_index)
     {
       /* If vector is too small, get a bigger one.  */
@@ -3760,9 +4179,16 @@ menu_bar_item (key, item_string, def)
       /* Add this item.  */
       XVECTOR (menu_bar_items_vector)->contents[i++] = key;
       XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
-      XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
       menu_bar_items_index = i;
     }
+  /* We did find an item for this KEY.  Add DEF to its list of maps.  */
+  else
+    {
+      Lisp_Object old;
+      old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (def, old);
+    }
 }
 \f
 /* Read a character using menus based on maps in the array MAPS.
@@ -3804,6 +4230,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++)
     {
@@ -3816,8 +4249,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))
@@ -3839,8 +4271,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
          /* If we got more than one event, put all but the first
             onto this list to be read later.
             Return just the first event now.  */
-         unread_command_events
-           = nconc2 (XCONS (value)->cdr, unread_command_events);
+         Vunread_command_events
+           = nconc2 (XCONS (value)->cdr, Vunread_command_events);
          value = XCONS (value)->car;
        }
       else if (NILP (value))
@@ -3849,13 +4281,12 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, 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;
@@ -3866,7 +4297,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)
@@ -3929,7 +4360,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.  */
@@ -3944,7 +4375,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.
@@ -4001,16 +4432,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 )
@@ -4033,29 +4464,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]))
@@ -4072,7 +4496,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;
@@ -4088,38 +4512,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++)
@@ -4163,10 +4555,11 @@ follow_key (key, nmaps, current, defs, next, case_converted)
    read_char will return it.  */
 
 static int
-read_key_sequence (keybuf, bufsize, prompt)
+read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last)
      Lisp_Object *keybuf;
      int bufsize;
      Lisp_Object prompt;
+     int dont_downcase_last;
 {
   int count = specpdl_ptr - specpdl;
 
@@ -4191,6 +4584,13 @@ read_key_sequence (keybuf, bufsize, prompt)
      in the current keymaps, or nil where it is not a prefix.  */
   Lisp_Object *submaps;
 
+  /* The local map to start out with at start of key sequence.  */
+  Lisp_Object orig_local_map;
+
+  /* 1 if we have already considered switching to the local-map property
+     of the place where a mouse click occurred.  */
+  int localized_local_map = 0;
+
   /* The index in defs[] of the first keymap that has a binding for
      this key sequence.  In other words, the lowest i such that
      defs[i] is non-nil.  */
@@ -4235,15 +4635,18 @@ read_key_sequence (keybuf, bufsize, prompt)
   Lisp_Object first_event;
 #endif
 
-  struct buffer *starting_buffer;
+  Lisp_Object original_uppercase;
+  int original_uppercase_position = -1;
 
-  /* Nonzero if we found the binding for one of the chars
-     in this key sequence by downcasing it.  */
-  int case_converted = 0;
+  /* Gets around Microsoft compiler limitations.  */
+  int dummyflag = 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;
 
@@ -4265,7 +4668,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 ();
@@ -4288,14 +4691,16 @@ read_key_sequence (keybuf, bufsize, prompt)
                           &junk);
 #endif /* GOBBLE_FIRST_EVENT */
 
+  orig_local_map = get_local_map (PT, current_buffer);
+
   /* We jump here when the key sequence has been thoroughly changed, and
      we need to rescan it starting from the beginning.  When we jump here,
      keybuf[0..mock_input] holds the sequence we should reread.  */
  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
@@ -4327,7 +4732,7 @@ read_key_sequence (keybuf, bufsize, prompt)
          }
        bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
 #ifdef USE_TEXT_PROPERTIES
-       submaps[nmaps-2] = get_local_map (PT, current_buffer);
+       submaps[nmaps-2] = orig_local_map;
 #else
        submaps[nmaps-2] = current_buffer->keymap;
 #endif
@@ -4358,15 +4763,13 @@ read_key_sequence (keybuf, bufsize, prompt)
             /* 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;
@@ -4410,7 +4813,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.  */
@@ -4418,8 +4822,21 @@ read_key_sequence (keybuf, bufsize, prompt)
        {
          struct buffer *buf = current_buffer;
 
-         key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
-                          &used_mouse_menu);
+         {
+#ifdef MULTI_PERDISPLAY
+           PERDISPLAY *interrupted_perdisplay = current_perdisplay;
+           if (setjmp (wrong_display_jmpbuf))
+             {
+               while (t > 0)
+                 interrupted_perdisplay->kbd_queue
+                   = Fcons (keybuf[--t], interrupted_perdisplay->kbd_queue);
+               mock_input = 0;
+               goto replay_sequence;
+             }
+#endif
+           key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
+                            &used_mouse_menu);
+         }
 
          /* read_char returns t when it shows a menu and the user rejects it.
             Just return -1.  */
@@ -4429,15 +4846,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;
@@ -4446,7 +4866,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;
@@ -4482,7 +4902,7 @@ read_key_sequence (keybuf, bufsize, prompt)
 
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
-             if (XTYPE (posn) == Lisp_Cons)
+             if (CONSP (posn))
                {
                  /* We're looking at the second event of a
                     sequence which we expanded before.  Set
@@ -4496,8 +4916,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;
@@ -4516,13 +4936,40 @@ read_key_sequence (keybuf, bufsize, prompt)
                  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
 
                  set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
+                 orig_local_map = get_local_map (PT, current_buffer);
                  goto replay_sequence;
                }
-             else if (XTYPE (posn) == Lisp_Symbol)
+             /* For a mouse click, get the local text-property keymap
+                of the place clicked on, rather than point.  */
+             if (last_real_key_start == 0 && CONSP (XCONS (key)->cdr)
+                 && ! localized_local_map)
                {
-                 /* Expand mode-line and scroll-bar events into two events:
-                    use posn as a fake prefix key.  */
+                 Lisp_Object map_here, start, pos;
 
+                 localized_local_map = 1;
+                 start = EVENT_START (key);
+                 if (CONSP (start) && CONSP (XCONS (start)->cdr))
+                   {
+                     pos = POSN_BUFFER_POSN (start);
+                     if (INTEGERP (pos))
+                       {
+                         map_here = get_local_map (XINT (pos), current_buffer);
+                         if (!EQ (map_here, orig_local_map))
+                           {
+                             orig_local_map = map_here;
+                             keybuf[t] = key;
+                             mock_input = t + 1;
+
+                             goto replay_sequence;
+                           }
+                       }
+                   }
+               }
+
+             /* Expand mode-line and scroll-bar events into two events:
+                use posn as a fake prefix key.  */
+             if (SYMBOLP (posn))
+               {
                  if (t + 1 >= bufsize)
                    error ("key sequence too long");
                  keybuf[t] = posn;
@@ -4547,7 +4994,9 @@ read_key_sequence (keybuf, bufsize, prompt)
                  goto replay_key;
                }
            }
-         else
+         else if (CONSP (XCONS (key)->cdr)
+                  && CONSP (EVENT_START (key))
+                  && CONSP (XCONS (EVENT_START (key))->cdr))
            {
              Lisp_Object posn;
 
@@ -4576,7 +5025,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
@@ -4593,8 +5042,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                                   nmaps   - first_binding,
                                   submaps + first_binding,
                                   defs    + first_binding,
-                                  submaps + first_binding,
-                                  &case_converted)
+                                  submaps + first_binding)
                       + first_binding);
 
       /* If KEY wasn't bound, we'll try some fallbacks.  */
@@ -4608,10 +5056,13 @@ read_key_sequence (keybuf, bufsize, prompt)
              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;
+             break;
            }
 
-         if (XTYPE (head) == Lisp_Symbol)
+         if (SYMBOLP (head))
            {
              Lisp_Object breakdown;
              int modifiers;
@@ -4636,8 +5087,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
@@ -4696,8 +5149,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                                       nmaps   - local_first_binding,
                                       submaps + local_first_binding,
                                       defs    + local_first_binding,
-                                      submaps + local_first_binding,
-                                      &case_converted)
+                                      submaps + local_first_binding)
                           + local_first_binding);
 
                      /* If that click is bound, go for it.  */
@@ -4724,7 +5176,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;
@@ -4739,14 +5191,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;
@@ -4754,6 +5206,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.  */
@@ -4799,14 +5259,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;
                }
              
@@ -4835,14 +5299,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;
@@ -4871,6 +5335,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
@@ -4893,14 +5359,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;
              }
 
@@ -4912,19 +5383,76 @@ 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)))
+       {
+         original_uppercase = key;
+         original_uppercase_position = t - 1;
+
+         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;
+       }
+      /* If KEY is not defined in any of the keymaps,
+        and cannot be part of a function key or translation,
+        and is a shifted function key,
+        use the corresponding unshifted function key instead.  */
+      if (first_binding == nmaps && ! function_key_possible
+         && ! key_translation_possible
+         && SYMBOLP (key))
+       {
+         Lisp_Object breakdown;
+         int modifiers;
+
+         original_uppercase = key;
+         original_uppercase_position = t - 1;
+
+         breakdown = parse_modifiers (key);
+         modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+         if (modifiers & shift_modifier)
+           {
+             modifiers &= ~shift_modifier;
+             key = apply_modifiers (make_number (modifiers),
+                                    XCONS (breakdown)->car);
+
+             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);
 
+  if (dont_downcase_last && t - 1 == original_uppercase_position)
+    keybuf[t - 1] = original_uppercase;
+
   /* Occasionally we fabricate events, perhaps by expanding something
      according to function-key-map, or by adding a prefix symbol to a
      mouse click in the scroll bar or modeline.  In this cases, return
@@ -4936,7 +5464,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]);
     }
 
@@ -4954,6 +5483,12 @@ First arg PROMPT is a prompt string.  If nil, do not prompt specially.\n\
 Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos\n\
 as a continuation of the previous key.\n\
 \n\
+The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not\n\
+convert the last event to lower case.  (Normally any upper case event\n\
+is converted to lower case if the original event is undefined and the lower\n\
+case equivalent is defined.)  A non-nil value is appropriate for reading\n\
+a key sequence to be defined.\n\
+\n\
 A C-g typed while in this function is treated like any other character,\n\
 and `quit-flag' is not set.\n\
 \n\
@@ -4981,10 +5516,10 @@ sequences, where they wouldn't conflict with ordinary bindings.  See\n\
   (prompt, continue_echo)
 #endif
 
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 2, 0,
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 3, 0,
   0)
-  (prompt, continue_echo)
-     Lisp_Object prompt, continue_echo;
+  (prompt, continue_echo, dont_downcase_last)
+     Lisp_Object prompt, continue_echo, dont_downcase_last;
 {
   Lisp_Object keybuf[30];
   register int i;
@@ -5001,7 +5536,8 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 2, 0,
   if (NILP (continue_echo))
     this_command_key_count = 0;
 
-  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt);
+  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+                        prompt, ! NILP (dont_downcase_last));
 
   if (i == -1)
     {
@@ -5027,11 +5563,12 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
   struct backtrace backtrace;
   extern int debug_on_next_call;
 
-  prefixarg = Vprefix_arg, Vprefix_arg = Qnil;
-  Vcurrent_prefix_arg = prefixarg;
+  prefixarg = current_perdisplay->Vprefix_arg;
+  current_perdisplay->Vprefix_arg = Qnil;
+  current_perdisplay->Vcurrent_prefix_arg = prefixarg;
   debug_on_next_call = 0;
 
-  if (XTYPE (cmd) == Lisp_Symbol)
+  if (SYMBOLP (cmd))
     {
       tem = Fget (cmd, Qdisabled);
       if (!NILP (tem) && !NILP (Vrun_hooks))
@@ -5048,8 +5585,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
@@ -5062,8 +5598,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;
@@ -5100,9 +5635,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
@@ -5135,18 +5670,18 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     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);
   }
 
   UNGCPRO;
 
   function = Fintern (function, Qnil);
-  Vprefix_arg = prefixarg;
+  current_perdisplay->Vprefix_arg = prefixarg;
   this_command = function;
 
   return Fcommand_execute (function, Qt);
@@ -5174,7 +5709,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;
@@ -5216,7 +5751,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;
 }
 
@@ -5229,8 +5764,11 @@ If FILE is nil, close any open dribble file.")
 {
   if (NILP (file))
     {
-      fclose (dribble);
-      dribble = 0;
+      if (dribble)
+       {
+         fclose (dribble);
+         dribble = 0;
+       }
     }
   else
     {
@@ -5248,7 +5786,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 ();
@@ -5270,10 +5808,8 @@ 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.")
@@ -5328,12 +5864,12 @@ On such systems, Emacs starts a subshell instead of suspending.")
 stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
-  register unsigned char *p;
-
 /* stuff_char works only in BSD, versions 4.2 and up.  */
 #ifdef BSD
 #ifndef BSD4_1
-  if (XTYPE (stuffstring) == Lisp_String)
+  register unsigned char *p;
+
+  if (STRINGP (stuffstring))
     {
       register int count;
 
@@ -5344,7 +5880,9 @@ stuff_buffered_input (stuffstring)
       stuff_char ('\n');
     }
   /* Anything we have read ahead, put back for the shell to read.  */
-  while (kbd_fetch_ptr != kbd_store_ptr)
+  /* ?? What should this do when we have multiple keyboards??
+     Should we ignore anything that was typed in at the "wrong" display?  */
+  for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++)
     {
       if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
        kbd_fetch_ptr = kbd_buffer;
@@ -5352,9 +5890,8 @@ stuff_buffered_input (stuffstring)
        stuff_char (kbd_fetch_ptr->code);
       kbd_fetch_ptr->kind = no_event;
       (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_fetch_ptr
-                                                    - kbd_buffer]
+                                                     - kbd_buffer]
        = Qnil);
-      kbd_fetch_ptr++;
     }
   input_pending = 0;
 #endif
@@ -5395,17 +5932,21 @@ clear_waiting_for_input ()
  If  quit-flag  is already non-nil, it stops the job right away.  */
 
 SIGTYPE
-interrupt_signal ()
+interrupt_signal (signalnum)   /* If we don't have an argument, */
+     int signalnum;            /* some compilers complain in signal calls. */
 {
   char c;
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
 
 #ifdef USG
-  /* USG systems forget handlers when they are used;
-     must reestablish each time */
-  signal (SIGINT, interrupt_signal);
-  signal (SIGQUIT, interrupt_signal);
+  if (!read_socket_hook && NILP (Vwindow_system))
+    {
+      /* USG systems forget handlers when they are used;
+        must reestablish each time */
+      signal (SIGINT, interrupt_signal);
+      signal (SIGQUIT, interrupt_signal);
+    }
 #endif /* USG */
 
   cancel_echoing ();
@@ -5509,7 +6050,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
@@ -5518,9 +6059,15 @@ quit_throw_to_read_char ()
     abort ();
 #endif
 #ifdef MULTI_FRAME
-  if (XTYPE (internal_last_event_frame) == Lisp_Frame
-      && XFRAME (internal_last_event_frame) != selected_frame)
-    Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
+  {
+    Lisp_Object frame;
+
+    if (!current_perdisplay)
+      abort ();
+    frame = current_perdisplay->internal_last_event_frame;
+    if (FRAMEP (frame) && XFRAME (frame) != selected_frame)
+      Fhandle_switch_frame (make_lispy_switch_frame (frame));
+  }
 #endif
 
   _longjmp (getcjmp, 1);
@@ -5541,8 +6088,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
@@ -5606,44 +6152,77 @@ 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);
 }
 
 \f
+/*
+ * Set up a perdisplay object with reasonable initial values.
+ */
+void
+init_perdisplay (perd)
+     PERDISPLAY *perd;
+{
+  perd->Vprefix_arg = Qnil;
+  perd->Vcurrent_prefix_arg = Qnil;
+#ifdef MULTI_FRAME
+  /* This means that command_loop_1 won't try to select anything the first
+     time through.  */
+  perd->internal_last_event_frame = Qnil;
+#endif
+  perd->kbd_queue = Qnil;
+  perd->Vlast_event_frame = Qnil;
+  perd->immediate_echo = 0;
+  perd->echoptr = perd->echobuf;
+  perd->echo_after_prompt = -1;
+}
+
+/*
+ * Destroy the contents of a perdisplay object, but not the object itself.
+ * We use this just before deleteing it, or if we're going to initialize
+ * it a second time.
+ */
+void
+wipe_perdisplay (perd)
+     PERDISPLAY *perd;
+{
+  /* Free anything that was malloc'd in init_perdisplay.  */
+  /* Placeholder -- currently no action required.  */
+}
+
 init_keyboard ()
 {
   /* This is correct before outermost invocation of the editor loop */
   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;
+  kbd_buffer_frame_or_window
+    = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
+#ifdef HAVE_MOUSE
+  do_mouse_tracking = Qnil;
+#endif
   input_pending = 0;
 
-#ifdef MULTI_FRAME
-  /* This means that command_loop_1 won't try to select anything the first
-     time through.  */
-  internal_last_event_frame = Qnil;
-  Vlast_event_frame = internal_last_event_frame;
+#ifndef MULTI_PERDISPLAY
+  if (initialized)
+    wipe_perdisplay (&the_only_perdisplay);
+  init_perdisplay (&the_only_perdisplay);
 #endif
 
-  /* If we're running a dumped Emacs, we need to clear out
-     kbd_buffer_frame_or_window, in case some events got into it
-     before we dumped.
-
-     If we're running an undumped Emacs, it hasn't been initialized by
-     syms_of_keyboard yet.  */
   if (initialized)
     Ffillarray (kbd_buffer_frame_or_window, Qnil);
 
-  if (!noninteractive)
+  kbd_buffer_frame_or_window
+    = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
+  if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
     {
       signal (SIGINT, interrupt_signal);
 #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS)
@@ -5651,11 +6230,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.  */
@@ -5695,6 +6275,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 ()
@@ -5723,6 +6306,9 @@ syms_of_keyboard ()
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
+  Qdeferred_action_function = intern ("deferred-action-function");
+  staticpro (&Qdeferred_action_function);
+
   Qcommand_hook_internal = intern ("command-hook-internal");
   staticpro (&Qcommand_hook_internal);
 
@@ -5764,6 +6350,9 @@ syms_of_keyboard ()
   Qactivate_menubar_hook = intern ("activate-menubar-hook");
   staticpro (&Qactivate_menubar_hook);
 
+  Qpolling_period = intern ("polling-period");
+  staticpro (&Qpolling_period);
+
   {
     struct event_head *p;
 
@@ -5806,6 +6395,9 @@ syms_of_keyboard ()
     = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
   staticpro (&kbd_buffer_frame_or_window);
 
+  accent_key_syms = Qnil;
+  staticpro (&accent_key_syms);
+
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
@@ -5820,7 +6412,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);
@@ -5839,7 +6433,7 @@ syms_of_keyboard ()
   DEFVAR_LISP ("last-command-char", &last_command_char,
     "Last input event that was part of a command.");
 
-  DEFVAR_LISP ("last-command-event", &last_command_char,
+  DEFVAR_LISP_NOPRO ("last-command-event", &last_command_char,
     "Last input event that was part of a command.");
 
   DEFVAR_LISP ("last-nonmenu-event", &last_nonmenu_event,
@@ -5851,10 +6445,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,
@@ -5863,12 +6457,20 @@ 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\
 but can be whatever was found in the keymap, or whatever the variable\n\
-`this-command' was set to by that command.");
+`this-command' was set to by that command.\n\
+\n\
+The value `mode-exit' is special; it means that the previous command\n\
+read an event that told it to exit, and it did so and unread that event.\n\
+In other words, the present command is the event that made the previous\n\
+command exit.\n\
+\n\
+The value `kill-region' is special; it means that the previous command\n\
+was a kill command.");
   last_command = Qnil;
 
   DEFVAR_LISP ("this-command", &this_command,
@@ -5887,7 +6489,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.");
@@ -5907,22 +6509,19 @@ 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.");
+    "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\
@@ -5971,16 +6570,16 @@ 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\
 Emacs applies the modifiers of the character stored here to each keyboard\n\
 character it reads.  For example, after evaluating the expression\n\
-    (setq extra-keyboard-modifiers ?\C-x)\n\
+    (setq extra-keyboard-modifiers ?\\C-x)\n\
 all input characters will have the control modifier applied to them.\n\
 \n\
-Note that the character ?\C-@, equivalent to the integer zero, does\n\
+Note that the character ?\\C-@, equivalent to the integer zero, does\n\
 not count as a control character; rather, it counts as a character\n\
 with no modifiers; thus, setting `extra-keyboard-modifiers' to zero\n\
 cancels any modification.");
@@ -5998,11 +6597,21 @@ Buffer modification stores t in this variable.");
   Vcommand_hook_internal = Qnil;
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
-    "Normal hook run before each command is executed.");
+    "Normal hook run before each command is executed.\n\
+While the hook is run, its value is temporarily set to nil\n\
+to avoid an unbreakable infinite loop if a hook function gets an error.\n\
+As a result, a hook function cannot straightforwardly alter the value of\n\
+`pre-command-hook'.  See the Emacs Lisp manual for a way of\n\
+implementing hook functions that alter the set of hook functions.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
-    "Normal hook run after each command is executed.");
+    "Normal hook run after each command is executed.\n\
+While the hook is run, its value is temporarily set to nil\n\
+to avoid an unbreakable infinite loop if a hook function gets an error.\n\
+As a result, a hook function cannot straightforwardly alter the value of\n\
+`post-command-hook'.  See the Emacs Lisp manual for a way of\n\
+implementing hook functions that alter the set of hook functions.");
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
@@ -6020,15 +6629,56 @@ 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_BOOL ("track-mouse", &do_mouse_tracking,
+  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_LISP ("track-mouse", &do_mouse_tracking,
               "*Non-nil means generate motion events for mouse motion.");
+#endif
 
   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 \"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;
+
+  DEFVAR_DISPLAY ("prefix-arg", Vprefix_arg,
+    "The value of the prefix argument for the next editing command.\n\
+It may be a number, or the symbol `-' for just a minus sign as arg,\n\
+or a list whose car is a number for just one or more C-U's\n\
+or nil if no argument has been specified.\n\
+\n\
+You cannot examine this variable to find the argument for this command\n\
+since it has been set to nil by the time you can look.\n\
+Instead, you should use the variable `current-prefix-arg', although\n\
+normally commands can get this prefix argument with (interactive \"P\").");
+
+  DEFVAR_DISPLAY ("current-prefix-arg", Vcurrent_prefix_arg,
+    "The value of the prefix argument for this editing command.\n\
+It may be a number, or the symbol `-' for just a minus sign as arg,\n\
+or a list whose car is a number for just one or more C-U's\n\
+or nil if no argument has been specified.\n\
+This is what `(interactive \"P\")' returns.");
+
+  DEFVAR_DISPLAY ("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'.");
 }
 
 keys_of_keyboard ()