]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(Frename_file) [WINDOWSNT]: Remove conditional code.
[gnu-emacs] / src / keyboard.c
index 45c5c46be2f376c5811e2d42c6b1803295906189..15f8eed53cbfa5db5ad975c7b88e8f001d974683 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Allow config.h to undefine symbols found here.  */
 #include <signal.h>
@@ -56,6 +57,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "xterm.h"
 #endif
 
+#ifdef HAVE_NTGUI
+#include "w32term.h"
+#endif /* HAVE_NTGUI */
+
 /* Include systime.h after xterm.h to avoid double inclusion of time.h. */
 #include "systime.h"
 
@@ -74,7 +79,7 @@ int interrupt_input_pending;
 /* File descriptor to use for input.  */
 extern int input_fd;
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
 #define KBD_BUFFER_SIZE 4096
 #else  /* No X-windows, character input */
@@ -120,6 +125,18 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* Record values of this_command_key_count and echo_length ()
+   before this command was read.  */
+static int before_command_key_count;
+static int before_command_echo_length;
+/* Values of before_command_key_count and before_command_echo_length
+   saved by reset-this-command-lengths.  */
+static int before_command_key_count_1;
+static int before_command_echo_length_1;
+/* Flag set by reset-this-command-lengths,
+   saying to reset the lengths when add_command_key is called.  */
+static int before_command_restore_flag;
+
 extern int minbuf_level;
 
 extern struct backtrace *backtrace_list;
@@ -139,6 +156,10 @@ int waiting_for_input;
 /* True while displaying for echoing.   Delays C-g throwing.  */
 static int echoing;
 
+/* True means we can start echoing at the next input pause
+   even though there is something in the echo area.  */
+static char *ok_to_echo_at_next_pause;
+
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
 
@@ -148,6 +169,9 @@ int immediate_quit;
 /* Character to recognize as the help char.  */
 Lisp_Object Vhelp_char;
 
+/* List of other event types to recognize as meaning "help".  */
+Lisp_Object Vhelp_event_list;
+
 /* Form to execute when help char is typed.  */
 Lisp_Object Vhelp_form;
 
@@ -157,6 +181,12 @@ Lisp_Object Vprefix_help_command;
 /* List of items that should move to the end of the menu bar.  */
 Lisp_Object Vmenu_bar_final_items;
 
+/* Non-nil means show the equivalent key-binding for
+   any M-x command that has one.
+   The value can be a length of time to show the message for.
+   If the value is non-nil and not a number, we wait 2 seconds.  */
+Lisp_Object Vsuggest_key_bindings;
+
 /* Character that causes a quit.  Normally C-g.
 
    If we are running on an ordinary terminal, this must be an ordinary
@@ -184,6 +214,10 @@ Lisp_Object Voverriding_local_map;
 /* If non-nil, Voverriding_local_map applies to the menu bar.  */
 Lisp_Object Voverriding_local_map_menu_flag;
 
+/* Keymap that defines special misc events that should
+   be processed immediately at a low level.  */
+Lisp_Object Vspecial_event_map;
+
 /* Current depth in recursive edits.  */
 int command_loop_level;
 
@@ -244,14 +278,9 @@ static int auto_save_interval;
 
 int last_auto_save;
 
-/* Last command executed by the editor command loop, not counting
-   commands that set the prefix argument.  */
-
-Lisp_Object last_command;
-
 /* The command being executed by the command loop.
-   Commands may set this, and the value set will be copied into last_command
-   instead of the actual command.  */
+   Commands may set this, and the value set will be copied into
+   current_kboard->Vlast_command instead of the actual command.  */
 Lisp_Object this_command;
 
 /* The value of point when the last command was executed.  */
@@ -282,7 +311,6 @@ Lisp_Object Qself_insert_command;
 Lisp_Object Qforward_char;
 Lisp_Object Qbackward_char;
 Lisp_Object Qundefined;
-Lisp_Object Qdigit_argument, Qnegative_argument;
 
 /* read_key_sequence stores here the command definition of the
    key sequence that it reads.  */
@@ -297,8 +325,9 @@ Lisp_Object Vkeyboard_translate_table;
 /* Keymap mapping ASCII function key sequences onto their preferred forms.  */
 extern Lisp_Object Vfunction_key_map;
 
-/* Keymap mapping ASCII function key sequences onto their preferred forms.  */
-Lisp_Object Vkey_translation_map;
+/* Another keymap that maps key sequences into key sequences.
+   This one takes precedence over ordinary definitions.  */
+extern Lisp_Object Vkey_translation_map;
 
 /* Non-nil means deactivate the mark at end of this command.  */
 Lisp_Object Vdeactivate_mark;
@@ -309,9 +338,14 @@ Lisp_Object Vlucid_menu_bar_dirty_flag;
 Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 
 /* Hooks to run before and after each command.  */
-Lisp_Object Qpre_command_hook, Qpost_command_hook;
-Lisp_Object Vpre_command_hook, Vpost_command_hook;
+Lisp_Object Qpre_command_hook, Vpre_command_hook;
+Lisp_Object Qpost_command_hook, Vpost_command_hook;
 Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
+/* Hook run after a command if there's no more input soon.  */
+Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
+
+/* Delay time in microseconds before running post-command-idle-hook.  */
+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.  */
@@ -385,20 +419,11 @@ static volatile struct input_event *kbd_store_ptr;
    dequeuing functions?  Such a flag could be screwed up by interrupts
    at inopportune times.  */
 
-/* If this flag is a frame, we check mouse_moved to see when the
+/* If this flag is non-nil, we check mouse_moved to see when the
    mouse moves, and motion events will appear in the input stream.
    Otherwise, mouse motion is ignored.  */
 static Lisp_Object do_mouse_tracking;
 
-#ifdef HAVE_MOUSE
-/* The window system handling code should set this if the mouse has
-   moved since the last call to the mouse_position_hook.  Calling that
-   hook should clear this.  Code assumes that if this is set, it can
-   call mouse_position_hook to get the promised position, so don't set
-   it unless you're prepared to substantiate the claim!  */
-int mouse_moved;
-#endif /* HAVE_MOUSE */
-
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
 Lisp_Object Qscroll_bar_movement;
@@ -410,6 +435,7 @@ Lisp_Object Qmake_frame_visible;
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
+Lisp_Object Qtimer_event;
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
@@ -442,9 +468,21 @@ extern Lisp_Object Qmenu_enable;
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
+EMACS_TIME timer_check ();
+
+extern char *x_get_keysym_name ();
 
 Lisp_Object Qpolling_period;
 
+/* List of absolute timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_list;
+
+/* List of idle time timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_idle_list;
+
+/* Incremented whenever a timer is run.  */
+int timers_run;
+
 extern Lisp_Object Vprint_level, Vprint_length;
 
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
@@ -458,7 +496,7 @@ int interrupt_input;
 /* Nonzero while interrupts are temporarily deferred during redisplay.  */
 int interrupts_deferred;
 
-/* nonzero means use ^S/^Q for flow control.  */
+/* Nonzero means use ^S/^Q for flow control.  */
 int flow_control;
 
 /* Allow m- file to inhibit use of FIONREAD.  */
@@ -474,11 +512,14 @@ int flow_control;
 #endif
 #endif
 
-/* If we support X Windows, turn on the code to poll periodically
+/* 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_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
+
+/* Non-nil enables Column Number mode.  */
+Lisp_Object Vcolumn_number_mode;
 \f
 /* Global variable declarations.  */
 
@@ -525,7 +566,7 @@ echo_prompt (str)
 
   current_kboard->echo_after_prompt = len;
 
-  echo ();
+  echo_now ();
 }
 
 /* Add C to the echo string, if echoing is going on.
@@ -564,7 +605,7 @@ echo_char (c)
        }
 
       if (current_kboard->echoptr == current_kboard->echobuf
-         && EQ (c, Vhelp_char))
+         && help_char_p (c))
        {
          strcpy (ptr, " (Type ? for further options)");
          ptr += strlen (ptr);
@@ -573,7 +614,7 @@ echo_char (c)
       *ptr = 0;
       current_kboard->echoptr = ptr;
 
-      echo ();
+      echo_now ();
     }
 }
 
@@ -598,13 +639,13 @@ echo_dash ()
   current_kboard->echoptr[0] = '-';
   current_kboard->echoptr[1] = 0;
 
-  echo ();
+  echo_now ();
 }
 
 /* Display the current echo string, and begin echoing if not already
    doing so.  */
 
