]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(byte-compile-no-warnings): New function.
[gnu-emacs] / src / keyboard.c
index 76a6c15c15755d6db0f227b75d3281e82187a26a..9260a175746d7c5c06edd0fe9417583b7d3672c6 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 2001
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA.  */
 #include "dispextern.h"
 #include "syntax.h"
 #include "intervals.h"
+#include "keymap.h"
 #include "blockinput.h"
 #include "puresize.h"
 #include "systime.h"
@@ -70,13 +71,10 @@ Boston, MA 02111-1307, USA.  */
 #include "w32term.h"
 #endif /* HAVE_NTGUI */
 
-#ifdef macintosh
+#ifdef MAC_OS
 #include "macterm.h"
 #endif
 
-/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
-#include "systime.h"
-
 #ifndef USE_CRT_DLL
 extern int errno;
 #endif
@@ -96,8 +94,8 @@ extern int input_fd;
 
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
-#ifdef macintosh
-/* But not too big (local data > 32K error) if on macintosh.  */
+#ifdef MAC_OS8
+/* But not too big (local data > 32K error) if on Mac OS Classic.  */
 #define KBD_BUFFER_SIZE 512
 #else
 #define KBD_BUFFER_SIZE 4096
@@ -147,13 +145,17 @@ 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;
 int raw_keybuf_count;
 
 #define GROW_RAW_KEYBUF                                                        \
-if (raw_keybuf_count == XVECTOR (raw_keybuf)->size)                    \
+ if (raw_keybuf_count == XVECTOR (raw_keybuf)->size)                   \
   {                                                                    \
     int newsize = 2 * XVECTOR (raw_keybuf)->size;                      \
     Lisp_Object new;                                                   \
@@ -171,13 +173,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;
 
@@ -224,7 +219,7 @@ static struct kboard *ok_to_echo_at_next_pause;
    exists, and echo_message_buffer is eq to the current message
    buffer, we know that the message comes from echo_kboard.  */
 
-static struct kboard *echo_kboard;
+struct kboard *echo_kboard;
 
 /* The buffer used for echoing.  Set in echo_now, reset in
    cancel_echoing.  */
@@ -300,7 +295,7 @@ Lisp_Object Vspecial_event_map;
 int command_loop_level;
 
 /* Total number of times command_loop has read a key sequence.  */
-int num_input_keys;
+EMACS_INT num_input_keys;
 
 /* Last input character read as a command.  */
 Lisp_Object last_command_char;
@@ -324,7 +319,7 @@ Lisp_Object Vunread_input_method_events;
 Lisp_Object Vunread_post_input_method_events;
 
 /* If not -1, an event to be read as subsequent command input.  */
-int unread_command_char;
+EMACS_INT unread_command_char;
 
 /* If not Qnil, this is a switch-frame event which we decided to put
    off until the end of a key sequence.  This should be read as the
@@ -336,7 +331,7 @@ int unread_command_char;
 Lisp_Object unread_switch_frame;
 
 /* A mask of extra modifier bits to put into every keyboard char.  */
-int extra_keyboard_modifiers;
+EMACS_INT extra_keyboard_modifiers;
 
 /* Char to use as prefix when a meta character is typed in.
    This is bound on entry to minibuffer in case ESC is changed there.  */
@@ -353,12 +348,12 @@ static Lisp_Object Vauto_save_timeout;
 int num_input_events;
 
 /* Total number of times read_char has returned, outside of macros.  */
-int num_nonmacro_input_events;
+EMACS_INT num_nonmacro_input_events;
 
 /* Auto-save automatically when this many characters have been typed
    since the last time.  */
 
-static int auto_save_interval;
+static EMACS_INT auto_save_interval;
 
 /* Value of num_nonmacro_input_events as of last auto save.  */
 
@@ -372,6 +367,10 @@ Lisp_Object Vthis_command;
 /* This is like Vthis_command, except that commands never set it.  */
 Lisp_Object real_this_command;
 
+/* If the lookup of the command returns a binding, the original
+   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.  */
 int last_point_position;
 
@@ -410,7 +409,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.  */
@@ -446,7 +445,7 @@ Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
 Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
 
 /* Delay time in microseconds before running post-command-idle-hook.  */
-int post_command_idle_delay;
+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.  */
@@ -503,7 +502,7 @@ static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
    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
+   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.  */
@@ -512,7 +511,7 @@ 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 the
+   This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the
    next available char is in kbd_buffer[0].  */
 static struct input_event *kbd_fetch_ptr;
 
@@ -542,16 +541,21 @@ Lisp_Object Qswitch_frame;
 Lisp_Object Qdelete_frame;
 Lisp_Object Qiconify_frame;
 Lisp_Object Qmake_frame_visible;
+Lisp_Object Qselect_window;
 Lisp_Object Qhelp_echo;
 
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-#ifdef WINDOWSNT
+#if defined(WINDOWSNT) || defined(MAC_OSX)
 Lisp_Object Qmouse_wheel;
+#endif
+#ifdef WINDOWSNT
 Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
+Lisp_Object Qsave_session;
+
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
@@ -584,17 +588,19 @@ Lisp_Object Qmode_line;
 Lisp_Object Qvertical_line;
 Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
+extern Lisp_Object Qleft_margin, Qright_margin;
 
 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;
 
@@ -638,14 +644,14 @@ 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
 
 /* After a command is executed, if point is moved into a region that
    has specific properties (e.g. composition, display), we adjust
    point to the boundary of the region.  But, if a command sets this
-   valiable to non-nil, we suppress this point adjustment.  This
+   variable to non-nil, we suppress this point adjustment.  This
    variable is set to nil before reading a command.  */
 
 Lisp_Object Vdisable_point_adjustment;
@@ -658,6 +664,11 @@ Lisp_Object Vglobal_disable_point_adjustment;
 
 static EMACS_TIME timer_idleness_start_time;
 
+/* After Emacs stops being idle, this saves the last value
+   of timer_idleness_start_time from when it was idle.  */
+
+static EMACS_TIME timer_last_idleness_start_time;
+
 \f
 /* Global variable declarations.  */
 
@@ -666,7 +677,9 @@ 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 ();
@@ -691,14 +704,12 @@ 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));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
 
-#define        min(a,b)        ((a)<(b)?(a):(b))
-#define        max(a,b)        ((a)>(b)?(a):(b))
-
 /* Install the string STR as the beginning of the string of echoing,
    so that it serves as a prompt for the next character.
    Also start echoing.  */
@@ -707,38 +718,8 @@ void
 echo_prompt (str)
      Lisp_Object str;
 {
-  int nbytes = STRING_BYTES (XSTRING (str));
-  int multibyte_p = STRING_MULTIBYTE (str);
-
-  if (nbytes > ECHOBUFSIZE - 4)
-    {
-      if (multibyte_p)
-       {
-         /* Have to find the last character that fit's into the 
-            echo buffer.  */
-         unsigned char *p = XSTRING (str)->data;
-         unsigned char *pend = p + ECHOBUFSIZE - 4;
-         int char_len;
-
-         do 
-           {
-             PARSE_MULTIBYTE_SEQ (p, pend - p, char_len);
-             p += char_len;
-           }
-         while (p < pend);
-
-         nbytes = p - XSTRING (str)->data - char_len;
-       }
-      else
-       nbytes = ECHOBUFSIZE - 4;
-    }
-
-  nbytes = copy_text (XSTRING (str)->data, current_kboard->echobuf, nbytes,
-                     STRING_MULTIBYTE (str), 1);
-  current_kboard->echoptr = current_kboard->echobuf + nbytes;
-  *current_kboard->echoptr = '\0';
-  current_kboard->echo_after_prompt = nbytes;
-
+  current_kboard->echo_string = str;
+  current_kboard->echo_after_prompt = SCHARS (str);
   echo_now ();
 }
 
@@ -752,43 +733,78 @@ echo_char (c)
 {
   if (current_kboard->immediate_echo)
     {
-      char *ptr = current_kboard->echoptr;
+      int size = KEY_DESCRIPTION_SIZE + 100;
+      char *buffer = (char *) alloca (size);
+      char *ptr = buffer;
+      Lisp_Object echo_string;
 
-      if (ptr != current_kboard->echobuf)
-       *ptr++ = ' ';
+      echo_string = current_kboard->echo_string;
 
       /* If someone has passed us a composite event, use its head symbol.  */
       c = EVENT_HEAD (c);
 
       if (INTEGERP (c))
        {
-         int ch = XINT (c);
-
-         if (ptr - current_kboard->echobuf
-             > ECHOBUFSIZE - KEY_DESCRIPTION_SIZE)
-           return;
-
-         ptr = push_key_description (ch, ptr, 1);
+         ptr = push_key_description (XINT (c), ptr, 1);
        }
       else if (SYMBOLP (c))
        {
-         struct Lisp_String *name = XSYMBOL (c)->name;
-         if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
-             > ECHOBUFSIZE)
-           return;
-         ptr += copy_text (name->data, ptr, STRING_BYTES (name),
-                           name->size_byte >= 0, 1);
+         Lisp_Object name = SYMBOL_NAME (c);
+         int nbytes = SBYTES (name);
+
+         if (size - (ptr - buffer) < nbytes)
+           {
+             int offset = ptr - buffer;
+             size = max (2 * size, size + nbytes);
+             buffer = (char *) alloca (size);
+             ptr = buffer + offset;
+           }
+
+         ptr += copy_text (SDATA (name), ptr, nbytes,
+                           STRING_MULTIBYTE (name), 1);
        }
 
-      if (current_kboard->echoptr == current_kboard->echobuf
+      if ((NILP (echo_string) || SCHARS (echo_string) == 0)
          && help_char_p (c))
        {
-         strcpy (ptr, " (Type ? for further options)");
-         ptr += strlen (ptr);
+         const char *text = " (Type ? for further options)";
+         int len = strlen (text);
+
+         if (size - (ptr - buffer) < len)
+           {
+             int offset = ptr - buffer;
+             size += len;
+             buffer = (char *) alloca (size);
+             ptr = buffer + offset;
+           }
+
+         bcopy (text, ptr, len);
+         ptr += len;
+       }
+
+      /* 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) > 1)
+       {
+         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);
+
+         /* 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 (" "));
        }
 
-      *ptr = 0;
-      current_kboard->echoptr = ptr;
+      current_kboard->echo_string
+       = concat2 (echo_string, make_string (buffer, ptr - buffer));
 
       echo_now ();
     }
@@ -800,22 +816,23 @@ echo_char (c)
 void
 echo_dash ()
 {
+  /* Do nothing if not echoing at all.  */
+  if (NILP (current_kboard->echo_string))
+    return;
+
   if (!current_kboard->immediate_echo
-      && current_kboard->echoptr == current_kboard->echobuf)
+      && SCHARS (current_kboard->echo_string) == 0)
     return;
+
   /* Do nothing if we just printed a prompt.  */
   if (current_kboard->echo_after_prompt
-      == current_kboard->echoptr - current_kboard->echobuf)
-    return;
-  /* Do nothing if not echoing at all.  */
-  if (current_kboard->echoptr == 0)
+      == SCHARS (current_kboard->echo_string))
     return;
 
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
-  current_kboard->echoptr[0] = '-';
-  current_kboard->echoptr[1] = 0;
-
+  current_kboard->echo_string = concat2 (current_kboard->echo_string,
+                                        build_string ("-"));
   echo_now ();
 }
 
@@ -833,17 +850,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;
-  message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
-                 1);
+  message3_nolog (current_kboard->echo_string,
+                 SBYTES (current_kboard->echo_string),
+                 STRING_MULTIBYTE (current_kboard->echo_string));
   echoing = 0;
 
   /* Record in what buffer we echoed, and from which kboard.  */
@@ -860,8 +893,8 @@ void
 cancel_echoing ()
 {
   current_kboard->immediate_echo = 0;
-  current_kboard->echoptr = current_kboard->echobuf;
   current_kboard->echo_after_prompt = -1;
+  current_kboard->echo_string = Qnil;
   ok_to_echo_at_next_pause = NULL;
   echo_kboard = NULL;
   echo_message_buffer = Qnil;
@@ -872,7 +905,9 @@ cancel_echoing ()
 static int
 echo_length ()
 {
-  return current_kboard->echoptr - current_kboard->echobuf;
+  return (STRINGP (current_kboard->echo_string)
+         ? SCHARS (current_kboard->echo_string)
+         : 0);
 }
 
 /* Truncate the current echo message to its first LEN chars.
@@ -880,12 +915,14 @@ echo_length ()
    switches frames while entering a key sequence.  */
 
 static void
-echo_truncate (len)
-     int len;
+echo_truncate (nchars)
+     int nchars;
 {
-  current_kboard->echobuf[len] = '\0';
-  current_kboard->echoptr = current_kboard->echobuf + len;
-  truncate_echo_area (len);
+  if (STRINGP (current_kboard->echo_string))
+    current_kboard->echo_string
+      = Fsubstring (current_kboard->echo_string,
+                   make_number (0), make_number (nchars));
+  truncate_echo_area (nchars);
 }
 
 \f
@@ -894,6 +931,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)
@@ -904,6 +943,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,
@@ -918,7 +958,7 @@ add_command_key (key)
 Lisp_Object
 recursive_edit_1 ()
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   Lisp_Object val;
 
   if (command_loop_level > 0)
@@ -930,8 +970,8 @@ recursive_edit_1 ()
 #ifdef HAVE_X_WINDOWS
   /* The command loop has started an hourglass timer, so we have to
      cancel it here, otherwise it will fire because the recursive edit
-     can take some time.  */
-  if (display_hourglass_p)
+     can take some time.  Do not check for display_hourglass_p here,
+     because it could already be nil.  */
     cancel_hourglass ();
 #endif
 
@@ -977,14 +1017,14 @@ force_auto_save_soon ()
 }
 \f
 DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
-  "Invoke the editor command loop recursively.\n\
-To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\
-that tells this function to return.\n\
-Alternately, `(throw 'exit t)' makes this function signal an error.\n\
-This function is called by the editor initialization to begin editing.")
-  ()
-{
-  int count = specpdl_ptr - specpdl;
+       doc: /* Invoke the editor command loop recursively.
+To get out of the recursive edit, a command can do `(throw 'exit nil)';
+that tells this function to return.
+Alternately, `(throw 'exit t)' makes this function signal an error.
+This function is called by the editor initialization to begin editing.  */)
+     ()
+{
+  int count = SPECPDL_INDEX ();
   Lisp_Object buffer;
 
   command_loop_level++;
@@ -1013,12 +1053,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;
@@ -1105,6 +1145,11 @@ cmd_error (data)
   Lisp_Object old_level, old_length;
   char macroerror[50];
 
+#ifdef HAVE_X_WINDOWS
+  if (display_hourglass_p)
+    cancel_hourglass ();
+#endif
+
   if (!NILP (executing_macro))
     {
       if (executing_macro_iterations == 1)
@@ -1181,14 +1226,19 @@ cmd_error_internal (data, context)
   else
     {
       Fdiscard_input ();
+      message_log_maybe_newline ();
       bitch_at_user ();
       stream = Qt;
     }
 
-  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);
+  print_error_message (data, stream, context, Vsignaling_function);
+
+  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.  */
@@ -1233,7 +1283,7 @@ command_loop ()
 /* Here we catch errors in execution of commands within the
    editing loop, and reenter the editing loop.
    When there is an error, cmd_error runs and returns a non-nil
-   value to us.  A value of nil means that cmd_loop_1 itself
+   value to us.  A value of nil means that command_loop_1 itself
    returned due to end of file (or end of kbd macro).  */
 
 Lisp_Object
@@ -1268,8 +1318,8 @@ top_level_1 ()
 }
 
 DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
-  "Exit all recursive editing levels.")
-  ()
+       doc: /* Exit all recursive editing levels.  */)
+     ()
 {
 #ifdef HAVE_X_WINDOWS
   if (display_hourglass_p)
@@ -1279,8 +1329,8 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
 }
 
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
-  "Exit from the innermost recursive edit or minibuffer.")
-  ()
+       doc: /* Exit from the innermost recursive edit or minibuffer.  */)
+     ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     Fthrow (Qexit, Qnil);
@@ -1290,8 +1340,8 @@ DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0,
 }
 
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
-  "Abort the command that requested this recursive edit or minibuffer input.")
-  ()
+       doc: /* Abort the command that requested this recursive edit or minibuffer input.  */)
+     ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     Fthrow (Qexit, Qt);
@@ -1303,11 +1353,21 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
-EXFUN (Fcommand_execute, 4);
 static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object,
                                  int, int, int));
 void safe_run_hooks P_ ((Lisp_Object));
-static void adjust_point_for_property P_ ((int));
+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 ();
+}
+#endif
 
 Lisp_Object
 command_loop_1 ()
@@ -1323,6 +1383,7 @@ command_loop_1 ()
 #ifdef MULTI_KBOARD
   int was_locked = single_kboard;
 #endif
+  int already_adjusted;
 
   current_kboard->Vprefix_arg = Qnil;
   current_kboard->Vlast_prefix_arg = Qnil;
@@ -1332,33 +1393,39 @@ command_loop_1 ()
 
   nonundocount = 0;
   this_command_key_count = 0;
+  this_command_key_count_reset = 0;
   this_single_command_key_start = 0;
 
