(construct_menu_click, construct_mouse_click):
[bpt/emacs.git] / src / keyboard.c
index 7dd56e9..f09b7fa 100644 (file)
@@ -40,9 +40,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <setjmp.h>
 #include <errno.h>
 
+#ifdef MSDOS
+#include "msdos.h"
+#include <time.h>
+#else /* not MSDOS */
 #ifndef VMS
 #include <sys/ioctl.h>
 #endif
+#endif /* not MSDOS */
 
 #include "syssignal.h"
 #include "systty.h"
@@ -118,7 +123,7 @@ int waiting_for_input;
 /* True while displaying for echoing.   Delays C-g throwing.  */
 static int echoing;
 
-/* Nonzero means C-G should cause immediate error-signal.  */
+/* Nonzero means C-g should cause immediate error-signal.  */
 int immediate_quit;
 
 /* Character to recognize as the help char.  */
@@ -154,6 +159,9 @@ int quit_char;
 extern Lisp_Object current_global_map;
 extern int minibuf_level;
 
+/* If non-nil, this is a map that overrides all other local maps.  */
+Lisp_Object Voverriding_local_map;
+
 /* Current depth in recursive edits.  */
 int command_loop_level;
 
@@ -224,6 +232,9 @@ Lisp_Object last_command;
    instead of the actual command.  */
 Lisp_Object this_command;
 
+/* The value of point when the last command was executed.  */
+int last_point_position;
+
 #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
@@ -274,6 +285,7 @@ Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 /* Hooks to run before and after each command.  */
 Lisp_Object Qpre_command_hook, Qpost_command_hook;
 Lisp_Object Vpre_command_hook, Vpost_command_hook;
+Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
 
 /* File in which we write all commands we read.  */
 FILE *dribble;
@@ -445,7 +457,8 @@ void (*keyboard_init_hook) ();
 static int read_avail_input ();
 static void get_input_pending ();
 static int readable_events ();
-static Lisp_Object read_char_menu_prompt ();
+static Lisp_Object read_char_x_menu_prompt ();
+static Lisp_Object read_char_minibuf_menu_prompt ();
 static Lisp_Object make_lispy_event ();
 static Lisp_Object make_lispy_movement ();
 static Lisp_Object modify_event_symbol ();
@@ -464,6 +477,10 @@ 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;
+
 #define        min(a,b)        ((a)<(b)?(a):(b))
 #define        max(a,b)        ((a)>(b)?(a):(b))
 
@@ -600,6 +617,7 @@ echo_truncate (len)
 {
   echobuf[len] = '\0';
   echoptr = echobuf + len;
+  truncate_echo_area (len);
 }
 
 \f
