(byte-compile-insert-header): If emacs-version
[bpt/emacs.git] / src / keyboard.c
index af1fb97..625e14b 100644 (file)
@@ -125,6 +125,10 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* Number of elements of this_command_keys
+   that precede this key sequence.  */
+int this_single_command_key_start;
+
 /* Record values of this_command_key_count and echo_length ()
    before this command was read.  */
 static int before_command_key_count;
@@ -289,14 +293,12 @@ int last_point_position;
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
-#ifdef MULTI_FRAME
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
    like Fselect_frame, to make sure that a switch-frame event is
    generated by the next character.  */
 Lisp_Object internal_last_event_frame;
-#endif
 
 /* A user-visible version of the above, intended to allow users to
    figure out where the last event came from, if the event doesn't
@@ -474,9 +476,15 @@ extern char *x_get_keysym_name ();
 
 Lisp_Object Qpolling_period;
 
-/* List of active timers.  Appears in order of next scheduled event.  */
+/* 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
@@ -490,7 +498,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.  */
@@ -511,9 +519,6 @@ int flow_control;
 #ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
-
-/* Non-nil enables Column Number mode.  */
-Lisp_Object Vcolumn_number_mode;
 \f
 /* Global variable declarations.  */
 
@@ -709,6 +714,8 @@ add_command_key (key)
   if (before_command_restore_flag)
     {
       this_command_key_count = before_command_key_count_1;
+      if (this_command_key_count < this_single_command_key_start)
+       this_single_command_key_start = this_command_key_count;
       echo_truncate (before_command_echo_length_1);
       before_command_restore_flag = 0;
     }
@@ -743,6 +750,10 @@ recursive_edit_1 ()
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
+  /* Handle throw from read_minibuf when using minibuffer
+     while it's active but we're in another window.  */
+  if (STRINGP (val))
+    Fsignal (Qerror, Fcons (val, Qnil));
 
   return unbind_to (count, Qnil);
 }
