Upgraded to mh-e version 6.1.1.
[bpt/emacs.git] / src / keyboard.c
index 3e80849..6c6eb0f 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
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -71,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
@@ -97,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
@@ -154,7 +151,7 @@ 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;                                                   \
@@ -301,7 +298,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;
@@ -325,7 +322,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
@@ -337,7 +334,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.  */
@@ -354,12 +351,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.  */
 
@@ -373,6 +370,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;
 
@@ -437,7 +438,7 @@ Lisp_Object Vdeactivate_mark;
 Lisp_Object Vlucid_menu_bar_dirty_flag;
 Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 
-Lisp_Object Qecho_area_clear_hook, Vecho_area_clear_hook;
+Lisp_Object Qecho_area_clear_hook;
 
 /* Hooks to run before and after each command.  */
 Lisp_Object Qpre_command_hook, Vpre_command_hook;
@@ -447,7 +448,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.  */
@@ -504,7 +505,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.  */
@@ -513,7 +514,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;
 
@@ -543,16 +544,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.  */
@@ -585,6 +591,7 @@ 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 ();
@@ -639,14 +646,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;
@@ -659,6 +666,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.  */
 
@@ -667,7 +679,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 ();
@@ -705,38 +719,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 ();
 }
 
@@ -750,43 +734,73 @@ echo_char (c)
 {
   if (current_kboard->immediate_echo)
     {
-      char *ptr = current_kboard->echoptr;
-
-      if (ptr != current_kboard->echobuf)
-       *ptr++ = ' ';
+      int size = KEY_DESCRIPTION_SIZE + 100;
+      char *buffer = (char *) alloca (size);
+      char *ptr = buffer;
+      Lisp_Object echo_string;
 
+      echo_string = current_kboard->echo_string;
+      
       /* If someone has passed us a composite event, use its head symbol.  */
       c = EVENT_HEAD (c);
 
       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) > 0)
+       {
+         Lisp_Object last_char, idx;
+
+         idx = make_number (SCHARS (echo_string) - 1);
+         last_char = Faref (echo_string, idx);
+
+         if (XINT (last_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 ();
     }
@@ -798,22 +812,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 ();
 }
 
@@ -840,8 +855,9 @@ echo_now ()
     }
 
   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.  */
@@ -858,8 +874,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;
@@ -870,7 +886,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.
@@ -878,12 +896,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
@@ -916,7 +936,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)
@@ -928,8 +948,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
 