@@ -612,8 +630,9 @@ add_command_key (key)
 
   if (this_command_key_count >= size)
     {
-      Lisp_Object new_keys = Fmake_vector (make_number (size * 2), Qnil);
+      Lisp_Object new_keys;
 
+      new_keys = Fmake_vector (make_number (size * 2), Qnil);
       bcopy (XVECTOR (this_command_keys)->contents,
             XVECTOR (new_keys)->contents,
             size * sizeof (Lisp_Object));
@@ -887,18 +906,26 @@ command_loop_1 ()
   waiting_for_input = 0;
   cancel_echoing ();
 
-  /* Don't clear out last_command at the beginning of a macro.  */
-  if (XTYPE (Vexecuting_macro) != Lisp_String)
-    last_command = Qt;
-
   nonundocount = 0;
   no_redisplay = 0;
   this_command_key_count = 0;
 
   /* Make sure this hook runs after commands that get errors and
      throw to top level.  */
-  if (!NILP (Vpost_command_hook))
-    call1 (Vrun_hooks, Qpost_command_hook);
+  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+    {
+      /* If we get an error during the post-command-hook,
+        cause post-command-hook to be nil.  */
+      Vcommand_hook_internal = Vpost_command_hook;
+      Vpost_command_hook = Qnil;
+
+      call1 (Vrun_hooks, Qcommand_hook_internal);
+      
+      Vpost_command_hook = Vcommand_hook_internal;
+    }
+
+  /* Do this after running Vpost_command_hook, for consistency.  */
+  last_command = this_command;
 
   while (1)
     {
@@ -964,35 +991,6 @@ command_loop_1 ()
          && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
        call0 (Qrecompute_lucid_menubar);
 
-#if 0 /* This is done in xdisp.c now.  */
-#ifdef MULTI_FRAME
-      for (tem = Vframe_list; CONSP (tem); tem = XCONS (tem)->cdr)
-       {
-         struct frame *f = XFRAME (XCONS (tem)->car);
-         struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-
-         /* If the user has switched buffers or windows, we need to
-            recompute to reflect the new bindings.  But we'll
-            recompute when update_mode_lines is set too; that means
-            that people can use force-mode-line-update to request
-            that the menu bar be recomputed.  The adverse effect on
-            the rest of the redisplay algorithm is about the same as
-            windows_or_buffers_changed anyway.  */
-         if (windows_or_buffers_changed
-             || update_mode_lines
-             || (XFASTINT (w->last_modified) < MODIFF
-                 && (XFASTINT (w->last_modified)
-                     <= XBUFFER (w->buffer)->save_modified)))
-           {
-             struct buffer *prev = current_buffer;
-             current_buffer = XBUFFER (w->buffer);
-             FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
-             current_buffer = prev;
-           }
-       }
-#endif /* MULTI_FRAME */
-#endif /* 0 */
-
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
 
@@ -1031,17 +1029,30 @@ command_loop_1 ()
        }
 
       /* Do redisplay processing after this command except in special
-        cases identified below that set no_redisplay to 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.  */
       no_redisplay = 0;
 
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
+      last_point_position = PT;
 
       /* Execute the command.  */
 
       this_command = cmd;
-      if (!NILP (Vpre_command_hook))
-       call1 (Vrun_hooks, Qpre_command_hook);
+      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;
+       }
 
       if (NILP (this_command))
        {
@@ -1139,8 +1150,9 @@ command_loop_1 ()
 
                      if (dp)
                        {
-                         Lisp_Object obj = DISP_CHAR_VECTOR (dp, lose);
+                         Lisp_Object obj;
 
+                         obj = DISP_CHAR_VECTOR (dp, lose);
                          if (XTYPE (obj) == Lisp_Vector
                              && XVECTOR (obj)->size == 1
                              && (XTYPE (obj = XVECTOR (obj)->contents[0])
@@ -1168,8 +1180,17 @@ command_loop_1 ()
        }
     directly_done: ;
 
-      if (!NILP (Vpost_command_hook))
-       call1 (Vrun_hooks, Qpost_command_hook);
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+       {
+         /* If we get an error during the post-command-hook,
+            cause post-command-hook to be nil.  */
+         Vcommand_hook_internal = Vpost_command_hook;
+         Vpost_command_hook = Qnil;
+
+         call1 (Vrun_hooks, Qcommand_hook_internal);
+
+         Vpost_command_hook = Vcommand_hook_internal;
+       }
 
       /* If there is a prefix argument,
         1) We don't want last_command to be ``universal-argument''
@@ -1187,7 +1208,7 @@ command_loop_1 ()
          this_command_key_count = 0;
        }
 
-      if (!NILP (current_buffer->mark_active))
+      if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
            {
@@ -1455,6 +1476,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     /* If already echoing, continue.  */
     echo_dash ();
 
+  /* Try reading a character via menu prompting in the minibuf.
+     Try this before the sit-for, because the sit-for
+     would do the wrong thing if we are supposed to do
+     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))
+    {
+      c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
+      if ( ! NILP(c) ) return c ;
+    }
+
   /* 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
@@ -1490,13 +1524,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       restore_getcjmp (temp);
     }
 
-  /* Try reading a character via menu prompting.
-     Try this before the sit-for, because the sit-for
-     would do the wrong thing if we are supposed to do
-     menu prompting.  */
-  c = Qnil;
-  if (INTERACTIVE && !NILP (prev_event))
-    c = read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+  /* Try reading using an X menu.
+     This is never confused with reading using the minibuf because the recursive
+     call of read_char in read_char_minibuf_menu_prompt does not pass on
+     any keys maps */
+  if (nmaps > 0 && INTERACTIVE &&
+      !NILP (prev_event) && EVENT_HAS_PARAMETERS (prev_event))
+    c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
 
   /* Slow down auto saves logarithmically in size of current buffer,
      and garbage collect while we're at it.  */
@@ -1607,10 +1641,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        putc (XINT (c), dribble);
       else
        {
-         Lisp_Object dribblee = c;
+         Lisp_Object dribblee;
 
          /* If it's a structured event, take the event header.  */
-         dribblee = EVENT_HEAD (dribblee);
+         dribblee = EVENT_HEAD (c);
 
          if (XTYPE (dribblee) == Lisp_Symbol)
            {
@@ -1660,7 +1694,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        internal_with_output_to_temp_buffer ("*Help*", print_help, tem0);
 
       cancel_echoing ();
-      c = read_char (0, 0, 0, Qnil, 0);
+      do
+       c = read_char (0, 0, 0, Qnil, 0);
+      while (XTYPE (c) == Lisp_Buffer);
       /* Remove the help from the frame */
       unbind_to (count, Qnil);
       prepare_menu_bars ();
@@ -1668,7 +1704,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (EQ (c, make_number (040)))
        {
          cancel_echoing ();
-         c = read_char (0, 0, 0, Qnil, 0);
+         do
+           c = read_char (0, 0, 0, Qnil, 0);
+         while (XTYPE (c) == Lisp_Buffer);
        }
     }
 
@@ -1792,9 +1830,9 @@ kbd_buffer_store_event (event)
             get returned to Emacs as an event, the next event read
             will set Vlast_event_frame again, so this is safe to do.  */
          {
-           Lisp_Object focus
-             = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
+           Lisp_Object focus;
 
+           focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
            if (NILP (focus))
              internal_last_event_frame = event->frame_or_window;
            else
@@ -1898,9 +1936,8 @@ kbd_buffer_get_event ()
          wait_reading_process_input (0, 0, minus_one, 1);
 
          if (!interrupt_input && EVENT_QUEUES_EMPTY)
-           {
-             read_avail_input (0);
-           }
+           /* Pass 1 for EXPECT since we just waited to have input.  */
+           read_avail_input (1);
        }
 #endif /* not VMS */
     }
@@ -1965,7 +2002,7 @@ kbd_buffer_get_event ()
            }
 
          if (! CONSP (tail))
-           kill (getpid (), SIGHUP);
+           Fkill_emacs (Qnil);
 
          Fdelete_frame (event->frame_or_window, Qt);
          kbd_fetch_ptr = event + 1;
@@ -1982,9 +2019,10 @@ kbd_buffer_get_event ()
       else
        {
 #ifdef MULTI_FRAME
-         Lisp_Object frame = event->frame_or_window;
+         Lisp_Object frame;
          Lisp_Object focus;
 
+         frame = event->frame_or_window;
          if (XTYPE (frame) == Lisp_Window)
            frame = WINDOW_FRAME (XWINDOW (frame));
 
@@ -2033,8 +2071,9 @@ kbd_buffer_get_event ()
         frames.  */
       if (f)
        {
-         Lisp_Object frame = FRAME_FOCUS_FRAME (f);
+         Lisp_Object frame;
 
+         frame = FRAME_FOCUS_FRAME (f);
          if (NILP (frame))
            XSET (frame, Lisp_Frame, f);
 
@@ -2114,9 +2153,12 @@ swallow_events ()
 \f
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
+static Lisp_Object system_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
 
+Lisp_Object Vsystem_key_alist;
+
 /* This is a list of keysym codes for special "accent" characters.
    It parallels lispy_accent_keys.  */
 
@@ -2215,7 +2257,7 @@ static char *lispy_function_keys[] =
   {
     /* X Keysym value */
 
-    "remove", 0, 0, 0, 0, 0, 0, 0,     /* 0xff00 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xff00 */
     "backspace",
     "tab",
     "linefeed",
@@ -2256,19 +2298,7 @@ static char *lispy_function_keys[] =
     "help",
     "break",                   /* 0xff6b */
 
-    /* Here are some keys found mostly on HP keyboards.  The X event
-       handling code will strip bit 29, which flags vendor-specific
-       keysyms.  */
-    "reset",                   /* 0x1000ff6c */
-    "system",
-    "user",
-    "clearline",
-    "insertline",
-    "deleteline",
-    "insertchar",
-    "deletechar",
-    "backtab",
-    "kp-backtab",              /* 0x1000ff75 */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0,                         /* 0xff76 */
     0, 0, 0, 0, 0, 0, 0, 0, "kp-numlock",      /* 0xff7f */
     "kp-space",                        /* 0xff80 */    /* IsKeypadKey */
@@ -2350,6 +2380,10 @@ Lisp_Object Vdouble_click_time;
 
 int double_click_count;
 
+#ifdef USE_X_TOOLKIT
+extern Lisp_Object map_event_to_object ();
+#endif /* USE_X_TOOLKIT  */
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -2398,14 +2432,27 @@ make_lispy_event (event)
        if (event->code == lispy_accent_codes[i])
          return modify_event_symbol (i,
                                      event->modifiers,
-                                     Qfunction_key,
+                                     Qfunction_key, Qnil,
                                      lispy_accent_keys, &accent_key_syms,
                                      (sizeof (lispy_accent_keys)
                                       / sizeof (lispy_accent_keys[0])));
 
+      /* Handle system-specific keysyms.  */
+      if (event->code & (1 << 28))
+       {
+         /* We need to use an alist rather than a vector as the cache
+            since we can't make a vector long enuf.  */
+         if (NILP (system_key_syms))
+           system_key_syms = Fcons (Qnil, Qnil);
+         return modify_event_symbol (event->code & 0xffffff,
+                                     event->modifiers,
+                                     Qfunction_key, Vsystem_key_alist,
+                                     0, &system_key_syms, 0xffffff);
+       }
+
       return modify_event_symbol (event->code - 0xff00,
                                  event->modifiers,
-                                 Qfunction_key,
+                                 Qfunction_key, Qnil,
                                  lispy_function_keys, &func_key_syms,
                                  (sizeof (lispy_function_keys)
                                   / sizeof (lispy_function_keys[0])));
@@ -2430,25 +2477,48 @@ make_lispy_event (event)
          {
            int part;
            FRAME_PTR f = XFRAME (event->frame_or_window);
-           Lisp_Object window
-             = window_from_coordinates (f, XINT (event->x), XINT (event->y),
-                                        &part);
+           Lisp_Object window;
            Lisp_Object posn;
+           int row, column;
 
-           if (XINT (event->y) < FRAME_MENU_BAR_LINES (f))
+           pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                                  &column, &row, 0, 0);
+
+#ifdef USE_X_TOOLKIT
+           if (FRAME_EXTERNAL_MENU_BAR (f) && XINT (event->y) == -1)
+#else
+           if (row < FRAME_MENU_BAR_LINES (f))
+#endif
              {
+               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;
-               Lisp_Object items;
+               int i;
+
                items = FRAME_MENU_BAR_ITEMS (f);
-               for (; CONSP (items); items = XCONS (items)->cdr)
+               for (i = 0; i < XVECTOR (items)->size; i += 3)
                  {
                    Lisp_Object pos, string;
-                   pos = Fcdr (Fcdr (Fcar (items)));
-                   string = Fcar (Fcdr (Fcar (items)));
-                   if (XINT (event->x) >= XINT (pos)
-                       && XINT (event->x) < XINT (pos) + XSTRING (string)->size)
+                   string = XVECTOR (items)->contents[i + 1];
+                   pos = XVECTOR (items)->contents[i + 2];
+                   if (NILP (string))
                      break;
+                   if (column >= XINT (pos)
+                       && column < XINT (pos) + XSTRING (string)->size)
+                     {
+                       item = XVECTOR (items)->contents[i];
+                       break;
+                     }
                  }
+#endif /* not USE_X_TOOLKIT  */
+
                position
                  = Fcons (event->frame_or_window,
                           Fcons (Qmenu_bar,
@@ -2456,20 +2526,21 @@ make_lispy_event (event)
                                         Fcons (make_number (event->timestamp),
                                                Qnil))));
 
-               if (CONSP (items))
-                 return Fcons (Fcar (Fcar (items)),
-                               Fcons (position, Qnil));
-               else
-                 return Fcons (Qnil, Fcons (position, Qnil));
+               return Fcons (item, Fcons (position, Qnil));
              }
-           else if (XTYPE (window) != Lisp_Window)
+
+           window = window_from_coordinates (f, column, row, &part);
+
+           if (XTYPE (window) != Lisp_Window)
              posn = Qnil;
            else
              {
-               XSETINT (event->x, 
-                        (XINT (event->x) - XINT (XWINDOW (window)->left)));
-               XSETINT (event->y,
-                        (XINT (event->y) - XINT (XWINDOW (window)->top)));
+               int pixcolumn, pixrow;
+               column -= XINT (XWINDOW (window)->left);
+               row -= XINT (XWINDOW (window)->top);
+               glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+               XSETINT (event->x, pixcolumn);
+               XSETINT (event->y, pixrow);
 
                if (part == 1)
                  posn = Qmode_line;
@@ -2478,8 +2549,7 @@ make_lispy_event (event)
                else
                  XSET (posn, Lisp_Int,
                        buffer_posn_from_coords (XWINDOW (window),
-                                                XINT (event->x),
-                                                XINT (event->y)));
+                                                column, row));
              }
 
            position
@@ -2491,17 +2561,20 @@ make_lispy_event (event)
          }
        else
          {
-           Lisp_Object window = event->frame_or_window;
-           Lisp_Object portion_whole = Fcons (event->x, event->y);
-           Lisp_Object part = *scroll_bar_parts[(int) event->part];
+           Lisp_Object window;
+           Lisp_Object portion_whole;
+           Lisp_Object part;
+
+           window = event->frame_or_window;
+           portion_whole = Fcons (event->x, event->y);
+           part = *scroll_bar_parts[(int) event->part];
 
            position =
              Fcons (window,
                     Fcons (Qvertical_scroll_bar,
                            Fcons (portion_whole,
                                   Fcons (make_number (event->timestamp),
-                                         Fcons (part,
-                                                Qnil)))));
+                                         Fcons (part, Qnil)))));
          }
 
        start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