@@ -876,10 +887,23 @@ cmd_error (data)
      Lisp_Object data;
 {
   Lisp_Object old_level, old_length;
+  char macroerror[50];
+
+  if (!NILP (executing_macro))
+    {
+      if (executing_macro_iterations == 1)
+       sprintf (macroerror, "After 1 kbd macro iteration: ");
+      else
+       sprintf (macroerror, "After %d kbd macro iterations: ",
+                executing_macro_iterations);
+    }
+  else
+    *macroerror = 0;
 
   Vstandard_output = Qt;
   Vstandard_input = Qt;
   Vexecuting_macro = Qnil;
+  executing_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
   cancel_echoing ();
 
@@ -888,7 +912,7 @@ cmd_error (data)
   old_length = Vprint_length;
   XSETFASTINT (Vprint_level, 10);
   XSETFASTINT (Vprint_length, 10);
-  cmd_error_internal (data, NULL);
+  cmd_error_internal (data, macroerror);
   Vprint_level = old_level;
   Vprint_length = old_length;
 
@@ -1062,6 +1086,7 @@ command_loop_1 ()
   nonundocount = 0;
   no_redisplay = 0;
   this_command_key_count = 0;
+  this_single_command_key_start = 0;
 
   /* Make sure this hook runs after commands that get errors and
      throw to top level.  */
@@ -1110,11 +1135,14 @@ command_loop_1 ()
             rather than quitting back to the minibuffer.  */
          int count = specpdl_ptr - specpdl;
          specbind (Qinhibit_quit, Qt);
+
          Fsit_for (make_number (2), Qnil, Qnil);
+         /* Clear the echo area.  */
+         message2 (0);
+
          unbind_to (count, Qnil);
 
-         echo_area_glyphs = 0;
-         no_direct = 1;
+         /* If a C-g came in before, treat it as input now.  */
          if (!NILP (Vquit_flag))
            {
              Vquit_flag = Qnil;
@@ -1128,7 +1156,6 @@ command_loop_1 ()
 #endif /* C_ALLOCA */
 
 #if 0
-#ifdef MULTI_FRAME
       /* Select the frame that the last event came from.  Usually,
         switch-frame events will take care of this, but if some lisp
         code swallows a switch-frame event, we'll fix things up here.
@@ -1136,7 +1163,6 @@ command_loop_1 ()
       if (FRAMEP (internal_last_event_frame)
          && XFRAME (internal_last_event_frame) != selected_frame)
        Fselect_frame (internal_last_event_frame, Qnil);
-#endif
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
@@ -1153,6 +1179,10 @@ command_loop_1 ()
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
                             Qnil, 0, 1);
 
+      /* A filter may have run while we were reading the input.  */
+      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+       set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+
       ++num_input_keys;
 
       /* Now we have read a key sequence of length I,
@@ -1166,6 +1196,7 @@ command_loop_1 ()
        {
          cancel_echoing ();
          this_command_key_count = 0;
+         this_single_command_key_start = 0;
          goto finalize;
        }
 
@@ -1241,12 +1272,14 @@ command_loop_1 ()
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
+                     && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT - 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
@@ -1265,12 +1298,14 @@ command_loop_1 ()
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
+                     && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT + 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (-1);
                  goto directly_done;
@@ -1294,13 +1329,15 @@ command_loop_1 ()
                    }
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
+                         || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                             < OVERLAY_MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_point)
                              != PT)
                          || MODIFF <= SAVE_MODIFF
                          || windows_or_buffers_changed
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
-                         || !NILP (Vcolumn_number_mode)
+                         || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_macro));
                  value = internal_self_insert (c, 0);
                  if (value)
@@ -1351,27 +1388,11 @@ command_loop_1 ()
          nonundocount = 0;
          if (NILP (current_kboard->Vprefix_arg))
            Fundo_boundary ();
-         Fcommand_execute (this_command, Qnil, 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 (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 Vlast_command to be ``universal-argument''
         (that would be dumb), so don't set Vlast_command,
@@ -1390,6 +1411,23 @@ command_loop_1 ()
          current_kboard->Vlast_command = this_command;
          cancel_echoing ();
          this_command_key_count = 0;
+         this_single_command_key_start = 0;
+       }
+
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpost_command_hook);
+
+      if (!NILP (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 (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
@@ -1470,11 +1508,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
@@ -1691,7 +1733,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (!NILP (Vexecuting_macro))
     {
-#ifdef MULTI_FRAME
       /* We set this to Qmacro; since that's not a frame, nobody will
         try to switch frames on us, and the selected window will
         remain unchanged.
@@ -1703,7 +1744,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         events read from a macro should never cause a new frame to be
         selected. */
       Vlast_event_frame = internal_last_event_frame = Qmacro;
-#endif
 
       /* Exit the macro if we are at the end.
         Also, some things replace the macro with t
@@ -1735,7 +1775,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto reread_first;
     }
 
-  if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+  if (commandflag >= 0 && !input_pending
+      && !detect_input_pending_run_timers (0))
     redisplay ();
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
@@ -1758,7 +1799,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events)
       && unread_command_char < 0
-      && !detect_input_pending ())
+      && !detect_input_pending_run_timers (0))
     {
       c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
       if (! NILP (c))
@@ -1777,10 +1818,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (_setjmp (local_getcjmp))
     {
       XSETINT (c, quit_char);
-#ifdef MULTI_FRAME
       XSETFRAME (internal_last_event_frame, selected_frame);
       Vlast_event_frame = internal_last_event_frame;
-#endif
       /* If we report the quit char as an event,
         don't do so more than once.  */
       if (!NILP (Vinhibit_quit))
@@ -1809,6 +1848,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.  */
 
@@ -1842,7 +1883,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (commandflag != 0
       && auto_save_interval > 0
       && num_nonmacro_input_chars - last_auto_save > max (auto_save_interval, 20)
-      && !detect_input_pending ())
+      && !detect_input_pending_run_timers (0))
     {
       Fdo_auto_save (Qnil, Qnil);
       /* Hooks can actually change some buffers in auto save.  */
@@ -1888,25 +1929,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
-         EMACS_TIME timer_delay;
-         EMACS_TIME delay, difference;
-
-         EMACS_SET_SECS (delay,
-                         delay_level * XFASTINT (Vauto_save_timeout) / 4);
-         EMACS_SET_USECS (delay, 0);
-
-         /* Don't wait longer than until the next timer will fire.  */
-         timer_delay = timer_check (0);
-         if (! EMACS_TIME_NEG_P (timer_delay))
-           {
-             EMACS_SUB_TIME (difference, timer_delay, delay);
-             if (EMACS_TIME_NEG_P (difference))
-               delay = timer_delay;
-           }
 
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (EMACS_SECS (delay), EMACS_USECS (delay), 1, 1);
+         tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+                         0, 1, 1);
          restore_getcjmp (save_jump);
 
          if (EQ (tem0, Qt))
@@ -1916,7 +1943,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
              /* If we have auto-saved and there is still no input
                 available, garbage collect if there has been enough
                 consing going on to make it worthwhile.  */
-             if (!detect_input_pending ()
+             if (!detect_input_pending_run_timers (0)
                  && consing_since_gc > gc_cons_threshold / 2)
                Fgarbage_collect ();
 
@@ -1938,13 +1965,11 @@ 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 ();
-#ifdef MULTI_FRAME
+         input_pending = readable_events (0);
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
            internal_last_event_frame = XCONS (XCONS (c)->cdr)->car;
          Vlast_event_frame = internal_last_event_frame;
-#endif
        }
     }
 
@@ -2026,12 +2051,17 @@ 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 (not used now).  */
+  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+    timer_stop_idle ();
+
   start_polling ();
 
   if (NILP (c))
     {
       if (commandflag >= 0
-         && !input_pending && !detect_input_pending ())
+         && !input_pending && !detect_input_pending_run_timers (0))
        redisplay ();
 
       goto wrong_kboard;