-echo ()
+echo_now ()
 {
   if (!current_kboard->immediate_echo)
     {
@@ -637,6 +678,7 @@ cancel_echoing ()
   current_kboard->immediate_echo = 0;
   current_kboard->echoptr = current_kboard->echobuf;
   current_kboard->echo_after_prompt = -1;
+  ok_to_echo_at_next_pause = 0;
 }
 
 /* Return the length of the current echo string.  */
@@ -668,6 +710,15 @@ add_command_key (key)
 {
   int size = XVECTOR (this_command_keys)->size;
 
+  /* If reset-this-command-length was called recently, obey it now.
+     See the doc string of that function for an explanation of why.  */
+  if (before_command_restore_flag)
+    {
+      this_command_key_count = before_command_key_count_1;
+      echo_truncate (before_command_echo_length_1);
+      before_command_restore_flag = 0;
+    }
+
   if (this_command_key_count >= size)
     {
       Lisp_Object new_keys;
@@ -835,15 +886,15 @@ cmd_error (data)
   Vstandard_output = Qt;
   Vstandard_input = Qt;
   Vexecuting_macro = Qnil;
-  clear_prefix_arg ();
+  current_kboard->Vprefix_arg = Qnil;
   cancel_echoing ();
 
   /* Avoid unquittable loop if data contains a circular list.  */
   old_level = Vprint_level;
   old_length = Vprint_length;
-  XSETFASTINT(Vprint_level, 10);
-  XSETFASTINT(Vprint_length, 10);
-  cmd_error_internal (data, 0);
+  XSETFASTINT (Vprint_level, 10);
+  XSETFASTINT (Vprint_length, 10);
+  cmd_error_internal (data, NULL);
   Vprint_level = old_level;
   Vprint_length = old_length;
 
@@ -861,10 +912,7 @@ cmd_error_internal (data, context)
      Lisp_Object data;
      char *context;
 {
-  Lisp_Object errmsg, tail, errname, file_error;
   Lisp_Object stream;
-  struct gcpro gcpro1;
-  int i;
 
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
@@ -886,49 +934,7 @@ cmd_error_internal (data, context)
   if (context != 0)
     write_string_1 (context, -1, stream);
 
-  errname = Fcar (data);
-
-  if (EQ (errname, Qerror))
-    {
-      data = Fcdr (data);
-      if (!CONSP (data)) data = Qnil;
-      errmsg = Fcar (data);
-      file_error = Qnil;
-    }
-  else
-    {
-      errmsg = Fget (errname, Qerror_message);
-      file_error = Fmemq (Qfile_error,
-                         Fget (errname, Qerror_conditions));
-    }
-
-  /* Print an error message including the data items.
-     This is done by printing it into a scratch buffer
-     and then making a copy of the text in the buffer. */
-
-  if (!CONSP (data)) data = Qnil;
-  tail = Fcdr (data);
-  GCPRO1 (tail);
-
-  /* For file-error, make error message by concatenating
-     all the data items.  They are all strings.  */
-  if (!NILP (file_error) && !NILP (tail))
-    errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
-
-  if (STRINGP (errmsg))
-    Fprinc (errmsg, stream);
-  else
-    write_string_1 ("peculiar error", -1, stream);
-
-  for (i = 0; CONSP (tail); tail = Fcdr (tail), i++)
-    {
-      write_string_1 (i ? ", " : ": ", 2, stream);
-      if (!NILP (file_error))
-       Fprinc (Fcar (tail), stream);
-      else
-       Fprin1 (Fcar (tail), stream);
-    }
-  UNGCPRO;
+  print_error_message (data, stream);
 
   /* 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.  */
@@ -1036,7 +1042,7 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 
 Lisp_Object Fcommand_execute ();
 static int read_key_sequence ();
-static void safe_run_hooks ();
+void safe_run_hooks ();
 
 Lisp_Object
 command_loop_1 ()
@@ -1054,6 +1060,7 @@ command_loop_1 ()
   int was_locked = single_kboard;
 #endif
 
+  current_kboard->Vprefix_arg = Qnil;
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
   cancel_echoing ();
@@ -1066,14 +1073,22 @@ command_loop_1 ()
      throw to top level.  */
   /* Note that the value cell will never directly contain nil
      if the symbol is a local variable.  */
-  if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
     safe_run_hooks (Qpost_command_hook);
 
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
 
+  if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+    {
+      if (NILP (Vunread_command_events)
+         && NILP (Vexecuting_macro)
+         && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+       safe_run_hooks (Qpost_command_idle_hook);
+    }
+
   /* Do this after running Vpost_command_hook, for consistency.  */
-  last_command = this_command;
+  current_kboard->Vlast_command = this_command;
 
   while (1)
     {
@@ -1094,7 +1109,8 @@ command_loop_1 ()
       /* If minibuffer on and echo area in use,
         wait 2 sec and redraw minibuffer.  */
 
-      if (minibuf_level && echo_area_glyphs)
+      if (minibuf_level && echo_area_glyphs
+         && EQ (minibuf_window, echo_area_window))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
@@ -1103,8 +1119,10 @@ command_loop_1 ()
          Fsit_for (make_number (2), Qnil, Qnil);
          unbind_to (count, Qnil);
 
-         echo_area_glyphs = 0;
-         no_direct = 1;
+         /* Clear the echo area.  */
+         message2 (0);
+
+         /* If a C-g came in before, treat it as input now.  */
          if (!NILP (Vquit_flag))
            {
              Vquit_flag = Qnil;
@@ -1134,6 +1152,11 @@ command_loop_1 ()
          && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
        call0 (Qrecompute_lucid_menubar);
 
+      before_command_key_count = this_command_key_count;
+      before_command_echo_length = echo_length ();
+
+      this_command = Qnil;
+
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
                             Qnil, 0, 1);
@@ -1190,22 +1213,12 @@ command_loop_1 ()
       last_point_position = PT;
       XSETBUFFER (last_point_position_buffer, prev_buffer);
 
-      /* If we're building a prefix argument, override minus and digits.  */
-      if (current_kboard->prefix_partial && i == 1 && NATNUMP (keybuf[0]))
-       {
-         if (XFASTINT (keybuf[0]) == '-'
-             && NILP (current_kboard->prefix_value))
-           cmd = Qnegative_argument;
-         else if (XFASTINT (keybuf[0]) >= '0' && XFASTINT (keybuf[0]) <= '9')
-           cmd = Qdigit_argument;
-       }
-
       /* Execute the command.  */
 
       this_command = cmd;
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
-      if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+      if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpre_command_hook);
 
       if (NILP (this_command))
@@ -1214,21 +1227,17 @@ command_loop_1 ()
          bitch_at_user ();
          current_kboard->defining_kbd_macro = Qnil;
          update_mode_lines = 1;
-         clear_prefix_arg ();
+         current_kboard->Vprefix_arg = Qnil;
        }
       else
        {
-         current_prefix_partial = current_kboard->prefix_partial;
-         if (current_kboard->prefix_partial)
-           finalize_prefix_arg ();
-
-         if (NILP (Vprefix_arg) && ! no_direct)
+         if (NILP (current_kboard->Vprefix_arg) && ! no_direct)
            {
              /* Recognize some common commands in common situations and
                 do them directly.  */
              if (EQ (this_command, Qforward_char) && PT < ZV)
                {
-                  struct Lisp_Vector *dp
+                  struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
                  lose = FETCH_CHAR (PT);
                  SET_PT (PT + 1);
@@ -1245,13 +1254,14 @@ command_loop_1 ()
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
+                     && NILP (Vcolumn_number_mode)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
                }
              else if (EQ (this_command, Qbackward_char) && PT > BEGV)
                {
-                  struct Lisp_Vector *dp
+                  struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
                  SET_PT (PT - 1);
                  lose = FETCH_CHAR (PT);
@@ -1268,6 +1278,7 @@ command_loop_1 ()
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
+                     && NILP (Vcolumn_number_mode)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (-1);
                  goto directly_done;
@@ -1297,6 +1308,7 @@ command_loop_1 ()
                          || windows_or_buffers_changed
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
+                         || !NILP (Vcolumn_number_mode)
                          || !NILP (Vexecuting_macro));
                  value = internal_self_insert (c, 0);
                  if (value)
@@ -1307,7 +1319,7 @@ command_loop_1 ()
                  if (!lose
                      && (PT == ZV || FETCH_CHAR (PT) == '\n'))
                    {
-                     struct Lisp_Vector *dp
+                     struct Lisp_Char_Table *dp
                        = window_display_table (XWINDOW (selected_window));
                      int lose = c;
 
@@ -1345,33 +1357,45 @@ command_loop_1 ()
          /* Here for a command that isn't executed directly */
 
          nonundocount = 0;
-         if (NILP (Vprefix_arg))
+         if (NILP (current_kboard->Vprefix_arg))
            Fundo_boundary ();
-         Fcommand_execute (this_command, Qnil);
+         Fcommand_execute (this_command, Qnil, Qnil, Qnil);
 
        }
     directly_done: ;
 
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
-      if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpost_command_hook);
 
       if (!NILP (Vdeferred_action_list))
        safe_run_hooks (Qdeferred_action_function);
 
+      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+       {
+         if (NILP (Vunread_command_events)
+             && NILP (Vexecuting_macro)
+             && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+           safe_run_hooks (Qpost_command_idle_hook);
+       }
+
       /* If there is a prefix argument,
-        1) We don't want last_command to be ``universal-argument''
-        (that would be dumb), so don't set last_command,
+        1) We don't want Vlast_command to be ``universal-argument''
+        (that would be dumb), so don't set Vlast_command,
         2) we want to leave echoing on so that the prefix will be
         echoed as part of this key sequence, so don't call
         cancel_echoing, and
         3) we want to leave this_command_key_count non-zero, so that
         read_char will realize that it is re-reading a character, and
-        not echo it a second time.  */
-      if (NILP (Vprefix_arg) && !current_kboard->prefix_partial)
+        not echo it a second time.
+
+        If the command didn't actually create a prefix arg,
+        but is merely a frame event that is transparent to prefix args,
+        then the above doesn't apply.  */
+      if (NILP (current_kboard->Vprefix_arg) || CONSP (last_command_char))
        {
-         last_command = this_command;
+         current_kboard->Vlast_command = this_command;
          cancel_echoing ();
          this_command_key_count = 0;
        }
@@ -1390,8 +1414,8 @@ command_loop_1 ()
     finalize:
       /* Install chars successfully executed in kbd macro.  */
 
-      if (!NILP (current_kboard->defining_kbd_macro) && NILP (Vprefix_arg)
-         && !current_kboard->prefix_partial)
+      if (!NILP (current_kboard->defining_kbd_macro)
+         && NILP (current_kboard->Vprefix_arg))
        finalize_kbd_macro_chars ();
 
 #ifdef MULTI_KBOARD
@@ -1423,7 +1447,7 @@ safe_run_hooks_error (data)
    to be nil.  Also inhibit quits, so that C-g won't cause the hook
    to mysteriously evaporate.  */
 
-static void
+void
 safe_run_hooks (hook)
      Lisp_Object hook;
 {
@@ -1431,7 +1455,7 @@ safe_run_hooks (hook)
   int count = specpdl_ptr - specpdl;
   specbind (Qinhibit_quit, hook);
 
-  internal_condition_case (safe_run_hooks_1, Qerror, safe_run_hooks_error);
+  internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
 
   unbind_to (count, Qnil);
 }
@@ -1454,11 +1478,15 @@ SIGTYPE
 input_poll_signal (signalnum)  /* If we don't have an argument, */
      int signalnum;            /* some compilers complain in signal calls. */
 {
+  /* This causes the call to start_polling at the end
+     to do its job.  It also arranges for a quit or error
+     from within read_avail_input to resume polling.  */
+  poll_suppress_count++;
   if (interrupt_input_blocked == 0
       && !waiting_for_input)
     read_avail_input (0);
-  signal (SIGALRM, input_poll_signal);
-  alarm (polling_period);
+  /* Turn on the SIGALRM handler and request another alarm.  */
+  start_polling ();
 }
 
 #endif
@@ -1631,14 +1659,27 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   int key_already_recorded = 0;
+  Lisp_Object tem, save;
   Lisp_Object also_record;
   also_record = Qnil;
 
+  before_command_key_count = this_command_key_count;
+  before_command_echo_length = echo_length ();
+
+ retry:
+
   if (CONSP (Vunread_command_events))
     {
       c = XCONS (Vunread_command_events)->car;
       Vunread_command_events = XCONS (Vunread_command_events)->cdr;
 
+      /* Undo what read_char_x_menu_prompt did when it unread
+        additional keys returned by Fx_popup_menu.  */
+      if (CONSP (c)
+         && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+         && NILP (XCONS (c)->cdr))
+       c = XCONS (c)->car;
+
       if (this_command_key_count == 0)
        goto reread_first;
       else
@@ -1656,6 +1697,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        goto reread;
     }
 
+  /* If there is no function key translated before
+     reset-this-command-lengths takes effect, forget about it.  */
+  before_command_restore_flag = 0;
+
   if (!NILP (Vexecuting_macro))
     {
 #ifdef MULTI_FRAME
@@ -1707,7 +1752,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
   if (echo_area_glyphs && *echo_area_glyphs
-      && echo_area_glyphs != current_kboard->echobuf)
+      && echo_area_glyphs != current_kboard->echobuf
+      && ok_to_echo_at_next_pause != echo_area_glyphs)
     cancel_echoing ();
   else
     /* If already echoing, continue.  */
@@ -1775,6 +1821,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto non_reread;
     }
 
+  timer_start_idle ();
+
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
@@ -1782,7 +1830,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && this_command_key_count > 0
       && ! noninteractive
       && echo_keystrokes > 0
-      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
+      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
+         || ok_to_echo_at_next_pause == echo_area_glyphs))
     {
       Lisp_Object tem0;
 
@@ -1790,7 +1839,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
       if (EVENT_HAS_PARAMETERS (prev_event))
-       echo ();
+       echo_now ();
       else
        {
          save_getcjmp (save_jump);
@@ -1798,7 +1847,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          tem0 = sit_for (echo_keystrokes, 0, 1, 1);
          restore_getcjmp (save_jump);
          if (EQ (tem0, Qt))
-           echo ();
+           echo_now ();
        }
     }
 
@@ -1853,11 +1902,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
-         int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
 
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (delay, 0, 1, 1);
+         tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+                         0, 1, 1);
          restore_getcjmp (save_jump);
 
          if (EQ (tem0, Qt))
@@ -1889,7 +1938,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            = XCONS (current_kboard->kbd_queue)->cdr;
          if (NILP (current_kboard->kbd_queue))
            current_kboard->kbd_queue_has_data = 0;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
 #ifdef MULTI_FRAME
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
@@ -1977,6 +2026,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
+  /* Now that we have read an event, Emacs is not idle--
+     unless the event was a timer event.  */
+  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+    timer_stop_idle ();
+
   start_polling ();
 
   if (NILP (c))
@@ -1998,6 +2052,28 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (key_already_recorded)
     return c;
 
+  /* Process special events within read_char
+     and loop around to read another event.  */
+  save = Vquit_flag;
+  Vquit_flag = Qnil;
+  tem = get_keyelt (access_keymap (get_keymap_1 (Vspecial_event_map, 0, 0),
+                                  c, 0, 0), 1);
+  Vquit_flag = save;
+
+  if (!NILP (tem))
+    {
+      int was_locked = single_kboard;
+
+      last_input_char = c;
+      Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
+
+      /* Resume allowing input from any kboard, if that was true before.  */
+      if (!was_locked)
+       any_kboard_state ();
+
+      goto retry;
+    }
+
   /* Wipe the echo area.  */
   echo_area_glyphs = 0;
 
@@ -2011,6 +2087,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (STRINGP (Vkeyboard_translate_table)
          && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
        XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
+      else if ((VECTORP (Vkeyboard_translate_table)
+               && XVECTOR (Vkeyboard_translate_table)->size > XFASTINT (c))
+              || CHAR_TABLE_P (Vkeyboard_translate_table))
+       {
+         Lisp_Object d;
+         d = Faref (Vkeyboard_translate_table, c);
+         /* nil in keyboard-translate-table means no translation.  */
+         if (!NILP (d))
+           c = d;
+       }
     }
 
   /* If this event is a mouse click in the menu bar,
@@ -2043,6 +2129,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  from_macro:
  reread_first:
+  before_command_key_count = this_command_key_count;
+  before_command_echo_length = echo_length ();
 
   /* Don't echo mouse motion events.  */
   if (echo_keystrokes
@@ -2052,6 +2140,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       echo_char (c);
       if (! NILP (also_record))
        echo_char (also_record);
+      /* Once we reread a character, echoing can happen
+        the next time we pause to read a new one.  */
+      ok_to_echo_at_next_pause = echo_area_glyphs;
     }
 
   /* Record this character as part of the current key.  */
@@ -2065,7 +2156,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   num_input_chars++;
 
   /* Process the help character specially if enabled */
-  if (EQ (c, Vhelp_char) && !NILP (Vhelp_form))
+  if (!NILP (Vhelp_form) && help_char_p (c))
     {
       Lisp_Object tem0;
       count = specpdl_ptr - specpdl;
@@ -2097,6 +2188,22 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   return c;
 }
 
+/* Return 1 if should recognize C as "the help character".  */
+
+int
+help_char_p (c)
+     Lisp_Object c;
+{
+  Lisp_Object tail;
+
+  if (EQ (c, Vhelp_char))
+    return 1;
+  for (tail = Vhelp_event_list; CONSP (tail); tail = XCONS (tail)->cdr)
+    if (EQ (c, XCONS (tail)->car))
+      return 1;
+  return 0;
+}
+
 /* Record the input event C in various ways.  */
 
 static void
@@ -2118,7 +2225,7 @@ record_char (c)
          if (XUINT (c) < 0x100)
            putc (XINT (c), dribble);
          else
-           fprintf (dribble, " 0x%x", XUINT (c));
+           fprintf (dribble, " 0x%x", (int) XUINT (c));
        }
       else
        {
@@ -2191,10 +2298,10 @@ tracking_off (old_value)
         input has been processed.  If the only input available was
         the sort that we have just disabled, then we need to call
         redisplay.  */
-      if (!readable_events ())
+      if (!readable_events (1))
        {
          redisplay_preserve_echo_area ();
-         get_input_pending (&input_pending);
+         get_input_pending (&input_pending, 1);
        }
     }
 }
