]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(Version, mh-version): Update for release 8.0.
[gnu-emacs] / src / keyboard.c
index 6006d9276ac35e0c8c579b9e77707deaacec6f29..30b06ef38fcc9e0b2ad878418eaa0415ee42007d 100644 (file)
@@ -1,6 +1,7 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 01, 02
-     Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
+                 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include <signal.h>
@@ -45,6 +46,9 @@ Boston, MA 02111-1307, USA.  */
 #include <setjmp.h>
 #include <errno.h>
 
+#ifdef HAVE_GTK_AND_PTHREAD
+#include <pthread.h>
+#endif
 #ifdef MSDOS
 #include "msdos.h"
 #include <time.h>
@@ -62,6 +66,10 @@ Boston, MA 02111-1307, USA.  */
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
 /* This is to get the definitions of the XK_ symbols.  */
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -117,6 +125,8 @@ struct backtrace
                           args points to slot holding list of
                           unevalled args */
     char evalargs;
+    /* Nonzero means call value of debugger when done with this operation. */
+    char debug_on_exit;
   };
 
 #ifdef MULTI_KBOARD
@@ -129,8 +139,8 @@ KBOARD the_only_kboard;
 #endif
 
 /* Non-nil disable property on a command means
-   do not execute it; call disabled-command-hook's value instead.  */
-Lisp_Object Qdisabled, Qdisabled_command_hook;
+   do not execute it; call disabled-command-function's value instead.  */
+Lisp_Object Qdisabled, Qdisabled_command_function;
 
 #define NUM_RECENT_KEYS (100)
 int recent_keys_index; /* Index for storing next element into recent_keys */
@@ -145,6 +155,10 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* 1 after calling Freset_this_command_lengths.
+   Usually it is 0.  */
+int this_command_key_count_reset;
+
 /* This vector is used as a buffer to record the events that were actually read
    by read_key_sequence.  */
 Lisp_Object raw_keybuf;
@@ -169,13 +183,6 @@ int this_single_command_key_start;
    before this command was read.  */
 static int before_command_key_count;
 static int before_command_echo_length;
-/* Values of before_command_key_count and before_command_echo_length
-   saved by reset-this-command-lengths.  */
-static int before_command_key_count_1;
-static int before_command_echo_length_1;
-/* Flag set by reset-this-command-lengths,
-   saying to reset the lengths when add_command_key is called.  */
-static int before_command_restore_flag;
 
 extern int minbuf_level;
 
@@ -374,12 +381,15 @@ Lisp_Object real_this_command;
    command is stored in this-original-command.  It is nil otherwise.  */
 Lisp_Object Vthis_original_command;
 
-/* The value of point when the last command was executed.  */
+/* The value of point when the last command was started.  */
 int last_point_position;
 
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
+/* The window that was selected when the last command was started.  */
+Lisp_Object last_point_position_window;
+
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
@@ -412,7 +422,7 @@ Lisp_Object Vecho_keystrokes;
 /* Form to evaluate (if non-nil) when Emacs is started.  */
 Lisp_Object Vtop_level;
 
-/* User-supplied string to translate input characters through.  */
+/* User-supplied table to translate input characters.  */
 Lisp_Object Vkeyboard_translate_table;
 
 /* Keymap mapping ASCII function key sequences onto their preferred forms.  */
@@ -444,11 +454,6 @@ Lisp_Object Qecho_area_clear_hook;
 Lisp_Object Qpre_command_hook, Vpre_command_hook;
 Lisp_Object Qpost_command_hook, Vpost_command_hook;
 Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
-/* Hook run after a command if there's no more input soon.  */
-Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
-
-/* Delay time in microseconds before running post-command-idle-hook.  */
-EMACS_INT post_command_idle_delay;
 
 /* 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.  */
@@ -472,46 +477,12 @@ 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 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,
-   internal_last_event_frame or the event itself points to the frame.
-   So that's all fine.
-
-   But while the event is sitting in the queue, it's completely
-   unprotected.  Suppose the user types one command which will run for
-   a while and then delete a frame, and then types another event at
-   the frame that will be deleted, before the command gets around to
-   it.  Suppose there are no references to this frame elsewhere in
-   Emacs, and a GC occurs before the second event is dequeued.  Now we
-   have an event referring to a freed frame, which will crash Emacs
-   when it is dequeued.
-
-   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 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
-
-   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.
    This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the
@@ -547,15 +518,21 @@ Lisp_Object Qmake_frame_visible;
 Lisp_Object Qselect_window;
 Lisp_Object Qhelp_echo;
 
+#ifdef HAVE_MOUSE
+Lisp_Object Qmouse_fixup_help_message;
+#endif
+
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-#ifdef WINDOWSNT
-Lisp_Object Qmouse_wheel;
+#if defined (WINDOWSNT) || defined (MAC_OS)
 Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
 Lisp_Object Qsave_session;
+#ifdef MAC_OS
+Lisp_Object Qmac_apple_event;
+#endif
 
 /* Lisp_Object Qmouse_movement; - also an event header */
 
@@ -590,17 +567,20 @@ Lisp_Object Qvertical_line;
 Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 extern Lisp_Object Qleft_margin, Qright_margin;
+extern Lisp_Object Qleft_fringe, Qright_fringe;
+extern Lisp_Object QCmap;
 
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
 EMACS_TIME timer_check ();
 
-extern Lisp_Object Vhistory_length;
+extern Lisp_Object Vhistory_length, Vtranslation_table_for_input;
 
 extern char *x_get_keysym_name ();
 
 static void record_menu_key ();
+static int echo_length ();
 
 Lisp_Object Qpolling_period;
 
@@ -636,7 +616,7 @@ int flow_control;
 
 /* We are unable to use interrupts if FIONREAD is not available,
    so flush SIGIO so we won't try.  */
-#ifndef FIONREAD
+#if !defined (FIONREAD)
 #ifdef SIGIO
 #undef SIGIO
 #endif
@@ -644,7 +624,7 @@ int flow_control;
 
 /* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
-#ifdef HAVE_WINDOW_SYSTEM
+#if defined(HAVE_WINDOW_SYSTEM) && !defined(USE_ASYNC_EVENTS)
 #define POLL_FOR_INPUT
 #endif
 
@@ -669,17 +649,25 @@ static EMACS_TIME timer_idleness_start_time;
 
 static EMACS_TIME timer_last_idleness_start_time;
 
+/* If non-nil, events produced by disabled menu items and tool-bar
+   buttons are not ignored.  Help functions bind this to allow help on
+   those items and buttons.  */
+Lisp_Object Venable_disabled_menus_and_buttons;
+
 \f
 /* Global variable declarations.  */
 
+/* Flags for readable_events.  */
+#define READABLE_EVENTS_DO_TIMERS_NOW          (1 << 0)
+#define READABLE_EVENTS_FILTER_EVENTS          (1 << 1)
+#define READABLE_EVENTS_IGNORE_SQUEEZABLES     (1 << 2)
+
 /* Function for init_keyboard to call with no args (if nonzero).  */
 void (*keyboard_init_hook) ();
 
 static int read_avail_input P_ ((int));
 static void get_input_pending P_ ((int *, int));
-static void get_filtered_input_pending P_ ((int *, int, int));
 static int readable_events P_ ((int));
-static int readable_filtered_events P_ ((int, int));
 static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
                                                Lisp_Object, int *));
 static Lisp_Object read_char_x_menu_prompt ();
@@ -704,11 +692,17 @@ 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));
+static SIGTYPE interrupt_signal P_ ((int signalnum));
+static void timer_start_idle P_ ((void));
+static void timer_stop_idle P_ ((void));
+static void timer_resume_idle P_ ((void));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
 
+extern Lisp_Object Qidentity, Qonly;
+\f
 /* 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.  */
@@ -738,7 +732,7 @@ echo_char (c)
       Lisp_Object echo_string;
 
       echo_string = current_kboard->echo_string;
-      
+
       /* If someone has passed us a composite event, use its head symbol.  */
       c = EVENT_HEAD (c);
 
@@ -748,9 +742,9 @@ echo_char (c)
        }
       else if (SYMBOLP (c))
        {
-         struct Lisp_String *name = XSTRING (SYMBOL_NAME (c));
-         int nbytes = STRING_BYTES (name);
-         
+         Lisp_Object name = SYMBOL_NAME (c);
+         int nbytes = SBYTES (name);
+
          if (size - (ptr - buffer) < nbytes)
            {
              int offset = ptr - buffer;
@@ -759,8 +753,8 @@ echo_char (c)
              ptr = buffer + offset;
            }
 
-         ptr += copy_text (name->data, ptr, nbytes,
-                           name->size_byte >= 0, 1);
+         ptr += copy_text (SDATA (name), ptr, nbytes,
+                           STRING_MULTIBYTE (name), 1);
        }
 
       if ((NILP (echo_string) || SCHARS (echo_string) == 0)
@@ -768,7 +762,7 @@ echo_char (c)
        {
          const char *text = " (Type ? for further options)";
          int len = strlen (text);
-         
+
          if (size - (ptr - buffer) < len)
            {
              int offset = ptr - buffer;
@@ -784,18 +778,25 @@ echo_char (c)
       /* Replace a dash from echo_dash with a space, otherwise
         add a space at the end as a separator between keys.  */
       if (STRINGP (echo_string)
-         && SCHARS (echo_string) > 0)
+         && SCHARS (echo_string) > 1)
        {
-         Lisp_Object last_char, idx;
+         Lisp_Object last_char, prev_char, idx;
+
+         idx = make_number (SCHARS (echo_string) - 2);
+         prev_char = Faref (echo_string, idx);
 
          idx = make_number (SCHARS (echo_string) - 1);
          last_char = Faref (echo_string, idx);
 
-         if (XINT (last_char) == '-')
+         /* We test PREV_CHAR to make sure this isn't the echoing
+            of a minus-sign.  */
+         if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
            Faset (echo_string, idx, make_number (' '));
          else
            echo_string = concat2 (echo_string, build_string (" "));
        }
+      else if (STRINGP (echo_string))
+       echo_string = concat2 (echo_string, build_string (" "));
 
       current_kboard->echo_string
        = concat2 (echo_string, make_string (buffer, ptr - buffer));
@@ -817,12 +818,27 @@ echo_dash ()
   if (!current_kboard->immediate_echo
       && SCHARS (current_kboard->echo_string) == 0)
     return;
-      
+
   /* Do nothing if we just printed a prompt.  */
   if (current_kboard->echo_after_prompt
       == SCHARS (current_kboard->echo_string))
     return;
-      
+
+  /* Do nothing if we have already put a dash at the end.  */
+  if (SCHARS (current_kboard->echo_string) > 1)
+    {
+      Lisp_Object last_char, prev_char, idx;
+
+      idx = make_number (SCHARS (current_kboard->echo_string) - 2);
+      prev_char = Faref (current_kboard->echo_string, idx);
+
+      idx = make_number (SCHARS (current_kboard->echo_string) - 1);
+      last_char = Faref (current_kboard->echo_string, idx);
+
+      if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
+       return;
+    }
+
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
   current_kboard->echo_string = concat2 (current_kboard->echo_string,
@@ -844,18 +860,33 @@ echo_now ()
       for (i = 0; i < this_command_key_count; i++)
        {
          Lisp_Object c;
+
+         /* Set before_command_echo_length to the value that would
+            have been saved before the start of this subcommand in
+            command_loop_1, if we had already been echoing then.  */
+         if (i == this_single_command_key_start)
+           before_command_echo_length = echo_length ();
+
          c = XVECTOR (this_command_keys)->contents[i];
          if (! (EVENT_HAS_PARAMETERS (c)
                 && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
            echo_char (c);
        }
+
+      /* Set before_command_echo_length to the value that would
+        have been saved before the start of this subcommand in
+        command_loop_1, if we had already been echoing then.  */
+      if (this_command_key_count == this_single_command_key_start)
+       before_command_echo_length = echo_length ();
+
+      /* Put a dash at the end to invite the user to type more.  */
       echo_dash ();
     }
 
   echoing = 1;
   message3_nolog (current_kboard->echo_string,
                  SBYTES (current_kboard->echo_string),
-                 SMBP (current_kboard->echo_string));
+                 STRING_MULTIBYTE (current_kboard->echo_string));
   echoing = 0;
 
   /* Record in what buffer we echoed, and from which kboard.  */
@@ -910,6 +941,8 @@ static void
 add_command_key (key)
      Lisp_Object key;
 {
+#if 0 /* Not needed after we made Freset_this_command_lengths
+        do the job immediately.  */
   /* 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)
@@ -920,6 +953,7 @@ add_command_key (key)
       echo_truncate (before_command_echo_length_1);
       before_command_restore_flag = 0;
     }
+#endif
 
   if (this_command_key_count >= ASIZE (this_command_keys))
     this_command_keys = larger_vector (this_command_keys,
@@ -996,13 +1030,18 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
        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.
+Alternatively, `(throw 'exit t)' makes this function signal an error.
 This function is called by the editor initialization to begin editing.  */)
      ()
 {
   int count = SPECPDL_INDEX ();
   Lisp_Object buffer;
 
+  /* If we enter while input is blocked, don't lock up here.
+     This may happen through the debugger during redisplay.  */
+  if (INPUT_BLOCKED_P)
+    return Qnil;
+
   command_loop_level++;
   update_mode_lines = 1;
 
@@ -1029,12 +1068,12 @@ recursive_edit_unwind (info)
 {
   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;
@@ -1072,6 +1111,19 @@ single_kboard_state ()
 #endif
 }
 
+/* If we're in single_kboard state for kboard KBOARD,
+   get out of it.  */
+
+void
+not_single_kboard_state (kboard)
+     KBOARD *kboard;
+{
+#ifdef MULTI_KBOARD
+  if (kboard == current_kboard)
+    single_kboard = 0;
+#endif
+}
+
 /* Maintain a stack of kboards, so other parts of Emacs
    can switch temporarily to the kboard of a given frame
    and then revert to the previous status.  */
@@ -1121,21 +1173,26 @@ cmd_error (data)
   Lisp_Object old_level, old_length;
   char macroerror[50];
 
-  if (!NILP (executing_macro))
+#ifdef HAVE_X_WINDOWS
+  if (display_hourglass_p)
+    cancel_hourglass ();
+#endif
+
+  if (!NILP (executing_kbd_macro))
     {
-      if (executing_macro_iterations == 1)
+      if (executing_kbd_macro_iterations == 1)
        sprintf (macroerror, "After 1 kbd macro iteration: ");
       else
        sprintf (macroerror, "After %d kbd macro iterations: ",
-                executing_macro_iterations);
+                executing_kbd_macro_iterations);
     }
   else
     *macroerror = 0;
 
   Vstandard_output = Qt;
   Vstandard_input = Qt;
-  Vexecuting_macro = Qnil;
-  executing_macro = Qnil;
+  Vexecuting_kbd_macro = Qnil;
+  executing_kbd_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
   current_kboard->Vlast_prefix_arg = Qnil;
   cancel_echoing ();
@@ -1153,7 +1210,8 @@ cmd_error (data)
 
   Vinhibit_quit = Qnil;
 #ifdef MULTI_KBOARD
-  any_kboard_state ();
+  if (command_loop_level == 0 && minibuf_level == 0)
+    any_kboard_state ();
 #endif
 
   return make_number (0);
@@ -1197,24 +1255,19 @@ cmd_error_internal (data, context)
   else
     {
       Fdiscard_input ();
+      message_log_maybe_newline ();
       bitch_at_user ();
       stream = Qt;
-
-      /* If we know from where the error was signaled, show it in
-        *Messages*.  */
-      if (!NILP (Vsignaling_function) && SYMBOLP (Vsignaling_function))
-       {
-         char *name = XSTRING (SYMBOL_NAME (Vsignaling_function))->data;
-         message_dolog (name, strlen (name), 0, 0);
-         message_dolog (": ", 2, 0, 0);
-         Vsignaling_function = Qnil;
-       }
     }
 
-  if (context != 0)
-    write_string_1 (context, -1, stream);
+  /* The immediate context is not interesting for Quits,
+     since they are asyncronous.  */
+  if (EQ (XCAR (data), Qquit))
+    Vsignaling_function = Qnil;
+
+  print_error_message (data, stream, context, Vsignaling_function);
 
-  print_error_message (data, stream);
+  Vsignaling_function = Qnil;
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're in -batch mode, this error should cause Emacs to exit.  */
@@ -1240,15 +1293,19 @@ command_loop ()
     {
       Lisp_Object val;
       val = internal_catch (Qexit, command_loop_2, Qnil);
-      executing_macro = Qnil;
+      executing_kbd_macro = Qnil;
       return val;
     }
   else
     while (1)
       {
        internal_catch (Qtop_level, top_level_1, Qnil);
+       /* Reset single_kboard in case top-level set it while
+          evaluating an -f option, or we are stuck there for some
+          other reason.  */
+       any_kboard_state ();
        internal_catch (Qtop_level, command_loop_2, Qnil);
-       executing_macro = Qnil;
+       executing_kbd_macro = Qnil;
 
        /* End of file in -batch run causes exit here.  */
        if (noninteractive)
@@ -1301,6 +1358,12 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
   if (display_hourglass_p)
     cancel_hourglass ();
 #endif
+
+  /* Unblock input if we enter with input blocked.  This may happen if
+     redisplay traps e.g. during tool-bar update with input blocked.  */
+  while (INPUT_BLOCKED_P)
+    UNBLOCK_INPUT;
+
   return Fthrow (Qtop_level, Qnil);
 }
 
@@ -1332,7 +1395,19 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 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));
+static void adjust_point_for_property P_ ((int, int));
+
+/* Cancel hourglass from protect_unwind.
+   ARG is not used.  */
+#ifdef HAVE_X_WINDOWS
+static Lisp_Object
+cancel_hourglass_unwind (arg)
+     Lisp_Object arg;
+{
+  cancel_hourglass ();
+  return Qnil;
+}
+#endif
 
 Lisp_Object
 command_loop_1 ()
@@ -1343,11 +1418,12 @@ command_loop_1 ()
   Lisp_Object keybuf[30];
   int i;
   int no_direct;
-  int prev_modiff;
+  int prev_modiff = 0;
   struct buffer *prev_buffer = NULL;
 #ifdef MULTI_KBOARD
   int was_locked = single_kboard;
 #endif
+  int already_adjusted;
 
   current_kboard->Vprefix_arg = Qnil;
   current_kboard->Vlast_prefix_arg = Qnil;
@@ -1357,6 +1433,7 @@ command_loop_1 ()
 
   nonundocount = 0;
   this_command_key_count = 0;
+  this_command_key_count_reset = 0;
   this_single_command_key_start = 0;
 
   if (NILP (Vmemory_full))
@@ -1374,21 +1451,9 @@ command_loop_1 ()
        resize_echo_area_exactly ();
 
       if (!NILP (Vdeferred_action_list))
-       call0 (Vdeferred_action_function);
-
-      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
-       {
-         if (NILP (Vunread_command_events)
-             && NILP (Vunread_input_method_events)
-             && NILP (Vunread_post_input_method_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
+       safe_run_hooks (Qdeferred_action_function);
     }
 
-  Vmemory_full = Qnil;
-
   /* Do this after running Vpost_command_hook, for consistency.  */
   current_kboard->Vlast_command = Vthis_command;
   current_kboard->Vreal_last_command = real_this_command;
@@ -1452,7 +1517,7 @@ command_loop_1 ()
         Is this a good idea?  */
       if (FRAMEP (internal_last_event_frame)
          && !EQ (internal_last_event_frame, selected_frame))
-       Fselect_frame (internal_last_event_frame, Qnil);
+       Fselect_frame (internal_last_event_frame);
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
@@ -1465,6 +1530,7 @@ command_loop_1 ()
 
       Vthis_command = Qnil;
       real_this_command = Qnil;
+      Vthis_original_command = Qnil;
 
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
@@ -1489,6 +1555,7 @@ command_loop_1 ()
        {
          cancel_echoing ();
          this_command_key_count = 0;
+         this_command_key_count_reset = 0;
          this_single_command_key_start = 0;
          goto finalize;
        }
@@ -1509,11 +1576,11 @@ command_loop_1 ()
        }
 
       cmd = read_key_sequence_cmd;
-      if (!NILP (Vexecuting_macro))
+      if (!NILP (Vexecuting_kbd_macro))
        {
          if (!NILP (Vquit_flag))
            {
-             Vexecuting_macro = Qt;
+             Vexecuting_kbd_macro = Qt;
              QUIT;             /* Make some noise. */
                                /* Will return since macro now empty. */
            }
@@ -1524,6 +1591,7 @@ command_loop_1 ()
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
+      last_point_position_window = selected_window;
       XSETBUFFER (last_point_position_buffer, prev_buffer);
 
       /* By default, we adjust point to a boundary of a region that
@@ -1541,7 +1609,7 @@ command_loop_1 ()
       if (SYMBOLP (cmd))
        {
          Lisp_Object cmd1;
-         if (cmd1 = Fremap_command (cmd), !NILP (cmd1))
+         if (cmd1 = Fcommand_remapping (cmd), !NILP (cmd1))
            cmd = cmd1;
        }
 
@@ -1553,11 +1621,16 @@ command_loop_1 ()
         if the symbol is a local variable.  */
       if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpre_command_hook);
-      
+
+      already_adjusted = 0;
+
       if (NILP (Vthis_command))
        {
          /* nil means key is undefined.  */
+         Lisp_Object keys = Fvector (i, keybuf);
+         keys = Fkey_description (keys, Qnil);
          bitch_at_user ();
+         message_with_string ("%s is undefined", keys, 0);
          current_kboard->defining_kbd_macro = Qnil;
          update_mode_lines = 1;
          current_kboard->Vprefix_arg = Qnil;
@@ -1577,12 +1650,23 @@ command_loop_1 ()
                    = window_display_table (XWINDOW (selected_window));
                  lose = FETCH_CHAR (PT_BYTE);
                  SET_PT (PT + 1);
-                 if ((dp
-                      ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
-                         ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
-                          : (NILP (DISP_CHAR_VECTOR (dp, lose))
-                             && (lose >= 0x20 && lose < 0x7f)))
-                      : (lose >= 0x20 && lose < 0x7f))
+                 if (! NILP (Vpost_command_hook))
+                   /* Put this before calling adjust_point_for_property
+                      so it will only get called once in any case.  */
+                   goto directly_done;
+                 if (current_buffer == prev_buffer
+                     && last_point_position != PT
+                     && NILP (Vdisable_point_adjustment)
+                     && NILP (Vglobal_disable_point_adjustment))
+                   adjust_point_for_property (last_point_position, 0);
+                 already_adjusted = 1;
+                 if (PT == last_point_position + 1
+                     && (dp
+                         ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
+                            ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
+                            : (NILP (DISP_CHAR_VECTOR (dp, lose))
+                               && (lose >= 0x20 && lose < 0x7f)))
+                         : (lose >= 0x20 && lose < 0x7f))
                      /* To extract the case of continuation on
                          wide-column characters.  */
                      && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT_BYTE)) == 1)