@@ -982,7 +1002,7 @@ Alternately, `(throw 'exit t)' makes this function signal an error.
 This function is called by the editor initialization to begin editing.  */)
      ()
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
   Lisp_Object buffer;
 
   command_loop_level++;
@@ -1103,6 +1123,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)
@@ -1179,14 +1204,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, context, Vsignaling_function);
 
-  print_error_message (data, stream);
+  Vsignaling_function = Qnil;
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're in -batch mode, this error should cause Emacs to exit.  */
@@ -1231,7 +1261,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
@@ -1331,31 +1361,36 @@ command_loop_1 ()
   this_command_key_count = 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;
@@ -1389,7 +1424,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);
@@ -1503,6 +1538,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 = Fremap_command (cmd), !NILP (cmd1))
+           cmd = cmd1;
+       }
+
       /* Execute the command.  */
 
       Vthis_command = cmd;
@@ -1631,7 +1675,8 @@ command_loop_1 ()
          /* Here for a command that isn't executed directly */
 
 #ifdef HAVE_X_WINDOWS
-         if (display_hourglass_p)
+         if (display_hourglass_p
+             && NILP (Vexecuting_macro))
            start_hourglass ();
 #endif
 
@@ -1641,7 +1686,12 @@ command_loop_1 ()
          Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
 #ifdef HAVE_X_WINDOWS
-         if (display_hourglass_p)
+         /* 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))
            cancel_hourglass ();
 #endif
        }
@@ -1697,8 +1747,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"));
@@ -1799,7 +1855,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);
@@ -1811,7 +1867,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.  */
 
@@ -2007,7 +2063,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.
 
@@ -2051,20 +2107,20 @@ 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;
            }
@@ -2088,6 +2144,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.
@@ -2127,6 +2191,7 @@ 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;
 
@@ -2228,7 +2293,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));
@@ -2304,7 +2369,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      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)
@@ -2460,7 +2525,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.  */
@@ -2567,7 +2632,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
@@ -2636,7 +2701,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))
     {
@@ -2653,7 +2718,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.  */
@@ -2669,6 +2734,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 ();
@@ -2681,10 +2753,10 @@ 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)
@@ -2767,7 +2839,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       Lisp_Object keys; 
       int key_count;
       struct gcpro gcpro1;
-      int count = specpdl_ptr - specpdl;
+      int count = SPECPDL_INDEX ();
 
       /* Save the echo status.  */
       int saved_immediate_echo = current_kboard->immediate_echo;
@@ -2847,11 +2919,17 @@ 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.  */
@@ -2891,7 +2969,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));
@@ -2917,6 +2995,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+ exit:
+  RESUME_POLLING;
   RETURN_UNGCPRO (c);
 }
 
@@ -2976,43 +3056,101 @@ 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.  */
 
-      help = Fnth (make_number (2), c);
-      if (STRINGP (help))
+      Lisp_Object ev1, ev2, ev3;
+      int ix1, ix2, ix3;
+      
+      if ((ix1 = recent_keys_index - 1) < 0)
+       ix1 = NUM_RECENT_KEYS - 1;
+      ev1 = AREF (recent_keys, ix1);
+      
+      if ((ix2 = ix1 - 1) < 0)
+       ix2 = NUM_RECENT_KEYS - 1;
+      ev2 = AREF (recent_keys, ix2);
+      
+      if ((ix3 = ix2 - 1) < 0)
+       ix3 = NUM_RECENT_KEYS - 1;
+      ev3 = AREF (recent_keys, ix3);
+     
+      if (EQ (XCAR (c), Qhelp_echo))
        {
-         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)))
+         /* 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))
+       {
+         /* 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.
@@ -3036,8 +3174,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);
            }
@@ -3045,11 +3183,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
@@ -3118,7 +3251,7 @@ 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);
@@ -3155,14 +3288,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;
@@ -3182,6 +3340,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;
 
@@ -3213,10 +3380,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;
 
@@ -3229,7 +3396,7 @@ kbd_buffer_store_event (event)
 
       if (c == quit_char)
        {
-         extern SIGTYPE interrupt_signal ();
+         static SIGTYPE interrupt_signal P_ ((int));
 #ifdef MULTI_KBOARD
          KBOARD *kb;
          struct input_event *sp;
@@ -3249,7 +3416,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;
                    }
@@ -3273,7 +3440,7 @@ kbd_buffer_store_event (event)
          }
 
          last_event_timestamp = event->timestamp;
-         interrupt_signal ();
+         interrupt_signal (0 /* dummy */);
          return;
        }
 
@@ -3283,11 +3450,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)
@@ -3301,12 +3468,12 @@ kbd_buffer_store_event (event)
     {
       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
@@ -3357,25 +3524,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;
 }
 
 
@@ -3390,21 +3549,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 ()
 {
@@ -3414,22 +3567,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.  */
 
@@ -3440,7 +3593,7 @@ kbd_buffer_events_waiting (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)
@@ -3450,7 +3603,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
@@ -3463,7 +3616,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;
 }
 
 
@@ -3568,7 +3721,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;
@@ -3587,7 +3740,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;
@@ -3603,8 +3756,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);
@@ -3613,14 +3766,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);
@@ -3628,14 +3781,14 @@ 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)
+      else if (event->kind == MENU_BAR_ACTIVATE_EVENT)
        {
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
@@ -3644,50 +3797,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)
        {
@@ -3705,6 +3855,14 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
+         kbd_fetch_ptr = event + 1;
+       }
+      else if (event->kind == SELECT_WINDOW_EVENT)
+       {
+         /* Make an event (select-window (WINDOW)).  */
+         obj = Fcons (event->frame_or_window, Qnil);
+         obj = Fcons (Qselect_window, Fcons (obj, Qnil));
+
          kbd_fetch_ptr = event + 1;
        }
       else
@@ -3736,7 +3894,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            {
              obj = make_lispy_event (event);
              
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS)
              /* 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
@@ -3830,7 +3988,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;
@@ -3849,7 +4007,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;
@@ -3891,6 +4049,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))
     {
@@ -4072,7 +4232,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
@@ -4113,7 +4273,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;
@@ -4522,7 +4682,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
@@ -4593,7 +4753,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. */
 
@@ -4616,7 +4776,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;
@@ -4640,7 +4800,7 @@ make_lispy_event (event)
        return lispy_c;
       }
 
-    case multibyte_char_keystroke:
+    case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
       {
        Lisp_Object lispy_c;
 
@@ -4650,7 +4810,7 @@ make_lispy_event (event)
 
       /* 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++)
@@ -4662,21 +4822,6 @@ 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);
-       }
-
 #ifdef XK_kana_A
       if (event->code >= 0x400 && event->code < 0x500)
        return modify_event_symbol (event->code - 0x400,
@@ -4696,30 +4841,26 @@ make_lispy_event (event)
                                    iso_lispy_function_keys, &func_key_syms,
                                    (sizeof (iso_lispy_function_keys)
                                     / sizeof (iso_lispy_function_keys[0])));
-      else
 #endif
 
-#ifdef HAVE_X_WINDOWS
-      if (event->code - FUNCTION_KEY_OFFSET < 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))
+             >= sizeof lispy_function_keys / sizeof *lispy_function_keys)
+         || !lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
        {
-         /* EVENT->code is an unknown keysym, for example someone
-            assigned `ccaron' to a key in a locale where
-            XmbLookupString doesn't return a translation for it.  */
-         char *name;
-         Lisp_Object symbol;
-         
-         BLOCK_INPUT;
-         /* This returns a pointer to a static area.  Don't free it.  */
-         name = XKeysymToString (event->code);
-         symbol = name ? intern (name) : Qnil;
-         UNBLOCK_INPUT;
-         
-         if (!NILP (symbol))
-           return apply_modifiers (event->modifiers, symbol);
+         /* 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);
        }
-#endif /* HAVE_X_WINDOWS */
 
       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
                                  event->modifiers,