-  /* Make sure this hook runs after commands that get errors and
-     throw to top level.  */
-  /* Note that the value cell will never directly contain nil
-     if the symbol is a local variable.  */
-  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-    safe_run_hooks (Qpost_command_hook);
+  if (NILP (Vmemory_full))
+    {
+      /* Make sure this hook runs after commands that get errors and
+        throw to top level.  */
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpost_command_hook);
 
-  /* If displaying a message, resize the echo area window to fit
-     that message's size exactly.  */
-  if (!NILP (echo_area_buffer[0]))
-    resize_echo_area_exactly ();
+      /* If displaying a message, resize the echo area window to fit
+        that message's size exactly.  */
+      if (!NILP (echo_area_buffer[0]))
+       resize_echo_area_exactly ();
 
-  if (!NILP (Vdeferred_action_list))
-    call0 (Vdeferred_action_function);
+      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);
+      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);
+       }
     }
 
+  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;
@@ -1392,7 +1459,7 @@ command_loop_1 ()
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
-         int count = specpdl_ptr - specpdl;
+         int count = SPECPDL_INDEX ();
          specbind (Qinhibit_quit, Qt);
 
          Fsit_for (Vminibuffer_message_timeout, Qnil, Qnil);
@@ -1459,6 +1526,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;
        }
@@ -1506,6 +1574,15 @@ command_loop_1 ()
         reset it before we execute the command. */
       Vdeactivate_mark = Qnil;
 
+      /* Remap command through active keymaps */
+      Vthis_original_command = cmd;
+      if (SYMBOLP (cmd))
+       {
+         Lisp_Object cmd1;
+         if (cmd1 = Fcommand_remapping (cmd), !NILP (cmd1))
+           cmd = cmd1;
+       }
+
       /* Execute the command.  */
 
       Vthis_command = cmd;
@@ -1514,7 +1591,9 @@ 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.  */
@@ -1538,12 +1617,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)
@@ -1567,12 +1657,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)
@@ -1588,10 +1687,13 @@ command_loop_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)
                      && !EQ (minibuf_window, selected_window))
@@ -1603,7 +1705,7 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
-                 
+
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1616,12 +1718,17 @@ command_loop_1 ()
                          || detect_input_pending ()
                          || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_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.  */
@@ -1633,20 +1740,33 @@ command_loop_1 ()
 
          /* Here for a command that isn't executed directly */
 
+          {
 #ifdef HAVE_X_WINDOWS
-         if (display_hourglass_p)
-           start_hourglass ();
+            int scount = SPECPDL_INDEX ();
+
+            if (display_hourglass_p
+                && NILP (Vexecuting_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
-         if (display_hourglass_p)
-           cancel_hourglass ();
+         /* Do not check display_hourglass_p here, because
+            Fcommand_execute could change it, but we should cancel
+            hourglass cursor anyway.
+            But don't cancel the hourglass within a macro
+            just because a command in the macro finishes.  */
+         if (NILP (Vexecuting_macro))
+            unbind_to (scount, Qnil);
 #endif
+          }
        }
     directly_done: ;
       current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg;
@@ -1693,6 +1813,7 @@ 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;
        }
 
@@ -1700,8 +1821,14 @@ command_loop_1 ()
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
            {
-             current_buffer->mark_active = Qnil;
-             call1 (Vrun_hooks, intern ("deactivate-mark-hook"));
+             /* We could also call `deactivate'mark'.  */
+             if (EQ (Vtransient_mark_mode, Qlambda))
+               Vtransient_mark_mode = Qnil;
+             else
+               {
+                 current_buffer->mark_active = Qnil;
+                 call1 (Vrun_hooks, intern ("deactivate-mark-hook"));
+               }
            }
          else if (current_buffer != prev_buffer || MODIFF != prev_modiff)
            call1 (Vrun_hooks, intern ("activate-mark-hook"));
@@ -1712,8 +1839,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.  */
 
@@ -1732,47 +1860,131 @@ 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.  */
        {
-         if (PT < last_pt)
-           SET_PT (start);
-         else
-           SET_PT (end);
-         check_composition = 1;
+         xassert (end > PT);
+         SET_PT (PT < last_pt ? 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;
+           }
+         xassert (PT == beg || PT == end);
+         /* 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;
     }
 }
 
@@ -1791,6 +2003,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);
 }
 
@@ -1802,7 +2019,7 @@ void
 safe_run_hooks (hook)
      Lisp_Object hook;
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   specbind (Qinhibit_quit, hook);
 
   internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
@@ -1814,7 +2031,7 @@ safe_run_hooks (hook)
 /* Number of seconds between polling for input.  This is a Lisp
    variable that can be bound.  */
 
-int polling_period;
+EMACS_INT polling_period;
 
 /* Nonzero means polling for input is temporarily suppressed.  */
 
@@ -1864,7 +2081,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
@@ -1874,7 +2091,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);
@@ -2010,7 +2227,7 @@ make_ctrl_char (c)
    the `display' property).  POS is the position in that string under
    the mouse.
 
-   OK_TO_IVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help
+   OK_TO_OVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help
    echo overwrites a keystroke echo currently displayed in the echo
    area.
 
@@ -2035,7 +2252,7 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
        }
       else
        help = safe_eval (help);
-      
+
       if (!STRINGP (help))
        return;
     }
@@ -2054,27 +2271,27 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
        {
          if (STRINGP (help))
            {
-             int count = BINDING_STACK_SIZE ();
+             int count = SPECPDL_INDEX ();
 
              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);
     }
 }
@@ -2091,6 +2308,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.
@@ -2130,11 +2355,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   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;
 
@@ -2180,13 +2408,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;
     }
@@ -2206,9 +2434,7 @@ 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))
     {
@@ -2231,7 +2457,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
        {
          XSETINT (c, -1);
-         RETURN_UNGCPRO (c);
+         goto exit;
        }
 
       c = Faref (Vexecuting_macro, make_number (executing_macro_index));
@@ -2283,7 +2509,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
@@ -2291,10 +2517,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
@@ -2306,8 +2532,8 @@ 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 something in the echo area  */
+
+  if (/* There currently is something in the echo area.  */
       !NILP (echo_area_buffer[0])
       && (/* And it's either not from echoing.  */
          !EQ (echo_area_buffer[0], echo_message_buffer)
@@ -2318,7 +2544,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
@@ -2361,15 +2587,21 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
        if (kb != current_kboard)
          {
-           Lisp_Object *tailp = &kb->kbd_queue;
+           Lisp_Object link = kb->kbd_queue;
            /* We shouldn't get here if we were in single-kboard mode!  */
            if (single_kboard)
              abort ();
-           while (CONSP (*tailp))
-             tailp = &XCDR (*tailp);
-           if (!NILP (*tailp))
-             abort ();
-           *tailp = Fcons (c, Qnil);
+           if (CONSP (link))
+             {
+               while (CONSP (XCDR (link)))
+                 link = XCDR (link);
+               if (!NILP (XCDR (link)))
+                 abort ();
+             }
+           if (!CONSP (link))
+             kb->kbd_queue = Fcons (c, Qnil);
+           else
+             XSETCDR (link, Fcons (c, Qnil));
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
            /* This is going to exit from read_char
@@ -2387,7 +2619,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
@@ -2404,7 +2636,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.  */
@@ -2457,7 +2689,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.  */
@@ -2564,7 +2796,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
@@ -2584,12 +2816,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 #ifdef MULTI_KBOARD
       if (! NILP (c) && (kb != current_kboard))
        {
-         Lisp_Object *tailp = &kb->kbd_queue;
-         while (CONSP (*tailp))
-           tailp = &XCDR (*tailp);
-         if (!NILP (*tailp))
-           abort ();
-         *tailp = Fcons (c, Qnil);
+         Lisp_Object link = kb->kbd_queue;
+         if (CONSP (link))
+           {
+             while (CONSP (XCDR (link)))
+               link = XCDR (link);
+             if (!NILP (XCDR (link)))
+               abort ();
+           }
+         if (!CONSP (link))
+           kb->kbd_queue = Fcons (c, Qnil);
+         else
+           XSETCDR (link, Fcons (c, Qnil));
          kb->kbd_queue_has_data = 1;
          c = Qnil;
          if (single_kboard)
@@ -2627,7 +2865,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      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))
     {
@@ -2644,7 +2882,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.  */
@@ -2660,6 +2898,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       last_input_char = c;
       Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
 
+      if (CONSP (c) && EQ (XCAR (c), Qselect_window))
+       /* We stopped being idle for this event; undo that.  This
+          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;
+
       /* Resume allowing input from any kboard, if that was true before.  */
       if (!was_locked)
        any_kboard_state ();
@@ -2672,14 +2917,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);
@@ -2705,7 +2950,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
+         POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -2755,16 +3000,17 @@ 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_ptr - specpdl;
+      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;
       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;
@@ -2773,9 +3019,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);
@@ -2785,6 +3033,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]))
@@ -2807,6 +3056,7 @@ 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;
 
@@ -2838,22 +3088,27 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
     {
       /* (help-echo FRAME HELP WINDOW OBJECT POS).  */
-      Lisp_Object help, object, position, window;
-      help = Fnth (make_number (2), c);
-      window = Fnth (make_number (3), c);
-      object = Fnth (make_number (4), c);
-      position = Fnth (make_number (5), c);
+      Lisp_Object help, object, position, window, tem;
+
+      tem = Fcdr (XCDR (c));
+      help = Fcar (tem);
+      tem = Fcdr (tem);
+      window = Fcar (tem);
+      tem = Fcdr (tem);
+      object = Fcar (tem);
+      tem = Fcdr (tem);
+      position = Fcar (tem);
+
       show_help_echo (help, window, object, position, 0);
 
       /* We stopped being idle for this event; undo that.  */
       timer_idleness_start_time = last_idle_start;
       goto retry;
     }
-  
-  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))
@@ -2882,7 +3137,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (!NILP (Vhelp_form) && help_char_p (c))
     {
       Lisp_Object tem0;
-      count = specpdl_ptr - specpdl;
+      count = SPECPDL_INDEX ();
 
       record_unwind_protect (Fset_window_configuration,
                             Fcurrent_window_configuration (Qnil));
@@ -2908,6 +3163,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+ exit:
+  RESUME_POLLING;
   RETURN_UNGCPRO (c);
 }
 
@@ -2923,8 +3180,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))
@@ -2967,44 +3226,102 @@ static void
 record_char (c)
      Lisp_Object c;
 {
-  /* Don't record `help-echo' in recent_keys unless it shows some help
-     message, and a different help than the previoiusly recorded
-     event.  */
-  if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
+  int recorded = 0;
+
+  if (CONSP (c) && (EQ (XCAR (c), Qhelp_echo) || EQ (XCAR (c), Qmouse_movement)))
     {
-      Lisp_Object help;
+      /* To avoid filling recent_keys with help-echo and mouse-movement
+        events, we filter out repeated help-echo events, only store the
+        first and last in a series of mouse-movement events, and don't
+        store repeated help-echo events which are only separated by
+        mouse-movement events.  */
+
+      Lisp_Object ev1, ev2, ev3;
+      int ix1, ix2, ix3;
 
-      help = Fnth (make_number (2), c);
-      if (STRINGP (help))
+      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
+            message, and a different help than the previously recorded
+            event.  */
+         Lisp_Object help, last_help;
+
+         help = Fcar_safe (Fcdr_safe (XCDR (c)));
+         if (!STRINGP (help))
+           recorded = 1;
+         else if (CONSP (ev1) && EQ (XCAR (ev1), Qhelp_echo)
+                  && (last_help = Fcar_safe (Fcdr_safe (XCDR (ev1))), EQ (last_help, help)))
+           recorded = 1;
+         else if (CONSP (ev1) && EQ (XCAR (ev1), Qmouse_movement)
+                  && CONSP (ev2) && EQ (XCAR (ev2), Qhelp_echo)
+                  && (last_help = Fcar_safe (Fcdr_safe (XCDR (ev2))), EQ (last_help, help)))
+           recorded = -1;
+         else if (CONSP (ev1) && EQ (XCAR (ev1), Qmouse_movement)
+                  && CONSP (ev2) && EQ (XCAR (ev2), Qmouse_movement)
+                  && CONSP (ev3) && EQ (XCAR (ev3), Qhelp_echo)
+                  && (last_help = Fcar_safe (Fcdr_safe (XCDR (ev3))), EQ (last_help, help)))
+           recorded = -2;
+       }
+      else if (EQ (XCAR (c), Qmouse_movement))
        {
-         int last_idx;
-         Lisp_Object last_c, last_help;
-         
-         last_idx = recent_keys_index - 1;
-         if (last_idx < 0)
-           last_idx = NUM_RECENT_KEYS - 1;
-         last_c = AREF (recent_keys, last_idx);
-         
-         if (!CONSP (last_c)
-             || !EQ (XCAR (last_c), Qhelp_echo)
-             || (last_help = Fnth (make_number (2), last_c),
-                 !EQ (last_help, help)))
+         /* Only record one pair of `mouse-movement' on a window in recent_keys.
+            So additional mouse movement events replace the last element.  */
+         Lisp_Object last_window, window;
+
+         window = Fcar_safe (Fcar_safe (XCDR (c)));
+         if (CONSP (ev1) && EQ (XCAR (ev1), Qmouse_movement)
+             && (last_window = Fcar_safe (Fcar_safe (XCDR (ev1))), EQ (last_window, window))
+             && CONSP (ev2) && EQ (XCAR (ev2), Qmouse_movement)
+             && (last_window = Fcar_safe (Fcar_safe (XCDR (ev2))), EQ (last_window, window)))
            {
-             total_keys++;
-             ASET (recent_keys, recent_keys_index, c);
-             if (++recent_keys_index >= NUM_RECENT_KEYS)
-               recent_keys_index = 0;
+             ASET (recent_keys, ix1, c);
+             recorded = 1;
            }
        }
     }
   else
+    store_kbd_macro_char (c);
+
+  if (!recorded)
     {
       total_keys++;
       ASET (recent_keys, recent_keys_index, c);
       if (++recent_keys_index >= NUM_RECENT_KEYS)
        recent_keys_index = 0;
     }
-      
+  else if (recorded < 0)
+    {
+      /* We need to remove one or two events from recent_keys.
+         To do this, we simply put nil at those events and move the
+        recent_keys_index backwards over those events.  Usually,
+        users will never see those nil events, as they will be
+        overwritten by the command keys entered to see recent_keys
+        (e.g. C-h l).  */
+
+      while (recorded++ < 0 && total_keys > 0)
+       {
+         if (total_keys < NUM_RECENT_KEYS)
+           total_keys--;
+         if (--recent_keys_index < 0)
+           recent_keys_index = NUM_RECENT_KEYS - 1;
+         ASET (recent_keys, recent_keys_index, Qnil);
+       }
+    }
+
+  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.  :-) */
@@ -3027,8 +3344,8 @@ record_char (c)
          if (SYMBOLP (dribblee))
            {
              putc ('<', dribble);
-             fwrite (XSYMBOL (dribblee)->name->data, sizeof (char),
-                     STRING_BYTES (XSYMBOL (dribblee)->name),
+             fwrite (SDATA (SYMBOL_NAME (dribblee)), sizeof (char),
+                     SBYTES (SYMBOL_NAME (dribblee)),
                      dribble);
              putc ('>', dribble);
            }
@@ -3036,11 +3353,6 @@ record_char (c)
 
       fflush (dribble);
     }
-
-  if (!CONSP (c) || !EQ (Qhelp_echo, XCAR (c)))
-    store_kbd_macro_char (c);
-
-  num_nonmacro_input_events++;
 }
 
 Lisp_Object
@@ -3101,14 +3413,15 @@ tracking_off (old_value)
 }
 
 DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
-  "Evaluate BODY with mouse movement events enabled.\n\
-Within a `track-mouse' form, mouse motion generates input events that\n\
-you can read with `read-event'.\n\
-Normally, mouse motion is ignored.")
-  (args)
+       doc: /* Evaluate BODY with mouse movement events enabled.
+Within a `track-mouse' form, mouse motion generates input events that
+you can read with `read-event'.
+Normally, mouse motion is ignored.
+usage: (track-mouse BODY ...)  */)
+     (args)
      Lisp_Object args;
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   Lisp_Object val;
 
   record_unwind_protect (tracking_off, do_mouse_tracking);
@@ -3145,14 +3458,39 @@ 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_events (do_timers_now)
+readable_filtered_events (do_timers_now, filter_events)
      int do_timers_now;