@@ -2212,29 +2319,46 @@ Normally, mouse motion is ignored.")
 
   record_unwind_protect (tracking_off, do_mouse_tracking);
 
-  XSETFRAME (do_mouse_tracking, selected_frame);
+  do_mouse_tracking = Qt;
 
   val = Fprogn (args);
   return unbind_to (count, val);
 }
 
+/* If mouse has moved on some frame, return one of those frames.
+   Return 0 otherwise.  */
+
+static FRAME_PTR
+some_mouse_moved ()
+{
+  Lisp_Object tail, frame;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      if (XFRAME (frame)->mouse_moved)
+       return XFRAME (frame);
+    }
+
+  return 0;
+}
+
 #endif /* HAVE_MOUSE */
 \f
 /* Low level keyboard/mouse input.
    kbd_buffer_store_event places events in kbd_buffer, and
-   kbd_buffer_get_event retrieves them.
-   mouse_moved indicates when the mouse has moved again, and
-   *mouse_position_hook provides the mouse position.  */
+   kbd_buffer_get_event retrieves them.  */
 
 /* 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 ()
+readable_events (do_timers_now)
+     int do_timers_now;
 {
+  timer_check (do_timers_now);
   if (kbd_fetch_ptr != kbd_store_ptr)
     return 1;
 #ifdef HAVE_MOUSE
-  if (FRAMEP (do_mouse_tracking) && mouse_moved)
+  if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
 #endif
   if (single_kboard)
@@ -2354,6 +2478,12 @@ kbd_buffer_store_event (event)
          return;
        }
     }
+  /* Don't insert two buffer_switch_event's in a row.
+     Just ignore the second one.  */
+  else if (event->kind == buffer_switch_event
+          && kbd_fetch_ptr != kbd_store_ptr
+          && kbd_store_ptr->kind == buffer_switch_event)
+    return;
 
   if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
     kbd_store_ptr = kbd_buffer;