@@ -2060,7 +2090,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       int was_locked = single_kboard;
 
       last_input_char = c;
-      Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char));
+      Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
 
       /* Resume allowing input from any kboard, if that was true before.  */
       if (!was_locked)
@@ -2080,11 +2110,12 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        return c;
 
       if (STRINGP (Vkeyboard_translate_table)
-         && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
+         && XSTRING (Vkeyboard_translate_table)->size > (unsigned) 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))
+               && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
+              || (CHAR_TABLE_P (Vkeyboard_translate_table)
+                  && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c)))
        {
          Lisp_Object d;
          d = Faref (Vkeyboard_translate_table, c);
@@ -2293,10 +2324,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);
        }
     }
 }
@@ -2346,9 +2377,12 @@ some_mouse_moved ()
 /* Return true iff there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
 static int
-readable_events ()
+readable_events (do_timers_now)
+     int do_timers_now;
 {
-  timer_check (1);
+  if (do_timers_now)
+    timer_check (do_timers_now);
+
   if (kbd_fetch_ptr != kbd_store_ptr)
     return 1;
 #ifdef HAVE_MOUSE
@@ -2445,7 +2479,6 @@ kbd_buffer_store_event (event)
            }
 #endif
 
-#ifdef MULTI_FRAME
          /* If this results in a quit_char being returned to Emacs as
             input, set Vlast_event_frame properly.  If this doesn't
             get returned to Emacs as an event, the next event read
@@ -2459,7 +2492,6 @@ kbd_buffer_store_event (event)
            internal_last_event_frame = focus;
            Vlast_event_frame = focus;
          }
-#endif
 
          last_event_timestamp = event->timestamp;
          interrupt_signal ();
@@ -2548,17 +2580,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        break;
 #endif
 
-      /* Check when the next timer fires.  */
-      next_timer_delay = timer_check (0);
-      if (EMACS_SECS (next_timer_delay) == 0
-         && EMACS_USECS (next_timer_delay) == 0)
-       break;
-      if (EMACS_TIME_NEG_P (next_timer_delay))
-       {
-         EMACS_SET_SECS (next_timer_delay, 0);
-         EMACS_SET_USECS (next_timer_delay, 0);
-       }
-
       /* If the quit flag is set, then read_char will return
         quit_char, so that counts as "available input."  */
       if (!NILP (Vquit_flag))
@@ -2584,9 +2605,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        Lisp_Object minus_one;
 
        XSETINT (minus_one, -1);
-       wait_reading_process_input (EMACS_SECS (next_timer_delay),
-                                   EMACS_USECS (next_timer_delay),
-                                   minus_one, 1);
+       wait_reading_process_input (0, 0, minus_one, 1);
 
        if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
          /* Pass 1 for EXPECT since we just waited to have input.  */
@@ -2631,7 +2650,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
             and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2648,7 +2667,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          /* Remove it from the buffer before processing it.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
          x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2689,8 +2708,9 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       else if (event->kind == menu_bar_activate_event)
        {
          kbd_fetch_ptr = event + 1;
-         input_pending = readable_events ();
-         x_activate_menubar (XFRAME (event->frame_or_window));
+         input_pending = readable_events (0);
+         if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
+           x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
       /* Just discard these, by returning nil.
@@ -2706,7 +2726,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
         time, and leave the event in the queue for next time.  */
       else
        {
-#ifdef MULTI_FRAME
          Lisp_Object frame;
          Lisp_Object focus;
 
@@ -2724,7 +2743,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && XFRAME (frame) != selected_frame)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
-#endif /* MULTI_FRAME */
 
          /* If we didn't decide to make a switch-frame event, go ahead
             and build a real event from the queue entry.  */
@@ -2771,7 +2789,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
       obj = Qnil;
 
-#ifdef MULTI_FRAME
       /* Decide if we should generate a switch-frame event.  Don't
         generate switch-frame events for motion outside of all Emacs
         frames.  */
@@ -2788,7 +2805,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
-#endif
 
       /* If we didn't decide to make a switch-frame event, go ahead and
         return a mouse-motion event.  */
@@ -2801,11 +2817,9 @@ 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;
-#endif
 
   return (obj);
 }
@@ -2814,8 +2828,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;
@@ -2838,7 +2855,7 @@ swallow_events ()
             and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2856,7 +2873,7 @@ swallow_events ()
          copy = *event;
 
          kbd_fetch_ptr = event + 1;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
          x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2864,13 +2881,78 @@ swallow_events ()
          abort ();
 #endif
        }
+      /* Note that timer_event is currently never used.  */
+      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.
@@ -2879,54 +2961,154 @@ swallow_events ()
    timer is triggering now, return zero seconds.
    If no timer is active, return -1 seconds.
 