+     int filter_events;
 {
   if (do_timers_now)
     timer_check (do_timers_now);
 
+  /* If the buffer contains only FOCUS_IN_EVENT events,
+     and FILTER_EVENTS is nonzero, report it as empty.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
-    return 1;
+    {
+      int have_live_event = 1;
+
+      if (filter_events)
+        {
+          struct input_event *event;
+
+          event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
+                   ? kbd_fetch_ptr
+                   : kbd_buffer);
+
+          while (have_live_event && event->kind == FOCUS_IN_EVENT)
+            {
+              event++;
+              if (event == kbd_buffer + KBD_BUFFER_SIZE)
+                event = kbd_buffer;
+              if (event == kbd_store_ptr)
+                have_live_event = 0;
+            }
+        }
+      if (have_live_event) return 1;
+    }
+
 #ifdef HAVE_MOUSE
   if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
@@ -3172,6 +3510,15 @@ readable_events (do_timers_now)
   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;
 
@@ -3203,10 +3550,10 @@ void
 kbd_buffer_store_event (event)
      register struct input_event *event;
 {
-  if (event->kind == no_event)
+  if (event->kind == NO_EVENT)
     abort ();
 
-  if (event->kind == ascii_keystroke)
+  if (event->kind == ASCII_KEYSTROKE_EVENT)
     {
       register int c = event->code & 0377;
 
@@ -3219,7 +3566,6 @@ kbd_buffer_store_event (event)
 
       if (c == quit_char)
        {
-         extern SIGTYPE interrupt_signal ();
 #ifdef MULTI_KBOARD
          KBOARD *kb;
          struct input_event *sp;
@@ -3239,7 +3585,7 @@ kbd_buffer_store_event (event)
 
                  if (event_to_kboard (sp) == kb)
                    {
-                     sp->kind = no_event;
+                     sp->kind = NO_EVENT;
                      sp->frame_or_window = Qnil;
                      sp->arg = Qnil;
                    }
@@ -3263,7 +3609,7 @@ kbd_buffer_store_event (event)
          }
 
          last_event_timestamp = event->timestamp;
-         interrupt_signal ();
+         interrupt_signal (0 /* dummy */);
          return;
        }
 
@@ -3273,11 +3619,11 @@ kbd_buffer_store_event (event)
          return;
        }
     }
-  /* Don't insert two buffer_switch_event's in a row.
+  /* Don't insert two BUFFER_SWITCH_EVENT's in a row.
      Just ignore the second one.  */
-  else if (event->kind == buffer_switch_event
+  else if (event->kind == BUFFER_SWITCH_EVENT
           && kbd_fetch_ptr != kbd_store_ptr
-          && kbd_store_ptr->kind == buffer_switch_event)
+          && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT)
     return;
 
   if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
@@ -3290,13 +3636,13 @@ kbd_buffer_store_event (event)
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
       int idx;
-      
-#if 0 /* The selection_request_event case looks bogus, and it's error
+
+#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)
+      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
@@ -3347,25 +3693,17 @@ gen_help_event (bufp, size, help, frame, window, object, pos)
      Lisp_Object help, frame, object, window;
      int pos;
 {
-  int nevents_stored = 0;
-  
-  if (size >= 2)
+  if (size >= 1)
     {
       bufp->kind = HELP_EVENT;
       bufp->frame_or_window = frame;
       bufp->arg = object;
-      bufp->x = make_number (pos);
-      bufp->code = 0;
-
-      ++bufp;
-      bufp->kind = HELP_EVENT;
-      bufp->frame_or_window = WINDOWP (window) ? window : frame;
-      bufp->arg = help;
-      bufp->code = 1;
-      nevents_stored = 2;
+      bufp->x = WINDOWP (window) ? window : frame;
+      bufp->y = help;
+      bufp->code = pos;
+      return 1;
     }
-
-  return nevents_stored;
+  return 0;
 }
 
 
@@ -3380,21 +3718,15 @@ kbd_buffer_store_help_event (frame, help)
   event.kind = HELP_EVENT;
   event.frame_or_window = frame;
   event.arg = Qnil;
-  event.x = make_number (0);
+  event.x = Qnil;
+  event.y = help;
   event.code = 0;
   kbd_buffer_store_event (&event);
-  
-  event.kind = HELP_EVENT;
-  event.frame_or_window = frame;
-  event.arg = help;
-  event.x = make_number (0);
-  event.code = 1;
-  kbd_buffer_store_event (&event);
 }
 
 \f
 /* Discard any mouse events in the event buffer by setting them to
-   no_event.  */
+   NO_EVENT.  */
 void
 discard_mouse_events ()
 {
@@ -3404,22 +3736,22 @@ discard_mouse_events ()
       if (sp == kbd_buffer + KBD_BUFFER_SIZE)
        sp = kbd_buffer;
 
-      if (sp->kind == mouse_click
+      if (sp->kind == MOUSE_CLICK_EVENT
 #ifdef WINDOWSNT
-         || sp->kind == w32_scroll_bar_click
+         || sp->kind == W32_SCROLL_BAR_CLICK_EVENT
 #endif
-         || sp->kind == scroll_bar_click)
+         || sp->kind == SCROLL_BAR_CLICK_EVENT)
        {
-         sp->kind = no_event;
+         sp->kind = NO_EVENT;
        }
     }
 }
 
 
 /* Return non-zero if there are any real events waiting in the event
-   buffer, not counting `no_event's.
+   buffer, not counting `NO_EVENT's.
 
-   If DISCARD is non-zero, discard no_event events at the front of
+   If DISCARD is non-zero, discard NO_EVENT events at the front of
    the input queue, possibly leaving the input queue empty if there
    are no real input events.  */
 
@@ -3428,9 +3760,9 @@ 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 != kbd_store_ptr && sp->kind == NO_EVENT;
        ++sp)
     {
       if (sp == kbd_buffer + KBD_BUFFER_SIZE)
@@ -3440,7 +3772,7 @@ kbd_buffer_events_waiting (discard)
   if (discard)
     kbd_fetch_ptr = sp;
 
-  return sp != kbd_store_ptr && sp->kind != no_event;
+  return sp != kbd_store_ptr && sp->kind != NO_EVENT;
 }
 
 \f
@@ -3453,7 +3785,7 @@ clear_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;
+  event->kind = NO_EVENT;
 }
 
 
@@ -3558,7 +3890,7 @@ 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)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3577,7 +3909,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif
        }
 
-      else if (event->kind == selection_clear_event)
+      else if (event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3593,8 +3925,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          abort ();
 #endif
        }
-#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (macintosh)
-      else if (event->kind == delete_window_event)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
+      else if (event->kind == DELETE_WINDOW_EVENT)
        {
          /* Make an event (delete-frame (FRAME)).  */
          obj = Fcons (event->frame_or_window, Qnil);
@@ -3603,14 +3935,14 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        }
 #endif
 #if defined (HAVE_X11) || defined (HAVE_NTGUI)
-      else if (event->kind == iconify_event)
+      else if (event->kind == ICONIFY_EVENT)
        {
          /* Make an event (iconify-frame (FRAME)).  */
          obj = Fcons (event->frame_or_window, Qnil);
          obj = Fcons (Qiconify_frame, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
-      else if (event->kind == deiconify_event)
+      else if (event->kind == DEICONIFY_EVENT)
        {
          /* Make an event (make-frame-visible (FRAME)).  */
          obj = Fcons (event->frame_or_window, Qnil);
@@ -3618,14 +3950,15 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          kbd_fetch_ptr = event + 1;
        }
 #endif
-      else if (event->kind == buffer_switch_event)
+      else if (event->kind == BUFFER_SWITCH_EVENT)
        {
          /* The value doesn't matter here; only the type is tested.  */
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
-      else if (event->kind == menu_bar_activate_event)
+#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;
          input_pending = readable_events (0);
@@ -3634,50 +3967,47 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        }
 #endif
 #ifdef WINDOWSNT
-      else if (event->kind == language_change_event)
+      else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
          /* Make an event (language-change (FRAME CHARSET LCID)).  */
          obj = Fcons (event->modifiers, Qnil);
-         obj = Fcons (event->code, Qnil);
+         obj = Fcons (event->code, obj);
          obj = Fcons (event->frame_or_window, obj);
          obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
 #endif
+      else if (event->kind == SAVE_SESSION_EVENT)
+        {
+          obj = Fcons (Qsave_session, Qnil);
+         kbd_fetch_ptr = event + 1;
+        }
       /* Just discard these, by returning nil.
         With MULTI_KBOARD, these events are used as placeholders
         when we need to randomly delete events from the queue.
         (They shouldn't otherwise be found in the buffer,
         but on some machines it appears they do show up
         even without MULTI_KBOARD.)  */
-      /* On Windows NT/9X, no_event is used to delete extraneous
+      /* On Windows NT/9X, NO_EVENT is used to delete extraneous
          mouse events during a popup-menu call.  */
-      else if (event->kind == no_event)
+      else if (event->kind == NO_EVENT)
        kbd_fetch_ptr = event + 1;
       else if (event->kind == HELP_EVENT)
        {
-         /* There are always two HELP_EVENTs in the input queue.  */
          Lisp_Object object, position, help, frame, window;
 
-         xassert (event->code == 0);
          frame = event->frame_or_window;
          object = event->arg;
-         position = event->x;
+         position = make_number (event->code);
+         window = event->x;
+         help = event->y;
          clear_event (event);
 
          kbd_fetch_ptr = event + 1;
-         event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
-                  ? kbd_fetch_ptr
-                  : kbd_buffer);
-         xassert (event->code == 1);
-         help = event->arg;
-         window = event->frame_or_window;
          if (!WINDOWP (window))
            window = Qnil;
          obj = Fcons (Qhelp_echo,
                       list5 (frame, help, window, object, position));
-         clear_event (event);
-         kbd_fetch_ptr = event + 1;
        }
       else if (event->kind == FOCUS_IN_EVENT)
        {
@@ -3725,8 +4055,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
@@ -3820,7 +4151,7 @@ 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)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3839,7 +4170,7 @@ swallow_events (do_display)
 #endif
        }
 
-      else if (event->kind == selection_clear_event)
+      else if (event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3881,6 +4212,8 @@ timer_start_idle ()
 
   EMACS_GET_TIME (timer_idleness_start_time);
 
+  timer_last_idleness_start_time = timer_idleness_start_time;
+
   /* Mark all idle-time timers as once again candidates for running.  */
   for (timers = Vtimer_idle_list; CONSP (timers); timers = XCDR (timers))
     {
@@ -4053,7 +4386,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
@@ -4062,7 +4395,7 @@ timer_check (do_it_now)
          if (NILP (vector[0]))
            {
              int was_locked = single_kboard;
-             int count = BINDING_STACK_SIZE ();
+             int count = SPECPDL_INDEX ();
              Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
@@ -4070,7 +4403,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++;
@@ -4103,7 +4436,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
+#if defined(WINDOWSNT) || defined(MAC_OSX)
 static Lisp_Object mouse_wheel_syms;
 #endif
 static Lisp_Object drag_n_drop_syms;
@@ -4178,6 +4511,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.
@@ -4198,6 +4566,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
@@ -4206,36 +4581,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 */
@@ -4252,25 +4627,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 */
@@ -4311,13 +4686,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 */
@@ -4339,17 +4714,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 */
@@ -4364,6 +4739,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[] =
   {
@@ -4378,7 +4757,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",
@@ -4398,6 +4777,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
 
@@ -4496,9 +4876,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",
@@ -4512,7 +4892,7 @@ static char *iso_lispy_function_keys[] =
 
 Lisp_Object Vlispy_mouse_stem;
 
-#ifdef WINDOWSNT
+#if defined(WINDOWSNT) || defined(MAC_OSX)
 /* 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
@@ -4520,7 +4900,7 @@ Lisp_Object Vlispy_mouse_stem;
    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[] = 
+static char *lispy_mouse_wheel_names[] =
 {
   "mouse-wheel"
 };
@@ -4583,7 +4963,7 @@ Lisp_Object Vdouble_click_time;
 /* Maximum number of pixels the mouse may be moved between clicks
    to make a double-click.  */
 
-int double_click_fuzz;
+EMACS_INT double_click_fuzz;
 
 /* The number of clicks in this multiple-click. */
 
@@ -4606,7 +4986,7 @@ make_lispy_event (event)
   switch (SWITCH_ENUM_CAST (event->kind))
     {
       /* A simple keystroke.  */
-    case ascii_keystroke:
+    case ASCII_KEYSTROKE_EVENT:
       {
        Lisp_Object lispy_c;
        int c = event->code & 0377;
@@ -4630,17 +5010,26 @@ make_lispy_event (event)
        return lispy_c;
       }
 
-    case multibyte_char_keystroke:
+    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;
       }
 
       /* A function key.  The symbol may need to have modifier prefixes
         tacked onto it.  */
-    case non_ascii_keystroke:
+    case NON_ASCII_KEYSTROKE_EVENT:
       button_down_time = 0;
 
       for (i = 0; i < sizeof (lispy_accent_codes) / sizeof (int); i++)
@@ -4652,21 +5041,7 @@ make_lispy_event (event)
                                      (sizeof (lispy_accent_keys)
                                       / sizeof (lispy_accent_keys[0])));
 
-      /* Handle system-specific keysyms.  */
-      if (event->code & (1 << 28))
-       {
-         /* We need to use an alist rather than a vector as the cache
-            since we can't make a vector long enuf.  */
-         if (NILP (current_kboard->system_key_syms))
-           current_kboard->system_key_syms = Fcons (Qnil, Qnil);
-         return modify_event_symbol (event->code,
-                                     event->modifiers,
-                                     Qfunction_key,
-                                     current_kboard->Vsystem_key_alist,
-                                     0, &current_kboard->system_key_syms,
-                                     (unsigned)-1);
-       }
-
+#if 0
 #ifdef XK_kana_A
       if (event->code >= 0x400 && event->code < 0x500)
        return modify_event_symbol (event->code - 0x400,
@@ -4676,6 +5051,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
@@ -4686,21 +5062,40 @@ make_lispy_event (event)
                                    iso_lispy_function_keys, &func_key_syms,
                                    (sizeof (iso_lispy_function_keys)
                                     / sizeof (iso_lispy_function_keys[0])));
-      else
 #endif
-       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
-                                   event->modifiers,
-                                   Qfunction_key, Qnil,
-                                   lispy_function_keys, &func_key_syms,
-                                   (sizeof (lispy_function_keys)
-                                    / sizeof (lispy_function_keys[0])));
+
+      /* Handle system-specific or unknown keysyms.  */
+      if (event->code & (1 << 28)
+         || event->code - FUNCTION_KEY_OFFSET < 0
+         || (event->code - FUNCTION_KEY_OFFSET
+             >= sizeof lispy_function_keys / sizeof *lispy_function_keys)
+         || !lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
+       {
+         /* We need to use an alist rather than a vector as the cache
+            since we can't make a vector long enuf.  */
+         if (NILP (current_kboard->system_key_syms))
+           current_kboard->system_key_syms = Fcons (Qnil, Qnil);
+         return modify_event_symbol (event->code,
+                                     event->modifiers,
+                                     Qfunction_key,
+                                     current_kboard->Vsystem_key_alist,
+                                     0, &current_kboard->system_key_syms,
+                                     (unsigned) -1);
+       }
+
+      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                 event->modifiers,
+                                 Qfunction_key, Qnil,
+                                 lispy_function_keys, &func_key_syms,
+                                 (sizeof (lispy_function_keys)
+                                  / sizeof (lispy_function_keys[0])));
 
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
-    case mouse_click:
+    case MOUSE_CLICK_EVENT:
 #ifndef USE_TOOLKIT_SCROLL_BARS
-    case scroll_bar_click:
+    case SCROLL_BAR_CLICK_EVENT:
 #endif
       {
        int button = event->code;
@@ -4713,13 +5108,14 @@ make_lispy_event (event)
        position = Qnil;
 
        /* Build the position as appropriate for this mouse click.  */
-       if (event->kind == mouse_click)
+       if (event->kind == MOUSE_CLICK_EVENT)
          {
-           int part;
+           enum window_part part;
            struct frame *f = XFRAME (event->frame_or_window);
            Lisp_Object posn;
            Lisp_Object string_info = Qnil;
            int row, column;
+           int wx, wy;
 
            /* Ignore mouse events that were made on frame that
               have been deleted.  */
@@ -4734,7 +5130,7 @@ make_lispy_event (event)
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                                   &column, &row, NULL, 1);
 
-#ifndef USE_X_TOOLKIT
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* In the non-toolkit version, clicks on the menu bar
               are ordinary button events in the event buffer.
               Distinguish them, and invoke the menu.
@@ -4768,7 +5164,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;
@@ -4786,12 +5182,13 @@ make_lispy_event (event)
 
                return Fcons (item, Fcons (position, Qnil));
              }
-#endif /* not USE_X_TOOLKIT */
+#endif /* not USE_X_TOOLKIT && not USE_GTK */
 
            /* 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);
+                                             XINT (event->y),
+                                             &part, &wx, &wy, 0);
 
            if (!WINDOWP (window))
              {
@@ -4804,30 +5201,34 @@ make_lispy_event (event)
                   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)
+               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 == 1 ? Qmode_line : Qheader_line;
-                   string = mode_line_string (w, wx, wy, part == 1, &charpos);
+
+                   posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+                   string = mode_line_string (w, wx, wy, part, &charpos);
                    if (STRINGP (string))
                      string_info = Fcons (string, make_number (charpos));
                  }
-               else if (part == 2)
+               else if (part == ON_VERTICAL_BORDER)
                  posn = Qvertical_line;
+               else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+                 {
+                   int charpos;
+                   Lisp_Object object = marginal_area_string (w, wx, wy, part,
+                                                              &charpos);
+                   posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
+                   if (STRINGP (object))
+                     string_info = Fcons (object, make_number (charpos));
+                 }
                else
                  {
                    Lisp_Object object;
@@ -4876,7 +5277,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;
@@ -4909,7 +5310,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);
@@ -4951,34 +5352,30 @@ make_lispy_event (event)
            else
 #endif
              {
-               /* The third element of every position should be the (x,y)
-                  pair.  */
                Lisp_Object down;
+               EMACS_INT xdiff = double_click_fuzz, ydiff = double_click_fuzz;
+
+               /* The third element of every position
+                  should be the (x,y) pair.  */
+               down = Fcar (Fcdr (Fcdr (start_pos)));
+               if (CONSP (down)
+                   && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down)))
+                 {
+                   xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down));
+                   ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down));
+                 }
 