@@ -2404,6 +2534,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 {
   register int c;
   Lisp_Object obj;
+  EMACS_TIME next_timer_delay;
 
   if (noninteractive)
     {
@@ -2419,7 +2550,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
 #ifdef HAVE_MOUSE
-      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
 #endif
 
@@ -2441,7 +2572,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
 #ifdef HAVE_MOUSE
-      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
 #endif
       {
@@ -2493,6 +2624,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
             and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2504,15 +2636,20 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       else if (event->kind == selection_clear_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_clear (event);
+         struct input_event copy;
+
+         /* Remove it from the buffer before processing it.  */
+         copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
          abort ();
 #endif
        }
-#ifdef HAVE_X11
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
       else if (event->kind == delete_window_event)
        {
          /* Make an event (delete-frame (FRAME)).  */
@@ -2541,6 +2678,14 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
+#ifdef USE_X_TOOLKIT
+      else if (event->kind == menu_bar_activate_event)
+       {
+         kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_activate_menubar (XFRAME (event->frame_or_window));
+       }
+#endif
       /* 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.
@@ -2580,7 +2725,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          if (NILP (obj))
            {
              obj = make_lispy_event (event);
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
              /* If this was a menu selection, then set the flag to inhibit
                 writing to last_nonmenu_event.  Don't do this if the event
                 we're returning is (menu-bar), though; that indicates the
@@ -2602,9 +2747,9 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
     }
 #ifdef HAVE_MOUSE
   /* Try generating a mouse motion event.  */
-  else if (FRAMEP (do_mouse_tracking) && mouse_moved)
+  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     {
-      FRAME_PTR f = XFRAME (do_mouse_tracking);
+      FRAME_PTR f = some_mouse_moved ();
       Lisp_Object bar_window;
       enum scroll_bar_part part;
       Lisp_Object x, y;
@@ -2649,7 +2794,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        something for us to read!  */
     abort ();
 
-  input_pending = readable_events ();
+  input_pending = readable_events (0);
 
 #ifdef MULTI_FRAME
   Vlast_event_frame = internal_last_event_frame;
@@ -2662,8 +2807,11 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
    then return, without reading any user-visible events.  */
 
 void
-swallow_events ()
+swallow_events (do_display)
+     int do_display;
 {
+  int old_timers_run;
+
   while (kbd_fetch_ptr != kbd_store_ptr)
     {
       struct input_event *event;
@@ -2680,8 +2828,13 @@ swallow_events ()
        {
 #ifdef HAVE_X11
          struct input_event copy;
+
+         /* Remove it from the buffer before processing it,
+            since otherwise swallow_events called recursively could see it
+            and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2693,24 +2846,321 @@ swallow_events ()
       else if (event->kind == selection_clear_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_clear (event);
+         struct input_event copy;
+
+         /* Remove it from the buffer before processing it,  */
+         copy = *event;
+
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
          abort ();
 #endif
        }
+      else if (event->kind == timer_event)
+       {
+         Lisp_Object tem, lisp_event;
+         int was_locked = single_kboard;
+
+         tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+         tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+                           1);
+         lisp_event = Fcons (Qtimer_event,
+                             Fcons (Fcdr (event->frame_or_window), Qnil));
+         kbd_fetch_ptr = event + 1;
+         if (kbd_fetch_ptr == kbd_store_ptr)
+           input_pending = 0;
+         Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event), Qt);
+         timers_run++;
+         if (do_display)
+           redisplay_preserve_echo_area ();
+
+         /* Resume allowing input from any kboard, if that was true before.  */
+         if (!was_locked)
+           any_kboard_state ();
+       }
       else
        break;
     }
 
-  get_input_pending (&input_pending);
+  old_timers_run = timers_run;
+  get_input_pending (&input_pending, 1);
+
+  if (timers_run != old_timers_run && do_display)
+    redisplay_preserve_echo_area ();
+}
+\f
+static EMACS_TIME timer_idleness_start_time;
+
+/* Record the start of when Emacs is idle,
+   for the sake of running idle-time timers.  */
+
+timer_start_idle ()
+{
+  Lisp_Object timers;
+
+  /* If we are already in the idle state, do nothing.  */
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    return;
+
+  EMACS_GET_TIME (timer_idleness_start_time);
+
+  /* Mark all idle-time timers as once again candidates for running.  */
+  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+    {
+      Lisp_Object timer;
+
+      timer = XCONS (timers)->car;
+
+      if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+       continue;
+      XVECTOR (timer)->contents[0] = Qnil;
+    }
+}
+
+/* Record that Emacs is no longer idle, so stop running idle-time timers.  */
+
+timer_stop_idle ()
+{
+  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+}
+
+/* This is only for debugging.  */
+struct input_event last_timer_event;
+
+/* Check whether a timer has fired.  To prevent larger problems we simply
+   disregard elements that are not proper timers.  Do not make a circular
+   timer list for the time being.
+
+   Returns the number of seconds to wait until the next timer fires.  If a
+   timer is triggering now, return zero seconds.
+   If no timer is active, return -1 seconds.
+
+   If a timer is ripe now, either queue a timer-event,
+   or call the timer's handler function here if DO_IT_NOW is nonzero.  */
+
+EMACS_TIME
+timer_check (do_it_now)
+     int do_it_now;
+{
+  EMACS_TIME nexttime;
+  EMACS_TIME now, idleness_now;
+  Lisp_Object timers, idle_timers, chosen_timer;
+  /* Nonzero if we generate some events.  */
+  int events_generated = 0;
+  struct gcpro gcpro1, gcpro2, gcpro3;
+
+  EMACS_SET_SECS (nexttime, -1);
+  EMACS_SET_USECS (nexttime, -1);
+
+  /* Always consider the ordinary timers.  */
+  timers = Vtimer_list;
+  /* Consider the idle timers only if Emacs is idle.  */
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    idle_timers = Vtimer_idle_list;
+  else
+    idle_timers = Qnil;
+  chosen_timer = Qnil;
+  GCPRO3 (timers, idle_timers, chosen_timer);
+
+  if (CONSP (timers) || CONSP (idle_timers))
+    {
+      EMACS_GET_TIME (now);
+      if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+       EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+    }
+
+  while (CONSP (timers) || CONSP (idle_timers))
+    {
+      int triggertime = EMACS_SECS (now);
+      Lisp_Object *vector;
+      Lisp_Object timer, idle_timer;
+      EMACS_TIME timer_time, idle_timer_time;
+      EMACS_TIME difference, timer_difference, idle_timer_difference;
+
+      /* Skip past invalid timers and timers already handled.  */
+      if (!NILP (timers))
+       {
+         timer = XCONS (timers)->car;
+         if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+           {
+             timers = XCONS (timers)->cdr;
+             continue;
+           }
+         vector = XVECTOR (timer)->contents;
+
+         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+             || !INTEGERP (vector[3])
+             || ! NILP (vector[0]))
+           {
+             timers = XCONS (timers)->cdr;
+             continue;
+           }
+       }
+      if (!NILP (idle_timers))
+       {
+         timer = XCONS (idle_timers)->car;
+         if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+           {
+             idle_timers = XCONS (idle_timers)->cdr;
+             continue;
+           }
+         vector = XVECTOR (timer)->contents;
+
+         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+             || !INTEGERP (vector[3])
+             || ! NILP (vector[0]))
+           {
+             idle_timers = XCONS (idle_timers)->cdr;
+             continue;
+           }
+       }
+
+      /* Set TIMER, TIMER_TIME and TIMER_DIFFERENCE
+        based on the next ordinary timer.
+        TIMER_DIFFERENCE is the distance in time from NOW to when
+        this timer becomes ripe (negative if it's already ripe).  */
+      if (!NILP (timers))
+       {
+         timer = XCONS (timers)->car;
+         vector = XVECTOR (timer)->contents;
+         EMACS_SET_SECS (timer_time,
+                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
+         EMACS_SET_USECS (timer_time, XINT (vector[3]));
+         EMACS_SUB_TIME (timer_difference, timer_time, now);
+       }
+
+      /* Set IDLE_TIMER, IDLE_TIMER_TIME and IDLE_TIMER_DIFFERENCE
+        based on the next idle timer.  */
+      if (!NILP (idle_timers))
+       {
+         idle_timer = XCONS (idle_timers)->car;
+         vector = XVECTOR (idle_timer)->contents;
+         EMACS_SET_SECS (idle_timer_time,
+                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
+         EMACS_SET_USECS (idle_timer_time, XINT (vector[3]));
+         EMACS_SUB_TIME (idle_timer_difference, idle_timer_time, idleness_now);
+       }
+
+      /* Decide which timer is the next timer,
+        and set CHOSEN_TIMER, VECTOR and DIFFERENCE accordingly.
+        Also step down the list where we found that timer.  */
+
+      if (! NILP (timers) && ! NILP (idle_timers))
+       {
+         EMACS_TIME temp;
+         EMACS_SUB_TIME (temp, timer_difference, idle_timer_difference);
+         if (EMACS_TIME_NEG_P (temp))
+           {
+             chosen_timer = timer;
+             timers = XCONS (timers)->cdr;
+             difference = timer_difference;
+           }
+         else
+           {
+             chosen_timer = idle_timer;
+             idle_timers = XCONS (idle_timers)->cdr;
+             difference = idle_timer_difference;
+           }
+       }
+      else if (! NILP (timers))
+       {
+         chosen_timer = timer;
+         timers = XCONS (timers)->cdr;
+         difference = timer_difference;
+       }
+      else
+       {
+         chosen_timer = idle_timer;
+         idle_timers = XCONS (idle_timers)->cdr;
+         difference = idle_timer_difference;
+       }
+      vector = XVECTOR (chosen_timer)->contents;
+       
+      /* If timer is rupe, run it if it hasn't been run.  */
+      if (EMACS_TIME_NEG_P (difference)
+         || (EMACS_SECS (difference) == 0
+             && EMACS_USECS (difference) == 0))
+       {
+         if (NILP (vector[0]))
+           {
+             /* Mark the timer as triggered to prevent problems if the lisp
+                code fails to reschedule it right.  */
+             vector[0] = Qt;
+
+             /* Run the timer or queue a timer event.  */
+             if (do_it_now)
+               {
+                 Lisp_Object tem, event;
+                 int was_locked = single_kboard;
+
+                 tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+                 tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+                                   1);
+                 event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
+                 Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
+                 timers_run++;
+
+                 /* Resume allowing input from any kboard, if that was true before.  */
+                 if (!was_locked)
+                   any_kboard_state ();
+
+                 /* Since we have handled the event,
+                    we don't need to tell the caller to wake up and do it.  */
+               }
+             else
+               {
+                 /* Generate a timer event so the caller will handle it.  */
+                 struct input_event event;
+
+                 event.kind = timer_event;
+                 event.modifiers = 0;
+                 event.x = event.y = Qnil;
+                 event.timestamp = triggertime;
+                 /* Store the timer in the frame slot.  */
+                 event.frame_or_window
+                   = Fcons (Fselected_frame (), chosen_timer);
+                 kbd_buffer_store_event (&event);
+
+                 last_timer_event = event;
+
+                 /* Tell caller to handle this event right away.  */
+                 events_generated = 1;
+                 EMACS_SET_SECS (nexttime, 0);
+                 EMACS_SET_USECS (nexttime, 0);
+
+                 /* Don't queue more than one event at once.
+                    When Emacs is ready for another, it will
+                    queue the next one.  */
+                 UNGCPRO;
+                 return nexttime;
+               }
+           }
+       }
+      else
+       /* When we encounter a timer that is still waiting,
+          return the amount of time to wait before it is ripe.  */
+       {
+         UNGCPRO;
+         /* But if we generated an event,
+            tell the caller to handle it now.  */
+         if (events_generated)
+           return nexttime;
+         return difference;
+       }
+    }
+
+  /* No timers are pending in the future.  */
+  /* Return 0 if we generated an event, and -1 if not.  */
+  UNGCPRO;
+  return nexttime;
 }
 \f
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
-static Lisp_Object system_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
 
@@ -2806,6 +3256,171 @@ static char *lispy_accent_keys[] =
   "dead-abovedot",
 };
 
