]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
*** empty log message ***
[gnu-emacs] / src / keyboard.c
index 05e2e50e11dd5971c5e02971c4aee677fd75f44f..927e986b2684438e6c9a0df90639a28604bb6aba 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 2001
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -27,6 +27,7 @@ Boston, MA 02111-1307, USA.  */
 #include "lisp.h"
 #include "termhooks.h"
 #include "macros.h"
 #include "lisp.h"
 #include "termhooks.h"
 #include "macros.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
@@ -34,7 +35,6 @@ Boston, MA 02111-1307, USA.  */
 #include "charset.h"
 #include "disptab.h"
 #include "dispextern.h"
 #include "charset.h"
 #include "disptab.h"
 #include "dispextern.h"
-#include "keyboard.h"
 #include "syntax.h"
 #include "intervals.h"
 #include "blockinput.h"
 #include "syntax.h"
 #include "intervals.h"
 #include "blockinput.h"
@@ -70,10 +70,16 @@ Boston, MA 02111-1307, USA.  */
 #include "w32term.h"
 #endif /* HAVE_NTGUI */
 
 #include "w32term.h"
 #endif /* HAVE_NTGUI */
 
+#ifdef macintosh
+#include "macterm.h"
+#endif
+
 /* Include systime.h after xterm.h to avoid double inclusion of time.h. */
 #include "systime.h"
 
 /* Include systime.h after xterm.h to avoid double inclusion of time.h. */
 #include "systime.h"
 
+#ifndef USE_CRT_DLL
 extern int errno;
 extern int errno;
+#endif
 
 /* Variables for blockinput.h: */
 
 
 /* Variables for blockinput.h: */
 
@@ -91,7 +97,7 @@ extern int input_fd;
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
 #ifdef macintosh
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
 #ifdef macintosh
-/* But not too big (local data > 32K error) if on macintosh */
+/* But not too big (local data > 32K error) if on macintosh */
 #define KBD_BUFFER_SIZE 512
 #else
 #define KBD_BUFFER_SIZE 4096
 #define KBD_BUFFER_SIZE 512
 #else
 #define KBD_BUFFER_SIZE 4096
@@ -196,7 +202,7 @@ int waiting_for_input;
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
 
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
 
-static int echoing;
+int echoing;
 
 /* Non-null means we can start echoing at the next input pause even
    though there is something in the echo area.  */
 
 /* Non-null means we can start echoing at the next input pause even
    though there is something in the echo area.  */
@@ -213,7 +219,7 @@ static struct kboard *echo_kboard;
 /* The buffer used for echoing.  Set in echo_now, reset in
    cancel_echoing.  */
 
 /* The buffer used for echoing.  Set in echo_now, reset in
    cancel_echoing.  */
 
-static Lisp_Object echo_message_buffer;
+Lisp_Object echo_message_buffer;
 
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
 
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
@@ -245,6 +251,10 @@ Lisp_Object Vmenu_bar_final_items;
    If the value is non-nil and not a number, we wait 2 seconds.  */
 Lisp_Object Vsuggest_key_bindings;
 
    If the value is non-nil and not a number, we wait 2 seconds.  */
 Lisp_Object Vsuggest_key_bindings;
 
+/* How long to display an echo-area message when the minibuffer is active.
+   If the value is not a number, such messages don't time out.  */
+Lisp_Object Vminibuffer_message_timeout;
+
 /* Character that causes a quit.  Normally C-g.
 
    If we are running on an ordinary terminal, this must be an ordinary
 /* Character that causes a quit.  Normally C-g.
 
    If we are running on an ordinary terminal, this must be an ordinary
@@ -450,6 +460,10 @@ int input_pending;
 
 int meta_key;
 
 
 int meta_key;
 
+/* Non-zero means force key bindings update in parse_menu_item.  */
+
+int update_menu_bindings;
+
 extern char *pending_malloc_warning;
 
 /* Circular buffer for pre-read keyboard input.  */
 extern char *pending_malloc_warning;
 
 /* Circular buffer for pre-read keyboard input.  */
@@ -509,7 +523,7 @@ static struct input_event * volatile kbd_store_ptr;
 /* If this flag is non-nil, we check mouse_moved to see when the
    mouse moves, and motion events will appear in the input stream.
    Otherwise, mouse motion is ignored.  */
 /* If this flag is non-nil, 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;
+Lisp_Object do_mouse_tracking;
 
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
 
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
@@ -630,27 +644,42 @@ Lisp_Object Vdisable_point_adjustment;
 
 Lisp_Object Vglobal_disable_point_adjustment;
 
 
 Lisp_Object Vglobal_disable_point_adjustment;
 
+/* The time when Emacs started being idle.  */
+
+static EMACS_TIME timer_idleness_start_time;
+
 \f
 /* Global variable declarations.  */
 
 /* Function for init_keyboard to call with no args (if nonzero).  */
 void (*keyboard_init_hook) ();
 
 \f
 /* Global variable declarations.  */
 
 /* Function for init_keyboard to call with no args (if nonzero).  */
 void (*keyboard_init_hook) ();
 
-static int read_avail_input ();
-static void get_input_pending ();
-static int readable_events ();
+static int read_avail_input P_ ((int));
+static void get_input_pending P_ ((int *, int));
+static int readable_events P_ ((int));
+static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
+                                               Lisp_Object, int *));
 static Lisp_Object read_char_x_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 read_char_minibuf_menu_prompt P_ ((int, int,
+                                                     Lisp_Object *));
+static Lisp_Object make_lispy_event P_ ((struct input_event *));
 #ifdef HAVE_MOUSE
 #ifdef HAVE_MOUSE
-static Lisp_Object make_lispy_movement ();
+static Lisp_Object make_lispy_movement P_ ((struct frame *, Lisp_Object,
+                                           enum scroll_bar_part,
+                                           Lisp_Object, Lisp_Object,
+                                           unsigned long));
 #endif
 #endif
-static Lisp_Object modify_event_symbol ();
-static Lisp_Object make_lispy_switch_frame ();
+static Lisp_Object modify_event_symbol P_ ((int, unsigned, Lisp_Object,
+                                           Lisp_Object, char **,
+                                           Lisp_Object *, unsigned));
+static Lisp_Object make_lispy_switch_frame P_ ((Lisp_Object));
+static int parse_solitary_modifier P_ ((Lisp_Object));
 static int parse_solitary_modifier ();
 static int parse_solitary_modifier ();
+static void save_getcjmp P_ ((jmp_buf));
 static void save_getcjmp ();
 static void save_getcjmp ();
-static void restore_getcjmp ();
+static void restore_getcjmp P_ ((jmp_buf));
 static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
+static void clear_event P_ ((struct input_event *));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
@@ -665,17 +694,39 @@ static int cannot_suspend;
 
 void
 echo_prompt (str)
 
 void
 echo_prompt (str)
-     char *str;
+     Lisp_Object str;
 {
 {
-  int len = strlen (str);
+  int nbytes = STRING_BYTES (XSTRING (str));
+  int multibyte_p = STRING_MULTIBYTE (str);
 
 
-  if (len > ECHOBUFSIZE - 4)
-    len = ECHOBUFSIZE - 4;
-  bcopy (str, current_kboard->echobuf, len);
-  current_kboard->echoptr = current_kboard->echobuf + len;
-  *current_kboard->echoptr = '\0';
+  if (nbytes > ECHOBUFSIZE - 4)
+    {
+      if (multibyte_p)
+       {
+         /* Have to find the last character that fit's into the 
+            echo buffer.  */
+         unsigned char *p = XSTRING (str)->data;
+         unsigned char *pend = p + ECHOBUFSIZE - 4;
+         int char_len;
 
 
-  current_kboard->echo_after_prompt = len;
+         do 
+           {
+             PARSE_MULTIBYTE_SEQ (p, pend - p, char_len);
+             p += char_len;
+           }
+         while (p < pend);
+
+         nbytes = p - XSTRING (str)->data - char_len;
+       }
+      else
+       nbytes = ECHOBUFSIZE - 4;
+    }
+
+  nbytes = copy_text (XSTRING (str)->data, current_kboard->echobuf, nbytes,
+                     STRING_MULTIBYTE (str), 1);
+  current_kboard->echoptr = current_kboard->echobuf + nbytes;
+  *current_kboard->echoptr = '\0';
+  current_kboard->echo_after_prompt = nbytes;
 
   echo_now ();
 }
 
   echo_now ();
 }
@@ -688,8 +739,6 @@ void
 echo_char (c)
      Lisp_Object c;
 {
 echo_char (c)
      Lisp_Object c;
 {
-  extern char *push_key_description ();
-
   if (current_kboard->immediate_echo)
     {
       char *ptr = current_kboard->echoptr;
   if (current_kboard->immediate_echo)
     {
       char *ptr = current_kboard->echoptr;
@@ -702,11 +751,13 @@ echo_char (c)
 
       if (INTEGERP (c))
        {
 
       if (INTEGERP (c))
        {
+         int ch = XINT (c);
+
          if (ptr - current_kboard->echobuf
              > ECHOBUFSIZE - KEY_DESCRIPTION_SIZE)
            return;
 
          if (ptr - current_kboard->echobuf
              > ECHOBUFSIZE - KEY_DESCRIPTION_SIZE)
            return;
 
-         ptr = push_key_description (XINT (c), ptr);
+         ptr = push_key_description (ch, ptr, 1);
        }
       else if (SYMBOLP (c))
        {
        }
       else if (SYMBOLP (c))
        {
@@ -714,8 +765,8 @@ echo_char (c)
          if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
              > ECHOBUFSIZE)
            return;
          if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
              > ECHOBUFSIZE)
            return;
-         bcopy (name->data, ptr, STRING_BYTES (name));
-         ptr += STRING_BYTES (name);
+         ptr += copy_text (name->data, ptr, STRING_BYTES (name),
+                           name->size_byte >= 0, 1);
        }
 
       if (current_kboard->echoptr == current_kboard->echobuf
        }
 
       if (current_kboard->echoptr == current_kboard->echobuf
@@ -781,7 +832,7 @@ echo_now ()
 
   echoing = 1;
   message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
 
   echoing = 1;
   message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
-                 ! NILP (current_buffer->enable_multibyte_characters));
+                 1);
   echoing = 0;
 
   /* Record in what buffer we echoed, and from which kboard.  */
   echoing = 0;
 
   /* Record in what buffer we echoed, and from which kboard.  */
@@ -873,13 +924,25 @@ recursive_edit_1 ()
     }
 
 #ifdef HAVE_X_WINDOWS
     }
 
 #ifdef HAVE_X_WINDOWS
-  /* The command loop has started a busy-cursor timer, so we have to
+  /* The command loop has started an hourglass timer, so we have to
      cancel it here, otherwise it will fire because the recursive edit
      can take some time.  */
      cancel it here, otherwise it will fire because the recursive edit
      can take some time.  */
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #endif
 
 #endif
 
+  /* This function may have been called from a debugger called from
+     within redisplay, for instance by Edebugging a function called
+     from fontification-functions.  We want to allow redisplay in
+     the debugging session.
+
+     The recursive edit is left with a `(throw exit ...)'.  The `exit'
+     tag is not caught anywhere in redisplay, i.e. when we leave the
+     recursive edit, the original redisplay leading to the recursive
+     edit will be unwound.  The outcome should therefore be safe.  */
+  specbind (Qinhibit_redisplay, Qnil);
+  redisplaying_p = 0;
+
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
@@ -1190,10 +1253,10 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
   ()
 {
 #ifdef HAVE_X_WINDOWS
   ()
 {
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #endif
 #endif
-  Fthrow (Qtop_level, Qnil);
+  return Fthrow (Qtop_level, Qnil);
 }
 
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
 }
 
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
@@ -1204,6 +1267,7 @@ DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0,
     Fthrow (Qexit, Qnil);
 
   error ("No recursive edit is in progress");
     Fthrow (Qexit, Qnil);
 
   error ("No recursive edit is in progress");
