]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Merge from emacs--devo--0
[gnu-emacs] / src / keyboard.c
index 21bd13060c40b30b6dc7548d8a41e00a094fd72a..d843b8fb348934b25c16b7025bc53fc4ad83d8c7 100644 (file)
@@ -33,7 +33,7 @@ Boston, MA 02110-1301, USA.  */
 #include "window.h"
 #include "commands.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "disptab.h"
 #include "dispextern.h"
 #include "syntax.h"
@@ -242,6 +242,9 @@ static int inhibit_local_menu_bar_menus;
 /* Nonzero means C-g should cause immediate error-signal.  */
 int immediate_quit;
 
+/* The user's hook function for outputting an error message.  */
+Lisp_Object Vcommand_error_function;
+
 /* The user's ERASE setting.  */
 Lisp_Object Vtty_erase_char;
 
@@ -649,6 +652,11 @@ static EMACS_TIME timer_idleness_start_time;
 
 static EMACS_TIME timer_last_idleness_start_time;
 
+/* If non-nil, events produced by disabled menu items and tool-bar
+   buttons are not ignored.  Help functions bind this to allow help on
+   those items and buttons.  */
+Lisp_Object Venable_disabled_menus_and_buttons;
+
 \f
 /* Global variable declarations.  */
 
@@ -998,7 +1006,7 @@ recursive_edit_1 ()
   /* 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));
+    xsignal1 (Qerror, val);
 
   return unbind_to (count, Qnil);
 }
@@ -1225,52 +1233,47 @@ cmd_error_internal (data, context)
      Lisp_Object data;
      char *context;
 {
-  Lisp_Object stream;
-  int kill_emacs_p = 0;
   struct frame *sf = SELECTED_FRAME ();
 
+  /* The immediate context is not interesting for Quits,
+     since they are asyncronous.  */
+  if (EQ (XCAR (data), Qquit))
+    Vsignaling_function = Qnil;
+
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
-  clear_message (1, 0);
 
+  /* Use user's specified output function if any.  */
+  if (!NILP (Vcommand_error_function))
+    call3 (Vcommand_error_function, data,
+          build_string (context ? context : ""),
+          Vsignaling_function);
   /* If the window system or terminal frame hasn't been initialized
-     yet, or we're not interactive, it's best to dump this message out
-     to stderr and exit.  */
-  if (!sf->glyphs_initialized_p
-      /* This is the case of the frame dumped with Emacs, when we're
-        running under a window system.  */
-      || (!NILP (Vwindow_system)
-         && !inhibit_window_system
-         && FRAME_TERMCAP_P (sf))
-      || noninteractive)
-    {
-      stream = Qexternal_debugging_output;
-      kill_emacs_p = 1;
+     yet, or we're not interactive, write the message to stderr and exit.  */
+  else if (!sf->glyphs_initialized_p
+          /* This is the case of the frame dumped with Emacs, when we're
+             running under a window system.  */
+          || (!NILP (Vwindow_system)
+              && !inhibit_window_system
+              && FRAME_TERMCAP_P (sf))
+          || noninteractive)
+    {
+      print_error_message (data, Qexternal_debugging_output,
+                          context, Vsignaling_function);
+      Fterpri (Qexternal_debugging_output);
+      Fkill_emacs (make_number (-1));
     }
   else
     {
+      clear_message (1, 0);
       Fdiscard_input ();
       message_log_maybe_newline ();
       bitch_at_user ();
-      stream = Qt;
-    }
 
-  /* The immediate context is not interesting for Quits,
-     since they are asyncronous.  */
-  if (EQ (XCAR (data), Qquit))
-    Vsignaling_function = Qnil;
-
-  print_error_message (data, stream, context, Vsignaling_function);
+      print_error_message (data, Qt, context, Vsignaling_function);
+    }
 
   Vsignaling_function = Qnil;
-
-  /* If the window system or terminal frame hasn't been initialized
-     yet, or we're in -batch mode, this error should cause Emacs to exit.  */
-  if (kill_emacs_p)
-    {
-      Fterpri (stream);
-      Fkill_emacs (make_number (-1));
-    }
 }
 \f
 Lisp_Object command_loop_1 ();
@@ -1384,6 +1387,72 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
   return Qnil;
 }
 \f