@@ -2561,8 +2634,9 @@ make_lispy_event (event)
              {
                /* The third element of every position should be the (x,y)
                   pair.  */
-               Lisp_Object down = Fnth (make_number (2), start_pos);
+               Lisp_Object down;
 
+               down = Fnth (make_number (2), start_pos);
                if (EQ (event->x, XCONS (down)->car)
                    && EQ (event->y, XCONS (down)->cdr))
                  {
@@ -2587,14 +2661,14 @@ make_lispy_event (event)
 
        {
          /* Get the symbol we should use for the mouse click.  */
-         Lisp_Object head
-           = modify_event_symbol (button,
-                                  event->modifiers,
-                                  Qmouse_click,
-                                  lispy_mouse_names, &mouse_syms,
-                                  (sizeof (lispy_mouse_names)
-                                   / sizeof (lispy_mouse_names[0])));
-         
+         Lisp_Object head;
+
+         head = modify_event_symbol (button,
+                                     event->modifiers,
+                                     Qmouse_click, Qnil,
+                                     lispy_mouse_names, &mouse_syms,
+                                     (sizeof (lispy_mouse_names)
+                                      / sizeof (lispy_mouse_names[0])));
          if (event->modifiers & drag_modifier)
            return Fcons (head,
                          Fcons (start_pos,
@@ -2629,8 +2703,9 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
-      Lisp_Object part_sym = *scroll_bar_parts[(int) part];
+      Lisp_Object part_sym;
 
+      part_sym = *scroll_bar_parts[(int) part];
       return Fcons (Qscroll_bar_movement,
                    (Fcons (Fcons (bar_window,
                                   Fcons (Qvertical_scroll_bar,
@@ -2645,16 +2720,25 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   else
     {
       int area;
-      Lisp_Object window =
-       (frame
-        ? window_from_coordinates (frame, XINT (x), XINT (y), &area)
-        : Qnil);
+      Lisp_Object window;
       Lisp_Object posn;
+      int column, row;
+
+      pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 0);
+
+      if (frame)
+       window = window_from_coordinates (frame, column, row, &area);
+      else
+       window = Qnil;
 
       if (XTYPE (window) == Lisp_Window)
        {
-         XSETINT (x, XINT (x) - XINT (XWINDOW (window)->left));
-         XSETINT (y, XINT (y) - XINT (XWINDOW (window)->top));
+         int pixcolumn, pixrow;
+         column -= XINT (XWINDOW (window)->left);
+         row -= XINT (XWINDOW (window)->top);
+         glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
+         XSETINT (x, pixcolumn);
+         XSETINT (y, pixrow);
 
          if (area == 1)
            posn = Qmode_line;
@@ -2662,8 +2746,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
            posn = Qvertical_line;
          else
            XSET (posn, Lisp_Int,
-                 buffer_posn_from_coords (XWINDOW (window),
-                                          XINT (x), XINT (y)));
+                 buffer_posn_from_coords (XWINDOW (window), column, row));
        }
       else if (frame != 0)
        {
@@ -2852,8 +2935,9 @@ apply_modifiers_uncached (modifiers, base, base_len)
   }
 
   {
-    Lisp_Object new_name = make_uninit_string (mod_len + base_len);
+    Lisp_Object new_name;
     
+    new_name = make_uninit_string (mod_len + base_len);
     bcopy (new_mods, XSTRING (new_name)->data,        mod_len);
     bcopy (base,     XSTRING (new_name)->data + mod_len, base_len);
 
@@ -2900,20 +2984,22 @@ static Lisp_Object
 parse_modifiers (symbol)
      Lisp_Object symbol;
 {
-  Lisp_Object elements = Fget (symbol, Qevent_symbol_element_mask);
+  Lisp_Object elements;
 
+  elements = Fget (symbol, Qevent_symbol_element_mask);
   if (CONSP (elements))
     return elements;
   else
     {
       int end;
       int modifiers = parse_modifiers_uncached (symbol, &end);
-      Lisp_Object unmodified
-       = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
-                               XSYMBOL (symbol)->name->size - end),
-                  Qnil);
+      Lisp_Object unmodified;
       Lisp_Object mask;
 
+      unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
+                                        XSYMBOL (symbol)->name->size - end),
+                           Qnil);
+
       if (modifiers & ~((1<<VALBITS) - 1))
        abort ();
       XFASTINT (mask) = modifiers;
@@ -2988,8 +3074,9 @@ apply_modifiers (modifiers, base)
      Qevent_kind set right as well.  */
   if (NILP (Fget (new_symbol, Qevent_kind)))
     {
-      Lisp_Object kind = Fget (base, Qevent_kind);
+      Lisp_Object kind;
 
+      kind = Fget (base, Qevent_kind);
       if (! NILP (kind))
        Fput (new_symbol, Qevent_kind, kind);
     }
@@ -3012,8 +3099,9 @@ reorder_modifiers (symbol)
 {
   /* It's hopefully okay to write the code this way, since everything
      will soon be in caches, and no consing will be done at all.  */
-  Lisp_Object parsed = parse_modifiers (symbol);
+  Lisp_Object parsed;
 
+  parsed = parse_modifiers (symbol);
   return apply_modifiers (XCONS (XCONS (parsed)->cdr)->car,
                          XCONS (parsed)->car);
 }
@@ -3028,10 +3116,13 @@ reorder_modifiers (symbol)
    is the name of the i'th symbol.  TABLE_SIZE is the number of elements
    in the table.
 
+   Alternatively, NAME_ALIST is an alist mapping codes into symbol names.
+   NAME_ALIST is used if it is non-nil; otherwise NAME_TABLE is used.
+
    SYMBOL_TABLE should be a pointer to a Lisp_Object whose value will
    persist between calls to modify_event_symbol that it can use to
    store a cache of the symbols it's generated for this NAME_TABLE
-   before.
+   before.  The object stored there may be a vector or an alist.
 
    SYMBOL_NUM is the number of the base name we want from NAME_TABLE.
    
@@ -3046,58 +3137,75 @@ reorder_modifiers (symbol)
    in the symbol's name.  */
 
 static Lisp_Object
-modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table,
-                     symbol_table, table_size)
+modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
+                     name_table, symbol_table, table_size)
      int symbol_num;
      unsigned modifiers;
      Lisp_Object symbol_kind;
+     Lisp_Object name_alist;
      char **name_table;
      Lisp_Object *symbol_table;
      int table_size;
 {
-  Lisp_Object *slot;
+  Lisp_Object value;
+  Lisp_Object symbol_int;
+
+  XSET (symbol_int, Lisp_Int, symbol_num);
 
   /* Is this a request for a valid symbol?  */
   if (symbol_num < 0 || symbol_num >= table_size)
     abort ();
 
+  if (CONSP (*symbol_table))
+    value = Fcdr (assq_no_quit (symbol_int, *symbol_table));
+
   /* If *symbol_table doesn't seem to be initialized properly, fix that.
      *symbol_table should be a lisp vector TABLE_SIZE elements long,
      where the Nth element is the symbol for NAME_TABLE[N], or nil if
      we've never used that symbol before.  */
-  if (XTYPE (*symbol_table) != Lisp_Vector
-      || XVECTOR (*symbol_table)->size != table_size)
+  else
     {
-      Lisp_Object size;
+      if (! VECTORP (*symbol_table)
+         || XVECTOR (*symbol_table)->size != table_size)
+       {
+         Lisp_Object size;
 
-      XFASTINT (size) = table_size;
-      *symbol_table = Fmake_vector (size, Qnil);
-    }
+         XFASTINT (size) = table_size;
+         *symbol_table = Fmake_vector (size, Qnil);
+       }
 
-  slot = & XVECTOR (*symbol_table)->contents[symbol_num];
+      value = XVECTOR (*symbol_table)->contents[symbol_num];
+    }
 
   /* Have we already used this symbol before?  */
-  if (NILP (*slot))
+  if (NILP (value))
     {
       /* No; let's create it.  */
-      if (name_table[symbol_num])
-       *slot = intern (name_table[symbol_num]);
+      if (!NILP (name_alist))
+       value = Fassq (symbol_int, name_alist);
+      else if (name_table[symbol_num])
+       value = intern (name_table[symbol_num]);
       else
        {
          char buf[20];
          sprintf (buf, "key-%d", symbol_num);
-         *slot = intern (buf);
+         value = intern (buf);
        }
 
+      if (CONSP (*symbol_table))
+       *symbol_table = Fcons (value, *symbol_table);
+      else
+       XVECTOR (*symbol_table)->contents[symbol_num] = value;
+
       /* Fill in the cache entries for this symbol; this also  
         builds the Qevent_symbol_elements property, which the user
         cares about.  */
-      apply_modifiers (modifiers & click_modifier, *slot);
-      Fput (*slot, Qevent_kind, symbol_kind);
+      apply_modifiers (modifiers & click_modifier, value);
+      Fput (value, Qevent_kind, symbol_kind);
     }
 
   /* Apply modifiers to that symbol.  */
-  return apply_modifiers (modifiers, *slot);
+  return apply_modifiers (modifiers, value);
 }
 
 \f
@@ -3175,6 +3283,10 @@ read_avail_input (expected)
         of characters on some systems when input is stuffed at us.  */
       unsigned char cbuf[KBD_BUFFER_SIZE - 1];
 
+#ifdef MSDOS
+      nread = dos_keysns ();
+      if (nread == 0) return 0;
+#else */ not MSDOS */
 #ifdef FIONREAD
       /* Find out how much input is available.  */
       if (ioctl (0, FIONREAD, &nread) < 0)
@@ -3198,24 +3310,33 @@ read_avail_input (expected)
       you lose;
 #endif
 #endif
+#endif /* not MSDOS */
 
       /* Now read; for one reason or another, this will not block.  */
       while (1)
        {
+#ifdef MSDOS
+         cbuf[0] = dos_keyread();
+         nread = 1;
+#else
          nread = read (fileno (stdin), cbuf, nread);
+#endif
 #ifdef AIX
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
             This looks incorrect, but it isn't, because _BSD causes
             O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
             and that causes a value other than 0 when there is no input.  */
          if (nread == 0)
-           kill (SIGHUP, 0);
+           kill (0, SIGHUP);
 #endif
          /* This code is wrong, but at least it gets the right results.
             Fix it for 19.23.  */
          /* Retry the read if it is interrupted.  */
          if (nread >= 0
-             || ! (errno == EAGAIN || errno == EFAULT
+             || ! (errno == EAGAIN 
+#ifdef EFAULT
+                   || errno == EFAULT
+#endif
 #ifdef EBADSLT
                    || errno == EBADSLT
 #endif
@@ -3344,15 +3465,24 @@ map_prompt (map)
   return Qnil;
 }
 
-static Lisp_Object menu_bar_item ();
-static Lisp_Object menu_bar_one_keymap ();
+static void menu_bar_item ();
+static void menu_bar_one_keymap ();
 
-/* Return a list of menu items for a menu bar, appropriate
-   to the current buffer.
-   The elements have the form (KEY STRING . nil).  */
+/* These variables hold the vector under construction within
+   menu_bar_items and its subroutines, and the current index
+   for storing into that vector.  */
+static Lisp_Object menu_bar_items_vector;
+static Lisp_Object menu_bar_items_index;
+
+/* Return a vector of menu items for a menu bar, appropriate
+   to the current buffer.  Each item has three elements in the vector:
+   KEY STRING nil.
+
+   OLD is an old vector we can optionally reuse, or nil.  */
 
 Lisp_Object
-menu_bar_items ()
+menu_bar_items (old)
+     Lisp_Object old;
 {
   /* The number of keymaps we're scanning right now, and the number of
      keymaps we have allocated space for.  */
@@ -3369,6 +3499,10 @@ menu_bar_items ()
   int mapno;
   Lisp_Object oquit;
 
+  int i;
+
+  struct gcpro gcpro1;
+
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -3378,6 +3512,14 @@ menu_bar_items ()
   oquit = Vinhibit_quit;
   Vinhibit_quit = Qt; 
 
+  if (!NILP (old))
+    menu_bar_items_vector = old;
+  else
+    menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
+  menu_bar_items_index = 0;
+
+  GCPRO1 (menu_bar_items_vector);
+
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -3386,14 +3528,23 @@ menu_bar_items ()
   { 
     Lisp_Object *tmaps;
 
-    nmaps = current_minor_maps (0, &tmaps) + 2;
-    maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-    bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
+    if (!NILP (Voverriding_local_map))
+      {
+       nmaps = 2;
+       maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+       maps[0] = Voverriding_local_map;
+      }
+    else
+      {
+       nmaps = current_minor_maps (0, &tmaps) + 2;
+       maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+       bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
 #ifdef USE_TEXT_PROPERTIES
-    maps[nmaps-2] = get_local_map (PT, current_buffer);
+       maps[nmaps-2] = get_local_map (PT, current_buffer);
 #else
-    maps[nmaps-2] = current_buffer->keymap;
+       maps[nmaps-2] = current_buffer->keymap;
 #endif
+      }
     maps[nmaps-1] = current_global_map;
   }
 
@@ -3410,29 +3561,66 @@ menu_bar_items ()
 
       tem = Fkeymapp (def);
       if (!NILP (tem))
-       result = menu_bar_one_keymap (def, result);
+       menu_bar_one_keymap (def);
     }
 
+  /* Move to the end those items that should be at the end.  */
+
   for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCONS (tail)->cdr)
     {
-      Lisp_Object elt;
+      int i;
+      int end = menu_bar_items_index;
 
-      elt = Fassq (XCONS (tail)->car, result);
-      if (!NILP (elt))
-       result = Fcons (elt, Fdelq (elt, result));
+      for (i = 0; i < end; i += 3)
+       if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
+         {
+           Lisp_Object tem0, tem1, tem2;
+           /* Move the item at index I to the end,
+              shifting all the others forward.  */
+           tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
+           tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
+           tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+           if (end > i + 3)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+                    &XVECTOR (menu_bar_items_vector)->contents[i],
+                    (end - i - 3) * sizeof (Lisp_Object));
+           XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem0;
+           XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem1;
+           XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem2;
+           break;
+         }
     }
 
-  result = Fnreverse (result);
+  /* Add nil, nil, nil at the end.  */
+  i = menu_bar_items_index;
+  if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+    {
+      Lisp_Object tem;
+      int newsize = 2 * i;
+      tem = Fmake_vector (make_number (2 * i), Qnil);
+      bcopy (XVECTOR (menu_bar_items_vector)->contents,
+            XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+      menu_bar_items_vector = tem;
+    }
+  /* Add this item.  */
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  menu_bar_items_index = i;
+
   Vinhibit_quit = oquit;
-  return result;
+  UNGCPRO;
+  return menu_bar_items_vector;
 }
 \f
 /* Scan one map KEYMAP, accumulating any menu items it defines
-   that have not yet been seen in RESULT.  Return the updated RESULT.  */
+   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.  */
 
-static Lisp_Object
-menu_bar_one_keymap (keymap, result)
-     Lisp_Object keymap, result;
+static void
+menu_bar_one_keymap (keymap)
+     Lisp_Object keymap;
 {
   Lisp_Object tail, item, key, binding, item_string, table;
 
@@ -3448,12 +3636,10 @@ menu_bar_one_keymap (keymap, result)
            {
              item_string = XCONS (binding)->car;
              if (XTYPE (item_string) == Lisp_String)
-               result = menu_bar_item (key, item_string,
-                                       Fcdr (binding), result);
+               menu_bar_item (key, item_string, Fcdr (binding));
            }
          else if (EQ (binding, Qundefined))
-           result = menu_bar_item (key, item_string,
-                                   binding, result);
+           menu_bar_item (key, item_string, binding);
        }
       else if (XTYPE (item) == Lisp_Vector)
        {
@@ -3469,32 +3655,47 @@ menu_bar_one_keymap (keymap, result)
                {
                  item_string = XCONS (binding)->car;
                  if (XTYPE (item_string) == Lisp_String)
-                   result = menu_bar_item (key, item_string,
-                                           Fcdr (binding), result);
+                   menu_bar_item (key, item_string, Fcdr (binding));
                }
              else if (EQ (binding, Qundefined))
-               result = menu_bar_item (key, item_string,
-                                       binding, result);
+               menu_bar_item (key, item_string, binding);
            }
        }
     }
-
-  return result;
 }
 
+/* This is used as the handler when calling internal_condition_case_1.  */
+
 static Lisp_Object
-menu_bar_item (key, item_string, def, result)
-     Lisp_Object key, item_string, def, result;
+menu_bar_item_1 (arg)
+     Lisp_Object arg;
+{
+  return Qnil;
+}
+
+static void
+menu_bar_item (key, item_string, def)
+     Lisp_Object key, item_string, def;
 {
   Lisp_Object tem;
   Lisp_Object enabled;
+  int i;
 
   if (EQ (def, Qundefined))
     {
       /* If a map has an explicit nil as definition,
         discard any previously made menu bar item.  */
-      tem = Fassq (key, result);
-      return Fdelq (tem, result);
+
+      for (i = 0; i < menu_bar_items_index; i += 3)
+       if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+         {
+           if (menu_bar_items_index > i + 3)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+                    &XVECTOR (menu_bar_items_vector)->contents[i],
+                    (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
+           menu_bar_items_index -= 3;
+           return;
+         }
     }
 
   /* See if this entry is enabled.  */
@@ -3506,16 +3707,40 @@ menu_bar_item (key, item_string, def, result)
         Otherwise, enable if value is not nil.  */
       tem = Fget (def, Qmenu_enable);
       if (!NILP (tem))
-       enabled = Feval (tem);
+       /* (condition-case nil (eval tem)
+            (error nil))  */
+       enabled = internal_condition_case_1 (Feval, tem, Qerror,
+                                            menu_bar_item_1);
     }
 
-  /* Add an entry for this key and string
-     if there is none yet.  */
-  tem = Fassq (key, result);
-  if (!NILP (enabled) && NILP (tem))
-    result = Fcons (Fcons (key, Fcons (item_string, Qnil)), result);
+  /* Ignore this item if it's not enabled.  */
+  if (NILP (enabled))
+    return;
 
-  return result;
+  /* If there's already such an item, don't make another.  */
+  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 (i == menu_bar_items_index)
+    {
+      /* If vector is too small, get a bigger one.  */
+      if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+       {
+         Lisp_Object tem;
+         int newsize = 2 * i;
+         tem = Fmake_vector (make_number (2 * i), Qnil);
+         bcopy (XVECTOR (menu_bar_items_vector)->contents,
+                XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+         menu_bar_items_vector = tem;
+       }
+      /* Add this item.  */
+      XVECTOR (menu_bar_items_vector)->contents[i++] = key;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
+      XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+      menu_bar_items_index = i;
+    }
 }
 \f
 /* Read a character using menus based on maps in the array MAPS.
@@ -3530,10 +3755,16 @@ menu_bar_item (key, item_string, def, result)
    USED_MOUSE_MENU is zero, *USED_MOUSE_MENU is left alone.
 
    The prompting is done based on the prompt-string of the map
-   and the strings associated with various map elements.  */
+   and the strings associated with various map elements.  
+
+   This can be done with X menus or with menus put in the minibuf.
+   These are done in different ways, depending on how the input will be read.
+   Menus using X are done after auto-saving in read-char, getting the input
+   event from Fx_popup_menu; menus using the minibuf use read_char recursively
+   and do auto-saving in the inner call of read_char. */
 
 static Lisp_Object
-read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
+read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
      int nmaps;
      Lisp_Object *maps;
      Lisp_Object prev_event;
@@ -3541,10 +3772,6 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
 {
   int mapno;
   register Lisp_Object name;
-  int nlength;
-  int width = FRAME_WIDTH (selected_frame) - 4;
-  char *menu = (char *) alloca (width + 4);
-  int idx = -1;
   Lisp_Object rest, vector;
 
   if (used_mouse_menu)
@@ -3602,6 +3829,38 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
     }
 #endif /* HAVE_X_MENU */
 #endif /* HAVE_X_WINDOWS */
+  return Qnil ;
+}
+
+static Lisp_Object
+read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
+     int commandflag ;
+     int nmaps;
+     Lisp_Object *maps;
+{
+  int mapno;
+  register Lisp_Object name;
+  int nlength;
+  int width = FRAME_WIDTH (selected_frame) - 4;
+  char *menu = (char *) alloca (width + 4);
+  int idx = -1;
+  int nobindings ;
+  Lisp_Object rest, vector;
+
+  if (! menu_prompting)
+    return Qnil;
+
+  /* Get the menu name from the first map that has one (a prompt string).  */
+  for (mapno = 0; mapno < nmaps; mapno++)
+    {
+      name = map_prompt (maps[mapno]);
+      if (!NILP (name))
+       break;
+    }
+
+  /* If we don't have any menus, just read a character normally.  */
+  if (mapno >= nmaps)
+    return Qnil;
 
   /* Prompt string always starts with map's prompt, and a space.  */
   strcpy (menu, XSTRING (name)->data);
@@ -3621,6 +3880,7 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
       int i = nlength;
       Lisp_Object obj;
       int ch;
+      int orig_defn_macro ;
 
       /* Loop over elements of map.  */
       while (i < width)
@@ -3635,10 +3895,8 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
                 or end this line if already have something on it.  */
              if (mapno == nmaps)
                {
-                 if (notfirst)
-                   break;
-                 else
-                   mapno = 0;
+                 mapno = 0;
+                 if (notfirst || nobindings) break;
                }
              rest = maps[mapno];
            }
@@ -3660,13 +3918,16 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
          else
            {
              /* An ordinary element.  */
-             s = Fcar_safe (Fcdr_safe (elt));
+             if ( idx < 0 )
+               s = Fcar_safe (Fcdr_safe (elt));        /* alist */
+             else
+               s = Fcar_safe(elt);                     /* vector */
              if (XTYPE (s) != Lisp_String)
                /* Ignore the element if it has no prompt string.  */
                ;
              /* If we have room for the prompt string, add it to this line.
                 If this is the first on the line, always add it.  */
-             else if (XSTRING (s)->size + i < width
+             else if (XSTRING (s)->size + i + 2 < width
                       || !notfirst)
                {
                  int thiswidth;
@@ -3678,6 +3939,7 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
                      i += 2;
                    }
                  notfirst = 1;
+                 nobindings = 0 ;
 
                  /* Add as much of string as fits.  */
                  thiswidth = XSTRING (s)->size;
@@ -3685,6 +3947,7 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
                    thiswidth = width - i;
                  bcopy (XSTRING (s)->data, menu + i, thiswidth);
                  i += thiswidth;
+                 menu[i] = 0;
                }
              else
                {
@@ -3695,7 +3958,7 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
                }
 
              /* Move past this element.  */
-             if (idx >= 0 && idx + 1 >= XVECTOR (rest)->size)
+             if (idx >= 0 && idx + 1 >= XVECTOR (vector)->size)
                /* Handle reaching end of dense table.  */
                idx = -1;
              if (idx >= 0)
@@ -3707,7 +3970,17 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
 
       /* Prompt with that and read response.  */
       message1 (menu);
-      obj = read_char (1, 0, 0, Qnil, 0);
+
+      /* Make believe its not a keyboard macro in case the help char 
+        is pressed.  Help characters are not recorded because menu prompting
+        is not used on replay.
+        */
+      orig_defn_macro = defining_kbd_macro ;
+      defining_kbd_macro = 0 ;
+      do
+       obj = read_char (commandflag, 0, 0, Qnil, 0);
+      while (XTYPE (obj) == Lisp_Buffer);
+      defining_kbd_macro = orig_defn_macro ;
 
       if (XTYPE (obj) != Lisp_Int)
        return obj;
@@ -3717,7 +3990,12 @@ read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
       if (! EQ (obj, menu_prompt_more_char)
          && (XTYPE (menu_prompt_more_char) != Lisp_Int
              || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char))))))