+  return Qnil;
 }
 
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
 }
 
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
@@ -1214,15 +1278,17 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
     Fthrow (Qexit, Qt);
 
   error ("No recursive edit is in progress");
     Fthrow (Qexit, Qt);
 
   error ("No recursive edit is in progress");
+  return Qnil;
 }
 \f
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
 }
 \f
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
-Lisp_Object Fcommand_execute ();
-static int read_key_sequence ();
-void safe_run_hooks ();
-static void adjust_point_for_property ();
+EXFUN (Fcommand_execute, 4);
+static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object,
+                                 int, int, int));
+void safe_run_hooks P_ ((Lisp_Object));
+static void adjust_point_for_property P_ ((int));
 
 Lisp_Object
 command_loop_1 ()
 
 Lisp_Object
 command_loop_1 ()
@@ -1234,7 +1300,7 @@ command_loop_1 ()
   int i;
   int no_direct;
   int prev_modiff;
   int i;
   int no_direct;
   int prev_modiff;
-  struct buffer *prev_buffer;
+  struct buffer *prev_buffer = NULL;
 #ifdef MULTI_KBOARD
   int was_locked = single_kboard;
 #endif
 #ifdef MULTI_KBOARD
   int was_locked = single_kboard;
 #endif
@@ -1298,18 +1364,19 @@ command_loop_1 ()
       Vdeactivate_mark = Qnil;
 
       /* If minibuffer on and echo area in use,
       Vdeactivate_mark = Qnil;
 
       /* If minibuffer on and echo area in use,
-        wait 2 sec and redraw minibuffer.  */
+        wait a short time and redraw minibuffer.  */
 
       if (minibuf_level
          && !NILP (echo_area_buffer[0])
 
       if (minibuf_level
          && !NILP (echo_area_buffer[0])
-         && EQ (minibuf_window, echo_area_window))
+         && EQ (minibuf_window, echo_area_window)
+         && NUMBERP (Vminibuffer_message_timeout))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
          int count = specpdl_ptr - specpdl;
          specbind (Qinhibit_quit, Qt);
 
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
          int count = specpdl_ptr - specpdl;
          specbind (Qinhibit_quit, Qt);
 
-         Fsit_for (make_number (2), Qnil, Qnil);
+         Fsit_for (Vminibuffer_message_timeout, Qnil, Qnil);
          /* Clear the echo area.  */
          message2 (0, 0, 0);
          safe_run_hooks (Qecho_area_clear_hook);
          /* Clear the echo area.  */
          message2 (0, 0, 0);
          safe_run_hooks (Qecho_area_clear_hook);
@@ -1416,6 +1483,10 @@ command_loop_1 ()
          this variable differently.  */
       Vdisable_point_adjustment = Qnil;
 
          this variable differently.  */
       Vdisable_point_adjustment = Qnil;
 
+      /* Process filters and timers may have messed with deactivate-mark.
+        reset it before we execute the command. */
+      Vdeactivate_mark = Qnil;
+
       /* Execute the command.  */
 
       Vthis_command = cmd;
       /* Execute the command.  */
 
       Vthis_command = cmd;
@@ -1544,8 +1615,8 @@ command_loop_1 ()
          /* Here for a command that isn't executed directly */
 
 #ifdef HAVE_X_WINDOWS
          /* Here for a command that isn't executed directly */
 
 #ifdef HAVE_X_WINDOWS
-         if (display_busy_cursor_p)
-           start_busy_cursor ();
+         if (display_hourglass_p)
+           start_hourglass ();
 #endif
 
          nonundocount = 0;
 #endif
 
          nonundocount = 0;
@@ -1554,8 +1625,8 @@ command_loop_1 ()
          Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
 #ifdef HAVE_X_WINDOWS
          Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
 #ifdef HAVE_X_WINDOWS
-         if (display_busy_cursor_p)
-           cancel_busy_cursor ();
+         if (display_hourglass_p)
+           cancel_hourglass ();
 #endif
        }
     directly_done: ;
 #endif
        }
     directly_done: ;
@@ -1907,9 +1978,18 @@ make_ctrl_char (c)
    arguments; the function should return a help string or nil for
    none.  For all other types of HELP evaluate it to obtain a string.
 
    arguments; the function should return a help string or nil for
    none.  For all other types of HELP evaluate it to obtain a string.
 
-   OBJECT is the object where a `help-echo' property was found; POS
-   is the position within OBJECT where it was found.  OBJECT is nil
-   if HELP isn't from a `help-echo' text property.
+   WINDOW is the window in which the help was generated, if any.
+   It is nil if not in a window.
+
+   If OBJECT is a buffer, POS is the position in the buffer where the
+   `help-echo' text property was found.
+
+   If OBJECT is an overlay, that overlay has a `help-echo' property,
+   and POS is the position in the overlay's buffer under the mouse.
+
+   If OBJECT is a string (an overlay string or a string displayed with
+   the `display' property).  POS is the position in that string under
+   the mouse.
 
    OK_TO_IVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help
    echo overwrites a keystroke echo currently displayed in the echo
 
    OK_TO_IVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help
    echo overwrites a keystroke echo currently displayed in the echo
@@ -1919,22 +1999,23 @@ make_ctrl_char (c)
    from X code running asynchronously.  */
 
 void
    from X code running asynchronously.  */
 
 void
-show_help_echo (help, object, pos, ok_to_overwrite_keystroke_echo)
-     Lisp_Object help, object, pos;
+show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
+     Lisp_Object help, window, object, pos;
      int ok_to_overwrite_keystroke_echo;
 {
   if (!NILP (help) && !STRINGP (help))
     {
       if (FUNCTIONP (help))
        {
      int ok_to_overwrite_keystroke_echo;
 {
   if (!NILP (help) && !STRINGP (help))
     {
       if (FUNCTIONP (help))
        {
-         Lisp_Object args[3];
+         Lisp_Object args[4];
          args[0] = help;
          args[0] = help;
-         args[1] = object;
-         args[2] = pos;
-         help = call_function (3, args);
+         args[1] = window;
+         args[2] = object;
+         args[3] = pos;
+         help = safe_call (4, args);
        }
       else
        }
       else
-       help = eval_form (help);
+       help = safe_eval (help);
       
       if (!STRINGP (help))
        return;
       
       if (!STRINGP (help))
        return;
@@ -1956,13 +2037,15 @@ show_help_echo (help, object, pos, ok_to_overwrite_keystroke_echo)
            {
              int count = specpdl_ptr - specpdl;
              specbind (Qmessage_truncate_lines, Qt);
            {
              int count = specpdl_ptr - specpdl;
              specbind (Qmessage_truncate_lines, Qt);
-             message3_nolog (help, XSTRING (help)->size,
+             message3_nolog (help, STRING_BYTES (XSTRING (help)),
                              STRING_MULTIBYTE (help));
              unbind_to (count, Qnil);
            }
          else
                              STRING_MULTIBYTE (help));
              unbind_to (count, Qnil);
            }
          else
-           message (0);
+             message (0);
        }
        }
+      
+      help_echo_showing_p = STRINGP (help);
     }
 }
 
     }
 }
 
@@ -2006,16 +2089,17 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      Lisp_Object prev_event;
      int *used_mouse_menu;
 {
      Lisp_Object prev_event;
      int *used_mouse_menu;
 {
-  Lisp_Object c;
+  volatile Lisp_Object c;
   int count;
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   int count;
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
-  int key_already_recorded = 0;
+  volatile int key_already_recorded = 0;
   Lisp_Object tem, save;
   Lisp_Object tem, save;
-  Lisp_Object previous_echo_area_message;
-  Lisp_Object also_record;
-  int reread;
+  volatile Lisp_Object previous_echo_area_message;
+  volatile Lisp_Object also_record;
+  volatile int reread;
   struct gcpro gcpro1, gcpro2;
   struct gcpro gcpro1, gcpro2;
+  EMACS_TIME last_idle_start;
 
   also_record = Qnil;
 
 
   also_record = Qnil;
 
@@ -2067,6 +2151,12 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && NILP (XCDR (c)))
        c = XCAR (c);
 
          && NILP (XCDR (c)))
        c = XCAR (c);
 
+      /* If the queued event is something that used the mouse,
+         set used_mouse_menu accordingly.  */
+      if (used_mouse_menu
+         && (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar)))
+       *used_mouse_menu = 1;
+      
       reread = 1;
       goto reread_for_input_method;
     }
       reread = 1;
       goto reread_for_input_method;
     }
@@ -2146,7 +2236,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Redisplay if no pending input.  */
       while (!input_pending)
        {
       /* Redisplay if no pending input.  */
       while (!input_pending)
        {
-         redisplay ();
+         if (help_echo_showing_p && !EQ (selected_window, minibuf_window))
+           redisplay_preserve_echo_area (5);
+         else
+           redisplay ();
 
          if (!input_pending)
            /* Normal case: no input arrived during redisplay.  */
 
          if (!input_pending)
            /* Normal case: no input arrived during redisplay.  */
@@ -2454,6 +2547,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Actually read a character, waiting if necessary.  */
       save_getcjmp (save_jump);
       restore_getcjmp (local_getcjmp);
       /* Actually read a character, waiting if necessary.  */
       save_getcjmp (save_jump);
       restore_getcjmp (local_getcjmp);
+      timer_start_idle ();
       c = kbd_buffer_get_event (&kb, used_mouse_menu);
       restore_getcjmp (save_jump);
 
       c = kbd_buffer_get_event (&kb, used_mouse_menu);
       restore_getcjmp (save_jump);
 
@@ -2499,8 +2593,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
 
  non_reread:
 
+  /* Record the last idle start time so that we can reset it
+     should the next event read be a help-echo.  */
+  last_idle_start = timer_idleness_start_time;
   timer_stop_idle ();
   timer_stop_idle ();
-
   start_polling ();
 
   if (NILP (c))
   start_polling ();
 
   if (NILP (c))
@@ -2524,8 +2620,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      and loop around to read another event.  */
   save = Vquit_flag;
   Vquit_flag = Qnil;
      and loop around to read another event.  */
   save = Vquit_flag;
   Vquit_flag = Qnil;
-  tem = get_keyelt (access_keymap (get_keymap_1 (Vspecial_event_map, 0, 0),
-                                  c, 0, 0), 1);
+  tem = access_keymap (get_keymap (Vspecial_event_map, 0, 1), c, 0, 0, 1);
   Vquit_flag = save;
 
   if (!NILP (tem))
   Vquit_flag = save;
 
   if (!NILP (tem))
@@ -2710,12 +2805,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* Display help if not echoing.  */
   if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
     {
   /* Display help if not echoing.  */
   if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
     {
-      /* (help-echo FRAME HELP OBJECT POS).  */
-      Lisp_Object help, object, position;
+      /* (help-echo FRAME HELP WINDOW OBJECT POS).  */
+      Lisp_Object help, object, position, window;
       help = Fnth (make_number (2), c);
       help = Fnth (make_number (2), c);
-      object = Fnth (make_number (3), c);
-      position = Fnth (make_number (4), c);
-      show_help_echo (help, object, position, 0);
+      window = Fnth (make_number (3), c);
+      object = Fnth (make_number (4), c);
+      position = Fnth (make_number (5), c);
+      show_help_echo (help, window, object, position, 0);
+
+      /* We stopped being idle for this event; undo that.  */
+      timer_idleness_start_time = last_idle_start;
       goto retry;
     }
   
       goto retry;
     }
   
@@ -2836,11 +2935,44 @@ static void
 record_char (c)
      Lisp_Object c;
 {
 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;
+  /* Don't record `help-echo' in recent_keys unless it shows some help
+     message, and a different help than the previoiusly recorded
+     event.  */
+  if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
+    {
+      Lisp_Object help;
 
 
+      help = Fnth (make_number (2), c);
+      if (STRINGP (help))
+       {
+         int last_idx;
+         Lisp_Object last_c, last_help;
+         
+         last_idx = recent_keys_index - 1;
+         if (last_idx < 0)
+           last_idx = NUM_RECENT_KEYS - 1;
+         last_c = AREF (recent_keys, last_idx);
+         
+         if (!CONSP (last_c)
+             || !EQ (XCAR (last_c), Qhelp_echo)
+             || (last_help = Fnth (make_number (2), last_c),
+                 !EQ (last_help, help)))
+           {
+             total_keys++;
+             ASET (recent_keys, recent_keys_index, c);
+             if (++recent_keys_index >= NUM_RECENT_KEYS)
+               recent_keys_index = 0;
+           }
+       }
+    }
+  else
+    {
+      total_keys++;
+      ASET (recent_keys, 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.  :-) */
   /* 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.  :-) */
@@ -2873,7 +3005,8 @@ record_char (c)
       fflush (dribble);
     }
 
       fflush (dribble);
     }
 