+#ifdef HAVE_MOUSE
+
+/* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
+   of this function.  */
+
+static Lisp_Object
+tracking_off (old_value)
+     Lisp_Object old_value;
+{
+  do_mouse_tracking = old_value;
+  if (NILP (old_value))
+    {
+      /* Redisplay may have been preempted because there was input
+        available, and it assumes it will be called again after the
+        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 (READABLE_EVENTS_DO_TIMERS_NOW))
+       {
+         redisplay_preserve_echo_area (6);
+         get_input_pending (&input_pending,
+                            READABLE_EVENTS_DO_TIMERS_NOW);
+       }
+    }
+  return Qnil;
+}
+
+DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
+       doc: /* Evaluate BODY with mouse movement events enabled.
+Within a `track-mouse' form, mouse motion generates input events that
+you can read with `read-event'.
+Normally, mouse motion is ignored.
+usage: (track-mouse BODY ...)  */)
+     (args)
+     Lisp_Object args;
+{
+  int count = SPECPDL_INDEX ();
+  Lisp_Object val;
+
+  record_unwind_protect (tracking_off, do_mouse_tracking);
+
+  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
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
@@ -1413,7 +1482,7 @@ command_loop_1 ()
   Lisp_Object keybuf[30];
   int i;
   int no_direct;
-  int prev_modiff;
+  int prev_modiff = 0;
   struct buffer *prev_buffer = NULL;
 #ifdef MULTI_KBOARD
   int was_locked = single_kboard;
@@ -1485,7 +1554,8 @@ command_loop_1 ()
          int count = SPECPDL_INDEX ();
          specbind (Qinhibit_quit, Qt);
 
-         Fsit_for (Vminibuffer_message_timeout, Qnil, Qnil);
+         sit_for (Vminibuffer_message_timeout, 0, 2);
+
          /* Clear the echo area.  */
          message2 (0, 0, 0);
          safe_run_hooks (Qecho_area_clear_hook);
@@ -1664,7 +1734,7 @@ command_loop_1 ()
                          : (lose >= 0x20 && lose < 0x7f))
                      /* To extract the case of continuation on
                          wide-column characters.  */
-                     && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT_BYTE)) == 1)
+                     && ASCII_BYTE_P (lose)
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1721,7 +1791,7 @@ command_loop_1 ()
                {
                  unsigned int c
                    = translate_char (Vtranslation_table_for_input,
-                                     XFASTINT (last_command_char), 0, 0, 0);
+                                     XFASTINT (last_command_char));
                  int value;
                  if (NILP (Vexecuting_kbd_macro)
                      && !EQ (minibuf_window, selected_window))