-   If a timer is triggering now, either queue a timer-event
-   or run the timer's handler function if DO_IT_NOW is nonzero.  */
+   If a timer is ripe, we run it, with quitting turned off.
+
+   DO_IT_NOW is now ignored.  It used to mean that we should
+   run the timer directly instead of queueing a timer-event.
+   Now we always run timers directly.  */
 
 EMACS_TIME
 timer_check (do_it_now)
      int do_it_now;
 {
   EMACS_TIME nexttime;
-  EMACS_TIME now;
-  Lisp_Object timers, timer;
+  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;
+  struct gcpro gcpro1, gcpro2, gcpro3;
 
   EMACS_SET_SECS (nexttime, -1);
   EMACS_SET_USECS (nexttime, -1);
 
+  /* Always consider the ordinary timers.  */
   timers = Vtimer_list;
-  timer = Qnil;
-  GCPRO2 (timers, timer);
+  /* 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))
-    EMACS_GET_TIME (now);
+  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))
+  while (CONSP (timers) || CONSP (idle_timers))
     {
-      int triggertime;
+      int triggertime = EMACS_SECS (now);
       Lisp_Object *vector;
-      EMACS_TIME timer_time;
-      EMACS_TIME difference;
+      Lisp_Object timer, idle_timer;
+      EMACS_TIME timer_time, idle_timer_time;
+      EMACS_TIME difference, timer_difference, idle_timer_difference;
 
-      timer = XCONS (timers)->car;
-      timers = XCONS (timers)->cdr;
+      /* 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 (!VECTORP (timer) || XVECTOR (timer)->size != 7)
-       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]))
-       continue;
+         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);
+       }
 
-      EMACS_SET_SECS (timer_time,
-                     (XINT (vector[1]) << 16) | (XINT (vector[2])));
-      EMACS_SET_USECS (timer_time, XINT (vector[3]));
-      EMACS_SUB_TIME (difference, timer_time, now);
-      /* If event is past, run it if it hasn't been run.  */
-      if (EMACS_TIME_NEG_P (difference))
+      /* 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]))
            {
@@ -2935,16 +3117,22 @@ timer_check (do_it_now)
              vector[0] = Qt;
 
              /* Run the timer or queue a timer event.  */
-             if (do_it_now)
+             if (1)
                {
                  Lisp_Object tem, event;
                  int was_locked = single_kboard;
+                 int count = specpdl_ptr - specpdl;
+
+                 specbind (Qinhibit_quit, Qt);
 
                  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 (timer, Qnil));
-                 Fcommand_execute (tem, Qnil, Fvector (1, &event));
+                 event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
+                 Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
+                 timers_run++;
+
+                 unbind_to (count, Qnil);
 
                  /* Resume allowing input from any kboard, if that was true before.  */
                  if (!was_locked)
@@ -2953,6 +3141,7 @@ timer_check (do_it_now)
                  /* Since we have handled the event,
                     we don't need to tell the caller to wake up and do it.  */
                }
+#if 0
              else
                {
                  /* Generate a timer event so the caller will handle it.  */
@@ -2963,14 +3152,24 @@ timer_check (do_it_now)
                  event.x = event.y = Qnil;
                  event.timestamp = triggertime;
                  /* Store the timer in the frame slot.  */
-                 event.frame_or_window = Fcons (Fselected_frame (), timer);
+                 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;
                }
+#endif /* 0 */
            }
        }
       else
@@ -2985,6 +3184,7 @@ timer_check (do_it_now)
          return difference;
        }
     }
+
   /* No timers are pending in the future.  */
   /* Return 0 if we generated an event, and -1 if not.  */
   UNGCPRO;
@@ -3358,10 +3558,12 @@ static char *lispy_mouse_names[] =
 
 /* Scroll bar parts.  */
 Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
+Lisp_Object Qup, Qdown;
 
 /* An array of scroll bar parts, indexed by an enum scroll_bar_part value.  */
 Lisp_Object *scroll_bar_parts[] = {
-  &Qabove_handle, &Qhandle, &Qbelow_handle
+  &Qabove_handle, &Qhandle, &Qbelow_handle,
+  &Qup, &Qdown,
 };
 
 
@@ -3469,6 +3671,7 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
+      /* Note that timer_event is currently never used.  */
     case timer_event:
       return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
 
@@ -3529,11 +3732,11 @@ make_lispy_event (event)
 
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
-               for (i = 0; i < XVECTOR (items)->size; i += 3)
+               for (i = 0; i < XVECTOR (items)->size; i += 4)
                  {
                    Lisp_Object pos, string;
                    string = XVECTOR (items)->contents[i + 1];
-                   pos = XVECTOR (items)->contents[i + 2];
+                   pos = XVECTOR (items)->contents[i + 3];
                    if (NILP (string))
                      break;
                    if (column >= XINT (pos)
@@ -3565,7 +3768,7 @@ make_lispy_event (event)
            else
              {
                int pixcolumn, pixrow;
-               column -= XINT (XWINDOW (window)->left);
+               column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
                row -= XINT (XWINDOW (window)->top);
                glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
                XSETINT (event->x, pixcolumn);
@@ -3598,12 +3801,12 @@ make_lispy_event (event)
            portion_whole = Fcons (event->x, event->y);
            part = *scroll_bar_parts[(int) event->part];
 
-           position =
-             Fcons (window,
-                    Fcons (Qvertical_scroll_bar,
-                           Fcons (portion_whole,
-                                  Fcons (make_number (event->timestamp),
-                                         Fcons (part, Qnil)))));
+           position
+             Fcons (window,
+                      Fcons (Qvertical_scroll_bar,
+                             Fcons (portion_whole,
+                                    Fcons (make_number (event->timestamp),
+                                           Fcons (part, Qnil)))));
          }
 
        start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
@@ -3715,6 +3918,56 @@ make_lispy_event (event)
                                 Qnil));
        }
       }