-  store_kbd_macro_char (c);
+  if (!CONSP (c) || !EQ (Qhelp_echo, XCAR (c)))
+    store_kbd_macro_char (c);
 
   num_nonmacro_input_events++;
 }
 
   num_nonmacro_input_events++;
 }
@@ -2928,7 +3061,7 @@ tracking_off (old_value)
         redisplay.  */
       if (!readable_events (1))
        {
         redisplay.  */
       if (!readable_events (1))
        {
-         redisplay_preserve_echo_area ();
+         redisplay_preserve_echo_area (6);
          get_input_pending (&input_pending, 1);
        }
     }
          get_input_pending (&input_pending, 1);
        }
     }
@@ -3162,36 +3295,45 @@ kbd_buffer_store_event (event)
 }
 
 
 }
 
 
-/* Generate HELP_EVENT input_events in BUFP.
+/* Generate HELP_EVENT input_events in BUFP which has room for
+   SIZE events.  If there's not enough room in BUFP, ignore this
+   event.
 
    HELP is the help form.
 
    FRAME is the frame on which the help is generated.  OBJECT is the
 
    HELP is the help form.
 
    FRAME is the frame on which the help is generated.  OBJECT is the
-   Lisp object where the help was found (a buffer, a string, or nil if
-   neither from a string nor from a buffer.  POS is the position
-   within OBJECT where the help was found.
+   Lisp object where the help was found (a buffer, a string, an
+   overlay, or nil if neither from a string nor from a buffer.  POS is
+   the position within OBJECT where the help was found.
 
    Value is the number of input_events generated.  */
 
 int
 
    Value is the number of input_events generated.  */
 
 int
-gen_help_event (bufp, help, frame, object, pos)
+gen_help_event (bufp, size, help, frame, window, object, pos)
      struct input_event *bufp;
      struct input_event *bufp;
-     Lisp_Object help, frame, object;
+     int size;
+     Lisp_Object help, frame, object, window;
      int pos;
 {
      int pos;
 {
-  bufp->kind = HELP_EVENT;
-  bufp->frame_or_window = frame;
-  bufp->arg = object;
-  bufp->x = make_number (pos);
-  bufp->code = 0;
-
-  ++bufp;
-  bufp->kind = HELP_EVENT;
-  bufp->frame_or_window = frame;
-  bufp->arg = help;
-  bufp->code = 1;
+  int nevents_stored = 0;
   
   
-  return 2;
+  if (size >= 2)
+    {
+      bufp->kind = HELP_EVENT;
+      bufp->frame_or_window = frame;
+      bufp->arg = object;
+      bufp->x = make_number (pos);
+      bufp->code = 0;
+
+      ++bufp;
+      bufp->kind = HELP_EVENT;
+      bufp->frame_or_window = WINDOWP (window) ? window : frame;
+      bufp->arg = help;
+      bufp->code = 1;
+      nevents_stored = 2;
+    }
+
+  return nevents_stored;
 }
 
 
 }
 
 
@@ -3240,7 +3382,49 @@ discard_mouse_events ()
        }
     }
 }
        }
     }
 }
+
+
+/* Return non-zero if there are any real events waiting in the event
+   buffer, not counting `no_event's.
+
+   If DISCARD is non-zero, discard no_event events at the front of
+   the input queue, possibly leaving the input queue empty if there
+   are no real input events.  */
+
+int
+kbd_buffer_events_waiting (discard)
+     int discard;
+{
+  struct input_event *sp;
+  
+  for (sp = kbd_fetch_ptr;
+       sp != kbd_store_ptr && sp->kind == no_event;
+       ++sp)
+    {
+      if (sp == kbd_buffer + KBD_BUFFER_SIZE)
+       sp = kbd_buffer;
+    }
+
+  if (discard)
+    kbd_fetch_ptr = sp;
+
+  return sp != kbd_store_ptr && sp->kind != no_event;
+}
+
 \f
 \f