@@ -1897,7 +1967,7 @@ adjust_point_for_property (last_pt, modified)
      int last_pt;
      int modified;
 {
-  int beg, end;
+  EMACS_INT beg, end;
   Lisp_Object val, overlay, tmp;
   int check_composition = 1, check_display = 1, check_invisible = 1;
   int orig_pt = PT;
@@ -2028,6 +2098,8 @@ static Lisp_Object
 safe_run_hooks_1 (hook)
      Lisp_Object hook;
 {
+  if (NILP (Vrun_hooks))
+    return Qnil;
   return call1 (Vrun_hooks, Vinhibit_quit);
 }
 
@@ -2301,7 +2373,17 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
 
 #ifdef HAVE_MOUSE
   if (!noninteractive && STRINGP (help))
-    help = call1 (Qmouse_fixup_help_message, help);
+    {
+      /* The mouse-fixup-help-message Lisp function can call
+        mouse_position_hook, which resets the mouse_moved flags.
+        This causes trouble if we are trying to read a mouse motion
+        event (i.e., if we are inside a `track-mouse' form), so we
+        restore the mouse_moved flag.  */
+      FRAME_PTR f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved ();
+      help = call1 (Qmouse_fixup_help_message, help);
+      if (f)
+       f->mouse_moved = 1;
+    }
 #endif
 
   if (STRINGP (help) || NILP (help))
@@ -2381,18 +2463,23 @@ do { if (polling_stopped_here) start_polling ();        \
    if we used a mouse menu to read the input, or zero otherwise.  If
    USED_MOUSE_MENU is null, we don't dereference it.
 
+   If END_TIME is non-null, it is a pointer to an EMACS_TIME
+   specifying the maximum time to wait until.  If no input arrives by
+   that time, stop waiting and return nil.
+
    Value is t if we showed a menu and the user rejected it.  */
 
 Lisp_Object
-read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
+read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu, end_time)
      int commandflag;
      int nmaps;
      Lisp_Object *maps;
      Lisp_Object prev_event;
      int *used_mouse_menu;
+     EMACS_TIME *end_time;
 {
   volatile Lisp_Object c;
-  int count;
+  int count, jmpcount;
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   volatile int key_already_recorded = 0;
@@ -2618,11 +2705,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      around any call to sit_for or kbd_buffer_get_event;
      it *must not* be in effect when we call redisplay.  */
 
+  jmpcount = SPECPDL_INDEX ();
   if (_setjmp (local_getcjmp))
     {
       /* We must have saved the outer value of getcjmp here,
         so restore it now.  */
       restore_getcjmp (save_jump);
+      unbind_to (jmpcount, Qnil);
       XSETINT (c, quit_char);
       internal_last_event_frame = selected_frame;
       Vlast_event_frame = internal_last_event_frame;
@@ -2663,12 +2752,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto non_reread;
     }
 
-  timer_start_idle ();
+  /* Start idle timers if no time limit is supplied.  We don't do it
+     if a time limit is supplied to avoid an infinite recursion in the
+     situation where an idle timer calls `sit-for'.  */
+
+  if (!end_time)
+    timer_start_idle ();
 
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
   if (minibuf_level == 0
+      && !end_time
       && !current_kboard->immediate_echo
       && this_command_key_count > 0
       && ! noninteractive
@@ -2684,8 +2779,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          /* Or not echoing before and echoing allowed.  */
          || (!echo_kboard && ok_to_echo_at_next_pause)))
     {
-      Lisp_Object tem0;
-
       /* After a mouse event, start echoing right away.
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
@@ -2693,13 +2786,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        echo_now ();
       else
        {
-         int sec, usec;
-         double duration = extract_float (Vecho_keystrokes);
-         sec = (int) duration;
-         usec = (duration - sec) * 1000000;
+         Lisp_Object tem0;
+
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (sec, usec, 1, 1, 0);
+         tem0 = sit_for (Vecho_keystrokes, 1, 1);
          restore_getcjmp (save_jump);
          if (EQ (tem0, Qt)
              && ! CONSP (Vunread_command_events))
@@ -2736,7 +2827,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
 
       /* Now that we have read an event, Emacs is not idle.  */
-      timer_stop_idle ();
+      if (!end_time)
+       timer_stop_idle ();
 
       goto exit;
     }
@@ -2766,11 +2858,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
+         int timeout = delay_level * XFASTINT (Vauto_save_timeout) / 4;
 
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
-                         0, 1, 1, 0);
+         tem0 = sit_for (make_number (timeout), 1, 1);
          restore_getcjmp (save_jump);
 
          if (EQ (tem0, Qt)
@@ -2855,11 +2947,20 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       KBOARD *kb;
 
+      if (end_time)
+       {
+         EMACS_TIME now;
+         EMACS_GET_TIME (now);
+         if (EMACS_TIME_GE (now, *end_time))
+           goto exit;
+       }
+
       /* Actually read a character, waiting if necessary.  */
       save_getcjmp (save_jump);
       restore_getcjmp (local_getcjmp);
-      timer_start_idle ();
-      c = kbd_buffer_get_event (&kb, used_mouse_menu);
+      if (!end_time)
+       timer_start_idle ();
+      c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time);
       restore_getcjmp (save_jump);
 
 #ifdef MULTI_KBOARD
@@ -2910,7 +3011,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
-  timer_stop_idle ();
+  if (!end_time)
+    timer_stop_idle ();
   RESUME_POLLING;
 
   if (NILP (c))
@@ -2944,7 +3046,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       last_input_char = c;
       Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
 
-      if (CONSP (c) && EQ (XCAR (c), Qselect_window))
+      if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time)
        /* We stopped being idle for this event; undo that.  This
           prevents automatic window selection (under
           mouse_autoselect_window from acting as a real input event, for
@@ -2970,7 +3072,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          || (VECTORP (Vkeyboard_translate_table)
              && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
          || (CHAR_TABLE_P (Vkeyboard_translate_table)
-             && CHAR_VALID_P (XINT (c), 0)))
+             && CHARACTERP (c)))
        {
          Lisp_Object d;
          d = Faref (Vkeyboard_translate_table, c);
@@ -3150,7 +3252,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       show_help_echo (help, window, object, position, 0);
 
       /* We stopped being idle for this event; undo that.  */
