]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(isearch): Use magenta2 as bg for (background light)
[gnu-emacs] / src / keyboard.c
index 990d38313f9316eb79435e10e86f4eba1a2c4f28..2aa4b51ccf3685000719d976ed64f5371aa4f92e 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -27,6 +27,7 @@ Boston, MA 02111-1307, USA.  */
 #include "lisp.h"
 #include "termhooks.h"
 #include "macros.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
@@ -34,9 +35,9 @@ Boston, MA 02111-1307, USA.  */
 #include "charset.h"
 #include "disptab.h"
 #include "dispextern.h"
-#include "keyboard.h"
 #include "syntax.h"
 #include "intervals.h"
+#include "keymap.h"
 #include "blockinput.h"
 #include "puresize.h"
 #include "systime.h"
@@ -70,10 +71,16 @@ Boston, MA 02111-1307, USA.  */
 #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"
 
+#ifndef USE_CRT_DLL
 extern int errno;
+#endif
 
 /* Variables for blockinput.h: */
 
@@ -91,15 +98,17 @@ extern int input_fd;
 #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
 #endif
 #else  /* No X-windows, character input */
-#define KBD_BUFFER_SIZE 256
+#define KBD_BUFFER_SIZE 4096
 #endif /* No X-windows */
 
+#define abs(x)         ((x) >= 0 ? (x) : -(x))
+
 /* Following definition copied from eval.c */
 
 struct backtrace
@@ -182,13 +191,21 @@ extern struct backtrace *backtrace_list;
 
 Lisp_Object Vshow_help_function;
 
+/* If a string, the message displayed before displaying a help-echo
+   in the echo area.  */
+
+Lisp_Object Vpre_help_message;
+
 /* Nonzero means do menu prompting.  */
+
 static int menu_prompting;
 
 /* Character to see next line of menu prompt.  */
+
 static Lisp_Object menu_prompt_more_char;
 
 /* For longjmp to where kbd input is being done.  */
+
 static jmp_buf getcjmp;
 
 /* True while doing kbd input.  */
@@ -196,7 +213,7 @@ int waiting_for_input;
 
 /* 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.  */
@@ -208,12 +225,12 @@ static struct kboard *ok_to_echo_at_next_pause;
    exists, and echo_message_buffer is eq to the current message
    buffer, we know that the message comes from echo_kboard.  */
 
-static struct kboard *echo_kboard;
+struct kboard *echo_kboard;
 
 /* 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;
@@ -245,6 +262,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;
 
+/* 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
@@ -450,12 +471,17 @@ int input_pending;
 
 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.  */
+
 static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
 
-/* Vector to GCPRO the frames and windows mentioned in kbd_buffer.
+/* Vector to GCPRO the Lisp objects referenced from kbd_buffer.
 
    The interrupt-level event handlers will never enqueue an event on a
    frame which is not in Vframe_list, and once an event is dequeued,
@@ -474,14 +500,16 @@ static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
    Similar things happen when an event on a scroll bar is enqueued; the
    window may be deleted while the event is in the queue.
 
-   So, we use this vector to protect the frame_or_window field in the
-   event queue.  That way, they'll be dequeued as dead frames or
-   windows, but still valid lisp objects.
+   So, we use this vector to protect the Lisp_Objects in the event
+   queue.  That way, they'll be dequeued as dead frames or windows,
+   but still valid Lisp objects.
 
    If kbd_buffer[i].kind != no_event, then
-     (XVECTOR (kbd_buffer_frame_or_window)->contents[i]
-      == kbd_buffer[i].frame_or_window.  */
-static Lisp_Object kbd_buffer_frame_or_window;
+
+   AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window.
+   AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg.  */
+
+static Lisp_Object kbd_buffer_gcpro;
 
 /* Pointer to next available character in kbd_buffer.
    If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty.
@@ -506,7 +534,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.  */
-static Lisp_Object do_mouse_tracking;
+Lisp_Object do_mouse_tracking;
 
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
@@ -620,57 +648,94 @@ int flow_control;
    point to the boundary of the region.  But, if a command sets this
    valiable to non-nil, we suppress this point adjustment.  This
    variable is set to nil before reading a command.  */
+
 Lisp_Object Vdisable_point_adjustment;
 
 /* If non-nil, always 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) ();
 
-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_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
-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
-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 void save_getcjmp P_ ((jmp_buf));
 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 void clear_event P_ ((struct input_event *));
+static void any_kboard_state P_ ((void));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
 
-#define        min(a,b)        ((a)<(b)?(a):(b))
-#define        max(a,b)        ((a)>(b)?(a):(b))
-
 /* Install the string STR as the beginning of the string of echoing,
    so that it serves as a prompt for the next character.
    Also start echoing.  */
 
 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;
+
+         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;
+    }
 
-  current_kboard->echo_after_prompt = len;
+  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 ();
 }
@@ -683,8 +748,6 @@ void
 echo_char (c)
      Lisp_Object c;
 {
-  extern char *push_key_description ();
-
   if (current_kboard->immediate_echo)
     {
       char *ptr = current_kboard->echoptr;
@@ -697,11 +760,13 @@ echo_char (c)
 
       if (INTEGERP (c))
        {
+         int ch = XINT (c);
+
          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))
        {
@@ -709,8 +774,8 @@ echo_char (c)
          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
@@ -776,7 +841,7 @@ echo_now ()
 
   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.  */
@@ -827,8 +892,6 @@ static void
 add_command_key (key)
      Lisp_Object key;
 {
-  int size = XVECTOR (this_command_keys)->size;
-
   /* If reset-this-command-length was called recently, obey it now.
      See the doc string of that function for an explanation of why.  */
   if (before_command_restore_flag)
@@ -840,20 +903,15 @@ add_command_key (key)
       before_command_restore_flag = 0;
     }
 
-  if (this_command_key_count >= size)
-    {
-      Lisp_Object new_keys;
-
-      new_keys = Fmake_vector (make_number (size * 2), Qnil);
-      bcopy (XVECTOR (this_command_keys)->contents,
-            XVECTOR (new_keys)->contents,
-            size * sizeof (Lisp_Object));
-
-      this_command_keys = new_keys;
-    }
+  if (this_command_key_count >= ASIZE (this_command_keys))
+    this_command_keys = larger_vector (this_command_keys,
+                                      2 * ASIZE (this_command_keys),
+                                      Qnil);
 
-  XVECTOR (this_command_keys)->contents[this_command_key_count++] = key;
+  AREF (this_command_keys, this_command_key_count) = key;
+  ++this_command_key_count;
 }
+
 \f
 Lisp_Object
 recursive_edit_1 ()
@@ -868,13 +926,25 @@ recursive_edit_1 ()
     }
 
 #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.  */
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #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);
@@ -905,38 +975,53 @@ force_auto_save_soon ()
 }
 \f
 DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
-  "Invoke the editor command loop recursively.\n\
-To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\
-that tells this function to return.\n\
-Alternately, `(throw 'exit t)' makes this function signal an error.\n\
-This function is called by the editor initialization to begin editing.")
-  ()
+       doc: /* Invoke the editor command loop recursively.
+To get out of the recursive edit, a command can do `(throw 'exit nil)';
+that tells this function to return.
+Alternately, `(throw 'exit t)' makes this function signal an error.
+This function is called by the editor initialization to begin editing.  */)
+     ()
 {
   int count = specpdl_ptr - specpdl;
+  Lisp_Object buffer;
 
   command_loop_level++;
   update_mode_lines = 1;
 
+  if (command_loop_level
+      && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
+    buffer = Fcurrent_buffer ();
+  else
+    buffer = Qnil;
+
+  /* If we leave recursive_edit_1 below with a `throw' for instance,
+     like it is done in the splash screen display, we have to
+     make sure that we restore single_kboard as command_loop_1
+     would have done if it were left normally.  */
   record_unwind_protect (recursive_edit_unwind,
-                        (command_loop_level
-                         && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
-                        ? Fcurrent_buffer ()
-                        : Qnil);
+                        Fcons (buffer, single_kboard ? Qt : Qnil));
+
   recursive_edit_1 ();
   return unbind_to (count, Qnil);
 }
 
 Lisp_Object
-recursive_edit_unwind (buffer)
-     Lisp_Object buffer;
+recursive_edit_unwind (info)
+     Lisp_Object info;
 {
-  if (!NILP (buffer))
-    Fset_buffer (buffer);
-
+  if (BUFFERP (XCAR (info)))
+    Fset_buffer (XCAR (info));
+  
+  if (NILP (XCDR (info)))
+    any_kboard_state ();
+  else
+    single_kboard_state ();
+      
   command_loop_level--;
   update_mode_lines = 1;
   return Qnil;
 }
+
 \f
 static void
 any_kboard_state ()
@@ -1181,43 +1266,45 @@ top_level_1 ()
 }
 
 DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
-  "Exit all recursive editing levels.")
-  ()
+       doc: /* Exit all recursive editing levels.  */)
+     ()
 {
 #ifdef HAVE_X_WINDOWS
-  if (display_busy_cursor_p)
-    cancel_busy_cursor ();
+  if (display_hourglass_p)
+    cancel_hourglass ();
 #endif
-  Fthrow (Qtop_level, Qnil);
+  return Fthrow (Qtop_level, Qnil);
 }
 
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
-  "Exit from the innermost recursive edit or minibuffer.")
-  ()
+       doc: /* Exit from the innermost recursive edit or minibuffer.  */)
+     ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     Fthrow (Qexit, Qnil);
 
   error ("No recursive edit is in progress");
+  return Qnil;
 }
 
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
-  "Abort the command that requested this recursive edit or minibuffer input.")
-  ()
+       doc: /* Abort the command that requested this recursive edit or minibuffer input.  */)
+     ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     Fthrow (Qexit, Qt);
 
   error ("No recursive edit is in progress");
+  return Qnil;
 }
 \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 ();
+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 ()
@@ -1229,7 +1316,7 @@ command_loop_1 ()
   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
@@ -1254,7 +1341,7 @@ command_loop_1 ()
   /* If displaying a message, resize the echo area window to fit
      that message's size exactly.  */
   if (!NILP (echo_area_buffer[0]))
-    resize_echo_area_axactly ();
+    resize_echo_area_exactly ();
 
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
@@ -1293,18 +1380,19 @@ command_loop_1 ()
       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])
-         && 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);
 
-         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);
@@ -1411,6 +1499,10 @@ command_loop_1 ()
          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;
@@ -1539,8 +1631,8 @@ command_loop_1 ()
          /* 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;
@@ -1549,8 +1641,8 @@ command_loop_1 ()
          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: ;
@@ -1564,7 +1656,7 @@ command_loop_1 ()
       /* If displaying a message, resize the echo area window to fit
         that message's size exactly.  */
       if (!NILP (echo_area_buffer[0]))
-       resize_echo_area_axactly ();
+       resize_echo_area_exactly ();
 
       if (!NILP (Vdeferred_action_list))
        safe_run_hooks (Qdeferred_action_function);
@@ -1667,6 +1759,7 @@ adjust_point_for_property (last_pt)
       if (check_display
          && PT > BEGV && PT < ZV
          && get_property_and_range (PT, Qdisplay, &val, &start, &end, Qnil)
+         && display_prop_intangible_p (val)
          && start < PT && end > PT
          && (last_pt <= start || last_pt >= end))
        {
@@ -1695,7 +1788,7 @@ static Lisp_Object
 safe_run_hooks_error (data)
      Lisp_Object data;
 {
-  Fset (Vinhibit_quit, Qnil);
+  return Fset (Vinhibit_quit, Qnil);
 }
 
 /* If we get an error while running the hook, cause the hook variable
@@ -1894,6 +1987,95 @@ make_ctrl_char (c)
   return c;
 }
 
+/* Display help echo in the echo area.
+
+   HELP a string means display that string, HELP nil means clear the
+   help echo.  If HELP is a function, call it with OBJECT and POS as
+   arguments; the function should return a help string or nil for
+   none.  For all other types of HELP evaluate it to obtain a string.
+
+   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
+   area.
+
+   Note: this function may only be called with HELP nil or a string
+   from X code running asynchronously.  */
+
+void
+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))
+       {
+         Lisp_Object args[4];
+         args[0] = help;
+         args[1] = window;
+         args[2] = object;
+         args[3] = pos;
+         help = safe_call (4, args);
+       }
+      else
+       help = safe_eval (help);
+      
+      if (!STRINGP (help))
+       return;
+    }
+
+  if (STRINGP (help) || NILP (help))
+    {
+      if (!NILP (Vshow_help_function))
+       call1 (Vshow_help_function, help);
+      else if (/* Don't overwrite minibuffer contents.  */
+              !MINI_WINDOW_P (XWINDOW (selected_window))
+              /* Don't overwrite a keystroke echo.  */
+              && (NILP (echo_message_buffer)
+                  || ok_to_overwrite_keystroke_echo)
+              /* Don't overwrite a prompt.  */
+              && !cursor_in_echo_area)
+       {
+         if (STRINGP (help))
+           {
+             int count = BINDING_STACK_SIZE ();
+
+             if (!help_echo_showing_p)
+               Vpre_help_message = current_message ();
+             
+             specbind (Qmessage_truncate_lines, Qt);
+             message3_nolog (help, STRING_BYTES (XSTRING (help)),
+                             STRING_MULTIBYTE (help));
+             unbind_to (count, Qnil);
+           }
+         else if (STRINGP (Vpre_help_message))
+           {
+             message3_nolog (Vpre_help_message,
+                             STRING_BYTES (XSTRING (Vpre_help_message)),
+                             STRING_MULTIBYTE (Vpre_help_message));
+             Vpre_help_message = Qnil;
+           }
+         else
+           message (0);
+       }
+      
+      help_echo_showing_p = STRINGP (help);
+    }
+}
+
 
 \f
 /* Input of single characters from keyboard */