-       return obj;
+       {
+         if ( defining_kbd_macro )
+           store_kbd_macro_char(obj) ;
+         return obj;
+       }
+      /* Help char - go round again */
     }
 }
 \f
@@ -4005,19 +4283,33 @@ read_key_sequence (keybuf, bufsize, prompt)
   { 
     Lisp_Object *maps;
 
-    nmaps = current_minor_maps (0, &maps) + 2;
-    if (nmaps > nmaps_allocated)
+    if (!NILP (Voverriding_local_map))
       {
-       submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
-       defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
-       nmaps_allocated = nmaps;
+       nmaps = 2;
+       if (nmaps > nmaps_allocated)
+         {
+           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
+           nmaps_allocated = nmaps;
+         }
+       submaps[0] = Voverriding_local_map;
       }
-    bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
+    else
+      {
+       nmaps = current_minor_maps (0, &maps) + 2;
+       if (nmaps > nmaps_allocated)
+         {
+           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
+           nmaps_allocated = nmaps;
+         }
+       bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
 #ifdef USE_TEXT_PROPERTIES
-    submaps[nmaps-2] = get_local_map (PT, current_buffer);
+       submaps[nmaps-2] = get_local_map (PT, current_buffer);
 #else
-    submaps[nmaps-2] = current_buffer->keymap;
+       submaps[nmaps-2] = current_buffer->keymap;
 #endif
+      }
     submaps[nmaps-1] = current_global_map;
   }
 