+
+#ifdef WINDOWSNT
+    case w32_scroll_bar_click:
+      {
+       int button = event->code;
+       int is_double;
+       Lisp_Object position;
+       Lisp_Object *start_pos_ptr;
+       Lisp_Object start_pos;
+
+       if (button < 0 || button >= NUM_MOUSE_BUTTONS)
+         abort ();
+
+       {
+         Lisp_Object window;
+         Lisp_Object portion_whole;
+         Lisp_Object part;
+
+         window = event->frame_or_window;
+         portion_whole = Fcons (event->x, event->y);
+         part = *scroll_bar_parts[(int) event->part];
+
+         position =
+           Fcons (window,
+                  Fcons (Qvertical_scroll_bar,
+                         Fcons (portion_whole,
+                                Fcons (make_number (event->timestamp),
+                                       Fcons (part, Qnil)))));
+       }
+
+       /* Always treat W32 scroll bar events as clicks. */
+       event->modifiers |= click_modifier;
+
+       {
+         /* Get the symbol we should use for the mouse click.  */
+         Lisp_Object head;
+
+         head = modify_event_symbol (button,
+                                     event->modifiers,
+                                     Qmouse_click, Qnil,
+                                     lispy_mouse_names, &mouse_syms,
+                                     (sizeof (lispy_mouse_names)
+                                      / sizeof (lispy_mouse_names[0])));
+         return Fcons (head,
+                       Fcons (position,
+                              Qnil));
+       }
+      }
+#endif
+
 #endif /* HAVE_MOUSE */
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
@@ -3741,7 +3994,6 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
      Lisp_Object x, y;
      unsigned long time;
 {
-#ifdef MULTI_FRAME
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
@@ -3760,18 +4012,13 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 
   /* Or is it an ordinary mouse movement?  */
   else
-#endif /* MULTI_FRAME */
     {
       int area;
       Lisp_Object window;
       Lisp_Object posn;
       int column, row;
 
-#ifdef MULTI_FRAME
       if (frame)
-#else
-      if (1)
-#endif
        {
          /* It's in a frame; which window on that frame?  */
          pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
@@ -3784,7 +4031,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
       if (WINDOWP (window))
        {
          int pixcolumn, pixrow;
-         column -= XINT (XWINDOW (window)->left);
+         column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
          row -= XINT (XWINDOW (window)->top);
          glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
          XSETINT (x, pixcolumn);
@@ -3798,13 +4045,11 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
            XSETINT (posn,
                     buffer_posn_from_coords (XWINDOW (window), column, row));
        }
-#ifdef MULTI_FRAME
       else if (frame != 0)
        {
          XSETFRAME (window, frame);
          posn = Qnil;
        }
-#endif
       else
        {
          window = Qnil;
@@ -4238,7 +4483,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
        }
 
       if (CONSP (*symbol_table))
-       *symbol_table = Fcons (value, *symbol_table);
+        *symbol_table = Fcons (Fcons (symbol_int, value), *symbol_table);
       else
        XVECTOR (*symbol_table)->contents[symbol_num] = value;
 
@@ -4261,7 +4506,7 @@ 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\
+drag, down, double or triple).  The base must be last.\n\
 The return value is an event type (a character or symbol) which\n\
 has the same base event type and all the specified modifiers.")
   (event_desc)
@@ -4279,9 +4524,10 @@ has the same base event type and all the specified modifiers.")
       int this = 0;
 
       elt = XCONS (rest)->car;
+      rest = XCONS (rest)->cdr;
 
       /* Given a symbol, see if it is a modifier name.  */
-      if (SYMBOLP (elt))
+      if (SYMBOLP (elt) && CONSP (rest))
        this = parse_solitary_modifier (elt);
 
       if (this != 0)
@@ -4291,7 +4537,6 @@ has the same base event type and all the specified modifiers.")
       else
        base = elt;
 
-      rest = XCONS (rest)->cdr;
     }
 
   /* Let the symbol A refer to the character A.  */
@@ -4428,14 +4673,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))
@@ -4443,7 +4691,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.  */
@@ -4457,7 +4705,7 @@ gobble_input (expected)
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4466,7 +4714,7 @@ gobble_input (expected)
   if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGALRM);