@@ -1934,16 +2116,17 @@ read_char (commandflag, nmaps, maps, prev_event, 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 key_already_recorded = 0;
+  volatile int key_already_recorded = 0;
   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;
+  EMACS_TIME last_idle_start;
 
   also_record = Qnil;
 
@@ -1991,10 +2174,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
       if (CONSP (c)
-         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
-         && NILP (XCDR (c)))
+         && EQ (XCDR (c), Qdisabled)
+         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (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;
     }
@@ -2074,7 +2263,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* 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.  */
@@ -2166,15 +2358,21 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
        if (kb != current_kboard)
          {
-           Lisp_Object *tailp = &kb->kbd_queue;
+           Lisp_Object link = kb->kbd_queue;
            /* We shouldn't get here if we were in single-kboard mode!  */
            if (single_kboard)
              abort ();
-           while (CONSP (*tailp))
-             tailp = &XCDR (*tailp);
-           if (!NILP (*tailp))
-             abort ();
-           *tailp = Fcons (c, Qnil);
+           if (CONSP (link))
+             {
+               while (CONSP (XCDR (link)))
+                 link = XCDR (link);
+               if (!NILP (XCDR (link)))
+                 abort ();
+             }
+           if (!CONSP (link))
+             kb->kbd_queue = Fcons (c, Qnil);
+           else
+             XSETCDR (link, Fcons (c, Qnil));
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
            /* This is going to exit from read_char
@@ -2382,18 +2580,25 @@ 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);
+      timer_start_idle ();
       c = kbd_buffer_get_event (&kb, used_mouse_menu);
       restore_getcjmp (save_jump);
 
 #ifdef MULTI_KBOARD
       if (! NILP (c) && (kb != current_kboard))
        {
-         Lisp_Object *tailp = &kb->kbd_queue;
-         while (CONSP (*tailp))
-           tailp = &XCDR (*tailp);
-         if (!NILP (*tailp))
-           abort ();
-         *tailp = Fcons (c, Qnil);
+         Lisp_Object link = kb->kbd_queue;
+         if (CONSP (link))
+           {
+             while (CONSP (XCDR (link)))
+               link = XCDR (link);
+             if (!NILP (XCDR (link)))
+               abort ();
+           }
+         if (!CONSP (link))
+           kb->kbd_queue = Fcons (c, Qnil);
+         else
+           XSETCDR (link, Fcons (c, Qnil));
          kb->kbd_queue_has_data = 1;
          c = Qnil;
          if (single_kboard)
@@ -2427,8 +2632,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  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 ();
-
   start_polling ();
 
   if (NILP (c))
@@ -2452,8 +2659,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      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))
@@ -2508,7 +2714,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
+         POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -2528,7 +2734,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (INTEGERP (c)
       && ! NILP (Vinput_method_function)
       && (unsigned) XINT (c) >= ' '
-      && (unsigned) XINT (c) < 127)
+      && (unsigned) XINT (c) != 127
+      && (unsigned) XINT (c) < 256)
     {
       previous_echo_area_message = Fcurrent_message ();
       Vinput_method_previous_message = previous_echo_area_message;
@@ -2536,7 +2743,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   /* Now wipe the echo area, except for help events which do their
      own stuff with the echo area.  */
-  if (!CONSP (c) || !(EQ (Qhelp_echo, XCAR (c))))
+  if (!CONSP (c)
+      || (!(EQ (Qhelp_echo, XCAR (c)))
+         && !(EQ (Qswitch_frame, XCAR (c)))))
     {
       if (!NILP (echo_area_buffer[0]))
        safe_run_hooks (Qecho_area_clear_hook);
@@ -2552,7 +2761,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         after the first event of the key sequence.  */
       && NILP (prev_event)
       && (unsigned) XINT (c) >= ' '
-      && (unsigned) XINT (c) < 127)
+      && (unsigned) XINT (c) != 127
+      && (unsigned) XINT (c) < 256)
     {
       Lisp_Object keys; 
       int key_count;
@@ -2636,25 +2846,22 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* Display help if not echoing.  */
   if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
     {
-      Lisp_Object msg;
-      
-      msg = XCDR (XCDR (c));
+      /* (help-echo FRAME HELP WINDOW OBJECT POS).  */
+      Lisp_Object help, object, position, window, tem;
 
-      if (!NILP (Vshow_help_function))
-       call1 (Vshow_help_function, msg);
-      else if (/* Don't overwrite minibuffer contents.  */
-              !MINI_WINDOW_P (XWINDOW (selected_window))
-              /* Don't overwrite a keystroke echo.  */
-              && NILP (echo_message_buffer)
-              /* Don't overwrite a prompt.  */
-              && !cursor_in_echo_area)
-       {
-         if (STRINGP (msg))
-           message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg));
-         else
-           message (0);
-       }
+      tem = Fcdr (XCDR (c));
+      help = Fcar (tem);
+      tem = Fcdr (tem);
+      window = Fcar (tem);
+      tem = Fcdr (tem);
+      object = Fcar (tem);
+      tem = Fcdr (tem);
+      position = Fcar (tem);
+
+      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;
     }
   
@@ -2775,11 +2982,44 @@ static void
 record_char (c)
      Lisp_Object c;
 {
-  total_keys++;
-  XVECTOR (recent_keys)->contents[recent_keys_index] = c;
-  if (++recent_keys_index >= NUM_RECENT_KEYS)
-    recent_keys_index = 0;
+  /* 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 = Fcar (Fcdr (XCDR (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 = Fcar (Fcdr (XCDR (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.  :-) */
@@ -2812,7 +3052,8 @@ record_char (c)
       fflush (dribble);
     }
 
-  store_kbd_macro_char (c);
+  if (!CONSP (c) || !EQ (Qhelp_echo, XCAR (c)))
+    store_kbd_macro_char (c);
 
   num_nonmacro_input_events++;
 }
@@ -2867,18 +3108,20 @@ tracking_off (old_value)
         redisplay.  */
       if (!readable_events (1))
        {
-         redisplay_preserve_echo_area ();
+         redisplay_preserve_echo_area (6);
          get_input_pending (&input_pending, 1);
        }
     }
+  return Qnil;
 }
 
 DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
-  "Evaluate BODY with mouse movement events enabled.\n\
-Within a `track-mouse' form, mouse motion generates input events that\n\
-you can read with `read-event'.\n\
-Normally, mouse motion is ignored.")
-  (args)
+       doc: /* Evaluate BODY with mouse movement events enabled.
+Within a `track-mouse' form, mouse motion generates input events that
+you can read with `read-event'.
+Normally, mouse motion is ignored.
+usage: (track-mouse BODY ...)  */)
+     (args)
      Lisp_Object args;
 {
   int count = specpdl_ptr - specpdl;
@@ -3014,6 +3257,7 @@ kbd_buffer_store_event (event)
                    {
                      sp->kind = no_event;
                      sp->frame_or_window = Qnil;
+                     sp->arg = Qnil;
                    }
                }
              return;
@@ -3061,6 +3305,11 @@ kbd_buffer_store_event (event)
      Discard the event if it would fill the last slot.  */
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
+      int idx;
+      
+#if 0 /* The selection_request_event case looks bogus, and it's error
+        prone to assign individual members for other events, in case
+        the input_event structure is changed.  --2000-07-13, gerd.  */
       struct input_event *sp = kbd_store_ptr;
       sp->kind = event->kind;
       if (event->kind == selection_request_event)
@@ -3071,22 +3320,94 @@ kbd_buffer_store_event (event)
          bcopy (event, (char *) sp, sizeof (*event));
        }
       else
+
        {
          sp->code = event->code;
          sp->part = event->part;
          sp->frame_or_window = event->frame_or_window;
+         sp->arg = event->arg;
          sp->modifiers = event->modifiers;
          sp->x = event->x;
          sp->y = event->y;
          sp->timestamp = event->timestamp;
        }
-      (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_store_ptr
-                                                     - kbd_buffer]
-       = event->frame_or_window);
+#else
+      *kbd_store_ptr = *event;
+#endif
 
-      kbd_store_ptr++;
+      idx = 2 * (kbd_store_ptr - kbd_buffer);
+      ASET (kbd_buffer_gcpro, idx, event->frame_or_window);
+      ASET (kbd_buffer_gcpro, idx + 1, event->arg);
+      ++kbd_store_ptr;
     }
 }
+
+
+/* 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
+   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
+gen_help_event (bufp, size, help, frame, window, object, pos)
+     struct input_event *bufp;
+     int size;
+     Lisp_Object help, frame, object, window;
+     int pos;
+{
+  int nevents_stored = 0;
+  
+  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;
+}
+
+
+/* Store HELP_EVENTs for HELP on FRAME in the input queue.  */
+
+void
+kbd_buffer_store_help_event (frame, help)
+     Lisp_Object frame, help;
+{
+  struct input_event event;
+
+  event.kind = HELP_EVENT;
+  event.frame_or_window = frame;
+  event.arg = Qnil;
+  event.x = make_number (0);
+  event.code = 0;
+  kbd_buffer_store_event (&event);
+  
+  event.kind = HELP_EVENT;
+  event.frame_or_window = frame;
+  event.arg = help;
+  event.x = make_number (0);
+  event.code = 1;
+  kbd_buffer_store_event (&event);
+}
+
 \f
 /* Discard any mouse events in the event buffer by setting them to
    no_event.  */
@@ -3109,7 +3430,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
+/* 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,
@@ -3246,7 +3609,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          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)).  */
@@ -3254,6 +3617,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          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)).  */
@@ -3275,7 +3640,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          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;
@@ -3307,15 +3672,51 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        kbd_fetch_ptr = event + 1;
       else if (event->kind == HELP_EVENT)
        {
-         /* The car of event->frame_or_window is a frame,
-            the cdr is the help to display.  */
-         obj = Fcons (Qhelp_echo, event->frame_or_window);
+         /* 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;
+         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)
+       {
+         /* Notification of a FocusIn event.  The frame receiving the
+            focus is in event->frame_or_window.  Generate a
+            switch-frame event if necessary.  */
+         Lisp_Object frame, focus;
+
+         frame = event->frame_or_window;
+         focus = FRAME_FOCUS_FRAME (XFRAME (frame));
+         if (FRAMEP (focus))
+           frame = focus;
+
+         if (!EQ (frame, internal_last_event_frame)
+             && !EQ (frame, selected_frame))
+           obj = make_lispy_switch_frame (frame);
+         internal_last_event_frame = frame;
          kbd_fetch_ptr = event + 1;
        }
-      /* If this event is on a different frame, return a switch-frame this
-        time, and leave the event in the queue for next time.  */
       else
        {
+         /* If this event is on a different frame, return a switch-frame this
+            time, and leave the event in the queue for next time.  */
          Lisp_Object frame;
          Lisp_Object focus;
 
@@ -3340,24 +3741,22 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          if (NILP (obj))
            {
              obj = make_lispy_event (event);
+             
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
              /* If this was a menu selection, then set the flag to inhibit
                 writing to last_nonmenu_event.  Don't do this if the event
                 we're returning is (menu-bar), though; that indicates the
                 beginning of the menu sequence, and we might as well leave
                 that as the `event with parameters' for this selection.  */
-             if ((event->kind == menu_bar_event
-                  || event->kind == TOOL_BAR_EVENT)
-                 && !(CONSP (obj) && EQ (XCAR (obj), Qmenu_bar))
-                 && !(CONSP (obj) && EQ (XCAR (obj), Qtool_bar))
-                 && used_mouse_menu)
+             if (used_mouse_menu
+                 && !EQ (event->frame_or_window, event->arg)
+                 && (event->kind == MENU_BAR_EVENT
+                     || event->kind == TOOL_BAR_EVENT))
                *used_mouse_menu = 1;
 #endif
 
              /* Wipe out this event, to catch bugs.  */
-             event->kind = no_event;
-             XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer] = Qnil;
-
+             clear_event (event);
              kbd_fetch_ptr = event + 1;
            }
        }