-               down = Fnth (make_number (2), start_pos);
-               if (EQ (event->x, XCAR (down)) && EQ (event->y, XCDR (down)))
-                 /* Mouse hasn't moved.  */
+               if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz
+                   && ydiff < double_click_fuzz
+                   && ydiff > - double_click_fuzz)
+                 /* Mouse hasn't moved (much).  */
                  event->modifiers |= click_modifier;
                else
                  {
-                   Lisp_Object window1, window2, posn1, posn2;
-
-                   /* Avoid generating a drag event if the mouse
-                      hasn't actually moved off the buffer position.  */
-                   window1 = Fnth (make_number (0), position);
-                   posn1 = Fnth (make_number (1), position);
-                   window2 = Fnth (make_number (0), start_pos);
-                   posn2 = Fnth (make_number (1), start_pos);
-
-                   if (EQ (window1, window2) && EQ (posn1, posn2))
-                     event->modifiers |= click_modifier;
-                   else
-                     {
-                       button_down_time = 0;
-                       event->modifiers |= drag_modifier;
-                     }
+                   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)
@@ -5019,7 +5416,7 @@ make_lispy_event (event)
        }
       }
 
-#if USE_TOOLKIT_SCROLL_BARS
+#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
@@ -5037,8 +5434,8 @@ 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:
+
+    case SCROLL_BAR_CLICK_EVENT:
       {
        Lisp_Object position, head, window, portion_whole, part;
 
@@ -5055,21 +5452,25 @@ 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
-    case w32_scroll_bar_click:
+    case W32_SCROLL_BAR_CLICK_EVENT:
       {
        int button = event->code;
        int is_double;
@@ -5103,7 +5504,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);
@@ -5112,9 +5513,11 @@ make_lispy_event (event)
                               Qnil));
        }
       }
-    case mouse_wheel:
+#endif /* WINDOWSNT */
+#if defined(MAC_OSX)
+    case MOUSE_WHEEL_EVENT:
       {
-       int part;
+       enum window_part part;
        FRAME_PTR f = XFRAME (event->frame_or_window);
        Lisp_Object window;
        Lisp_Object posn;
@@ -5128,7 +5531,8 @@ make_lispy_event (event)
        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);
+                                          XINT (event->y),
+                                         &part, 0, 0, 0);
 
        if (!WINDOWP (window))
          {
@@ -5138,18 +5542,18 @@ make_lispy_event (event)
        else
          {
            int pixcolumn, pixrow;
-           column -= XINT (XWINDOW (window)->left);
-           row -= XINT (XWINDOW (window)->top);
+           column -= WINDOW_LEFT_EDGE_COL (XWINDOW (window));
+           row -= WINDOW_TOP_EDGE_LINE (XWINDOW (window));
            glyph_to_pixel_coords (XWINDOW(window), column, row,
                                    &pixcolumn, &pixrow);
            XSETINT (event->x, pixcolumn);
            XSETINT (event->y, pixrow);
 
-           if (part == 1)
+           if (part == ON_MODE_LINE)
              posn = Qmode_line;
-           else if (part == 2)
+           else if (part == ON_VERTICAL_BORDER)
              posn = Qvertical_line;
-           else if (part == 3)
+           else if (part == ON_HEADER_LINE)
              posn = Qheader_line;
            else
              {
@@ -5177,19 +5581,22 @@ make_lispy_event (event)
                                      &mouse_wheel_syms, 1);
          return Fcons (head,
                        Fcons (position,
-                              Fcons (make_number (event->code),
-                                     Qnil)));
+                              /* Insert 1 here so event-click-count works.  */
+                              Fcons (make_number (1),
+                                     Fcons (make_number (event->code),
+                                            Qnil))));
        }
       }
-#endif /* WINDOWSNT */
+#endif /* MAC_OSX */
 
-    case drag_n_drop:
+    case DRAG_N_DROP_EVENT:
       {
-       int part;
+       enum window_part part;
        FRAME_PTR f;
        Lisp_Object window;
        Lisp_Object posn;
        Lisp_Object files;
+       int wx, wy;
 
        /* The frame_or_window field should be a cons of the frame in
           which the event occurred and a list of the filenames
@@ -5206,7 +5613,8 @@ make_lispy_event (event)
          return Qnil;
 
        window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y), &part, 0);
+                                          XINT (event->y),
+                                         &part, &wx, &wy, 0);
 
        if (!WINDOWP (window))
          {
@@ -5219,20 +5627,16 @@ make_lispy_event (event)
               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)
+           if (part == ON_MODE_LINE)
              posn = Qmode_line;
-           else if (part == 2)
+           else if (part == ON_VERTICAL_BORDER)
              posn = Qvertical_line;
-           else if (part == 3)
+           else if (part == ON_HEADER_LINE)
              posn = Qheader_line;
            else
              {
@@ -5265,7 +5669,8 @@ make_lispy_event (event)
       }
 #endif /* HAVE_MOUSE */
 
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
+#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
@@ -5275,10 +5680,16 @@ 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
-          `(tool_bar)' because the code in keyboard.c for menu
+          `(tool_bar)' because the code in keyboard.c for tool bar
           events, which we use, relies on this.  */
        return Fcons (Qtool_bar, Qnil);
       else if (SYMBOLP (event->arg))
@@ -5288,7 +5699,10 @@ make_lispy_event (event)
     case USER_SIGNAL_EVENT:
       /* A user signal.  */
       return *lispy_user_signals[event->code];
-      
+
+    case SAVE_SESSION_EVENT:
+      return Qsave_session;
+
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -5324,32 +5738,31 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Or is it an ordinary mouse movement?  */
   else
     {
-      int area;
+      enum window_part area;
       Lisp_Object window;
       Lisp_Object posn;
+      int wx, wy;
 
       if (frame)
        /* It's in a frame; which window on that frame?  */
-       window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
+       window = window_from_coordinates (frame, XINT (x), XINT (y),
+                                         &area, &wx, &wy, 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));
+
+         /* Set window relative coordinates.  */
          XSETINT (x, wx);
          XSETINT (y, wy);
-         
-         if (area == 1)
+
+         if (area == ON_MODE_LINE)
            posn = Qmode_line;
-         else if (area == 2)
+         else if (area == ON_VERTICAL_BORDER)
            posn = Qvertical_line;
-         else if (area == 3)
+         else if (area == ON_HEADER_LINE)
            posn = Qheader_line;
          else
            {
@@ -5407,16 +5820,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, 1);
+  CHECK_SYMBOL (symbol);
 
   modifiers = 0;
-  name = XSYMBOL (symbol)->name;
+  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;
@@ -5425,7 +5838,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)
@@ -5455,6 +5868,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.  */
@@ -5463,8 +5896,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.  */
@@ -5475,9 +5908,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)
@@ -5532,8 +5965,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);
   }
@@ -5591,11 +6024,11 @@ parse_modifiers (symbol)
       Lisp_Object unmodified;
       Lisp_Object mask;
 
-      unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
-                                        STRING_BYTES (XSYMBOL (symbol)->name) - end),
+      unmodified = Fintern (make_string (SDATA (SYMBOL_NAME (symbol)) + end,
+                                        SBYTES (SYMBOL_NAME (symbol)) - end),
                            Qnil);
 
-      if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1))
+      if (modifiers & ~VALMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -5632,7 +6065,7 @@ apply_modifiers (modifiers, base)
   Lisp_Object cache, index, entry, new_symbol;
 
   /* Mask out upper bits.  We don't know where this value's been.  */
-  modifiers &= ((EMACS_INT)1 << VALBITS) - 1;
+  modifiers &= VALMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -5645,20 +6078,23 @@ apply_modifiers (modifiers, base)
     {
       /* We have to create the symbol ourselves.  */
       new_symbol = apply_modifiers_uncached (modifiers,
-                                            XSYMBOL (base)->name->data,
-                                            XSYMBOL (base)->name->size,
-                                            STRING_BYTES (XSYMBOL (base)->name));
+                                            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.
@@ -5785,10 +6221,14 @@ 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);
+         if (sizeof (int) == sizeof (EMACS_INT))
+           sprintf (buf, "%s-%d", SDATA (name_alist_or_stem),
+                    XINT (symbol_int) + 1);
+         else if (sizeof (long) == sizeof (EMACS_INT))
+           sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
+                    XINT (symbol_int) + 1);
          value = intern (buf);
        }
       else if (name_table != 0 && name_table[symbol_num])
@@ -5831,13 +6271,13 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem,
    event type as a number or a symbol.  */
 
 DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
-  "Convert the event description list EVENT-DESC to an event type.\n\
-EVENT-DESC should contain one base event type (a character or symbol)\n\
-and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
-drag, down, double or triple).  The base must be last.\n\
-The return value is an event type (a character or symbol) which\n\
-has the same base event type and all the specified modifiers.")
-  (event_desc)
+       doc: /* Convert the event description list EVENT-DESC to an event type.
+EVENT-DESC should contain one base event type (a character or symbol)
+and zero or more modifier names (control, meta, hyper, super, shift, alt,
+drag, down, double or triple).  The base must be last.
+The return value is an event type (a character or symbol) which
+has the same base event type and all the specified modifiers.  */)
+     (event_desc)
      Lisp_Object event_desc;
 {
   Lisp_Object base;
@@ -5868,8 +6308,8 @@ has the same base event type and all the specified modifiers.")
     }
 
   /* Let the symbol A refer to the character A.  */
-  if (SYMBOLP (base) && XSYMBOL (base)->name->size == 1)
-    XSETINT (base, XSYMBOL (base)->name->data[0]);
+  if (SYMBOLP (base) && SCHARS (SYMBOL_NAME (base)) == 1)
+    XSETINT (base, SREF (SYMBOL_NAME (base), 0));
 
   if (INTEGERP (base))
     {
@@ -5904,17 +6344,17 @@ static int
 parse_solitary_modifier (symbol)
      Lisp_Object symbol;
 {
-  struct Lisp_String *name = XSYMBOL (symbol)->name;
+  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':
@@ -6012,15 +6452,18 @@ 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 DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
+   If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
 
 static void
-get_input_pending (addr, do_timers_now)
+get_filtered_input_pending (addr, do_timers_now, filter_events)
      int *addr;
      int do_timers_now;
+     int filter_events;
 {
   /* First of all, have we already counted some input?  */
-  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
+  *addr = (!NILP (Vquit_flag)
+           || readable_filtered_events (do_timers_now, filter_events));
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -6028,7 +6471,23 @@ get_input_pending (addr, do_timers_now)
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
+  *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);
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -6062,7 +6521,7 @@ gobble_input (expected)
 #endif
 }
 
-/* Put a buffer_switch_event in the buffer
+/* Put a BUFFER_SWITCH_EVENT in the buffer
    so that read_key_sequence will notice the new current buffer.  */
 
 void
@@ -6071,7 +6530,7 @@ record_asynch_buffer_change ()
   struct input_event event;
   Lisp_Object tem;
 
-  event.kind = buffer_switch_event;
+  event.kind = BUFFER_SWITCH_EVENT;
   event.frame_or_window = Qnil;
   event.arg = Qnil;
 
@@ -6163,7 +6622,7 @@ read_avail_input (expected)
       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);
@@ -6220,13 +6679,13 @@ 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;
+         buf[i].kind = ASCII_KEYSTROKE_EVENT;
          buf[i].modifiers = 0;
          if (meta_key == 1 && (cbuf[i] & 0x80))
            buf[i].modifiers = meta_modifier;
@@ -6245,7 +6704,7 @@ read_avail_input (expected)
       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
+      if (buf[i].kind == ASCII_KEYSTROKE_EVENT
          && buf[i].code == quit_char)
        break;
     }
@@ -6257,7 +6716,7 @@ read_avail_input (expected)
 #ifdef SIGIO   /* for entire page */
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 
-SIGTYPE
+static SIGTYPE
 input_available_signal (signo)
      int signo;
 {
@@ -6318,27 +6777,8 @@ reinvoke_input_signal ()
 
 
 \f
-/* Return the prompt-string of a sparse keymap.
-   This is the first element which is a string.
-   Return nil if there is none.  */
-
-Lisp_Object
-map_prompt (map)
-     Lisp_Object map;
-{
-  while (CONSP (map))
-    {
-      register Lisp_Object tem;
-      tem = Fcar (map);
-      if (STRINGP (tem))
-       return tem;
-      map = Fcdr (map);
-    }
-  return Qnil;
-}
-
-static void menu_bar_item 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
@@ -6413,17 +6853,20 @@ menu_bar_items (old)
       }
     else
       {
-       /* No, so use major and minor mode keymaps and keymap property.  */
-       int extra_maps = 2;
-       Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
-       if (!NILP (map))
-         extra_maps = 3;
-       nmaps = current_minor_maps (NULL, &tmaps);
-       maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
-                                      * sizeof (maps[0]));
-       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-       if (!NILP (map))
-         maps[nmaps++] = map;
+       /* No, so use major and minor mode keymaps and keymap property.
+          Note that menu-bar bindings in the local-map and keymap
+          properties may not work reliable, as they are only
+          recognized when the menu-bar (or mode-line) is updated,
+          which does not normally happen after every command.  */
+       Lisp_Object tem;
+       int nminor;
+       nminor = current_minor_maps (NULL, &tmaps);
+       maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0]));
+       nmaps = 0;
+       if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem))
+         maps[nmaps++] = tem;
+       bcopy (tmaps, (void *) (maps + nmaps), nminor * sizeof (maps[0]));
+       nmaps += nminor;
        maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
       }
     maps[nmaps++] = current_global_map;
@@ -6439,7 +6882,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.  */
@@ -6493,48 +6939,15 @@ menu_bar_items (old)
   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;
@@ -6607,7 +7020,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
@@ -6624,13 +7040,13 @@ 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)
      Lisp_Object sexpr;
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   Lisp_Object val;
   specbind (Qinhibit_redisplay, Qt);
   val = internal_condition_case_1 (Feval, sexpr, Qerror,
@@ -6677,7 +7093,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;
 
@@ -6697,7 +7113,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)))
@@ -6706,7 +7122,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;
 
@@ -6802,7 +7218,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))
@@ -6813,11 +7229,6 @@ parse_menu_item (item, notreal, inmenubar)
       AREF (item_properties, ITEM_PROPERTY_DEF) = def;
     }
 
-  /* If we got no definition, this item is just unselectable text which
-     is OK in a submenu but not in the menubar.  */
-  if (NILP (def))
-    return (inmenubar ? 0 : 1);
   /* Enable or disable selection of item.  */
   tem = AREF (item_properties, ITEM_PROPERTY_ENABLE);
   if (!EQ (tem, Qt))
@@ -6831,6 +7242,11 @@ parse_menu_item (item, notreal, inmenubar)
       AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
     }
 
+  /* If we got no definition, this item is just unselectable text which
+     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);
@@ -6841,7 +7257,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.  */
@@ -6853,22 +7269,22 @@ parse_menu_item (item, notreal, inmenubar)
     {
       /* We have to create a cachelist.  */
       CHECK_IMPURE (start);
-      XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
+      XSETCDR (start, Fcons (Fcons (Qnil, Qnil), XCDR (start)));
       cachelist = XCAR (XCDR (start));
       newcache = 1;
       tem = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (!NILP (keyhint))
        {
-         XCAR (cachelist) = XCAR (keyhint);
+         XSETCAR (cachelist, XCAR (keyhint));
          newcache = 0;
        }
       else if (STRINGP (tem))
        {
-         XCDR (cachelist) = Fsubstitute_command_keys (tem);
-         XCAR (cachelist) = Qt;
+         XSETCDR (cachelist, Fsubstitute_command_keys (tem));
+         XSETCAR (cachelist, Qt);
        }
     }
-  
+
   tem = XCAR (cachelist);
   if (!EQ (tem, Qt))
     {
@@ -6876,7 +7292,7 @@ parse_menu_item (item, notreal, inmenubar)
       Lisp_Object prefix;
 
       if (!NILP (tem))
-       tem = Fkey_binding (tem, Qnil);
+       tem = Fkey_binding (tem, Qnil, Qnil);
 
       prefix = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (CONSP (prefix))
@@ -6922,11 +7338,11 @@ parse_menu_item (item, notreal, inmenubar)
              && SYMBOLP (XSYMBOL (def)->function)
              && ! NILP (Fget (def, Qmenu_alias)))
            def = XSYMBOL (def)->function;
-         tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
-         XCAR (cachelist) = tem;
+         tem = Fwhere_is_internal (def, Qnil, Qt, Qnil, Qt);
+         XSETCAR (cachelist, tem);
          if (NILP (tem))
            {
-             XCDR (cachelist) = Qnil;
+             XSETCDR (cachelist, Qnil);
              chkcache = 0;
            }
        }
@@ -6947,7 +7363,7 @@ parse_menu_item (item, notreal, inmenubar)
              if (STRINGP (XCDR (prefix)))
                tem = concat2 (tem, XCDR (prefix));
            }