-      timer_resume_idle ();
+      if (!end_time)
+       timer_resume_idle ();
       goto retry;
     }
 
@@ -3196,7 +3299,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       cancel_echoing ();
       do
-       c = read_char (0, 0, 0, Qnil, 0);
+       c = read_char (0, 0, 0, Qnil, 0, NULL);
       while (BUFFERP (c));
       /* Remove the help from the frame */
       unbind_to (count, Qnil);
@@ -3206,7 +3309,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        {
          cancel_echoing ();
          do
-           c = read_char (0, 0, 0, Qnil, 0);
+           c = read_char (0, 0, 0, Qnil, 0, NULL);
          while (BUFFERP (c));
        }
     }
@@ -3434,72 +3537,6 @@ restore_getcjmp (temp)
   bcopy (temp, getcjmp, sizeof getcjmp);
 }
 \f
-#ifdef HAVE_MOUSE
-
-/* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
-   of this function.  */
-
-static Lisp_Object
-tracking_off (old_value)
-     Lisp_Object old_value;
-{
-  do_mouse_tracking = old_value;
-  if (NILP (old_value))
-    {
-      /* Redisplay may have been preempted because there was input
-        available, and it assumes it will be called again after the
-        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 (READABLE_EVENTS_DO_TIMERS_NOW))
-       {
-         redisplay_preserve_echo_area (6);
-         get_input_pending (&input_pending,
-                            READABLE_EVENTS_DO_TIMERS_NOW);
-       }
-    }
-  return Qnil;
-}
-
-DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
-       doc: /* Evaluate BODY with mouse movement events enabled.
-Within a `track-mouse' form, mouse motion generates input events that
-you can read with `read-event'.
-Normally, mouse motion is ignored.
-usage: (track-mouse BODY ...)  */)
-     (args)
-     Lisp_Object args;
-{
-  int count = SPECPDL_INDEX ();
-  Lisp_Object val;
-
-  record_unwind_protect (tracking_off, do_mouse_tracking);
-
-  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.  */
@@ -3885,9 +3922,10 @@ clear_event (event)
    We always read and discard one event.  */
 
 static Lisp_Object
-kbd_buffer_get_event (kbp, used_mouse_menu)
+kbd_buffer_get_event (kbp, used_mouse_menu, end_time)
      KBOARD **kbp;
      int *used_mouse_menu;
+     EMACS_TIME *end_time;
 {
   register int c;
   Lisp_Object obj;
@@ -3931,13 +3969,26 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
 #endif
-      {
+      if (end_time)
+       {
+         EMACS_TIME duration;
+         EMACS_GET_TIME (duration);
+         if (EMACS_TIME_GE (duration, *end_time))
+           return Qnil;        /* finished waiting */
+         else
+           {
+             EMACS_SUB_TIME (duration, *end_time, duration);
+             wait_reading_process_output (EMACS_SECS (duration),
+                                          EMACS_USECS (duration),
+                                          -1, 1, Qnil, NULL, 0);
+           }
+       }
+      else
        wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
 
-       if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
-         /* Pass 1 for EXPECT since we just waited to have input.  */
-         read_avail_input (1);
-      }
+      if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
+       /* Pass 1 for EXPECT since we just waited to have input.  */
+       read_avail_input (1);
 #endif /* not VMS */
     }
 
@@ -4499,6 +4550,32 @@ timer_check (do_it_now)
   UNGCPRO;
   return nexttime;
 }
+
+DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0,
+       doc: /* Return the current length of Emacs idleness.
+The value is returned as a list of three integers.  The first has the
+most significant 16 bits of the seconds, while the second has the
+least significant 16 bits.  The third integer gives the microsecond
+count.
+
+The microsecond count is zero on systems that do not provide
+resolution finer than a second.  */)
+  ()
+{
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    {
+      EMACS_TIME now, idleness_now;
+
+      EMACS_GET_TIME (now);
+      EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+
+      return list3 (make_number ((EMACS_SECS (idleness_now) >> 16) & 0xffff),
+                   make_number ((EMACS_SECS (idleness_now) >> 0)  & 0xffff),
+                   make_number (EMACS_USECS (idleness_now)));
+    }
+
+  return Qnil;
+}
 \f
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
@@ -5876,8 +5953,7 @@ make_lispy_event (event)
        spec[1] = event->y;
        return Fcons (Qmac_apple_event,
                      Fcons (Fvector (2, spec),
-                            Fcons (mac_make_lispy_event_code (event->code),
-                                   Qnil)));
+                            Fcons (event->arg, Qnil)));
       }
 #endif
 