+/* Clear input event EVENT.  */
+
+static INLINE void
+clear_event (event)
+     struct input_event *event;
+{
+  int idx = 2 * (event - kbd_buffer);
+  ASET (kbd_buffer_gcpro, idx, Qnil);
+  ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+  event->kind = no_event;
+}
+
+
 /* Read one event from the event buffer, waiting if necessary.
    The value is a Lisp object representing the event.
    The value is nil for an event that should be ignored,
 /* Read one event from the event buffer, waiting if necessary.
    The value is a Lisp object representing the event.
    The value is nil for an event that should be ignored,
@@ -3377,7 +3561,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          abort ();
 #endif
        }
          abort ();
 #endif
        }
-#if defined (HAVE_X11) || defined (HAVE_NTGUI)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (macintosh)
       else if (event->kind == delete_window_event)
        {
          /* Make an event (delete-frame (FRAME)).  */
       else if (event->kind == delete_window_event)
        {
          /* Make an event (delete-frame (FRAME)).  */
@@ -3385,6 +3569,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          obj = Fcons (Qdelete_frame, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
          obj = Fcons (Qdelete_frame, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
+#endif
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
       else if (event->kind == iconify_event)
        {
          /* Make an event (iconify-frame (FRAME)).  */
       else if (event->kind == iconify_event)
        {
          /* Make an event (iconify-frame (FRAME)).  */
@@ -3406,7 +3592,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
       else if (event->kind == menu_bar_activate_event)
        {
          kbd_fetch_ptr = event + 1;
       else if (event->kind == menu_bar_activate_event)
        {
          kbd_fetch_ptr = event + 1;
@@ -3438,21 +3624,28 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        kbd_fetch_ptr = event + 1;
       else if (event->kind == HELP_EVENT)
        {
        kbd_fetch_ptr = event + 1;
       else if (event->kind == HELP_EVENT)
        {
-         /* There are always two consecutive HELP_EVENTs in the
-            input queue.  */
-         Lisp_Object object, position, help, frame;
-         
+         /* There are always two HELP_EVENTs in the input queue.  */
+         Lisp_Object object, position, help, frame, window;
+
          xassert (event->code == 0);
          frame = event->frame_or_window;
          object = event->arg;
          position = event->x;
          xassert (event->code == 0);
          frame = event->frame_or_window;
          object = event->arg;
          position = event->x;
-         xassert ((event + 1)->code == 1);
-         help = (event + 1)->arg;
-         
-         /* Event->frame_or_window is a frame, event->arg is the
-            help to display.  */
-         obj = list5 (Qhelp_echo, frame, help, object, position);
-         kbd_fetch_ptr = event + 2;
+         clear_event (event);
+
+         kbd_fetch_ptr = event + 1;
+         event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
+                  ? kbd_fetch_ptr
+                  : kbd_buffer);
+         xassert (event->code == 1);
+         help = event->arg;
+         window = event->frame_or_window;
+         if (!WINDOWP (window))
+           window = Qnil;
+         obj = Fcons (Qhelp_echo,
+                      list5 (frame, help, window, object, position));
+         clear_event (event);
+         kbd_fetch_ptr = event + 1;
        }
       else if (event->kind == FOCUS_IN_EVENT)
        {
        }
       else if (event->kind == FOCUS_IN_EVENT)
        {
@@ -3499,8 +3692,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
          if (NILP (obj))
            {
 
          if (NILP (obj))
            {
-             int idx;
-             
              obj = make_lispy_event (event);
              
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
              obj = make_lispy_event (event);
              
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
@@ -3517,11 +3708,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif
 
              /* Wipe out this event, to catch bugs.  */
 #endif
 
              /* Wipe out this event, to catch bugs.  */
-             event->kind = no_event;
-             idx = 2 * (event - kbd_buffer);
-             ASET (kbd_buffer_gcpro, idx, Qnil);
-             ASET (kbd_buffer_gcpro, idx + 1, Qnil);
-
+             clear_event (event);
              kbd_fetch_ptr = event + 1;
            }
        }
              kbd_fetch_ptr = event + 1;
            }
        }
@@ -3645,11 +3832,9 @@ swallow_events (do_display)
   get_input_pending (&input_pending, 1);
 
   if (timers_run != old_timers_run && do_display)
   get_input_pending (&input_pending, 1);
 
   if (timers_run != old_timers_run && do_display)
-    redisplay_preserve_echo_area ();
+    redisplay_preserve_echo_area (7);
 }
 \f
 }
 \f
-static EMACS_TIME timer_idleness_start_time;
-
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
@@ -3734,7 +3919,7 @@ timer_check (do_it_now)
   while (CONSP (timers) || CONSP (idle_timers))
     {
       Lisp_Object *vector;
   while (CONSP (timers) || CONSP (idle_timers))
     {
       Lisp_Object *vector;
-      Lisp_Object timer, idle_timer;
+      Lisp_Object timer = Qnil, idle_timer = Qnil;
       EMACS_TIME timer_time, idle_timer_time;
       EMACS_TIME difference, timer_difference, idle_timer_difference;
 
       EMACS_TIME timer_time, idle_timer_time;
       EMACS_TIME difference, timer_difference, idle_timer_difference;
 
@@ -3845,17 +4030,18 @@ timer_check (do_it_now)
          if (NILP (vector[0]))
            {
              int was_locked = single_kboard;
          if (NILP (vector[0]))
            {
              int was_locked = single_kboard;
-             int count = specpdl_ptr - specpdl;
+             int count = BINDING_STACK_SIZE ();
+             Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
              vector[0] = Qt;
 
              specbind (Qinhibit_quit, Qt);
 
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
              vector[0] = Qt;
 
              specbind (Qinhibit_quit, Qt);
-
+             
              call1 (Qtimer_event_handler, chosen_timer);
              call1 (Qtimer_event_handler, chosen_timer);
+             Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
              timers_run++;
-
              unbind_to (count, Qnil);
 
              /* Resume allowing input from any kboard, if that was true before.  */
              unbind_to (count, Qnil);
 
              /* Resume allowing input from any kboard, if that was true before.  */
@@ -4407,6 +4593,14 @@ make_lispy_event (event)
        return lispy_c;
       }
 
        return lispy_c;
       }
 
+    case multibyte_char_keystroke:
+      {
+       Lisp_Object lispy_c;
+
+       XSETFASTINT (lispy_c, event->code);
+       return lispy_c;
+      }
+
       /* A function key.  The symbol may need to have modifier prefixes
         tacked onto it.  */
     case non_ascii_keystroke:
       /* A function key.  The symbol may need to have modifier prefixes
         tacked onto it.  */
     case non_ascii_keystroke:
@@ -4478,6 +4672,8 @@ make_lispy_event (event)
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
 
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
 
+       position = Qnil;
+
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == mouse_click)
          {
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == mouse_click)
          {
@@ -4530,14 +4726,14 @@ make_lispy_event (event)
                for (i = 0; i < XVECTOR (items)->size; i += 4)
                  {
                    Lisp_Object pos, string;
                for (i = 0; i < XVECTOR (items)->size; i += 4)
                  {
                    Lisp_Object pos, string;
-                   string = XVECTOR (items)->contents[i + 1];
-                   pos = XVECTOR (items)->contents[i + 3];
+                   string = AREF (items, i + 1);
+                   pos = AREF (items, i + 3);
                    if (NILP (string))
                      break;
                    if (column >= XINT (pos)
                        && column < XINT (pos) + XSTRING (string)->size)
                      {
                    if (NILP (string))
                      break;
                    if (column >= XINT (pos)
                        && column < XINT (pos) + XSTRING (string)->size)
                      {
-                       item = XVECTOR (items)->contents[i];
+                       item = AREF (items, i);
                        break;
                      }
                  }
                        break;
                      }
                  }
@@ -4583,7 +4779,7 @@ make_lispy_event (event)
 
                if (part == 1 || part == 3)
                  {
 
                if (part == 1 || part == 3)
                  {
-                   /* Mode line or top line.  Look for a string under
+                   /* Mode line or header line.  Look for a string under
                       the mouse that may have a `local-map' property.  */
                    Lisp_Object string;
                    int charpos;
                       the mouse that may have a `local-map' property.  */
                    Lisp_Object string;
                    int charpos;
@@ -4596,7 +4792,16 @@ make_lispy_event (event)
                else if (part == 2)
                  posn = Qvertical_line;
                else
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+                 {
+                   Lisp_Object object;
+                   struct display_pos p;
+                   buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+                   posn = make_number (CHARPOS (p.pos));
+                   if (STRINGP (object))
+                     string_info
+                       = Fcons (object,
+                                make_number (CHARPOS (p.string_pos)));
+                 }
              }
 
            position
              }
 
            position
@@ -4629,15 +4834,14 @@ make_lispy_event (event)
          }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
          }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
-       if (button >= XVECTOR (button_down_location)->size)
+       if (button >= ASIZE (button_down_location))
          {
            button_down_location = larger_vector (button_down_location,
                                                  button + 1, Qnil);
            mouse_syms = larger_vector (mouse_syms, button + 1, Qnil);
          }
        
          {
            button_down_location = larger_vector (button_down_location,
                                                  button + 1, Qnil);
            mouse_syms = larger_vector (mouse_syms, button + 1, Qnil);
          }
        
-       start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
-
+       start_pos_ptr = &AREF (button_down_location, button);
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
@@ -4674,12 +4878,11 @@ make_lispy_event (event)
            see if this was a click or a drag.  */
        else if (event->modifiers & up_modifier)
          {
            see if this was a click or a drag.  */
        else if (event->modifiers & up_modifier)
          {
-           /* If we did not see a down before this up,
-              ignore the up.  Probably this happened because
-              the down event chose a menu item.
-              It would be an annoyance to treat the release
-              of the button that chose the menu item
-              as a separate event.  */
+           /* If we did not see a down before this up, ignore the up.
+              Probably this happened because the down event chose a
+              menu item.  It would be an annoyance to treat the
+              release of the button that chose the menu item as a
+              separate event.  */
 
            if (!CONSP (start_pos))
              return Qnil;
 
            if (!CONSP (start_pos))
              return Qnil;
@@ -4696,16 +4899,29 @@ make_lispy_event (event)
                Lisp_Object down;
 
                down = Fnth (make_number (2), start_pos);
                Lisp_Object down;
 
                down = Fnth (make_number (2), start_pos);
-               if (EQ (event->x, XCAR (down))
-                   && EQ (event->y, XCDR (down)))
-                 {
-                   event->modifiers |= click_modifier;
-                 }
+               if (EQ (event->x, XCAR (down)) && EQ (event->y, XCDR (down)))
+                 /* Mouse hasn't moved.  */
+                 event->modifiers |= click_modifier;
                else
                  {
                else
                  {
-                   button_down_time = 0;
-                   event->modifiers |= drag_modifier;
+                   Lisp_Object window1, window2, posn1, posn2;
+
+                   /* Avoid generating a drag event if the mouse
+                      hasn't actually moved off the buffer position.  */
+                   window1 = Fnth (make_number (0), position);
+                   posn1 = Fnth (make_number (1), position);
+                   window2 = Fnth (make_number (0), start_pos);
+                   posn2 = Fnth (make_number (1), start_pos);
+
+                   if (EQ (window1, window2) && EQ (posn1, posn2))
+                     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)
                /* Don't check is_double; treat this as multiple
                   if the down-event was multiple.  */
                if (double_click_count > 1)
@@ -4854,7 +5070,8 @@ make_lispy_event (event)
          return Qnil;
        pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                               &column, &row, NULL, 1);
          return Qnil;
        pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                               &column, &row, NULL, 1);
-       window = window_from_coordinates (f, column, row, &part, 0);
+       window = window_from_coordinates (f, XINT (event->x),
+                                          XINT (event->y), &part, 0);
 
        if (!WINDOWP (window))
          {
 
        if (!WINDOWP (window))
          {
@@ -4878,9 +5095,13 @@ make_lispy_event (event)
            else if (part == 3)
              posn = Qheader_line;
            else
            else if (part == 3)
              posn = Qheader_line;
            else
-             XSETINT (posn,
-                      buffer_posn_from_coords (XWINDOW (window),
-                                               &column, &row));
+             {
+               Lisp_Object object;
+               struct display_pos p;
+               buffer_posn_from_coords (XWINDOW (window), &column, &row,
+                                        &object, &p);
+               posn = make_number (CHARPOS (p.pos));
+             }
          }
 
        {
          }
 
        {
@@ -4912,7 +5133,6 @@ make_lispy_event (event)
        Lisp_Object window;
        Lisp_Object posn;
        Lisp_Object files;
        Lisp_Object window;
        Lisp_Object posn;
        Lisp_Object files;
-       int row, column;
 
        /* The frame_or_window field should be a cons of the frame in
           which the event occurred and a list of the filenames
 
        /* The frame_or_window field should be a cons of the frame in
           which the event occurred and a list of the filenames
@@ -4927,9 +5147,9 @@ make_lispy_event (event)
           have been deleted.  */
        if (! FRAME_LIVE_P (f))
          return Qnil;
           have been deleted.  */
        if (! FRAME_LIVE_P (f))
          return Qnil;
-       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                              &column, &row, NULL, 1);
-       window = window_from_coordinates (f, column, row, &part, 0);
+
+       window = window_from_coordinates (f, XINT (event->x),
+                                          XINT (event->y), &part, 0);
 
        if (!WINDOWP (window))
          {
 
        if (!WINDOWP (window))
          {
@@ -4958,7 +5178,12 @@ make_lispy_event (event)
            else if (part == 3)
              posn = Qheader_line;
            else
            else if (part == 3)
              posn = Qheader_line;
            else
-             XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+             {
+               Lisp_Object object;
+               struct display_pos p;
+               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+               posn = make_number (CHARPOS (p.pos));
+             }
          }
 
        {
          }
 
        {
@@ -4983,7 +5208,7 @@ make_lispy_event (event)
       }
 #endif /* HAVE_MOUSE */
 
       }
 #endif /* HAVE_MOUSE */
 
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
     case MENU_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
     case MENU_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
@@ -5070,7 +5295,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
          else if (area == 3)
            posn = Qheader_line;
          else
          else if (area == 3)
            posn = Qheader_line;
          else
-           XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+           {
+             Lisp_Object object;
+             struct display_pos p;
+             buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+             posn = make_number (CHARPOS (p.pos));
+           }
        }
       else if (frame != 0)
        {
        }
       else if (frame != 0)
        {
@@ -5427,7 +5657,7 @@ reorder_modifiers (symbol)
 
    Alternatively, NAME_ALIST_OR_STEM is either an alist mapping codes
    into symbol names, or a string specifying a name stem used to
 
    Alternatively, NAME_ALIST_OR_STEM is either an alist mapping codes
    into symbol names, or a string specifying a name stem used to
-   contruct a symbol name or the form `STEM-N', where N is the decimal
+   construct a symbol name or the form `STEM-N', where N is the decimal
    representation of SYMBOL_NUM.  NAME_ALIST_OR_STEM is used if it is
    non-nil; otherwise NAME_TABLE is used.
 
    representation of SYMBOL_NUM.  NAME_ALIST_OR_STEM is used if it is
    non-nil; otherwise NAME_TABLE is used.
 
@@ -5604,7 +5834,10 @@ has the same base event type and all the specified modifiers.")
   else if (SYMBOLP (base))
     return apply_modifiers (modifiers, base);
   else
   else if (SYMBOLP (base))
     return apply_modifiers (modifiers, base);
   else
-    error ("Invalid base event");
+    {
+      error ("Invalid base event");
+      return Qnil;
+    }
 }
 
 /* Try to recognize SYMBOL as a modifier name.
 }
 
 /* Try to recognize SYMBOL as a modifier name.
@@ -5700,6 +5933,12 @@ lucid_event_type_list_p (object)
   if (! CONSP (object))
     return 0;
 
   if (! CONSP (object))
     return 0;
 
+  if (EQ (XCAR (object), Qhelp_echo)
+      || EQ (XCAR (object), Qvertical_line)
+      || EQ (XCAR (object), Qmode_line)
+      || EQ (XCAR (object), Qheader_line))
+    return 0;
+
   for (tail = object; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object elt;
   for (tail = object; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object elt;
@@ -6041,8 +6280,8 @@ map_prompt (map)
   return Qnil;
 }
 
   return Qnil;
 }
 
-static void menu_bar_item ();
-static void menu_bar_one_keymap ();
+static void menu_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void menu_bar_one_keymap P_ ((Lisp_Object));
 
 /* These variables hold the vector under construction within
    menu_bar_items and its subroutines, and the current index
 
 /* These variables hold the vector under construction within
    menu_bar_items and its subroutines, and the current index
@@ -6068,7 +6307,7 @@ menu_bar_items (old)
      in the current keymaps, or nil where it is not a prefix.  */
   Lisp_Object *maps;
 
      in the current keymaps, or nil where it is not a prefix.  */
   Lisp_Object *maps;
 
-  Lisp_Object def, tem, tail;
+  Lisp_Object def, tail;
 
   Lisp_Object result;
 
 
   Lisp_Object result;
 
@@ -6119,7 +6358,7 @@ menu_bar_items (old)
       {
        /* No, so use major and minor mode keymaps and keymap property.  */
        int extra_maps = 2;
       {
        /* No, so use major and minor mode keymaps and keymap property.  */
        int extra_maps = 2;
-       Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+       Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
        if (!NILP (map))
          extra_maps = 3;
        nmaps = current_minor_maps (NULL, &tmaps);
        if (!NILP (map))
          extra_maps = 3;
        nmaps = current_minor_maps (NULL, &tmaps);
@@ -6127,8 +6366,8 @@ menu_bar_items (old)
                                       * sizeof (maps[0]));
        bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
        if (!NILP (map))
                                       * sizeof (maps[0]));
        bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
        if (!NILP (map))
-         maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
-       maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+         maps[nmaps++] = map;
+       maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
       }
     maps[nmaps++] = current_global_map;
   }
       }
     maps[nmaps++] = current_global_map;
   }
@@ -6138,16 +6377,13 @@ menu_bar_items (old)
   result = Qnil;
 
   for (mapno = nmaps - 1; mapno >= 0; mapno--)
   result = Qnil;
 
   for (mapno = nmaps - 1; mapno >= 0; mapno--)
-    {
-      if (! NILP (maps[mapno]))
-       def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0), 0);
-      else
-       def = Qnil;
-
-      tem = Fkeymapp (def);
-      if (!NILP (tem))
-       menu_bar_one_keymap (def);
-    }
+    if (!NILP (maps[mapno]))
+      {
+       def = get_keymap (access_keymap (maps[mapno], Qmenu_bar, 1, 0, 1),
+                         0, 1);
+       if (CONSP (def))
+         menu_bar_one_keymap (def);
+      }
 
   /* Move to the end those items that should be at the end.  */
 
 
   /* Move to the end those items that should be at the end.  */
 
@@ -6260,29 +6496,27 @@ menu_bar_item (key, item)
                     &XVECTOR (menu_bar_items_vector)->contents[i],
                     (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
            menu_bar_items_index -= 4;
                     &XVECTOR (menu_bar_items_vector)->contents[i],
                     (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
            menu_bar_items_index -= 4;
-           return;
          }
          }
-
-      /* If there's no definition for this key yet,
-        just ignore `undefined'.  */
-      return;
     }
 
     }
 
-  GCPRO1 (key);                        /* Is this necessary? */
-  i = parse_menu_item (item, 0, 1);
-  UNGCPRO;
-  if (!i)
-    return;
-
   /* If this keymap has already contributed to this KEY,
      don't contribute to it a second time.  */
   tem = Fmemq (key, menu_bar_one_keymap_changed_items);
   /* If this keymap has already contributed to this KEY,
      don't contribute to it a second time.  */
   tem = Fmemq (key, menu_bar_one_keymap_changed_items);
-  if (!NILP (tem))
+  if (!NILP (tem) || NILP (item))
     return;
 
   menu_bar_one_keymap_changed_items
     = Fcons (key, menu_bar_one_keymap_changed_items);
 
     return;
 
   menu_bar_one_keymap_changed_items
     = Fcons (key, menu_bar_one_keymap_changed_items);
 
+  /* We add to menu_bar_one_keymap_changed_items before doing the
+     parse_menu_item, so that if it turns out it wasn't a menu item,
+     it still correctly hides any further menu item.  */
+  GCPRO1 (key);
+  i = parse_menu_item (item, 0, 1);
+  UNGCPRO;
+  if (!i)
+    return;
+
   item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
 
   /* Find any existing item for this KEY.  */
   item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
 
   /* Find any existing item for this KEY.  */
@@ -6384,11 +6618,11 @@ parse_menu_item (item, notreal, inmenubar)
 
   /* Initialize optional entries.  */
   for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
 
   /* Initialize optional entries.  */
   for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
-    XVECTOR (item_properties)->contents[i] = Qnil;
-  XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = Qt;
+    AREF (item_properties, i) = Qnil;
+  AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
         
   /* Save the item here to protect it from GC.  */
         
   /* Save the item here to protect it from GC.  */
-  XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item;
+  AREF (item_properties, ITEM_PROPERTY_ITEM) = item;
 
   item_string = XCAR (item);
 
 
   item_string = XCAR (item);
 
@@ -6397,13 +6631,12 @@ parse_menu_item (item, notreal, inmenubar)
   if (STRINGP (item_string))
     {
       /* Old format menu item.  */
   if (STRINGP (item_string))
     {
       /* Old format menu item.  */
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+      AREF (item_properties, ITEM_PROPERTY_NAME) = item_string;
 
       /* Maybe help string.  */
       if (CONSP (item) && STRINGP (XCAR (item)))
        {
 
       /* Maybe help string.  */
       if (CONSP (item) && STRINGP (XCAR (item)))
        {
-         XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
-           = XCAR (item);
+         AREF (item_properties, ITEM_PROPERTY_HELP) = XCAR (item);
          start = item;
          item = XCDR (item);
        }
          start = item;
          item = XCDR (item);
        }
@@ -6418,27 +6651,25 @@ parse_menu_item (item, notreal, inmenubar)
        }
       
       /* This is the real definition--the function to run.  */
        }
       
       /* This is the real definition--the function to run.  */
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = item;
+      AREF (item_properties, ITEM_PROPERTY_DEF) = item;
 
       /* Get enable property, if any.  */
       if (SYMBOLP (item))
        {
          tem = Fget (item, Qmenu_enable);
          if (!NILP (tem))
 
       /* Get enable property, if any.  */
       if (SYMBOLP (item))
        {
          tem = Fget (item, Qmenu_enable);
          if (!NILP (tem))
-           XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+           AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
        }
     }
   else if (EQ (item_string, Qmenu_item) && CONSP (item))
     {
       /* New format menu item.  */
        }
     }
   else if (EQ (item_string, Qmenu_item) && CONSP (item))
     {
       /* New format menu item.  */
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]
-       = XCAR (item);
+      AREF (item_properties, ITEM_PROPERTY_NAME) = XCAR (item);
       start = XCDR (item);
       if (CONSP (start))
        {
          /* We have a real binding.  */
       start = XCDR (item);
       if (CONSP (start))
        {
          /* We have a real binding.  */
-         XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]
-           = XCAR (start);
+         AREF (item_properties, ITEM_PROPERTY_DEF) = XCAR (start);
 
          item = XCDR (start);
          /* Is there a cache list with key equivalences. */
 
          item = XCDR (start);
          /* Is there a cache list with key equivalences. */
@@ -6455,8 +6686,7 @@ parse_menu_item (item, notreal, inmenubar)
              item = XCDR (item);
 
              if (EQ (tem, QCenable))
              item = XCDR (item);
 
              if (EQ (tem, QCenable))
-               XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]
-                 = XCAR (item);
+               AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
              else if (EQ (tem, QCvisible) && !notreal)
                {
                  /* If got a visible property and that evaluates to nil
              else if (EQ (tem, QCvisible) && !notreal)
                {
                  /* If got a visible property and that evaluates to nil
@@ -6466,8 +6696,7 @@ parse_menu_item (item, notreal, inmenubar)
                    return 0;
                }
              else if (EQ (tem, QChelp))
                    return 0;
                }
              else if (EQ (tem, QChelp))
-               XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
-                 = XCAR (item);
+               AREF (item_properties, ITEM_PROPERTY_HELP) = XCAR (item);
              else if (EQ (tem, QCfilter))
                filter = item;
              else if (EQ (tem, QCkey_sequence))
              else if (EQ (tem, QCfilter))
                filter = item;
              else if (EQ (tem, QCkey_sequence))
@@ -6482,8 +6711,7 @@ parse_menu_item (item, notreal, inmenubar)
                {
                  tem = XCAR (item);
                  if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
                {
                  tem = XCAR (item);
                  if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
-                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
-                     = tem;
+                   AREF (item_properties, ITEM_PROPERTY_KEYEQ) = tem;
                }
              else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
                {
                }
              else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
                {
@@ -6492,9 +6720,9 @@ parse_menu_item (item, notreal, inmenubar)
                  type = XCAR (tem);
                  if (EQ (type, QCtoggle) || EQ (type, QCradio))
                    {
                  type = XCAR (tem);
                  if (EQ (type, QCtoggle) || EQ (type, QCradio))
                    {
-                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+                     AREF (item_properties, ITEM_PROPERTY_SELECTED)
                        = XCDR (tem);
                        = XCDR (tem);
-                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+                     AREF (item_properties, ITEM_PROPERTY_TYPE)
                        = type;
                    }
                }
                        = type;
                    }
                }
@@ -6509,23 +6737,23 @@ parse_menu_item (item, notreal, inmenubar)
 
   /* If item string is not a string, evaluate it to get string.
      If we don't get a string, skip this item.  */
 
   /* If item string is not a string, evaluate it to get string.
      If we don't get a string, skip this item.  */
-  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+  item_string = AREF (item_properties, ITEM_PROPERTY_NAME);
   if (!(STRINGP (item_string) || notreal))
     {
       item_string = menu_item_eval_property (item_string);
       if (!STRINGP (item_string))
        return 0;
   if (!(STRINGP (item_string) || notreal))
     {
       item_string = menu_item_eval_property (item_string);
       if (!STRINGP (item_string))
        return 0;
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+      AREF (item_properties, ITEM_PROPERTY_NAME) = item_string;
     }
      
   /* If got a filter apply it on definition.  */
     }
      
   /* If got a filter apply it on definition.  */
-  def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+  def = AREF (item_properties, ITEM_PROPERTY_DEF);
   if (!NILP (filter))
     {
       def = menu_item_eval_property (list2 (XCAR (filter),
                                            list2 (Qquote, def)));
 
   if (!NILP (filter))
     {
       def = menu_item_eval_property (list2 (XCAR (filter),
                                            list2 (Qquote, def)));
 
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = def;
+      AREF (item_properties, ITEM_PROPERTY_DEF) = def;
     }
 
   /* If we got no definition, this item is just unselectable text which
     }
 
   /* If we got no definition, this item is just unselectable text which
@@ -6534,7 +6762,7 @@ parse_menu_item (item, notreal, inmenubar)
     return (inmenubar ? 0 : 1);
  
   /* Enable or disable selection of item.  */
     return (inmenubar ? 0 : 1);
  
   /* Enable or disable selection of item.  */
-  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+  tem = AREF (item_properties, ITEM_PROPERTY_ENABLE);
   if (!EQ (tem, Qt))
     {
       if (notreal)
   if (!EQ (tem, Qt))
     {
       if (notreal)
@@ -6543,19 +6771,20 @@ parse_menu_item (item, notreal, inmenubar)
        tem = menu_item_eval_property (tem);
       if (inmenubar && NILP (tem))
        return 0;               /* Ignore disabled items in menu bar.  */
        tem = menu_item_eval_property (tem);
       if (inmenubar && NILP (tem))
        return 0;               /* Ignore disabled items in menu bar.  */
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+      AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
     }
 
   /* See if this is a separate pane or a submenu.  */
     }
 
   /* See if this is a separate pane or a submenu.  */
-  def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
-  tem = get_keymap_1 (def, 0, 1);
+  def = AREF (item_properties, ITEM_PROPERTY_DEF);
+  tem = get_keymap (def, 0, 1);
   /* For a subkeymap, just record its details and exit.  */
   /* For a subkeymap, just record its details and exit.  */
-  if (!NILP (tem))
+  if (CONSP (tem))
     {
     {
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
-      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
+      AREF (item_properties, ITEM_PROPERTY_MAP) = tem;
+      AREF (item_properties, ITEM_PROPERTY_DEF) = tem;
       return 1;
     }
       return 1;
     }
+  
   /* At the top level in the menu bar, do likewise for commands also.
      The menu bar does not display equivalent key bindings anyway.
      ITEM_PROPERTY_DEF is already set up properly.  */
   /* At the top level in the menu bar, do likewise for commands also.
      The menu bar does not display equivalent key bindings anyway.
      ITEM_PROPERTY_DEF is already set up properly.  */
@@ -6570,7 +6799,7 @@ parse_menu_item (item, notreal, inmenubar)
       XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
       cachelist = XCAR (XCDR (start));
       newcache = 1;
       XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
       cachelist = XCAR (XCDR (start));
       newcache = 1;
-      tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+      tem = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (!NILP (keyhint))
        {
          XCAR (cachelist) = XCAR (keyhint);
       if (!NILP (keyhint))
        {
          XCAR (cachelist) = XCAR (keyhint);
@@ -6582,6 +6811,7 @@ parse_menu_item (item, notreal, inmenubar)
          XCAR (cachelist) = Qt;
        }
     }
          XCAR (cachelist) = Qt;
        }
     }
+  
   tem = XCAR (cachelist);
   if (!EQ (tem, Qt))
     {
   tem = XCAR (cachelist);
   if (!EQ (tem, Qt))
     {
@@ -6591,21 +6821,22 @@ parse_menu_item (item, notreal, inmenubar)
       if (!NILP (tem))
        tem = Fkey_binding (tem, Qnil);
 
       if (!NILP (tem))
        tem = Fkey_binding (tem, Qnil);
 
-      prefix = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+      prefix = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (CONSP (prefix))
        {
          def = XCAR (prefix);
          prefix = XCDR (prefix);
        }
       else
       if (CONSP (prefix))
        {
          def = XCAR (prefix);
          prefix = XCDR (prefix);
        }
       else
-       def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+       def = AREF (item_properties, ITEM_PROPERTY_DEF);
 
 
-      if (NILP (XCAR (cachelist))) /* Have no saved key.  */
+      if (!update_menu_bindings)
+       chkcache = 0;
+      else if (NILP (XCAR (cachelist))) /* Have no saved key.  */
        {
          if (newcache          /* Always check first time.  */
              /* Should we check everything when precomputing key
                 bindings?  */
        {
          if (newcache          /* Always check first time.  */
              /* Should we check everything when precomputing key
                 bindings?  */
-             /* || notreal */
              /* If something had no key binding before, don't recheck it
                 because that is too slow--except if we have a list of
                 rebound commands in Vdefine_key_rebound_commands, do
              /* If something had no key binding before, don't recheck it
                 because that is too slow--except if we have a list of
                 rebound commands in Vdefine_key_rebound_commands, do
@@ -6630,7 +6861,8 @@ parse_menu_item (item, notreal, inmenubar)
             command name has equivalent keys.  Otherwise look up the
             specified command itself.  We don't try both, because that
             makes lmenu menus slow. */
             command name has equivalent keys.  Otherwise look up the
             specified command itself.  We don't try both, because that
             makes lmenu menus slow. */
-         if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+         if (SYMBOLP (def)
+             && SYMBOLP (XSYMBOL (def)->function)
              && ! NILP (Fget (def, Qmenu_alias)))
            def = XSYMBOL (def)->function;
          tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
              && ! NILP (Fget (def, Qmenu_alias)))
            def = XSYMBOL (def)->function;
          tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
@@ -6674,7 +6906,7 @@ parse_menu_item (item, notreal, inmenubar)
     return 1;
 
   /* If we have an equivalent key binding, use that.  */
     return 1;
 
   /* If we have an equivalent key binding, use that.  */
-  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] = tem;
+  AREF (item_properties, ITEM_PROPERTY_KEYEQ) = tem;
 
   /* Include this when menu help is implemented.
   tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP];
 
   /* Include this when menu help is implemented.
   tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP];
@@ -6688,9 +6920,9 @@ parse_menu_item (item, notreal, inmenubar)
   */
 
   /* Handle radio buttons or toggle boxes.  */ 
   */
 
   /* Handle radio buttons or toggle boxes.  */ 
-  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+  tem = AREF (item_properties, ITEM_PROPERTY_SELECTED);
   if (!NILP (tem))
   if (!NILP (tem))
-    XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+    AREF (item_properties, ITEM_PROPERTY_SELECTED)
       = menu_item_eval_property (tem);
 
   return 1;
       = menu_item_eval_property (tem);
 
   return 1;
@@ -6778,7 +7010,7 @@ tool_bar_items (reuse, nitems)
     {
       /* No, so use major and minor mode keymaps and keymap property.  */
       int extra_maps = 2;
     {
       /* No, so use major and minor mode keymaps and keymap property.  */
       int extra_maps = 2;
-      Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
       if (!NILP (map))
        extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
       if (!NILP (map))
        extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
@@ -6786,8 +7018,8 @@ tool_bar_items (reuse, nitems)
                                     * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
       if (!NILP (map))
                                     * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
       if (!NILP (map))
-       maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
-      maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+       maps[nmaps++] = map;
+      maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
     }
 
   /* Add global keymap at the end.  */
     }
 
   /* Add global keymap at the end.  */
@@ -6799,9 +7031,9 @@ tool_bar_items (reuse, nitems)
     if (!NILP (maps[i]))
       {
        Lisp_Object keymap;
     if (!NILP (maps[i]))
       {
        Lisp_Object keymap;
-      
-       keymap = get_keyelt (access_keymap (maps[i], Qtool_bar, 1, 1), 0);
-       if (!NILP (Fkeymapp (keymap)))
+
+       keymap = get_keymap (access_keymap (maps[i], Qtool_bar, 1, 0, 1), 0, 1);
+       if (CONSP (keymap))
          {
            Lisp_Object tail;
            
          {
            Lisp_Object tail;
            
@@ -6918,9 +7150,9 @@ parse_tool_bar_item (key, item)
   extern Lisp_Object QCbutton, QCtoggle, QCradio;
   int i;
 
   extern Lisp_Object QCbutton, QCtoggle, QCradio;
   int i;
 
-  /* Defininition looks like `(tool-bar-item CAPTION BINDING
-     PROPS...)'.  Rule out items that aren't lists, don't start with
-     `tool-bar-item' or whose rest following `tool-bar-item' is not a
+  /* Defininition looks like `(menu-item CAPTION BINDING PROPS...)'.
+     Rule out items that aren't lists, don't start with
+     `menu-item' or whose rest following `tool-bar-item' is not a
      list.  */
   if (!CONSP (item)
       || !EQ (XCAR (item), Qmenu_item)
      list.  */
   if (!CONSP (item)
       || !EQ (XCAR (item), Qmenu_item)
@@ -6964,6 +7196,10 @@ parse_tool_bar_item (key, item)
   PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
   item = XCDR (item);
 
   PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
   item = XCDR (item);
 
+  /* Ignore cached key binding, if any.  */
+  if (CONSP (item) && CONSP (XCAR (item)))
+    item = XCDR (item);
+
   /* Process the rest of the properties.  */
   for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
     {
   /* Process the rest of the properties.  */
   for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
     {
@@ -7017,7 +7253,7 @@ parse_tool_bar_item (key, item)
                                               PROP (TOOL_BAR_ITEM_BINDING))));
 
   /* See if the binding is a keymap.  Give up if it is.  */
                                               PROP (TOOL_BAR_ITEM_BINDING))));
 
   /* See if the binding is a keymap.  Give up if it is.  */
-  if (!NILP (get_keymap_1 (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
+  if (CONSP (get_keymap (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
     return 0;
 
   /* Enable or disable selection of item.  */
     return 0;
 
   /* Enable or disable selection of item.  */
@@ -7223,6 +7459,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   Lisp_Object rest, vector;
   char *menu;
 
   Lisp_Object rest, vector;
   char *menu;
 
+  vector = Qnil;
+
   if (! menu_prompting)
     return Qnil;
 
   if (! menu_prompting)
     return Qnil;
 
@@ -7326,7 +7564,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
                  /* 1 if the char to type matches the string.  */
                  int char_matches;
                  Lisp_Object upcased_event, downcased_event;
                  /* 1 if the char to type matches the string.  */
                  int char_matches;
                  Lisp_Object upcased_event, downcased_event;
-                 Lisp_Object desc;
+                 Lisp_Object desc = Qnil;
                  Lisp_Object s
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
 
                  Lisp_Object s
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
 
@@ -7335,7 +7573,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
                  char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
                                  || XINT (downcased_event) == XSTRING (s)->data[0]);
                  if (! char_matches)
                  char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
                                  || XINT (downcased_event) == XSTRING (s)->data[0]);
                  if (! char_matches)
-                   desc = Fsingle_key_description (event);
+                   desc = Fsingle_key_description (event, Qnil);
 
                  tem
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
 
                  tem
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
@@ -7429,7 +7667,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
       orig_defn_macro = current_kboard->defining_kbd_macro;
       current_kboard->defining_kbd_macro = Qnil;
       do
       orig_defn_macro = current_kboard->defining_kbd_macro;
       current_kboard->defining_kbd_macro = Qnil;
       do
-       obj = read_char (commandflag, 0, 0, Qnil, 0);
+       obj = read_char (commandflag, 0, 0, Qt, 0);
       while (BUFFERP (obj));
       current_kboard->defining_kbd_macro = orig_defn_macro;
 
       while (BUFFERP (obj));
       current_kboard->defining_kbd_macro = orig_defn_macro;
 
@@ -7476,31 +7714,6 @@ follow_key (key, nmaps, current, defs, next)
   int i, first_binding;
   int did_meta = 0;
 
   int i, first_binding;
   int did_meta = 0;
 
-  /* If KEY is a meta ASCII character, treat it like meta-prefix-char
-     followed by the corresponding non-meta character.
-     Put the results into DEFS, since we are going to alter that anyway.
-     Do not alter CURRENT or NEXT.  */
-  if (INTEGERP (key) && (XUINT (key) & CHAR_META))
-    {
-      for (i = 0; i < nmaps; i++)
-       if (! NILP (current[i]))
-         {
-           Lisp_Object def;
-           def = get_keyelt (access_keymap (current[i],
-                                            meta_prefix_char, 1, 0), 0);
-
-           /* Note that since we pass the resulting bindings through
-              get_keymap_1, non-prefix bindings for meta-prefix-char
-              disappear.  */
-           defs[i] = get_keymap_1 (def, 0, 1);
-         }
-       else
-         defs[i] = Qnil;
-
-      did_meta = 1;
-      XSETINT (key, XFASTINT (key) & ~CHAR_META);
-    }
-
   first_binding = nmaps;
   for (i = nmaps - 1; i >= 0; i--)
     {
   first_binding = nmaps;
   for (i = nmaps - 1; i >= 0; i--)
     {
@@ -7512,7 +7725,7 @@ follow_key (key, nmaps, current, defs, next)
          else
            map = current[i];
 
          else
            map = current[i];
 
-         defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 1);
+         defs[i] = access_keymap (map, key, 1, 0, 1);
          if (! NILP (defs[i]))
            first_binding = i;
        }
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -7523,7 +7736,7 @@ follow_key (key, nmaps, current, defs, next)
   /* Given the set of bindings we've found, produce the next set of maps.  */
   if (first_binding < nmaps)
     for (i = 0; i < nmaps; i++)
   /* Given the set of bindings we've found, produce the next set of maps.  */
   if (first_binding < nmaps)
     for (i = 0; i < nmaps; i++)
-      next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0, 1);
+      next[i] = NILP (defs[i]) ? Qnil : get_keymap (defs[i], 0, 1);
 
   return first_binding;
 }
 
   return first_binding;
 }
@@ -7575,44 +7788,45 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      int can_return_switch_frame;
      int fix_current_buffer;
 {
      int can_return_switch_frame;
      int fix_current_buffer;
 {
-  int count = specpdl_ptr - specpdl;
+  volatile Lisp_Object from_string;
+  volatile int count = specpdl_ptr - specpdl;
 
   /* How many keys there are in the current key sequence.  */
 
   /* How many keys there are in the current key sequence.  */
-  int t;
+  volatile int t;
 
   /* The length of the echo buffer when we started reading, and
      the length of this_command_keys when we started reading.  */
 
   /* The length of the echo buffer when we started reading, and
      the length of this_command_keys when we started reading.  */
-  int echo_start;
-  int keys_start;
+  volatile int echo_start;
+  volatile int keys_start;
 
   /* The number of keymaps we're scanning right now, and the number of
      keymaps we have allocated space for.  */
 
   /* The number of keymaps we're scanning right now, and the number of
      keymaps we have allocated space for.  */
-  int nmaps;
-  int nmaps_allocated = 0;
+  volatile int nmaps;
+  volatile int nmaps_allocated = 0;
 
   /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in
      the current keymaps.  */
 
   /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in
      the current keymaps.  */
-  Lisp_Object *defs;
+  Lisp_Object *volatile defs = NULL;
 
   /* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1]
      in the current keymaps, or nil where it is not a prefix.  */
 
   /* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1]
      in the current keymaps, or nil where it is not a prefix.  */
-  Lisp_Object *submaps;
+  Lisp_Object *volatile submaps = NULL;
 
   /* The local map to start out with at start of key sequence.  */
 
   /* The local map to start out with at start of key sequence.  */
-  Lisp_Object orig_local_map;
+  volatile Lisp_Object orig_local_map;
 
   /* The map from the `keymap' property to start out with at start of
      key sequence.  */
 
   /* The map from the `keymap' property to start out with at start of
      key sequence.  */
-  Lisp_Object orig_keymap;
+  volatile Lisp_Object orig_keymap;
 
   /* 1 if we have already considered switching to the local-map property
      of the place where a mouse click occurred.  */
 
   /* 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;
+  volatile 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.  */
 
   /* 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.  */
-  int first_binding;
+  volatile int first_binding;
 
   /* If t < mock_input, then KEYBUF[t] should be read as the next
      input key.
 
   /* If t < mock_input, then KEYBUF[t] should be read as the next
      input key.
@@ -7627,7 +7841,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      restart_sequence; the loop will read keys from keybuf up until
      mock_input, thus rebuilding the state; and then it will resume
      reading characters from the keyboard.  */
      restart_sequence; the loop will read keys from keybuf up until
      mock_input, thus rebuilding the state; and then it will resume
      reading characters from the keyboard.  */
-  int mock_input = 0;
+  volatile int mock_input = 0;
 
   /* If the sequence is unbound in submaps[], then
      keybuf[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map,
 
   /* If the sequence is unbound in submaps[], then
      keybuf[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map,
@@ -7637,24 +7851,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      should hold off until t reaches them.  We do this when we've just
      recognized a function key, to avoid searching for the function
      key's again in Vfunction_key_map.  */
      should hold off until t reaches them.  We do this when we've just
      recognized a function key, to avoid searching for the function
      key's again in Vfunction_key_map.  */
-  int fkey_start = 0, fkey_end = 0;
-  Lisp_Object fkey_map;
+  volatile int fkey_start = 0, fkey_end = 0;
+  volatile Lisp_Object fkey_map;
 
   /* Likewise, for key_translation_map.  */
 
   /* Likewise, for key_translation_map.  */
-  int keytran_start = 0, keytran_end = 0;
-  Lisp_Object keytran_map;
+  volatile int keytran_start = 0, keytran_end = 0;
+  volatile Lisp_Object keytran_map;
 
   /* If we receive a ``switch-frame'' event in the middle of a key sequence,
      we put it off for later.  While we're reading, we keep the event here.  */
 
   /* If we receive a ``switch-frame'' event in the middle of a key sequence,
      we put it off for later.  While we're reading, we keep the event here.  */
-  Lisp_Object delayed_switch_frame;
+  volatile Lisp_Object delayed_switch_frame;
 
   /* See the comment below... */
 #if defined (GOBBLE_FIRST_EVENT)
   Lisp_Object first_event;
 #endif
 
 
   /* See the comment below... */
 #if defined (GOBBLE_FIRST_EVENT)
   Lisp_Object first_event;
 #endif
 
-  Lisp_Object original_uppercase;
-  int original_uppercase_position = -1;
+  volatile Lisp_Object original_uppercase;
+  volatile int original_uppercase_position = -1;
 
   /* Gets around Microsoft compiler limitations.  */
   int dummyflag = 0;
 
   /* Gets around Microsoft compiler limitations.  */
   int dummyflag = 0;
@@ -7663,8 +7877,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   /* Nonzero if we seem to have got the beginning of a binding
      in function_key_map.  */
 
   /* 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;
+  volatile int function_key_possible = 0;
+  volatile int key_translation_possible = 0;
+
+  /* List of events for which a fake prefix key has been generated.  */
+  volatile Lisp_Object fake_prefixed_keys = Qnil;
 
   /* Save the status of key translation before each step,
      so that we can restore this after downcasing.  */
 
   /* Save the status of key translation before each step,
      so that we can restore this after downcasing.  */
@@ -7680,6 +7897,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int junk;
 #endif
 
   int junk;
 #endif
 
+  struct gcpro gcpro1;
+
+  GCPRO1 (fake_prefixed_keys);
   raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
   raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
@@ -7689,17 +7909,17 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   keytran_map = Vkey_translation_map;
 
   /* If there is no function-key-map, turn off function key scanning.  */
   keytran_map = Vkey_translation_map;
 
   /* If there is no function-key-map, turn off function key scanning.  */
-  if (NILP (Fkeymapp (Vfunction_key_map)))
+  if (!KEYMAPP (Vfunction_key_map))
     fkey_start = fkey_end = bufsize + 1;
 
   /* If there is no key-translation-map, turn off scanning.  */
     fkey_start = fkey_end = bufsize + 1;
 
   /* If there is no key-translation-map, turn off scanning.  */
-  if (NILP (Fkeymapp (Vkey_translation_map)))
+  if (!KEYMAPP (Vkey_translation_map))
     keytran_start = keytran_end = bufsize + 1;
 
   if (INTERACTIVE)
     {
       if (!NILP (prompt))
     keytran_start = keytran_end = bufsize + 1;
 
   if (INTERACTIVE)
     {
       if (!NILP (prompt))
-       echo_prompt (XSTRING (prompt)->data);
+       echo_prompt (prompt);
       else if (cursor_in_echo_area
               && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
               && NILP (Fzerop (Vecho_keystrokes)))
       else if (cursor_in_echo_area
               && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
               && NILP (Fzerop (Vecho_keystrokes)))
@@ -7726,8 +7946,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                           &junk);
 #endif /* GOBBLE_FIRST_EVENT */
 
                           &junk);
 #endif /* GOBBLE_FIRST_EVENT */
 
-  orig_local_map = get_local_map (PT, current_buffer, local_map);
-  orig_keymap = get_local_map (PT, current_buffer, keymap);
+  orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+  orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
+  from_string = Qnil;
 
   /* 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,
 
   /* 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,
@@ -7775,7 +7996,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                                              * sizeof (defs[0]));
            nmaps_allocated = nmaps + extra_maps;
          }
                                              * sizeof (defs[0]));
            nmaps_allocated = nmaps + extra_maps;
          }
-       bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
+       bcopy (maps, (void *) submaps, nmaps * sizeof (submaps[0]));
        if (!NILP (orig_keymap))
          submaps[nmaps++] = orig_keymap;
        submaps[nmaps++] = orig_local_map;
        if (!NILP (orig_keymap))
          submaps[nmaps++] = orig_keymap;
        submaps[nmaps++] = orig_local_map;
@@ -7822,13 +8043,13 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          (say, a mouse click on the mode line which is being treated
          as [mode-line (mouse-...)], then we backtrack to this point
          of keybuf.  */
          (say, a mouse click on the mode line which is being treated
          as [mode-line (mouse-...)], then we backtrack to this point
          of keybuf.  */
-      int last_real_key_start;
+      volatile int last_real_key_start;
 
       /* These variables are analogous to echo_start and keys_start;
         while those allow us to restart the entire key sequence,
         echo_local_start and keys_local_start allow us to throw away
         just one key.  */
 
       /* These variables are analogous to echo_start and keys_start;
         while those allow us to restart the entire key sequence,
         echo_local_start and keys_local_start allow us to throw away
         just one key.  */
-      int echo_local_start, keys_local_start, local_first_binding;
+      volatile int echo_local_start, keys_local_start, local_first_binding;
 
       if (t >= bufsize)
        error ("Key sequence too long");
 
       if (t >= bufsize)
        error ("Key sequence too long");
@@ -7896,12 +8117,13 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                               interrupted_kboard->kbd_queue);
                  }
                mock_input = 0;
                               interrupted_kboard->kbd_queue);
                  }
                mock_input = 0;
-               orig_local_map = get_local_map (PT, current_buffer, local_map);
-               orig_keymap = get_local_map (PT, current_buffer, keymap);
+               orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+               orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                goto replay_sequence;
              }
 #endif
                goto replay_sequence;
              }
 #endif
-           key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
+           key = read_char (NILP (prompt), nmaps,
+                            (Lisp_Object *) submaps, last_nonmenu_event,
                             &used_mouse_menu);
          }
 
                             &used_mouse_menu);
          }
 
@@ -7910,6 +8132,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (EQ (key, Qt))
            {
              unbind_to (count, Qnil);
          if (EQ (key, Qt))
            {
              unbind_to (count, Qnil);
+             UNGCPRO;
              return -1;
            }
 
              return -1;
            }
 
@@ -7942,8 +8165,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                    Fset_buffer (XWINDOW (selected_window)->buffer);
                }
 
                    Fset_buffer (XWINDOW (selected_window)->buffer);
                }
 
-             orig_local_map = get_local_map (PT, current_buffer, local_map);
-             orig_keymap = get_local_map (PT, current_buffer, keymap);
+             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
              goto replay_sequence;
            }
 
@@ -7957,8 +8180,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
-             orig_local_map = get_local_map (PT, current_buffer, local_map);
-             orig_keymap = get_local_map (PT, current_buffer, keymap);
+             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
              goto replay_sequence;
            }
 
@@ -8007,10 +8230,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
 
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
 
-             if (CONSP (posn))
+             if (CONSP (posn)
+                 || (!NILP (fake_prefixed_keys)
+                     && !NILP (Fmemq (key, fake_prefixed_keys))))
                {
                {
-                 /* We're looking at the second event of a
-                    sequence which we expanded before.  Set
+                 /* We're looking a second time at an event for which
+                    we generated a fake prefix key.  Set
                     last_real_key_start appropriately.  */
                  if (t > 0)
                    last_real_key_start = t - 1;
                     last_real_key_start appropriately.  */
                  if (t > 0)
                    last_real_key_start = t - 1;
@@ -8043,12 +8268,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  if (! FRAME_LIVE_P (XFRAME (selected_frame)))
                    Fkill_emacs (Qnil);
 
                  if (! FRAME_LIVE_P (XFRAME (selected_frame)))
                    Fkill_emacs (Qnil);
-                 set_buffer_internal (XBUFFER (XWINDOW
-                 (window)->buffer)
-);
+                 set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
                  orig_local_map = get_local_map (PT, current_buffer,
                  orig_local_map = get_local_map (PT, current_buffer,
-                                                 local_map);
-                 orig_keymap = get_local_map (PT, current_buffer, keymap);
+                                                 Qlocal_map);
+                 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                  goto replay_sequence;
                }
              
                  goto replay_sequence;
                }
              
@@ -8070,7 +8293,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                          && XINT (pos) >= BEG && XINT (pos) <= Z)
                        {
                          map_here = get_local_map (XINT (pos),
                          && XINT (pos) >= BEG && XINT (pos) <= Z)
                        {
                          map_here = get_local_map (XINT (pos),
-                                                   current_buffer, local_map);
+                                                   current_buffer, Qlocal_map);
                          if (!EQ (map_here, orig_local_map))
                            {
                              orig_local_map = map_here;
                          if (!EQ (map_here, orig_local_map))
                            {
                              orig_local_map = map_here;
@@ -8080,7 +8303,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                              goto replay_sequence;
                            }
                          map_here = get_local_map (XINT (pos),
                              goto replay_sequence;
                            }
                          map_here = get_local_map (XINT (pos),
-                                                    current_buffer, keymap);
+                                                    current_buffer, Qkeymap);
                          if (!EQ (map_here, orig_keymap))
                            {
                              orig_keymap = map_here;
                          if (!EQ (map_here, orig_keymap))
                            {
                              orig_keymap = map_here;
@@ -8095,18 +8318,22 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              /* Expand mode-line and scroll-bar events into two events:
                 use posn as a fake prefix key.  */
 
              /* Expand mode-line and scroll-bar events into two events:
                 use posn as a fake prefix key.  */
-             if (SYMBOLP (posn))
+             if (SYMBOLP (posn)
+                 && (NILP (fake_prefixed_keys)
+                     || NILP (Fmemq (key, fake_prefixed_keys))))
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
-                 keybuf[t] = posn;
-                 keybuf[t+1] = key;
-                 mock_input = t + 2;
                  
                  
-                 /* Zap the position in key, so we know that we've
-                    expanded it, and don't try to do so again.  */
-                 POSN_BUFFER_POSN (EVENT_START (key))
-                   = Fcons (posn, Qnil);
+                 keybuf[t]     = posn;
+                 keybuf[t + 1] = key;
+                 mock_input    = t + 2;
+
+                 /* Record that a fake prefix key has been generated
+                    for KEY.  Don't modify the event; this would
+                    prevent proper action when the event is pushed
+                    back tino unread-command-events.  */
+                 fake_prefixed_keys = Fcons (key, fake_prefixed_keys);
 
                  /* If on a mode line string with a local keymap,
                     reconsider the key sequence with that keymap.  */
 
                  /* If on a mode line string with a local keymap,
                     reconsider the key sequence with that keymap.  */
@@ -8133,6 +8360,35 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  goto replay_key;
                }
 
                  goto replay_key;
                }
+             else if (CONSP (POSN_STRING (EVENT_START (key)))
+                      && NILP (from_string))
+               {
+                 /* For a click on a string, i.e. overlay string or a
+                    string displayed via the `display' property,
+                    consider `local-map' and `keymap' properties of
+                    that string.  */
+                 Lisp_Object string, pos, map, map2;
+
+                 string = POSN_STRING (EVENT_START (key));
+                 pos = XCDR (string);
+                 string = XCAR (string);
+                 if (XINT (pos) >= 0
+                     && XINT (pos) < XSTRING (string)->size)
+                   {
+                     map = Fget_text_property (pos, Qlocal_map, string);
+                     if (!NILP (map))
+                       orig_local_map = map;
+                     map2 = Fget_text_property (pos, Qkeymap, string);
+                     if (!NILP (map2))
+                       orig_keymap = map2;
+
+                     if (!NILP (map) || !NILP (map2))
+                       {
+                         from_string = string;
+                         goto replay_sequence;
+                       }
+                   }
+               }
            }
          else if (CONSP (XCDR (key))
                   && CONSP (EVENT_START (key))
            }
          else if (CONSP (XCDR (key))
                   && CONSP (EVENT_START (key))
@@ -8333,22 +8589,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              Lisp_Object key;
 
              key = keybuf[fkey_end++];
              Lisp_Object key;
 
              key = keybuf[fkey_end++];
-             /* Look up meta-characters by prefixing them
-                with meta_prefix_char.  I hate this.  */
-             if (INTEGERP (key) && XUINT (key) & meta_modifier)
-               {
-                 fkey_next
-                   = get_keymap_1
-                     (get_keyelt
-                      (access_keymap (fkey_map, meta_prefix_char, 1, 0), 0),
-                      0, 1);
-                 XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
-               }
-             else
-               fkey_next = fkey_map;
-
              fkey_next
              fkey_next
-               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 1);
+               = access_keymap (fkey_map, key, 1, 0, 1);
 
              /* Handle symbol with autoload definition.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
 
              /* Handle symbol with autoload definition.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
@@ -8361,7 +8603,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                 or an array.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
                  && (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
                 or an array.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
                  && (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
-                     || !NILP (Fkeymapp (XSYMBOL (fkey_next)->function))))
+                     || KEYMAPP (XSYMBOL (fkey_next)->function)))
                fkey_next = XSYMBOL (fkey_next)->function;
 
 #if 0 /* I didn't turn this on, because it might cause trouble
                fkey_next = XSYMBOL (fkey_next)->function;
 
 #if 0 /* I didn't turn this on, because it might cause trouble
@@ -8434,11 +8676,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  goto replay_sequence;
                }
 
                  goto replay_sequence;
                }
 
-             fkey_map = get_keymap_1 (fkey_next, 0, 1);
+             fkey_map = get_keymap (fkey_next, 0, 1);
 
              /* If we no longer have a bound suffix, try a new positions for
                 fkey_start.  */
 
              /* If we no longer have a bound suffix, try a new positions for
                 fkey_start.  */
-             if (NILP (fkey_map))
+             if (!CONSP (fkey_map))
                {
                  fkey_end = ++fkey_start;
                  fkey_map = Vfunction_key_map;
                {
                  fkey_end = ++fkey_start;
                  fkey_map = Vfunction_key_map;
@@ -8457,22 +8699,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            Lisp_Object key;
 
            key = keybuf[keytran_end++];
            Lisp_Object key;
 
            key = keybuf[keytran_end++];
-           /* Look up meta-characters by prefixing them
-              with meta_prefix_char.  I hate this.  */
-           if (INTEGERP (key) && XUINT (key) & meta_modifier)
-             {
-               keytran_next
-                 = get_keymap_1
-                   (get_keyelt
-                    (access_keymap (keytran_map, meta_prefix_char, 1, 0), 0),
-                    0, 1);
-               XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
-             }
-           else
-             keytran_next = keytran_map;
-
            keytran_next
            keytran_next
-             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 1);
+             = access_keymap (keytran_map, key, 1, 0, 1);
 
            /* Handle symbol with autoload definition.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
 
            /* Handle symbol with autoload definition.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
@@ -8485,7 +8713,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
               or an array.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
                && (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
               or an array.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
                && (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
-                   || !NILP (Fkeymapp (XSYMBOL (keytran_next)->function))))
+                   || KEYMAPP (XSYMBOL (keytran_next)->function)))
              keytran_next = XSYMBOL (keytran_next)->function;
            
            /* If the key translation map gives a function, not an
              keytran_next = XSYMBOL (keytran_next)->function;
            
            /* If the key translation map gives a function, not an
@@ -8549,11 +8777,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                goto replay_sequence;
              }
 
                goto replay_sequence;
              }
 
-           keytran_map = get_keymap_1 (keytran_next, 0, 1);
+           keytran_map = get_keymap (keytran_next, 0, 1);
 
            /* If we no longer have a bound suffix, try a new positions for
               keytran_start.  */
 
            /* If we no longer have a bound suffix, try a new positions for
               keytran_start.  */
-           if (NILP (keytran_map))
+           if (!CONSP (keytran_map))
              {
                keytran_end = ++keytran_start;
                keytran_map = Vkey_translation_map;
              {
                keytran_end = ++keytran_start;
                keytran_map = Vkey_translation_map;
@@ -8674,6 +8902,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   
 
 
   
 
+  UNGCPRO;
   return t;
 }
 
   return t;
 }
 
@@ -8761,17 +8990,21 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
     }
 
 #ifdef HAVE_X_WINDOWS
     }
 
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #endif
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
                         ! NILP (can_return_switch_frame), 0);
 
 #endif
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
                         ! NILP (can_return_switch_frame), 0);
 