-         XCDR (cachelist) = tem;
+         XSETCDR (cachelist, tem);
        }
     }
 
@@ -6955,7 +7371,7 @@ parse_menu_item (item, notreal, inmenubar)
   if (newcache && !NILP (tem))
     {
       tem = concat3 (build_string ("  ("), tem, build_string (")"));
-      XCDR (cachelist) = tem;
+      XSETCDR (cachelist, tem);
     }
 
   /* If we only want to precompute equivalent key bindings, stop here. */
@@ -6976,7 +7392,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)
@@ -6992,7 +7408,7 @@ parse_menu_item (item, notreal, inmenubar)
  ***********************************************************************/
 
 /* A vector holding tool bar items while they are parsed in function
-   tool_bar_items runs Each item occupies TOOL_BAR_ITEM_NSCLOTS elements
+   tool_bar_items. Each item occupies TOOL_BAR_ITEM_NSCLOTS elements
    in the vector.  */
 
 static Lisp_Object tool_bar_items_vector;
@@ -7032,8 +7448,6 @@ tool_bar_items (reuse, nitems)
   int nmaps, i;
   Lisp_Object oquit;
   Lisp_Object *tmaps;
-  extern Lisp_Object Voverriding_local_map_menu_flag;
-  extern Lisp_Object Voverriding_local_map;
 
   *nitems = 0;
 
@@ -7045,13 +7459,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))
     {
@@ -7065,17 +7479,20 @@ tool_bar_items (reuse, nitems)
     }
   else
     {
-      /* No, so use major and minor mode keymaps and keymap property.  */
-      int extra_maps = 2;
-      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
-      if (!NILP (map))
-       extra_maps = 3;
-      nmaps = current_minor_maps (NULL, &tmaps);
-      maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
-                                    * sizeof (maps[0]));
-      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-      if (!NILP (map))
-       maps[nmaps++] = map;
+      /* No, so use major and minor mode keymaps and keymap property.
+        Note that tool-bar bindings in the local-map and keymap
+        properties may not work reliable, as they are only
+        recognized when the tool-bar (or mode-line) is updated,
+        which does not normally happen after every command.  */
+      Lisp_Object tem;
+      int nminor;
+      nminor = current_minor_maps (NULL, &tmaps);
+      maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0]));
+      nmaps = 0;
+      if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem))
+       maps[nmaps++] = tem;
+      bcopy (tmaps, (void *) (maps + nmaps), nminor * sizeof (maps[0]));
+      nmaps += nminor;
       maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
     }
 
@@ -7093,7 +7510,7 @@ tool_bar_items (reuse, nitems)
        if (CONSP (keymap))
          {
            Lisp_Object tail;
-           
+
            /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
            for (tail = keymap; CONSP (tail); tail = XCDR (tail))
              {
@@ -7131,7 +7548,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)
@@ -7157,41 +7574,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
@@ -7203,8 +7620,6 @@ parse_tool_bar_item (key, item)
 
   Lisp_Object filter = Qnil;
   Lisp_Object caption;
-  extern Lisp_Object QCenable, QCvisible, QChelp, QCfilter;
-  extern Lisp_Object QCbutton, QCtoggle, QCradio;
   int i;
 
   /* Defininition looks like `(menu-item CAPTION BINDING PROPS...)'.
@@ -7227,11 +7642,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.  */
@@ -7298,7 +7713,7 @@ parse_tool_bar_item (key, item)
               && (CONSP (value)
                   || (VECTORP (value) && XVECTOR (value)->size == 4)))
        /* Value is either a single image specification or a vector
-          of 4 such specifications for the different buttion states.  */
+          of 4 such specifications for the different button states.  */
        PROP (TOOL_BAR_ITEM_IMAGES) = value;
     }
 
@@ -7318,13 +7733,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
 }
 
@@ -7351,7 +7766,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)
@@ -7406,7 +7821,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;
@@ -7426,13 +7841,13 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
 
   /* If we don't have any menus, just read a character normally.  */
-  if (mapno >= nmaps)
+  if (!STRINGP (name))
     return Qnil;
 
 #ifdef HAVE_MENUS
@@ -7473,7 +7888,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
              record_menu_key (XCAR (tem));
              if (SYMBOLP (XCAR (tem))
                  || INTEGERP (XCAR (tem)))
-               XCAR (tem) = Fcons (XCAR (tem), Qdisabled);
+               XSETCAR (tem, Fcons (XCAR (tem), Qdisabled));
            }
 
          /* If we got more than one event, put all but the first
@@ -7508,13 +7923,15 @@ 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;
   char *menu;
 
   vector = Qnil;
+  name = Qnil;
 
   if (! menu_prompting)
     return Qnil;
@@ -7536,18 +7953,18 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
-      name = map_prompt (maps[mapno]);
+      name = Fkeymap_prompt (maps[mapno]);
       if (!NILP (name))
        break;
     }
 
   /* If we don't have any menus, just read a character normally.  */
-  if (mapno >= nmaps)
+  if (!STRINGP (name))
     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;
@@ -7625,17 +8042,19 @@ 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);
 
+#if 0  /* It is redundant to list the equivalent key bindings because
+         the prefix is what the user has already typed.  */
                  tem
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
                  if (!NILP (tem))
                    /* Insert equivalent keybinding. */
                    s = concat2 (s, tem);
-
+#endif
                  tem
                    = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
                  if (EQ (tem, QCradio) || EQ (tem, QCtoggle))
@@ -7649,12 +8068,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)
                    {
@@ -7674,20 +8093,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;
                    }
@@ -7712,7 +8131,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
@@ -7767,20 +8186,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;
        }
@@ -7796,6 +8208,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.
@@ -7844,7 +8378,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      int fix_current_buffer;
 {
   volatile Lisp_Object from_string;
-  volatile int count = specpdl_ptr - specpdl;
+  volatile int count = SPECPDL_INDEX ();
 
   /* How many keys there are in the current key sequence.  */
   volatile int t;
@@ -7882,6 +8416,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      this key sequence.  In other words, the lowest i such that
      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.  */
+  volatile int first_unbound;
 
   /* If t < mock_input, then KEYBUF[t] should be read as the next
      input key.
@@ -7899,22 +8436,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... */
@@ -7930,24 +8466,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   struct buffer *starting_buffer;
 
-  /* Nonzero if we seem to have got the beginning of a binding
-     in function_key_map.  */
-  volatile int function_key_possible = 0;
-  volatile int key_translation_possible = 0;
-
   /* List of events for which a fake prefix key has been generated.  */
   volatile Lisp_Object fake_prefixed_keys = Qnil;
 
-  /* Save the status of key translation before each step,
-     so that we can restore this after downcasing.  */
-  Lisp_Object prev_fkey_map;
-  int prev_fkey_start;
-  int prev_fkey_end;
-
-  Lisp_Object prev_keytran_map;
-  int prev_keytran_start;
-  int prev_keytran_end;
-
 #if defined (GOBBLE_FIRST_EVENT)
   int junk;
 #endif
@@ -7960,16 +8481,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)
     {
@@ -8011,53 +8527,56 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
  replay_sequence:
 
   starting_buffer = current_buffer;
-  function_key_possible = 0;
-  key_translation_possible = 0;
+  first_unbound = bufsize + 1;
 
   /* 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
      click and we need to switch buffers, we jump back here to rebuild
      the initial keymaps from the current buffer.  */
-  {
-    Lisp_Object *maps;
+  nmaps = 0;
 
-    if (!NILP (current_kboard->Voverriding_terminal_local_map)
-       || !NILP (Voverriding_local_map))
-      {
-       if (3 > nmaps_allocated)
-         {
-           submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
-           nmaps_allocated = 3;
-         }
-       nmaps = 0;
-       if (!NILP (current_kboard->Voverriding_terminal_local_map))
-         submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
-       if (!NILP (Voverriding_local_map))
-         submaps[nmaps++] = Voverriding_local_map;
-      }
-    else
-      {
-       int extra_maps = 2;
-       nmaps = current_minor_maps (0, &maps);
-       if (!NILP (orig_keymap))
-         extra_maps = 3;
-       if (nmaps + extra_maps > nmaps_allocated)
-         {
-           submaps = (Lisp_Object *) alloca ((nmaps+extra_maps)
-                                             * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca ((nmaps+extra_maps)
-                                             * sizeof (defs[0]));
-           nmaps_allocated = nmaps + extra_maps;
-         }
-       bcopy (maps, (void *) submaps, nmaps * sizeof (submaps[0]));
-       if (!NILP (orig_keymap))
-         submaps[nmaps++] = orig_keymap;
-       submaps[nmaps++] = orig_local_map;
-      }
-    submaps[nmaps++] = current_global_map;
-  }
+  if (!NILP (current_kboard->Voverriding_terminal_local_map)
+      || !NILP (Voverriding_local_map))
+    {
+      if (3 > nmaps_allocated)
+       {
+         submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
+         defs    = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
+         nmaps_allocated = 3;
+       }
+      if (!NILP (current_kboard->Voverriding_terminal_local_map))
+       submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+      if (!NILP (Voverriding_local_map))
+       submaps[nmaps++] = Voverriding_local_map;
+    }
+  else
+    {
+      int nminor;
+      int total;
+      Lisp_Object *maps;
+
+      nminor = current_minor_maps (0, &maps);
+      total = nminor + (!NILP (orig_keymap) ? 3 : 2);
+
+      if (total > nmaps_allocated)
+       {
+         submaps = (Lisp_Object *) alloca (total * sizeof (submaps[0]));
+         defs    = (Lisp_Object *) alloca (total * sizeof (defs[0]));
+         nmaps_allocated = total;
+       }
+
+      if (!NILP (orig_keymap))
+       submaps[nmaps++] = orig_keymap;
+
+      bcopy (maps, (void *) (submaps + nmaps),
+            nminor * sizeof (submaps[0]));
+
+      nmaps += nminor;
+
+      submaps[nmaps++] = orig_local_map;
+    }
+  submaps[nmaps++] = current_global_map;
 
   /* Find an accurate initial value for first_binding.  */
   for (first_binding = 0; first_binding < nmaps; first_binding++)
@@ -8076,19 +8595,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
-            /* mock input is never part of a function key's sequence.  */
-            && mock_input <= fkey_start)
-        || (first_binding >= nmaps
-            && keytran_start < t && key_translation_possible)
+  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;
@@ -8106,6 +8621,29 @@ 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);
+
+      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
+            (if the user keeps entering fkey or keytran prefixes
+            like C-c ESC ESC ESC ESC ...)  */
+         int i;
+         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 = fkey.parent;
+         keytran.end = keytran.start -= first_unbound + 1;
+         keytran.map = keytran.parent;
+         goto replay_sequence;
+       }
+
       if (t >= bufsize)
        error ("Key sequence too long");
 
@@ -8207,6 +8745,15 @@ 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;
+
              mock_input = t;
              /* Reset the current buffer from the selected window
                 in case something changed the former and not the latter.
@@ -8245,6 +8792,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
@@ -8331,7 +8879,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
@@ -8342,7 +8890,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  localized_local_map = 1;
                  start = EVENT_START (key);
-                 
+
                  if (CONSP (start) && CONSP (XCDR (start)))
                    {
                      pos = POSN_BUFFER_POSN (start);
@@ -8381,7 +8929,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;
@@ -8389,7 +8937,7 @@ 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,
@@ -8402,7 +8950,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                      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))
@@ -8430,7 +8978,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  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))
@@ -8465,8 +9013,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
-                 POSN_BUFFER_POSN (EVENT_START (key))
-                   = Fcons (posn, Qnil);
+                 POSN_BUFFER_SET_POSN (EVENT_START (key),
+                                       Fcons (posn, Qnil));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -8492,10 +9040,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                       + first_binding);
 
       /* If KEY wasn't bound, we'll try some fallbacks.  */
-      if (first_binding >= nmaps)
+      if (first_binding < nmaps)
+       /* 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,
+          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.  */
+         first_unbound = min (t, first_unbound);
+
          head = EVENT_HEAD (key);
          if (help_char_p (head) && t > 0)
            {
@@ -8569,7 +9128,32 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                             generate mouse events, so it's okay to zero
                             mock_input in that case too.
 
+                            FIXME: The above paragraph seems just plain
+                            wrong, if you consider things like
+                            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;
@@ -8621,238 +9205,69 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       /* Record what part of this_command_keys is the current key sequence.  */
       this_single_command_key_start = this_command_key_count - t;
 
-      prev_fkey_map = fkey_map;
-      prev_fkey_start = fkey_start;
-      prev_fkey_end = fkey_end;
-
-      prev_keytran_map = keytran_map;
-      prev_keytran_start = keytran_start;
-      prev_keytran_end = keytran_end;
-
-      /* If the sequence is unbound, see if we can hang a function key
-        off the end of it.  We only want to scan real keyboard input
-        for function key sequences, so if mock_input says that we're
-        re-reading old events, don't examine it.  */
-      if (first_binding >= nmaps
-         && t >= mock_input)
+      if (first_binding < nmaps && NILP (submaps[first_binding]))
+       /* There is a binding and it's not a prefix.
+          There is thus no function-key in this sequence.
+          Moving fkey.start is important in this case to allow keytran.start
+          to go over the sequence before we return (since we keep the
+          invariant that keytran.end <= fkey.start).  */
        {
-         Lisp_Object fkey_next;
-
-         /* Continue scan from fkey_end until we find a bound suffix.
-            If we fail, increment fkey_start
-            and start fkey_end 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))
-                 && fkey_end == t)
-               {
-                 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");
-               }
-
-             function_key_possible = ! NILP (fkey_next);
-
-             /* 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))
-                 && fkey_end == t)
-               {
-                 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;
-                 function_key_possible = 0;
-               }
-           }
+         if (fkey.start < t)
+           (fkey.start = fkey.end = t, fkey.map = fkey.parent);
        }
-
-      /* 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 < t)
+      else
+       /* If the sequence is unbound, see if we can hang a function key
+          off the end of it.  */
+       /* 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))
-               && keytran_end == t)
-             {
-               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");
-             }
-
-           key_translation_possible = ! NILP (keytran_next);
-
-           /* If keybuf[keytran_start..keytran_end] is bound in the
-              key translation map and it's a suffix of the current
-              sequence (i.e. keytran_end == t), replace it with
-              the binding and restart with keytran_start at the end. */
-           if ((VECTORP (keytran_next) || STRINGP (keytran_next))
-               && keytran_end == t)
+           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));
-
-               t = keytran_start + len;
-               if (t >= bufsize)
-                 error ("Key sequence too long");
-
-               if (VECTORP (keytran_next))
-                 bcopy (XVECTOR (keytran_next)->contents,
-                        keybuf + keytran_start,
-                        (t - keytran_start) * sizeof (keybuf[0]));
-               else if (STRINGP (keytran_next))
-                 {
-                   int i;
-
-                   for (i = 0; i < len; i++)
-                     XSETFASTINT (keybuf[keytran_start + i],
-                                  XSTRING (keytran_next)->data[i]);
-                 }
-
-               mock_input = t;
-               keytran_start = keytran_end = t;
-               keytran_map = Vkey_translation_map;
-
-               /* Don't pass the results of key-translation-map
-                  through function-key-map.  */
-               fkey_start = fkey_end = t;
-               fkey_map = Vfunction_key_map;
-
+               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;
-               key_translation_possible = 0;
-             }
-         }
-      }
+         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 && ! function_key_possible
-         && ! key_translation_possible
+      if (first_binding >= nmaps
+         && fkey.start >= t && keytran.start >= t
          && INTEGERP (key)
          && ((((XINT (key) & 0x3ffff)
                < XCHAR_TABLE (current_buffer->downcase_table)->size)
@@ -8874,15 +9289,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
             the lower-case char is defined in the keymaps, because they
             might get translated through function-key-map.  */
          keybuf[t - 1] = new_key;
-         mock_input = t;
-
-         fkey_map = prev_fkey_map;
-         fkey_start = prev_fkey_start;
-         fkey_end = prev_fkey_end;
-
-         keytran_map = prev_keytran_map;
-         keytran_start = prev_keytran_start;
-         keytran_end = prev_keytran_end;
+         mock_input = max (t, mock_input);
 
          goto replay_sequence;
        }
@@ -8890,8 +9297,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         and cannot be part of a function key or translation,
         and is a shifted function key,
         use the corresponding unshifted function key instead.  */
-      if (first_binding == nmaps && ! function_key_possible
-         && ! key_translation_possible
+      if (first_binding >= nmaps
+         && fkey.start >= t && keytran.start >= t
          && SYMBOLP (key))
        {
          Lisp_Object breakdown;
@@ -8911,15 +9318,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                                         XCAR (breakdown));
 
              keybuf[t - 1] = new_key;
-             mock_input = t;
-
-             fkey_map = prev_fkey_map;
-             fkey_start = prev_fkey_start;
-             fkey_end = prev_fkey_end;
-
-             keytran_map = prev_keytran_map;
-             keytran_start = prev_keytran_start;
-             keytran_end = prev_keytran_end;
+             mock_input = max (t, mock_input);
 
              goto replay_sequence;
            }
@@ -8957,66 +9356,59 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       add_command_key (keybuf[t]);
     }
 
-  
+
 
   UNGCPRO;
   return t;
 }
 