@@ -1596,7 +1680,7 @@ command_loop_1 ()
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
-                     && NILP (Vexecuting_macro))
+                     && NILP (Vexecuting_kbd_macro))
                    direct_output_forward_char (1);
                  goto directly_done;
                }
@@ -1606,12 +1690,21 @@ command_loop_1 ()
                    = window_display_table (XWINDOW (selected_window));
                  SET_PT (PT - 1);
                  lose = FETCH_CHAR (PT_BYTE);
-                 if ((dp
-                      ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
-                         ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
-                          : (NILP (DISP_CHAR_VECTOR (dp, lose))
-                             && (lose >= 0x20 && lose < 0x7f)))
-                      : (lose >= 0x20 && lose < 0x7f))
+                 if (! NILP (Vpost_command_hook))
+                   goto directly_done;
+                 if (current_buffer == prev_buffer
+                     && last_point_position != PT
+                     && NILP (Vdisable_point_adjustment)
+                     && NILP (Vglobal_disable_point_adjustment))
+                   adjust_point_for_property (last_point_position, 0);
+                 already_adjusted = 1;
+                 if (PT == last_point_position - 1
+                     && (dp
+                         ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
+                            ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
+                            : (NILP (DISP_CHAR_VECTOR (dp, lose))
+                               && (lose >= 0x20 && lose < 0x7f)))
+                         : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1622,17 +1715,20 @@ command_loop_1 ()
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
-                     && NILP (Vexecuting_macro))
+                     && NILP (Vexecuting_kbd_macro))
                    direct_output_forward_char (-1);
                  goto directly_done;
                }
              else if (EQ (Vthis_command, Qself_insert_command)
-                      /* Try this optimization only on ascii keystrokes.  */
-                      && INTEGERP (last_command_char))
+                      /* Try this optimization only on char keystrokes.  */
+                      && NATNUMP (last_command_char)
+                      && CHAR_VALID_P (XFASTINT (last_command_char), 0))
                {
-                 unsigned int c = XINT (last_command_char);
+                 unsigned int c
+                   = translate_char (Vtranslation_table_for_input,
+                                     XFASTINT (last_command_char), 0, 0, 0);
                  int value;
-                 if (NILP (Vexecuting_macro)
+                 if (NILP (Vexecuting_kbd_macro)
                      && !EQ (minibuf_window, selected_window))
                    {
                      if (!nonundocount || nonundocount >= 20)
@@ -1642,7 +1738,7 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
-                 
+
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1654,13 +1750,18 @@ command_loop_1 ()
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
                          || !NILP (XWINDOW (selected_window)->column_number_displayed)
-                         || !NILP (Vexecuting_macro));
-                 
+                         || !NILP (Vexecuting_kbd_macro));
+
                  value = internal_self_insert (c, 0);
 
                  if (value == 2)
                    nonundocount = 0;
 
+                 if (! NILP (Vpost_command_hook))
+                   /* Put this before calling adjust_point_for_property
+                      so it will only get called once in any case.  */
+                   goto directly_done;
+
                  /* VALUE == 1 when AFTER-CHANGE functions are
                     installed which is the case most of the time
                     because FONT-LOCK installs one.  */
@@ -1672,16 +1773,22 @@ command_loop_1 ()
 
          /* Here for a command that isn't executed directly */
 
+          {
 #ifdef HAVE_X_WINDOWS
-         if (display_hourglass_p
-             && NILP (Vexecuting_macro))
-           start_hourglass ();
+            int scount = SPECPDL_INDEX ();
+
+            if (display_hourglass_p
+                && NILP (Vexecuting_kbd_macro))
+              {
+                record_unwind_protect (cancel_hourglass_unwind, Qnil);
+                start_hourglass ();
+              }
 #endif
 
-         nonundocount = 0;
-         if (NILP (current_kboard->Vprefix_arg))
-           Fundo_boundary ();
-         Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
+            nonundocount = 0;
+            if (NILP (current_kboard->Vprefix_arg))
+              Fundo_boundary ();
+            Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
 #ifdef HAVE_X_WINDOWS
          /* Do not check display_hourglass_p here, because
@@ -1689,9 +1796,10 @@ command_loop_1 ()
             hourglass cursor anyway.
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
-         if (NILP (Vexecuting_macro))
-           cancel_hourglass ();
+         if (NILP (Vexecuting_kbd_macro))
+            unbind_to (scount, Qnil);
 #endif
+          }
        }
     directly_done: ;
       current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg;
@@ -1709,16 +1817,6 @@ command_loop_1 ()
       if (!NILP (Vdeferred_action_list))
        safe_run_hooks (Qdeferred_action_function);
 
-      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
-       {
-         if (NILP (Vunread_command_events)
-             && NILP (Vunread_input_method_events)
-             && NILP (Vunread_post_input_method_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
-
       /* If there is a prefix argument,
         1) We don't want Vlast_command to be ``universal-argument''
         (that would be dumb), so don't set Vlast_command,
@@ -1738,11 +1836,20 @@ command_loop_1 ()
          current_kboard->Vreal_last_command = real_this_command;
          cancel_echoing ();
          this_command_key_count = 0;
+         this_command_key_count_reset = 0;
          this_single_command_key_start = 0;
        }
 
       if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
+         /* Setting transient-mark-mode to `only' is a way of
+            turning it on for just one command.  */
+
+         if (EQ (Vtransient_mark_mode, Qidentity))
+           Vtransient_mark_mode = Qnil;
+         if (EQ (Vtransient_mark_mode, Qonly))
+           Vtransient_mark_mode = Qidentity;
+
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
            {
              /* We could also call `deactivate'mark'.  */
@@ -1763,8 +1870,9 @@ command_loop_1 ()
       if (current_buffer == prev_buffer
          && last_point_position != PT
          && NILP (Vdisable_point_adjustment)
-         && NILP (Vglobal_disable_point_adjustment))
-       adjust_point_for_property (last_point_position);
+         && NILP (Vglobal_disable_point_adjustment)
+         && !already_adjusted)
+       adjust_point_for_property (last_point_position, MODIFF != prev_modiff);
 
       /* Install chars successfully executed in kbd macro.  */
 
@@ -1783,47 +1891,139 @@ extern Lisp_Object Qcomposition, Qdisplay;
 
 /* Adjust point to a boundary of a region that has such a property
    that should be treated intangible.  For the moment, we check
-   `composition' and `display' property.  LAST_PT is the last position
-   of point.  */
+   `composition', `display' and `invisible' properties.
+   LAST_PT is the last position of point.  */
+
+extern Lisp_Object Qafter_string, Qbefore_string;
+extern Lisp_Object get_pos_property P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
 
 static void
-adjust_point_for_property (last_pt)
+adjust_point_for_property (last_pt, modified)
      int last_pt;
+     int modified;
 {
-  int start, end;
-  Lisp_Object val;
-  int check_composition = 1, check_display = 1;
+  int beg, end;
+  Lisp_Object val, overlay, tmp;
+  int check_composition = 1, check_display = 1, check_invisible = 1;
+  int orig_pt = PT;
 
-  while (check_composition || check_display)
+  /* FIXME: cycling is probably not necessary because these properties
+     can't be usefully combined anyway.  */
+  while (check_composition || check_display || check_invisible)
     {
       if (check_composition
          && PT > BEGV && PT < ZV
-         && get_property_and_range (PT, Qcomposition, &val, &start, &end, Qnil)
-         && COMPOSITION_VALID_P (start, end, val)
-         && start < PT && end > PT
-         && (last_pt <= start || last_pt >= end))
+         && get_property_and_range (PT, Qcomposition, &val, &beg, &end, Qnil)
+         && COMPOSITION_VALID_P (beg, end, val)
+         && beg < PT /* && end > PT   <- It's always the case.  */
+         && (last_pt <= beg || last_pt >= end))
        {
-         if (PT < last_pt)
-           SET_PT (start);
-         else
-           SET_PT (end);
-         check_display = 1;
+         xassert (end > PT);
+         SET_PT (PT < last_pt ? beg : end);
+         check_display = check_invisible = 1;
        }
       check_composition = 0;
       if (check_display
          && PT > BEGV && PT < ZV
-         && get_property_and_range (PT, Qdisplay, &val, &start, &end, Qnil)
+         && !NILP (val = get_char_property_and_overlay
+                             (make_number (PT), Qdisplay, Qnil, &overlay))
          && display_prop_intangible_p (val)
-         && start < PT && end > PT
-         && (last_pt <= start || last_pt >= end))
+         && (!OVERLAYP (overlay)
+             ? get_property_and_range (PT, Qdisplay, &val, &beg, &end, Qnil)
+             : (beg = OVERLAY_POSITION (OVERLAY_START (overlay)),
+                end = OVERLAY_POSITION (OVERLAY_END (overlay))))
+         && (beg < PT /* && end > PT   <- It's always the case.  */
+             || (beg <= PT && STRINGP (val) && SCHARS (val) == 0)))
        {
-         if (PT < last_pt)
-           SET_PT (start);
-         else
-           SET_PT (end);
-         check_composition = 1;
+         xassert (end > PT);
+         SET_PT (PT < last_pt
+                 ? (STRINGP (val) && SCHARS (val) == 0 ? beg - 1 : beg)
+                 : end);
+         check_composition = check_invisible = 1;
        }
       check_display = 0;
+      if (check_invisible && PT > BEGV && PT < ZV)
+       {
+         int inv, ellipsis = 0;
+         beg = end = PT;
+
+         /* Find boundaries `beg' and `end' of the invisible area, if any.  */
+         while (end < ZV
+                && !NILP (val = get_char_property_and_overlay
+                          (make_number (end), Qinvisible, Qnil, &overlay))
+                && (inv = TEXT_PROP_MEANS_INVISIBLE (val)))
+           {
+             ellipsis = ellipsis || inv > 1
+               || (OVERLAYP (overlay)
+                   && (!NILP (Foverlay_get (overlay, Qafter_string))
+                       || !NILP (Foverlay_get (overlay, Qbefore_string))));
+             tmp = Fnext_single_char_property_change
+               (make_number (end), Qinvisible, Qnil, Qnil);
+             end = NATNUMP (tmp) ? XFASTINT (tmp) : ZV;
+           }
+         while (beg > BEGV
+                && !NILP (val = get_char_property_and_overlay
+                          (make_number (beg - 1), Qinvisible, Qnil, &overlay))
+                && (inv = TEXT_PROP_MEANS_INVISIBLE (val)))
+           {
+             ellipsis = ellipsis || inv > 1
+               || (OVERLAYP (overlay)
+                   && (!NILP (Foverlay_get (overlay, Qafter_string))
+                       || !NILP (Foverlay_get (overlay, Qbefore_string))));
+             tmp = Fprevious_single_char_property_change
+               (make_number (beg), Qinvisible, Qnil, Qnil);
+             beg = NATNUMP (tmp) ? XFASTINT (tmp) : BEGV;
+           }
+
+         /* Move away from the inside area.  */
+         if (beg < PT && end > PT)
+           {
+             SET_PT ((orig_pt == PT && (last_pt < beg || last_pt > end))
+                     /* We haven't moved yet (so we don't need to fear
+                        infinite-looping) and we were outside the range
+                        before (so either end of the range still corresponds
+                        to a move in the right direction): pretend we moved
+                        less than we actually did, so that we still have
+                        more freedom below in choosing which end of the range
+                        to go to.  */
+                     ? (orig_pt = -1, PT < last_pt ? end : beg)
+                     /* We either have moved already or the last point
+                        was already in the range: we don't get to choose
+                        which end of the range we have to go to.  */
+                     : (PT < last_pt ? beg : end));
+             check_composition = check_display = 1;
+           }
+#if 0 /* This assertion isn't correct, because SET_PT may end up setting
+        the point to something other than its argument, due to
+        point-motion hooks, intangibility, etc.  */
+         xassert (PT == beg || PT == end);
+#endif
+
+         /* Pretend the area doesn't exist if the buffer is not
+            modified.  */
+         if (!modified && !ellipsis && beg < end)
+           {
+             if (last_pt == beg && PT == end && end < ZV)
+               (check_composition = check_display = 1, SET_PT (end + 1));
+             else if (last_pt == end && PT == beg && beg > BEGV)
+               (check_composition = check_display = 1, SET_PT (beg - 1));
+             else if (PT == ((PT < last_pt) ? beg : end))
+               /* We've already moved as far as we can.  Trying to go
+                  to the other end would mean moving backwards and thus
+                  could lead to an infinite loop.  */
+               ;
+             else if (val = get_pos_property (make_number (PT),
+                                              Qinvisible, Qnil),
+                      TEXT_PROP_MEANS_INVISIBLE (val)
+                      && (val = get_pos_property
+                          (make_number (PT == beg ? end : beg),
+                           Qinvisible, Qnil),
+                          !TEXT_PROP_MEANS_INVISIBLE (val)))
+               (check_composition = check_display = 1,
+                SET_PT (PT == beg ? end : beg));
+           }
+       }
+      check_invisible = 0;
     }
 }
 
@@ -1842,6 +2042,11 @@ static Lisp_Object
 safe_run_hooks_error (data)
      Lisp_Object data;
 {
+  Lisp_Object args[3];
+  args[0] = build_string ("Error in %s: %s");
+  args[1] = Vinhibit_quit;
+  args[2] = data;
+  Fmessage (3, args);
   return Fset (Vinhibit_quit, Qnil);
 }
 
@@ -1898,7 +2103,11 @@ poll_for_input (timer)
      struct atimer *timer;
 {
   if (poll_suppress_count == 0)
+#ifdef SYNC_INPUT
+    interrupt_input_pending = 1;
+#else
     poll_for_input_1 ();
+#endif
 }
 
 #endif /* POLL_FOR_INPUT */
@@ -1915,7 +2124,7 @@ start_polling ()
       /* Turn alarm handling on unconditionally.  It might have
         been turned off in process.c.  */
       turn_on_atimers (1);
-      
+
       /* If poll timer doesn't exist, are we need one with
         a different interval, start a new one.  */
       if (poll_timer == NULL
@@ -1925,7 +2134,7 @@ start_polling ()
 
          if (poll_timer)
            cancel_atimer (poll_timer);
-      
+
          EMACS_SET_SECS_USECS (interval, polling_period, 0);
          poll_timer = start_atimer (ATIMER_CONTINUOUS, interval,
                                     poll_for_input, NULL);
@@ -2041,12 +2250,16 @@ make_ctrl_char (c)
   return c;
 }
 
-/* Display help echo in the echo area.
+/* Display the help-echo property of the character after the mouse pointer.
+   Either show it in the echo area, or call show-help-function to display
+   it by other means (maybe in a tooltip).
 
-   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.
+   If HELP is nil, that means clear the previous help echo.
+
+   If HELP is a string, display that string.  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.
@@ -2086,11 +2299,16 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
        }
       else
        help = safe_eval (help);
-      
+
       if (!STRINGP (help))
        return;
     }
 
+#ifdef HAVE_MOUSE
+  if (!noninteractive && STRINGP (help))
+    help = call1 (Qmouse_fixup_help_message, help);
+#endif
+
   if (STRINGP (help) || NILP (help))
     {
       if (!NILP (Vshow_help_function))
@@ -2109,23 +2327,23 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
 
              if (!help_echo_showing_p)
                Vpre_help_message = current_message ();
-             
+
              specbind (Qmessage_truncate_lines, Qt);
-             message3_nolog (help, STRING_BYTES (XSTRING (help)),
+             message3_nolog (help, SBYTES (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)),
+                             SBYTES (Vpre_help_message),
                              STRING_MULTIBYTE (Vpre_help_message));
              Vpre_help_message = Qnil;
            }
          else
            message (0);
        }
-      
+
       help_echo_showing_p = STRINGP (help);
     }
 }
@@ -2142,6 +2360,14 @@ static void record_char ();
 static jmp_buf wrong_kboard_jmpbuf;
 #endif
 
+#define STOP_POLLING                                   \
+do { if (! polling_stopped_here) stop_polling ();      \
+       polling_stopped_here = 1; } while (0)
+
+#define RESUME_POLLING                                 \
+do { if (polling_stopped_here) start_polling ();       \
+       polling_stopped_here = 0; } while (0)
+
 /* read a character from the keyboard; call the redisplay if needed */
 /* commandflag 0 means do not do auto-saving, but do do redisplay.
    -1 means do not do redisplay, but do do autosaving.
@@ -2180,12 +2406,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   volatile Lisp_Object also_record;
   volatile int reread;
   struct gcpro gcpro1, gcpro2;
-  EMACS_TIME last_idle_start;
+  int polling_stopped_here = 0;
 
   also_record = Qnil;
 
+#if 0  /* This was commented out as part of fixing echo for C-u left.  */
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
+#endif
   c = Qnil;
   previous_echo_area_message = Qnil;
 
@@ -2231,13 +2459,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && 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;
     }
@@ -2257,11 +2485,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto reread_for_input_method;
     }
 
-  /* If there is no function key translated before
-     reset-this-command-lengths takes effect, forget about it.  */
-  before_command_restore_flag = 0;
+  this_command_key_count_reset = 0;
 