@@ -3481,11 +3880,9 @@ swallow_events (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
-static EMACS_TIME timer_idleness_start_time;
-
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
@@ -3570,7 +3967,7 @@ timer_check (do_it_now)
   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;
 
@@ -3681,17 +4078,18 @@ timer_check (do_it_now)
          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);
-
+             
              call1 (Qtimer_event_handler, chosen_timer);
+             Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
-
              unbind_to (count, Qnil);
 
              /* Resume allowing input from any kboard, if that was true before.  */
@@ -4193,11 +4591,16 @@ static int last_mouse_x;
 static int last_mouse_y;
 static unsigned long button_down_time;
 
-/* The maximum time between clicks to make a double-click,
-   or Qnil to disable double-click detection,
-   or Qt for no time limit.  */
+/* The maximum time between clicks to make a double-click, or Qnil to
+   disable double-click detection, or Qt for no time limit.  */
+
 Lisp_Object Vdouble_click_time;
 
+/* Maximum number of pixels the mouse may be moved between clicks
+   to make a double-click.  */
+
+int double_click_fuzz;
+
 /* The number of clicks in this multiple-click. */
 
 int double_click_count;
@@ -4243,6 +4646,14 @@ make_lispy_event (event)
        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:
@@ -4293,12 +4704,35 @@ make_lispy_event (event)
                                     / sizeof (iso_lispy_function_keys[0])));
       else
 #endif
-       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
-                                   event->modifiers,
-                                   Qfunction_key, Qnil,
-                                   lispy_function_keys, &func_key_syms,
-                                   (sizeof (lispy_function_keys)
-                                    / sizeof (lispy_function_keys[0])));
+
+#ifdef HAVE_X_WINDOWS
+      if (event->code - FUNCTION_KEY_OFFSET < 0
+         || (event->code - FUNCTION_KEY_OFFSET
+             >= sizeof lispy_function_keys / sizeof *lispy_function_keys))
+       {
+         /* EVENT->code is an unknown keysym, for example someone
+            assigned `ccaron' to a key in a locale where
+            XmbLookupString doesn't return a translation for it.  */
+         char *name;
+         Lisp_Object symbol;
+         
+         BLOCK_INPUT;
+         /* This returns a pointer to a static area.  Don't free it.  */
+         name = XKeysymToString (event->code);
+         symbol = name ? intern (name) : Qnil;
+         UNBLOCK_INPUT;
+         
+         if (!NILP (symbol))
+           return apply_modifiers (event->modifiers, symbol);
+       }
+#endif /* HAVE_X_WINDOWS */
+
+      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                 event->modifiers,
+                                 Qfunction_key, Qnil,
+                                 lispy_function_keys, &func_key_syms,
+                                 (sizeof (lispy_function_keys)
+                                  / sizeof (lispy_function_keys[0])));
 
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
@@ -4313,13 +4747,15 @@ make_lispy_event (event)
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
+       Lisp_Object window;
+
+       position = Qnil;
 
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == mouse_click)
          {
            int part;
-           FRAME_PTR f = XFRAME (event->frame_or_window);
-           Lisp_Object window;
+           struct frame *f = XFRAME (event->frame_or_window);
            Lisp_Object posn;
            Lisp_Object string_info = Qnil;
            int row, column;
@@ -4366,14 +4802,14 @@ make_lispy_event (event)
                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)
                      {
-                       item = XVECTOR (items)->contents[i];
+                       item = AREF (items, i);
                        break;
                      }
                  }
@@ -4419,7 +4855,7 @@ make_lispy_event (event)
 
                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;
@@ -4432,7 +4868,16 @@ make_lispy_event (event)
                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
@@ -4448,7 +4893,6 @@ make_lispy_event (event)
        else
          {
            /* It's a scrollbar click.  */
-           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -4465,26 +4909,46 @@ make_lispy_event (event)
          }
 #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);
          }
        
-       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;
 
-       is_double = (button == last_mouse_button
-                    && XINT (event->x) == last_mouse_x
-                    && XINT (event->y) == last_mouse_y
-                    && button_down_time != 0
-                    && (EQ (Vdouble_click_time, Qt)
-                        || (INTEGERP (Vdouble_click_time)
-                            && ((int)(event->timestamp - button_down_time)
-                                < XINT (Vdouble_click_time)))));
+       {
+         /* On window-system frames, use the value of
+            double-click-fuzz as is.  On other frames, interpret it
+            as a multiple of 1/8 characters.  */
+         struct frame *f;
+         int fuzz;
+
+         if (WINDOWP (event->frame_or_window))
+           f = XFRAME (XWINDOW (event->frame_or_window)->frame);
+         else if (FRAMEP (event->frame_or_window))
+           f = XFRAME (event->frame_or_window);
+         else
+           abort ();
+
+         if (FRAME_WINDOW_P (f))
+           fuzz = double_click_fuzz;
+         else
+           fuzz = double_click_fuzz / 8;
+
+         is_double = (button == last_mouse_button
+                      && (abs (XINT (event->x) - last_mouse_x) <= fuzz)
+                      && (abs (XINT (event->y) - last_mouse_y) <= fuzz)
+                      && button_down_time != 0
+                      && (EQ (Vdouble_click_time, Qt)
+                          || (INTEGERP (Vdouble_click_time)
+                              && ((int)(event->timestamp - button_down_time)
+                                  < XINT (Vdouble_click_time)))));
+       }
+       
        last_mouse_button = button;
        last_mouse_x = XINT (event->x);
        last_mouse_y = XINT (event->y);
@@ -4510,12 +4974,11 @@ make_lispy_event (event)
            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;
@@ -4527,21 +4990,30 @@ make_lispy_event (event)
            else
 #endif
              {
-               /* The third element of every position should be the (x,y)
-                  pair.  */
                Lisp_Object down;
+               EMACS_INT xdiff = double_click_fuzz, ydiff = double_click_fuzz;
 
-               down = Fnth (make_number (2), start_pos);
-               if (EQ (event->x, XCAR (down))
-                   && EQ (event->y, XCDR (down)))
+               /* The third element of every position
+                  should be the (x,y) pair.  */
+               down = Fcar (Fcdr (Fcdr (start_pos)));
+               if (CONSP (down)
+                   && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down)))
                  {
-                   event->modifiers |= click_modifier;
+                   xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down));
+                   ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down));
                  }
+
+               if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz
+                   && ydiff < double_click_fuzz
+                   && ydiff > - double_click_fuzz)
+                 /* Mouse hasn't moved (much).  */
+                 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)
@@ -4690,7 +5162,8 @@ make_lispy_event (event)
          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))
          {
@@ -4702,7 +5175,8 @@ make_lispy_event (event)
            int pixcolumn, pixrow;
            column -= XINT (XWINDOW (window)->left);
            row -= XINT (XWINDOW (window)->top);
-           glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+           glyph_to_pixel_coords (XWINDOW(window), column, row,
+                                   &pixcolumn, &pixrow);
            XSETINT (event->x, pixcolumn);
            XSETINT (event->y, pixrow);
 
@@ -4713,9 +5187,13 @@ make_lispy_event (event)
            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));
+             }
          }
 
        {
@@ -4747,7 +5225,6 @@ make_lispy_event (event)
        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
@@ -4762,9 +5239,9 @@ make_lispy_event (event)
           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))
          {
@@ -4793,7 +5270,12 @@ make_lispy_event (event)
            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));
+             }
          }
 
        {
@@ -4818,26 +5300,27 @@ make_lispy_event (event)
       }
 #endif /* HAVE_MOUSE */
 
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
-    case menu_bar_event:
-      /* The event value is in the cdr of the frame_or_window slot.  */
-      if (!CONSP (event->frame_or_window))
-       abort ();
-      return XCDR (event->frame_or_window);
+#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
+          `(menu_bar)' because the code in keyboard.c for menu
+          events, which we use, relies on this.  */
+       return Fcons (Qmenu_bar, Qnil);
+      return event->arg;
 #endif
 
     case TOOL_BAR_EVENT:
-      {
-       Lisp_Object key;
-       if (!CONSP (event->frame_or_window))
-         abort ();
-       key = XCDR (event->frame_or_window);
-       if (SYMBOLP (key))
-         key = apply_modifiers (event->modifiers, key);
-       return key;
-      }
-
-    case user_signal:
+      if (EQ (event->arg, event->frame_or_window))
+       /* This is the prefix key.  We translate this to
+          `(tool_bar)' because the code in keyboard.c for menu
+          events, which we use, relies on this.  */
+       return Fcons (Qtool_bar, Qnil);
+      else if (SYMBOLP (event->arg))
+       return apply_modifiers (event->modifiers, event->arg);
+      return event->arg;
+
+    case USER_SIGNAL_EVENT:
       /* A user signal.  */
       return *lispy_user_signals[event->code];
       
@@ -4904,7 +5387,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
          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)
        {
@@ -4958,7 +5446,7 @@ parse_modifiers_uncached (symbol, modifier_end)
   int i;
   int modifiers;
 
-  CHECK_SYMBOL (symbol, 1);
+  CHECK_SYMBOL (symbol);
 
   modifiers = 0;
   name = XSYMBOL (symbol)->name;
@@ -5142,7 +5630,7 @@ parse_modifiers (symbol)
                                         STRING_BYTES (XSYMBOL (symbol)->name) - end),
                            Qnil);
 
-      if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1))
+      if (modifiers & ~VALMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -5179,7 +5667,7 @@ apply_modifiers (modifiers, base)
   Lisp_Object cache, index, entry, new_symbol;
 
   /* Mask out upper bits.  We don't know where this value's been.  */
-  modifiers &= ((EMACS_INT)1 << VALBITS) - 1;
+  modifiers &= VALMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -5261,7 +5749,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
-   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.
 
@@ -5378,13 +5866,13 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem,
    event type as a number or a symbol.  */
 
 DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
-  "Convert the event description list EVENT-DESC to an event type.\n\
-EVENT-DESC should contain one base event type (a character or symbol)\n\
-and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
-drag, down, double or triple).  The base must be last.\n\
-The return value is an event type (a character or symbol) which\n\
-has the same base event type and all the specified modifiers.")
-  (event_desc)
+       doc: /* Convert the event description list EVENT-DESC to an event type.
+EVENT-DESC should contain one base event type (a character or symbol)
+and zero or more modifier names (control, meta, hyper, super, shift, alt,
+drag, down, double or triple).  The base must be last.
+The return value is an event type (a character or symbol) which
+has the same base event type and all the specified modifiers.  */)
+     (event_desc)
      Lisp_Object event_desc;
 {
   Lisp_Object base;
@@ -5438,7 +5926,10 @@ has the same base event type and all the specified modifiers.")
   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.
@@ -5534,6 +6025,12 @@ lucid_event_type_list_p (object)
   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;
@@ -5611,6 +6108,7 @@ record_asynch_buffer_change ()
 
   event.kind = buffer_switch_event;
   event.frame_or_window = Qnil;
+  event.arg = Qnil;
 
 #ifdef subprocesses
   /* We don't need a buffer-switch event unless Emacs is waiting for input.
@@ -5772,6 +6270,7 @@ read_avail_input (expected)
 
          buf[i].code = cbuf[i];
          buf[i].frame_or_window = selected_frame;
+         buf[i].arg = Qnil;
        }
     }
 
@@ -5854,27 +6353,8 @@ reinvoke_input_signal ()
 
 
 \f
-/* Return the prompt-string of a sparse keymap.
-   This is the first element which is a string.
-   Return nil if there is none.  */
-
-Lisp_Object
-map_prompt (map)
-     Lisp_Object map;
-{
-  while (CONSP (map))
-    {
-      register Lisp_Object tem;
-      tem = Fcar (map);
-      if (STRINGP (tem))
-       return tem;
-      map = Fcdr (map);
-    }
-  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
@@ -5900,7 +6380,7 @@ menu_bar_items (old)
      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;
 
@@ -5949,11 +6429,18 @@ menu_bar_items (old)
       }
     else
       {
-       /* No, so use major and minor mode keymaps.  */
+       /* No, so use major and minor mode keymaps and keymap property.  */
+       int extra_maps = 2;
+       Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
+       if (!NILP (map))
+         extra_maps = 3;
        nmaps = current_minor_maps (NULL, &tmaps);
-       maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+       maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
+                                      * sizeof (maps[0]));
        bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-       maps[nmaps++] = get_local_map (PT, current_buffer);
+       if (!NILP (map))
+         maps[nmaps++] = map;
+       maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
       }
     maps[nmaps++] = current_global_map;
   }