-#if 0 /* This doc string is too long for some compilers.
-        This commented-out definition serves for DOC.  */
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
-  "Read a sequence of keystrokes and return as a string or vector.\n\
-The sequence is sufficient to specify a non-prefix command in the\n\
-current local and global maps.\n\
-\n\
-First arg PROMPT is a prompt string.  If nil, do not prompt specially.\n\
-Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos\n\
-as a continuation of the previous key.\n\
-\n\
-The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not\n\
-convert the last event to lower case.  (Normally any upper case event\n\
-is converted to lower case if the original event is undefined and the lower\n\
-case equivalent is defined.)  A non-nil value is appropriate for reading\n\
-a key sequence to be defined.\n\
-\n\
-A C-g typed while in this function is treated like any other character,\n\
-and `quit-flag' is not set.\n\
-\n\
-If the key sequence starts with a mouse click, then the sequence is read\n\
-using the keymaps of the buffer of the window clicked in, not the buffer\n\
-of the selected window as normal.\n\
-""\n\
-`read-key-sequence' drops unbound button-down events, since you normally\n\
-only care about the click or drag events which follow them.  If a drag\n\
-or multi-click event is unbound, but the corresponding click event would\n\
-be bound, `read-key-sequence' turns the event into a click event at the\n\
-drag's starting position.  This means that you don't have to distinguish\n\
-between click and drag, double, or triple events unless you want to.\n\
-\n\
-`read-key-sequence' prefixes mouse events on mode lines, the vertical\n\
-lines separating windows, and scroll bars with imaginary keys\n\
-`mode-line', `vertical-line', and `vertical-scroll-bar'.\n\
-\n\
-Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this\n\
-function will process a switch-frame event if the user switches frames\n\
-before typing anything.  If the user switches frames in the middle of a\n\
-key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME\n\
-is nil, then the event will be put off until after the current key sequence.\n\
-\n\
-`read-key-sequence' checks `function-key-map' for function key\n\
-sequences, where they wouldn't conflict with ordinary bindings.  See\n\
-`function-key-map' for more details.\n\
-\n\
-The optional fifth argument COMMAND-LOOP, if non-nil, means\n\
-that this key sequence is being read by something that will\n\
-read commands one after another.  It should be nil if the caller\n\
-will read just one key sequence.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
-#endif
-
 DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
-  0)
+       doc: /* Read a sequence of keystrokes and return as a string or vector.
+The sequence is sufficient to specify a non-prefix command in the
+current local and global maps.
+
+First arg PROMPT is a prompt string.  If nil, do not prompt specially.
+Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
+as a continuation of the previous key.
+
+The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
+convert the last event to lower case.  (Normally any upper case event
+is converted to lower case if the original event is undefined and the lower
+case equivalent is defined.)  A non-nil value is appropriate for reading
+a key sequence to be defined.
+
+A C-g typed while in this function is treated like any other character,
+and `quit-flag' is not set.
+
+If the key sequence starts with a mouse click, then the sequence is read
+using the keymaps of the buffer of the window clicked in, not the buffer
+of the selected window as normal.
+
+`read-key-sequence' drops unbound button-down events, since you normally
+only care about the click or drag events which follow them.  If a drag
+or multi-click event is unbound, but the corresponding click event would
+be bound, `read-key-sequence' turns the event into a click event at the
+drag's starting position.  This means that you don't have to distinguish
+between click and drag, double, or triple events unless you want to.
+
+`read-key-sequence' prefixes mouse events on mode lines, the vertical
+lines separating windows, and scroll bars with imaginary keys
+`mode-line', `vertical-line', and `vertical-scroll-bar'.
+
+Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this
+function will process a switch-frame event if the user switches frames
+before typing anything.  If the user switches frames in the middle of a
+key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME
+is nil, then the event will be put off until after the current key sequence.
+
+`read-key-sequence' checks `function-key-map' for function key
+sequences, where they wouldn't conflict with ordinary bindings.  See
+`function-key-map' for more details.
+
+The optional fifth argument COMMAND-LOOP, if non-nil, means
+that this key sequence is being read by something that will
+read commands one after another.  It should be nil if the caller
+will read just one key sequence.  */)
   (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
    command_loop)
      Lisp_Object prompt, continue_echo, dont_downcase_last;
@@ -9025,10 +9417,10 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
   Lisp_Object keybuf[30];
   register int i;
   struct gcpro gcpro1;
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
 
   if (!NILP (prompt))
-    CHECK_STRING (prompt, 0);
+    CHECK_STRING (prompt);
   QUIT;
 
   specbind (Qinput_method_exit_on_first_char,
@@ -9043,6 +9435,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
   if (NILP (continue_echo))
     {
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
       this_single_command_key_start = 0;
     }
 
@@ -9056,7 +9449,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
                         ! NILP (can_return_switch_frame), 0);
 
 #if 0  /* The following is fine for code reading a key sequence and
-         then proceeding with a lenghty compuation, but it's not good
+         then proceeding with a lenghty computation, but it's not good
          for code reading keys in a loop, like an input method.  */
 #ifdef HAVE_X_WINDOWS
   if (display_hourglass_p)
@@ -9075,19 +9468,19 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
 
 DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
        Sread_key_sequence_vector, 1, 5, 0,
-  "Like `read-key-sequence' but always return a vector.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
-   command_loop)
+       doc: /* Like `read-key-sequence' but always return a vector.  */)
+     (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+      command_loop)
      Lisp_Object prompt, continue_echo, dont_downcase_last;
      Lisp_Object can_return_switch_frame, command_loop;
 {
   Lisp_Object keybuf[30];
   register int i;
   struct gcpro gcpro1;
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
 
   if (!NILP (prompt))
-    CHECK_STRING (prompt, 0);
+    CHECK_STRING (prompt);
   QUIT;
 
   specbind (Qinput_method_exit_on_first_char,
@@ -9102,6 +9495,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;
     }
 
@@ -9129,15 +9523,15 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
 }
 \f
 DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
- "Execute CMD as an editor command.\n\
-CMD must be a symbol that satisfies the `commandp' predicate.\n\
-Optional second arg RECORD-FLAG non-nil\n\
-means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.\n\
-The argument KEYS specifies the value to use instead of (this-command-keys)\n\
-when reading the arguments; if it is nil, (this-command-keys) is used.\n\
-The argument SPECIAL, if non-nil, means that this command is executing\n\
-a special event, so ignore the prefix argument and don't clear it.")
+       doc: /* Execute CMD as an editor command.
+CMD must be a symbol that satisfies the `commandp' predicate.
+Optional second arg RECORD-FLAG non-nil
+means unconditionally put this command in `command-history'.
+Otherwise, that is done only if an arg is read using the minibuffer.
+The argument KEYS specifies the value to use instead of (this-command-keys)
+when reading the arguments; if it is nil, (this-command-keys) is used.
+The argument SPECIAL, if non-nil, means that this command is executing
+a special event, so ignore the prefix argument and don't clear it.  */)
      (cmd, record_flag, keys, special)
      Lisp_Object cmd, record_flag, keys, special;
 {
@@ -9202,11 +9596,11 @@ a special event, so ignore the prefix argument and don't clear it.")
            {
              tem = Fnthcdr (Vhistory_length, Vcommand_history);
              if (CONSP (tem))
-               XCDR (tem) = Qnil;
+               XSETCDR (tem, Qnil);
            }
        }
 
-      return Fexecute_kbd_macro (final, prefixarg);
+      return Fexecute_kbd_macro (final, prefixarg, Qnil);
     }
 
   if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
@@ -9229,21 +9623,24 @@ a special event, so ignore the prefix argument and don't clear it.")
 
 \f
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
-  1, 1, "P",
-  "Read function name, then read its arguments and call it.")
-  (prefixarg)
+       1, 1, "P",
+       doc: /* Read function name, then read its arguments and call it.  */)
+     (prefixarg)
      Lisp_Object prefixarg;
 {
   Lisp_Object function;
   char buf[40];
-  Lisp_Object saved_keys;
+  int saved_last_point_position;
+  Lisp_Object saved_keys, saved_last_point_position_buffer;
   Lisp_Object bindings, value;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1, gcpro2, gcpro3;
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
+  saved_last_point_position_buffer = last_point_position_buffer;
+  saved_last_point_position = last_point_position;
   buf[0] = 0;
-  GCPRO2 (saved_keys, prefixarg);
+  GCPRO3 (saved_keys, prefixarg, saved_last_point_position_buffer);
 
   if (EQ (prefixarg, Qminus))
     strcpy (buf, "- ");
@@ -9282,30 +9679,32 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                               Qt, Qnil, Qextended_command_history, Qnil,
                               Qnil);
 
-  if (STRINGP (function) && XSTRING (function)->size == 0)
+  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'));
   }
 
+  last_point_position = saved_last_point_position;
+  last_point_position_buffer = saved_last_point_position_buffer;
+
   UNGCPRO;
 
   function = Fintern (function, Qnil);
@@ -9318,7 +9717,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
       && NILP (Vexecuting_macro)
       && SYMBOLP (function))
     bindings = Fwhere_is_internal (function, Voverriding_local_map,
-                                  Qt, Qnil);
+                                  Qt, Qnil, Qnil);
   else
     bindings = Qnil;
 
@@ -9349,18 +9748,18 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          Lisp_Object binding;
          char *newmessage;
          int message_p = push_message ();
-         int count = BINDING_STACK_SIZE ();
+         int count = SPECPDL_INDEX ();
 
-         record_unwind_protect (push_message_unwind, Qnil);
+         record_unwind_protect (pop_message_unwind, Qnil);
          binding = Fkey_description (bindings);
 
          newmessage
-           = (char *) alloca (XSYMBOL (function)->name->size
-                              + STRING_BYTES (XSTRING (binding))
+           = (char *) alloca (SCHARS (SYMBOL_NAME (function))
+                              + SBYTES (binding)
                               + 100);
          sprintf (newmessage, "You can run the command `%s' with %s",
-                  XSYMBOL (function)->name->data,
-                  XSTRING (binding)->data);
+                  SDATA (SYMBOL_NAME (function)),
+                  SDATA (binding));
          message2_nolog (newmessage,
                          strlen (newmessage),
                          STRING_MULTIBYTE (binding));
@@ -9377,49 +9776,6 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   RETURN_UNGCPRO (value);
 }
 
-/* Find the set of keymaps now active.
-   Store into *MAPS_P a vector holding the various maps
-   and return the number of them.  The vector was malloc'd
-   and the caller should free it.  */
-
-int
-current_active_maps (maps_p)
-     Lisp_Object **maps_p;
-{
-  Lisp_Object *tmaps, *maps;
-  int nmaps;
-
-  /* Should overriding-terminal-local-map and overriding-local-map apply?  */
-  if (!NILP (Voverriding_local_map_menu_flag))
-    {
-      /* Yes, use them (if non-nil) as well as the global map.  */
-      maps = (Lisp_Object *) xmalloc (3 * sizeof (maps[0]));
-      nmaps = 0;
-      if (!NILP (current_kboard->Voverriding_terminal_local_map))
-       maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
-      if (!NILP (Voverriding_local_map))
-       maps[nmaps++] = Voverriding_local_map;
-    }
-  else
-    {
-      /* No, so use major and minor mode keymaps and keymap property.  */
-      int extra_maps = 2;
-      Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
-      if (!NILP (map))
-       extra_maps = 3;
-      nmaps = current_minor_maps (NULL, &tmaps);
-      maps = (Lisp_Object *) alloca ((nmaps + extra_maps)
-                                    * sizeof (maps[0]));
-      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-      if (!NILP (map))
-       maps[nmaps++] = map;
-      maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
-    }
-  maps[nmaps++] = current_global_map;
-
-  *maps_p = maps;
-  return nmaps;
-}
 \f
 /* Return nonzero if input events are pending.  */
 
@@ -9470,7 +9826,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
-   call it, and return return if it runs Lisp code that unreads something.
+   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.  */
 
@@ -9482,20 +9838,21 @@ requeued_events_pending_p ()
 
 
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
-  "T if command input is currently available with no waiting.\n\
-Actually, the value is nil only if we can be sure that no input is available.")
-  ()
+       doc: /* Return t if command input is currently available with no wait.
+Actually, the value is nil only if we can be sure that no input is available;
+if there is a doubt, the value is t.  */)
+     ()
 {
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  get_input_pending (&input_pending, 1);
+  get_filtered_input_pending (&input_pending, 1, 1);
   return input_pending > 0 ? Qt : Qnil;
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
-  "Return vector of last 100 events, not counting those from keyboard macros.")
-  ()
+       doc: /* Return vector of last 100 events, not counting those from keyboard macros.  */)
+     ()
 {
   Lisp_Object *keys = XVECTOR (recent_keys)->contents;
   Lisp_Object val;
@@ -9516,17 +9873,21 @@ DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
 }
 
 DEFUN ("this-command-keys", Fthis_command_keys, Sthis_command_keys, 0, 0, 0,
-  "Return the key sequence that invoked this command.\n\
-The value is a string or a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command.
+However, if the command has called `read-key-sequence', it returns
+the last key sequence that has been read.
+The value is a string or a vector.  */)
+     ()
 {
   return make_event_array (this_command_key_count,
                           XVECTOR (this_command_keys)->contents);
 }
 
 DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
-  "Return the key sequence that invoked this command, as a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command, as a vector.
+However, if the command has called `read-key-sequence', it returns
+the last key sequence that has been read.  */)
+     ()
 {
   return Fvector (this_command_key_count,
                  XVECTOR (this_command_keys)->contents);
@@ -9534,11 +9895,13 @@ DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys
 
 DEFUN ("this-single-command-keys", Fthis_single_command_keys,
        Sthis_single_command_keys, 0, 0, 0,
-  "Return the key sequence that invoked this command.\n\
-Unlike `this-command-keys', this function's value\n\
-does not include prefix arguments.\n\
-The value is always a vector.")
-  ()
+       doc: /* Return the key sequence that invoked this command.
+More generally, it returns the last key sequence read, either by
+the command loop or by `read-key-sequence'.
+Unlike `this-command-keys', this function's value
+does not include prefix arguments.
+The value is always a vector.  */)
+     ()
 {
   return Fvector (this_command_key_count
                  - this_single_command_key_start,
@@ -9548,57 +9911,71 @@ The value is always a vector.")
 
 DEFUN ("this-single-command-raw-keys", Fthis_single_command_raw_keys,
        Sthis_single_command_raw_keys, 0, 0, 0,
-  "Return the raw events that were read for this command.\n\
-Unlike `this-single-command-keys', this function's value\n\
-shows the events before all translations (except for input methods).\n\
-The value is always a vector.")
-  ()
+       doc: /* Return the raw events that were read for this command.
+More generally, it returns the last key sequence read, either by
+the command loop or by `read-key-sequence'.
+Unlike `this-single-command-keys', this function's value
+shows the events before all translations (except for input methods).
+The value is always a vector.  */)
+     ()
 {
   return Fvector (raw_keybuf_count,
                  (XVECTOR (raw_keybuf)->contents));
 }
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
-  Sreset_this_command_lengths, 0, 0, 0,
-  "Used for complicated reasons in `universal-argument-other-key'.\n\
-\n\
-`universal-argument-other-key' rereads the event just typed.\n\
-It then gets translated through `function-key-map'.\n\
-The translated event gets included in the echo area and in\n\
-the value of `this-command-keys' in addition to the raw original event.\n\
-That is not right.\n\
-\n\
-Calling this function directs the translated event to replace\n\
-the original event, so that only one version of the event actually\n\
-appears in the echo area and in the value of `this-command-keys.'.")
-  ()
-{
-  before_command_restore_flag = 1;
-  before_command_key_count_1 = before_command_key_count;
-  before_command_echo_length_1 = before_command_echo_length;
+       Sreset_this_command_lengths, 0, 0, 0,
+       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 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.  */)
+     ()
+{
+  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,
-  "Clear out the vector that `this-command-keys' returns.\n\
-Clear vector containing last 100 events.")
-  ()
+       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, 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;
 }
 
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
-  "Return the current depth in recursive edits.")
-  ()
+       doc: /* Return the current depth in recursive edits.  */)
+     ()
 {
   Lisp_Object temp;
   XSETFASTINT (temp, command_loop_level + minibuf_level);
@@ -9606,10 +9983,10 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
 }
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
-  "FOpen dribble file: ",
-  "Start writing all keyboard characters to a dribble file called FILE.\n\
-If FILE is nil, close any open dribble file.")
-  (file)
+       "FOpen dribble file: ",
+       doc: /* Start writing all keyboard characters to a dribble file called FILE.
+If FILE is nil, close any open dribble file.  */)
+     (file)
      Lisp_Object file;
 {
   if (dribble)
@@ -9620,7 +9997,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));
     }
@@ -9628,11 +10005,17 @@ If FILE is nil, close any open dribble file.")
 }
 
 DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0,