-  if (!NILP (Vexecuting_macro))
+  if (!NILP (Vexecuting_kbd_macro))
     {
       /* We set this to Qmacro; since that's not a frame, nobody will
         try to switch frames on us, and the selected window will
@@ -2278,19 +2504,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Exit the macro if we are at the end.
         Also, some things replace the macro with t
         to force an early exit.  */
-      if (EQ (Vexecuting_macro, Qt)
-         || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
+      if (EQ (Vexecuting_kbd_macro, Qt)
+         || executing_kbd_macro_index >= XFASTINT (Flength (Vexecuting_kbd_macro)))
        {
          XSETINT (c, -1);
-         RETURN_UNGCPRO (c);
+         goto exit;
        }
 
-      c = Faref (Vexecuting_macro, make_number (executing_macro_index));
-      if (STRINGP (Vexecuting_macro)
-         && (XINT (c) & 0x80))
+      c = Faref (Vexecuting_kbd_macro, make_number (executing_kbd_macro_index));
+      if (STRINGP (Vexecuting_kbd_macro)
+         && (XINT (c) & 0x80) && (XUINT (c) <= 0xff))
        XSETFASTINT (c, CHAR_META | (XINT (c) & ~0x80));
 
-      executing_macro_index++;
+      executing_kbd_macro_index++;
 
       goto from_macro;
     }
@@ -2334,7 +2560,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Message turns off echoing unless more keystrokes turn it on again.
-     
+
      The code in 20.x for the condition was
 
      1. echo_area_glyphs && *echo_area_glyphs
@@ -2342,10 +2568,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      3. && ok_to_echo_at_next_pause != echo_area_glyphs
 
      (1) means there's a current message displayed
-     
+
      (2) means it's not the message from echoing from the current
      kboard.
-     
+
      (3) There's only one place in 20.x where ok_to_echo_at_next_pause
      is set to a non-null value.  This is done in read_char and it is
      set to echo_area_glyphs after a call to echo_char.  That means
@@ -2357,7 +2583,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      must be either null, or the current message isn't from echoing at
      all, or it's from echoing from a different kboard than the
      current one.  */
-  
+
   if (/* There currently is something in the echo area.  */
       !NILP (echo_area_buffer[0])
       && (/* And it's either not from echoing.  */
@@ -2369,7 +2595,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     cancel_echoing ();
   else
     echo_dash ();
-      
+
   /* Try reading a character via menu prompting in the minibuf.
      Try this before the sit-for, because the sit-for
      would do the wrong thing if we are supposed to do
@@ -2399,6 +2625,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (_setjmp (local_getcjmp))
     {
+      /* We must have saved the outer value of getcjmp here,
+        so restore it now.  */
+      restore_getcjmp (save_jump);
       XSETINT (c, quit_char);
       internal_last_event_frame = selected_frame;
       Vlast_event_frame = internal_last_event_frame;
@@ -2444,7 +2673,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
-  if (minibuf_level == 0 
+  if (minibuf_level == 0
       && !current_kboard->immediate_echo
       && this_command_key_count > 0
       && ! noninteractive
@@ -2461,7 +2690,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          || (!echo_kboard && ok_to_echo_at_next_pause)))
     {
       Lisp_Object tem0;
-      
+
       /* After a mouse event, start echoing right away.
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
@@ -2514,7 +2743,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Now that we have read an event, Emacs is not idle.  */
       timer_stop_idle ();
 
-      RETURN_UNGCPRO (c);
+      goto exit;
     }
 
   /* Maybe autosave and/or garbage collect due to idleness.  */
@@ -2621,7 +2850,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  wrong_kboard:
 
-  stop_polling ();
+  STOP_POLLING;
 
   /* Finally, we read from the main queue,
      and if that gives us something we can't use yet, we put it on the
@@ -2686,11 +2915,8 @@ 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 ();
+  RESUME_POLLING;
 
   if (NILP (c))
     {
@@ -2707,7 +2933,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      so don't show them to the user.
      Also, don't record a key if we already did.  */
   if (BUFFERP (c) || key_already_recorded)
-    RETURN_UNGCPRO (c);
+    goto exit;
 
   /* Process special events within read_char
      and loop around to read another event.  */
@@ -2728,7 +2954,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
           prevents automatic window selection (under
           mouse_autoselect_window from acting as a real input event, for
           example banishing the mouse under mouse-avoidance-mode.  */
-       timer_idleness_start_time = last_idle_start;
+       timer_resume_idle ();
 
       /* Resume allowing input from any kboard, if that was true before.  */
       if (!was_locked)
@@ -2742,14 +2968,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       /* If kbd_buffer_get_event gave us an EOF, return that.  */
       if (XINT (c) == -1)
-       RETURN_UNGCPRO (c);
+       goto exit;
 
       if ((STRINGP (Vkeyboard_translate_table)
-          && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
+          && SCHARS (Vkeyboard_translate_table) > (unsigned) XFASTINT (c))
          || (VECTORP (Vkeyboard_translate_table)
              && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
          || (CHAR_TABLE_P (Vkeyboard_translate_table)
-             && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c)))
+             && CHAR_VALID_P (XINT (c), 0)))
        {
          Lisp_Object d;
          d = Faref (Vkeyboard_translate_table, c);
@@ -2769,13 +2995,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       Lisp_Object posn;
 
-      posn = POSN_BUFFER_POSN (EVENT_START (c));
+      posn = POSN_POSN (EVENT_START (c));
       /* Handle menu-bar events:
         insert the dummy prefix event `menu-bar'.  */
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
+         POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -2825,16 +3051,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && (unsigned) XINT (c) != 127
       && (unsigned) XINT (c) < 256)
     {
-      Lisp_Object keys; 
-      int key_count;
+      Lisp_Object keys;
+      int key_count, key_count_reset;
       struct gcpro gcpro1;
       int count = SPECPDL_INDEX ();
 
       /* Save the echo status.  */
       int saved_immediate_echo = current_kboard->immediate_echo;
       struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+      Lisp_Object saved_echo_string = current_kboard->echo_string;
       int saved_echo_after_prompt = current_kboard->echo_after_prompt;
 
+#if 0
       if (before_command_restore_flag)
        {
          this_command_key_count = before_command_key_count_1;
@@ -2843,9 +3071,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          echo_truncate (before_command_echo_length_1);
          before_command_restore_flag = 0;
        }
+#endif
 
       /* Save the this_command_keys status.  */
       key_count = this_command_key_count;
+      key_count_reset = this_command_key_count_reset;
 
       if (key_count > 0)
        keys = Fcopy_sequence (this_command_keys);
@@ -2855,6 +3085,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       /* Clear out this_command_keys.  */
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
 
       /* Now wipe the echo area.  */
       if (!NILP (echo_area_buffer[0]))
@@ -2877,11 +3108,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Restore the saved echoing state
         and this_command_keys state.  */
       this_command_key_count = key_count;
+      this_command_key_count_reset = key_count_reset;
       if (key_count > 0)
        this_command_keys = keys;
 
       cancel_echoing ();
       ok_to_echo_at_next_pause = saved_ok_to_echo;
+      current_kboard->echo_string = saved_echo_string;
       current_kboard->echo_after_prompt = saved_echo_after_prompt;
       if (saved_immediate_echo)
        echo_now ();
@@ -2922,14 +3155,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       show_help_echo (help, window, object, position, 0);
 
       /* We stopped being idle for this event; undo that.  */
-      timer_idleness_start_time = last_idle_start;
+      timer_resume_idle ();
       goto retry;
     }
-  
-  if (this_command_key_count == 0 || ! reread)
+
+  if (! reread || this_command_key_count == 0
+      || this_command_key_count_reset)
     {
-      before_command_key_count = this_command_key_count;
-      before_command_echo_length = echo_length ();
 
       /* Don't echo mouse motion events.  */
       if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
@@ -2984,6 +3216,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+ exit:
+  RESUME_POLLING;
   RETURN_UNGCPRO (c);
 }
 
@@ -2999,8 +3233,10 @@ record_menu_key (c)
 
   record_char (c);
 
+#if 0
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
+#endif
 
   /* Don't echo mouse motion events.  */
   if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
@@ -3055,19 +3291,19 @@ record_char (c)
 
       Lisp_Object ev1, ev2, ev3;
       int ix1, ix2, ix3;
-      
+
       if ((ix1 = recent_keys_index - 1) < 0)
        ix1 = NUM_RECENT_KEYS - 1;
       ev1 = AREF (recent_keys, ix1);
-      
+
       if ((ix2 = ix1 - 1) < 0)
        ix2 = NUM_RECENT_KEYS - 1;
       ev2 = AREF (recent_keys, ix2);
-      
+
       if ((ix3 = ix2 - 1) < 0)
        ix3 = NUM_RECENT_KEYS - 1;
       ev3 = AREF (recent_keys, ix3);
-     
+
       if (EQ (XCAR (c), Qhelp_echo))
        {
          /* Don't record `help-echo' in recent_keys unless it shows some help
@@ -3138,7 +3374,7 @@ record_char (c)
     }
 
   num_nonmacro_input_events++;
-      
+
   /* 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.  :-) */
@@ -3161,8 +3397,8 @@ record_char (c)
          if (SYMBOLP (dribblee))
            {
              putc ('<', dribble);
-             fwrite (XSTRING (SYMBOL_NAME (dribblee))->data, sizeof (char),
-                     STRING_BYTES (XSTRING (SYMBOL_NAME (dribblee))),
+             fwrite (SDATA (SYMBOL_NAME (dribblee)), sizeof (char),
+                     SBYTES (SYMBOL_NAME (dribblee)),
                      dribble);
              putc ('>', dribble);
            }
@@ -3220,10 +3456,11 @@ tracking_off (old_value)
         input has been processed.  If the only input available was
         the sort that we have just disabled, then we need to call
         redisplay.  */
-      if (!readable_events (1))
+      if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
        {
          redisplay_preserve_echo_area (6);
-         get_input_pending (&input_pending, 1);
+         get_input_pending (&input_pending,
+                            READABLE_EVENTS_DO_TIMERS_NOW);
        }
     }
   return Qnil;
@@ -3275,20 +3512,21 @@ some_mouse_moved ()
 /* Return true iff there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
 static int
-readable_filtered_events (do_timers_now, filter_events)
-     int do_timers_now;
-     int filter_events;
+readable_events (flags)
+     int flags;
 {
-  if (do_timers_now)
-    timer_check (do_timers_now);
+  if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
+    timer_check (1);
 
-  /* If the buffer contains only FOCUS_IN_EVENT events,
-     and FILTER_EVENTS is nonzero, report it as empty.  */
+  /* If the buffer contains only FOCUS_IN_EVENT events, and
+     READABLE_EVENTS_FILTER_EVENTS is set, report it as empty.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
     {
-      int have_live_event = 1;
-
-      if (filter_events)
+      if (flags & (READABLE_EVENTS_FILTER_EVENTS
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                  | READABLE_EVENTS_IGNORE_SQUEEZABLES
+#endif
+                  ))
         {
           struct input_event *event;
 
@@ -3296,20 +3534,34 @@ readable_filtered_events (do_timers_now, filter_events)
                    ? kbd_fetch_ptr
                    : kbd_buffer);
 
-          while (have_live_event && event->kind == FOCUS_IN_EVENT)
-            {
-              event++;
+         do
+           {
+             if (!(
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                   (flags & READABLE_EVENTS_FILTER_EVENTS) &&
+#endif
+                   event->kind == FOCUS_IN_EVENT)
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                 && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+                      && event->kind == SCROLL_BAR_CLICK_EVENT
+                      && event->part == scroll_bar_handle
+                      && event->modifiers == 0)
+#endif
+                 )
+               return 1;
+             event++;
               if (event == kbd_buffer + KBD_BUFFER_SIZE)
                 event = kbd_buffer;
-              if (event == kbd_store_ptr)
-                have_live_event = 0;
-            }
+           }
+         while (event != kbd_store_ptr);
         }
-      if (have_live_event) return 1;
+      else
+       return 1;
     }
 
 #ifdef HAVE_MOUSE
-  if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+      && !NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
 #endif
   if (single_kboard)
@@ -3327,15 +3579,6 @@ readable_filtered_events (do_timers_now, filter_events)
   return 0;
 }
 
-/* Return true iff there are any events in the queue that read-char
-   would return.  If this returns false, a read-char would block.  */
-static int
-readable_events (do_timers_now)
-     int do_timers_now;
-{
-  return readable_filtered_events (do_timers_now, 0);
-}
-
 /* Set this for debugging, to have a way to get out */
 int stop_character;
 
@@ -3361,15 +3604,41 @@ event_to_kboard (event)
 }
 #endif
 
+
+Lisp_Object Vthrow_on_input;
+
 /* Store an event obtained at interrupt level into kbd_buffer, fifo */
 
 void
 kbd_buffer_store_event (event)
      register struct input_event *event;
+{
+  kbd_buffer_store_event_hold (event, 0);
+}
+
+/* Store EVENT obtained at interrupt level into kbd_buffer, fifo.
+
+   If HOLD_QUIT is 0, just stuff EVENT into the fifo.
+   Else, if HOLD_QUIT.kind != NO_EVENT, discard EVENT.
+   Else, if EVENT is a quit event, store the quit event
+   in HOLD_QUIT, and return (thus ignoring further events).
+
+   This is used in read_avail_input to postpone the processing
+   of the quit event until all subsequent input events have been
+   parsed (and discarded).
+ */
+
+void
+kbd_buffer_store_event_hold (event, hold_quit)
+     register struct input_event *event;
+     struct input_event *hold_quit;
 {
   if (event->kind == NO_EVENT)
     abort ();
 
+  if (hold_quit && hold_quit->kind != NO_EVENT)
+    return;
+
   if (event->kind == ASCII_KEYSTROKE_EVENT)
     {
       register int c = event->code & 0377;
@@ -3383,7 +3652,6 @@ kbd_buffer_store_event (event)
 
       if (c == quit_char)
        {
-         static SIGTYPE interrupt_signal P_ ((int));
 #ifdef MULTI_KBOARD
          KBOARD *kb;
          struct input_event *sp;
@@ -3412,6 +3680,12 @@ kbd_buffer_store_event (event)
            }
 #endif
 
+         if (hold_quit)
+           {
+             bcopy (event, (char *) hold_quit, sizeof (*event));
+             return;
+           }
+
          /* If this results in a quit_char being returned to Emacs as
             input, set Vlast_event_frame properly.  If this doesn't
             get returned to Emacs as an event, the next event read
@@ -3441,7 +3715,9 @@ kbd_buffer_store_event (event)
      Just ignore the second one.  */
   else if (event->kind == BUFFER_SWITCH_EVENT
           && kbd_fetch_ptr != kbd_store_ptr
-          && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT)
+          && ((kbd_store_ptr == kbd_buffer
+               ? kbd_buffer + KBD_BUFFER_SIZE - 1
+               : kbd_store_ptr - 1)->kind) == BUFFER_SWITCH_EVENT)
     return;
 
   if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
@@ -3453,40 +3729,44 @@ 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)
-       {
-         /* We must not use the ordinary copying code for this case,
-            since `part' is an enum and copying it might not copy enough
-            in this case.  */
-         bcopy (event, (char *) sp, sizeof (*event));
-       }
-      else
+      *kbd_store_ptr = *event;
+      ++kbd_store_ptr;
+    }
 
+  /* If we're inside while-no-input, and this event qualifies
+     as input, set quit-flag to cause an interrupt.  */
+  if (!NILP (Vthrow_on_input)
+      && event->kind != FOCUS_IN_EVENT
+      && event->kind != HELP_EVENT
+      && event->kind != DEICONIFY_EVENT)
+    {
+      Vquit_flag = Vthrow_on_input;
+      /* If we're inside a function that wants immediate quits,
+        do it now.  */
+      if (immediate_quit && NILP (Vinhibit_quit))
        {
-         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;
+         immediate_quit = 0;
+         sigfree ();
+         QUIT;
        }
-#else
-      *kbd_store_ptr = *event;
-#endif
+    }
+}
 
-      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;
+
+/* Put an input event back in the head of the event queue.  */
+
+void
+kbd_buffer_unget_event (event)
+     register struct input_event *event;
+{
+  if (kbd_fetch_ptr == kbd_buffer)
+    kbd_fetch_ptr = kbd_buffer + KBD_BUFFER_SIZE;
+
+  /* Don't let the very last slot in the buffer become full,  */
+  if (kbd_fetch_ptr - 1 != kbd_store_ptr)
+    {
+      --kbd_fetch_ptr;
+      *kbd_fetch_ptr = *event;
     }
 }
 
@@ -3504,24 +3784,22 @@ kbd_buffer_store_event (event)
 
    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;
+void
+gen_help_event (help, frame, window, object, pos)
      Lisp_Object help, frame, object, window;
      int pos;
 {
-  if (size >= 1)
-    {
-      bufp->kind = HELP_EVENT;
-      bufp->frame_or_window = frame;
-      bufp->arg = object;
-      bufp->x = WINDOWP (window) ? window : frame;
-      bufp->y = help;
-      bufp->code = pos;
-      return 1;
-    }
-  return 0;
+  struct input_event event;
+
+  EVENT_INIT (event);
+
+  event.kind = HELP_EVENT;
+  event.frame_or_window = frame;
+  event.arg = object;
+  event.x = WINDOWP (window) ? window : frame;
+  event.y = help;
+  event.code = pos;
+  kbd_buffer_store_event (&event);
 }
 
 
@@ -3555,6 +3833,7 @@ discard_mouse_events ()
        sp = kbd_buffer;
 
       if (sp->kind == MOUSE_CLICK_EVENT
+         || sp->kind == WHEEL_EVENT
 #ifdef WINDOWSNT
          || sp->kind == W32_SCROLL_BAR_CLICK_EVENT
 #endif
@@ -3578,7 +3857,7 @@ 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)
@@ -3600,9 +3879,6 @@ 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;
 }
 
@@ -3661,10 +3937,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        break;
 #endif
       {
-       Lisp_Object minus_one;
-
-       XSETINT (minus_one, -1);
-       wait_reading_process_input (0, 0, minus_one, 1);
+       wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
 
        if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
          /* Pass 1 for EXPECT since we just waited to have input.  */
@@ -3708,7 +3981,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       /* These two kinds of events get special handling
         and don't actually appear to the command loop.
         We return nil for them.  */
-      if (event->kind == SELECTION_REQUEST_EVENT)
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3719,7 +3993,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          copy = *event;
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
-         x_handle_selection_request (&copy);
+         x_handle_selection_event (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -3727,22 +4001,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif
        }
 
-      else if (event->kind == SELECTION_CLEAR_EVENT)
-       {
-#ifdef HAVE_X11
-         struct input_event copy;
-
-         /* Remove it from the buffer before processing it.  */
-         copy = *event;
-         kbd_fetch_ptr = event + 1;
-         input_pending = readable_events (0);
-         x_handle_selection_clear (&copy);
-#else
-         /* We're getting selection request events, but we don't have
-             a window system.  */
-         abort ();
-#endif
-       }
 #if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
       else if (event->kind == DELETE_WINDOW_EVENT)
        {
@@ -3752,7 +4010,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          kbd_fetch_ptr = event + 1;
        }
 #endif
-#if defined (HAVE_X11) || defined (HAVE_NTGUI)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
       else if (event->kind == ICONIFY_EVENT)
        {
          /* Make an event (iconify-frame (FRAME)).  */
@@ -3774,7 +4032,8 @@ 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) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+    || defined (USE_GTK)
       else if (event->kind == MENU_BAR_ACTIVATE_EVENT)
        {
          kbd_fetch_ptr = event + 1;
@@ -3783,13 +4042,16 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
       else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
+#ifdef MAC_OS
+         /* Make an event (language-change (KEY_SCRIPT)).  */
+         obj = Fcons (make_number (event->code), Qnil);
+#else
          /* Make an event (language-change (FRAME CHARSET LCID)).  */
-         obj = Fcons (event->modifiers, Qnil);
-         obj = Fcons (event->code, obj);
-         obj = Fcons (event->frame_or_window, obj);
+         obj = Fcons (event->frame_or_window, Qnil);
+#endif
          obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
@@ -3842,14 +4104,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
-         kbd_fetch_ptr = event + 1;
-       }
-      else if (event->kind == SELECT_WINDOW_EVENT)
-       {
-         /* Make an event (select-window (WINDOW)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qselect_window, Fcons (obj, Qnil));
-
          kbd_fetch_ptr = event + 1;
        }
       else
@@ -3880,8 +4134,9 @@ 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 defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS) \
+    || defined (USE_GTK)
              /* 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
@@ -3975,7 +4230,8 @@ swallow_events (do_display)
 
       /* These two kinds of events get special handling
         and don't actually appear to the command loop.  */
-      if (event->kind == SELECTION_REQUEST_EVENT)
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3986,46 +4242,28 @@ swallow_events (do_display)
          copy = *event;
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
-         x_handle_selection_request (&copy);
+         x_handle_selection_event (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
          abort ();
 #endif
        }
+      else
+       break;
+    }
 
-      else if (event->kind == SELECTION_CLEAR_EVENT)
-       {
-#ifdef HAVE_X11
-         struct input_event copy;
+  old_timers_run = timers_run;
+  get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
 
-         /* Remove it from the buffer before processing it,  */
-         copy = *event;
+  if (timers_run != old_timers_run && do_display)
+    redisplay_preserve_echo_area (7);
+}
+\f
+/* Record the start of when Emacs is idle,
+   for the sake of running idle-time timers.  */
 
-         kbd_fetch_ptr = event + 1;
-         input_pending = readable_events (0);
-         x_handle_selection_clear (&copy);
-#else
-         /* We're getting selection request events, but we don't have
-             a window system.  */
-         abort ();
-#endif
-       }
-      else
-       break;
-    }
-
-  old_timers_run = timers_run;
-  get_input_pending (&input_pending, 1);
-
-  if (timers_run != old_timers_run && do_display)
-    redisplay_preserve_echo_area (7);
-}
-\f
-/* Record the start of when Emacs is idle,
-   for the sake of running idle-time timers.  */
-
-void
+static void
 timer_start_idle ()
 {
   Lisp_Object timers;
@@ -4053,12 +4291,23 @@ timer_start_idle ()
 
 /* Record that Emacs is no longer idle, so stop running idle-time timers.  */
 
-void
+static void
 timer_stop_idle ()
 {
   EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
 }
 
+/* Resume idle timer from last idle start time.  */
+
+static void
+timer_resume_idle ()
+{
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    return;
+
+  timer_idleness_start_time = timer_last_idleness_start_time;
+}
+
 /* This is only for debugging.  */
 struct input_event last_timer_event;
 
@@ -4210,7 +4459,7 @@ timer_check (do_it_now)
          difference = idle_timer_difference;
        }
       vector = XVECTOR (chosen_timer)->contents;