@@ -4731,9 +4872,9 @@ make_lispy_event (event)
 #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;
@@ -4746,7 +4887,7 @@ 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;
            struct frame *f = XFRAME (event->frame_or_window);
@@ -4801,7 +4942,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;
@@ -4861,6 +5002,15 @@ make_lispy_event (event)
                  }
                else if (part == 2)
                  posn = Qvertical_line;
+               else if (part == 6 || part == 7)
+                 {
+                   int charpos;
+                   Lisp_Object object = marginal_area_string (w, wx, wy, part,
+                                                              &charpos);
+                   posn = (part == 6) ? Qleft_margin : Qright_margin;
+                   if (STRINGP (object))
+                     string_info = Fcons (object, make_number (charpos));
+                 }
                else
                  {
                    Lisp_Object object;
@@ -4984,32 +5134,28 @@ 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
@@ -5052,7 +5198,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
@@ -5071,7 +5217,7 @@ make_lispy_event (event)
         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;
 
@@ -5088,6 +5234,7 @@ make_lispy_event (event)
 
        /* Always treat scroll bar events as clicks. */
        event->modifiers |= click_modifier;
+       event->modifiers &= ~up_modifier;
 
        /* Get the symbol we should use for the mouse click.  */
        head = modify_event_symbol (event->code,
@@ -5102,7 +5249,7 @@ make_lispy_event (event)
 #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;
@@ -5145,7 +5292,9 @@ make_lispy_event (event)
                               Qnil));
        }
       }
-    case mouse_wheel:
+#endif /* WINDOWSNT */
+#if defined(WINDOWSNT) || defined(MAC_OSX)
+    case MOUSE_WHEEL_EVENT:
       {
        int part;
        FRAME_PTR f = XFRAME (event->frame_or_window);
@@ -5210,13 +5359,15 @@ 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 /* WINDOWSNT || MAC_OSX */
 
-    case drag_n_drop:
+    case DRAG_N_DROP_EVENT:
       {
        int part;
        FRAME_PTR f;
@@ -5298,7 +5449,7 @@ 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)
     case MENU_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
@@ -5311,7 +5462,7 @@ make_lispy_event (event)
     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))
@@ -5322,6 +5473,9 @@ make_lispy_event (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 ();
@@ -5440,16 +5594,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;
@@ -5458,7 +5612,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)
@@ -5496,8 +5650,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.  */
@@ -5508,9 +5662,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)
@@ -5565,8 +5719,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);
   }