@@ -7271,7 +7347,9 @@ parse_menu_item (item, notreal, inmenubar)
       if (SYMBOLP (item))
        {
          tem = Fget (item, Qmenu_enable);
-         if (!NILP (tem))
+         if (!NILP (Venable_disabled_menus_and_buttons))
+           AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
+         else if (!NILP (tem))
            AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
        }
     }
@@ -7300,7 +7378,12 @@ parse_menu_item (item, notreal, inmenubar)
              item = XCDR (item);
 
              if (EQ (tem, QCenable))
-               AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
+               {
+                 if (!NILP (Venable_disabled_menus_and_buttons))
+                   AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
+                 else
+                   AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
+               }
              else if (EQ (tem, QCvisible) && !notreal)
                {
                  /* If got a visible property and that evaluates to nil
@@ -7569,7 +7652,7 @@ Lisp_Object QCimage;
 /* Function prototypes.  */
 
 static void init_tool_bar_items P_ ((Lisp_Object));
-static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*));
 static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
 static void append_tool_bar_item P_ ((void));
 
@@ -7647,17 +7730,7 @@ tool_bar_items (reuse, nitems)
 
        keymap = get_keymap (access_keymap (maps[i], Qtool_bar, 1, 0, 1), 0, 1);
        if (CONSP (keymap))
-         {
-           Lisp_Object tail;
-
-           /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
-           for (tail = keymap; CONSP (tail); tail = XCDR (tail))
-             {
-               Lisp_Object keydef = XCAR (tail);
-               if (CONSP (keydef))
-                 process_tool_bar_item (XCAR (keydef), XCDR (keydef));
-             }
-         }
+         map_keymap (keymap, process_tool_bar_item, Qnil, NULL, 1);
       }
 
   Vinhibit_quit = oquit;
@@ -7669,8 +7742,9 @@ tool_bar_items (reuse, nitems)
 /* Process the definition of KEY which is DEF.  */
 
 static void