-       
+
       /* If timer is ripe, run it if it hasn't been run.  */
       if (EMACS_TIME_NEG_P (difference)
          || (EMACS_SECS (difference) == 0
@@ -4227,7 +4476,7 @@ timer_check (do_it_now)
              vector[0] = Qt;
 
              specbind (Qinhibit_quit, Qt);
-             
+
              call1 (Qtimer_event_handler, chosen_timer);
              Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
@@ -4260,9 +4509,7 @@ timer_check (do_it_now)
 static Lisp_Object accent_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
-#ifdef WINDOWSNT
-static Lisp_Object mouse_wheel_syms;
-#endif
+static Lisp_Object wheel_syms;
 static Lisp_Object drag_n_drop_syms;
 
 /* This is a list of keysym codes for special "accent" characters.
@@ -4335,6 +4582,41 @@ static int lispy_accent_codes[] =
 #else
   0,
 #endif
+#ifdef XK_dead_abovering
+  XK_dead_abovering,
+#else
+  0,
+#endif
+#ifdef XK_dead_iota
+  XK_dead_iota,
+#else
+  0,
+#endif
+#ifdef XK_dead_belowdot
+  XK_dead_belowdot,
+#else
+  0,
+#endif
+#ifdef XK_dead_voiced_sound
+  XK_dead_voiced_sound,
+#else
+  0,
+#endif
+#ifdef XK_dead_semivoiced_sound
+  XK_dead_semivoiced_sound,
+#else
+  0,
+#endif
+#ifdef XK_dead_hook
+  XK_dead_hook,
+#else
+  0,
+#endif
+#ifdef XK_dead_horn
+  XK_dead_horn,
+#else
+  0,
+#endif
 };
 
 /* This is a list of Lisp names for special "accent" characters.
@@ -4355,6 +4637,13 @@ static char *lispy_accent_keys[] =
   "dead-caron",
   "dead-doubleacute",
   "dead-abovedot",
+  "dead-abovering",
+  "dead-iota",
+  "dead-belowdot",
+  "dead-voiced-sound",
+  "dead-semivoiced-sound",
+  "dead-hook",
+  "dead-horn",
 };
 
 #ifdef HAVE_NTGUI
@@ -4363,36 +4652,36 @@ static char *lispy_accent_keys[] =
 char *lispy_function_keys[] =
   {
     0,                /* 0                      */
-    
+
     0,                /* VK_LBUTTON        0x01 */
     0,                /* VK_RBUTTON        0x02 */
     "cancel",         /* VK_CANCEL         0x03 */
     0,                /* VK_MBUTTON        0x04 */
-    
+
     0, 0, 0,          /*    0x05 .. 0x07        */
-    
+
     "backspace",      /* VK_BACK           0x08 */
     "tab",            /* VK_TAB            0x09 */
-    
+
     0, 0,             /*    0x0A .. 0x0B        */
-    
+
     "clear",          /* VK_CLEAR          0x0C */
     "return",         /* VK_RETURN         0x0D */
-    
+
     0, 0,             /*    0x0E .. 0x0F        */
-  
+
     0,                /* VK_SHIFT          0x10 */
     0,                /* VK_CONTROL        0x11 */
     0,                /* VK_MENU           0x12 */
     "pause",          /* VK_PAUSE          0x13 */
     "capslock",       /* VK_CAPITAL        0x14 */
-    
+
     0, 0, 0, 0, 0, 0, /*    0x15 .. 0x1A        */
-    
+
     "escape",         /* VK_ESCAPE         0x1B */
-    
+
     0, 0, 0, 0,       /*    0x1C .. 0x1F        */
-    
+
     0,                /* VK_SPACE          0x20 */
     "prior",          /* VK_PRIOR          0x21 */
     "next",           /* VK_NEXT           0x22 */
@@ -4409,25 +4698,25 @@ char *lispy_function_keys[] =
     "insert",         /* VK_INSERT         0x2D */
     "delete",         /* VK_DELETE         0x2E */
     "help",           /* VK_HELP           0x2F */
-  
+
     /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
-    
+
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    
+
     0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40       */
-    
+
     /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
-    
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
-    
+
     "lwindow",       /* VK_LWIN           0x5B */
     "rwindow",       /* VK_RWIN           0x5C */
     "apps",          /* VK_APPS           0x5D */
-    
+
     0, 0,            /*    0x5E .. 0x5F        */
-    
+
     "kp-0",          /* VK_NUMPAD0        0x60 */
     "kp-1",          /* VK_NUMPAD1        0x61 */
     "kp-2",          /* VK_NUMPAD2        0x62 */
@@ -4468,13 +4757,13 @@ char *lispy_function_keys[] =
     "f22",           /* VK_F22            0x85 */
     "f23",           /* VK_F23            0x86 */
     "f24",           /* VK_F24            0x87 */
-    
+
     0, 0, 0, 0,      /*    0x88 .. 0x8B        */
     0, 0, 0, 0,      /*    0x8C .. 0x8F        */
-    
+
     "kp-numlock",    /* VK_NUMLOCK        0x90 */
     "scroll",        /* VK_SCROLL         0x91 */
-    
+
     "kp-space",             /* VK_NUMPAD_CLEAR   0x92 */
     "kp-enter",             /* VK_NUMPAD_ENTER   0x93 */
     "kp-prior",             /* VK_NUMPAD_PRIOR   0x94 */
@@ -4496,17 +4785,17 @@ char *lispy_function_keys[] =
      * No other API or message will distinguish left and right keys this way.
      */
     /* 0xA0 .. 0xEF */
-    
+
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    
+
     /* 0xF0 .. 0xF5 */
-    
+
     0, 0, 0, 0, 0, 0,
-    
+
     "attn",          /* VK_ATTN           0xF6 */
     "crsel",         /* VK_CRSEL          0xF7 */
     "exsel",         /* VK_EXSEL          0xF8 */
@@ -4521,6 +4810,10 @@ char *lispy_function_keys[] =
 
 #else /* not HAVE_NTGUI */
 
+/* This should be dealt with in XTread_socket now, and that doesn't
+   depend on the client system having the Kana syms defined.  See also
+   the XK_kana_A case below.  */
+#if 0
 #ifdef XK_kana_A
 static char *lispy_kana_keys[] =
   {
@@ -4535,7 +4828,7 @@ static char *lispy_kana_keys[] =
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,"overline",0,
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x480 .. 0x48f */
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x490 .. 0x49f */
-    0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket", 
+    0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket",
     "kana-comma", "kana-conjunctive", "kana-WO", "kana-a",
     "kana-i", "kana-u", "kana-e", "kana-o",
     "kana-ya", "kana-yu", "kana-yo", "kana-tsu",
@@ -4555,6 +4848,7 @@ static char *lispy_kana_keys[] =
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x4f0 .. 0x4ff */
   };
 #endif /* XK_kana_A */
+#endif /* 0 */
 
 #define FUNCTION_KEY_OFFSET 0xff00
 
@@ -4653,9 +4947,9 @@ static char *iso_lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe10 */
     0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe18 */
     "iso-lefttab",             /* 0xfe20 */
-    "iso-move-line-up", "iso-move-line-down", 
-    "iso-partial-line-up", "iso-partial-line-down", 
-    "iso-partial-space-left", "iso-partial-space-right", 
+    "iso-move-line-up", "iso-move-line-down",
+    "iso-partial-line-up", "iso-partial-line-down",
+    "iso-partial-space-left", "iso-partial-space-right",
     "iso-set-margin-left", "iso-set-margin-right", /* 0xffe27, 28 */
     "iso-release-margin-left", "iso-release-margin-right",
     "iso-release-both-margins",
@@ -4669,21 +4963,11 @@ static char *iso_lispy_function_keys[] =
 
 Lisp_Object Vlispy_mouse_stem;
 
-#ifdef WINDOWSNT
-/* mouse-wheel events are generated by the wheel on devices such as
-   the MS Intellimouse.  The wheel sits in between the left and right
-   mouse buttons, and is typically used to scroll or zoom the window
-   underneath the pointer.  mouse-wheel events specify the object on
-   which they operate, and a delta corresponding to the amount and
-   direction that the wheel is rotated.  Clicking the mouse-wheel
-   generates a mouse-2 event.  */
-static char *lispy_mouse_wheel_names[] = 
-{
-  "mouse-wheel"
+static char *lispy_wheel_names[] =
+{
+  "wheel-up", "wheel-down"
 };
 
-#endif /* WINDOWSNT */
-
 /* drag-n-drop events are generated when a set of selected files are
    dragged from another application and dropped onto an Emacs window.  */
 static char *lispy_drag_n_drop_names[] =
@@ -4746,6 +5030,189 @@ EMACS_INT double_click_fuzz;
 
 int double_click_count;
 
+/* Return position of a mouse click or wheel event */
+
+static Lisp_Object
+make_lispy_position (f, x, y, time)
+     struct frame *f;
+     Lisp_Object *x, *y;
+     unsigned long time;
+{
+  Lisp_Object window;
+  enum window_part part;
+  Lisp_Object posn = Qnil;
+  Lisp_Object extra_info = Qnil;
+  int wx, wy;
+
+  /* Set `window' to the window under frame pixel coordinates (x,y)  */
+  if (f)
+    window = window_from_coordinates (f, XINT (*x), XINT (*y),
+                                     &part, &wx, &wy, 0);
+  else
+    window = Qnil;
+
+  if (WINDOWP (window))
+    {
+      /* It's a click in window window at frame coordinates (x,y)  */
+      struct window *w = XWINDOW (window);
+      Lisp_Object string_info = Qnil;
+      int textpos = -1, rx = -1, ry = -1;
+      int dx = -1, dy = -1;
+      int width = -1, height = -1;
+      Lisp_Object object = Qnil;
+
+      /* Set event coordinates to window-relative coordinates
+        for constructing the Lisp event below.  */
+      XSETINT (*x, wx);
+      XSETINT (*y, wy);
+
+      if (part == ON_TEXT)
+       {
+         wx += WINDOW_LEFT_MARGIN_WIDTH (w);
+       }
+      else if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
+       {
+         /* Mode line or header line.  Look for a string under
+            the mouse that may have a `local-map' property.  */
+         Lisp_Object string;
+         int charpos;
+
+         posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+         rx = wx, ry = wy;
+         string = mode_line_string (w, part, &rx, &ry, &charpos,
+                                    &object, &dx, &dy, &width, &height);
+         if (STRINGP (string))
+           string_info = Fcons (string, make_number (charpos));
+         if (w == XWINDOW (selected_window))
+           textpos = PT;
+         else
+           textpos = XMARKER (w->pointm)->charpos;
+       }
+      else if (part == ON_VERTICAL_BORDER)
+       {
+         posn = Qvertical_line;
+         wx = -1;
+         dx = 0;
+         width = 1;
+       }
+      else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+       {
+         Lisp_Object string;
+         int charpos;
+
+         posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
+         rx = wx, ry = wy;
+         string = marginal_area_string (w, part, &rx, &ry, &charpos,
+                                        &object, &dx, &dy, &width, &height);
+         if (STRINGP (string))
+           string_info = Fcons (string, make_number (charpos));
+         if (part == ON_LEFT_MARGIN)
+           wx = 0;
+         else
+           wx = window_box_right_offset (w, TEXT_AREA) - 1;
+       }
+      else if (part == ON_LEFT_FRINGE)
+       {
+         posn = Qleft_fringe;
+         rx = 0;
+         dx = wx;
+         wx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+               ? 0
+               : window_box_width (w, LEFT_MARGIN_AREA));
+         dx -= wx;
+       }
+      else if (part == ON_RIGHT_FRINGE)
+       {
+         posn = Qright_fringe;
+         rx = 0;
+         dx = wx;
+         wx = (window_box_width (w, LEFT_MARGIN_AREA)
+               + window_box_width (w, TEXT_AREA)
+               + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                  ? window_box_width (w, RIGHT_MARGIN_AREA)
+                  : 0));
+         dx -= wx;
+       }
+      else
+       {
+         /* Note: We have no special posn for part == ON_SCROLL_BAR.  */
+         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
+       }
+
+      if (textpos < 0)
+       {
+         Lisp_Object string2, object2 = Qnil;
+         struct display_pos p;
+         int dx2, dy2;
+         int width2, height2;
+         string2 = buffer_posn_from_coords (w, &wx, &wy, &p,
+                                            &object2, &dx2, &dy2,
+                                            &width2, &height2);
+         textpos = CHARPOS (p.pos);
+         if (rx < 0) rx = wx;
+         if (ry < 0) ry = wy;
+         if (dx < 0) dx = dx2;
+         if (dy < 0) dy = dy2;
+         if (width < 0) width = width2;
+         if (height < 0) height = height2;
+
+         if (NILP (posn))
+           {
+             posn = make_number (textpos);
+             if (STRINGP (string2))
+               string_info = Fcons (string2,
+                                    make_number (CHARPOS (p.string_pos)));
+           }
+         if (NILP (object))
+           object = object2;
+       }
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (IMAGEP (object))
+       {
+         Lisp_Object image_map, hotspot;
+         if ((image_map = Fplist_get (XCDR (object), QCmap),
+              !NILP (image_map))
+             && (hotspot = find_hot_spot (image_map, dx, dy),
+                 CONSP (hotspot))
+             && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+           posn = XCAR (hotspot);
+       }
+#endif
+
+      /* Object info */
+      extra_info = Fcons (object,
+                         Fcons (Fcons (make_number (dx),
+                                       make_number (dy)),
+                                Fcons (Fcons (make_number (width),
+                                              make_number (height)),
+                                       Qnil)));
+
+      /* String info */
+      extra_info = Fcons (string_info,
+                         Fcons (make_number (textpos),
+                                Fcons (Fcons (make_number (rx),
+                                              make_number (ry)),
+                                       extra_info)));
+    }
+  else if (f != 0)
+    {
+      XSETFRAME (window, f);
+    }
+  else
+    {
+      window = Qnil;
+      XSETFASTINT (*x, 0);
+      XSETFASTINT (*y, 0);
+    }
+
+  return Fcons (window,
+               Fcons (posn,
+                      Fcons (Fcons (*x, *y),
+                             Fcons (make_number (time),
+                                    extra_info))));
+}
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -4790,8 +5257,17 @@ make_lispy_event (event)
     case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
       {
        Lisp_Object lispy_c;
+       int c = event->code;
 
-       XSETFASTINT (lispy_c, event->code);
+       /* Add in the other modifier bits.  We took care of ctrl_modifier
+          just above, and the shift key was taken care of by the X code,
+          and applied to control characters by make_ctrl_char.  */
+       c |= (event->modifiers
+             & (meta_modifier | alt_modifier
+                | hyper_modifier | super_modifier | ctrl_modifier));
+       /* What about the `shift' modifier ?  */
+       button_down_time = 0;
+       XSETFASTINT (lispy_c, c);
        return lispy_c;
       }
 
@@ -4809,6 +5285,7 @@ make_lispy_event (event)
                                      (sizeof (lispy_accent_keys)
                                       / sizeof (lispy_accent_keys[0])));
 
+#if 0
 #ifdef XK_kana_A
       if (event->code >= 0x400 && event->code < 0x500)
        return modify_event_symbol (event->code - 0x400,
@@ -4818,6 +5295,7 @@ make_lispy_event (event)
                                    (sizeof (lispy_kana_keys)
                                     / sizeof (lispy_kana_keys[0])));
 #endif /* XK_kana_A */
+#endif /* 0 */
 
 #ifdef ISO_FUNCTION_KEY_OFFSET
       if (event->code < FUNCTION_KEY_OFFSET
@@ -4869,24 +5347,23 @@ 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_EVENT)
          {
-           int part;
            struct frame *f = XFRAME (event->frame_or_window);
-           Lisp_Object posn;
-           Lisp_Object string_info = Qnil;
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            int row, column;
+#endif
 
            /* Ignore mouse events that were made on frame that
               have been deleted.  */
            if (! FRAME_LIVE_P (f))
              return Qnil;
 
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* EVENT->x and EVENT->y are frame-relative pixel
               coordinates at this place.  Under old redisplay, COLUMN
               and ROW are set to frame relative glyph coordinates
@@ -4895,7 +5372,6 @@ make_lispy_event (event)
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                                   &column, &row, NULL, 1);
 
-#ifndef USE_X_TOOLKIT
            /* In the non-toolkit version, clicks on the menu bar
               are ordinary button events in the event buffer.
               Distinguish them, and invoke the menu.
@@ -4929,7 +5405,7 @@ make_lispy_event (event)
                    if (NILP (string))
                      break;
                    if (column >= XINT (pos)
-                       && column < XINT (pos) + XSTRING (string)->size)
+                       && column < XINT (pos) + SCHARS (string))
                      {
                        item = AREF (items, i);
                        break;
@@ -4947,83 +5423,16 @@ make_lispy_event (event)
 
                return Fcons (item, Fcons (position, Qnil));
              }
-#endif /* not USE_X_TOOLKIT */
-
-           /* Set `window' to the window under frame pixel coordinates
-              event->x/event->y.  */
-           window = window_from_coordinates (f, XINT (event->x),
-                                             XINT (event->y), &part, 0);
-
-           if (!WINDOWP (window))
-             {
-               window = event->frame_or_window;
-               posn = Qnil;
-             }
-           else
-             {
-               /* It's a click in window window at frame coordinates
-                  event->x/ event->y.  */
-               struct window *w = XWINDOW (window);
-
-               /* Get window relative coordinates.  Original code
-                  `rounded' this to glyph boundaries.  */
-               int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
-               int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
-               /* Set event coordinates to window-relative coordinates
-                  for constructing the Lisp event below.  */
-               XSETINT (event->x, wx);
-               XSETINT (event->y, wy);
-
-               if (part == 1 || part == 3)
-                 {
-                   /* Mode line or header line.  Look for a string under
-                      the mouse that may have a `local-map' property.  */
-                   Lisp_Object string;
-                   int charpos;
-                   
-                   posn = part == 1 ? Qmode_line : Qheader_line;
-                   string = mode_line_string (w, wx, wy, part == 1, &charpos);
-                   if (STRINGP (string))
-                     string_info = Fcons (string, make_number (charpos));
-                 }
-               else if (part == 2)
-                 posn = Qvertical_line;
-               else if (part == 6 || part == 7)
-                 {
-                   int charpos;
-                   Lisp_Object object = marginal_area_string (w, wx, wy, part,
-                                                              &charpos);
-                   posn = (part == 6) ? Qleft_margin : Qright_margin;
-                   if (STRINGP (object))
-                     string_info = Fcons (object, make_number (charpos));
-                 }
-               else
-                 {
-                   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)));
-                 }
-             }
+#endif /* not USE_X_TOOLKIT && not USE_GTK */
 
-           position
-             = Fcons (window,
-                      Fcons (posn,
-                             Fcons (Fcons (event->x, event->y),
-                                    Fcons (make_number (event->timestamp),
-                                           (NILP (string_info)
-                                            ? Qnil
-                                            : Fcons (string_info, Qnil))))));
+           position = make_lispy_position (f, &event->x, &event->y,
+                                           event->timestamp);
          }
 #ifndef USE_TOOLKIT_SCROLL_BARS
        else
          {
            /* It's a scrollbar click.  */
+           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -5046,7 +5455,7 @@ make_lispy_event (event)
                                                  button + 1, Qnil);
            mouse_syms = larger_vector (mouse_syms, button + 1, Qnil);
          }
-       
+
        start_pos_ptr = &AREF (button_down_location, button);
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
@@ -5079,7 +5488,7 @@ make_lispy_event (event)
                               && ((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);
@@ -5130,13 +5539,23 @@ make_lispy_event (event)
                if (CONSP (down)
                    && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down)))
                  {
-                   xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down));
-                   ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down));
+                   xdiff = XINT (event->x) - XINT (XCAR (down));
+                   ydiff = XINT (event->y) - XINT (XCDR (down));
                  }
 
                if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz
-                   && ydiff < double_click_fuzz
-                   && ydiff > - double_click_fuzz)
+                   && ydiff < double_click_fuzz && ydiff > - double_click_fuzz
+                 /* Maybe the mouse has moved a lot, caused scrolling, and
+                    eventually ended up at the same screen position (but
+                    not buffer position) in which case it is a drag, not
+                    a click.  */
+                   /* FIXME: OTOH if the buffer position has changed
+                      because of a timer or process filter rather than
+                      because of mouse movement, it should be considered as
+                      a click.  But mouse-drag-region completely ignores
+                      this case and it hasn't caused any real problem, so
+                      it's probably OK to ignore it as well.  */
+                   && EQ (Fcar (Fcdr (start_pos)), Fcar (Fcdr (position))))
                  /* Mouse hasn't moved (much).  */
                  event->modifiers |= click_modifier;
                else
@@ -5144,7 +5563,7 @@ make_lispy_event (event)
                    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)
@@ -5185,7 +5604,114 @@ make_lispy_event (event)
        }
       }
 
-#if USE_TOOLKIT_SCROLL_BARS
+    case WHEEL_EVENT:
+      {
+       Lisp_Object position;
+       Lisp_Object head;
+
+       /* Build the position as appropriate for this mouse click.  */
+       struct frame *f = XFRAME (event->frame_or_window);
+
+       /* Ignore wheel events that were made on frame that have been
+          deleted.  */
+       if (! FRAME_LIVE_P (f))
+         return Qnil;
+
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
+
+       /* Set double or triple modifiers to indicate the wheel speed.  */
+       {
+         /* 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;
+         int is_double;
+
+         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 = (last_mouse_button < 0
+                      && (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)))));
+         if (is_double)
+           {
+             double_click_count++;
+             event->modifiers |= ((double_click_count > 2)
+                                  ? triple_modifier
+                                  : double_modifier);
+           }
+         else
+           {
+             double_click_count = 1;
+             event->modifiers |= click_modifier;
+           }
+
+         button_down_time = event->timestamp;
+         /* Use a negative value to distinguish wheel from mouse button.  */
+         last_mouse_button = -1;
+         last_mouse_x = XINT (event->x);
+         last_mouse_y = XINT (event->y);
+       }
+
+       {
+         int symbol_num;
+
+         if (event->modifiers & up_modifier)
+           {
+             /* Emit a wheel-up event.  */
+             event->modifiers &= ~up_modifier;
+             symbol_num = 0;
+           }
+         else if (event->modifiers & down_modifier)
+           {
+             /* Emit a wheel-down event.  */
+             event->modifiers &= ~down_modifier;
+             symbol_num = 1;
+           }
+         else
+           /* Every wheel event should either have the down_modifier or
+              the up_modifier set.  */
+           abort ();
+
+         /* Get the symbol we should use for the wheel event.  */
+         head = modify_event_symbol (symbol_num,
+                                     event->modifiers,
+                                     Qmouse_click,
+                                     Qnil,
+                                     lispy_wheel_names,
+                                     &wheel_syms,
+                                     ASIZE (wheel_syms));
+       }
+
+       if (event->modifiers & (double_modifier | triple_modifier))
+         return Fcons (head,
+                       Fcons (position,
+                              Fcons (make_number (double_click_count),
+                                     Qnil)));
+       else
+         return Fcons (head,
+                       Fcons (position,
+                              Qnil));
+      }
+
+
+#ifdef USE_TOOLKIT_SCROLL_BARS
 
       /* We don't have down and up events if using toolkit scroll bars,
         so make this always a click event.  Store in the `part' of
@@ -5203,7 +5729,7 @@ make_lispy_event (event)
         The incoming input_event contains in its `part' member an
         index of type `enum scroll_bar_part' which we can use as an
         index in scroll_bar_parts to get the appropriate symbol.  */
-        
+
     case SCROLL_BAR_CLICK_EVENT:
       {
        Lisp_Object position, head, window, portion_whole, part;
@@ -5221,17 +5747,21 @@ make_lispy_event (event)
 
        /* Always treat scroll bar events as clicks. */
        event->modifiers |= click_modifier;
+       event->modifiers &= ~up_modifier;
+
+       if (event->code >= ASIZE (mouse_syms))
+          mouse_syms = larger_vector (mouse_syms, event->code + 1, Qnil);
 
        /* Get the symbol we should use for the mouse click.  */
        head = modify_event_symbol (event->code,
                                    event->modifiers,
-                                   Qmouse_click, 
+                                   Qmouse_click,
                                    Vlispy_mouse_stem,
                                    NULL, &mouse_syms,
                                    XVECTOR (mouse_syms)->size);
        return Fcons (head, Fcons (position, Qnil));
       }
-      
+
 #endif /* USE_TOOLKIT_SCROLL_BARS */
 
 #ifdef WINDOWSNT
@@ -5269,7 +5799,7 @@ make_lispy_event (event)
 
          head = modify_event_symbol (button,
                                      event->modifiers,
-                                     Qmouse_click, 
+                                     Qmouse_click,
                                      Vlispy_mouse_stem,
                                      NULL, &mouse_syms,
                                      XVECTOR (mouse_syms)->size);
@@ -5278,162 +5808,38 @@ make_lispy_event (event)
                               Qnil));
        }
       }