@@ -5624,8 +5778,8 @@ 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 & ~VALMASK)
@@ -5678,9 +5832,9 @@ 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);
@@ -5818,9 +5972,9 @@ 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,
+         sprintf (buf, "%s-%d", SDATA (name_alist_or_stem),
                   XINT (symbol_int) + 1);
          value = intern (buf);
        }
@@ -5901,8 +6055,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))
     {
@@ -5937,17 +6091,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':
@@ -6045,15 +6199,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))
@@ -6061,7 +6218,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.  */
@@ -6095,7 +6268,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
@@ -6104,7 +6277,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;
 
@@ -6259,7 +6432,7 @@ read_avail_input (expected)
 #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;
@@ -6278,7 +6451,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;
     }
@@ -6427,17 +6600,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;
@@ -6644,7 +6820,7 @@ 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,
@@ -6827,11 +7003,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))
@@ -6845,6 +7016,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);
@@ -6890,7 +7066,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))
@@ -6936,7 +7112,7 @@ 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);
+         tem = Fwhere_is_internal (def, Qnil, Qt, Qnil, Qt);
          XSETCAR (cachelist, tem);
          if (NILP (tem))
            {
@@ -7006,7 +7182,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;
@@ -7046,8 +7222,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;
 
@@ -7079,17 +7253,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);
     }
 
@@ -7217,8 +7394,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...)'.
@@ -7312,7 +7487,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;
     }
 
@@ -7446,7 +7621,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* If we don't have any menus, just read a character normally.  */
-  if (mapno >= nmaps)
+  if (!STRINGP (name))
     return Qnil;
 
 #ifdef HAVE_MENUS
@@ -7529,6 +7704,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   char *menu;
 
   vector = Qnil;
+  name = Qnil;
 
   if (! menu_prompting)
     return Qnil;
@@ -7556,12 +7732,12 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
     }
 
   /* 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;
@@ -7639,17 +7815,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))
@@ -7667,8 +7845,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
 
                  /* 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)
                    {
@@ -7688,20 +7866,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;
                    }
@@ -7858,7 +8036,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;
@@ -7896,6 +8074,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.
@@ -7944,24 +8125,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
@@ -8025,53 +8191,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++)
@@ -8091,12 +8260,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      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)
+        || (first_binding >= nmaps && fkey_start < t)
+        || (first_binding >= nmaps && keytran_start < t)
         /* 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
@@ -8120,6 +8285,26 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         just one key.  */
       volatile int echo_local_start, keys_local_start, local_first_binding;
 
+      /* 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 = Vfunction_key_map;
+         keytran_end = keytran_start -= first_unbound + 1;
+         keytran_map = Vkey_translation_map;
+         goto replay_sequence;
+       }
+
       if (t >= bufsize)
        error ("Key sequence too long");
 
@@ -8221,6 +8406,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.
@@ -8403,7 +8597,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,
@@ -8416,7 +8610,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))
@@ -8444,7 +8638,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))
@@ -8506,9 +8700,20 @@ 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)
@@ -8583,6 +8788,10 @@ 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 (t == last_real_key_start)
                            {
@@ -8635,33 +8844,30 @@ 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).  */
+       {
+         if (fkey_start < t)
+           (fkey_start = fkey_end = t, fkey_map = Vfunction_key_map);
+       }
+      else
+       /* If the sequence is unbound, see if we can hang a function key
+          off the end of it.  */
        {
          Lisp_Object fkey_next;
 
          /* Continue scan from fkey_end until we find a bound suffix.
-            If we fail, increment fkey_start
-            and start fkey_end from there.  */
+            If we fail, increment fkey_start and start over from there.  */
          while (fkey_end < t)
            {
              Lisp_Object key;
 
              key = keybuf[fkey_end++];
-             fkey_next
-               = access_keymap (fkey_map, key, 1, 0, 1);
+             fkey_next = access_keymap (fkey_map, key, 1, 0, 1);
 
              /* Handle symbol with autoload definition.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
@@ -8689,7 +8895,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                 array, then call the function with no args and use
                 its value instead.  */
              if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
-                 && fkey_end == t)
+                 /* If there's a binding (i.e. first_binding >= nmaps)
+                    we don't want to apply this function-key-mapping.  */
+                 && fkey_end == t && first_binding >= nmaps)
                {
                  struct gcpro gcpro1, gcpro2, gcpro3;
                  Lisp_Object tem;
@@ -8706,14 +8914,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                    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)
+                 /* If there's a binding (i.e. first_binding >= nmaps)
+                    we don't want to apply this function-key-mapping.  */
+                 && fkey_end == t && first_binding >= nmaps)
                {
                  int len = XFASTINT (Flength (fkey_next));
 
@@ -8731,7 +8939,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                      for (i = 0; i < len; i++)
                        XSETFASTINT (keybuf[fkey_start + i],
-                                    XSTRING (fkey_next)->data[i]);
+                                    SREF (fkey_next, i));
                    }
 
                  mock_input = t;