-process_tool_bar_item (key, def)
-     Lisp_Object key, def;
+process_tool_bar_item (key, def, data, args)
+     Lisp_Object key, def, data;
+     void *args;
 {
   int i;
   extern Lisp_Object Qundefined;
@@ -7820,8 +7894,13 @@ parse_tool_bar_item (key, item)
       value = XCAR (XCDR (item));
 
       if (EQ (key, QCenable))
-       /* `:enable FORM'.  */
-       PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+       {
+         /* `:enable FORM'.  */
+         if (!NILP (Venable_disabled_menus_and_buttons))
+           PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
+         else
+           PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+       }
       else if (EQ (key, QCvisible))
        {
          /* `:visible FORM'.  If got a visible property and that
@@ -8280,7 +8359,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
       orig_defn_macro = current_kboard->defining_kbd_macro;
       current_kboard->defining_kbd_macro = Qnil;
       do
-       obj = read_char (commandflag, 0, 0, Qt, 0);
+       obj = read_char (commandflag, 0, 0, Qt, 0, NULL);
       while (BUFFERP (obj));
       current_kboard->defining_kbd_macro = orig_defn_macro;
 
@@ -8351,7 +8430,15 @@ follow_key (key, nmaps, current, defs, next)
    such as Vfunction_key_map and Vkey_translation_map.  */
 typedef struct keyremap
 {
-  Lisp_Object map, parent;
+  /* This is the map originally specified for this use.  */
+  Lisp_Object parent;
+  /* This is a submap reached by looking up, in PARENT,
+     the events from START to END.  */
+  Lisp_Object map;
+  /* Positions [START, END) in the key sequence buffer
+     are the key that we have scanned so far.
+     Those events are the ones that we will replace
+     if PAREHT maps them into a key sequence.  */
   int start, end;
 } keyremap;
 
@@ -8380,7 +8467,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall)
   /* Handle a symbol whose function definition is a keymap
      or an array.  */
   if (SYMBOLP (next) && !NILP (Ffboundp (next))
-      && (!NILP (Farrayp (XSYMBOL (next)->function))
+      && (ARRAYP (XSYMBOL (next)->function)
          || KEYMAPP (XSYMBOL (next)->function)))
     next = XSYMBOL (next)->function;
 
@@ -8424,7 +8511,11 @@ keyremap_step (keybuf, bufsize, fkey, input, doit, diff, prompt)
   Lisp_Object next, key;
 
   key = keybuf[fkey->end++];
-  next = access_keymap_keyremap (fkey->map, key, prompt, doit);
+
+  if (KEYMAPP (fkey->parent))
+    next = access_keymap_keyremap (fkey->map, key, prompt, doit);
+  else
+    next = Qnil;
 
   /* If keybuf[fkey->start..fkey->end] is bound in the
      map and we're in a position to do the key remapping, replace it with
@@ -8622,9 +8713,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   delayed_switch_frame = Qnil;
   fkey.map = fkey.parent = Vfunction_key_map;
   keytran.map = keytran.parent = Vkey_translation_map;
-  /* If there is no translation-map, turn off scanning.  */
-  fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
-  keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
+  fkey.start = fkey.end = 0;
+  keytran.start = keytran.end = 0;
 
   if (INTERACTIVE)
     {
@@ -8653,7 +8743,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Read the first char of the sequence specially, before setting
      up any keymaps, in case a filter runs and switches buffers on us.  */
   first_event = read_char (NILP (prompt), 0, submaps, last_nonmenu_event,
-                          &junk);
+                          &junk, NULL);
 #endif /* GOBBLE_FIRST_EVENT */
 
   orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
@@ -8856,7 +8946,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 #endif
            key = read_char (NILP (prompt), nmaps,
                             (Lisp_Object *) submaps, last_nonmenu_event,
-                            &used_mouse_menu);
+                            &used_mouse_menu, NULL);
          }
 
          /* read_char returns t when it shows a menu and the user rejects it.
@@ -9402,9 +9492,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (first_binding >= nmaps
          && fkey.start >= t && keytran.start >= t
          && INTEGERP (key)
-         && ((((XINT (key) & 0x3ffff)
-               < XCHAR_TABLE (current_buffer->downcase_table)->size)
-              && UPPERCASEP (XINT (key) & 0x3ffff))
+         && ((CHARACTERP (make_number (XINT (key) & ~CHAR_MODIFIER_MASK))
+              && UPPERCASEP (XINT (key) & ~CHAR_MODIFIER_MASK))
              || (XINT (key) & shift_modifier)))
        {
          Lisp_Object new_key;
@@ -9415,8 +9504,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (XINT (key) & shift_modifier)
            XSETINT (new_key, XINT (key) & ~shift_modifier);
          else
-           XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
-                              | (XINT (key) & ~0x3ffff)));
+           XSETINT (new_key, (DOWNCASE (XINT (key) & ~CHAR_MODIFIER_MASK)
+                              | (XINT (key) & ~CHAR_MODIFIER_MASK)));
 
          /* We have to do this unconditionally, regardless of whether
             the lower-case char is defined in the keymaps, because they
@@ -9452,8 +9541,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              keybuf[t - 1] = new_key;
              mock_input = max (t, mock_input);
-             fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
-             keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
+             fkey.start = fkey.end = 0;
+             keytran.start = keytran.end = 0;
 
              goto replay_sequence;
            }
@@ -9471,6 +9560,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
   if ((dont_downcase_last || first_binding >= nmaps)
+      && t > 0
       && t - 1 == original_uppercase_position)
     keybuf[t - 1] = original_uppercase;
 
@@ -9700,7 +9790,7 @@ a special event, so ignore the prefix argument and don't clear it.  */)
 
   while (1)
     {
-      final = Findirect_function (cmd);
+      final = Findirect_function (cmd, Qnil);
 
       if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
        {
@@ -9760,7 +9850,13 @@ a special event, so ignore the prefix argument and don't clear it.  */)
 \f
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
        1, 1, "P",
-       doc: /* Read function name, then read its arguments and call it.  */)
+       doc: /* Read function name, then read its arguments and call it.
+
+To pass a numeric argument to the command you are invoking with, specify
+the numeric argument to this command.
+
+Noninteractively, the argument PREFIXARG is the prefix argument to
+give to the command you invoke, if it asks for an argument.  */)
      (prefixarg)
      Lisp_Object prefixarg;
 {
@@ -9866,19 +9962,18 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                                      Qmouse_movement)))
     {
       /* But first wait, and skip the message if there is input.  */
-      int delay_time;
-      if (!NILP (echo_area_buffer[0]))
-       /* This command displayed something in the echo area;
-          so wait a few seconds, then display our suggestion message.  */
-       delay_time = (NUMBERP (Vsuggest_key_bindings)
-                     ? XINT (Vsuggest_key_bindings) : 2);
+      Lisp_Object waited;
+
+      /* If this command displayed something in the echo area;
+        wait a few seconds, then display our suggestion message.  */
+      if (NILP (echo_area_buffer[0]))
+       waited = sit_for (make_number (0), 0, 2);
+      else if (NUMBERP (Vsuggest_key_bindings))
+       waited = sit_for (Vminibuffer_message_timeout, 0, 2);
       else
-       /* This command left the echo area empty,
-          so display our message immediately.  */
-       delay_time = 0;
+       waited = sit_for (make_number (2), 0, 2);
 
-      if (!NILP (Fsit_for (make_number (delay_time), Qnil, Qnil))
-         && ! CONSP (Vunread_command_events))
+      if (!NILP (waited) && ! CONSP (Vunread_command_events))
        {
          Lisp_Object binding;
          char *newmessage;
@@ -9898,10 +9993,12 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          message2_nolog (newmessage,
                          strlen (newmessage),
                          STRING_MULTIBYTE (binding));
-         if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
-                               ? Vsuggest_key_bindings : make_number (2)),
-                              Qnil, Qnil))
-             && message_p)
+         if (NUMBERP (Vsuggest_key_bindings))
+           waited = sit_for (Vsuggest_key_bindings, 0, 2);
+         else
+           waited = sit_for (make_number (2), 0, 2);
+
+         if (!NILP (waited) && message_p)
            restore_message ();
 
          unbind_to (count, Qnil);