-    case MOUSE_WHEEL_EVENT:
-      {
-       int part;
-       FRAME_PTR f = XFRAME (event->frame_or_window);
-       Lisp_Object window;
-       Lisp_Object posn;
-       Lisp_Object head, position;
-       int row, column;
-
-       /* Ignore mouse events that were made on frame that
-          have been deleted.  */
-       if (! FRAME_LIVE_P (f))
-         return Qnil;
-       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                              &column, &row, NULL, 1);
-       window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y), &part, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = event->frame_or_window;
-           posn = Qnil;
-         }
-       else
-         {
-           int pixcolumn, pixrow;
-           column -= XINT (XWINDOW (window)->left);
-           row -= XINT (XWINDOW (window)->top);
-           glyph_to_pixel_coords (XWINDOW(window), column, row,
-                                   &pixcolumn, &pixrow);
-           XSETINT (event->x, pixcolumn);
-           XSETINT (event->y, pixrow);
-
-           if (part == 1)
-             posn = Qmode_line;
-           else if (part == 2)
-             posn = Qvertical_line;
-           else if (part == 3)
-             posn = Qheader_line;
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (XWINDOW (window), &column, &row,
-                                        &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-             }
-         }
-
-       {
-         Lisp_Object head, position;
-
-         position
-           = Fcons (window,
-                    Fcons (posn,
-                           Fcons (Fcons (event->x, event->y),
-                                  Fcons (make_number (event->timestamp),
-                                         Qnil))));
-
-         head = modify_event_symbol (0, event->modifiers,
-                                     Qmouse_wheel, Qnil,
-                                     lispy_mouse_wheel_names,
-                                     &mouse_wheel_syms, 1);
-         return Fcons (head,
-                       Fcons (position,
-                              /* Insert 1 here so event-click-count works.  */
-                              Fcons (make_number (1),
-                                     Fcons (make_number (event->code),
-                                            Qnil))));
-       }
-      }
 #endif /* WINDOWSNT */
 
     case DRAG_N_DROP_EVENT:
       {
-       int part;
        FRAME_PTR f;
-       Lisp_Object window;
-       Lisp_Object posn;
+       Lisp_Object head, position;
        Lisp_Object files;
 
-       /* The frame_or_window field should be a cons of the frame in
-          which the event occurred and a list of the filenames
-          dropped.  */
-       if (! CONSP (event->frame_or_window))
-         abort ();
-
-       f = XFRAME (XCAR (event->frame_or_window));
-       files = XCDR (event->frame_or_window);
+       f = XFRAME (event->frame_or_window);
+       files = event->arg;
 
        /* Ignore mouse events that were made on frames that
           have been deleted.  */
        if (! FRAME_LIVE_P (f))
          return Qnil;
 
-       window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y), &part, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = XCAR (event->frame_or_window);
-           posn = Qnil;
-         }
-       else
-         {
-           /* It's an event in window `window' at frame coordinates
-              event->x/ event->y.  */
-           struct window *w = XWINDOW (window);
-
-           /* Get window relative coordinates.  */
-           int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
-           int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
-           /* Set event coordinates to window-relative coordinates
-              for constructing the Lisp event below.  */
-           XSETINT (event->x, wx);
-           XSETINT (event->y, wy);
-
-           if (part == 1)
-             posn = Qmode_line;
-           else if (part == 2)
-             posn = Qvertical_line;
-           else if (part == 3)
-             posn = Qheader_line;
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-             }
-         }
-
-       {
-         Lisp_Object head, position;
-
-         position
-           = Fcons (window,
-                    Fcons (posn,
-                           Fcons (Fcons (event->x, event->y),
-                                  Fcons (make_number (event->timestamp),
-                                         Qnil))));
-
-         head = modify_event_symbol (0, event->modifiers,
-                                     Qdrag_n_drop, Qnil,
-                                     lispy_drag_n_drop_names,
-                                     &drag_n_drop_syms, 1);
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (files,
-                                     Qnil)));
-       }
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
+
+       head = modify_event_symbol (0, event->modifiers,
+                                   Qdrag_n_drop, Qnil,
+                                   lispy_drag_n_drop_names,
+                                   &drag_n_drop_syms, 1);
+       return Fcons (head,
+                     Fcons (position,
+                            Fcons (files,
+                                   Qnil)));
       }
 #endif /* HAVE_MOUSE */
 
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+    || defined (USE_GTK)
     case MENU_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
@@ -5443,6 +5849,12 @@ make_lispy_event (event)
       return event->arg;
 #endif
 
+    case SELECT_WINDOW_EVENT:
+      /* Make an event (select-window (WINDOW)).  */
+      return Fcons (Qselect_window,
+                   Fcons (Fcons (event->frame_or_window, Qnil),
+                          Qnil));
+
     case TOOL_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
@@ -5456,10 +5868,23 @@ make_lispy_event (event)
     case USER_SIGNAL_EVENT:
       /* A user signal.  */
       return *lispy_user_signals[event->code];
-      
+
     case SAVE_SESSION_EVENT:
       return Qsave_session;
-      
+
+#ifdef MAC_OS
+    case MAC_APPLE_EVENT:
+      {
+       Lisp_Object spec[2];
+
+       spec[0] = event->x;
+       spec[1] = event->y;
+       return Fcons (Qmac_apple_event,
+                     Fcons (Fvector (2, spec),
+                            Fcons (event->arg, Qnil)));
+      }
+#endif
+
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -5495,60 +5920,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Or is it an ordinary mouse movement?  */
   else
     {
-      int area;
-      Lisp_Object window;
-      Lisp_Object posn;
+      Lisp_Object position;
 
-      if (frame)
-       /* It's in a frame; which window on that frame?  */
-       window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
-      else
-       window = Qnil;
-
-      if (WINDOWP (window))
-       {
-         struct window *w = XWINDOW (window);
-         int wx, wy;
-         
-         /* Get window relative coordinates.  */
-         wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
-         wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
-         XSETINT (x, wx);
-         XSETINT (y, wy);
-         
-         if (area == 1)
-           posn = Qmode_line;
-         else if (area == 2)
-           posn = Qvertical_line;
-         else if (area == 3)
-           posn = Qheader_line;
-         else
-           {
-             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)
-       {
-         XSETFRAME (window, frame);
-         posn = Qnil;
-       }
-      else
-       {
-         window = Qnil;
-         posn = Qnil;
-         XSETFASTINT (x, 0);
-         XSETFASTINT (y, 0);
-       }
+      position = make_lispy_position (frame, &x, &y, time);
 
       return Fcons (Qmouse_movement,
-                   Fcons (Fcons (window,
-                                 Fcons (posn,
-                                        Fcons (Fcons (x, y),
-                                               Fcons (make_number (time),
-                                                      Qnil)))),
+                   Fcons (position,
                           Qnil));
     }
 }
@@ -5578,16 +5955,16 @@ parse_modifiers_uncached (symbol, modifier_end)
      Lisp_Object symbol;
      int *modifier_end;
 {
-  struct Lisp_String *name;
+  Lisp_Object name;
   int i;
   int modifiers;
 
   CHECK_SYMBOL (symbol);
 
   modifiers = 0;
-  name = XSTRING (SYMBOL_NAME (symbol));
+  name = SYMBOL_NAME (symbol);
 
-  for (i = 0; i+2 <= STRING_BYTES (name); )
+  for (i = 0; i+2 <= SBYTES (name); )
     {
       int this_mod_end = 0;
       int this_mod = 0;
@@ -5596,7 +5973,7 @@ parse_modifiers_uncached (symbol, modifier_end)
         Check that the word appears, but don't check what follows it.
         Set this_mod and this_mod_end to record what we find.  */
 
-      switch (name->data[i])
+      switch (SREF (name, i))
        {
 #define SINGLE_LETTER_MOD(BIT)                         \
          (this_mod_end = i + 1, this_mod = BIT)
@@ -5626,6 +6003,26 @@ parse_modifiers_uncached (symbol, modifier_end)
          break;
 
 #undef SINGLE_LETTER_MOD
+
+#define MULTI_LETTER_MOD(BIT, NAME, LEN)                       \
+         if (i + LEN + 1 <= SBYTES (name)                      \
+             && ! strncmp (SDATA (name) + i, NAME, LEN))       \
+           {                                                   \
+             this_mod_end = i + LEN;                           \
+             this_mod = BIT;                                   \
+           }
+
+       case 'd':
+         MULTI_LETTER_MOD (drag_modifier, "drag", 4);
+         MULTI_LETTER_MOD (down_modifier, "down", 4);
+         MULTI_LETTER_MOD (double_modifier, "double", 6);
+         break;
+
+       case 't':
+         MULTI_LETTER_MOD (triple_modifier, "triple", 6);
+         break;
+#undef MULTI_LETTER_MOD
+
        }
 
       /* If we found no modifier, stop looking for them.  */
@@ -5634,8 +6031,8 @@ parse_modifiers_uncached (symbol, modifier_end)
 
       /* Check there is a dash after the modifier, so that it
         really is a modifier.  */
-      if (this_mod_end >= STRING_BYTES (name)
-         || name->data[this_mod_end] != '-')
+      if (this_mod_end >= SBYTES (name)
+         || SREF (name, this_mod_end) != '-')
        break;
 
       /* This modifier is real; look for another.  */
@@ -5646,9 +6043,9 @@ parse_modifiers_uncached (symbol, modifier_end)
   /* Should we include the `click' modifier?  */
   if (! (modifiers & (down_modifier | drag_modifier
                      | double_modifier | triple_modifier))
-      && i + 7 == STRING_BYTES (name)
-      && strncmp (name->data + i, "mouse-", 6) == 0
-      && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9'))
+      && i + 7 == SBYTES (name)
+      && strncmp (SDATA (name) + i, "mouse-", 6) == 0
+      && ('0' <= SREF (name, i + 6) && SREF (name, i + 6) <= '9'))
     modifiers |= click_modifier;
 
   if (modifier_end)
@@ -5703,8 +6100,8 @@ apply_modifiers_uncached (modifiers, base, base_len, base_len_byte)
 
     new_name = make_uninit_multibyte_string (mod_len + base_len,
                                             mod_len + base_len_byte);
-    bcopy (new_mods, XSTRING (new_name)->data,        mod_len);
-    bcopy (base,     XSTRING (new_name)->data + mod_len, base_len_byte);
+    bcopy (new_mods, SDATA (new_name),        mod_len);
+    bcopy (base,     SDATA (new_name) + mod_len, base_len_byte);
 
     return Fintern (new_name, Qnil);
   }
@@ -5762,11 +6159,11 @@ parse_modifiers (symbol)
       Lisp_Object unmodified;
       Lisp_Object mask;
 
-      unmodified = Fintern (make_string (XSTRING (SYMBOL_NAME (symbol))->data + end,
-                                        STRING_BYTES (XSTRING (SYMBOL_NAME (symbol))) - end),
+      unmodified = Fintern (make_string (SDATA (SYMBOL_NAME (symbol)) + end,
+                                        SBYTES (SYMBOL_NAME (symbol)) - end),
                            Qnil);
 
-      if (modifiers & ~VALMASK)
+      if (modifiers & ~INTMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -5803,7 +6200,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 &= VALMASK;
+  modifiers &= INTMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -5816,20 +6213,23 @@ apply_modifiers (modifiers, base)
     {
       /* We have to create the symbol ourselves.  */
       new_symbol = apply_modifiers_uncached (modifiers,
-                                            XSTRING (SYMBOL_NAME (base))->data,
-                                            XSTRING (SYMBOL_NAME (base))->size,
-                                            STRING_BYTES (XSTRING (SYMBOL_NAME (base))));
+                                            SDATA (SYMBOL_NAME (base)),
+                                            SCHARS (SYMBOL_NAME (base)),
+                                            SBYTES (SYMBOL_NAME (base)));
 
       /* Add the new symbol to the base's cache.  */
       entry = Fcons (index, new_symbol);
       Fput (base, Qmodifier_cache, Fcons (entry, cache));
 
-      /* We have the parsing info now for free, so add it to the caches.  */
-      XSETFASTINT (index, modifiers);
-      Fput (new_symbol, Qevent_symbol_element_mask,
-           Fcons (base, Fcons (index, Qnil)));
-      Fput (new_symbol, Qevent_symbol_elements,
-           Fcons (base, lispy_modifier_list (modifiers)));
+      /* We have the parsing info now for free, so we could add it to
+        the caches:
+         XSETFASTINT (index, modifiers);
+         Fput (new_symbol, Qevent_symbol_element_mask,
+               Fcons (base, Fcons (index, Qnil)));
+         Fput (new_symbol, Qevent_symbol_elements,
+               Fcons (base, lispy_modifier_list (modifiers)));
+        Sadly, this is only correct if `base' is indeed a base event,
+        which is not necessarily the case.  -stef  */
     }
 
   /* Make sure this symbol is of the same kind as BASE.
@@ -5956,10 +6356,10 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem,
        value = Fcdr_safe (Fassq (symbol_int, name_alist_or_stem));
       else if (STRINGP (name_alist_or_stem))
        {
-         int len = STRING_BYTES (XSTRING (name_alist_or_stem));
+         int len = SBYTES (name_alist_or_stem);
          char *buf = (char *) alloca (len + 50);
-         sprintf (buf, "%s-%d", XSTRING (name_alist_or_stem)->data,
-                  XINT (symbol_int) + 1);
+         sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
+                  (long) XINT (symbol_int) + 1);
          value = intern (buf);
        }
       else if (name_table != 0 && name_table[symbol_num])
@@ -6039,8 +6439,8 @@ has the same base event type and all the specified modifiers.  */)
     }
 
   /* Let the symbol A refer to the character A.  */
-  if (SYMBOLP (base) && XSTRING (SYMBOL_NAME (base))->size == 1)
-    XSETINT (base, XSTRING (SYMBOL_NAME (base))->data[0]);
+  if (SYMBOLP (base) && SCHARS (SYMBOL_NAME (base)) == 1)
+    XSETINT (base, SREF (SYMBOL_NAME (base), 0));
 
   if (INTEGERP (base))
     {
@@ -6075,17 +6475,17 @@ static int
 parse_solitary_modifier (symbol)
      Lisp_Object symbol;
 {
-  struct Lisp_String *name = XSTRING (SYMBOL_NAME (symbol));
+  Lisp_Object name = SYMBOL_NAME (symbol);
 
-  switch (name->data[0])
+  switch (SREF (name, 0))
     {
 #define SINGLE_LETTER_MOD(BIT)                         \
-      if (STRING_BYTES (name) == 1)                    \
+      if (SBYTES (name) == 1)                          \
        return BIT;
 
 #define MULTI_LETTER_MOD(BIT, NAME, LEN)               \
-      if (LEN == STRING_BYTES (name)                   \
-         && ! strncmp (name->data, NAME, LEN))         \
+      if (LEN == SBYTES (name)                         \
+         && ! strncmp (SDATA (name), NAME, LEN))       \
        return BIT;
 
     case 'A':
@@ -6183,18 +6583,20 @@ lucid_event_type_list_p (object)
    but works even if FIONREAD does not exist.
    (In fact, this may actually read some input.)
 
-   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
-   If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
+   If READABLE_EVENTS_DO_TIMERS_NOW is set in FLAGS, actually run
+   timer events that are ripe.
+   If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal
+   events (FOCUS_IN_EVENT).
+   If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
+   movements and toolkit scroll bar thumb drags. */
 
 static void
-get_filtered_input_pending (addr, do_timers_now, filter_events)
+get_input_pending (addr, flags)
      int *addr;
-     int do_timers_now;
-     int filter_events;
+     int flags;
 {
   /* First of all, have we already counted some input?  */
-  *addr = (!NILP (Vquit_flag)
-           || readable_filtered_events (do_timers_now, filter_events));
+  *addr = (!NILP (Vquit_flag) || readable_events (flags));
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -6202,23 +6604,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events)
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = (!NILP (Vquit_flag)
-           || readable_filtered_events (do_timers_now, filter_events));
-}
-
-/* Store into *addr a value nonzero if terminal input chars are available.
-   Serves the purpose of ioctl (0, FIONREAD, addr)
-   but works even if FIONREAD does not exist.
-   (In fact, this may actually read some input.)
-
-   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
-
-static void
-get_input_pending (addr, do_timers_now)
-     int *addr;
-     int do_timers_now;
-{
-  get_filtered_input_pending (addr, do_timers_now, 0);
+  *addr = (!NILP (Vquit_flag) || readable_events (flags));
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -6260,6 +6646,7 @@ record_asynch_buffer_change ()
 {
   struct input_event event;
   Lisp_Object tem;
+  EVENT_INIT (event);
 
   event.kind = BUFFER_SWITCH_EVENT;
   event.frame_or_window = Qnil;
@@ -6314,13 +6701,26 @@ static int
 read_avail_input (expected)
      int expected;
 {
-  struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
-  int nread;
+  int nread = 0;
 
   if (read_socket_hook)
-    /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
+    {
+      int nr;
+      struct input_event hold_quit;
+
+      EVENT_INIT (hold_quit);
+      hold_quit.kind = NO_EVENT;
+
+      /* No need for FIONREAD or fcntl; just say don't wait.  */
+      while (nr = (*read_socket_hook) (input_fd, expected, &hold_quit), nr > 0)
+       {
+         nread += nr;
+         expected = 0;
+       }
+      if (hold_quit.kind != NO_EVENT)
+       kbd_buffer_store_event (&hold_quit);
+    }
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -6347,13 +6747,18 @@ read_avail_input (expected)
        /* ??? Is it really right to send the signal just to this process
           rather than to the whole process group?
           Perhaps on systems with FIONREAD Emacs is alone in its group.  */
-       kill (getpid (), SIGHUP);
+       {
+         if (! noninteractive)
+           kill (getpid (), SIGHUP);
+         else
+           n_to_read = 0;
+       }
       if (n_to_read == 0)
        return 0;
       if (n_to_read > sizeof cbuf)
        n_to_read = sizeof cbuf;
 #else /* no FIONREAD */
-#if defined (USG) || defined (DGUX)
+#if defined (USG) || defined (DGUX) || defined(CYGWIN)
       /* Read some input if available, but don't wait.  */
       n_to_read = sizeof cbuf;
       fcntl (input_fd, F_SETFL, O_NDELAY);
@@ -6410,53 +6815,72 @@ read_avail_input (expected)
             );
 
 #ifndef FIONREAD
-#if defined (USG) || defined (DGUX)
+#if defined (USG) || defined (DGUX) || defined (CYGWIN)
       fcntl (input_fd, F_SETFL, 0);
-#endif /* USG or DGUX */
+#endif /* USG or DGUX or CYGWIN */
 #endif /* no FIONREAD */
       for (i = 0; i < nread; i++)
        {
-         buf[i].kind = ASCII_KEYSTROKE_EVENT;
-         buf[i].modifiers = 0;
+         struct input_event buf;
+         EVENT_INIT (buf);
+         buf.kind = ASCII_KEYSTROKE_EVENT;
+         buf.modifiers = 0;
          if (meta_key == 1 && (cbuf[i] & 0x80))
-           buf[i].modifiers = meta_modifier;
+           buf.modifiers = meta_modifier;
          if (meta_key != 2)
            cbuf[i] &= ~0x80;
 
-         buf[i].code = cbuf[i];
-         buf[i].frame_or_window = selected_frame;
-         buf[i].arg = Qnil;
-       }
-    }
+         buf.code = cbuf[i];
+         buf.frame_or_window = selected_frame;
+         buf.arg = Qnil;
 
-  /* Scan the chars for C-g and store them in kbd_buffer.  */
-  for (i = 0; i < nread; i++)
-    {
-      kbd_buffer_store_event (&buf[i]);
-      /* Don't look at input that follows a C-g too closely.
-        This reduces lossage due to autorepeat on C-g.  */
-      if (buf[i].kind == ASCII_KEYSTROKE_EVENT
-         && buf[i].code == quit_char)
-       break;
+         kbd_buffer_store_event (&buf);
+         /* Don't look at input that follows a C-g too closely.
+            This reduces lossage due to autorepeat on C-g.  */
+         if (buf.kind == ASCII_KEYSTROKE_EVENT
+             && buf.code == quit_char)
+           break;
+       }
     }
 
   return nread;
 }
 #endif /* not VMS */
 \f
+void
+handle_async_input ()
+{
+#ifdef BSD4_1
+  extern int select_alarmed;
+#endif
+
+  interrupt_input_pending = 0;
+
+  while (1)
+    {
+      int nread;
+      nread = read_avail_input (1);
+      /* -1 means it's not ok to read the input now.
+        UNBLOCK_INPUT will read it later; now, avoid infinite loop.
+        0 means there was no keyboard input available.  */
+      if (nread <= 0)
+       break;
+
+#ifdef BSD4_1
+      select_alarmed = 1;  /* Force the select emulator back to life */
+#endif
+    }
+}
+
 #ifdef SIGIO   /* for entire page */
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 
-SIGTYPE
+static SIGTYPE
 input_available_signal (signo)
      int signo;
 {
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
-#ifdef BSD4_1
-  extern int select_alarmed;
-#endif
-
 #if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
@@ -6467,23 +6891,18 @@ input_available_signal (signo)
   sigisheld (SIGIO);
 #endif
 
+#ifdef SYNC_INPUT
+  interrupt_input_pending = 1;
+#else
+  SIGNAL_THREAD_CHECK (signo);
+#endif
+
   if (input_available_clear_time)
     EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
 
-  while (1)
-    {
-      int nread;
-      nread = read_avail_input (1);
-      /* -1 means it's not ok to read the input now.
-        UNBLOCK_INPUT will read it later; now, avoid infinite loop.
-        0 means there was no keyboard input available.  */
-      if (nread <= 0)
-       break;
-
-#ifdef BSD4_1
-      select_alarmed = 1;  /* Force the select emulator back to life */
+#ifndef SYNC_INPUT
+  handle_async_input ();
 #endif
-    }
 
 #ifdef BSD4_1
   sigfree ();
@@ -6502,14 +6921,14 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (getpid (), SIGIO);
+  handle_async_input ();
 #endif
 }
 
 
 \f
-static void menu_bar_item P_ ((Lisp_Object, Lisp_Object));
-static void menu_bar_one_keymap P_ ((Lisp_Object));
+static void menu_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*));
+static Lisp_Object menu_bar_one_keymap_changed_items;
 
 /* These variables hold the vector under construction within
    menu_bar_items and its subroutines, and the current index
@@ -6544,8 +6963,6 @@ menu_bar_items (old)
 
   int i;
 
-  struct gcpro gcpro1;
-
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -6561,8 +6978,6 @@ menu_bar_items (old)
     menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
   menu_bar_items_index = 0;
 
-  GCPRO1 (menu_bar_items_vector);
-
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -6613,7 +7028,10 @@ menu_bar_items (old)
        def = get_keymap (access_keymap (maps[mapno], Qmenu_bar, 1, 0, 1),
                          0, 1);
        if (CONSP (def))
-         menu_bar_one_keymap (def);
+         {
+           menu_bar_one_keymap_changed_items = Qnil;
+           map_keymap (def, menu_bar_item, Qnil, NULL, 1);
+         }
       }
 
   /* Move to the end those items that should be at the end.  */
@@ -6663,52 +7081,18 @@ menu_bar_items (old)
   menu_bar_items_index = i;
 
   Vinhibit_quit = oquit;
-  UNGCPRO;
   return menu_bar_items_vector;
 }
 \f