@@ -5963,16 +6450,13 @@ menu_bar_items (old)
   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.  */
 
@@ -6085,29 +6569,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;
-           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 (!NILP (tem))
+  if (!NILP (tem) || NILP (item))
     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.  */
@@ -6209,11 +6691,11 @@ parse_menu_item (item, notreal, inmenubar)
 
   /* 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.  */
-  XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item;
+  AREF (item_properties, ITEM_PROPERTY_ITEM) = item;
 
   item_string = XCAR (item);
 
@@ -6222,18 +6704,17 @@ parse_menu_item (item, notreal, inmenubar)
   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)))
        {
-         XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
-           = XCAR (item);
+         AREF (item_properties, ITEM_PROPERTY_HELP) = XCAR (item);
          start = item;
          item = XCDR (item);
        }
          
-      /* Maybee key binding cache.  */
+      /* Maybe key binding cache.  */
       if (CONSP (item) && CONSP (XCAR (item))
          && (NILP (XCAR (XCAR (item)))
              || VECTORP (XCAR (XCAR (item)))))
@@ -6243,27 +6724,25 @@ parse_menu_item (item, notreal, inmenubar)
        }
       
       /* 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))
-           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.  */
-      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.  */
-         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. */
@@ -6280,8 +6759,7 @@ parse_menu_item (item, notreal, inmenubar)
              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
@@ -6291,8 +6769,7 @@ parse_menu_item (item, notreal, inmenubar)
                    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))
@@ -6307,8 +6784,7 @@ parse_menu_item (item, notreal, inmenubar)
                {
                  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)))
                {
@@ -6317,9 +6793,9 @@ parse_menu_item (item, notreal, inmenubar)
                  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);
-                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+                     AREF (item_properties, ITEM_PROPERTY_TYPE)
                        = type;
                    }
                }
@@ -6334,23 +6810,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.  */
-  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;
-      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.  */
-  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)));
 
-      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
@@ -6359,7 +6835,7 @@ parse_menu_item (item, notreal, inmenubar)
     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)
@@ -6368,19 +6844,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.  */
-      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.  */
-  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.  */
-  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;
     }
+  
   /* 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.  */
@@ -6392,21 +6869,22 @@ parse_menu_item (item, notreal, inmenubar)
     {
       /* We have to create a cachelist.  */
       CHECK_IMPURE (start);
-      XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
+      XSETCDR (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);
+         XSETCAR (cachelist, XCAR (keyhint));
          newcache = 0;
        }
       else if (STRINGP (tem))
        {
-         XCDR (cachelist) = Fsubstitute_command_keys (tem);
-         XCAR (cachelist) = Qt;
+         XSETCDR (cachelist, Fsubstitute_command_keys (tem));
+         XSETCAR (cachelist, Qt);
        }
     }
+  
   tem = XCAR (cachelist);
   if (!EQ (tem, Qt))
     {
@@ -6416,21 +6894,22 @@ parse_menu_item (item, notreal, inmenubar)
       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
-       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?  */
-             /* || 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
@@ -6455,14 +6934,15 @@ 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. */
-         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);
-         XCAR (cachelist) = tem;
+         XSETCAR (cachelist, tem);
          if (NILP (tem))
            {
-             XCDR (cachelist) = Qnil;
+             XSETCDR (cachelist, Qnil);
              chkcache = 0;
            }
        }
@@ -6483,7 +6963,7 @@ parse_menu_item (item, notreal, inmenubar)
              if (STRINGP (XCDR (prefix)))
                tem = concat2 (tem, XCDR (prefix));
            }
-         XCDR (cachelist) = tem;
+         XSETCDR (cachelist, tem);
        }
     }
 
@@ -6491,7 +6971,7 @@ parse_menu_item (item, notreal, inmenubar)
   if (newcache && !NILP (tem))
     {
       tem = concat3 (build_string ("  ("), tem, build_string (")"));
-      XCDR (cachelist) = tem;
+      XSETCDR (cachelist, tem);
     }
 
   /* If we only want to precompute equivalent key bindings, stop here. */
@@ -6499,7 +6979,7 @@ parse_menu_item (item, notreal, inmenubar)
     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];
@@ -6513,9 +6993,9 @@ parse_menu_item (item, notreal, inmenubar)
   */
 
   /* Handle radio buttons or toggle boxes.  */ 
-  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+  tem = AREF (item_properties, ITEM_PROPERTY_SELECTED);
   if (!NILP (tem))
-    XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+    AREF (item_properties, ITEM_PROPERTY_SELECTED)
       = menu_item_eval_property (tem);
 
   return 1;
@@ -6601,11 +7081,18 @@ tool_bar_items (reuse, nitems)
     }
   else
     {
-      /* No, so use major and minor mode keymaps.  */
+      /* No, so use major and minor mode keymaps and keymap property.  */
+      int extra_maps = 2;
+      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
+      if (!NILP (map))
+       extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
-      maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+      maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
+                                    * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-      maps[nmaps++] = get_local_map (PT, current_buffer);
+      if (!NILP (map))
+       maps[nmaps++] = map;
+      maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
     }
 
   /* Add global keymap at the end.  */
@@ -6617,9 +7104,9 @@ tool_bar_items (reuse, nitems)
     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;
            
@@ -6736,9 +7223,9 @@ parse_tool_bar_item (key, item)
   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)
@@ -6782,6 +7269,10 @@ parse_tool_bar_item (key, 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)))
     {
@@ -6835,7 +7326,7 @@ parse_tool_bar_item (key, item)
                                               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.  */
@@ -6951,7 +7442,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
@@ -6993,14 +7484,12 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
             to indicate that they came from a mouse menu,
             so that when present in last_nonmenu_event
             they won't confuse things.  */
-         for (tem = XCDR (value); !NILP (tem);
-              tem = XCDR (tem))
+         for (tem = XCDR (value); !NILP (tem); tem = XCDR (tem))
            {
              record_menu_key (XCAR (tem));
              if (SYMBOLP (XCAR (tem))
                  || INTEGERP (XCAR (tem)))
-               XCAR (tem)
-                 = Fcons (XCAR (tem), Qnil);
+               XSETCAR (tem, Fcons (XCAR (tem), Qdisabled));
            }
 
          /* If we got more than one event, put all but the first
@@ -7041,6 +7530,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   Lisp_Object rest, vector;
   char *menu;
 
+  vector = Qnil;
+
   if (! menu_prompting)
     return Qnil;
 
@@ -7061,7 +7552,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
@@ -7144,7 +7635,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;
-                 Lisp_Object desc;
+                 Lisp_Object desc = Qnil;
                  Lisp_Object s
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
 
@@ -7153,7 +7644,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)
-                   desc = Fsingle_key_description (event);
+                   desc = Fsingle_key_description (event, Qnil);
 
                  tem
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
@@ -7247,7 +7738,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
       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;
 
@@ -7294,31 +7785,6 @@ follow_key (key, nmaps, current, defs, next)
   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) && (XINT (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--)
     {
@@ -7330,7 +7796,7 @@ follow_key (key, nmaps, current, defs, next)
          else
            map = current[i];
 
-         defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 0);
+         defs[i] = access_keymap (map, key, 1, 0, 1);
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -7341,7 +7807,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++)
-      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;
 }
@@ -7393,40 +7859,45 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      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.  */
-  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.  */
-  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.  */
-  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.  */
-  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.  */
-  Lisp_Object *submaps;
+  Lisp_Object *volatile submaps = NULL;
 
   /* 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.  */
+  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.  */
-  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.  */
-  int first_binding;
+  volatile int first_binding;
 
   /* If t < mock_input, then KEYBUF[t] should be read as the next
      input key.
@@ -7441,7 +7912,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.  */
-  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,
@@ -7451,24 +7922,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.  */
-  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.  */
-  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.  */
-  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
 
-  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;
@@ -7477,8 +7948,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.  */
-  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.  */
@@ -7494,6 +7968,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int junk;
 #endif
 
+  struct gcpro gcpro1;
+
+  GCPRO1 (fake_prefixed_keys);
   raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
@@ -7503,17 +7980,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.  */
-  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.  */
-  if (NILP (Fkeymapp (Vkey_translation_map)))
+  if (!KEYMAPP (Vkey_translation_map))
     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)))
@@ -7540,7 +8017,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                           &junk);
 #endif /* GOBBLE_FIRST_EVENT */
 
-  orig_local_map = get_local_map (PT, current_buffer);
+  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,
@@ -7576,14 +8055,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       }
     else
       {
+       int extra_maps = 2;
        nmaps = current_minor_maps (0, &maps);
-       if (nmaps + 2 > nmaps_allocated)
+       if (!NILP (orig_keymap))
+         extra_maps = 3;
+       if (nmaps + extra_maps > nmaps_allocated)
          {
-           submaps = (Lisp_Object *) alloca ((nmaps+2) * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca ((nmaps+2) * sizeof (defs[0]));
-           nmaps_allocated = nmaps + 2;
+           submaps = (Lisp_Object *) alloca ((nmaps+extra_maps)
+                                             * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca ((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;
       }
     submaps[nmaps++] = current_global_map;
@@ -7628,13 +8114,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.  */
-      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.  */
-      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");
@@ -7702,11 +8188,13 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                               interrupted_kboard->kbd_queue);
                  }
                mock_input = 0;
-               orig_local_map = get_local_map (PT, current_buffer);
+               orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+               orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                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);
          }
 
@@ -7715,6 +8203,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (EQ (key, Qt))
            {
              unbind_to (count, Qnil);
+             UNGCPRO;
              return -1;
            }
 
@@ -7747,21 +8236,25 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                    Fset_buffer (XWINDOW (selected_window)->buffer);
                }
 
-             orig_local_map = get_local_map (PT, current_buffer);
+             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
          /* If we have a quit that was typed in another frame, and
             quit_throw_to_read_char switched buffers,
             replay to get the right keymap.  */
-         if (XINT (key) == quit_char && current_buffer != starting_buffer)
+         if (INTEGERP (key)
+             && XINT (key) == quit_char
+             && current_buffer != starting_buffer)
            {
              GROW_RAW_KEYBUF;
              XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
-             orig_local_map = get_local_map (PT, current_buffer);
+             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
@@ -7810,10 +8303,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              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;
@@ -7847,7 +8342,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  if (! FRAME_LIVE_P (XFRAME (selected_frame)))
                    Fkill_emacs (Qnil);
                  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,
+                                                 Qlocal_map);
+                 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                  goto replay_sequence;
                }
              
@@ -7868,13 +8365,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                      if (INTEGERP (pos)
                          && XINT (pos) >= BEG && XINT (pos) <= Z)
                        {
-                         map_here = get_local_map (XINT (pos), current_buffer);
+                         map_here = get_local_map (XINT (pos),
+                                                   current_buffer, Qlocal_map);
                          if (!EQ (map_here, orig_local_map))
                            {
                              orig_local_map = map_here;
                              keybuf[t] = key;
                              mock_input = t + 1;
 
+                             goto replay_sequence;
+                           }
+                         map_here = get_local_map (XINT (pos),
+                                                    current_buffer, Qkeymap);
+                         if (!EQ (map_here, orig_keymap))
+                           {
+                             orig_keymap = map_here;
+                             keybuf[t] = key;
+                             mock_input = t + 1;
+
                              goto replay_sequence;
                            }
                        }
@@ -7883,41 +8391,76 @@ 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.  */
-             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");
-                 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 (CONSP (POSN_STRING (EVENT_START (key))))
                    {
-                     Lisp_Object string, pos, map;
+                     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),
-                             !NILP (map)))
+                      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))
+                            goto replay_sequence;
+                        }
+                   }
+
+                 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))
                        {
-                         orig_local_map = map;
+                         from_string = string;
                          goto replay_sequence;
                        }
                    }