+#ifdef HAVE_NTGUI
+#define FUNCTION_KEY_OFFSET 0x0
+
+char *lispy_function_keys[] =
+  {
+    0,                /* 0                      */
+    
+    0,                /* VK_LBUTTON        0x01 */
+    0,                /* VK_RBUTTON        0x02 */
+    "cancel",         /* VK_CANCEL         0x03 */
+    0,                /* VK_MBUTTON        0x04 */
+    
+    0, 0, 0,          /*    0x05 .. 0x07        */
+    
+    "backspace",      /* VK_BACK           0x08 */
+    "tab",            /* VK_TAB            0x09 */
+    
+    0, 0,             /*    0x0A .. 0x0B        */
+    
+    "clear",          /* VK_CLEAR          0x0C */
+    "return",         /* VK_RETURN         0x0D */
+    
+    0, 0,             /*    0x0E .. 0x0F        */
+  
+    "shift",          /* VK_SHIFT          0x10 */
+    "control",        /* VK_CONTROL        0x11 */
+    "menu",           /* VK_MENU           0x12 */
+    "pause",          /* VK_PAUSE          0x13 */
+    "capital",        /* VK_CAPITAL        0x14 */
+    
+    0, 0, 0, 0, 0, 0, /*    0x15 .. 0x1A        */
+    
+    0,                /* VK_ESCAPE         0x1B */
+    
+    0, 0, 0, 0,       /*    0x1C .. 0x1F        */
+    
+    0,                /* VK_SPACE          0x20 */
+    "prior",          /* VK_PRIOR          0x21 */
+    "next",           /* VK_NEXT           0x22 */
+    "end",            /* VK_END            0x23 */
+    "home",           /* VK_HOME           0x24 */
+    "left",           /* VK_LEFT           0x25 */
+    "up",             /* VK_UP             0x26 */
+    "right",          /* VK_RIGHT          0x27 */
+    "down",           /* VK_DOWN           0x28 */
+    "select",         /* VK_SELECT         0x29 */
+    "print",          /* VK_PRINT          0x2A */
+    "execute",        /* VK_EXECUTE        0x2B */
+    "snapshot",       /* VK_SNAPSHOT       0x2C */
+    "insert",         /* VK_INSERT         0x2D */
+    "delete",         /* VK_DELETE         0x2E */
+    "help",           /* VK_HELP           0x2F */
+  
+    /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    
+    0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40       */
+    
+    /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0,
+    
+    "lwindow",       /* VK_LWIN           0x5B */
+    "rwindow",       /* VK_RWIN           0x5C */
+    "apps",          /* VK_APPS           0x5D */
+    
+    0, 0,            /*    0x5E .. 0x5F        */
+    
+    "kp-0",          /* VK_NUMPAD0        0x60 */
+    "kp-1",          /* VK_NUMPAD1        0x61 */
+    "kp-2",          /* VK_NUMPAD2        0x62 */
+    "kp-3",          /* VK_NUMPAD3        0x63 */
+    "kp-4",          /* VK_NUMPAD4        0x64 */
+    "kp-5",          /* VK_NUMPAD5        0x65 */
+    "kp-6",          /* VK_NUMPAD6        0x66 */
+    "kp-7",          /* VK_NUMPAD7        0x67 */
+    "kp-8",          /* VK_NUMPAD8        0x68 */
+    "kp-9",          /* VK_NUMPAD9        0x69 */
+    "kp-multiply",   /* VK_MULTIPLY       0x6A */
+    "kp-add",        /* VK_ADD            0x6B */
+    "kp-separator",  /* VK_SEPARATOR      0x6C */
+    "kp-subtract",   /* VK_SUBTRACT       0x6D */
+    "kp-decimal",    /* VK_DECIMAL        0x6E */
+    "kp-divide",     /* VK_DIVIDE         0x6F */
+    "f1",            /* VK_F1             0x70 */
+    "f2",            /* VK_F2             0x71 */
+    "f3",            /* VK_F3             0x72 */
+    "f4",            /* VK_F4             0x73 */
+    "f5",            /* VK_F5             0x74 */
+    "f6",            /* VK_F6             0x75 */
+    "f7",            /* VK_F7             0x76 */
+    "f8",            /* VK_F8             0x77 */
+    "f9",            /* VK_F9             0x78 */
+    "f10",           /* VK_F10            0x79 */
+    "f11",           /* VK_F11            0x7A */
+    "f12",           /* VK_F12            0x7B */
+    "f13",           /* VK_F13            0x7C */
+    "f14",           /* VK_F14            0x7D */
+    "f15",           /* VK_F15            0x7E */
+    "f16",           /* VK_F16            0x7F */
+    "f17",           /* VK_F17            0x80 */
+    "f18",           /* VK_F18            0x81 */
+    "f19",           /* VK_F19            0x82 */
+    "f20",           /* VK_F20            0x83 */
+    "f21",           /* VK_F21            0x84 */
+    "f22",           /* VK_F22            0x85 */
+    "f23",           /* VK_F23            0x86 */
+    "f24",           /* VK_F24            0x87 */
+    
+    0, 0, 0, 0,      /*    0x88 .. 0x8B        */
+    0, 0, 0, 0,      /*    0x8C .. 0x8F        */
+    
+    "kp-numlock",    /* VK_NUMLOCK        0x90 */
+    "scroll",        /* VK_SCROLL         0x91 */
+    
+    "kp-space",             /* VK_NUMPAD_CLEAR   0x92 */
+    "kp-enter",             /* VK_NUMPAD_ENTER   0x93 */
+    "kp-prior",             /* VK_NUMPAD_PRIOR   0x94 */
+    "kp-next",      /* VK_NUMPAD_NEXT    0x95 */
+    "kp-end",       /* VK_NUMPAD_END     0x96 */
+    "kp-home",      /* VK_NUMPAD_HOME    0x97 */
+    "kp-left",      /* VK_NUMPAD_LEFT    0x98 */
+    "kp-up",        /* VK_NUMPAD_UP      0x99 */
+    "kp-right",             /* VK_NUMPAD_RIGHT   0x9A */
+    "kp-down",      /* VK_NUMPAD_DOWN    0x9B */
+    "kp-insert",     /* VK_NUMPAD_INSERT  0x9C */
+    "kp-delete",     /* VK_NUMPAD_DELETE  0x9D */
+
+    0, 0,           /*    0x9E .. 0x9F        */
+
+    /*
+     * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
+     * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+     * No other API or message will distinguish left and right keys this way.
+     */
+    /* 0xA0 .. 0xEF */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    
+    /* 0xF0 .. 0xF5 */
+    
+    0, 0, 0, 0, 0, 0,
+    
+    "attn",          /* VK_ATTN           0xF6 */
+    "crsel",         /* VK_CRSEL          0xF7 */
+    "exsel",         /* VK_EXSEL          0xF8 */
+    "ereof",         /* VK_EREOF          0xF9 */
+    "play",          /* VK_PLAY           0xFA */
+    "zoom",          /* VK_ZOOM           0xFB */
+    "noname",        /* VK_NONAME         0xFC */
+    "pa1",           /* VK_PA1            0xFD */
+    "oem_clear",     /* VK_OEM_CLEAR      0xFE */
+  };
+
+#else
+
+#define FUNCTION_KEY_OFFSET 0xff00
+
 /* You'll notice that this table is arranged to be conveniently
    indexed by X Windows keysym values.  */
 static char *lispy_function_keys[] =
@@ -2902,6 +3517,8 @@ static char *lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0, "delete"
     };
 
+#endif /* HAVE_NTGUI */
+
 static char *lispy_mouse_names[] =
 {
   "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
@@ -3002,16 +3619,17 @@ make_lispy_event (event)
        {
          /* We need to use an alist rather than a vector as the cache
             since we can't make a vector long enuf.  */
-         if (NILP (system_key_syms))
-           system_key_syms = Fcons (Qnil, Qnil);
-         return modify_event_symbol (event->code & 0xffffff,
+         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, &system_key_syms, 0xffffff);
+                                     0, &current_kboard->system_key_syms,
+                                     (unsigned)-1);
        }
 
-      return modify_event_symbol (event->code - 0xff00,
+      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
                                  event->modifiers,
                                  Qfunction_key, Qnil,
                                  lispy_function_keys, &func_key_syms,
@@ -3019,6 +3637,9 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
+    case timer_event:
+      return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+
 #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.  */
@@ -3049,7 +3670,7 @@ make_lispy_event (event)
              return Qnil;
 
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                                  &column, &row, 0, 1);
+                                  &column, &row, NULL, 1);
 
 #ifndef USE_X_TOOLKIT
            /* In the non-toolkit version, clicks on the menu bar
@@ -3059,17 +3680,20 @@ make_lispy_event (event)
               (In the toolkit version, the toolkit handles the menu bar
               and Emacs doesn't know about it until after the user
               makes a selection.)  */
-           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
+           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
+               && (event->modifiers & down_modifier))
              {
                Lisp_Object items, item;
                int hpos;
                int i;
 
+#if 0
                /* Activate the menu bar on the down event.  If the
                   up event comes in before the menu code can deal with it,
                   just ignore it.  */
                if (! (event->modifiers & down_modifier))
                  return Qnil;
+#endif
 
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
@@ -3261,7 +3885,7 @@ make_lispy_event (event)
       }
 #endif /* HAVE_MOUSE */
 
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
     case menu_bar_event:
       /* The event value is in the cdr of the frame_or_window slot.  */
       if (!CONSP (event->frame_or_window))
@@ -3318,7 +3942,8 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 #endif
        {
          /* It's in a frame; which window on that frame?  */
-         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
+         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
+                                NULL, 1);
          window = window_from_coordinates (frame, column, row, &area);
        }
       else
@@ -3525,7 +4150,7 @@ apply_modifiers_uncached (modifiers, base, base_len)
 static char *modifier_names[] =
 {
   "up", "down", "drag", "click", "double", "triple", 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, "alt", "super", "hyper", "shift", "control", "meta"
 };
 #define NUM_MOD_NAMES (sizeof (modifier_names) / sizeof (modifier_names[0]))
@@ -3722,12 +4347,13 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
      Lisp_Object name_alist;
      char **name_table;
      Lisp_Object *symbol_table;