@@ -11062,6 +11159,7 @@ syms_of_keyboard ()
   menu_bar_items_vector = Qnil;
   staticpro (&menu_bar_items_vector);
 
+  defsubr (&Scurrent_idle_time);
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
@@ -11119,14 +11217,16 @@ These events are processed first, before actual keyboard input.  */);
 
   DEFVAR_LISP ("unread-post-input-method-events", &Vunread_post_input_method_events,
               doc: /* List of events to be processed as input by input methods.
-These events are processed after `unread-command-events', but
-before actual keyboard input.  */);
+These events are processed before `unread-command-events'
+and actual keyboard input without given to `input-method-function'.  */);
   Vunread_post_input_method_events = Qnil;
 
   DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,
               doc: /* List of events to be processed as input by input methods.
 These events are processed after `unread-command-events', but
-before actual keyboard input.  */);
+before actual keyboard input.
+If there's an active input method, the events are given to
+`input-method-function'.  */);
   Vunread_input_method_events = Qnil;
 
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
@@ -11471,6 +11571,23 @@ If the value is not a number, such messages don't time out.  */);
 The value of that variable is passed to `quit-flag' and later causes a
 peculiar kind of quitting.  */);
   Vthrow_on_input = Qnil;
+
+  DEFVAR_LISP ("command-error-function", &Vcommand_error_function,
+              doc: /* If non-nil, function to output error messages.
+The arguments are the error data, a list of the form
+ (SIGNALED-CONDITIONS . SIGNAL-DATA)
+such as just as `condition-case' would bind its variable to,
+the context (a string which normally goes at the start of the message),
+and the Lisp function within which the error was signaled.  */);
+  Vcommand_error_function = Qnil;
+
+  DEFVAR_LISP ("enable-disabled-menus-and-buttons",
+              &Venable_disabled_menus_and_buttons,
+              doc: /* If non-nil, don't ignore events produced by disabled menu items and tool-bar.
+
+Help functions bind this to allow help on disabled menu items
+and tool-bar buttons.  */);
+  Venable_disabled_menus_and_buttons = Qnil;
 }
 
 void