@@ -8755,7 +8963,6 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                {
                  fkey_end = ++fkey_start;
                  fkey_map = Vfunction_key_map;
-                 function_key_possible = 0;
                }
            }
        }
@@ -8765,7 +8972,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
        Lisp_Object keytran_next;
 
        /* Scan from keytran_end until we find a bound suffix.  */
-       while (keytran_end < t)
+       while (keytran_end < fkey_start)
          {
            Lisp_Object key;
 
@@ -8790,8 +8997,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            /* 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)
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next)))
              {
                struct gcpro gcpro1, gcpro2, gcpro3;
                Lisp_Object tem;
@@ -8808,42 +9014,39 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  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)
+           if ((VECTORP (keytran_next) || STRINGP (keytran_next)))
              {
                int len = XFASTINT (Flength (keytran_next));
+               int i, diff = len - (keytran_end - keytran_start);
 
-               t = keytran_start + len;
-               if (t >= bufsize)
+               mock_input = max (t, mock_input);
+               if (mock_input + diff >= 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;
+               /* Shift the keys that are after keytran_end.  */
+               if (diff < 0)
+                 for (i = keytran_end; i < mock_input; i++)
+                   keybuf[i + diff] = keybuf[i];
+               else if (diff > 0)
+                 for (i = mock_input - 1; i >= keytran_end; i--)
+                   keybuf[i + diff] = keybuf[i];
+               /* Replace the keys between keytran_start and keytran_end
+                  with those from keytran_next.  */
+               for (i = 0; i < len; i++)
+                 keybuf[keytran_start + i]
+                   = Faref (keytran_next, make_number (i));
+
+               mock_input += diff;
+               keytran_start = keytran_end += diff;
                keytran_map = Vkey_translation_map;
 
-               /* Don't pass the results of key-translation-map
-                  through function-key-map.  */
-               fkey_start = fkey_end = t;
-               fkey_map = Vfunction_key_map;
+               /* Adjust the function-key-map counters.  */
+               fkey_start += diff;
+               fkey_end += diff;
 
                goto replay_sequence;
              }
@@ -8856,7 +9059,6 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              {
                keytran_end = ++keytran_start;
                keytran_map = Vkey_translation_map;
-               key_translation_possible = 0;
              }
          }
       }
@@ -8865,8 +9067,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         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)
@@ -8888,15 +9090,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;
        }
@@ -8904,8 +9098,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;
@@ -8925,15 +9119,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;
            }
@@ -9032,10 +9218,10 @@ will read just one key sequence.  */)
   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,
@@ -9063,7 +9249,7 @@ will read just one key sequence.  */)
                         ! 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)
@@ -9091,10 +9277,10 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
   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,
@@ -9213,7 +9399,7 @@ a special event, so ignore the prefix argument and don't clear it.  */)
            }
        }
 
-      return Fexecute_kbd_macro (final, prefixarg);
+      return Fexecute_kbd_macro (final, prefixarg, Qnil);
     }
 
   if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
@@ -9243,14 +9429,17 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 {
   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, "- ");
@@ -9289,13 +9478,12 @@ 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;
 
@@ -9306,13 +9494,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     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);
@@ -9325,7 +9515,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;
 
@@ -9356,18 +9546,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));
@@ -9384,49 +9574,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.  */
 
@@ -9477,7 +9624,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.  */
 
@@ -9497,7 +9644,7 @@ 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;
 }
 
@@ -9525,6 +9672,8 @@ DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
 
 DEFUN ("this-command-keys", Fthis_command_keys, Sthis_command_keys, 0, 0, 0,
        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.  */)
      ()
 {
@@ -9533,7 +9682,9 @@ The value is a string or a vector.  */)
 }
 
 DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
-       doc: /* 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,
@@ -9543,6 +9694,8 @@ 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,
        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.  */)
@@ -9557,6 +9710,8 @@ 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,
        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.  */)