@@ -4032,7 +4324,7 @@ read_key_sequence (keybuf, bufsize, prompt)
   /* These are no-ops the first time through, but if we restart, they
      revert the echo area and this_command_keys to their original state.  */
   this_command_key_count = keys_start;
-  if (INTERACTIVE)
+  if (INTERACTIVE && t < mock_input)
     echo_truncate (echo_start);
 
   /* If the best binding for the current key sequence is a keymap, or
@@ -4083,7 +4375,7 @@ read_key_sequence (keybuf, bufsize, prompt)
         jumped back up to replay_key; in that case, these restore the
         variables to their original state, allowing us to replay the
         loop.  */
-      if (INTERACTIVE)
+      if (INTERACTIVE && t < mock_input)
        echo_truncate (echo_local_start);
       this_command_key_count = keys_local_start;
       first_binding = local_first_binding;
@@ -4121,6 +4413,14 @@ read_key_sequence (keybuf, bufsize, prompt)
              goto done;
            }
          
+         /* If the current buffer has been changed from under us, the
+            keymap may have changed, so replay the sequence.  */
+         if (XTYPE (key) == Lisp_Buffer)
+           {
+             mock_input = t;
+             goto replay_sequence;
+           }
+
          /* 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.  */
@@ -4131,7 +4431,7 @@ read_key_sequence (keybuf, bufsize, prompt)
              Vquit_flag = Qnil;
              goto replay_sequence;
            }