-  "Discard the contents of the terminal input buffer.\n\
-Also cancel any kbd macro being defined.")
-  ()
+       doc: /* Discard the contents of the terminal input buffer.
+Also 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;
@@ -9648,27 +10031,28 @@ Also cancel any kbd macro being defined.")
 }
 \f
 DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
-  "Stop Emacs and return to superior process.  You can resume later.\n\
-If `cannot-suspend' is non-nil, or if the system doesn't support job\n\
-control, run a subshell instead.\n\n\
-If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
-to be read as terminal input by Emacs's parent, after suspension.\n\
-\n\
-Before suspending, run the normal hook `suspend-hook'.\n\
-After resumption run the normal hook `suspend-resume-hook'.\n\
-\n\
-Some operating systems cannot stop the Emacs process and resume it later.\n\
-On such systems, Emacs starts a subshell instead of suspending.")
-  (stuffstring)
+       doc: /* Stop Emacs and return to superior process.  You can resume later.
+If `cannot-suspend' is non-nil, or if the system doesn't support job
+control, run a subshell instead.
+
+If optional arg STUFFSTRING is non-nil, its characters are stuffed
+to be read as terminal input by Emacs's parent, after suspension.
+
+Before suspending, run the normal hook `suspend-hook'.
+After resumption run the normal hook `suspend-resume-hook'.
+
+Some operating systems cannot stop the Emacs process and resume it later.
+On such systems, Emacs starts a subshell instead of suspending.  */)
+     (stuffstring)
      Lisp_Object stuffstring;
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   int old_height, old_width;
   int width, height;
   struct gcpro gcpro1;
 
   if (!NILP (stuffstring))
-    CHECK_STRING (stuffstring, 0);
+    CHECK_STRING (stuffstring);
 
   /* Run the functions in suspend-hook.  */
   if (!NILP (Vrun_hooks))
@@ -9719,31 +10103,31 @@ stuff_buffered_input (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?  */
   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)
+      if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT)
        stuff_char (kbd_fetch_ptr->code);
-      
-      kbd_fetch_ptr->kind = no_event;
+
+      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);
     }
-  
+
   input_pending = 0;
 #endif
 #endif /* BSD_SYSTEM and not BSD4_1 */
@@ -9772,8 +10156,8 @@ clear_waiting_for_input ()
   input_available_clear_time = 0;
 }
 
-/* This routine is called at interrupt level in response to C-G.
-   
+/* 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.
@@ -9785,7 +10169,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. */
 {
@@ -9863,7 +10247,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;
@@ -9958,17 +10342,17 @@ quit_throw_to_read_char ()
 }
 \f
 DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 4, 0,
-  "Set mode of reading keyboard input.\n\
-First arg INTERRUPT non-nil means use input interrupts;\n\
- nil means use CBREAK mode.\n\
-Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal\n\
- (no effect except in CBREAK mode).\n\
-Third arg META t means accept 8-bit input (for a Meta key).\n\
- META nil means ignore the top bit, on the assumption it is parity.\n\
- Otherwise, accept 8-bit input and don't use the top bit for Meta.\n\
-Optional fourth arg QUIT if non-nil specifies character to use for quitting.\n\
-See also `current-input-mode'.")
-  (interrupt, flow, meta, quit)
+       doc: /* Set mode of reading keyboard input.
+First arg INTERRUPT non-nil means use input interrupts;
+ nil means use CBREAK mode.
+Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal
+ (no effect except in CBREAK mode).
+Third arg META t means accept 8-bit input (for a Meta key).
+ META nil means ignore the top bit, on the assumption it is parity.
+ Otherwise, accept 8-bit input and don't use the top bit for Meta.
+Optional fourth arg QUIT if non-nil specifies character to use for quitting.
+See also `current-input-mode'.  */)
+     (interrupt, flow, meta, quit)
      Lisp_Object interrupt, flow, meta, quit;
 {
   if (!NILP (quit)
@@ -10030,20 +10414,20 @@ See also `current-input-mode'.")
 }
 
 DEFUN ("current-input-mode", Fcurrent_input_mode, Scurrent_input_mode, 0, 0, 0,
-  "Return information about the way Emacs currently reads keyboard input.\n\
-The value is a list of the form (INTERRUPT FLOW META QUIT), where\n\
-  INTERRUPT is non-nil if Emacs is using interrupt-driven input; if\n\
-    nil, Emacs is using CBREAK mode.\n\
-  FLOW is non-nil if Emacs uses ^S/^Q flow control for output to the\n\
-    terminal; this does not apply if Emacs uses interrupt-driven input.\n\
-  META is t if accepting 8-bit input with 8th bit as Meta flag.\n\
-    META nil means ignoring the top bit, on the assumption it is parity.\n\
-    META is neither t nor nil if accepting 8-bit input and using\n\
-    all 8 bits as the character code.\n\
-  QUIT is the character Emacs currently uses to quit.\n\
-The elements of this list correspond to the arguments of\n\
-`set-input-mode'.")
-  ()
+       doc: /* Return information about the way Emacs currently reads keyboard input.
+The value is a list of the form (INTERRUPT FLOW META QUIT), where
+  INTERRUPT is non-nil if Emacs is using interrupt-driven input; if
+    nil, Emacs is using CBREAK mode.
+  FLOW is non-nil if Emacs uses ^S/^Q flow control for output to the
+    terminal; this does not apply if Emacs uses interrupt-driven input.
+  META is t if accepting 8-bit input with 8th bit as Meta flag.
+    META nil means ignoring the top bit, on the assumption it is parity.
+    META is neither t nor nil if accepting 8-bit input and using
+    all 8 bits as the character code.
+  QUIT is the character Emacs currently uses to quit.
+The elements of this list correspond to the arguments of
+`set-input-mode'.  */)
+     ()
 {
   Lisp_Object val[4];
 
@@ -10071,7 +10455,7 @@ init_kboard (kb)
   kb->kbd_queue = Qnil;
   kb->kbd_queue_has_data = 0;
   kb->immediate_echo = 0;
-  kb->echoptr = kb->echobuf;
+  kb->echo_string = Qnil;
   kb->echo_after_prompt = -1;
   kb->kbd_macro_buffer = 0;
   kb->kbd_macro_bufsize = 0;
@@ -10105,7 +10489,7 @@ delete_kboard (kb)
      KBOARD *kb;
 {
   KBOARD **kbp;
-  
+
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
       abort ();
@@ -10120,7 +10504,7 @@ delete_kboard (kb)
       if (current_kboard == kb)
        abort ();
     }
-  
+
   wipe_kboard (kb);
   xfree (kb);
 }
@@ -10197,6 +10581,11 @@ init_keyboard ()
   poll_suppress_count = 1;
   start_polling ();
 #endif
+
+#ifdef MAC_OSX
+  /* At least provide an escape route since C-g doesn't work.  */
+  signal (SIGINT, interrupt_signal);
+#endif
 }
 
 /* This type's only use is in syms_of_keyboard, to initialize the
@@ -10208,12 +10597,15 @@ struct event_head {
 };
 
 struct event_head head_table[] = {
-  &Qmouse_movement,    "mouse-movement",       &Qmouse_movement,
-  &Qscroll_bar_movement, "scroll-bar-movement",        &Qmouse_movement,
-  &Qswitch_frame,      "switch-frame",         &Qswitch_frame,
-  &Qdelete_frame,      "delete-frame",         &Qdelete_frame,
-  &Qiconify_frame,     "iconify-frame",        &Qiconify_frame,
-  &Qmake_frame_visible,        "make-frame-visible",   &Qmake_frame_visible,
+  {&Qmouse_movement,      "mouse-movement",      &Qmouse_movement},
+  {&Qscroll_bar_movement, "scroll-bar-movement", &Qmouse_movement},
+  {&Qswitch_frame,        "switch-frame",        &Qswitch_frame},
+  {&Qdelete_frame,        "delete-frame",        &Qdelete_frame},
+  {&Qiconify_frame,       "iconify-frame",       &Qiconify_frame},
+  {&Qmake_frame_visible,  "make-frame-visible",  &Qmake_frame_visible},
+  /* `select-window' should be handled just like `switch-frame'
+     in read_key_sequence.  */
+  {&Qselect_window,       "select-window",       &Qswitch_frame}
 };
 
 void
@@ -10221,7 +10613,7 @@ syms_of_keyboard ()
 {
   Vpre_help_message = Qnil;
   staticpro (&Vpre_help_message);
-  
+
   Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
@@ -10283,15 +10675,20 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-#ifdef WINDOWSNT
+#if defined(WINDOWSNT) || defined(MAC_OSX)
   Qmouse_wheel = intern ("mouse-wheel");
   staticpro (&Qmouse_wheel);
+#endif
+#ifdef WINDOWSNT
   Qlanguage_change = intern ("language-change");
   staticpro (&Qlanguage_change);
 #endif
   Qdrag_n_drop = intern ("drag-n-drop");
   staticpro (&Qdrag_n_drop);
 
+  Qsave_session = intern ("save-session");
+  staticpro(&Qsave_session);
+
   Qusr1_signal = intern ("usr1-signal");
   staticpro (&Qusr1_signal);
   Qusr2_signal = intern ("usr2-signal");
@@ -10430,10 +10827,9 @@ syms_of_keyboard ()
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
-#ifdef WINDOWSNT
+#if defined(WINDOWSNT) || defined(MAC_OSX)
   mouse_wheel_syms = Qnil;
   staticpro (&mouse_wheel_syms);
-  
   drag_n_drop_syms = Qnil;
   staticpro (&drag_n_drop_syms);
 #endif
@@ -10478,377 +10874,389 @@ syms_of_keyboard ()
   defsubr (&Sexecute_extended_command);
 
   DEFVAR_LISP ("last-command-char", &last_command_char,
-    "Last input event that was part of a command.");
+              doc: /* Last input event that was part of a command.  */);
 
   DEFVAR_LISP_NOPRO ("last-command-event", &last_command_char,
-    "Last input event that was part of a command.");
+                    doc: /* Last input event that was part of a command.  */);
 
   DEFVAR_LISP ("last-nonmenu-event", &last_nonmenu_event,
-    "Last input event in a command, except for mouse menu events.\n\
-Mouse menus give back keys that don't look like mouse events;\n\
-this variable holds the actual mouse event that led to the menu,\n\
-so that you can determine whether the command was run by mouse or not.");
+              doc: /* Last input event in a command, except for mouse menu events.
+Mouse menus give back keys that don't look like mouse events;
+this variable holds the actual mouse event that led to the menu,
+so that you can determine whether the command was run by mouse or not.  */);
 
   DEFVAR_LISP ("last-input-char", &last_input_char,
-    "Last input event.");
+              doc: /* Last input event.  */);
 
   DEFVAR_LISP_NOPRO ("last-input-event", &last_input_char,
-    "Last input event.");
+                    doc: /* Last input event.  */);
 
   DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
-    "List of events to be read as the command input.\n\
-These events are processed first, before actual keyboard input.");
+              doc: /* List of events to be read as the command input.
+These events are processed first, before actual keyboard input.  */);
   Vunread_command_events = Qnil;
 
   DEFVAR_INT ("unread-command-char", &unread_command_char,
-    "If not -1, an object to be read as next command input event.");
+             doc: /* If not -1, an object to be read as next command input event.  */);
 
   DEFVAR_LISP ("unread-post-input-method-events", &Vunread_post_input_method_events,
-    "List of events to be processed as input by input methods.\n\
-These events are processed after `unread-command-events', but\n\
-before actual keyboard input.");
+              doc: /* List of events to be processed as input by input methods.
+These events are processed after `unread-command-events', but
+before actual keyboard input.  */);
   Vunread_post_input_method_events = Qnil;
 
   DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,
-    "List of events to be processed as input by input methods.\n\
-These events are processed after `unread-command-events', but\n\
-before actual keyboard input.");
+              doc: /* List of events to be processed as input by input methods.
+These events are processed after `unread-command-events', but
+before actual keyboard input.  */);
   Vunread_input_method_events = Qnil;
 
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
-    "Meta-prefix character code.\n\
-Meta-foo as command input turns into this character followed by foo.");
+              doc: /* Meta-prefix character code.
+Meta-foo as command input turns into this character followed by foo.  */);
   XSETINT (meta_prefix_char, 033);
 
   DEFVAR_KBOARD ("last-command", Vlast_command,
-    "The last command executed.\n\
-Normally a symbol with a function definition, but can be whatever was found\n\
-in the keymap, or whatever the variable `this-command' was set to by that\n\
-command.\n\
-\n\
-The value `mode-exit' is special; it means that the previous command\n\
-read an event that told it to exit, and it did so and unread that event.\n\
-In other words, the present command is the event that made the previous\n\
-command exit.\n\
-\n\
-The value `kill-region' is special; it means that the previous command\n\
-was a kill command.");
+                doc: /* The last command executed.
+Normally a symbol with a function definition, but can be whatever was found
+in the keymap, or whatever the variable `this-command' was set to by that
+command.
+
+The value `mode-exit' is special; it means that the previous command
+read an event that told it to exit, and it did so and unread that event.
+In other words, the present command is the event that made the previous
+command exit.
+
+The value `kill-region' is special; it means that the previous command
+was a kill command.  */);
 
   DEFVAR_KBOARD ("real-last-command", Vreal_last_command,
-    "Same as `last-command', but never altered by Lisp code.");
+                doc: /* Same as `last-command', but never altered by Lisp code.  */);
 
   DEFVAR_LISP ("this-command", &Vthis_command,
-    "The command now being executed.\n\
-The command can set this variable; whatever is put here\n\
-will be in `last-command' during the following command.");
+              doc: /* The command now being executed.
+The command can set this variable; whatever is put here
+will be in `last-command' during the following command.  */);
   Vthis_command = Qnil;
 
+  DEFVAR_LISP ("this-original-command", &Vthis_original_command,
+              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,
-    "*Number of input events between auto-saves.\n\
-Zero means disable autosaving due to number of characters typed.");
+             doc: /* *Number of input events between auto-saves.
+Zero means disable autosaving due to number of characters typed.  */);
   auto_save_interval = 300;
 
   DEFVAR_LISP ("auto-save-timeout", &Vauto_save_timeout,
-    "*Number of seconds idle time before auto-save.\n\
-Zero or nil means disable auto-saving due to idleness.\n\
-After auto-saving due to this many seconds of idle time,\n\
-Emacs also does a garbage collection if that seems to be warranted.");
+              doc: /* *Number of seconds idle time before auto-save.
+Zero or nil means disable auto-saving due to idleness.
+After auto-saving due to this many seconds of idle time,
+Emacs also does a garbage collection if that seems to be warranted.  */);
   XSETFASTINT (Vauto_save_timeout, 30);
 
   DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes,