-/* Scan one map KEYMAP, accumulating any menu items it defines
-   in menu_bar_items_vector.  */
-
-static Lisp_Object menu_bar_one_keymap_changed_items;
-
-static void
-menu_bar_one_keymap (keymap)
-     Lisp_Object keymap;
-{
-  Lisp_Object tail, item;
-
-  menu_bar_one_keymap_changed_items = Qnil;
-
-  /* Loop over all keymap entries that have menu strings.  */
-  for (tail = keymap; CONSP (tail); tail = XCDR (tail))
-    {
-      item = XCAR (tail);
-      if (CONSP (item))
-       menu_bar_item (XCAR (item), XCDR (item));
-      else if (VECTORP (item))
-       {
-         /* Loop over the char values represented in the vector.  */
-         int len = XVECTOR (item)->size;
-         int c;
-         for (c = 0; c < len; c++)
-           {
-             Lisp_Object character;
-             XSETFASTINT (character, c);
-             menu_bar_item (character, XVECTOR (item)->contents[c]);
-           }
-       }
-    }
-}
-
 /* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
    If there's already an item for KEY, add this DEF to it.  */
 
 Lisp_Object item_properties;
 
 static void
-menu_bar_item (key, item)
-     Lisp_Object key, item;
+menu_bar_item (key, item, dummy1, dummy2)
+     Lisp_Object key, item, dummy1;
+     void *dummy2;
 {
   struct gcpro gcpro1;
   int i;
@@ -6781,7 +7165,10 @@ menu_bar_item (key, item)
     {
       Lisp_Object old;
       old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
-      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old);
+      /* If the new and the old items are not both keymaps,
+        the lookup will only find `item'.  */
+      item = Fcons (item, KEYMAPP (item) && KEYMAPP (XCAR (old)) ? old : Qnil);
+      XVECTOR (menu_bar_items_vector)->contents[i + 2] = item;
     }
 }
 \f
@@ -6798,7 +7185,7 @@ menu_item_eval_property_1 (arg)
   return Qnil;
 }
 
-/* Evaluate an expression and return the result (or nil if something 
+/* Evaluate an expression and return the result (or nil if something
    went wrong).  Used to evaluate dynamic parts of menu items.  */
 Lisp_Object
 menu_item_eval_property (sexpr)
@@ -6851,7 +7238,7 @@ parse_menu_item (item, notreal, inmenubar)
   for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
     AREF (item_properties, i) = Qnil;
   AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
-        
+
   /* Save the item here to protect it from GC.  */
   AREF (item_properties, ITEM_PROPERTY_ITEM) = item;
 
@@ -6871,7 +7258,7 @@ parse_menu_item (item, notreal, inmenubar)
          start = item;
          item = XCDR (item);
        }
-         
+
       /* Maybe key binding cache.  */
       if (CONSP (item) && CONSP (XCAR (item))
          && (NILP (XCAR (XCAR (item)))
@@ -6880,7 +7267,7 @@ parse_menu_item (item, notreal, inmenubar)
          cachelist = XCAR (item);
          item = XCDR (item);
        }
-      
+
       /* This is the real definition--the function to run.  */
       AREF (item_properties, ITEM_PROPERTY_DEF) = item;
 
@@ -6888,7 +7275,9 @@ parse_menu_item (item, notreal, inmenubar)
       if (SYMBOLP (item))
        {
          tem = Fget (item, Qmenu_enable);
-         if (!NILP (tem))
+         if (!NILP (Venable_disabled_menus_and_buttons))
+           AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
+         else if (!NILP (tem))
            AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
        }
     }
@@ -6917,7 +7306,12 @@ parse_menu_item (item, notreal, inmenubar)
              item = XCDR (item);
 
              if (EQ (tem, QCenable))
-               AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
+               {
+                 if (!NILP (Venable_disabled_menus_and_buttons))
+                   AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
+                 else
+                   AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
+               }
              else if (EQ (tem, QCvisible) && !notreal)
                {
                  /* If got a visible property and that evaluates to nil
@@ -6976,7 +7370,7 @@ parse_menu_item (item, notreal, inmenubar)
        return 0;
       AREF (item_properties, ITEM_PROPERTY_NAME) = item_string;
     }
-     
+
   /* If got a filter apply it on definition.  */
   def = AREF (item_properties, ITEM_PROPERTY_DEF);
   if (!NILP (filter))
@@ -7004,7 +7398,7 @@ parse_menu_item (item, notreal, inmenubar)
      is OK in a submenu but not in the menubar.  */
   if (NILP (def))
     return (inmenubar ? 0 : 1);
+
   /* See if this is a separate pane or a submenu.  */
   def = AREF (item_properties, ITEM_PROPERTY_DEF);
   tem = get_keymap (def, 0, 1);
@@ -7015,7 +7409,7 @@ parse_menu_item (item, notreal, inmenubar)
       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.  */
@@ -7042,7 +7436,7 @@ parse_menu_item (item, notreal, inmenubar)
          XSETCAR (cachelist, Qt);
        }
     }
-  
+
   tem = XCAR (cachelist);
   if (!EQ (tem, Qt))
     {
@@ -7061,9 +7455,7 @@ parse_menu_item (item, notreal, inmenubar)
       else
        def = AREF (item_properties, ITEM_PROPERTY_DEF);
 
-      if (!update_menu_bindings)
-       chkcache = 0;
-      else if (NILP (XCAR (cachelist))) /* Have no saved key.  */
+      if (NILP (XCAR (cachelist))) /* Have no saved key.  */
        {
          if (newcache          /* Always check first time.  */
              /* Should we check everything when precomputing key
@@ -7113,7 +7505,7 @@ parse_menu_item (item, notreal, inmenubar)
       newcache = chkcache;
       if (chkcache)
        {
-         tem = Fkey_description (tem);
+         tem = Fkey_description (tem, Qnil);
          if (CONSP (prefix))
            {
              if (STRINGP (XCAR (prefix)))
@@ -7150,7 +7542,7 @@ parse_menu_item (item, notreal, inmenubar)
     }
   */
 
-  /* Handle radio buttons or toggle boxes.  */ 
+  /* Handle radio buttons or toggle boxes.  */
   tem = AREF (item_properties, ITEM_PROPERTY_SELECTED);
   if (!NILP (tem))
     AREF (item_properties, ITEM_PROPERTY_SELECTED)
@@ -7188,7 +7580,7 @@ Lisp_Object QCimage;
 /* Function prototypes.  */
 
 static void init_tool_bar_items P_ ((Lisp_Object));
-static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*));
 static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
 static void append_tool_bar_item P_ ((void));
 
@@ -7217,13 +7609,13 @@ tool_bar_items (reuse, nitems)
      avoids risk of specpdl overflow.  */
   oquit = Vinhibit_quit;
   Vinhibit_quit = Qt;
-  
+
   /* Initialize tool_bar_items_vector and protect it from GC.  */
   init_tool_bar_items (reuse);
 
   /* Build list of keymaps in maps.  Set nmaps to the number of maps
      to process.  */
-  
+
   /* Should overriding-terminal-local-map and overriding-local-map apply?  */
   if (!NILP (Voverriding_local_map_menu_flag))
     {
@@ -7266,17 +7658,7 @@ tool_bar_items (reuse, nitems)
 
        keymap = get_keymap (access_keymap (maps[i], Qtool_bar, 1, 0, 1), 0, 1);
        if (CONSP (keymap))
-         {
-           Lisp_Object tail;
-           
-           /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
-           for (tail = keymap; CONSP (tail); tail = XCDR (tail))
-             {
-               Lisp_Object keydef = XCAR (tail);
-               if (CONSP (keydef))
-                 process_tool_bar_item (XCAR (keydef), XCDR (keydef));
-             }
-         }
+         map_keymap (keymap, process_tool_bar_item, Qnil, NULL, 1);
       }
 
   Vinhibit_quit = oquit;
@@ -7288,8 +7670,9 @@ tool_bar_items (reuse, nitems)
 /* Process the definition of KEY which is DEF.  */
 
 static void
-process_tool_bar_item (key, def)
-     Lisp_Object key, def;
+process_tool_bar_item (key, def, data, args)
+     Lisp_Object key, def, data;
+     void *args;
 {
   int i;
   extern Lisp_Object Qundefined;
@@ -7306,7 +7689,7 @@ process_tool_bar_item (key, def)
       for (i = 0; i < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS)
        {
          Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i;
-         
+
          if (EQ (key, v[TOOL_BAR_ITEM_KEY]))
            {
              if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS)
@@ -7332,41 +7715,41 @@ process_tool_bar_item (key, def)
    invalid.
 
    ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
-   
+
    CAPTION is the caption of the item,  If it's not a string, it is
    evaluated to get a string.
-   
+
    BINDING is the tool bar item's binding.  Tool-bar items with keymaps
    as binding are currently ignored.
 
    The following properties are recognized:
 
    - `:enable FORM'.
-   
+
    FORM is evaluated and specifies whether the tool bar item is
    enabled or disabled.
-   
+
    - `:visible FORM'
-   
+
    FORM is evaluated and specifies whether the tool bar item is visible.
-   
+
    - `:filter FUNCTION'
 
    FUNCTION is invoked with one parameter `(quote BINDING)'.  Its
    result is stored as the new binding.
-   
+
    - `:button (TYPE SELECTED)'
 
    TYPE must be one of `:radio' or `:toggle'.  SELECTED is evaluated
    and specifies whether the button is selected (pressed) or not.
-   
+
    - `:image IMAGES'
 
    IMAGES is either a single image specification or a vector of four
    image specifications.  See enum tool_bar_item_images.
-   
+
    - `:help HELP-STRING'.
-   
+
    Gives a help string to display for the tool bar item.  */
 
 static int
@@ -7400,11 +7783,11 @@ parse_tool_bar_item (key, item)
   else
     tool_bar_item_properties
       = Fmake_vector (make_number (TOOL_BAR_ITEM_NSLOTS), Qnil);
-  
+
   /* Set defaults.  */
   PROP (TOOL_BAR_ITEM_KEY) = key;
   PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
-        
+
   /* Get the caption of the item.  If the caption is not a string,
      evaluate it to get a string.  If we don't get a string, skip this
      item.  */
@@ -7439,8 +7822,13 @@ parse_tool_bar_item (key, item)
       value = XCAR (XCDR (item));
 
       if (EQ (key, QCenable))
-       /* `:enable FORM'.  */
-       PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+       {
+         /* `:enable FORM'.  */
+         if (!NILP (Venable_disabled_menus_and_buttons))
+           PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
+         else
+           PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+       }
       else if (EQ (key, QCvisible))
        {
          /* `:visible FORM'.  If got a visible property and that
@@ -7491,13 +7879,13 @@ parse_tool_bar_item (key, item)
     PROP (TOOL_BAR_ITEM_ENABLED_P)
       = menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P));
 
-  /* Handle radio buttons or toggle boxes.  */ 
+  /* Handle radio buttons or toggle boxes.  */
   if (!NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)))
     PROP (TOOL_BAR_ITEM_SELECTED_P)
       = menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P));
 
   return 1;
-  
+
 #undef PROP
 }
 
@@ -7524,7 +7912,7 @@ static void
 append_tool_bar_item ()
 {
   Lisp_Object *to, *from;
-  
+
   /* Enlarge tool_bar_items_vector if necessary.  */
   if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS
       >= XVECTOR (tool_bar_items_vector)->size)
@@ -7579,7 +7967,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
      int *used_mouse_menu;
 {
   int mapno;
-  register Lisp_Object name;
+  register Lisp_Object name = Qnil;
 
   if (used_mouse_menu)
     *used_mouse_menu = 0;
@@ -7681,7 +8069,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   int mapno;
   register Lisp_Object name;
   int nlength;
-  int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
+  /* FIXME: Use the minibuffer's frame width.  */
+  int width = FRAME_COLS (SELECTED_FRAME ()) - 4;
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
@@ -7720,8 +8109,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
     return Qnil;
 
   /* Prompt string always starts with map's prompt, and a space.  */
-  strcpy (menu, XSTRING (name)->data);
-  nlength = STRING_BYTES (XSTRING (name));
+  strcpy (menu, SDATA (name));
+  nlength = SBYTES (name);
   menu[nlength++] = ':';
   menu[nlength++] = ' ';
   menu[nlength] = 0;
@@ -7799,8 +8188,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
 
                  upcased_event = Fupcase (event);
                  downcased_event = Fdowncase (event);
-                 char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
-                                 || XINT (downcased_event) == XSTRING (s)->data[0]);
+                 char_matches = (XINT (upcased_event) == SREF (s, 0)
+                                 || XINT (downcased_event) == SREF (s, 0));
                  if (! char_matches)
                    desc = Fsingle_key_description (event, Qnil);
 
@@ -7825,12 +8214,12 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
                        tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
                      s = concat2 (tem, s);
                    }
-                 
+
 
                  /* If we have room for the prompt string, add it to this line.
                     If this is the first on the line, always add it.  */
-                 if ((XSTRING (s)->size + i + 2
-                      + (char_matches ? 0 : XSTRING (desc)->size + 3))
+                 if ((SCHARS (s) + i + 2
+                      + (char_matches ? 0 : SCHARS (desc) + 3))
                      < width
                      || !notfirst)
                    {
@@ -7850,20 +8239,20 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
                      if (! char_matches)
                        {
                          /* Add as much of string as fits.  */
-                         thiswidth = XSTRING (desc)->size;
+                         thiswidth = SCHARS (desc);
                          if (thiswidth + i > width)
                            thiswidth = width - i;
-                         bcopy (XSTRING (desc)->data, menu + i, thiswidth);
+                         bcopy (SDATA (desc), menu + i, thiswidth);
                          i += thiswidth;
                          strcpy (menu + i, " = ");
                          i += 3;
                        }
 
                      /* Add as much of string as fits.  */
-                     thiswidth = XSTRING (s)->size;
+                     thiswidth = SCHARS (s);
                      if (thiswidth + i > width)
                        thiswidth = width - i;
-                     bcopy (XSTRING (s)->data, menu + i, thiswidth);
+                     bcopy (SDATA (s), menu + i, thiswidth);
                      i += thiswidth;
                      menu[i] = 0;
                    }
@@ -7888,7 +8277,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
        }
 
       /* Prompt with that and read response.  */
-      message2_nolog (menu, strlen (menu), 
+      message2_nolog (menu, strlen (menu),
                      ! NILP (current_buffer->enable_multibyte_characters));
 
       /* Make believe its not a keyboard macro in case the help char
@@ -7943,20 +8332,13 @@ follow_key (key, nmaps, current, defs, next)
      int nmaps;
 {
   int i, first_binding;
-  int did_meta = 0;
 
   first_binding = nmaps;
   for (i = nmaps - 1; i >= 0; i--)
     {
       if (! NILP (current[i]))
        {
-         Lisp_Object map;
-         if (did_meta)
-           map = defs[i];
-         else
-           map = current[i];
-
-         defs[i] = access_keymap (map, key, 1, 0, 1);
+         defs[i] = access_keymap (current[i], key, 1, 0, 1);
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -7972,6 +8354,128 @@ follow_key (key, nmaps, current, defs, next)
   return first_binding;
 }
 
+/* Structure used to keep track of partial application of key remapping
+   such as Vfunction_key_map and Vkey_translation_map.  */
+typedef struct keyremap
+{
+  Lisp_Object map, parent;
+  int start, end;
+} keyremap;
+
+/* Lookup KEY in MAP.
+   MAP is a keymap mapping keys to key vectors or functions.
+   If the mapping is a function and DO_FUNCTION is non-zero, then
+   the function is called with PROMPT as parameter and its return
+   value is used as the return value of this function (after checking
+   that it is indeed a vector).  */
+
+static Lisp_Object
+access_keymap_keyremap (map, key, prompt, do_funcall)
+     Lisp_Object map, key, prompt;
+     int do_funcall;
+{
+  Lisp_Object next;
+
+  next = access_keymap (map, key, 1, 0, 1);
+
+  /* Handle symbol with autoload definition.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && CONSP (XSYMBOL (next)->function)
+      && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
+    do_autoload (XSYMBOL (next)->function, next);
+
+  /* Handle a symbol whose function definition is a keymap
+     or an array.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && (!NILP (Farrayp (XSYMBOL (next)->function))
+         || KEYMAPP (XSYMBOL (next)->function)))
+    next = XSYMBOL (next)->function;
+
+  /* If the keymap gives a function, not an
+     array, then call the function with one arg and use
+     its value instead.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next)) && do_funcall)
+    {
+      Lisp_Object tem;
+      tem = next;
+
+      next = call1 (next, prompt);
+      /* If the function returned something invalid,
+        barf--don't ignore it.
+        (To ignore it safely, we would need to gcpro a bunch of
+        other variables.)  */
+      if (! (VECTORP (next) || STRINGP (next)))
+       error ("Function %s returns invalid key sequence", tem);
+    }
+  return next;
+}
+
+/* Do one step of the key remapping used for function-key-map and
+   key-translation-map:
+   KEYBUF is the buffer holding the input events.
+   BUFSIZE is its maximum size.
+   FKEY is a pointer to the keyremap structure to use.
+   INPUT is the index of the last element in KEYBUF.
+   DOIT if non-zero says that the remapping can actually take place.
+   DIFF is used to return the number of keys added/removed by the remapping.
+   PARENT is the root of the keymap.
+   PROMPT is the prompt to use if the remapping happens through a function.
+   The return value is non-zero if the remapping actually took place.  */
+
+static int
+keyremap_step (keybuf, bufsize, fkey, input, doit, diff, prompt)
+     Lisp_Object *keybuf, prompt;
+     keyremap *fkey;
+     int input, doit, *diff, bufsize;
+{
+  Lisp_Object next, key;
+
+  key = keybuf[fkey->end++];
+  next = access_keymap_keyremap (fkey->map, key, prompt, doit);
+
+  /* If keybuf[fkey->start..fkey->end] is bound in the
+     map and we're in a position to do the key remapping, replace it with
+     the binding and restart with fkey->start at the end. */
+  if ((VECTORP (next) || STRINGP (next)) && doit)
+    {
+      int len = XFASTINT (Flength (next));
+      int i;
+
+      *diff = len - (fkey->end - fkey->start);
+
+      if (input + *diff >= bufsize)
+       error ("Key sequence too long");
+
+      /* Shift the keys that follow fkey->end.  */
+      if (*diff < 0)
+       for (i = fkey->end; i < input; i++)
+         keybuf[i + *diff] = keybuf[i];
+      else if (*diff > 0)
+       for (i = input - 1; i >= fkey->end; i--)
+         keybuf[i + *diff] = keybuf[i];
+      /* Overwrite the old keys with the new ones.  */
+      for (i = 0; i < len; i++)
+       keybuf[fkey->start + i]
+         = Faref (next, make_number (i));
+
+      fkey->start = fkey->end += *diff;
+      fkey->map = fkey->parent;
+
+      return 1;
+    }
+
+  fkey->map = get_keymap (next, 0, 1);
+
+  /* If we no longer have a bound suffix, try a new position for
+     fkey->start.  */
+  if (!CONSP (fkey->map))
+    {
+      fkey->end = ++fkey->start;
+      fkey->map = fkey->parent;
+    }
+  return 0;
+}
+
 /* Read a sequence of keys that ends with a non prefix character,
    storing it in KEYBUF, a buffer of size BUFSIZE.
    Prompt with PROMPT.
@@ -8059,7 +8563,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      defs[i] is non-nil.  */
   volatile int first_binding;
   /* Index of the first key that has no binding.
-     It is useless to try fkey_start larger than that.  */
+     It is useless to try fkey.start larger than that.  */
   volatile int first_unbound;
 
   /* If t < mock_input, then KEYBUF[t] should be read as the next
@@ -8078,22 +8582,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   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,
-     and fkey_map is its binding.
+     keybuf[fkey.start..fkey.end-1] is a prefix in Vfunction_key_map,
+     and fkey.map is its binding.
 
      These might be > t, indicating that all function key scanning
      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.  */
-  volatile int fkey_start = 0, fkey_end = 0;
-  volatile Lisp_Object fkey_map;
+  volatile keyremap fkey;
 
   /* Likewise, for key_translation_map.  */
-  volatile int keytran_start = 0, keytran_end = 0;
-  volatile Lisp_Object keytran_map;
+  volatile keyremap keytran;
 
-  /* If we receive a ``switch-frame'' event in the middle of a key sequence,
-     we put it off for later.  While we're reading, we keep the event here.  */
+  /* If we receive a `switch-frame' or `select-window' event in the middle of
+     a key sequence, we put it off for later.
+     While we're reading, we keep the event here.  */
   volatile Lisp_Object delayed_switch_frame;
 
   /* See the comment below... */
@@ -8124,16 +8627,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   last_nonmenu_event = Qnil;
 
   delayed_switch_frame = Qnil;