-           
+
          Vquit_flag = Qnil;
        }
 
@@ -4151,13 +4451,15 @@ read_key_sequence (keybuf, bufsize, prompt)
         or when user programs play with this-command-keys.  */
       if (EVENT_HAS_PARAMETERS (key))
        {
-         Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+         Lisp_Object kind;
 
+         kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
            {
-             Lisp_Object window = POSN_WINDOW      (EVENT_START (key));
-             Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             Lisp_Object window, posn;
 
+             window = POSN_WINDOW      (EVENT_START (key));
+             posn   = POSN_BUFFER_POSN (EVENT_START (key));
              if (XTYPE (posn) == Lisp_Cons)
                {
                  /* We're looking at the second event of a
@@ -4225,8 +4527,9 @@ read_key_sequence (keybuf, bufsize, prompt)
            }
          else
            {
-             Lisp_Object posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             Lisp_Object posn;
 
+             posn = POSN_BUFFER_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
              if (EQ (posn, Qmenu_bar))
@@ -4234,7 +4537,8 @@ read_key_sequence (keybuf, bufsize, prompt)
                  if (t + 1 >= bufsize)
                    error ("key sequence too long");
                  /* Run the Lucid hook.  */
-                 call1 (Vrun_hooks, Qactivate_menubar_hook);
+                 if (!NILP (Vrun_hooks))
+                   call1 (Vrun_hooks, Qactivate_menubar_hook);
                  /* If it has changed current-menubar from previous value,
                     really recompute the menubar from the value.  */
                  if (! NILP (Vlucid_menu_bar_dirty_flag))
@@ -4274,8 +4578,9 @@ read_key_sequence (keybuf, bufsize, prompt)
       /* If KEY wasn't bound, we'll try some fallbacks.  */
       if (first_binding >= nmaps)
        {
-         Lisp_Object head = EVENT_HEAD (key);
+         Lisp_Object head;
 
+         head = EVENT_HEAD (key);
          if (EQ (head, Vhelp_char))
            {
              read_key_sequence_cmd = Vprefix_help_command;
@@ -4286,9 +4591,11 @@ read_key_sequence (keybuf, bufsize, prompt)
 
          if (XTYPE (head) == Lisp_Symbol)
            {
-             Lisp_Object breakdown = parse_modifiers (head);
-             int modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+             Lisp_Object breakdown;
+             int modifiers;
 
+             breakdown = parse_modifiers (head);
+             modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
              /* Attempt to reduce an unbound mouse event to a simpler
                 event that is bound:
                   Drags reduce to clicks.
@@ -4531,7 +4838,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                Lisp_Object tem;
                tem = keytran_next;
 
-               GCPRO3 (keytran_map, keytran_map, delayed_switch_frame);
+               GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
                keytran_next = call1 (keytran_next, prompt);
                UNGCPRO;
                /* If the function returned something invalid,
@@ -4539,7 +4846,7 @@ read_key_sequence (keybuf, bufsize, prompt)
                   (To ignore it safely, we would need to gcpro a bunch of 
                   other variables.)  */
                if (! (VECTORP (keytran_next) || STRINGP (keytran_next)))
-                 error ("Function in function-key-map returns invalid key sequence");
+                 error ("Function in key-translation-map returns invalid key sequence");
              }
 
            /* If keybuf[keytran_start..keytran_end] is bound in the
@@ -4705,7 +5012,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
   if (XTYPE (cmd) == Lisp_Symbol)
     {
       tem = Fget (cmd, Qdisabled);
-      if (!NILP (tem))
+      if (!NILP (tem) && !NILP (Vrun_hooks))
        return call1 (Vrun_hooks, Qdisabled_command_hook);
     }
 
@@ -4762,7 +5069,8 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object saved_keys;
   struct gcpro gcpro1;
 
-  saved_keys = Fthis_command_keys ();
+  saved_keys = Fvector (this_command_key_count,
+                       XVECTOR (this_command_keys)->contents);
   buf[0] = 0;
   GCPRO1 (saved_keys);
 
@@ -4792,17 +5100,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
      function, followed by a RET.  */
   {
     struct Lisp_String *str;
+    Lisp_Object *keys;
     int i;
     Lisp_Object tem;
 
     this_command_key_count = 0;
 
-    str = XSTRING (saved_keys);
-    for (i = 0; i < str->size; i++)
-      {
-       XFASTINT (tem) = str->data[i];
-       add_command_key (tem);
-      }
+    keys = XVECTOR (saved_keys)->contents;
+    for (i = 0; i < XVECTOR (saved_keys)->size; i++)
+      add_command_key (keys[i]);
 
     str = XSTRING (function);
     for (i = 0; i < str->size; i++)
@@ -4937,7 +5243,8 @@ Also cancel any kbd macro being defined.")
 \f
 DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
   "Stop Emacs and return to superior process.  You can resume later.\n\
-On systems that don't have job control, run a subshell instead.\n\n\
+If `cannot-suspend' is non-nil, or if the system doesn't support job\n\
+control, run a subshell instead.\n\n\
 If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
 to be read as terminal input by Emacs's parent, after suspension.\n\
 \n\
@@ -4972,7 +5279,10 @@ On such systems, Emacs starts a subshell instead of suspending.")
      and the system resources aren't available for that.  */
   record_unwind_protect (init_sys_modes, 0);
   stuff_buffered_input (stuffstring);
-  sys_suspend ();
+  if (cannot_suspend)
+    sys_subshell ();
+  else
+    sys_suspend ();
   unbind_to (count, Qnil);
 
   /* Check if terminal/window size has changed.
@@ -5107,24 +5417,41 @@ interrupt_signal ()
       printf ("you can continue or abort.\n");
 #endif /* not VMS */
 #endif /* not SIGTSTP */
+#ifdef MSDOS
+      /* We must remain inside the screen area when the internal terminal
+        is used.  Note that [Enter] is not echoed by dos.  */
+      cursor_to (0, 0);
+#endif
       printf ("Auto-save? (y or n) ");
       fflush (stdout);
       if (((c = getchar ()) & ~040) == 'Y')
        {
          Fdo_auto_save (Qt, Qnil);
+#ifdef MSDOS
+         printf ("\r\nAuto-save done");
+#else /* not MSDOS */
          printf ("Auto-save done\n");
+#endif /* not MSDOS */
        }
       while (c != '\n') c = getchar ();
+#ifdef MSDOS
+      printf ("\r\nAbort?  (y or n) ");
+#else /* not MSDOS */
 #ifdef VMS
       printf ("Abort (and enter debugger)? (y or n) ");
 #else /* not VMS */
       printf ("Abort (and dump core)? (y or n) ");
 #endif /* not VMS */
+#endif /* not MSDOS */
       fflush (stdout);
       if (((c = getchar ()) & ~040) == 'Y')
        abort ();
       while (c != '\n') c = getchar ();
+#ifdef MSDOS
+      printf ("\r\nContinuing...\r\n");
+#else /* not MSDOS */
       printf ("Continuing...\n");
+#endif /* not MSDOS */
       fflush (stdout);
       init_sys_modes ();
     }
@@ -5374,6 +5701,9 @@ syms_of_keyboard ()
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
+  Qcommand_hook_internal = intern ("command-hook-internal");
+  staticpro (&Qcommand_hook_internal);
+
   Qfunction_key = intern ("function-key");
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
@@ -5598,6 +5928,11 @@ This keymap works like `function-key-map', but comes after that,\n\
 and applies even for keys that have ordinary bindings.");
   Vkey_translation_map = Qnil;
 
+  DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
+    "Non-nil means to always spawn a subshell instead of suspending,\n\
+even if the operating system has support for stopping a process.");
+  cannot_suspend = 0;
+
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
     "Non-nil means prompt with menus when appropriate.\n\
 This is done when reading from a keymap that has a prompt string,\n\
@@ -5633,6 +5968,10 @@ and tests the value when the command returns.\n\
 Buffer modification stores t in this variable.");
   Vdeactivate_mark = Qnil;
 
+  DEFVAR_LISP ("command-hook-internal", &Vcommand_hook_internal,
+    "Temporary storage of pre-command-hook or post-command-hook.");
+  Vcommand_hook_internal = Qnil;
+
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
     "Normal hook run before each command is executed.");
   Vpre_command_hook = Qnil;
@@ -5650,8 +5989,21 @@ Buffer modification stores t in this variable.");
 The elements of the list are event types that may have menu bar bindings.");
   Vmenu_bar_final_items = Qnil;
 
+  DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
+    "Keymap that overrides all other local keymaps.\n\
+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,
               "*Non-nil means generate motion events for mouse motion.");
+
+  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;
 }
 
 keys_of_keyboard ()