-    "*Nonzero means echo unfinished commands after this many seconds of pause.\n\
-The value may be integer or floating point.");
+              doc: /* *Nonzero means echo unfinished commands after this many seconds of pause.
+The value may be integer or floating point.  */);
   Vecho_keystrokes = make_number (1);
 
   DEFVAR_INT ("polling-period", &polling_period,
-    "*Interval between polling for input during Lisp execution.\n\
-The reason for polling is to make C-g work to stop a running program.\n\
-Polling is needed only when using X windows and SIGIO does not work.\n\
-Polling is automatically disabled in all other cases.");
+             doc: /* *Interval between polling for input during Lisp execution.
+The reason for polling is to make C-g work to stop a running program.
+Polling is needed only when using X windows and SIGIO does not work.
+Polling is automatically disabled in all other cases.  */);
   polling_period = 2;
 
   DEFVAR_LISP ("double-click-time", &Vdouble_click_time,
-    "*Maximum time between mouse clicks to make a double-click.\n\
-Measured in milliseconds.  nil means disable double-click recognition;\n\
-t means double-clicks have no time limit and are detected\n\
-by position only.");
+              doc: /* *Maximum time between mouse clicks to make a double-click.
+Measured in milliseconds.  nil means disable double-click recognition;
+t means double-clicks have no time limit and are detected
+by position only.  */);
   Vdouble_click_time = make_number (500);
 
   DEFVAR_INT ("double-click-fuzz", &double_click_fuzz,
-    "*Maximum mouse movement between clicks to make a double-click.\n\
-On window-system frames, value is the number of pixels the mouse may have\n\
-moved horizontally or vertically between two clicks to make a double-click.\n\
-On non window-system frames, value is interpreted in units of 1/8 characters\n\
-instead of pixels.");
+             doc: /* *Maximum mouse movement between clicks to make a double-click.
+On window-system frames, value is the number of pixels the mouse may have
+moved horizontally or vertically between two clicks to make a double-click.
+On non window-system frames, value is interpreted in units of 1/8 characters
+instead of pixels.
+
+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,
-    "*Non-nil means inhibit local map menu bar menus.");
+              doc: /* *Non-nil means inhibit local map menu bar menus.  */);
   inhibit_local_menu_bar_menus = 0;
 
   DEFVAR_INT ("num-input-keys", &num_input_keys,
-    "Number of complete key sequences read as input so far.\n\
-This includes key sequences read from keyboard macros.\n\
-The number is effectively the number of interactive command invocations.");
+             doc: /* Number of complete key sequences read as input so far.
+This includes key sequences read from keyboard macros.
+The number is effectively the number of interactive command invocations.  */);
   num_input_keys = 0;
 
   DEFVAR_INT ("num-nonmacro-input-events", &num_nonmacro_input_events,
-    "Number of input events read from the keyboard so far.\n\
-This does not include events generated by keyboard macros.");
+             doc: /* Number of input events read from the keyboard so far.
+This does not include events generated by keyboard macros.  */);
   num_nonmacro_input_events = 0;
 
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
-    "The frame in which the most recently read event occurred.\n\
-If the last event came from a keyboard macro, this is set to `macro'.");
+              doc: /* The frame in which the most recently read event occurred.
+If the last event came from a keyboard macro, this is set to `macro'.  */);
   Vlast_event_frame = Qnil;
 
   /* This variable is set up in sysdep.c.  */
   DEFVAR_LISP ("tty-erase-char", &Vtty_erase_char,
-    "The ERASE character as set by the user with stty.");
+              doc: /* The ERASE character as set by the user with stty.  */);
 
   DEFVAR_LISP ("help-char", &Vhelp_char,
-    "Character to recognize as meaning Help.\n\
-When it is read, do `(eval help-form)', and display result if it's a string.\n\
-If the value of `help-form' is nil, this char can be read normally.");
+              doc: /* Character to recognize as meaning Help.
+When it is read, do `(eval help-form)', and display result if it's a string.
+If the value of `help-form' is nil, this char can be read normally.  */);
   XSETINT (Vhelp_char, Ctl ('H'));
 
   DEFVAR_LISP ("help-event-list", &Vhelp_event_list,
-    "List of input events to recognize as meaning Help.\n\
-These work just like the value of `help-char' (see that).");
+              doc: /* List of input events to recognize as meaning Help.
+These work just like the value of `help-char' (see that).  */);
   Vhelp_event_list = Qnil;
 
   DEFVAR_LISP ("help-form", &Vhelp_form,
-    "Form to execute when character `help-char' is read.\n\
-If the form returns a string, that string is displayed.\n\
-If `help-form' is nil, the help char is not recognized.");
+              doc: /* Form to execute when character `help-char' is read.
+If the form returns a string, that string is displayed.
+If `help-form' is nil, the help char is not recognized.  */);
   Vhelp_form = Qnil;
 
   DEFVAR_LISP ("prefix-help-command", &Vprefix_help_command,
-    "Command to run when `help-char' character follows a prefix key.\n\
-This command is used only when there is no actual binding\n\
-for that character after that prefix key.");
+              doc: /* Command to run when `help-char' character follows a prefix key.
+This command is used only when there is no actual binding
+for that character after that prefix key.  */);
   Vprefix_help_command = Qnil;
 
   DEFVAR_LISP ("top-level", &Vtop_level,
-    "Form to evaluate when Emacs starts up.\n\
-Useful to set before you dump a modified Emacs.");
+              doc: /* Form to evaluate when Emacs starts up.
+Useful to set before you dump a modified Emacs.  */);
   Vtop_level = Qnil;
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
-    "Translate table for keyboard input, or nil.\n\
-Each character is looked up in this string and the contents used instead.\n\
-The value may be a string, a vector, or a char-table.\n\
-If it is a string or vector of length N,\n\
-character codes N and up are untranslated.\n\
-In a vector or a char-table, an element which is nil means \"no translation\".");
+              doc: /* Translate table for keyboard input, or nil.
+Each character is looked up in this string and the contents used instead.
+The value may be a string, a vector, or a char-table.
+If it is a string or vector of length N,
+character codes N and up are untranslated.
+In a vector or a char-table, an element which is nil means "no translation".
+
+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,
-    "Non-nil means to always spawn a subshell instead of suspending.\n\
-\(Even if the operating system has support for stopping a process.\)");
+              doc: /* Non-nil means to always spawn a subshell instead of suspending.
+\(Even if the operating system has support for stopping a process.\)  */);
   cannot_suspend = 0;
 
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
-    "Non-nil means prompt with menus when appropriate.\n\
-This is done when reading from a keymap that has a prompt string,\n\
-for elements that have prompt strings.\n\
-The menu is displayed on the screen\n\
-if X menus were enabled at configuration\n\
-time and the previous event was a mouse click prefix key.\n\
-Otherwise, menu prompting uses the echo area.");
+              doc: /* Non-nil means prompt with menus when appropriate.
+This is done when reading from a keymap that has a prompt string,
+for elements that have prompt strings.
+The menu is displayed on the screen
+if X menus were enabled at configuration
+time and the previous event was a mouse click prefix key.
+Otherwise, menu prompting uses the echo area.  */);
   menu_prompting = 1;
 
   DEFVAR_LISP ("menu-prompt-more-char", &menu_prompt_more_char,
-    "Character to see next line of menu prompt.\n\
-Type this character while in a menu prompt to rotate around the lines of it.");
+              doc: /* Character to see next line of menu prompt.
+Type this character while in a menu prompt to rotate around the lines of it.  */);
   XSETINT (menu_prompt_more_char, ' ');
 
   DEFVAR_INT ("extra-keyboard-modifiers", &extra_keyboard_modifiers,
-    "A mask of additional modifier keys to use with every keyboard character.\n\
-Emacs applies the modifiers of the character stored here to each keyboard\n\
-character it reads.  For example, after evaluating the expression\n\
-    (setq extra-keyboard-modifiers ?\\C-x)\n\
-all input characters will have the control modifier applied to them.\n\
-\n\
-Note that the character ?\\C-@, equivalent to the integer zero, does\n\
-not count as a control character; rather, it counts as a character\n\
-with no modifiers; thus, setting `extra-keyboard-modifiers' to zero\n\
-cancels any modification.");
+             doc: /* A mask of additional modifier keys to use with every keyboard character.
+Emacs applies the modifiers of the character stored here to each keyboard
+character it reads.  For example, after evaluating the expression
+    (setq extra-keyboard-modifiers ?\\C-x)
+all input characters will have the control modifier applied to them.
+
+Note that the character ?\\C-@, equivalent to the integer zero, does
+not count as a control character; rather, it counts as a character
+with no modifiers; thus, setting `extra-keyboard-modifiers' to zero
+cancels any modification.  */);
   extra_keyboard_modifiers = 0;
 
   DEFVAR_LISP ("deactivate-mark", &Vdeactivate_mark,
-    "If an editing command sets this to t, deactivate the mark afterward.\n\
-The command loop sets this to nil before each command,\n\
-and tests the value when the command returns.\n\
-Buffer modification stores t in this variable.");
+              doc: /* If an editing command sets this to t, deactivate the mark afterward.
+The command loop sets this to nil before each command,
+and tests the value when the command returns.
+Buffer modification stores t in this variable.  */);
   Vdeactivate_mark = Qnil;
 
   DEFVAR_LISP ("command-hook-internal", &Vcommand_hook_internal,
-    "Temporary storage of pre-command-hook or post-command-hook.");
+              doc: /* Temporary storage of pre-command-hook or post-command-hook.  */);
   Vcommand_hook_internal = Qnil;
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
-    "Normal hook run before each command is executed.\n\
-If an unhandled error happens in running this hook,\n\
-the hook value is set to nil, since otherwise the error\n\
-might happen repeatedly and make Emacs nonfunctional.");
+              doc: /* Normal hook run before each command is executed.
+If an unhandled error happens in running this hook,
+the hook value is set to nil, since otherwise the error
+might happen repeatedly and make Emacs nonfunctional.  */);
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
-    "Normal hook run after each command is executed.\n\
-If an unhandled error happens in running this hook,\n\
-the hook value is set to nil, since otherwise the error\n\
-might happen repeatedly and make Emacs nonfunctional.");
+              doc: /* Normal hook run after each command is executed.
+If an unhandled error happens in running this hook,
+the hook value is set to nil, since otherwise the error
+might happen repeatedly and make Emacs nonfunctional.  */);
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
-    "Normal hook run after each command is executed, if idle.\n\
-Errors running the hook are caught and ignored.\n\
-This feature is obsolete; use idle timers instead.  See `etc/NEWS'.");
+              doc: /* Normal hook run after each command is executed, if idle.
+Errors running the hook are caught and ignored.  */);
   Vpost_command_idle_hook = Qnil;
 
   DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
-    "Delay time before running `post-command-idle-hook'.\n\
-This is measured in microseconds.");
+             doc: /* Delay time before running `post-command-idle-hook'.
+This is measured in microseconds.  */);
   post_command_idle_delay = 100000;
 
 #if 0
   DEFVAR_LISP ("echo-area-clear-hook", ...,
-    "Normal hook run when clearing the echo area.");
+              doc: /* Normal hook run when clearing the echo area.  */);
 #endif
   Qecho_area_clear_hook = intern ("echo-area-clear-hook");
-  XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+  SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
-    "t means menu bar, specified Lucid style, needs to be recomputed.");
+              doc: /* Non-nil means menu bar, specified Lucid style, needs to be recomputed.  */);
   Vlucid_menu_bar_dirty_flag = Qnil;
 
   DEFVAR_LISP ("menu-bar-final-items", &Vmenu_bar_final_items,
-    "List of menu bar items to move to the end of the menu bar.\n\
-The elements of the list are event types that may have menu bar bindings.");
+              doc: /* List of menu bar items to move to the end of the menu bar.
+The elements of the list are event types that may have menu bar bindings.  */);
   Vmenu_bar_final_items = Qnil;
 
   DEFVAR_KBOARD ("overriding-terminal-local-map",
                 Voverriding_terminal_local_map,
-    "Per-terminal keymap that overrides all other local keymaps.\n\
-If this variable is non-nil, it is used as a keymap instead of the\n\
-buffer's local map, and the minor mode keymaps and text property keymaps.\n\
-This variable is intended to let commands such as `universal-argument'\n\
-set up a different keymap for reading the next command.");
+                doc: /* Per-terminal keymap that overrides all other local keymaps.
+If this variable is non-nil, it is used as a keymap instead of the
+buffer's local map, and the minor mode keymaps and text property keymaps.
+This variable is intended to let commands such as `universal-argument'
+set up a different keymap for reading the next command.  */);
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
-    "Keymap that overrides all other local keymaps.\n\
-If this variable is non-nil, it is used as a keymap instead of the\n\
-buffer's local map, and the minor mode keymaps and text property keymaps.");
+              doc: /* Keymap that overrides all other local keymaps.
+If this variable is non-nil, it is used as a keymap instead of the
+buffer's local map, and the minor mode keymaps and text property keymaps.  */);
   Voverriding_local_map = Qnil;
 
   DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
-    "Non-nil means `overriding-local-map' applies to the menu bar.\n\
-Otherwise, the menu bar continues to reflect the buffer's local map\n\
-and the minor mode maps regardless of `overriding-local-map'.");
+              doc: /* Non-nil means `overriding-local-map' applies to the menu bar.
+Otherwise, the menu bar continues to reflect the buffer's local map
+and the minor mode maps regardless of `overriding-local-map'.  */);
   Voverriding_local_map_menu_flag = Qnil;
 
   DEFVAR_LISP ("special-event-map", &Vspecial_event_map,
-    "Keymap defining bindings for special events to execute at low level.");
+              doc: /* Keymap defining bindings for special events to execute at low level.  */);
   Vspecial_event_map = Fcons (intern ("keymap"), Qnil);
 
   DEFVAR_LISP ("track-mouse", &do_mouse_tracking,
-    "*Non-nil means generate motion events for mouse motion.");
+              doc: /* *Non-nil means generate motion events for mouse motion.  */);
 
   DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist,
-    "Alist of system-specific X windows key symbols.\n\
-Each element should have the form (N . SYMBOL) where N is the\n\
-numeric keysym code (sans the \"system-specific\" bit 1<<28)\n\
-and SYMBOL is its name.");
+                doc: /* Alist of system-specific X windows key symbols.
+Each element should have the form (N . SYMBOL) where N is the
+numeric keysym code (sans the \"system-specific\" bit 1<<28)
+and SYMBOL is its name.  */);
 
   DEFVAR_LISP ("deferred-action-list", &Vdeferred_action_list,
-    "List of deferred actions to be performed at a later time.\n\
-The precise format isn't relevant here; we just check whether it is nil.");
+              doc: /* List of deferred actions to be performed at a later time.
+The precise format isn't relevant here; we just check whether it is nil.  */);
   Vdeferred_action_list = Qnil;
 
   DEFVAR_LISP ("deferred-action-function", &Vdeferred_action_function,
-    "Function to call to handle deferred actions, after each command.\n\
-This function is called with no arguments after each command\n\
-whenever `deferred-action-list' is non-nil.");
+              doc: /* Function to call to handle deferred actions, after each command.
+This function is called with no arguments after each command
+whenever `deferred-action-list' is non-nil.  */);
   Vdeferred_action_function = Qnil;
 
   DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
-    "*Non-nil means show the equivalent key-binding when M-x command has one.\n\
-The value can be a length of time to show the message for.\n\
-If the value is non-nil and not a number, we wait 2 seconds.");
+              doc: /* *Non-nil means show the equivalent key-binding when M-x command has one.
+The value can be a length of time to show the message for.
+If the value is non-nil and not a number, we wait 2 seconds.  */);
   Vsuggest_key_bindings = Qt;
 
   DEFVAR_LISP ("timer-list", &Vtimer_list,
-    "List of active absolute time timers in order of increasing time");
+              doc: /* List of active absolute time timers in order of increasing time.  */);
   Vtimer_list = Qnil;
 
   DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
-    "List of active idle-time timers in order of increasing time");
+              doc: /* List of active idle-time timers in order of increasing time.  */);
   Vtimer_idle_list = Qnil;
 
   DEFVAR_LISP ("input-method-function", &Vinput_method_function,
-    "If non-nil, the function that implements the current input method.\n\
-It's called with one argument, a printing character that was just read.\n\
-\(That means a character with code 040...0176.)\n\
-Typically this function uses `read-event' to read additional events.\n\
-When it does so, it should first bind `input-method-function' to nil\n\
-so it will not be called recursively.\n\
-\n\
-The function should return a list of zero or more events\n\
-to be used as input.  If it wants to put back some events\n\
-to be reconsidered, separately, by the input method,\n\
-it can add them to the beginning of `unread-command-events'.\n\
-\n\
-The input method function can find in `input-method-previous-method'\n\
-the previous echo area message.\n\
-\n\
-The input method function should refer to the variables\n\
-`input-method-use-echo-area' and `input-method-exit-on-first-char'\n\
-for guidance on what to do.");
+              doc: /* If non-nil, the function that implements the current input method.
+It's called with one argument, a printing character that was just read.
+\(That means a character with code 040...0176.)
+Typically this function uses `read-event' to read additional events.
+When it does so, it should first bind `input-method-function' to nil
+so it will not be called recursively.
+
+The function should return a list of zero or more events
+to be used as input.  If it wants to put back some events
+to be reconsidered, separately, by the input method,
+it can add them to the beginning of `unread-command-events'.
+
+The input method function can find in `input-method-previous-method'
+the previous echo area message.
+
+The input method function should refer to the variables
+`input-method-use-echo-area' and `input-method-exit-on-first-char'
+for guidance on what to do.  */);
   Vinput_method_function = Qnil;
 
   DEFVAR_LISP ("input-method-previous-message",
               &Vinput_method_previous_message,
-    "When `input-method-function' is called, hold the previous echo area message.\n\
-This variable exists because `read-event' clears the echo area\n\
-before running the input method.  It is nil if there was no message.");
+              doc: /* When `input-method-function' is called, hold the previous echo area message.
+This variable exists because `read-event' clears the echo area
+before running the input method.  It is nil if there was no message.  */);
   Vinput_method_previous_message = Qnil;
 
   DEFVAR_LISP ("show-help-function", &Vshow_help_function,
-    "If non-nil, the function that implements the display of help.\n\
-It's called with one argument, the help string to display.");
+              doc: /* If non-nil, the function that implements the display of help.
+It's called with one argument, the help string to display.  */);
   Vshow_help_function = Qnil;
 
   DEFVAR_LISP ("disable-point-adjustment", &Vdisable_point_adjustment,
-    "If non-nil, suppress point adjustment after executing a command.\n\
-\n\
-After a command is executed, if point is moved into a region that has\n\
-special properties (e.g. composition, display), we adjust point to\n\
-the boundary of the region.  But, several special commands sets this\n\
-variable to non-nil, then we suppress the point adjustment.\n\
-\n\
-This variable is set to nil before reading a command, and is checked\n\
-just after executing the command");
+              doc: /* If non-nil, suppress point adjustment after executing a command.
+
+After a command is executed, if point is moved into a region that has
+special properties (e.g. composition, display), we adjust point to
+the boundary of the region.  But, several special commands sets this
+variable to non-nil, then we suppress the point adjustment.
+
+This variable is set to nil before reading a command, and is checked
+just after executing the command.  */);
   Vdisable_point_adjustment = Qnil;
 
   DEFVAR_LISP ("global-disable-point-adjustment",
               &Vglobal_disable_point_adjustment,
-    "*If non-nil, always suppress point adjustment.\n\
-\n\
-The default value is nil, in which case, point adjustment are\n\
-suppressed only after special commands that set\n\
-`disable-point-adjustment' (which see) to non-nil.");
+              doc: /* *If non-nil, always suppress point adjustment.
+
+The default value is nil, in which case, point adjustment are
+suppressed only after special commands that set
+`disable-point-adjustment' (which see) to non-nil.  */);
   Vglobal_disable_point_adjustment = Qnil;
 
   DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings,
-    "Non-nil means updating menu bindings is allowed.\n\
-A value of nil means menu bindings should not be updated.\n\
-Used during Emacs' startup.");
+              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,
-    "*How long to display an echo-area message when the minibuffer is active.\n\
-If the value is not a number, such messages don't time out.");
+              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);
 }
 
@@ -10867,4 +11275,12 @@ keys_of_keyboard ()
                            "ignore-event");
   initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
                            "ignore-event");
+  /* 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");
 }