+      mask = sigblock (sigmask (SIGALRM));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4506,7 +4754,7 @@ record_asynch_buffer_change ()
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       kbd_buffer_store_event (&event);
       sigsetmask (mask);
     }
@@ -4543,8 +4791,7 @@ read_avail_input (expected)
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE,
-                                expected, expected);
+    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -4641,11 +4888,7 @@ read_avail_input (expected)
            cbuf[i] &= ~0x80;
 
          buf[i].code = cbuf[i];
-#ifdef MULTI_FRAME
          XSETFRAME (buf[i].frame_or_window, selected_frame);
-#else
-         buf[i].frame_or_window = Qnil;
-#endif
        }
     }
 
@@ -4677,7 +4920,7 @@ input_available_signal (signo)
   extern int select_alarmed;
 #endif
 
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
   signal (signo, input_available_signal);
@@ -4722,7 +4965,7 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (0, SIGIO);
+  kill (getpid (), SIGIO);
 #endif
 }
 
@@ -4859,29 +5102,31 @@ menu_bar_items (old)
       int i;
       int end = menu_bar_items_index;
 
-      for (i = 0; i < end; i += 3)
+      for (i = 0; i < end; i += 4)
        if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
          {
-           Lisp_Object tem0, tem1, tem2;
+           Lisp_Object tem0, tem1, tem2, tem3;
            /* Move the item at index I to the end,
               shifting all the others forward.  */
            tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
            tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
            tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
-           if (end > i + 3)
-             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+           tem3 = XVECTOR (menu_bar_items_vector)->contents[i + 3];
+           if (end > i + 4)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
                     &XVECTOR (menu_bar_items_vector)->contents[i],
-                    (end - i - 3) * sizeof (Lisp_Object));
-           XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem0;
-           XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem1;
-           XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem2;
+                    (end - i - 4) * sizeof (Lisp_Object));
+           XVECTOR (menu_bar_items_vector)->contents[end - 4] = tem0;
+           XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem1;
+           XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem2;
+           XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem3;
            break;
          }
     }
 
-  /* Add nil, nil, nil at the end.  */
+  /* Add nil, nil, nil, nil at the end.  */
   i = menu_bar_items_index;