-
-                 goto replay_key;
                }
            }
          else if (CONSP (XCDR (key))
@@ -7938,8 +8481,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* 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);
+                 POSN_BUFFER_SET_POSN (EVENT_START (key),
+                                       Fcons (posn, Qnil));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -8119,22 +8662,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              Lisp_Object key;
 
              key = keybuf[fkey_end++];
-             /* Look up meta-characters by prefixing them
-                with meta_prefix_char.  I hate this.  */
-             if (INTEGERP (key) && XINT (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
-               = 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))
@@ -8147,7 +8676,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))
-                     || !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
@@ -8220,11 +8749,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  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 (NILP (fkey_map))
+             if (!CONSP (fkey_map))
                {
                  fkey_end = ++fkey_start;
                  fkey_map = Vfunction_key_map;
@@ -8243,22 +8772,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            Lisp_Object key;
 
            key = keybuf[keytran_end++];
-           /* Look up meta-characters by prefixing them
-              with meta_prefix_char.  I hate this.  */
-           if (INTEGERP (key) && XINT (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
-             = 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))
@@ -8271,7 +8786,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))
-                   || !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
@@ -8335,11 +8850,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                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 (NILP (keytran_map))
+           if (!CONSP (keytran_map))
              {
                keytran_end = ++keytran_start;
                keytran_map = Vkey_translation_map;
@@ -8460,63 +8975,57 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   
 
+  UNGCPRO;
   return t;
 }
 
-#if 0 /* This doc string is too long for some compilers.
-        This commented-out definition serves for DOC.  */
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
-  "Read a sequence of keystrokes and return as a string or vector.\n\
-The sequence is sufficient to specify a non-prefix command in the\n\
-current local and global maps.\n\
-\n\
-First arg PROMPT is a prompt string.  If nil, do not prompt specially.\n\
-Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos\n\
-as a continuation of the previous key.\n\
-\n\
-The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not\n\
-convert the last event to lower case.  (Normally any upper case event\n\
-is converted to lower case if the original event is undefined and the lower\n\
-case equivalent is defined.)  A non-nil value is appropriate for reading\n\
-a key sequence to be defined.\n\
-\n\
-A C-g typed while in this function is treated like any other character,\n\
-and `quit-flag' is not set.\n\
-\n\
-If the key sequence starts with a mouse click, then the sequence is read\n\
-using the keymaps of the buffer of the window clicked in, not the buffer\n\
-of the selected window as normal.\n\
-""\n\
-`read-key-sequence' drops unbound button-down events, since you normally\n\
-only care about the click or drag events which follow them.  If a drag\n\
-or multi-click event is unbound, but the corresponding click event would\n\
-be bound, `read-key-sequence' turns the event into a click event at the\n\
-drag's starting position.  This means that you don't have to distinguish\n\
-between click and drag, double, or triple events unless you want to.\n\
-\n\
-`read-key-sequence' prefixes mouse events on mode lines, the vertical\n\
-lines separating windows, and scroll bars with imaginary keys\n\
-`mode-line', `vertical-line', and `vertical-scroll-bar'.\n\
-\n\
-Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this\n\
-function will process a switch-frame event if the user switches frames\n\
-before typing anything.  If the user switches frames in the middle of a\n\
-key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME\n\
-is nil, then the event will be put off until after the current key sequence.\n\
-\n\
-`read-key-sequence' checks `function-key-map' for function key\n\
-sequences, where they wouldn't conflict with ordinary bindings.  See\n\
-`function-key-map' for more details.\n\
-\n\
-The optional fifth argument COMMAND-LOOP, if non-nil, means\n\
-that this key sequence is being read by something that will\n\
-read commands one after another.  It should be nil if the caller\n\
-will read just one key sequence.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
-#endif
-
 DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
-  0)
+       doc: /* Read a sequence of keystrokes and return as a string or vector.
+The sequence is sufficient to specify a non-prefix command in the
+current local and global maps.
+
+First arg PROMPT is a prompt string.  If nil, do not prompt specially.
+Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
+as a continuation of the previous key.
+
+The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
+convert the last event to lower case.  (Normally any upper case event
+is converted to lower case if the original event is undefined and the lower
+case equivalent is defined.)  A non-nil value is appropriate for reading
+a key sequence to be defined.
+
+A C-g typed while in this function is treated like any other character,
+and `quit-flag' is not set.
+
+If the key sequence starts with a mouse click, then the sequence is read
+using the keymaps of the buffer of the window clicked in, not the buffer
+of the selected window as normal.
+
+`read-key-sequence' drops unbound button-down events, since you normally
+only care about the click or drag events which follow them.  If a drag
+or multi-click event is unbound, but the corresponding click event would
+be bound, `read-key-sequence' turns the event into a click event at the
+drag's starting position.  This means that you don't have to distinguish
+between click and drag, double, or triple events unless you want to.
+
+`read-key-sequence' prefixes mouse events on mode lines, the vertical
+lines separating windows, and scroll bars with imaginary keys
+`mode-line', `vertical-line', and `vertical-scroll-bar'.
+
+Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this
+function will process a switch-frame event if the user switches frames
+before typing anything.  If the user switches frames in the middle of a
+key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME
+is nil, then the event will be put off until after the current key sequence.
+
+`read-key-sequence' checks `function-key-map' for function key
+sequences, where they wouldn't conflict with ordinary bindings.  See
+`function-key-map' for more details.
+
+The optional fifth argument COMMAND-LOOP, if non-nil, means
+that this key sequence is being read by something that will
+read commands one after another.  It should be nil if the caller
+will read just one key sequence.  */)
   (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
    command_loop)
      Lisp_Object prompt, continue_echo, dont_downcase_last;
@@ -8528,7 +9037,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
   int count = specpdl_ptr - specpdl;
 
   if (!NILP (prompt))
-    CHECK_STRING (prompt, 0);
+    CHECK_STRING (prompt);
   QUIT;
 
   specbind (Qinput_method_exit_on_first_char,
@@ -8547,17 +9056,21 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
     }
 
 #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);
 
+#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
-  if (display_busy_cursor_p)
-    start_busy_cursor ();
+  if (display_hourglass_p)
+    start_hourglass ();
+#endif
 #endif
 
   if (i == -1)
@@ -8571,9 +9084,9 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
 
 DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
        Sread_key_sequence_vector, 1, 5, 0,
-  "Like `read-key-sequence' but always return a vector.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
-   command_loop)
+       doc: /* Like `read-key-sequence' but always return a vector.  */)
+     (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+      command_loop)
      Lisp_Object prompt, continue_echo, dont_downcase_last;
      Lisp_Object can_return_switch_frame, command_loop;
 {
@@ -8583,7 +9096,7 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
   int count = specpdl_ptr - specpdl;
 
   if (!NILP (prompt))
-    CHECK_STRING (prompt, 0);
+    CHECK_STRING (prompt);
   QUIT;
 
   specbind (Qinput_method_exit_on_first_char,
@@ -8602,8 +9115,8 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
     }
 
 #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])),
@@ -8611,8 +9124,8 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
                         ! 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)
@@ -8625,15 +9138,15 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
 }
 \f
 DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
- "Execute CMD as an editor command.\n\
-CMD must be a symbol that satisfies the `commandp' predicate.\n\
-Optional second arg RECORD-FLAG non-nil\n\
-means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.\n\
-The argument KEYS specifies the value to use instead of (this-command-keys)\n\
-when reading the arguments; if it is nil, (this-command-keys) is used.\n\
-The argument SPECIAL, if non-nil, means that this command is executing\n\
-a special event, so ignore the prefix argument and don't clear it.")
+       doc: /* Execute CMD as an editor command.
+CMD must be a symbol that satisfies the `commandp' predicate.
+Optional second arg RECORD-FLAG non-nil
+means unconditionally put this command in `command-history'.
+Otherwise, that is done only if an arg is read using the minibuffer.
+The argument KEYS specifies the value to use instead of (this-command-keys)
+when reading the arguments; if it is nil, (this-command-keys) is used.
+The argument SPECIAL, if non-nil, means that this command is executing
+a special event, so ignore the prefix argument and don't clear it.  */)
      (cmd, record_flag, keys, special)
      Lisp_Object cmd, record_flag, keys, special;
 {
@@ -8698,7 +9211,7 @@ a special event, so ignore the prefix argument and don't clear it.")
            {
              tem = Fnthcdr (Vhistory_length, Vcommand_history);
              if (CONSP (tem))
-               XCDR (tem) = Qnil;
+               XSETCDR (tem, Qnil);
            }
        }
 
@@ -8721,11 +9234,13 @@ a special event, so ignore the prefix argument and don't clear it.")
     }
   return Qnil;
 }
+
+
 \f
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
-  1, 1, "P",
-  "Read function name, then read its arguments and call it.")
-  (prefixarg)
+       1, 1, "P",
+       doc: /* Read function name, then read its arguments and call it.  */)
+     (prefixarg)
      Lisp_Object prefixarg;
 {
   Lisp_Object function;
@@ -8843,7 +9358,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          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
@@ -8862,7 +9379,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
              && message_p)
            restore_message ();
 
-         pop_message ();
+         unbind_to (count, Qnil);
        }
     }
 
@@ -8894,11 +9411,18 @@ current_active_maps (maps_p)
     }
   else
     {
-      /* No, so use major and minor mode keymaps.  */
+      /* No, so use major and minor mode keymaps and keymap property.  */
+      int extra_maps = 2;
+      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
+      if (!NILP (map))
+       extra_maps = 3;
       nmaps = current_minor_maps (NULL, &tmaps);
-      maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0]));
+      maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
+                                    * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-      maps[nmaps++] = get_local_map (PT, current_buffer);
+      if (!NILP (map))
+       maps[nmaps++] = map;
+      maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
     }
   maps[nmaps++] = current_global_map;
 
@@ -8930,7 +9454,7 @@ detect_input_pending_run_timers (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
@@ -8967,9 +9491,10 @@ requeued_events_pending_p ()
 
 
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
-  "T if command input is currently available with no waiting.\n\
-Actually, the value is nil only if we can be sure that no input is available.")
-  ()
+       doc: /* Return t if command input is currently available with no wait.
+Actually, the value is nil only if we can be sure that no input is available;
+if there is a doubt, the value is t.  */)
+     ()
 {
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
@@ -8979,8 +9504,8 @@ Actually, the value is nil only if we can be sure that no input is available.")
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
-  "Return vector of last 100 events, not counting those from keyboard macros.")
-  ()
+       doc: /* Return vector of last 100 events, not counting those from keyboard macros.  */)
+     ()
 {
   Lisp_Object *keys = XVECTOR (recent_keys)->contents;
   Lisp_Object val;
@@ -9001,17 +9526,17 @@ DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
 }
 
 DEFUN ("this-command-keys", Fthis_command_keys, Sthis_command_keys, 0, 0, 0,
-  "Return the key sequence that invoked this command.\n\
-The value is a string or a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command.
+The value is a string or a vector.  */)
+     ()
 {
   return make_event_array (this_command_key_count,
                           XVECTOR (this_command_keys)->contents);
 }
 
 DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