-     int table_size;
+     unsigned int table_size;
 {
   Lisp_Object value;
   Lisp_Object symbol_int;
 
-  XSETINT (symbol_int, symbol_num);
+  /* Get rid of the "vendor-specific" bit here.  */
+  XSETINT (symbol_int, symbol_num & 0xffffff);
 
   /* Is this a request for a valid symbol?  */
   if (symbol_num < 0 || symbol_num >= table_size)
@@ -3763,6 +4389,15 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
       else if (name_table[symbol_num])
        value = intern (name_table[symbol_num]);
 
+#ifdef HAVE_WINDOW_SYSTEM
+      if (NILP (value))
+       {
+         char *name = x_get_keysym_name (symbol_num);
+         if (name)
+           value = intern (name);
+       }
+#endif
+
       if (NILP (value))
        {
          char buf[20];
@@ -3790,16 +4425,22 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
    such as (ctrl meta backspace), into the usual representation of that
    event type as a number or a symbol.  */
 
-Lisp_Object
-convert_event_type_list (event)
-     Lisp_Object event;
+DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
+  "Convert the event description list EVENT-DESC to an event type.\n\
+EVENT-DESC should contain one base event type (a character or symbol)\n\
+and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
+drag, down, double or triple).\n\
+The return value is an event type (a character or symbol) which\n\
+has the same base event type and all the specified modifiers.")
+  (event_desc)
+     Lisp_Object event_desc;
 {
   Lisp_Object base;
   int modifiers = 0;
   Lisp_Object rest;
 
   base = Qnil;
-  rest = event;
+  rest = event_desc;
   while (CONSP (rest))
     {
       Lisp_Object elt;
@@ -3955,14 +4596,17 @@ lucid_event_type_list_p (object)
 /* 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.)  */
+   (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)
+get_input_pending (addr, do_timers_now)
      int *addr;
+     int do_timers_now;
 {
   /* First of all, have we already counted some input?  */
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -3970,7 +4614,7 @@ get_input_pending (addr)
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -4104,7 +4748,7 @@ read_avail_input (expected)
       if (n_to_read > sizeof cbuf)
        n_to_read = sizeof cbuf;
 #else /* no FIONREAD */
-#if defined(USG) || defined(DGUX)
+#if defined (USG) || defined (DGUX)
       /* Read some input if available, but don't wait.  */
       n_to_read = sizeof cbuf;
       fcntl (input_fd, F_SETFL, O_NDELAY);
@@ -4120,7 +4764,7 @@ read_avail_input (expected)
       do
        {
 #ifdef MSDOS
-         cbuf[0] = dos_keyread();
+         cbuf[0] = dos_keyread ();
          nread = 1;
 #else
          nread = read (input_fd, cbuf, n_to_read);
@@ -4249,7 +4893,7 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (0, SIGIO);
+  kill (getpid (), SIGIO);
 #endif
 }
 
@@ -4337,36 +4981,30 @@ menu_bar_items (old)
   {
     Lisp_Object *tmaps;
 
-    /* Should overriding-local-map apply, here?  */
+    /* Should overriding-terminal-local-map and overriding-local-map apply?  */
     if (!NILP (Voverriding_local_map_menu_flag))
       {
-       if (NILP (Voverriding_local_map))
-         {
-           /* Yes, and it is nil.  Use just global map.  */
-           nmaps = 1;
-           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-         }
-       else
-         {
-           /* Yes, and it is non-nil.  Use it and the global map.  */
-           nmaps = 2;
-           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-           maps[0] = Voverriding_local_map;
-         }
+       /* Yes, use them (if non-nil) as well as the global map.  */
+       maps = (Lisp_Object *) alloca (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.  */
-       nmaps = current_minor_maps (0, &tmaps) + 2;
-       maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-       bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
+       nmaps = current_minor_maps (NULL, &tmaps);
+       maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
 #ifdef USE_TEXT_PROPERTIES
-       maps[nmaps-2] = get_local_map (PT, current_buffer);
+       maps[nmaps++] = get_local_map (PT, current_buffer);
 #else
-       maps[nmaps-2] = current_buffer->keymap;
+       maps[nmaps++] = current_buffer->keymap;
 #endif
       }
-    maps[nmaps-1] = current_global_map;
+    maps[nmaps++] = current_global_map;
   }
 
   /* Look up in each map the dummy prefix key `menu-bar'.  */
@@ -4634,7 +5272,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   if (mapno >= nmaps)
     return Qnil;
 
-#if (defined (HAVE_X_WINDOWS) && defined (HAVE_X_MENU)) || defined (MSDOS)
+#ifdef HAVE_MENUS
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
   if (EVENT_HAS_PARAMETERS (prev_event)
@@ -4654,6 +5292,23 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
       value = Fx_popup_menu (prev_event, Flist (nmaps1, realmaps));
       if (CONSP (value))
        {
+         Lisp_Object tem;
+
+         /* If we got multiple events, unread all but
+            the first.
+            There is no way to prevent those unread events
+            from showing up later in last_nonmenu_event.
+            So turn symbol and integer events into lists,
+            to indicate that they came from a mouse menu,
+            so that when present in last_nonmenu_event
+            they won't confuse things.  */
+         for (tem = XCONS (value)->cdr; !NILP (tem);
+              tem = XCONS (tem)->cdr)
+           if (SYMBOLP (XCONS (tem)->car)
+               || INTEGERP (XCONS (tem)->car))
+             XCONS (tem)->car
+               = Fcons (XCONS (tem)->car, Qnil);
+
          /* If we got more than one event, put all but the first
             onto this list to be read later.
             Return just the first event now.  */
@@ -4667,10 +5322,16 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
        *used_mouse_menu = 1;
       return value;
     }
-#endif /* (HAVE_X_WINDOWS && HAVE_X_MENU) || MSDOS */
+#endif /* HAVE_MENUS */
   return Qnil ;
 }
 
+/* Buffer in use so far for the minibuf prompts for menu keymaps.
+   We make this bigger when necessary, and never free it.  */
+static char *read_char_minibuf_menu_text;
+/* Size of that buffer.  */
+static int read_char_minibuf_menu_width;
+
 static Lisp_Object
 read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
      int commandflag ;
@@ -4681,14 +5342,28 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   register Lisp_Object name;
   int nlength;
   int width = FRAME_WIDTH (selected_frame) - 4;
-  char *menu = (char *) alloca (width + 4);
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
+  char *menu;
 
   if (! menu_prompting)
     return Qnil;
 
+  /* Make sure we have a big enough buffer for the menu text.  */
+  if (read_char_minibuf_menu_text == 0)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text = (char *) xmalloc (width + 4);
+    }
+  else if (width + 4 > read_char_minibuf_menu_width)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text
+       = (char *) xrealloc (read_char_minibuf_menu_text, width + 4);
+    }
+  menu = read_char_minibuf_menu_text;
+
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
@@ -4757,43 +5432,81 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
          else
            {
              /* An ordinary element.  */
-             if ( idx < 0 )
-               s = Fcar_safe (Fcdr_safe (elt));        /* alist */
+             Lisp_Object event;
+
+             if (idx < 0)
+               {
+                 s = Fcar_safe (Fcdr_safe (elt));      /* alist */
+                 event = Fcar_safe (elt);
+               }
              else
-               s = Fcar_safe(elt);                     /* vector */
-             if (!STRINGP (s))
-               /* Ignore the element if it has no prompt string.  */
-               ;
-             /* If we have room for the prompt string, add it to this line.
-                If this is the first on the line, always add it.  */
-             else if (XSTRING (s)->size + i + 2 < width
-                      || !notfirst)
                {
-                 int thiswidth;
+                 s = Fcar_safe (elt);                  /* vector */
+                 XSETINT (event, idx);
+               }
 
-                 /* Punctuate between strings.  */
-                 if (notfirst)
+             /* Ignore the element if it has no prompt string.  */
+             if (STRINGP (s) && INTEGERP (event))
+               {
+                 /* 1 if the char to type matches the string.  */
+                 int char_matches;
+                 Lisp_Object upcased_event, downcased_event;
+                 Lisp_Object desc;
+
+                 upcased_event = Fupcase (event);
+                 downcased_event = Fdowncase (event);
+                 char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
+                                 || XINT (downcased_event) == XSTRING (s)->data[0]);
+                 if (! char_matches)
+                   desc = Fsingle_key_description (event);
+
+                 /* 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))
+                     < width
+                     || !notfirst)
                    {
-                     strcpy (menu + i, ", ");
-                     i += 2;
+                     int thiswidth;
+
+                     /* Punctuate between strings.  */
+                     if (notfirst)
+                       {
+                         strcpy (menu + i, ", ");
+                         i += 2;
+                       }
+                     notfirst = 1;
+                     nobindings = 0 ;
+
+                     /* If the char to type doesn't match the string's
+                        first char, explicitly show what char to type.  */
+                     if (! char_matches)
+                       {
+                         /* Add as much of string as fits.  */
+                         thiswidth = XSTRING (desc)->size;
+                         if (thiswidth + i > width)
+                           thiswidth = width - i;
+                         bcopy (XSTRING (desc)->data, menu + i, thiswidth);
+                         i += thiswidth;
+                         strcpy (menu + i, " = ");
+                         i += 3;
+                       }
+
+                     /* Add as much of string as fits.  */
+                     thiswidth = XSTRING (s)->size;
+                     if (thiswidth + i > width)
+                       thiswidth = width - i;
+                     bcopy (XSTRING (s)->data, menu + i, thiswidth);
+                     i += thiswidth;
+                     menu[i] = 0;
+                   }
+                 else
+                   {
+                     /* If this element does not fit, end the line now,
+                        and save the element for the next line.  */
+                     strcpy (menu + i, "...");
+                     break;
                    }
-                 notfirst = 1;
-                 nobindings = 0 ;
-
-                 /* Add as much of string as fits.  */
-                 thiswidth = XSTRING (s)->size;
-                 if (thiswidth + i > width)
-                   thiswidth = width - i;
-                 bcopy (XSTRING (s)->data, menu + i, thiswidth);
-                 i += thiswidth;
-                 menu[i] = 0;
-               }
-             else
-               {
-                 /* If this element does not fit, end the line now,
-                    and save the element for the next line.  */
-                 strcpy (menu + i, "...");
-                 break;
                }
 
              /* Move past this element.  */
@@ -4853,7 +5566,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
    If KEY has no bindings in any of the CURRENT maps, NEXT is left
    unmodified.
 
-   NEXT may == CURRENT.  */
+   NEXT may be the same array as CURRENT.  */
 
 static int
 follow_key (key, nmaps, current, defs, next)
@@ -4862,26 +5575,30 @@ follow_key (key, nmaps, current, defs, next)
      int nmaps;
 {
   int i, first_binding;
+  int did_meta = 0;
 
   /* If KEY is a meta ASCII character, treat it like meta-prefix-char
-     followed by the corresponding non-meta character.  */
+     followed by the corresponding non-meta character.
+     Put the results into DEFS, since we are going to alter that anyway.
+     Do not alter CURRENT or NEXT.  */
   if (INTEGERP (key) && (XINT (key) & CHAR_META))
     {
       for (i = 0; i < nmaps; i++)
        if (! NILP (current[i]))
          {
-           next[i] =
-             get_keyelt (access_keymap (current[i], meta_prefix_char, 1, 0));
+           Lisp_Object def;
+           def = get_keyelt (access_keymap (current[i],
+                                            meta_prefix_char, 1, 0));
 
            /* Note that since we pass the resulting bindings through
               get_keymap_1, non-prefix bindings for meta-prefix-char
               disappear.  */
-           next[i] = get_keymap_1 (next[i], 0, 1);
+           defs[i] = get_keymap_1 (def, 0, 1);
          }
        else
-         next[i] = Qnil;
+         defs[i] = Qnil;
 
-      current = next;
+      did_meta = 1;
       XSETINT (key, XFASTINT (key) & ~CHAR_META);
     }
 
@@ -4890,7 +5607,13 @@ follow_key (key, nmaps, current, defs, next)
     {
       if (! NILP (current[i]))
        {
-         defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
+         Lisp_Object map;
+         if (did_meta)
+           map = defs[i];
+         else
+           map = current[i];
+
+         defs[i] = get_keyelt (access_keymap (map, key, 1, 0));
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -5036,6 +5759,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int function_key_possible = 0;
   int key_translation_possible = 0;
 
+  /* Save the status of key translation before each step,
+     so that we can restore this after downcasing.  */
+  Lisp_Object prev_fkey_map;
+  Lisp_Object prev_fkey_start;
+  Lisp_Object prev_fkey_end;
+
+  Lisp_Object prev_keytran_map;
+  Lisp_Object prev_keytran_start;
+  Lisp_Object prev_keytran_end;
+
   int junk;
 
   last_nonmenu_event = Qnil;
@@ -5098,34 +5831,38 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   {
     Lisp_Object *maps;
 
-    if (!NILP (Voverriding_local_map))
+    if (!NILP (current_kboard->Voverriding_terminal_local_map)
+       || !NILP (Voverriding_local_map))
       {
-       nmaps = 2;
-       if (nmaps > nmaps_allocated)
+       if (3 > nmaps_allocated)
          {
-           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
-           nmaps_allocated = nmaps;
+           submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
+           nmaps_allocated = 3;
          }
-       submaps[0] = Voverriding_local_map;
+       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
       {
-       nmaps = current_minor_maps (0, &maps) + 2;
-       if (nmaps > nmaps_allocated)
+       nmaps = current_minor_maps (0, &maps);
+       if (nmaps + 2 > nmaps_allocated)
          {
-           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
-           nmaps_allocated = nmaps;
+           submaps = (Lisp_Object *) alloca ((nmaps+2) * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca ((nmaps+2) * sizeof (defs[0]));
+           nmaps_allocated = nmaps + 2;
          }
-       bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
+       bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
 #ifdef USE_TEXT_PROPERTIES
-       submaps[nmaps-2] = orig_local_map;
+       submaps[nmaps++] = orig_local_map;
 #else
-       submaps[nmaps-2] = current_buffer->keymap;
+       submaps[nmaps++] = current_buffer->keymap;
 #endif
       }
-    submaps[nmaps-1] = current_global_map;
+    submaps[nmaps++] = current_global_map;
   }
 
   /* Find an accurate initial value for first_binding.  */
@@ -5176,7 +5913,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       int echo_local_start, keys_local_start, local_first_binding;
 
       if (t >= bufsize)
-       error ("key sequence too long");
+       error ("Key sequence too long");
 
       if (INTERACTIVE)
        echo_local_start = echo_length ();
@@ -5365,7 +6102,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  if (CONSP (start) && CONSP (XCONS (start)->cdr))
                    {
                      pos = POSN_BUFFER_POSN (start);
-                     if (INTEGERP (pos))
+                     if (INTEGERP (pos)
+                         && XINT (pos) >= BEG && XINT (pos) <= Z)
                        {
                          map_here = get_local_map (XINT (pos), current_buffer);
                          if (!EQ (map_here, orig_local_map))
@@ -5385,7 +6123,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              if (SYMBOLP (posn))
                {
                  if (t + 1 >= bufsize)
-                   error ("key sequence too long");
+                   error ("Key sequence too long");
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
                  mock_input = t + 2;
@@ -5420,14 +6158,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              if (EQ (posn, Qmenu_bar))
                {
                  if (t + 1 >= bufsize)
-                   error ("key sequence too long");
-                 /* Run the Lucid hook.  */
-                 if (!NILP (Vrun_hooks))
-                   call1 (Vrun_hooks, Qactivate_menubar_hook);
-                 /* If it has changed current-menubar from previous value,
-                    really recompute the menubar from the value.  */
-                 if (! NILP (Vlucid_menu_bar_dirty_flag))
-                   call0 (Qrecompute_lucid_menubar);
+                   error ("Key sequence too long");
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
 
@@ -5465,7 +6196,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Lisp_Object head;
 
          head = EVENT_HEAD (key);
-         if (EQ (head, Vhelp_char))
+         if (help_char_p (head) && t > 0)
            {
              read_key_sequence_cmd = Vprefix_help_command;
              keybuf[t++] = key;
@@ -5586,6 +6317,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (!used_mouse_menu)
        last_nonmenu_event = key;
 
+      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
@@ -5662,7 +6401,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  t = fkey_start + len;
                  if (t >= bufsize)
-                   error ("key sequence too long");
+                   error ("Key sequence too long");
 
                  if (VECTORP (fkey_next))
                    bcopy (XVECTOR (fkey_next)->contents,
@@ -5762,7 +6501,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                t = keytran_start + len;
                if (t >= bufsize)
-                 error ("key sequence too long");
+                 error ("Key sequence too long");
 
                if (VECTORP (keytran_next))
                  bcopy (XVECTOR (keytran_next)->contents,
@@ -5814,17 +6553,31 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
               && UPPERCASEP (XINT (key) & 0x3ffff))
              || (XINT (key) & shift_modifier)))
        {
+         Lisp_Object new_key;
+
          original_uppercase = key;
          original_uppercase_position = t - 1;
 
-         if (XINT (key) & shift_modifier)
-           XSETINT (key, XINT (key) & ~shift_modifier);
+         if (XINT (new_key) & shift_modifier)
+           XSETINT (new_key, XINT (key) & ~shift_modifier);
          else
-           XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
-                          | (XINT (key) & ~0x3ffff)));
+           XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
+                              | (XINT (key) & ~0x3ffff)));
 
-         keybuf[t - 1] = key;
+         /* We have to do this unconditionally, regardless of whether
+            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;
+
          goto replay_sequence;
        }
       /* If KEY is not defined in any of the keymaps,
@@ -5838,19 +6591,30 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Lisp_Object breakdown;
          int modifiers;
 
-         original_uppercase = key;
-         original_uppercase_position = t - 1;
-
          breakdown = parse_modifiers (key);
          modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
          if (modifiers & shift_modifier)
            {
+             Lisp_Object new_key;
+
+             original_uppercase = key;
+             original_uppercase_position = t - 1;
+
              modifiers &= ~shift_modifier;
-             key = apply_modifiers (modifiers,
-                                    XCONS (breakdown)->car);
+             new_key = apply_modifiers (modifiers,
+                                        XCONS (breakdown)->car);
 
-             keybuf[t - 1] = key;
+             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;
+
              goto replay_sequence;
            }
        }
@@ -5864,7 +6628,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   unread_switch_frame = delayed_switch_frame;
   unbind_to (count, Qnil);
 
-  if (dont_downcase_last && t - 1 == original_uppercase_position)
+  /* Don't downcase the last character if the caller says don't.
+     Don't downcase it if the result is undefined, either.  */
+  if ((dont_downcase_last || first_binding >= nmaps)
+      && t - 1 == original_uppercase_position)
     keybuf[t - 1] = original_uppercase;
 
   /* Occasionally we fabricate events, perhaps by expanding something
@@ -5967,14 +6734,18 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
   return make_event_array (i, keybuf);
 }
 \f
-DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 0,
+DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
  "Execute CMD as an editor command.\n\
 CMD must be a symbol that satisfies the `commandp' predicate.\n\
 Optional second arg RECORD-FLAG non-nil\n\
 means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.")
-     (cmd, record)
-     Lisp_Object cmd, record;
+Otherwise, that is done only if an arg is read using the minibuffer.\n\
+The argument KEYS specifies the value to use instead of (this-command-keys)\n\
+when reading the arguments; if it is nil, (this_command_key_count) is used.\n\
+The argument SPECIAL, if non-nil, means that this command is executing\n\
+a special event, so ignore the prefix argument and don't clear it.")
+     (cmd, record_flag, keys, special)
+     Lisp_Object cmd, record_flag, keys, special;
 {
   register Lisp_Object final;
   register Lisp_Object tem;
@@ -5982,16 +6753,26 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
   struct backtrace backtrace;
   extern int debug_on_next_call;
 
-  prefixarg = Vprefix_arg;
-  clear_prefix_arg ();
-  Vcurrent_prefix_arg = prefixarg;
   debug_on_next_call = 0;
 
+  if (NILP (special))
+    {
+      prefixarg = current_kboard->Vprefix_arg;
+      Vcurrent_prefix_arg = prefixarg;
+      current_kboard->Vprefix_arg = Qnil;
+    }
+  else
+    prefixarg = Qnil;
+
   if (SYMBOLP (cmd))
     {
       tem = Fget (cmd, Qdisabled);
       if (!NILP (tem) && !NILP (Vrun_hooks))
-       return call1 (Vrun_hooks, Qdisabled_command_hook);
+       {
+         tem = Fsymbol_value (Qdisabled_command_hook);
+         if (!NILP (tem))
+           return call1 (Vrun_hooks, Qdisabled_command_hook);
+       }
     }
 
   while (1)
@@ -6009,7 +6790,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
       /* If requested, place the macro in the command history.  For
         other sorts of commands, call-interactively takes care of
         this.  */
-      if (!NILP (record))
+      if (!NILP (record_flag))
        Vcommand_history
          = Fcons (Fcons (Qexecute_kbd_macro,
                          Fcons (final, Fcons (prefixarg, Qnil))),
@@ -6026,7 +6807,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
       backtrace.nargs = 1;
       backtrace.evalargs = 0;
 
-      tem = Fcall_interactively (cmd, record);
+      tem = Fcall_interactively (cmd, record_flag, keys);
 
       backtrace_list = backtrace.next;
       return tem;
@@ -6086,6 +6867,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                               Vobarray, Qcommandp,
                               Qt, Qnil, Qextended_command_history);
 
+  if (STRINGP (function) && XSTRING (function)->size == 0)
+    error ("No command name given");
+
   /* Set this_command_keys to the concatenation of saved_keys and
      function, followed by a RET.  */
   {
@@ -6114,17 +6898,96 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   UNGCPRO;
 
   function = Fintern (function, Qnil);
-  Vprefix_arg = prefixarg;
+  current_kboard->Vprefix_arg = prefixarg;
   this_command = function;
 
-  return Fcommand_execute (function, Qt);
+  /* If enabled, show which key runs this command.  */
+  if (!NILP (Vsuggest_key_bindings)
+      && SYMBOLP (function))
+    {
+      Lisp_Object bindings;
+
+      bindings = Fwhere_is_internal (function, Voverriding_local_map,
+                                    Qt, Qnil);
+
+      if (!NILP (bindings))
+       {
+         message ("You can run the command `%s' by typing %s",
+                  XSYMBOL (function)->name->data,
+                  XSTRING (Fkey_description (bindings))->data);
+         Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+                    ? Vsuggest_key_bindings : make_number (2)),
+                   Qnil, Qnil);
+       }
+    }
+
+  return Fcommand_execute (function, Qt, Qnil, Qnil);
+}
+
+/* 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.  */
+      nmaps = current_minor_maps (NULL, &tmaps);
+      maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0]));
+      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+#ifdef USE_TEXT_PROPERTIES
+      maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+      maps[nmaps++] = current_buffer->keymap;
+#endif
+    }
+  maps[nmaps++] = current_global_map;
+
+  *maps_p = maps;
+  return nmaps;
 }
 \f
+/* Return nonzero if input events are pending.  */
 
 detect_input_pending ()
 {
   if (!input_pending)
-    get_input_pending (&input_pending);
+    get_input_pending (&input_pending, 0);
+
+  return input_pending;
+}
+
+/* Return nonzero if input events are pending.
+   Execute timers immediately; don't make events for them.  */
+
+detect_input_pending_run_timers (do_display)
+     int do_display;
+{
+  int old_timers_run = timers_run;
+
+  if (!input_pending)
+    get_input_pending (&input_pending, 1);
+
+  if (old_timers_run != timers_run && do_display)
+    redisplay_preserve_echo_area ();
 
   return input_pending;
 }
@@ -6145,7 +7008,8 @@ Actually, the value is nil only if we can be sure that no input is available.")
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  return detect_input_pending () ? Qt : Qnil;
+  get_input_pending (&input_pending, 1);
+  return input_pending > 0 ? Qt : Qnil;
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
@@ -6179,6 +7043,26 @@ The value is a string or a vector.")
                           XVECTOR (this_command_keys)->contents);
 }
 
+DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
+  Sreset_this_command_lengths, 0, 0, 0,
+  "Used for complicated reasons in `universal-argument-other-key'.\n\
+\n\
+`universal-argument-other-key' rereads the event just typed.\n\
+It then gets translated through `function-key-map'.\n\
+The translated event gets included in the echo area and in\n\
+the value of `this-command-keys' in addition to the raw original event.\n\
+That is not right.\n\
+\n\
+Calling this function directs the translated event to replace\n\
+the original event, so that only one version of the event actually\n\
+appears in the echo area and in the value of `this-command-keys.'.")
+  ()
+{
+  before_command_restore_flag = 1;
+  before_command_key_count_1 = before_command_key_count;
+  before_command_echo_length_1 = before_command_echo_length;
+}
+
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
   "Return the current depth in recursive edits.")
   ()
@@ -6195,18 +7079,17 @@ If FILE is nil, close any open dribble file.")
   (file)
      Lisp_Object file;
 {
-  if (NILP (file))
+  if (dribble)
     {
-      if (dribble)
-       {
-         fclose (dribble);
-         dribble = 0;
-       }
+      fclose (dribble);
+      dribble = 0;
     }
-  else
+  if (!NILP (file))
     {
       file = Fexpand_file_name (file, Qnil);
       dribble = fopen (XSTRING (file)->data, "w");
+      if (dribble == 0)
+       report_file_error ("Opening dribble", Fcons (file, Qnil));
     }
   return Qnil;
 }
@@ -6418,18 +7301,35 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
         is used.  Note that [Enter] is not echoed by dos.  */
       cursor_to (0, 0);
 #endif
-      printf ("Auto-save? (y or n) ");
-      fflush (stdout);
-      if (((c = getchar ()) & ~040) == 'Y')
+      /* It doesn't work to autosave while GC is in progress;
+        the code used for auto-saving doesn't cope with the mark bit.  */
+      if (!gc_in_progress)
        {
-         Fdo_auto_save (Qt, Qnil);
+         printf ("Auto-save? (y or n) ");
+         fflush (stdout);
+         if (((c = getchar ()) & ~040) == 'Y')
+           {
+             Fdo_auto_save (Qt, Qnil);
 #ifdef MSDOS
-         printf ("\r\nAuto-save done");
+             printf ("\r\nAuto-save done");
 #else /* not MSDOS */
-         printf ("Auto-save done\n");
+             printf ("Auto-save done\n");
 #endif /* not MSDOS */
+           }
+         while (c != '\n') c = getchar ();
        }