-  if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+  if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
     {
       Lisp_Object tem;
       int newsize = 2 * i;
@@ -4894,6 +5139,7 @@ menu_bar_items (old)
   XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
   XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
   XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+  XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
   menu_bar_items_index = i;
 
   Vinhibit_quit = oquit;
@@ -4970,19 +5216,23 @@ menu_bar_item (key, item_string, def)
   Lisp_Object enabled;
   int i;
 
+  /* Skip menu-bar equiv keys data.  */
+  if (CONSP (def) && CONSP (XCONS (def)->car))
+    def = XCONS (def)->cdr;
+
   if (EQ (def, Qundefined))
     {
       /* If a map has an explicit `undefined' as definition,
         discard any previously made menu bar item.  */
 
-      for (i = 0; i < menu_bar_items_index; i += 3)
+      for (i = 0; i < menu_bar_items_index; i += 4)
        if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
          {
-           if (menu_bar_items_index > i + 3)
-             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+           if (menu_bar_items_index > i + 4)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
                     &XVECTOR (menu_bar_items_vector)->contents[i],
-                    (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
-           menu_bar_items_index -= 3;
+                    (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
+           menu_bar_items_index -= 4;
            return;
          }
 
@@ -5011,7 +5261,7 @@ menu_bar_item (key, item_string, def)
     return;
 
   /* Find any existing item for this KEY.  */
-  for (i = 0; i < menu_bar_items_index; i += 3)
+  for (i = 0; i < menu_bar_items_index; i += 4)
     if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
       break;
 
@@ -5019,7 +5269,7 @@ menu_bar_item (key, item_string, def)
   if (i == menu_bar_items_index)
     {
       /* If vector is too small, get a bigger one.  */
-      if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+      if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
        {
          Lisp_Object tem;
          int newsize = 2 * i;
@@ -5032,6 +5282,7 @@ menu_bar_item (key, item_string, def)
       XVECTOR (menu_bar_items_vector)->contents[i++] = key;
       XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
       XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
+      XVECTOR (menu_bar_items_vector)->contents[i++] = make_number (0);
       menu_bar_items_index = i;
     }
   /* We did find an item for this KEY.  Add DEF to its list of maps.  */
@@ -5629,6 +5880,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   if (INTERACTIVE)
     echo_start = echo_length ();
   keys_start = this_command_key_count;
+  this_single_command_key_start = keys_start;
 
 #if defined (GOBBLE_FIRST_EVENT)
   /* This doesn't quite work, because some of the things that read_char
@@ -6146,6 +6398,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (!used_mouse_menu)
        last_nonmenu_event = key;
 
+      /* Record what part of this_command_keys is the current key sequence.  */
+      this_single_command_key_start = this_command_key_count - t;
+
       prev_fkey_map = fkey_map;
       prev_fkey_start = fkey_start;
       prev_fkey_end = fkey_end;
@@ -6214,7 +6469,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                     (To ignore it safely, we would need to gcpro a bunch of
                     other variables.)  */
                  if (! (VECTORP (fkey_next) || STRINGP (fkey_next)))
-                   error ("Function in function-key-map returns invalid key sequence");
+                   error ("Function in key-translation-map returns invalid key sequence");
                }
 
              function_key_possible = ! NILP (fkey_next);
@@ -6387,7 +6642,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          original_uppercase = key;
          original_uppercase_position = t - 1;
 
-         if (XINT (new_key) & shift_modifier)
+         if (XINT (key) & shift_modifier)
            XSETINT (new_key, XINT (key) & ~shift_modifier);
          else
            XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
@@ -6548,7 +6803,10 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
   gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
 
   if (NILP (continue_echo))
-    this_command_key_count = 0;
+    {
+      this_command_key_count = 0;
+      this_single_command_key_start = 0;
+    }
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
@@ -6563,16 +6821,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, 3, 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.\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.")
-     (cmd, record_flag, keys)
-     Lisp_Object cmd, record_flag, keys;
+when reading the arguments; if it is nil, (this-command-keys) is used.\n\
+The argument SPECIAL, if non-nil, means that this command is executing\n\
+a special event, so ignore the prefix argument and don't clear it.")
+     (cmd, record_flag, keys, special)
+     Lisp_Object cmd, record_flag, keys, special;
 {
   register Lisp_Object final;
   register Lisp_Object tem;
@@ -6580,11 +6840,17 @@ when reading the arguments; if it is nil, (this_command_key_count) is used.")
   struct backtrace backtrace;
   extern int debug_on_next_call;
 
-  prefixarg = current_kboard->Vprefix_arg;
-  current_kboard->Vprefix_arg = Qnil;
-  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);
@@ -6601,7 +6867,13 @@ when reading the arguments; if it is nil, (this_command_key_count) is used.")
       final = Findirect_function (cmd);
 
       if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
-       do_autoload (final, cmd);
+       {
+         struct gcpro gcpro1, gcpro2;
+
+         GCPRO2 (cmd, prefixarg);
+         do_autoload (final, cmd);
+         UNGCPRO;
+       }
       else
        break;
     }
@@ -6645,12 +6917,13 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object function;
   char buf[40];
   Lisp_Object saved_keys;
-  struct gcpro gcpro1;
+  Lisp_Object bindings, value;
+  struct gcpro gcpro1, gcpro2;
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
   buf[0] = 0;
-  GCPRO1 (saved_keys);
+  GCPRO2 (saved_keys, prefixarg);
 
   if (EQ (prefixarg, Qminus))
     strcpy (buf, "- ");
@@ -6700,6 +6973,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     Lisp_Object tem;
 
     this_command_key_count = 0;
+    this_single_command_key_start = 0;
 
     keys = XVECTOR (saved_keys)->contents;
     for (i = 0; i < XVECTOR (saved_keys)->size; i++)
@@ -6724,25 +6998,48 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 
   /* If enabled, show which key runs this command.  */
   if (!NILP (Vsuggest_key_bindings)
+      && NILP (Vexecuting_macro)
       && SYMBOLP (function))
-    {
-      Lisp_Object bindings;
+    bindings = Fwhere_is_internal (function, Voverriding_local_map,
+                                  Qt, Qnil);
+  else
+    bindings = Qnil;
 
-      bindings = Fwhere_is_internal (function, Voverriding_local_map,
-                                    Qt, Qnil);
+  value = Qnil;
+  GCPRO2 (bindings, value);
+  value = Fcommand_execute (function, Qt, Qnil, Qnil);
 
-      if (!NILP (bindings))
+  /* If the command has a key binding, print it now.  */
+  if (!NILP (bindings))
+    {
+      /* But first wait, and skip the message if there is input.  */
+      if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+                           ? Vsuggest_key_bindings : make_number (2)),
+                          Qnil, Qnil)))
        {
-         message ("You can run the command `%s' by typing %s",
+         Lisp_Object binding;
+         char *newmessage;
+         char *oldmessage = echo_area_glyphs;
+         int oldmessage_len = echo_area_glyphs_length;
+
+         binding = Fkey_description (bindings);
+
+         newmessage
+           = (char *) alloca (XSYMBOL (function)->name->size
+                              + XSTRING (binding)->size
+                              + 100);
+         sprintf (newmessage, "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);
+                  XSTRING (binding)->data);
+         message1_nolog (newmessage);
+         if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+                               ? Vsuggest_key_bindings : make_number (2)),
+                              Qnil, Qnil)))
+           message2_nolog (oldmessage, oldmessage_len);
        }
     }
 
-  return Fcommand_execute (function, Qt, Qnil);
+  RETURN_UNGCPRO (value);
 }
 
 /* Find the set of keymaps now active.
@@ -6786,11 +7083,28 @@ current_active_maps (maps_p)
   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, and run any pending timers.  */
+
+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;
 }