-  "Return the key sequence that invoked this command, as a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command, as a vector.  */)
+     ()
 {
   return Fvector (this_command_key_count,
                  XVECTOR (this_command_keys)->contents);
@@ -9019,11 +9544,11 @@ DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys
 
 DEFUN ("this-single-command-keys", Fthis_single_command_keys,
        Sthis_single_command_keys, 0, 0, 0,
-  "Return the key sequence that invoked this command.\n\
-Unlike `this-command-keys', this function's value\n\
-does not include prefix arguments.\n\
-The value is always a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command.
+Unlike `this-command-keys', this function's value
+does not include prefix arguments.
+The value is always a vector.  */)
+     ()
 {
   return Fvector (this_command_key_count
                  - this_single_command_key_start,
@@ -9033,30 +9558,30 @@ The value is always a vector.")
 
 DEFUN ("this-single-command-raw-keys", Fthis_single_command_raw_keys,
        Sthis_single_command_raw_keys, 0, 0, 0,
-  "Return the raw events that were read for this command.\n\
-Unlike `this-single-command-keys', this function's value\n\
-shows the events before all translations (except for input methods).\n\
-The value is always a vector.")
-  ()
+       doc: /* Return the raw events that were read for this command.
+Unlike `this-single-command-keys', this function's value
+shows the events before all translations (except for input methods).
+The value is always a vector.  */)
+     ()
 {
   return Fvector (raw_keybuf_count,
                  (XVECTOR (raw_keybuf)->contents));
 }
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
-  Sreset_this_command_lengths, 0, 0, 0,
-  "Used for complicated reasons in `universal-argument-other-key'.\n\
-\n\
-`universal-argument-other-key' rereads the event just typed.\n\
-It then gets translated through `function-key-map'.\n\
-The translated event gets included in the echo area and in\n\
-the value of `this-command-keys' in addition to the raw original event.\n\
-That is not right.\n\
-\n\
-Calling this function directs the translated event to replace\n\
-the original event, so that only one version of the event actually\n\
-appears in the echo area and in the value of `this-command-keys.'.")
-  ()
+       Sreset_this_command_lengths, 0, 0, 0,
+       doc: /* Used for complicated reasons in `universal-argument-other-key'.
+
+`universal-argument-other-key' rereads the event just typed.
+It then gets translated through `function-key-map'.
+The translated event gets included in the echo area and in
+the value of `this-command-keys' in addition to the raw original event.
+That is not right.
+
+Calling this function directs the translated event to replace
+the original event, so that only one version of the event actually
+appears in the echo area and in the value of `this-command-keys'.  */)
+     ()
 {
   before_command_restore_flag = 1;
   before_command_key_count_1 = before_command_key_count;
@@ -9065,10 +9590,10 @@ appears in the echo area and in the value of `this-command-keys.'.")
 }
 
 DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
-  Sclear_this_command_keys, 0, 0, 0,
-  "Clear out the vector that `this-command-keys' returns.\n\
-Clear vector containing last 100 events.")
-  ()
+       Sclear_this_command_keys, 0, 0, 0,
+       doc: /* Clear out the vector that `this-command-keys' returns.
+Clear vector containing last 100 events.  */)
+     ()
 {
   int i;
   
@@ -9082,8 +9607,8 @@ Clear vector containing last 100 events.")
 }
 
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
-  "Return the current depth in recursive edits.")
-  ()
+       doc: /* Return the current depth in recursive edits.  */)
+     ()
 {
   Lisp_Object temp;
   XSETFASTINT (temp, command_loop_level + minibuf_level);
@@ -9091,10 +9616,10 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
 }
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
-  "FOpen dribble file: ",
-  "Start writing all keyboard characters to a dribble file called FILE.\n\
-If FILE is nil, close any open dribble file.")
-  (file)
+       "FOpen dribble file: ",
+       doc: /* Start writing all keyboard characters to a dribble file called FILE.
+If FILE is nil, close any open dribble file.  */)
+     (file)
      Lisp_Object file;
 {
   if (dribble)
@@ -9113,9 +9638,9 @@ If FILE is nil, close any open dribble file.")
 }
 
 DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0,
-  "Discard the contents of the terminal input buffer.\n\
-Also cancel any kbd macro being defined.")
-  ()
+       doc: /* Discard the contents of the terminal input buffer.
+Also cancel any kbd macro being defined.  */)
+     ()
 {
   current_kboard->defining_kbd_macro = Qnil;
   update_mode_lines++;
@@ -9126,25 +9651,26 @@ Also cancel any kbd macro being defined.")
   discard_tty_input ();
 
   kbd_fetch_ptr =  kbd_store_ptr;
-  Ffillarray (kbd_buffer_frame_or_window, Qnil);
+  Ffillarray (kbd_buffer_gcpro, Qnil);
   input_pending = 0;
 
   return Qnil;
 }
 \f
 DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
-  "Stop Emacs and return to superior process.  You can resume later.\n\
-If `cannot-suspend' is non-nil, or if the system doesn't support job\n\
-control, run a subshell instead.\n\n\
-If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
-to be read as terminal input by Emacs's parent, after suspension.\n\
-\n\
-Before suspending, run the normal hook `suspend-hook'.\n\
-After resumption run the normal hook `suspend-resume-hook'.\n\
-\n\
-Some operating systems cannot stop the Emacs process and resume it later.\n\
-On such systems, Emacs starts a subshell instead of suspending.")
-  (stuffstring)
+       doc: /* Stop Emacs and return to superior process.  You can resume later.
+If `cannot-suspend' is non-nil, or if the system doesn't support job
+control, run a subshell instead.
+
+If optional arg STUFFSTRING is non-nil, its characters are stuffed
+to be read as terminal input by Emacs's parent, after suspension.
+
+Before suspending, run the normal hook `suspend-hook'.
+After resumption run the normal hook `suspend-resume-hook'.
+
+Some operating systems cannot stop the Emacs process and resume it later.
+On such systems, Emacs starts a subshell instead of suspending.  */)
+     (stuffstring)
      Lisp_Object stuffstring;
 {
   int count = specpdl_ptr - specpdl;
@@ -9153,7 +9679,7 @@ On such systems, Emacs starts a subshell instead of suspending.")
   struct gcpro gcpro1;
 
   if (!NILP (stuffstring))
-    CHECK_STRING (stuffstring, 0);
+    CHECK_STRING (stuffstring);
 
   /* Run the functions in suspend-hook.  */
   if (!NILP (Vrun_hooks))
@@ -9210,20 +9736,25 @@ stuff_buffered_input (stuffstring)
        stuff_char (*p++);
       stuff_char ('\n');
     }
+  
   /* Anything we have read ahead, put back for the shell to read.  */
   /* ?? What should this do when we have multiple keyboards??
      Should we ignore anything that was typed in at the "wrong" kboard?  */
   for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++)
     {
+      int idx;
+      
       if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
        kbd_fetch_ptr = kbd_buffer;
       if (kbd_fetch_ptr->kind == ascii_keystroke)
        stuff_char (kbd_fetch_ptr->code);
+      
       kbd_fetch_ptr->kind = no_event;
-      (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_fetch_ptr
-                                                     - kbd_buffer]
-       = Qnil);
+      idx = 2 * (kbd_fetch_ptr - kbd_buffer);
+      ASET (kbd_buffer_gcpro, idx, Qnil);
+      ASET (kbd_buffer_gcpro, idx + 1, Qnil);
     }
+  
   input_pending = 0;
 #endif
 #endif /* BSD_SYSTEM and not BSD4_1 */
@@ -9253,16 +9784,17 @@ clear_waiting_for_input ()
 }
 
 /* This routine is called at interrupt level in response to C-G.
- If interrupt_input, this is the handler for SIGINT.
- Otherwise, it is called from kbd_buffer_store_event,
- in handling SIGIO or SIGTINT.
+   
+   If interrupt_input, this is the handler for SIGINT.  Otherwise, it
+   is called from kbd_buffer_store_event, in handling SIGIO or
+   SIGTINT.
 
- If `waiting_for_input' is non zero, then unless `echoing' is nonzero,
- immediately throw back to read_char.
+   If `waiting_for_input' is non zero, then unless `echoing' is
  nonzero, immediately throw back to read_char.
 
- Otherwise it sets the Lisp variable  quit-flag  not-nil.
- This causes  eval  to throw, when it gets a chance.
If  quit-flag  is already non-nil, it stops the job right away.  */
+   Otherwise it sets the Lisp variable quit-flag not-nil.  This causes
+   eval to throw, when it gets a chance.  If quit-flag is already
  non-nil, it stops the job right away.  */
 
 SIGTYPE
 interrupt_signal (signalnum)   /* If we don't have an argument, */
@@ -9431,23 +9963,23 @@ 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),
-                    Qnil, 0);
+                    0, 0);
 
   _longjmp (getcjmp, 1);
 }
 \f
 DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 4, 0,
-  "Set mode of reading keyboard input.\n\
-First arg INTERRUPT non-nil means use input interrupts;\n\
- nil means use CBREAK mode.\n\
-Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal\n\
- (no effect except in CBREAK mode).\n\
-Third arg META t means accept 8-bit input (for a Meta key).\n\
- META nil means ignore the top bit, on the assumption it is parity.\n\
- Otherwise, accept 8-bit input and don't use the top bit for Meta.\n\
-Optional fourth arg QUIT if non-nil specifies character to use for quitting.\n\
-See also `current-input-mode'.")
-  (interrupt, flow, meta, quit)
+       doc: /* Set mode of reading keyboard input.
+First arg INTERRUPT non-nil means use input interrupts;
+ nil means use CBREAK mode.
+Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal
+ (no effect except in CBREAK mode).
+Third arg META t means accept 8-bit input (for a Meta key).
+ META nil means ignore the top bit, on the assumption it is parity.
+ Otherwise, accept 8-bit input and don't use the top bit for Meta.
+Optional fourth arg QUIT if non-nil specifies character to use for quitting.
+See also `current-input-mode'.  */)
+     (interrupt, flow, meta, quit)
      Lisp_Object interrupt, flow, meta, quit;
 {
   if (!NILP (quit)
@@ -9509,20 +10041,20 @@ See also `current-input-mode'.")
 }
 
 DEFUN ("current-input-mode", Fcurrent_input_mode, Scurrent_input_mode, 0, 0, 0,
-  "Return information about the way Emacs currently reads keyboard input.\n\
-The value is a list of the form (INTERRUPT FLOW META QUIT), where\n\
-  INTERRUPT is non-nil if Emacs is using interrupt-driven input; if\n\
-    nil, Emacs is using CBREAK mode.\n\
-  FLOW is non-nil if Emacs uses ^S/^Q flow control for output to the\n\
-    terminal; this does not apply if Emacs uses interrupt-driven input.\n\
-  META is t if accepting 8-bit input with 8th bit as Meta flag.\n\
-    META nil means ignoring the top bit, on the assumption it is parity.\n\
-    META is neither t nor nil if accepting 8-bit input and using\n\
-    all 8 bits as the character code.\n\
-  QUIT is the character Emacs currently uses to quit.\n\
-The elements of this list correspond to the arguments of\n\
-`set-input-mode'.")
-  ()
+       doc: /* Return information about the way Emacs currently reads keyboard input.
+The value is a list of the form (INTERRUPT FLOW META QUIT), where
+  INTERRUPT is non-nil if Emacs is using interrupt-driven input; if
+    nil, Emacs is using CBREAK mode.
+  FLOW is non-nil if Emacs uses ^S/^Q flow control for output to the
+    terminal; this does not apply if Emacs uses interrupt-driven input.
+  META is t if accepting 8-bit input with 8th bit as Meta flag.
+    META nil means ignoring the top bit, on the assumption it is parity.
+    META is neither t nor nil if accepting 8-bit input and using
+    all 8 bits as the character code.
+  QUIT is the character Emacs currently uses to quit.
+The elements of this list correspond to the arguments of
+`set-input-mode'.  */)
+     ()
 {
   Lisp_Object val[4];
 
@@ -9576,19 +10108,35 @@ wipe_kboard (kb)
 }
 
 #ifdef MULTI_KBOARD
+
+/* Free KB and memory referenced from it.  */
+
 void
 delete_kboard (kb)
-  KBOARD *kb;
+     KBOARD *kb;
 {
   KBOARD **kbp;
+  
   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);
 }
-#endif
+
+#endif /* MULTI_KBOARD */
 
 void
 init_keyboard ()
@@ -9604,8 +10152,7 @@ init_keyboard ()
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  kbd_buffer_frame_or_window
-    = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
+  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
 #ifdef HAVE_MOUSE
   do_mouse_tracking = Qnil;
 #endif
@@ -9622,11 +10169,6 @@ init_keyboard ()
   wipe_kboard (current_kboard);
   init_kboard (current_kboard);
 
-  if (initialized)
-    Ffillarray (kbd_buffer_frame_or_window, Qnil);
-
-  kbd_buffer_frame_or_window
-    = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
   if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
     {
       signal (SIGINT, interrupt_signal);
@@ -9688,9 +10230,12 @@ struct event_head head_table[] = {
 void
 syms_of_keyboard ()
 {
+  Vpre_help_message = Qnil;
+  staticpro (&Vpre_help_message);
+  
   Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
-  
+
   /* Tool-bars.  */
   QCimage = intern (":image");
   staticpro (&QCimage);
@@ -9842,6 +10387,8 @@ syms_of_keyboard ()
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
 
+  last_point_position_buffer = Qnil;
+
   {
     struct event_head *p;
 
@@ -9885,9 +10432,8 @@ syms_of_keyboard ()
   Fset (Qextended_command_history, Qnil);
   staticpro (&Qextended_command_history);
 
-  kbd_buffer_frame_or_window
-    = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
-  staticpro (&kbd_buffer_frame_or_window);
+  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
+  staticpro (&kbd_buffer_gcpro);
 
   accent_key_syms = Qnil;
   staticpro (&accent_key_syms);
@@ -9943,359 +10489,378 @@ syms_of_keyboard ()
   defsubr (&Sexecute_extended_command);
 
   DEFVAR_LISP ("last-command-char", &last_command_char,
-    "Last input event that was part of a command.");
+              doc: /* Last input event that was part of a command.  */);
 
   DEFVAR_LISP_NOPRO ("last-command-event", &last_command_char,
-    "Last input event that was part of a command.");
+                    doc: /* Last input event that was part of a command.  */);
 
   DEFVAR_LISP ("last-nonmenu-event", &last_nonmenu_event,
-    "Last input event in a command, except for mouse menu events.\n\
-Mouse menus give back keys that don't look like mouse events;\n\
-this variable holds the actual mouse event that led to the menu,\n\
-so that you can determine whether the command was run by mouse or not.");
+              doc: /* Last input event in a command, except for mouse menu events.
+Mouse menus give back keys that don't look like mouse events;
+this variable holds the actual mouse event that led to the menu,
+so that you can determine whether the command was run by mouse or not.  */);
 
   DEFVAR_LISP ("last-input-char", &last_input_char,
-    "Last input event.");
+              doc: /* Last input event.  */);
 
   DEFVAR_LISP_NOPRO ("last-input-event", &last_input_char,
-    "Last input event.");
+                    doc: /* Last input event.  */);
 
   DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