+#if 0  /* The following is fine for code reading a key sequence and
+         then proceeding with a lenghty compuation, but it's not good
+         for code reading keys in a loop, like an input method.  */
 #ifdef HAVE_X_WINDOWS
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    start_busy_cursor ();
+  if (display_hourglass_p)
+    start_hourglass ();
+#endif
 #endif
 
   if (i == -1)
 #endif
 
   if (i == -1)
@@ -8816,8 +9049,8 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
     }
 
 #ifdef HAVE_X_WINDOWS
     }
 
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #endif
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
 #endif
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
@@ -8825,8 +9058,8 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
                         ! NILP (can_return_switch_frame), 0);
 
 #ifdef HAVE_X_WINDOWS
                         ! NILP (can_return_switch_frame), 0);
 
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    start_busy_cursor ();
+  if (display_hourglass_p)
+    start_hourglass ();
 #endif
 
   if (i == -1)
 #endif
 
   if (i == -1)
@@ -8935,6 +9168,8 @@ a special event, so ignore the prefix argument and don't clear it.")
     }
   return Qnil;
 }
     }
   return Qnil;
 }
+
+
 \f
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
   1, 1, "P",
 \f
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
   1, 1, "P",
@@ -9057,7 +9292,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          Lisp_Object binding;
          char *newmessage;
          int message_p = push_message ();
          Lisp_Object binding;
          char *newmessage;
          int message_p = push_message ();