@@ -9588,19 +9743,24 @@ appears in the echo area and in the value of `this-command-keys'.  */)
 }
 
 DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
-       Sclear_this_command_keys, 0, 0, 0,
+       Sclear_this_command_keys, 0, 1, 0,
        doc: /* Clear out the vector that `this-command-keys' returns.
-Clear vector containing last 100 events.  */)
-     ()
+Also clear the record of the last 100 events, unless optional arg
+KEEP-RECORD is non-nil.  */)
+     (keep_record)
+     Lisp_Object keep_record;
 {
   int i;
   
   this_command_key_count = 0;
 
-  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;
 }
 
@@ -9628,7 +9788,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));
     }
@@ -9637,10 +9797,16 @@ If FILE is nil, close any open dribble file.  */)
 
 DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0,
        doc: /* Discard the contents of the terminal input buffer.
-Also cancel any kbd macro being defined.  */)
+Also end any kbd macro being defined.  */)
      ()
 {
-  current_kboard->defining_kbd_macro = Qnil;
+  if (!NILP (current_kboard->defining_kbd_macro))
+    {
+      /* Discard the last command from the macro.  */
+      Fcancel_kbd_macro_events ();
+      end_kbd_macro ();
+    }
+
   update_mode_lines++;
 
   Vunread_command_events = Qnil;
@@ -9671,13 +9837,13 @@ 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))
@@ -9728,8 +9894,8 @@ 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');
@@ -9744,10 +9910,10 @@ stuff_buffered_input (stuffstring)
       
       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);
@@ -9781,7 +9947,7 @@ 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
@@ -10080,7 +10246,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;
@@ -10217,12 +10383,13 @@ 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},
+  {&Qselect_window,       "select-window",       &Qselect_window}
 };
 
 void
@@ -10282,9 +10449,6 @@ syms_of_keyboard ()
   Qpost_command_idle_hook = intern ("post-command-idle-hook");
   staticpro (&Qpost_command_idle_hook);
 
-  Qecho_area_clear_hook = intern ("echo-area-clear-hook");
-  staticpro (&Qecho_area_clear_hook);
-
   Qdeferred_action_function = intern ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
@@ -10295,15 +10459,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");
@@ -10442,10 +10611,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
@@ -10502,7 +10670,7 @@ 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,
-              doc: /* Last input character.  */);
+              doc: /* Last input event.  */);
 
   DEFVAR_LISP_NOPRO ("last-input-event", &last_input_char,
                     doc: /* Last input event.  */);
@@ -10555,6 +10723,12 @@ 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: /* If non-nil, the original command bound to the current key sequence.
+The value of `this-command' is the result of looking up the original
+command in the active keymaps.  */);
+  Vthis_original_command = Qnil;
+
   DEFVAR_INT ("auto-save-interval", &auto_save_interval,
              doc: /* *Number of input events between auto-saves.
 Zero means disable autosaving due to number of characters typed.  */);
@@ -10591,7 +10765,10 @@ by position only.  */);
 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.  */);
+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,
@@ -10715,8 +10892,7 @@ might happen repeatedly and make Emacs nonfunctional.  */);
 
   DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
               doc: /* Normal hook run after each command is executed, if idle.
-Errors running the hook are caught and ignored.
-This feature is obsolete; use idle timers instead.  See `etc/NEWS'.  */);
+Errors running the hook are caught and ignored.  */);
   Vpost_command_idle_hook = Qnil;
 
   DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
@@ -10724,12 +10900,15 @@ This feature is obsolete; use idle timers instead.  See `etc/NEWS'.  */);
 This is measured in microseconds.  */);
   post_command_idle_delay = 100000;
 
-  DEFVAR_LISP ("echo-area-clear-hook", &Vecho_area_clear_hook,
+#if 0
+  DEFVAR_LISP ("echo-area-clear-hook", ...,
               doc: /* Normal hook run when clearing the echo area.  */);
-  Vecho_area_clear_hook = Qnil;
+#endif
+  Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+  SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
-              doc: /* 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,
@@ -10876,4 +11055,8 @@ keys_of_keyboard ()
                            "ignore-event");
   initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
                            "ignore-event");
+  initial_define_lispy_key (Vspecial_event_map, "select-window",
+                           "handle-select-window");
+  initial_define_lispy_key (Vspecial_event_map, "save-session",
+                           "handle-save-session");
 }