-      while (c != '\n') c = getchar ();
+      else 
+       {
+         /* During GC, it must be safe to reenable quitting again.  */
+         Vinhibit_quit = Qnil;
+#ifdef MSDOS
+         printf ("\r\n");
+#endif /* not MSDOS */
+         printf ("Garbage collection in progress; cannot auto-save now\r\n");
+         printf ("but will instead do a real quit after garbage collection ends\r\n");
+         fflush (stdout);
+       }
+
 #ifdef MSDOS
       printf ("\r\nAbort?  (y or n) ");
 #else /* not MSDOS */
@@ -6486,15 +7386,20 @@ quit_throw_to_read_char ()
   Vunread_command_events = Qnil;
   unread_command_char = -1;
 
+#if 0 /* Currently, sit_for is called from read_char without turning
+        off polling.  And that can call set_waiting_for_input.
+        It seems to be harmless.  */
 #ifdef POLL_FOR_INPUT
   /* May be > 1 if in recursive minibuffer.  */
   if (poll_suppress_count == 0)
     abort ();
 #endif
+#endif
 #ifdef MULTI_FRAME
   if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
-    Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
+    do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
+                    Qnil, 0);
 #endif
 
   _longjmp (getcjmp, 1);
@@ -6522,22 +7427,34 @@ See also `current-input-mode'.")
   stop_polling ();
 #endif
 
+#ifndef MSDOS
+  /* this causes startup screen to be restored and messes with the mouse */
   reset_sys_modes ();
+#endif
+
 #ifdef SIGIO
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
-#ifdef NO_SOCK_SIGIO
   if (read_socket_hook)
-    interrupt_input = 0;       /* No interrupts if reading from a socket.  */
-  else
+    {
+      /* When using X, don't give the user a real choice,
+        because we haven't implemented the mechanisms to support it.  */
+#ifdef NO_SOCK_SIGIO
+      interrupt_input = 0;
+#else /* not NO_SOCK_SIGIO */
+      interrupt_input = 1;
 #endif /* NO_SOCK_SIGIO */
+    }
+  else
     interrupt_input = !NILP (interrupt);
 #else /* not SIGIO */
   interrupt_input = 0;
 #endif /* not SIGIO */
+
 /* Our VMS input only works by interrupts, as of now.  */
 #ifdef VMS
   interrupt_input = 1;
 #endif
+
   flow_control = !NILP (flow);
   if (NILP (meta))
     meta_key = 0;
@@ -6549,7 +7466,9 @@ See also `current-input-mode'.")
     /* Don't let this value be out of range.  */
     quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
 
+#ifndef MSDOS
   init_sys_modes ();
+#endif
 
 #ifdef POLL_FOR_INPUT
   poll_suppress_count = 1;
@@ -6592,10 +7511,9 @@ void
 init_kboard (kb)
      KBOARD *kb;
 {
-  kb->prefix_factor = Qnil;
-  kb->prefix_value = Qnil;
-  kb->prefix_sign = 1;
-  kb->prefix_partial = 0;
+  kb->Voverriding_terminal_local_map = Qnil;
+  kb->Vlast_command = Qnil;
+  kb->Vprefix_arg = Qnil;
   kb->kbd_queue = Qnil;
   kb->kbd_queue_has_data = 0;
   kb->immediate_echo = 0;
@@ -6607,12 +7525,13 @@ init_kboard (kb)
   kb->Vlast_kbd_macro = Qnil;
   kb->reference_count = 0;
   kb->Vsystem_key_alist = Qnil;
+  kb->system_key_syms = Qnil;
   kb->Vdefault_minibuffer_frame = Qnil;
 }
 
 /*
  * Destroy the contents of a kboard object, but not the object itself.
- * We use this just before deleteing it, or if we're going to initialize
+ * We use this just before deleting it, or if we're going to initialize
  * it a second time.
  */
 static void
@@ -6646,6 +7565,7 @@ init_keyboard ()
   quit_char = Ctl ('g');
   Vunread_command_events = Qnil;
   unread_command_char = -1;
+  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
   total_keys = 0;
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
@@ -6753,18 +7673,15 @@ syms_of_keyboard ()
   Qundefined = intern ("undefined");
   staticpro (&Qundefined);
 
-  Qdigit_argument = intern ("digit-argument");
-  staticpro (&Qdigit_argument);
-
-  Qnegative_argument = intern ("negative-argument");
-  staticpro (&Qnegative_argument);
-
   Qpre_command_hook = intern ("pre-command-hook");
   staticpro (&Qpre_command_hook);
 
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
+  Qpost_command_idle_hook = intern ("post-command-idle-hook");
+  staticpro (&Qpost_command_idle_hook);
+
   Qdeferred_action_function = intern ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
@@ -6775,6 +7692,8 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
+  Qtimer_event = intern ("timer-event");
+  staticpro (&Qtimer_event);
 
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
@@ -6860,15 +7779,13 @@ syms_of_keyboard ()
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
-  system_key_syms = Qnil;
-  staticpro (&system_key_syms);
-
   mouse_syms = Qnil;
   staticpro (&mouse_syms);
 
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
 
+  defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Srecursive_edit);
 #ifdef HAVE_MOUSE
@@ -6878,6 +7795,7 @@ syms_of_keyboard ()
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
+  defsubr (&Sreset_this_command_lengths);
   defsubr (&Ssuspend_emacs);
   defsubr (&Sabort_recursive_edit);
   defsubr (&Sexit_recursive_edit);
@@ -6918,7 +7836,7 @@ so that you can determine whether the command was run by mouse or not.");
 turns into this character followed by foo.");
   XSETINT (meta_prefix_char, 033);
 
-  DEFVAR_LISP ("last-command", &last_command,
+  DEFVAR_KBOARD ("last-command", Vlast_command,
     "The last command executed.  Normally a symbol with a function definition,\n\
 but can be whatever was found in the keymap, or whatever the variable\n\
 `this-command' was set to by that command.\n\
@@ -6930,7 +7848,6 @@ command exit.\n\
 \n\
 The value `kill-region' is special; it means that the previous command\n\
 was a kill command.");
-  last_command = Qnil;
 
   DEFVAR_LISP ("this-command", &this_command,
     "The command now being executed.\n\
@@ -6987,6 +7904,11 @@ When it is read, do `(eval help-form)', and display result if it's a string.\n\
 If the value of `help-form' is nil, this char can be read normally.");
   XSETINT (Vhelp_char, Ctl ('H'));
 
+  DEFVAR_LISP ("help-event-list", &Vhelp_event_list,
+    "List of input events to recognize as meaning Help.\n\
+These work just like the value of `help-char' (see that).");
+  Vhelp_event_list = Qnil;
+
   DEFVAR_LISP ("help-form", &Vhelp_form,
     "Form to execute when character `help-char' is read.\n\
 If the form returns a string, that string is displayed.\n\
@@ -7005,17 +7927,14 @@ Useful to set before you dump a modified Emacs.");
   Vtop_level = Qnil;
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
-    "String used as translate table for keyboard input, or nil.\n\
+    "Translate table for keyboard input, or nil.\n\
 Each character is looked up in this string and the contents used instead.\n\
-If string is of length N, character codes N and up are untranslated.");
+The value may be a string, a vector, or a char-table.\n\
+If it is a string or vector of length N,\n\
+character codes N and up are untranslated.\n\
+In a vector or a char-table, an element which is nil means \"no translation\".");
   Vkeyboard_translate_table = Qnil;
 
-  DEFVAR_LISP ("key-translation-map", &Vkey_translation_map,
-    "Keymap of key translations that can override keymaps.\n\
-This keymap works like `function-key-map', but comes after that,\n\
-and applies even for keys that have ordinary bindings.");
-  Vkey_translation_map = Qnil;
-
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
     "Non-nil means to always spawn a subshell instead of suspending,\n\
 even if the operating system has support for stopping a process.");
@@ -7062,22 +7981,24 @@ Buffer modification stores t in this variable.");
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
     "Normal hook run before each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`pre-command-hook'.  See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
     "Normal hook run after each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`post-command-hook'.  See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
   Vpost_command_hook = Qnil;
 
+  DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
+    "Normal hook run after each command is executed, if idle.\n\
+Errors running the hook are caught and ignored.");
+  Vpost_command_idle_hook = Qnil;
+
+  DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
+    "Delay time before running `post-command-idle-hook'.\n\
+This is measured in microseconds.");
+  post_command_idle_delay = 100000;
+
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
     "t means menu bar, specified Lucid style, needs to be recomputed.");
   Vlucid_menu_bar_dirty_flag = Qnil;
@@ -7087,6 +8008,12 @@ implementing hook functions that alter the set of hook functions.");
 The elements of the list are event types that may have menu bar bindings.");
   Vmenu_bar_final_items = Qnil;
 
+  DEFVAR_KBOARD ("overriding-terminal-local-map",
+                Voverriding_terminal_local_map,
+    "Keymap that overrides all other local keymaps.\n\
+If this variable is non-nil, it is used as a keymap instead of the\n\
+buffer's local map, and the minor mode keymaps and text property keymaps.");
+
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
     "Keymap that overrides all other local keymaps.\n\
 If this variable is non-nil, it is used as a keymap instead of the\n\
@@ -7099,6 +8026,10 @@ Otherwise, the menu bar continues to reflect the buffer's local map\n\
 and the minor mode maps regardless of `overriding-local-map'.");
   Voverriding_local_map_menu_flag = Qnil;
 
+  DEFVAR_LISP ("special-event-map", &Vspecial_event_map,
+    "Keymap defining bindings for special events to execute at low level.");
+  Vspecial_event_map = Fcons (intern ("keymap"), Qnil);
+
   DEFVAR_LISP ("track-mouse", &do_mouse_tracking,
     "*Non-nil means generate motion events for mouse motion.");
 
@@ -7118,6 +8049,24 @@ The precise format isn't relevant here; we just check whether it is nil.");
 This function is called with no arguments after each command\n\
 whenever `deferred-action-list' is non-nil.");
   Vdeferred_action_function = Qnil;
+
+  DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
+    "Non-nil means show the equivalent key-binding when M-x command has one.\n\
+The value can be a length of time to show the message for.\n\
+If the value is non-nil and not a number, we wait 2 seconds.");
+  Vsuggest_key_bindings = Qt;
+
+  DEFVAR_LISP ("column-number-mode", &Vcolumn_number_mode,
+    "Non-nil enables display of the current column number in the mode line.");
+  Vcolumn_number_mode = Qnil;
+
+  DEFVAR_LISP ("timer-list", &Vtimer_list,
+    "List of active absolute time timers in order of increasing time");
+  Vtimer_list = Qnil;
+
+  DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
+    "List of active idle-time timers in order of increasing time");
+  Vtimer_idle_list = Qnil;
 }
 
 keys_of_keyboard ()
@@ -7127,4 +8076,11 @@ keys_of_keyboard ()
   initial_define_key (meta_map, Ctl ('C'), "exit-recursive-edit");
   initial_define_key (global_map, Ctl (']'), "abort-recursive-edit");
   initial_define_key (meta_map, 'x', "execute-extended-command");
+
+  initial_define_lispy_key (Vspecial_event_map, "delete-frame",
+                           "handle-delete-frame");
+  initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
+                           "ignore-event");
+  initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
+                           "ignore-event");
 }