+         int count = BINDING_STACK_SIZE ();
 
 
+         record_unwind_protect (push_message_unwind, Qnil);
          binding = Fkey_description (bindings);
 
          newmessage
          binding = Fkey_description (bindings);
 
          newmessage
@@ -9076,7 +9313,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
              && message_p)
            restore_message ();
 
              && message_p)
            restore_message ();
 
-         pop_message ();
+         unbind_to (count, Qnil);
        }
     }
 
        }
     }
 
@@ -9110,7 +9347,7 @@ current_active_maps (maps_p)
     {
       /* No, so use major and minor mode keymaps and keymap property.  */
       int extra_maps = 2;
     {
       /* No, so use major and minor mode keymaps and keymap property.  */
       int extra_maps = 2;
-      Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
       if (!NILP (map))
        extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
       if (!NILP (map))
        extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
@@ -9118,8 +9355,8 @@ current_active_maps (maps_p)
                                     * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
       if (!NILP (map))
                                     * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
       if (!NILP (map))
-       maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
-      maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+       maps[nmaps++] = map;
+      maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
     }
   maps[nmaps++] = current_global_map;
 
     }
   maps[nmaps++] = current_global_map;
 
@@ -9151,7 +9388,7 @@ detect_input_pending_run_timers (do_display)
 
   if (old_timers_run != timers_run && do_display)
     {
 
   if (old_timers_run != timers_run && do_display)
     {
-      redisplay_preserve_echo_area ();
+      redisplay_preserve_echo_area (8);
       /* The following fixes a bug when using lazy-lock with
         lazy-lock-defer-on-the-fly set to t, i.e.  when fontifying
         from an idle timer function.  The symptom of the bug is that
       /* The following fixes a bug when using lazy-lock with
         lazy-lock-defer-on-the-fly set to t, i.e.  when fontifying
         from an idle timer function.  The symptom of the bug is that
@@ -9658,7 +9895,7 @@ quit_throw_to_read_char ()
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
-                    Qnil, 0);
+                    0, 0);
 
   _longjmp (getcjmp, 1);
 }
 
   _longjmp (getcjmp, 1);
 }
@@ -9803,19 +10040,35 @@ wipe_kboard (kb)
 }
 
 #ifdef MULTI_KBOARD
 }
 
 #ifdef MULTI_KBOARD
+
+/* Free KB and memory referenced from it.  */
+
 void
 delete_kboard (kb)
 void
 delete_kboard (kb)
-  KBOARD *kb;
+     KBOARD *kb;
 {
   KBOARD **kbp;
 {
   KBOARD **kbp;
+  
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
       abort ();
   *kbp = kb->next_kboard;
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
       abort ();
   *kbp = kb->next_kboard;
+
+  /* Prevent a dangling reference to KB.  */
+  if (kb == current_kboard
+      && FRAMEP (selected_frame)
+      && FRAME_LIVE_P (XFRAME (selected_frame)))
+    {
+      current_kboard = XFRAME (selected_frame)->kboard;
+      if (current_kboard == kb)
+       abort ();
+    }
+  
   wipe_kboard (kb);
   xfree (kb);
 }
   wipe_kboard (kb);
   xfree (kb);
 }
-#endif
+
+#endif /* MULTI_KBOARD */
 
 void
 init_keyboard ()
 
 void
 init_keyboard ()
@@ -9848,10 +10101,6 @@ init_keyboard ()
   wipe_kboard (current_kboard);
   init_kboard (current_kboard);
 
   wipe_kboard (current_kboard);
   init_kboard (current_kboard);
 
-  if (initialized)
-    Ffillarray (kbd_buffer_gcpro, Qnil);
-
-  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
   if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
     {
       signal (SIGINT, interrupt_signal);
   if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
     {
       signal (SIGINT, interrupt_signal);
@@ -10067,6 +10316,8 @@ syms_of_keyboard ()
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
 
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
 
+  last_point_position_buffer = Qnil;
+
   {
     struct event_head *p;
 
   {
     struct event_head *p;
 
@@ -10414,7 +10665,7 @@ The elements of the list are event types that may have menu bar bindings.");
     "Per-terminal 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.\n\
     "Per-terminal 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.\n\
-This variable is intended to let commands such as `universal-argumemnt'\n\
+This variable is intended to let commands such as `universal-argument'\n\
 set up a different keymap for reading the next command.");
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
 set up a different keymap for reading the next command.");
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
@@ -10520,6 +10771,17 @@ The default value is nil, in which case, point adjustment are\n\
 suppressed only after special commands that set\n\
 `disable-point-adjustment' (which see) to non-nil.");
   Vglobal_disable_point_adjustment = Qnil;
 suppressed only after special commands that set\n\
 `disable-point-adjustment' (which see) to non-nil.");
   Vglobal_disable_point_adjustment = Qnil;
+
+  DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings,
+    "Non-nil means updating menu bindings is allowed.\n\
+A value of nil means menu bindings should not be updated.\n\
+Used during Emacs' startup.");
+  update_menu_bindings = 1;
+
+  DEFVAR_LISP ("minibuffer-message-timeout", &Vminibuffer_message_timeout,
+    "*How long to display an echo-area message when the minibuffer is active.\n\
+If the value is not a number, such messages don't time out.");
+  Vminibuffer_message_timeout = make_number (2);
 }
 
 void
 }
 
 void