-  fkey_map = Vfunction_key_map;
-  keytran_map = Vkey_translation_map;
-
-  /* If there is no function-key-map, turn off function key scanning.  */
-  if (!KEYMAPP (Vfunction_key_map))
-    fkey_start = fkey_end = bufsize + 1;
-
-  /* If there is no key-translation-map, turn off scanning.  */
-  if (!KEYMAPP (Vkey_translation_map))
-    keytran_start = keytran_end = bufsize + 1;
+  fkey.map = fkey.parent = Vfunction_key_map;
+  keytran.map = keytran.parent = Vkey_translation_map;
+  /* If there is no translation-map, turn off scanning.  */
+  fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
+  keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
 
   if (INTERACTIVE)
     {
@@ -8243,15 +8741,15 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* If the best binding for the current key sequence is a keymap, or
      we may be looking at a function key's escape sequence, keep on
      reading.  */
-  while ((first_binding < nmaps && ! NILP (submaps[first_binding]))
-        || (first_binding >= nmaps && fkey_start < t)
-        || (first_binding >= nmaps && keytran_start < t)
+  while (first_binding < nmaps
+        /* Keep reading as long as there's a prefix binding.  */
+        ? !NILP (submaps[first_binding])
         /* Don't return in the middle of a possible function key sequence,
            if the only bindings we found were via case conversion.
            Thus, if ESC O a has a function-key-map translation
            and ESC o has a binding, don't return after ESC O,
            so that we can translate ESC O plus the next character.  */
-        )
+        : (fkey.start < t || keytran.start < t))
     {
       Lisp_Object key;
       int used_mouse_menu = 0;
@@ -8269,10 +8767,13 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         just one key.  */
       volatile int echo_local_start, keys_local_start, local_first_binding;
 
+      eassert (fkey.end == t || (fkey.end > t && fkey.end <= mock_input));
+      eassert (fkey.start <= fkey.end);
+      eassert (keytran.start <= keytran.end);
       /* key-translation-map is applied *after* function-key-map.  */
-      eassert (keytran_end <= fkey_start);
+      eassert (keytran.end <= fkey.start);
 
-      if (first_unbound < fkey_start && first_unbound < keytran_start)
+      if (first_unbound < fkey.start && first_unbound < keytran.start)
        { /* The prefix upto first_unbound has no binding and has
             no translation left to do either, so we know it's unbound.
             If we don't stop now, we risk staying here indefinitely
@@ -8282,10 +8783,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          for (i = first_unbound + 1; i < t; i++)
            keybuf[i - first_unbound - 1] = keybuf[i];
          mock_input = t - first_unbound - 1;
-         fkey_end = fkey_start -= first_unbound + 1;
-         fkey_map = Vfunction_key_map;
-         keytran_end = keytran_start -= first_unbound + 1;
-         keytran_map = Vkey_translation_map;
+         fkey.end = fkey.start -= first_unbound + 1;
+         fkey.map = fkey.parent;
+         keytran.end = keytran.start -= first_unbound + 1;
+         keytran.map = keytran.parent;
          goto replay_sequence;
        }
 
@@ -8390,14 +8891,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
             keymap may have changed, so replay the sequence.  */
          if (BUFFERP (key))
            {
-             EMACS_TIME initial_idleness_start_time;
-             EMACS_SET_SECS_USECS (initial_idleness_start_time,
-                                   EMACS_SECS (timer_last_idleness_start_time),
-                                   EMACS_USECS (timer_last_idleness_start_time));
-
-             /* Resume idle state, using the same start-time as before.  */
-             timer_start_idle ();
-             timer_idleness_start_time = initial_idleness_start_time;
+             timer_resume_idle ();
 
              mock_input = t;
              /* Reset the current buffer from the selected window
@@ -8437,6 +8931,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Vquit_flag = Qnil;
 
          if (EVENT_HAS_PARAMETERS (key)
+             /* Either a `switch-frame' or a `select-window' event.  */
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
            {
              /* If we're at the beginning of a key sequence, and the caller
@@ -8470,6 +8965,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (EVENT_HAS_PARAMETERS (key))
        {
          Lisp_Object kind;
+         Lisp_Object string;
 
          kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
@@ -8477,7 +8973,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              Lisp_Object window, posn;
 
              window = POSN_WINDOW      (EVENT_START (key));
-             posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             posn   = POSN_POSN (EVENT_START (key));
 
              if (CONSP (posn)
                  || (!NILP (fake_prefixed_keys)
@@ -8523,7 +9019,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                  goto replay_sequence;
                }
-             
+
              /* For a mouse click, get the local text-property keymap
                 of the place clicked on, rather than point.  */
              if (last_real_key_start == 0
@@ -8534,8 +9030,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  localized_local_map = 1;
                  start = EVENT_START (key);
-                 
-                 if (CONSP (start) && CONSP (XCDR (start)))
+
+                 if (CONSP (start) && POSN_INBUFFER_P (start))
                    {
                      pos = POSN_BUFFER_POSN (start);
                      if (INTEGERP (pos)
@@ -8573,7 +9069,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
-                 
+
                  keybuf[t]     = posn;
                  keybuf[t + 1] = key;
                  mock_input    = t + 2;
@@ -8581,20 +9077,20 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  /* 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.  */
+                    back into 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))))
+                 if (string = POSN_STRING (EVENT_START (key)),
+                     (CONSP (string) && STRINGP (XCAR (string))))
                    {
-                     Lisp_Object string, pos, map, map2;
+                     Lisp_Object pos, map, map2;
 
-                     string = POSN_STRING (EVENT_START (key));
                      pos = XCDR (string);
                      string = XCAR (string);
                       if (XINT (pos) >= 0
-                         && XINT (pos) < XSTRING (string)->size)
+                         && XINT (pos) < SCHARS (string))
                         {
                           map = Fget_text_property (pos, Qlocal_map, string);
                           if (!NILP (map))
@@ -8609,20 +9105,20 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  goto replay_key;
                }
-             else if (CONSP (POSN_STRING (EVENT_START (key)))
-                      && NILP (from_string))
+             else if (NILP (from_string)
+                      && (string = POSN_STRING (EVENT_START (key)),
+                          (CONSP (string) && STRINGP (XCAR (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;
+                 Lisp_Object pos, map, map2;
 
-                 string = POSN_STRING (EVENT_START (key));
                  pos = XCDR (string);
                  string = XCAR (string);
                  if (XINT (pos) >= 0
-                     && XINT (pos) < XSTRING (string)->size)
+                     && XINT (pos) < SCHARS (string))
                    {
                      map = Fget_text_property (pos, Qlocal_map, string);
                      if (!NILP (map))
@@ -8645,7 +9141,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            {
              Lisp_Object posn;
 
-             posn = POSN_BUFFER_POSN (EVENT_START (key));
+             posn = POSN_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
              if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
@@ -8657,8 +9153,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_SET_POSN (EVENT_START (key),
-                                       Fcons (posn, Qnil));
+                 POSN_SET_POSN (EVENT_START (key),
+                                Fcons (posn, Qnil));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -8688,15 +9184,15 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
        /* This is needed for the following scenario:
           event 0: a down-event that gets dropped by calling replay_key.
           event 1: some normal prefix like C-h.
-          After event 0, first_unbound is 0, after event 1 fkey_start
-          and keytran_start are both 1, so when we see that C-h is bound,
+          After event 0, first_unbound is 0, after event 1 fkey.start
+          and keytran.start are both 1, so when we see that C-h is bound,
           we need to update first_unbound.  */
        first_unbound = max (t + 1, first_unbound);
       else
        {
          Lisp_Object head;
-         
-         /* Remember the position to put an upper bound on fkey_start.  */
+
+         /* Remember the position to put an upper bound on fkey.start.  */
          first_unbound = min (t, first_unbound);
 
          head = EVENT_HEAD (key);
@@ -8777,6 +9273,27 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                             xterm-mouse-mode.  -stef
 
                             Isn't this just the most wonderful code ever?  */
+
+                         /* If mock_input > t + 1, the above simplification
+                            will actually end up dropping keys on the floor.
+                            This is probably OK for now, but even
+                            if mock_input <= t + 1, we need to adjust fkey
+                            and keytran.
+                            Typical case [header-line down-mouse-N]:
+                            mock_input = 2, t = 1, fkey.end = 1,
+                            last_real_key_start = 0.  */
+                         if (fkey.end > last_real_key_start)
+                           {
+                             fkey.end = fkey.start
+                               = min (last_real_key_start, fkey.start);
+                             fkey.map = fkey.parent;
+                             if (keytran.end > last_real_key_start)
+                               {
+                                 keytran.end = keytran.start
+                                   = min (last_real_key_start, keytran.start);
+                                 keytran.map = keytran.parent;
+                               }
+                           }
                          if (t == last_real_key_start)
                            {
                              mock_input = 0;
@@ -8835,224 +9352,62 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
           to go over the sequence before we return (since we keep the
           invariant that keytran.end <= fkey.start).  */
        {
-         if (fkey_start < t)
-           (fkey_start = fkey_end = t, fkey_map = Vfunction_key_map);
+         if (fkey.start < t)
+           (fkey.start = fkey.end = t, fkey.map = fkey.parent);
        }
       else
        /* If the sequence is unbound, see if we can hang a function key
           off the end of it.  */
-       {
-         Lisp_Object fkey_next;
-
-         /* Continue scan from fkey_end until we find a bound suffix.
-            If we fail, increment fkey_start and start over from there.  */
-         while (fkey_end < t)
-           {
-             Lisp_Object key;
-
-             key = keybuf[fkey_end++];
-             fkey_next = access_keymap (fkey_map, key, 1, 0, 1);
-
-             /* Handle symbol with autoload definition.  */
-             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
-                 && CONSP (XSYMBOL (fkey_next)->function)
-                 && EQ (XCAR (XSYMBOL (fkey_next)->function), Qautoload))
-               do_autoload (XSYMBOL (fkey_next)->function,
-                            fkey_next);
-
-             /* Handle a symbol whose function definition is a keymap
-                or an array.  */
-             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
-                 && (!NILP (Farrayp (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
-        for the mapping of return into C-m and tab into C-i.  */
-             /* Optionally don't map function keys into other things.
-                This enables the user to redefine kp- keys easily.  */
-             if (SYMBOLP (key) && !NILP (Vinhibit_function_key_mapping))
-               fkey_next = Qnil;
-#endif
-
-             /* If the function key map gives a function, not an
-                array, then call the function with no args and use
-                its value instead.  */
-             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
-                 /* If there's a binding (i.e. first_binding >= nmaps)
-                    we don't want to apply this function-key-mapping.  */
-                 && fkey_end == t && first_binding >= nmaps)
-               {
-                 struct gcpro gcpro1, gcpro2, gcpro3;
-                 Lisp_Object tem;
-                 tem = fkey_next;
-
-                 GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
-                 fkey_next = call1 (fkey_next, prompt);
-                 UNGCPRO;
-                 /* If the function returned something invalid,
-                    barf--don't ignore it.
-                    (To ignore it safely, we would need to gcpro a bunch of
-                    other variables.)  */
-                 if (! (VECTORP (fkey_next) || STRINGP (fkey_next)))
-                   error ("Function in key-translation-map returns invalid key sequence");
-               }
-
-             /* If keybuf[fkey_start..fkey_end] is bound in the
-                function key map and it's a suffix of the current
-                sequence (i.e. fkey_end == t), replace it with
-                the binding and restart with fkey_start at the end. */
-             if ((VECTORP (fkey_next) || STRINGP (fkey_next))
-                 /* If there's a binding (i.e. first_binding >= nmaps)
-                    we don't want to apply this function-key-mapping.  */
-                 && fkey_end == t && first_binding >= nmaps)
-               {
-                 int len = XFASTINT (Flength (fkey_next));
-
-                 t = fkey_start + len;
-                 if (t >= bufsize)
-                   error ("Key sequence too long");
-
-                 if (VECTORP (fkey_next))
-                   bcopy (XVECTOR (fkey_next)->contents,
-                          keybuf + fkey_start,
-                          (t - fkey_start) * sizeof (keybuf[0]));
-                 else if (STRINGP (fkey_next))
-                   {
-                     int i;
-
-                     for (i = 0; i < len; i++)
-                       XSETFASTINT (keybuf[fkey_start + i],
-                                    XSTRING (fkey_next)->data[i]);
-                   }
-
-                 mock_input = t;
-                 fkey_start = fkey_end = t;
-                 fkey_map = Vfunction_key_map;
-
-                 /* Do pass the results through key-translation-map.
-                    But don't retranslate what key-translation-map
-                    has already translated.  */
-                 keytran_end = keytran_start;
-                 keytran_map = Vkey_translation_map;
-
-                 goto replay_sequence;
-               }
-
-             fkey_map = get_keymap (fkey_next, 0, 1);
-
-             /* If we no longer have a bound suffix, try a new positions for
-                fkey_start.  */
-             if (!CONSP (fkey_map))
-               {
-                 fkey_end = ++fkey_start;
-                 fkey_map = Vfunction_key_map;
-               }
-           }
-       }
-
-      /* Look for this sequence in key-translation-map.  */
-      {
-       Lisp_Object keytran_next;
-
-       /* Scan from keytran_end until we find a bound suffix.  */
-       while (keytran_end < fkey_start)
+       /* Continue scan from fkey.end until we find a bound suffix.  */
+       while (fkey.end < t)
          {
-           Lisp_Object key;
-
-           key = keybuf[keytran_end++];
-           keytran_next
-             = access_keymap (keytran_map, key, 1, 0, 1);
-
-           /* Handle symbol with autoload definition.  */
-           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
-               && CONSP (XSYMBOL (keytran_next)->function)
-               && EQ (XCAR (XSYMBOL (keytran_next)->function), Qautoload))
-             do_autoload (XSYMBOL (keytran_next)->function,
-                          keytran_next);
-
-           /* Handle a symbol whose function definition is a keymap
-              or an array.  */
-           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
-               && (!NILP (Farrayp (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
-              array, then call the function with one arg and use
-              its value instead.  */
-           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next)))
-             {
-               struct gcpro gcpro1, gcpro2, gcpro3;
-               Lisp_Object tem;
-               tem = keytran_next;
-
-               GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
-               keytran_next = call1 (keytran_next, prompt);
-               UNGCPRO;
-               /* If the function returned something invalid,
-                  barf--don't ignore it.
-                  (To ignore it safely, we would need to gcpro a bunch of
-                  other variables.)  */
-               if (! (VECTORP (keytran_next) || STRINGP (keytran_next)))
-                 error ("Function in key-translation-map returns invalid key sequence");
-             }
-
-           /* If keybuf[keytran_start..keytran_end] is bound in the
-              key translation map and it's a suffix of the current
-              sequence (i.e. keytran_end == t), replace it with
-              the binding and restart with keytran_start at the end. */
-           if ((VECTORP (keytran_next) || STRINGP (keytran_next)))
+           struct gcpro gcpro1, gcpro2, gcpro3;
+           int done, diff;
+
+           GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+           done = keyremap_step (keybuf, bufsize, &fkey,
+                                 max (t, mock_input),
+                                 /* If there's a binding (i.e.
+                                    first_binding >= nmaps) we don't want
+                                    to apply this function-key-mapping.  */
+                                 fkey.end + 1 == t && first_binding >= nmaps,
+                                 &diff, prompt);
+           UNGCPRO;
+           if (done)
              {
-               int len = XFASTINT (Flength (keytran_next));
-               int i, diff = len - (keytran_end - keytran_start);
-
-               mock_input = max (t, mock_input);
-               if (mock_input + diff >= bufsize)
-                 error ("Key sequence too long");
-
-               /* Shift the keys that are after keytran_end.  */
-               if (diff < 0)
-                 for (i = keytran_end; i < mock_input; i++)
-                   keybuf[i + diff] = keybuf[i];
-               else if (diff > 0)
-                 for (i = mock_input - 1; i >= keytran_end; i--)
-                   keybuf[i + diff] = keybuf[i];
-               /* Replace the keys between keytran_start and keytran_end
-                  with those from keytran_next.  */
-               for (i = 0; i < len; i++)
-                 keybuf[keytran_start + i]
-                   = Faref (keytran_next, make_number (i));
-
-               mock_input += diff;
-               keytran_start = keytran_end += diff;
-               keytran_map = Vkey_translation_map;
-
-               /* Adjust the function-key-map counters.  */
-               fkey_start += diff;
-               fkey_end += diff;
-
+               mock_input = diff + max (t, mock_input);
                goto replay_sequence;
              }
+         }
 
-           keytran_map = get_keymap (keytran_next, 0, 1);
+      /* Look for this sequence in key-translation-map.
+        Scan from keytran.end until we find a bound suffix.  */
+      while (keytran.end < fkey.start)
+       {
+         struct gcpro gcpro1, gcpro2, gcpro3;
+         int done, diff;
 
-           /* If we no longer have a bound suffix, try a new positions for
-              keytran_start.  */
-           if (!CONSP (keytran_map))
-             {
-               keytran_end = ++keytran_start;
-               keytran_map = Vkey_translation_map;
-             }
-         }
-      }
+         GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+         done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input),
+                               1, &diff, prompt);
+         UNGCPRO;
+         if (done)
+           {
+             mock_input = diff + max (t, mock_input);
+             /* Adjust the function-key-map counters.  */
+             fkey.end += diff;
+             fkey.start += diff;
+
+             goto replay_sequence;
+           }
+       }
 
       /* If KEY is not defined in any of the keymaps,
         and cannot be part of a function key or translation,
         and is an upper case letter
         use the corresponding lower-case letter instead.  */
       if (first_binding >= nmaps
-         && fkey_start >= t && keytran_start >= t
+         && fkey.start >= t && keytran.start >= t
          && INTEGERP (key)
          && ((((XINT (key) & 0x3ffff)
                < XCHAR_TABLE (current_buffer->downcase_table)->size)
@@ -9083,7 +9438,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         and is a shifted function key,
         use the corresponding unshifted function key instead.  */
       if (first_binding >= nmaps
-         && fkey_start >= t && keytran_start >= t
+         && fkey.start >= t && keytran.start >= t
          && SYMBOLP (key))
        {
          Lisp_Object breakdown;
@@ -9104,6 +9459,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              keybuf[t - 1] = new_key;
              mock_input = max (t, mock_input);
+             fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
+             keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
 
              goto replay_sequence;
            }
@@ -9121,6 +9478,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
   if ((dont_downcase_last || first_binding >= nmaps)
+      && t > 0
       && t - 1 == original_uppercase_position)
     keybuf[t - 1] = original_uppercase;
 
@@ -9141,7 +9499,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       add_command_key (keybuf[t]);
     }
 
-  
+
 
   UNGCPRO;
   return t;
@@ -9220,6 +9578,7 @@ will read just one key sequence.  */)
   if (NILP (continue_echo))
     {
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
       this_single_command_key_start = 0;
     }
 
@@ -9279,6 +9638,7 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
   if (NILP (continue_echo))
     {
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
       this_single_command_key_start = 0;
     }
 
@@ -9340,15 +9700,15 @@ a special event, so ignore the prefix argument and don't clear it.  */)
       tem = Fget (cmd, Qdisabled);
       if (!NILP (tem) && !NILP (Vrun_hooks))
        {
-         tem = Fsymbol_value (Qdisabled_command_hook);
+         tem = Fsymbol_value (Qdisabled_command_function);
          if (!NILP (tem))
-           return call1 (Vrun_hooks, Qdisabled_command_hook);
+           return call1 (Vrun_hooks, Qdisabled_command_function);
        }
     }
 
   while (1)
     {
-      final = Findirect_function (cmd);
+      final = Findirect_function (cmd, Qnil);
 
       if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
        {
@@ -9383,7 +9743,7 @@ a special event, so ignore the prefix argument and don't clear it.  */)
            }
        }
 
-      return Fexecute_kbd_macro (final, prefixarg);
+      return Fexecute_kbd_macro (final, prefixarg, Qnil);
     }
 
   if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
@@ -9394,6 +9754,7 @@ a special event, so ignore the prefix argument and don't clear it.  */)
       backtrace.args = &cmd;
       backtrace.nargs = 1;
       backtrace.evalargs = 0;
+      backtrace.debug_on_exit = 0;
 
       tem = Fcall_interactively (cmd, record_flag, keys);
 
@@ -9417,6 +9778,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object saved_keys, saved_last_point_position_buffer;
   Lisp_Object bindings, value;
   struct gcpro gcpro1, gcpro2, gcpro3;
+#ifdef HAVE_X_WINDOWS
+  /* The call to Fcompleting_read wil start and cancel the hourglass,
+     but if the hourglass was already scheduled, this means that no
+     hourglass will be shown for the actual M-x command itself.
+     So we restart it if it is already scheduled.  Note that checking
+     hourglass_shown_p is not enough,  normally the hourglass is not shown,
+     just scheduled to be shown.  */
+  int hstarted = hourglass_started ();
+#endif
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
@@ -9430,23 +9800,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   else if (CONSP (prefixarg) && XINT (XCAR (prefixarg)) == 4)
     strcpy (buf, "C-u ");
   else if (CONSP (prefixarg) && INTEGERP (XCAR (prefixarg)))
-    {
-      if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d ", XINT (XCAR (prefixarg)));
-      else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
-      else
-       abort ();
-    }
+    sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
   else if (INTEGERP (prefixarg))
-    {
-      if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d ", XINT (prefixarg));
-      else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", (long) XINT (prefixarg));
-      else
-       abort ();
-    }
+    sprintf (buf, "%ld ", (long) XINT (prefixarg));
 
   /* This isn't strictly correct if execute-extended-command
      is bound to anything else.  Perhaps it should use
@@ -9462,25 +9818,28 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                               Qt, Qnil, Qextended_command_history, Qnil,
                               Qnil);
 
-  if (STRINGP (function) && XSTRING (function)->size == 0)
+#ifdef HAVE_X_WINDOWS
+  if (hstarted) start_hourglass ();
+#endif
+
+  if (STRINGP (function) && SCHARS (function) == 0)
     error ("No command name given");
 
   /* Set this_command_keys to the concatenation of saved_keys and
      function, followed by a RET.  */
   {
-    struct Lisp_String *str;
     Lisp_Object *keys;
     int i;
 
     this_command_key_count = 0;
+    this_command_key_count_reset = 0;
     this_single_command_key_start = 0;
 
     keys = XVECTOR (saved_keys)->contents;
     for (i = 0; i < XVECTOR (saved_keys)->size; i++)
       add_command_key (keys[i]);
 
-    str = XSTRING (function);
-    for (i = 0; i < str->size; i++)
+    for (i = 0; i < SCHARS (function); i++)
       add_command_key (Faref (function, make_number (i)));
 
     add_command_key (make_number ('\015'));
@@ -9498,7 +9857,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 
   /* If enabled, show which key runs this command.  */
   if (!NILP (Vsuggest_key_bindings)
-      && NILP (Vexecuting_macro)
+      && NILP (Vexecuting_kbd_macro)
       && SYMBOLP (function))
     bindings = Fwhere_is_internal (function, Voverriding_local_map,
                                   Qt, Qnil, Qnil);
@@ -9534,16 +9893,16 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          int message_p = push_message ();
          int count = SPECPDL_INDEX ();
 
-         record_unwind_protect (push_message_unwind, Qnil);
-         binding = Fkey_description (bindings);
+         record_unwind_protect (pop_message_unwind, Qnil);
+         binding = Fkey_description (bindings, Qnil);
 
          newmessage
-           = (char *) alloca (XSTRING (SYMBOL_NAME (function))->size
-                              + STRING_BYTES (XSTRING (binding))
+           = (char *) alloca (SCHARS (SYMBOL_NAME (function))
+                              + SBYTES (binding)
                               + 100);
          sprintf (newmessage, "You can run the command `%s' with %s",
-                  XSTRING (SYMBOL_NAME (function))->data,
-                  XSTRING (binding)->data);
+                  SDATA (SYMBOL_NAME (function)),
+                  SDATA (binding));
          message2_nolog (newmessage,
                          strlen (newmessage),
                          STRING_MULTIBYTE (binding));
@@ -9572,6 +9931,18 @@ detect_input_pending ()
   return input_pending;
 }
 
+/* Return nonzero if input events other than mouse movements are
+   pending.  */
+
+int
+detect_input_pending_ignore_squeezables ()
+{
+  if (!input_pending)
+    get_input_pending (&input_pending, READABLE_EVENTS_IGNORE_SQUEEZABLES);
+
+  return input_pending;
+}
+
 /* Return nonzero if input events are pending, and run any pending timers.  */
 
 int
@@ -9581,7 +9952,7 @@ detect_input_pending_run_timers (do_display)
   int old_timers_run = timers_run;
 
   if (!input_pending)
-    get_input_pending (&input_pending, 1);
+    get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
 
   if (old_timers_run != timers_run && do_display)
     {
@@ -9609,7 +9980,7 @@ clear_input_pending ()
 }
 
 /* Return nonzero if there are pending requeued events.
-   This isn't used yet.  The hope is to make wait_reading_process_input
+   This isn't used yet.  The hope is to make wait_reading_process_output
    call it, and return if it runs Lisp code that unreads something.
    The problem is, kbd_buffer_get_event needs to be fixed to know what
    to do in that case.  It isn't trivial.  */
@@ -9630,7 +10001,9 @@ if there is a doubt, the value is t.  */)
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  get_filtered_input_pending (&input_pending, 1, 1);
+  get_input_pending (&input_pending,
+                    READABLE_EVENTS_DO_TIMERS_NOW
+                    | READABLE_EVENTS_FILTER_EVENTS);
   return input_pending > 0 ? Qt : Qnil;
 }
 
@@ -9709,39 +10082,51 @@ The value is always a vector.  */)
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
        Sreset_this_command_lengths, 0, 0, 0,
-       doc: /* Used for complicated reasons in `universal-argument-other-key'.
+       doc: /* Make the unread events replace the last command and echo.
+Used 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'.  */)
+The translated event has to replace the real events,
+both in the value of (this-command-keys) and in echoing.
+To achieve this, `universal-argument-other-key' calls
+`reset-this-command-lengths', which discards the record of reading
+these events the first time.  */)
      ()
 {
-  before_command_restore_flag = 1;
-  before_command_key_count_1 = before_command_key_count;
-  before_command_echo_length_1 = before_command_echo_length;
+  this_command_key_count = before_command_key_count;
+  if (this_command_key_count < this_single_command_key_start)
+    this_single_command_key_start = this_command_key_count;
+
+  echo_truncate (before_command_echo_length);
+
+  /* Cause whatever we put into unread-command-events
+     to echo as if it were being freshly read from the keyboard.  */
+  this_command_key_count_reset = 1;
+
   return Qnil;
 }
 
 DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
-       Sclear_this_command_keys, 0, 0, 0,
+       Sclear_this_command_keys, 0, 1, 0,
        doc: /* Clear out the vector that `this-command-keys' returns.
-Also clear the record of the last 100 events.  */)
-     ()
+Also clear the record of the last 100 events, unless optional arg
+KEEP-RECORD is non-nil.  */)
+     (keep_record)
+     Lisp_Object keep_record;
 {
   int i;
-  
+
   this_command_key_count = 0;
+  this_command_key_count_reset = 0;
 
-  for (i = 0; i < XVECTOR (recent_keys)->size; ++i)
-    XVECTOR (recent_keys)->contents[i] = Qnil;
-  total_keys = 0;
-  recent_keys_index = 0;
+  if (NILP (keep_record))
+    {
+      for (i = 0; i < XVECTOR (recent_keys)->size; ++i)
+       XVECTOR (recent_keys)->contents[i] = Qnil;
+      total_keys = 0;
+      recent_keys_index = 0;
+    }
   return Qnil;
 }
 
@@ -9769,7 +10154,7 @@ If FILE is nil, close any open dribble file.  */)
   if (!NILP (file))
     {
       file = Fexpand_file_name (file, Qnil);
-      dribble = fopen (XSTRING (file)->data, "w");
+      dribble = fopen (SDATA (file), "w");
       if (dribble == 0)
        report_file_error ("Opening dribble", Fcons (file, Qnil));
     }