-    "List of events to be read as the command input.\n\
-These events are processed first, before actual keyboard input.");
+              doc: /* List of events to be read as the command input.
+These events are processed first, before actual keyboard input.  */);
   Vunread_command_events = Qnil;
 
   DEFVAR_INT ("unread-command-char", &unread_command_char,
-    "If not -1, an object to be read as next command input event.");
+             doc: /* If not -1, an object to be read as next command input event.  */);
 
   DEFVAR_LISP ("unread-post-input-method-events", &Vunread_post_input_method_events,
-    "List of events to be processed as input by input methods.\n\
-These events are processed after `unread-command-events', but\n\
-before actual keyboard input.");
+              doc: /* List of events to be processed as input by input methods.
+These events are processed after `unread-command-events', but
+before actual keyboard input.  */);
   Vunread_post_input_method_events = Qnil;
 
   DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,
-    "List of events to be processed as input by input methods.\n\
-These events are processed after `unread-command-events', but\n\
-before actual keyboard input.");
+              doc: /* List of events to be processed as input by input methods.
+These events are processed after `unread-command-events', but
+before actual keyboard input.  */);
   Vunread_input_method_events = Qnil;
 
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
-    "Meta-prefix character code.\n\
-Meta-foo as command input turns into this character followed by foo.");
+              doc: /* Meta-prefix character code.
+Meta-foo as command input turns into this character followed by foo.  */);
   XSETINT (meta_prefix_char, 033);
 
   DEFVAR_KBOARD ("last-command", Vlast_command,
-    "The last command executed.\n\
-Normally a symbol with a function definition, but can be whatever was found\n\
-in the keymap, or whatever the variable `this-command' was set to by that\n\
-command.\n\
-\n\
-The value `mode-exit' is special; it means that the previous command\n\
-read an event that told it to exit, and it did so and unread that event.\n\
-In other words, the present command is the event that made the previous\n\
-command exit.\n\
-\n\
-The value `kill-region' is special; it means that the previous command\n\
-was a kill command.");
+                doc: /* The last command executed.
+Normally a symbol with a function definition, but can be whatever was found
+in the keymap, or whatever the variable `this-command' was set to by that
+command.
+
+The value `mode-exit' is special; it means that the previous command
+read an event that told it to exit, and it did so and unread that event.
+In other words, the present command is the event that made the previous
+command exit.
+
+The value `kill-region' is special; it means that the previous command
+was a kill command.  */);
 
   DEFVAR_KBOARD ("real-last-command", Vreal_last_command,
-    "Same as `last-command', but never altered by Lisp code.");
+                doc: /* Same as `last-command', but never altered by Lisp code.  */);
 
   DEFVAR_LISP ("this-command", &Vthis_command,
-    "The command now being executed.\n\
-The command can set this variable; whatever is put here\n\
-will be in `last-command' during the following command.");
+              doc: /* The command now being executed.
+The command can set this variable; whatever is put here
+will be in `last-command' during the following command.  */);
   Vthis_command = Qnil;
 
   DEFVAR_INT ("auto-save-interval", &auto_save_interval,
-    "*Number of input events between auto-saves.\n\
-Zero means disable autosaving due to number of characters typed.");
+             doc: /* *Number of input events between auto-saves.
+Zero means disable autosaving due to number of characters typed.  */);
   auto_save_interval = 300;
 
   DEFVAR_LISP ("auto-save-timeout", &Vauto_save_timeout,
-    "*Number of seconds idle time before auto-save.\n\
-Zero or nil means disable auto-saving due to idleness.\n\
-After auto-saving due to this many seconds of idle time,\n\
-Emacs also does a garbage collection if that seems to be warranted.");
+              doc: /* *Number of seconds idle time before auto-save.
+Zero or nil means disable auto-saving due to idleness.
+After auto-saving due to this many seconds of idle time,
+Emacs also does a garbage collection if that seems to be warranted.  */);
   XSETFASTINT (Vauto_save_timeout, 30);
 
   DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes,
-    "*Nonzero means echo unfinished commands after this many seconds of pause.\n\
-The value may be integer or floating point.");
+              doc: /* *Nonzero means echo unfinished commands after this many seconds of pause.
+The value may be integer or floating point.  */);
   Vecho_keystrokes = make_number (1);
 
   DEFVAR_INT ("polling-period", &polling_period,
-    "*Interval between polling for input during Lisp execution.\n\
-The reason for polling is to make C-g work to stop a running program.\n\
-Polling is needed only when using X windows and SIGIO does not work.\n\
-Polling is automatically disabled in all other cases.");
+             doc: /* *Interval between polling for input during Lisp execution.
+The reason for polling is to make C-g work to stop a running program.
+Polling is needed only when using X windows and SIGIO does not work.
+Polling is automatically disabled in all other cases.  */);
   polling_period = 2;
 
   DEFVAR_LISP ("double-click-time", &Vdouble_click_time,
-    "*Maximum time between mouse clicks to make a double-click.\n\
-Measured in milliseconds.  nil means disable double-click recognition;\n\
-t means double-clicks have no time limit and are detected\n\
-by position only.");
+              doc: /* *Maximum time between mouse clicks to make a double-click.
+Measured in milliseconds.  nil means disable double-click recognition;
+t means double-clicks have no time limit and are detected
+by position only.  */);
   Vdouble_click_time = make_number (500);
 
+  DEFVAR_INT ("double-click-fuzz", &double_click_fuzz,
+             doc: /* *Maximum mouse movement between clicks to make a double-click.
+On window-system frames, value is the number of pixels the mouse may have
+moved horizontally or vertically between two clicks to make a double-click.
+On non window-system frames, value is interpreted in units of 1/8 characters
+instead of pixels.  */);
+  double_click_fuzz = 3;
+  
   DEFVAR_BOOL ("inhibit-local-menu-bar-menus", &inhibit_local_menu_bar_menus,
-    "*Non-nil means inhibit local map menu bar menus.");
+              doc: /* *Non-nil means inhibit local map menu bar menus.  */);
   inhibit_local_menu_bar_menus = 0;
 
   DEFVAR_INT ("num-input-keys", &num_input_keys,
-    "Number of complete key sequences read as input so far.\n\
-This includes key sequences read from keyboard macros.\n\
-The number is effectively the number of interactive command invocations.");
+             doc: /* Number of complete key sequences read as input so far.
+This includes key sequences read from keyboard macros.
+The number is effectively the number of interactive command invocations.  */);
   num_input_keys = 0;
 
   DEFVAR_INT ("num-nonmacro-input-events", &num_nonmacro_input_events,
-    "Number of input events read from the keyboard so far.\n\
-This does not include events generated by keyboard macros.");
+             doc: /* Number of input events read from the keyboard so far.
+This does not include events generated by keyboard macros.  */);
   num_nonmacro_input_events = 0;
 
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
-    "The frame in which the most recently read event occurred.\n\
-If the last event came from a keyboard macro, this is set to `macro'.");
+              doc: /* The frame in which the most recently read event occurred.
+If the last event came from a keyboard macro, this is set to `macro'.  */);
   Vlast_event_frame = Qnil;
 
   /* This variable is set up in sysdep.c.  */
   DEFVAR_LISP ("tty-erase-char", &Vtty_erase_char,
-    "The ERASE character as set by the user with stty.");
+              doc: /* The ERASE character as set by the user with stty.  */);
 
   DEFVAR_LISP ("help-char", &Vhelp_char,
-    "Character to recognize as meaning Help.\n\
-When it is read, do `(eval help-form)', and display result if it's a string.\n\
-If the value of `help-form' is nil, this char can be read normally.");
+              doc: /* Character to recognize as meaning Help.
+When it is read, do `(eval help-form)', and display result if it's a string.
+If the value of `help-form' is nil, this char can be read normally.  */);
   XSETINT (Vhelp_char, Ctl ('H'));
 
   DEFVAR_LISP ("help-event-list", &Vhelp_event_list,
-    "List of input events to recognize as meaning Help.\n\
-These work just like the value of `help-char' (see that).");
+              doc: /* List of input events to recognize as meaning Help.
+These work just like the value of `help-char' (see that).  */);
   Vhelp_event_list = Qnil;
 
   DEFVAR_LISP ("help-form", &Vhelp_form,
-    "Form to execute when character `help-char' is read.\n\
-If the form returns a string, that string is displayed.\n\
-If `help-form' is nil, the help char is not recognized.");
+              doc: /* Form to execute when character `help-char' is read.
+If the form returns a string, that string is displayed.
+If `help-form' is nil, the help char is not recognized.  */);
   Vhelp_form = Qnil;
 
   DEFVAR_LISP ("prefix-help-command", &Vprefix_help_command,
-    "Command to run when `help-char' character follows a prefix key.\n\
-This command is used only when there is no actual binding\n\
-for that character after that prefix key.");
+              doc: /* Command to run when `help-char' character follows a prefix key.
+This command is used only when there is no actual binding
+for that character after that prefix key.  */);
   Vprefix_help_command = Qnil;
 
   DEFVAR_LISP ("top-level", &Vtop_level,
-    "Form to evaluate when Emacs starts up.\n\
-Useful to set before you dump a modified Emacs.");
+              doc: /* Form to evaluate when Emacs starts up.
+Useful to set before you dump a modified Emacs.  */);
   Vtop_level = Qnil;
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
-    "Translate table for keyboard input, or nil.\n\
-Each character is looked up in this string and the contents used instead.\n\
-The value may be a string, a vector, or a char-table.\n\
-If it is a string or vector of length N,\n\
-character codes N and up are untranslated.\n\
-In a vector or a char-table, an element which is nil means \"no translation\".");
+              doc: /* Translate table for keyboard input, or nil.
+Each character is looked up in this string and the contents used instead.
+The value may be a string, a vector, or a char-table.
+If it is a string or vector of length N,
+character codes N and up are untranslated.
+In a vector or a char-table, an element which is nil means "no translation".  */);
   Vkeyboard_translate_table = Qnil;
 
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
-    "Non-nil means to always spawn a subshell instead of suspending.\n\
-\(Even if the operating system has support for stopping a process.\)");
+              doc: /* Non-nil means to always spawn a subshell instead of suspending.
+\(Even if the operating system has support for stopping a process.\)  */);
   cannot_suspend = 0;
 
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
-    "Non-nil means prompt with menus when appropriate.\n\
-This is done when reading from a keymap that has a prompt string,\n\
-for elements that have prompt strings.\n\
-The menu is displayed on the screen\n\
-if X menus were enabled at configuration\n\
-time and the previous event was a mouse click prefix key.\n\
-Otherwise, menu prompting uses the echo area.");
+              doc: /* Non-nil means prompt with menus when appropriate.
+This is done when reading from a keymap that has a prompt string,
+for elements that have prompt strings.
+The menu is displayed on the screen
+if X menus were enabled at configuration
+time and the previous event was a mouse click prefix key.
+Otherwise, menu prompting uses the echo area.  */);
   menu_prompting = 1;
 
   DEFVAR_LISP ("menu-prompt-more-char", &menu_prompt_more_char,
-    "Character to see next line of menu prompt.\n\
-Type this character while in a menu prompt to rotate around the lines of it.");
+              doc: /* Character to see next line of menu prompt.
+Type this character while in a menu prompt to rotate around the lines of it.  */);
   XSETINT (menu_prompt_more_char, ' ');
 
   DEFVAR_INT ("extra-keyboard-modifiers", &extra_keyboard_modifiers,
-    "A mask of additional modifier keys to use with every keyboard character.\n\
-Emacs applies the modifiers of the character stored here to each keyboard\n\
-character it reads.  For example, after evaluating the expression\n\
-    (setq extra-keyboard-modifiers ?\\C-x)\n\
-all input characters will have the control modifier applied to them.\n\
-\n\
-Note that the character ?\\C-@, equivalent to the integer zero, does\n\
-not count as a control character; rather, it counts as a character\n\
-with no modifiers; thus, setting `extra-keyboard-modifiers' to zero\n\
-cancels any modification.");
+             doc: /* A mask of additional modifier keys to use with every keyboard character.
+Emacs applies the modifiers of the character stored here to each keyboard
+character it reads.  For example, after evaluating the expression
+    (setq extra-keyboard-modifiers ?\\C-x)
+all input characters will have the control modifier applied to them.
+
+Note that the character ?\\C-@, equivalent to the integer zero, does
+not count as a control character; rather, it counts as a character
+with no modifiers; thus, setting `extra-keyboard-modifiers' to zero
+cancels any modification.  */);
   extra_keyboard_modifiers = 0;
 
   DEFVAR_LISP ("deactivate-mark", &Vdeactivate_mark,
-    "If an editing command sets this to t, deactivate the mark afterward.\n\
-The command loop sets this to nil before each command,\n\
-and tests the value when the command returns.\n\
-Buffer modification stores t in this variable.");
+              doc: /* If an editing command sets this to t, deactivate the mark afterward.
+The command loop sets this to nil before each command,
+and tests the value when the command returns.
+Buffer modification stores t in this variable.  */);
   Vdeactivate_mark = Qnil;
 
   DEFVAR_LISP ("command-hook-internal", &Vcommand_hook_internal,
-    "Temporary storage of pre-command-hook or post-command-hook.");
+              doc: /* Temporary storage of pre-command-hook or post-command-hook.  */);
   Vcommand_hook_internal = Qnil;
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
-    "Normal hook run before each command is executed.\n\
-If an unhandled error happens in running this hook,\n\
-the hook value is set to nil, since otherwise the error\n\
-might happen repeatedly and make Emacs nonfunctional.");
+              doc: /* Normal hook run before each command is executed.
+If an unhandled error happens in running this hook,
+the hook value is set to nil, since otherwise the error
+might happen repeatedly and make Emacs nonfunctional.  */);
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
-    "Normal hook run after each command is executed.\n\
-If an unhandled error happens in running this hook,\n\
-the hook value is set to nil, since otherwise the error\n\
-might happen repeatedly and make Emacs nonfunctional.");
+              doc: /* Normal hook run after each command is executed.
+If an unhandled error happens in running this hook,
+the hook value is set to nil, since otherwise the error
+might happen repeatedly and make Emacs nonfunctional.  */);
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
-    "Normal hook run after each command is executed, if idle.\n\
-Errors running the hook are caught and ignored.\n\
-This feature is obsolete; use idle timers instead.  See `etc/NEWS'.");
+              doc: /* Normal hook run after each command is executed, if idle.
+Errors running the hook are caught and ignored.
+This feature is obsolete; use idle timers instead.  See `etc/NEWS'.  */);
   Vpost_command_idle_hook = Qnil;
 
   DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