@@ -6803,6 +7117,18 @@ clear_input_pending ()
   input_pending = 0;
 }
 
+/* Return nonzero if there are pending requeued events.
+   This isn't used yet.  The hope is to make wait_reading_process_input
+   call it, and return return if it runs Lisp code that unreads something.
+   The problem is, kbd_buffer_get_event needs to be fixed to know what
+   to do in that case.  It isn't trivial.  */
+
+requeued_events_pending_p ()
+{
+  return (!NILP (Vunread_command_events) || unread_command_char != -1);
+}
+
+
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
   "T if command input is currently available with no waiting.\n\
 Actually, the value is nil only if we can be sure that no input is available.")
@@ -6811,7 +7137,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,
@@ -6845,6 +7172,20 @@ The value is a string or a vector.")
                           XVECTOR (this_command_keys)->contents);
 }
 
+DEFUN ("this-single-command-keys", Fthis_single_command_keys,
+       Sthis_single_command_keys, 0, 0, 0,
+  "Return the key sequence that invoked this command.\n\
+Unlike `this-command-keys', this function's value\n\
+does not include prefix arguments.\n\
+The value is a string or a vector.")
+  ()
+{
+  return make_event_array (this_command_key_count
+                          - this_single_command_key_start,
+                          (XVECTOR (this_command_keys)->contents
+                           + this_single_command_key_start));
+}
+
 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\
@@ -6881,18 +7222,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;
 }
@@ -6984,7 +7324,7 @@ stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
 /* stuff_char works only in BSD, versions 4.2 and up.  */
-#ifdef BSD
+#ifdef BSD_SYSTEM
 #ifndef BSD4_1
   register unsigned char *p;
 
@@ -7014,7 +7354,7 @@ stuff_buffered_input (stuffstring)
     }
   input_pending = 0;
 #endif
-#endif /* BSD and not BSD4_1 */
+#endif /* BSD_SYSTEM and not BSD4_1 */
 }
 \f
 set_waiting_for_input (time_to_clear)
@@ -7058,7 +7398,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
 
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
   if (!read_socket_hook && NILP (Vwindow_system))
     {
       /* USG systems forget handlers when they are used;
@@ -7198,12 +7538,10 @@ quit_throw_to_read_char ()
     abort ();
 #endif
 #endif
-#ifdef MULTI_FRAME
   if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     Qnil, 0);
-#endif
 
   _longjmp (getcjmp, 1);
 }
@@ -7368,6 +7706,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;
@@ -7379,12 +7718,10 @@ init_keyboard ()
 #endif
   input_pending = 0;
 
-#ifdef MULTI_FRAME
   /* This means that command_loop_1 won't try to select anything the first
      time through.  */
   internal_last_event_frame = Qnil;
   Vlast_event_frame = internal_last_event_frame;
-#endif
 
 #ifdef MULTI_KBOARD
   current_kboard = initial_kboard;
@@ -7515,6 +7852,10 @@ syms_of_keyboard ()
   staticpro (&Qhandle);
   Qbelow_handle = intern ("below-handle");
   staticpro (&Qbelow_handle);
+  Qup = intern ("up");
+  staticpro (&Qup);
+  Qdown = intern ("down");
+  staticpro (&Qdown);
 
   Qevent_kind = intern ("event-kind");
   staticpro (&Qevent_kind);
@@ -7587,6 +7928,12 @@ syms_of_keyboard ()
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
 
+  internal_last_event_frame = Qnil;
+  staticpro (&internal_last_event_frame);
+
+  read_key_sequence_cmd = Qnil;
+  staticpro (&read_key_sequence_cmd);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Srecursive_edit);
@@ -7597,6 +7944,7 @@ syms_of_keyboard ()
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
+  defsubr (&Sthis_single_command_keys);
   defsubr (&Sreset_this_command_lengths);
   defsubr (&Ssuspend_emacs);
   defsubr (&Sabort_recursive_edit);
@@ -7692,7 +8040,9 @@ by position only.");
   inhibit_local_menu_bar_menus = 0;
 
   DEFVAR_INT ("num-input-keys", &num_input_keys,
-    "Number of complete keys read from the keyboard so far.");
+    "Number of complete key sequences read from the keyboard so far.\n\
+This includes key sequences read from keyboard macros.\n\
+The number is effectively the number of interactive command invocations.");
   num_input_keys = 0;
 
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
@@ -7793,11 +8143,12 @@ Errors running the hook are caught and ignored.");
 
   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.");
+Errors running the hook are caught and ignored.\n\
+This feature is obsolete; use idle timers instead.  See `etc/NEWS'.");
   Vpost_command_idle_hook = Qnil;
 
   DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
-    "Delay time before running `post-command-idle-delay'.\n\
+    "Delay time before running `post-command-idle-hook'.\n\
 This is measured in microseconds.");
   post_command_idle_delay = 100000;
 
@@ -7858,13 +8209,13 @@ 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 timers in order of increasing time");
+    "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 ()