@@ -9778,10 +10163,16 @@ If FILE is nil, close any open dribble file.  */)
 
 DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0,
        doc: /* Discard the contents of the terminal input buffer.
-Also cancel any kbd macro being defined.  */)
+Also end any kbd macro being defined.  */)
      ()
 {
-  current_kboard->defining_kbd_macro = Qnil;
+  if (!NILP (current_kboard->defining_kbd_macro))
+    {
+      /* Discard the last command from the macro.  */
+      Fcancel_kbd_macro_events ();
+      end_kbd_macro ();
+    }
+
   update_mode_lines++;
 
   Vunread_command_events = Qnil;
@@ -9790,7 +10181,6 @@ Also cancel any kbd macro being defined.  */)
   discard_tty_input ();
 
   kbd_fetch_ptr =  kbd_store_ptr;
-  Ffillarray (kbd_buffer_gcpro, Qnil);
   input_pending = 0;
 
   return Qnil;
@@ -9860,43 +10250,39 @@ void
 stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
-/* stuff_char works only in BSD, versions 4.2 and up.  */
-#ifdef BSD_SYSTEM
-#ifndef BSD4_1
+#ifdef SIGTSTP  /* stuff_char is defined if SIGTSTP.  */
   register unsigned char *p;
 
   if (STRINGP (stuffstring))
     {
       register int count;
 
-      p = XSTRING (stuffstring)->data;
-      count = STRING_BYTES (XSTRING (stuffstring));
+      p = SDATA (stuffstring);
+      count = SBYTES (stuffstring);
       while (count-- > 0)
        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?  */
+     Should we ignore anything that was typed in at the "wrong" kboard?
+
+     rms: we should stuff everything back into the kboard
+     it came from.  */
   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_EVENT)
        stuff_char (kbd_fetch_ptr->code);
-      
-      kbd_fetch_ptr->kind = NO_EVENT;
-      idx = 2 * (kbd_fetch_ptr - kbd_buffer);
-      ASET (kbd_buffer_gcpro, idx, Qnil);
-      ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+
+      clear_event (kbd_fetch_ptr);
     }
-  
+
   input_pending = 0;
-#endif
-#endif /* BSD_SYSTEM and not BSD4_1 */
+#endif /* SIGTSTP */
 }
 \f
 void
@@ -9923,7 +10309,7 @@ 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.
@@ -9935,7 +10321,7 @@ clear_waiting_for_input ()
    eval to throw, when it gets a chance.  If quit-flag is already
    non-nil, it stops the job right away.  */
 
-SIGTYPE
+static SIGTYPE
 interrupt_signal (signalnum)   /* If we don't have an argument, */
      int signalnum;            /* some compilers complain in signal calls. */
 {
@@ -9954,6 +10340,7 @@ interrupt_signal (signalnum)     /* If we don't have an argument, */
     }
 #endif /* USG */
 
+  SIGNAL_THREAD_CHECK (signalnum);
   cancel_echoing ();
 
   if (!NILP (Vquit_flag)
@@ -10013,7 +10400,7 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
            }
          while (c != '\n') c = getchar ();
        }
-      else 
+      else
        {
          /* During GC, it must be safe to reenable quitting again.  */
          Vinhibit_quit = Qnil;
@@ -10205,6 +10592,81 @@ The elements of this list correspond to the arguments of
   return Flist (sizeof (val) / sizeof (val[0]), val);
 }
 
+DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
+       doc: /* Return position information for pixel coordinates X and Y.
+By default, X and Y are relative to text area of the selected window.
+Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window.
+If optional fourth arg WHOLE is non-nil, X is relative to the left
+edge of the window.
+
+The return value is similar to a mouse click position:
+   (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+    IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists.  */)
+  (x, y, frame_or_window, whole)
+     Lisp_Object x, y, frame_or_window, whole;
+{
+  CHECK_NATNUM (x);
+  CHECK_NATNUM (y);
+
+  if (NILP (frame_or_window))
+    frame_or_window = selected_window;
+
+  if (WINDOWP (frame_or_window))
+    {
+      struct window *w;
+
+      CHECK_LIVE_WINDOW (frame_or_window);
+
+      w = XWINDOW (frame_or_window);
+      XSETINT (x, (XINT (x)
+                  + WINDOW_LEFT_EDGE_X (w)
+                  + (NILP (whole)
+                     ? window_box_left_offset (w, TEXT_AREA)
+                     : 0)));
+      XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y)));
+      frame_or_window = w->frame;
+    }
+
+  CHECK_LIVE_FRAME (frame_or_window);
+
+  return make_lispy_position (XFRAME (frame_or_window), &x, &y, 0);
+}
+
+DEFUN ("posn-at-point", Fposn_at_point, Sposn_at_point, 0, 2, 0,
+       doc: /* Return position information for buffer POS in WINDOW.
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.
+
+Return nil if position is not visible in window.  Otherwise,
+the return value is similar to that returned by `event-start' for
+a mouse click at the upper left corner of the glyph corresponding
+to the given buffer position:
+   (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+    IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists.  */)
+  (pos, window)
+     Lisp_Object pos, window;
+{
+  Lisp_Object tem;
+
+  if (NILP (window))
+    window = selected_window;
+
+  tem = Fpos_visible_in_window_p (pos, window, Qt);
+  if (!NILP (tem))
+    {
+      Lisp_Object x = XCAR (tem);
+      Lisp_Object y = XCAR (XCDR (tem));
+
+      /* Point invisible due to hscrolling?  */
+      if (XINT (x) < 0)
+       return Qnil;
+      tem = Fposn_at_x_y (x, y, window, Qnil);
+    }
+
+  return tem;
+}
+
 \f
 /*
  * Set up a new kboard object with reasonable initial values.
@@ -10255,7 +10717,7 @@ delete_kboard (kb)
      KBOARD *kb;
 {
   KBOARD **kbp;
-  
+
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
       abort ();
@@ -10270,7 +10732,7 @@ delete_kboard (kb)
       if (current_kboard == kb)
        abort ();
     }
-  
+
   wipe_kboard (kb);
   xfree (kb);
 }
@@ -10291,7 +10753,6 @@ init_keyboard ()
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
 #ifdef HAVE_MOUSE
   do_mouse_tracking = Qnil;
 #endif
@@ -10364,7 +10825,9 @@ struct event_head head_table[] = {
   {&Qdelete_frame,        "delete-frame",        &Qdelete_frame},
   {&Qiconify_frame,       "iconify-frame",       &Qiconify_frame},
   {&Qmake_frame_visible,  "make-frame-visible",  &Qmake_frame_visible},
-  {&Qselect_window,       "select-window",       &Qselect_window}
+  /* `select-window' should be handled just like `switch-frame'
+     in read_key_sequence.  */
+  {&Qselect_window,       "select-window",       &Qswitch_frame}
 };
 
 void
@@ -10372,7 +10835,7 @@ syms_of_keyboard ()
 {
   Vpre_help_message = Qnil;
   staticpro (&Vpre_help_message);
-  
+
   Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
@@ -10397,8 +10860,8 @@ syms_of_keyboard ()
   Qtimer_event_handler = intern ("timer-event-handler");
   staticpro (&Qtimer_event_handler);
 
-  Qdisabled_command_hook = intern ("disabled-command-hook");
-  staticpro (&Qdisabled_command_hook);
+  Qdisabled_command_function = intern ("disabled-command-function");
+  staticpro (&Qdisabled_command_function);
 
   Qself_insert_command = intern ("self-insert-command");
   staticpro (&Qself_insert_command);
@@ -10421,9 +10884,6 @@ syms_of_keyboard ()
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
-  Qpost_command_idle_hook = intern ("post-command-idle-hook");
-  staticpro (&Qpost_command_idle_hook);
-
   Qdeferred_action_function = intern ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
@@ -10434,9 +10894,7 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-#ifdef WINDOWSNT
-  Qmouse_wheel = intern ("mouse-wheel");
-  staticpro (&Qmouse_wheel);
+#if defined (WINDOWSNT) || defined (MAC_OS)
   Qlanguage_change = intern ("language-change");
   staticpro (&Qlanguage_change);
 #endif
@@ -10444,8 +10902,13 @@ syms_of_keyboard ()
   staticpro (&Qdrag_n_drop);
 
   Qsave_session = intern ("save-session");
-  staticpro(&Qsave_session);
-  
+  staticpro (&Qsave_session);
+
+#ifdef MAC_OS
+  Qmac_apple_event = intern ("mac-apple-event");
+  staticpro (&Qmac_apple_event);
+#endif
+
   Qusr1_signal = intern ("usr1-signal");
   staticpro (&Qusr1_signal);
   Qusr2_signal = intern ("usr2-signal");
@@ -10483,6 +10946,11 @@ syms_of_keyboard ()
   Qmenu_bar = intern ("menu-bar");
   staticpro (&Qmenu_bar);
 
+#ifdef HAVE_MOUSE
+  Qmouse_fixup_help_message = intern ("mouse-fixup-help-message");
+  staticpro (&Qmouse_fixup_help_message);
+#endif
+
   Qabove_handle = intern ("above-handle");
   staticpro (&Qabove_handle);
   Qhandle = intern ("handle");
@@ -10531,6 +10999,7 @@ syms_of_keyboard ()
   Fset (Qinput_method_use_echo_area, Qnil);
 
   last_point_position_buffer = Qnil;
+  last_point_position_window = Qnil;
 
   {
     struct event_head *p;
@@ -10550,6 +11019,8 @@ syms_of_keyboard ()
   staticpro (&button_down_location);
   mouse_syms = Fmake_vector (make_number (1), Qnil);
   staticpro (&mouse_syms);
+  wheel_syms = Fmake_vector (make_number (2), Qnil);
+  staticpro (&wheel_syms);
 
   {
     int i;
@@ -10575,22 +11046,14 @@ syms_of_keyboard ()
   Fset (Qextended_command_history, Qnil);
   staticpro (&Qextended_command_history);
 
-  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
-  staticpro (&kbd_buffer_gcpro);
-
   accent_key_syms = Qnil;
   staticpro (&accent_key_syms);
 
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
-#ifdef WINDOWSNT
-  mouse_wheel_syms = Qnil;
-  staticpro (&mouse_wheel_syms);
-  
   drag_n_drop_syms = Qnil;
   staticpro (&drag_n_drop_syms);
-#endif
 
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
@@ -10604,6 +11067,9 @@ syms_of_keyboard ()
   menu_bar_one_keymap_changed_items = Qnil;
   staticpro (&menu_bar_one_keymap_changed_items);
 
+  menu_bar_items_vector = Qnil;
+  staticpro (&menu_bar_items_vector);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
@@ -10630,6 +11096,8 @@ syms_of_keyboard ()
   defsubr (&Sset_input_mode);
   defsubr (&Scurrent_input_mode);
   defsubr (&Sexecute_extended_command);
+  defsubr (&Sposn_at_point);
+  defsubr (&Sposn_at_x_y);
 
   DEFVAR_LISP ("last-command-char", &last_command_char,
               doc: /* Last input event that was part of a command.  */);
@@ -10698,9 +11166,10 @@ will be in `last-command' during the following command.  */);
   Vthis_command = Qnil;
 
   DEFVAR_LISP ("this-original-command", &Vthis_original_command,
-              doc: /* If non-nil, the original command bound to the current key sequence.
-The value of `this-command' is the result of looking up the original
-command in the active keymaps.  */);
+              doc: /* The command bound to the current key sequence before remapping.
+It equals `this-command' if the original command was not remapped through
+any of the active keymaps.  Otherwise, the value of `this-command' is the
+result of looking up the original command in the active keymaps.  */);
   Vthis_original_command = Qnil;
 
   DEFVAR_INT ("auto-save-interval", &auto_save_interval,
@@ -10744,7 +11213,7 @@ instead of pixels.
 This variable is also the threshold for motion of the mouse
 to count as a drag.  */);
   double_click_fuzz = 3;
-  
+
   DEFVAR_BOOL ("inhibit-local-menu-bar-menus", &inhibit_local_menu_bar_menus,
               doc: /* *Non-nil means inhibit local map menu bar menus.  */);
   inhibit_local_menu_bar_menus = 0;
@@ -10799,11 +11268,16 @@ Useful to set before you dump a modified Emacs.  */);
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
               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".  */);
+If non-nil, the value should be a char-table.  Each character read
+from the keyboard is looked up in this char-table.  If the value found
+there is non-nil, then it is used instead of the actual input character.
+
+The value can also be a string or vector, but this is considered obsolete.
+If it is a string or vector of length N, character codes N and up are left
+untranslated.  In a vector, an element which is nil means "no translation".
+
+This is applied to the characters supplied to input methods, not their
+output.  See also `translation-table-for-input'.  */);
   Vkeyboard_translate_table = Qnil;
 
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
@@ -10864,21 +11338,12 @@ 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,
-              doc: /* Normal hook run after each command is executed, if idle.
-Errors running the hook are caught and ignored.  */);
-  Vpost_command_idle_hook = Qnil;
-
-  DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
-             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", ...,
               doc: /* Normal hook run when clearing the echo area.  */);
 #endif
   Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+  staticpro (&Qecho_area_clear_hook);
   SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
@@ -10895,13 +11360,15 @@ The elements of the list are event types that may have menu bar bindings.  */);
                 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.
+It also replaces `overriding-local-map'.
+
 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,
               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.  */);
+If this variable is non-nil, it is used as a keymap--replacing the
+buffer's local map, the minor mode keymaps, and char property keymaps.  */);
   Voverriding_local_map = Qnil;
 
   DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
@@ -10986,8 +11453,8 @@ It's called with one argument, the help string to display.  */);
 
 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.
+the boundary of the region.  But, when a command sets this variable to
+non-nil, we suppress the point adjustment.
 
 This variable is set to nil before reading a command, and is checked
 just after executing the command.  */);
@@ -11002,16 +11469,24 @@ 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);
+
+  DEFVAR_LISP ("throw-on-input", &Vthrow_on_input,
+              doc: /* If non-nil, any keyboard input throws to this symbol.
+The value of that variable is passed to `quit-flag' and later causes a
+peculiar kind of quitting.  */);
+  Vthrow_on_input = Qnil;
+
+  DEFVAR_LISP ("enable-disabled-menus-and-buttons",
+              &Venable_disabled_menus_and_buttons,
+              doc: /* If non-nil, don't ignore events produced by disabled menu items and tool-bar.
+
+Help functions bind this to allow help on disabled menu items
+and tool-bar buttons.  */);
+  Venable_disabled_menus_and_buttons = Qnil;
 }
 
 void
@@ -11025,12 +11500,81 @@ keys_of_keyboard ()
 
   initial_define_lispy_key (Vspecial_event_map, "delete-frame",
                            "handle-delete-frame");
+  /* Here we used to use `ignore-event' which would simple set prefix-arg to
+     current-prefix-arg, as is done in `handle-switch-frame'.
+     But `handle-switch-frame is not run from the special-map.
+     Commands from that map are run in a special way that automatically
+     preserves the prefix-arg.  Restoring the prefix arg here is not just
+     redundant but harmful:
+     - C-u C-x v =
+     - current-prefix-arg is set to non-nil, prefix-arg is set to nil.
+     - after the first prompt, the exit-minibuffer-hook is run which may
+       iconify a frame and thus push a `iconify-frame' event.
+     - after running exit-minibuffer-hook, current-prefix-arg is
+       restored to the non-nil value it had before the prompt.
+     - we enter the second prompt.
+       current-prefix-arg is non-nil, prefix-arg is nil.
+     - before running the first real event, we run the special iconify-frame
+       event, but we pass the `special' arg to execute-command so
+       current-prefix-arg and prefix-arg are left untouched.
+     - here we foolishly copy the non-nil current-prefix-arg to prefix-arg.
+     - the next key event will have a spuriously non-nil current-prefix-arg.  */
   initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
-                           "ignore-event");
+                           "ignore");
   initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
-                           "ignore-event");
-  initial_define_lispy_key (Vspecial_event_map, "select-window",
-                           "handle-select-window");
+                           "ignore");
+  /* Handling it at such a low-level causes read_key_sequence to get
+   * confused because it doesn't realize that the current_buffer was
+   * changed by read_char.
+   *
+   * initial_define_lispy_key (Vspecial_event_map, "select-window",
+   *                       "handle-select-window"); */
   initial_define_lispy_key (Vspecial_event_map, "save-session",
                            "handle-save-session");
 }
+
+/* Mark the pointers in the kboard objects.
+   Called by the Fgarbage_collector.  */
+void
+mark_kboards ()
+{
+  KBOARD *kb;
+  Lisp_Object *p;
+  for (kb = all_kboards; kb; kb = kb->next_kboard)
+    {
+      if (kb->kbd_macro_buffer)
+       for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++)
+         mark_object (*p);
+      mark_object (kb->Voverriding_terminal_local_map);
+      mark_object (kb->Vlast_command);
+      mark_object (kb->Vreal_last_command);
+      mark_object (kb->Vprefix_arg);
+      mark_object (kb->Vlast_prefix_arg);
+      mark_object (kb->kbd_queue);
+      mark_object (kb->defining_kbd_macro);
+      mark_object (kb->Vlast_kbd_macro);
+      mark_object (kb->Vsystem_key_alist);
+      mark_object (kb->system_key_syms);
+      mark_object (kb->Vdefault_minibuffer_frame);
+      mark_object (kb->echo_string);
+    }
+  {
+    struct input_event *event;
+    for (event = kbd_fetch_ptr; event != kbd_store_ptr; event++)
+      {
+       if (event == kbd_buffer + KBD_BUFFER_SIZE)
+         event = kbd_buffer;
+       if (event->kind != SELECTION_REQUEST_EVENT
+           && event->kind != SELECTION_CLEAR_EVENT)
+         {
+           mark_object (event->x);
+           mark_object (event->y);
+         }
+       mark_object (event->frame_or_window);
+       mark_object (event->arg);
+      }
+  }
+}
+
+/* arch-tag: 774e34d7-6d31-42f3-8397-e079a4e4c9ca
+   (do not change this comment) */