-    "Delay time before running `post-command-idle-hook'.\n\
-This is measured in microseconds.");
+             doc: /* Delay time before running `post-command-idle-hook'.
+This is measured in microseconds.  */);
   post_command_idle_delay = 100000;
 
 #if 0
   DEFVAR_LISP ("echo-area-clear-hook", ...,
-    "Normal hook run when clearing the echo area.");
+              doc: /* Normal hook run when clearing the echo area.  */);
 #endif
   Qecho_area_clear_hook = intern ("echo-area-clear-hook");
-  XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+  SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
-    "t means menu bar, specified Lucid style, needs to be recomputed.");
+              doc: /* Non-nil means menu bar, specified Lucid style, needs to be recomputed.  */);
   Vlucid_menu_bar_dirty_flag = Qnil;
 
   DEFVAR_LISP ("menu-bar-final-items", &Vmenu_bar_final_items,
-    "List of menu bar items to move to the end of the menu bar.\n\
-The elements of the list are event types that may have menu bar bindings.");
+              doc: /* List of menu bar items to move to the end of the menu bar.
+The elements of the list are event types that may have menu bar bindings.  */);
   Vmenu_bar_final_items = Qnil;
 
   DEFVAR_KBOARD ("overriding-terminal-local-map",
                 Voverriding_terminal_local_map,
-    "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\
-set up a different keymap for reading the next command.");
+                doc: /* Per-terminal keymap that overrides all other local keymaps.
+If this variable is non-nil, it is used as a keymap instead of the
+buffer's local map, and the minor mode keymaps and text property keymaps.
+This variable is intended to let commands such as `universal-argument'
+set up a different keymap for reading the next command.  */);
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
-    "Keymap that overrides all other local keymaps.\n\
-If this variable is non-nil, it is used as a keymap instead of the\n\
-buffer's local map, and the minor mode keymaps and text property keymaps.");
+              doc: /* Keymap that overrides all other local keymaps.
+If this variable is non-nil, it is used as a keymap instead of the
+buffer's local map, and the minor mode keymaps and text property keymaps.  */);
   Voverriding_local_map = Qnil;
 
   DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
-    "Non-nil means `overriding-local-map' applies to the menu bar.\n\
-Otherwise, the menu bar continues to reflect the buffer's local map\n\
-and the minor mode maps regardless of `overriding-local-map'.");
+              doc: /* Non-nil means `overriding-local-map' applies to the menu bar.
+Otherwise, the menu bar continues to reflect the buffer's local map
+and the minor mode maps regardless of `overriding-local-map'.  */);
   Voverriding_local_map_menu_flag = Qnil;
 
   DEFVAR_LISP ("special-event-map", &Vspecial_event_map,
-    "Keymap defining bindings for special events to execute at low level.");
+              doc: /* Keymap defining bindings for special events to execute at low level.  */);
   Vspecial_event_map = Fcons (intern ("keymap"), Qnil);
 
   DEFVAR_LISP ("track-mouse", &do_mouse_tracking,
-    "*Non-nil means generate motion events for mouse motion.");
+              doc: /* *Non-nil means generate motion events for mouse motion.  */);
 
   DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist,
-    "Alist of system-specific X windows key symbols.\n\
-Each element should have the form (N . SYMBOL) where N is the\n\
-numeric keysym code (sans the \"system-specific\" bit 1<<28)\n\
-and SYMBOL is its name.");
+                doc: /* Alist of system-specific X windows key symbols.
+Each element should have the form (N . SYMBOL) where N is the
+numeric keysym code (sans the \"system-specific\" bit 1<<28)
+and SYMBOL is its name.  */);
 
   DEFVAR_LISP ("deferred-action-list", &Vdeferred_action_list,
-    "List of deferred actions to be performed at a later time.\n\
-The precise format isn't relevant here; we just check whether it is nil.");
+              doc: /* List of deferred actions to be performed at a later time.
+The precise format isn't relevant here; we just check whether it is nil.  */);
   Vdeferred_action_list = Qnil;
 
   DEFVAR_LISP ("deferred-action-function", &Vdeferred_action_function,
-    "Function to call to handle deferred actions, after each command.\n\
-This function is called with no arguments after each command\n\
-whenever `deferred-action-list' is non-nil.");
+              doc: /* Function to call to handle deferred actions, after each command.
+This function is called with no arguments after each command
+whenever `deferred-action-list' is non-nil.  */);
   Vdeferred_action_function = Qnil;
 
   DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
-    "*Non-nil means show the equivalent key-binding when M-x command has one.\n\
-The value can be a length of time to show the message for.\n\
-If the value is non-nil and not a number, we wait 2 seconds.");
+              doc: /* *Non-nil means show the equivalent key-binding when M-x command has one.
+The value can be a length of time to show the message for.
+If the value is non-nil and not a number, we wait 2 seconds.  */);
   Vsuggest_key_bindings = Qt;
 
   DEFVAR_LISP ("timer-list", &Vtimer_list,
-    "List of active absolute time timers in order of increasing time");
+              doc: /* List of active absolute time timers in order of increasing time.  */);
   Vtimer_list = Qnil;
 
   DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
-    "List of active idle-time timers in order of increasing time");
+              doc: /* List of active idle-time timers in order of increasing time.  */);
   Vtimer_idle_list = Qnil;
 
   DEFVAR_LISP ("input-method-function", &Vinput_method_function,
-    "If non-nil, the function that implements the current input method.\n\
-It's called with one argument, a printing character that was just read.\n\
-\(That means a character with code 040...0176.)\n\
-Typically this function uses `read-event' to read additional events.\n\
-When it does so, it should first bind `input-method-function' to nil\n\
-so it will not be called recursively.\n\
-\n\
-The function should return a list of zero or more events\n\
-to be used as input.  If it wants to put back some events\n\
-to be reconsidered, separately, by the input method,\n\
-it can add them to the beginning of `unread-command-events'.\n\
-\n\
-The input method function can find in `input-method-previous-method'\n\
-the previous echo area message.\n\
-\n\
-The input method function should refer to the variables\n\
-`input-method-use-echo-area' and `input-method-exit-on-first-char'\n\
-for guidance on what to do.");
+              doc: /* If non-nil, the function that implements the current input method.
+It's called with one argument, a printing character that was just read.
+\(That means a character with code 040...0176.)
+Typically this function uses `read-event' to read additional events.
+When it does so, it should first bind `input-method-function' to nil
+so it will not be called recursively.
+
+The function should return a list of zero or more events
+to be used as input.  If it wants to put back some events
+to be reconsidered, separately, by the input method,
+it can add them to the beginning of `unread-command-events'.
+
+The input method function can find in `input-method-previous-method'
+the previous echo area message.
+
+The input method function should refer to the variables
+`input-method-use-echo-area' and `input-method-exit-on-first-char'
+for guidance on what to do.  */);
   Vinput_method_function = Qnil;
 
   DEFVAR_LISP ("input-method-previous-message",
               &Vinput_method_previous_message,
-    "When `input-method-function' is called, hold the previous echo area message.\n\
-This variable exists because `read-event' clears the echo area\n\
-before running the input method.  It is nil if there was no message.");
+              doc: /* When `input-method-function' is called, hold the previous echo area message.
+This variable exists because `read-event' clears the echo area
+before running the input method.  It is nil if there was no message.  */);
   Vinput_method_previous_message = Qnil;
 
   DEFVAR_LISP ("show-help-function", &Vshow_help_function,
-    "If non-nil, the function that implements the display of help.\n\
-It's called with one argument, the help string to display.");
+              doc: /* If non-nil, the function that implements the display of help.
+It's called with one argument, the help string to display.  */);
   Vshow_help_function = Qnil;
 
   DEFVAR_LISP ("disable-point-adjustment", &Vdisable_point_adjustment,
-    "If non-nil, suppress point adjustment after executing a command.\n\
-\n\
-After a command is executed, if point is moved into a region that has\n\
-special properties (e.g. composition, display), we adjust point to\n\
-the boundary of the region.  But, several special commands sets this\n\
-variable to non-nil, then we suppress the point adjustment.\n\
-\n\
-This variable is set to nil before reading a command, and is checked\n\
-just after executing the command");
+              doc: /* If non-nil, suppress point adjustment after executing a command.
+
+After a command is executed, if point is moved into a region that has
+special properties (e.g. composition, display), we adjust point to
+the boundary of the region.  But, several special commands sets this
+variable to non-nil, then we suppress the point adjustment.
+
+This variable is set to nil before reading a command, and is checked
+just after executing the command.  */);
   Vdisable_point_adjustment = Qnil;
 
   DEFVAR_LISP ("global-disable-point-adjustment",
               &Vglobal_disable_point_adjustment,
-    "*If non-nil, always suppress point adjustment.\n\
-\n\
-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.");
+              doc: /* *If non-nil, always suppress point adjustment.
+
+The default value is nil, in which case, point adjustment are
+suppressed only after special commands that set
+`disable-point-adjustment' (which see) to non-nil.  */);
   Vglobal_disable_point_adjustment = Qnil;
+
+  DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings,
+              doc: /* Non-nil means updating menu bindings is allowed.
+A value of nil means menu bindings should not be updated.
+Used during Emacs' startup.  */);
+  update_menu_bindings = 1;
+
+  DEFVAR_LISP ("minibuffer-message-timeout", &Vminibuffer_message_timeout,
+              doc: /* *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.  */);
+  Vminibuffer_message_timeout = make_number (2);
 }
 
 void