]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
*** empty log message ***
[gnu-emacs] / src / keyboard.c
index 0eb82533120cd172bf2d2a014eb041eb4998d3ef..364fa893539e09cf0e4f30b34a777ebf14d2f58b 100644 (file)
@@ -1,6 +1,7 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995, 1996, 1997,
-     1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
+                 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include <signal.h>
@@ -241,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;
 
@@ -380,12 +384,15 @@ Lisp_Object real_this_command;
    command is stored in this-original-command.  It is nil otherwise.  */
 Lisp_Object Vthis_original_command;
 
-/* The value of point when the last command was executed.  */
+/* The value of point when the last command was started.  */
 int last_point_position;
 
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
+/* The window that was selected when the last command was started.  */
+Lisp_Object last_point_position_window;
+
 /* 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
@@ -450,11 +457,6 @@ Lisp_Object Qecho_area_clear_hook;
 Lisp_Object Qpre_command_hook, Vpre_command_hook;
 Lisp_Object Qpost_command_hook, Vpost_command_hook;
 Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
-/* Hook run after a command if there's no more input soon.  */
-Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
-
-/* Delay time in microseconds before running post-command-idle-hook.  */
-EMACS_INT post_command_idle_delay;
 
 /* List of deferred actions to be performed at a later time.
    The precise format isn't relevant here; we just check whether it is nil.  */
@@ -478,10 +480,6 @@ int input_pending;
 
 int meta_key;
 
-/* Non-zero means force key bindings update in parse_menu_item.  */
-
-int update_menu_bindings;
-
 extern char *pending_malloc_warning;
 
 /* Circular buffer for pre-read keyboard input.  */
@@ -530,11 +528,14 @@ Lisp_Object Qmouse_fixup_help_message;
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
 Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
 Lisp_Object Qsave_session;
+#ifdef MAC_OS
+Lisp_Object Qmac_apple_event;
+#endif
 
 /* Lisp_Object Qmouse_movement; - also an event header */
 
@@ -651,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.  */
 
@@ -792,6 +798,8 @@ echo_char (c)
          else
            echo_string = concat2 (echo_string, build_string (" "));
        }
+      else if (STRINGP (echo_string))
+       echo_string = concat2 (echo_string, build_string (" "));
 
       current_kboard->echo_string
        = concat2 (echo_string, make_string (buffer, ptr - buffer));
@@ -822,16 +830,16 @@ echo_dash ()
   /* Do nothing if we have already put a dash at the end.  */
   if (SCHARS (current_kboard->echo_string) > 1)
     {
-         Lisp_Object last_char, prev_char, idx;
+      Lisp_Object last_char, prev_char, idx;
 
-         idx = make_number (SCHARS (current_kboard->echo_string) - 2);
-         prev_char = Faref (current_kboard->echo_string, idx);
+      idx = make_number (SCHARS (current_kboard->echo_string) - 2);
+      prev_char = Faref (current_kboard->echo_string, idx);
 
-         idx = make_number (SCHARS (current_kboard->echo_string) - 1);
-         last_char = Faref (current_kboard->echo_string, idx);
+      idx = make_number (SCHARS (current_kboard->echo_string) - 1);
+      last_char = Faref (current_kboard->echo_string, idx);
 
-         if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
-           return;
+      if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
+       return;
     }
 
   /* Put a dash at the end of the buffer temporarily,
@@ -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);
 }
@@ -1025,7 +1033,7 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
        doc: /* Invoke the editor command loop recursively.
 To get out of the recursive edit, a command can do `(throw 'exit nil)';
 that tells this function to return.
-Alternately, `(throw 'exit t)' makes this function signal an error.
+Alternatively, `(throw 'exit t)' makes this function signal an error.
 This function is called by the editor initialization to begin editing.  */)
      ()
 {
@@ -1173,21 +1181,21 @@ cmd_error (data)
     cancel_hourglass ();
 #endif
 
-  if (!NILP (executing_macro))
+  if (!NILP (executing_kbd_macro))
     {
-      if (executing_macro_iterations == 1)
+      if (executing_kbd_macro_iterations == 1)
        sprintf (macroerror, "After 1 kbd macro iteration: ");
       else
        sprintf (macroerror, "After %d kbd macro iterations: ",
-                executing_macro_iterations);
+                executing_kbd_macro_iterations);
     }
   else
     *macroerror = 0;
 
   Vstandard_output = Qt;
   Vstandard_input = Qt;
-  Vexecuting_macro = Qnil;
-  executing_macro = Qnil;
+  Vexecuting_kbd_macro = Qnil;
+  executing_kbd_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
   current_kboard->Vlast_prefix_arg = Qnil;
   cancel_echoing ();
@@ -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 ();
@@ -1288,7 +1291,7 @@ command_loop ()
     {
       Lisp_Object val;
       val = internal_catch (Qexit, command_loop_2, Qnil);
-      executing_macro = Qnil;
+      executing_kbd_macro = Qnil;
       return val;
     }
   else
@@ -1300,7 +1303,7 @@ command_loop ()
           other reason.  */
        any_kboard_state ();
        internal_catch (Qtop_level, command_loop_2, Qnil);
-       executing_macro = Qnil;
+       executing_kbd_macro = Qnil;
 
        /* End of file in -batch run causes exit here.  */
        if (noninteractive)
@@ -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;
@@ -1447,20 +1516,8 @@ command_loop_1 ()
 
       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 (Vunread_input_method_events)
-             && NILP (Vunread_post_input_method_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
     }
 
-  Vmemory_full = Qnil;
-
   /* Do this after running Vpost_command_hook, for consistency.  */
   current_kboard->Vlast_command = Vthis_command;
   current_kboard->Vreal_last_command = real_this_command;
@@ -1489,15 +1546,18 @@ command_loop_1 ()
 
       if (minibuf_level
          && !NILP (echo_area_buffer[0])
-         && EQ (minibuf_window, echo_area_window)
-         && NUMBERP (Vminibuffer_message_timeout))
+         && EQ (minibuf_window, echo_area_window))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
          int count = SPECPDL_INDEX ();
          specbind (Qinhibit_quit, Qt);
 
-         Fsit_for (Vminibuffer_message_timeout, Qnil, Qnil);
+         if (NUMBERP (Vminibuffer_message_timeout))
+           sit_for (Vminibuffer_message_timeout, 0, 2);
+         else
+           sit_for (Qt, 0, 2);
+
          /* Clear the echo area.  */
          message2 (0, 0, 0);
          safe_run_hooks (Qecho_area_clear_hook);
@@ -1524,7 +1584,7 @@ command_loop_1 ()
         Is this a good idea?  */
       if (FRAMEP (internal_last_event_frame)
          && !EQ (internal_last_event_frame, selected_frame))
-       Fselect_frame (internal_last_event_frame, Qnil);
+       Fselect_frame (internal_last_event_frame);
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
@@ -1537,6 +1597,7 @@ command_loop_1 ()
 
       Vthis_command = Qnil;
       real_this_command = Qnil;
+      Vthis_original_command = Qnil;
 
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
@@ -1582,11 +1643,11 @@ command_loop_1 ()
        }
 
       cmd = read_key_sequence_cmd;
-      if (!NILP (Vexecuting_macro))
+      if (!NILP (Vexecuting_kbd_macro))
        {
          if (!NILP (Vquit_flag))
            {
-             Vexecuting_macro = Qt;
+             Vexecuting_kbd_macro = Qt;
              QUIT;             /* Make some noise. */
                                /* Will return since macro now empty. */
            }
@@ -1597,6 +1658,7 @@ command_loop_1 ()
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
+      last_point_position_window = selected_window;
       XSETBUFFER (last_point_position_buffer, prev_buffer);
 
       /* By default, we adjust point to a boundary of a region that
@@ -1614,7 +1676,7 @@ command_loop_1 ()
       if (SYMBOLP (cmd))
        {
          Lisp_Object cmd1;
-         if (cmd1 = Fcommand_remapping (cmd), !NILP (cmd1))
+         if (cmd1 = Fcommand_remapping (cmd, Qnil), !NILP (cmd1))
            cmd = cmd1;
        }
 
@@ -1685,7 +1747,7 @@ command_loop_1 ()
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
-                     && NILP (Vexecuting_macro))
+                     && NILP (Vexecuting_kbd_macro))
                    direct_output_forward_char (1);
                  goto directly_done;
                }
@@ -1720,7 +1782,7 @@ command_loop_1 ()
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
-                     && NILP (Vexecuting_macro))
+                     && NILP (Vexecuting_kbd_macro))
                    direct_output_forward_char (-1);
                  goto directly_done;
                }
@@ -1733,7 +1795,7 @@ command_loop_1 ()
                    = translate_char (Vtranslation_table_for_input,
                                      XFASTINT (last_command_char), 0, 0, 0);
                  int value;
-                 if (NILP (Vexecuting_macro)
+                 if (NILP (Vexecuting_kbd_macro)
                      && !EQ (minibuf_window, selected_window))
                    {
                      if (!nonundocount || nonundocount >= 20)
@@ -1755,7 +1817,7 @@ command_loop_1 ()
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
                          || !NILP (XWINDOW (selected_window)->column_number_displayed)
-                         || !NILP (Vexecuting_macro));
+                         || !NILP (Vexecuting_kbd_macro));
 
                  value = internal_self_insert (c, 0);
 
@@ -1783,7 +1845,7 @@ command_loop_1 ()
             int scount = SPECPDL_INDEX ();
 
             if (display_hourglass_p
-                && NILP (Vexecuting_macro))
+                && NILP (Vexecuting_kbd_macro))
               {
                 record_unwind_protect (cancel_hourglass_unwind, Qnil);
                 start_hourglass ();
@@ -1801,7 +1863,7 @@ command_loop_1 ()
             hourglass cursor anyway.
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
-         if (NILP (Vexecuting_macro))
+         if (NILP (Vexecuting_kbd_macro))
             unbind_to (scount, Qnil);
 #endif
           }
@@ -1822,16 +1884,6 @@ command_loop_1 ()
       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 (Vunread_input_method_events)
-             && NILP (Vunread_post_input_method_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
-
       /* If 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,
@@ -1947,10 +1999,13 @@ adjust_point_for_property (last_pt, modified)
              ? get_property_and_range (PT, Qdisplay, &val, &beg, &end, Qnil)
              : (beg = OVERLAY_POSITION (OVERLAY_START (overlay)),
                 end = OVERLAY_POSITION (OVERLAY_END (overlay))))
-         && beg < PT) /* && end > PT   <- It's always the case.  */
+         && (beg < PT /* && end > PT   <- It's always the case.  */
+             || (beg <= PT && STRINGP (val) && SCHARS (val) == 0)))
        {
          xassert (end > PT);
-         SET_PT (PT < last_pt ? beg : end);
+         SET_PT (PT < last_pt
+                 ? (STRINGP (val) && SCHARS (val) == 0 ? beg - 1 : beg)
+                 : end);
          check_composition = check_invisible = 1;
        }
       check_display = 0;
@@ -2045,6 +2100,8 @@ static Lisp_Object
 safe_run_hooks_1 (hook)
      Lisp_Object hook;
 {
+  if (NILP (Vrun_hooks))
+    return Qnil;
   return call1 (Vrun_hooks, Vinhibit_quit);
 }
 
@@ -2318,7 +2375,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))
@@ -2398,18 +2465,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;
@@ -2465,6 +2537,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       c = XCAR (Vunread_command_events);
       Vunread_command_events = XCDR (Vunread_command_events);
 
+      reread = 1;
+
+      /* Undo what sit-for did when it unread additional keys
+        inside universal-argument.  */
+
+      if (CONSP (c)
+         && EQ (XCAR (c), Qt))
+       {
+         reread = 0;
+         c = XCDR (c);
+       }
+
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
       if (CONSP (c)
@@ -2478,7 +2562,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar)))
        *used_mouse_menu = 1;
 
-      reread = 1;
       goto reread_for_input_method;
     }
 
@@ -2499,7 +2582,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   this_command_key_count_reset = 0;
 
-  if (!NILP (Vexecuting_macro))
+  if (!NILP (Vexecuting_kbd_macro))
     {
       /* We set this to Qmacro; since that's not a frame, nobody will
         try to switch frames on us, and the selected window will
@@ -2516,19 +2599,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Exit the macro if we are at the end.
         Also, some things replace the macro with t
         to force an early exit.  */
-      if (EQ (Vexecuting_macro, Qt)
-         || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
+      if (EQ (Vexecuting_kbd_macro, Qt)
+         || executing_kbd_macro_index >= XFASTINT (Flength (Vexecuting_kbd_macro)))
        {
          XSETINT (c, -1);
          goto exit;
        }
 
-      c = Faref (Vexecuting_macro, make_number (executing_macro_index));
-      if (STRINGP (Vexecuting_macro)
+      c = Faref (Vexecuting_kbd_macro, make_number (executing_kbd_macro_index));
+      if (STRINGP (Vexecuting_kbd_macro)
          && (XINT (c) & 0x80) && (XUINT (c) <= 0xff))
        XSETFASTINT (c, CHAR_META | (XINT (c) & ~0x80));
 
-      executing_macro_index++;
+      executing_kbd_macro_index++;
 
       goto from_macro;
     }
@@ -2635,8 +2718,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;
@@ -2677,12 +2765,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
@@ -2698,8 +2792,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.  */
@@ -2707,13 +2799,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))
@@ -2750,7 +2840,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;
     }
@@ -2780,11 +2871,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)
@@ -2869,11 +2960,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
@@ -2924,7 +3024,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))
@@ -2958,7 +3059,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
@@ -3164,12 +3265,14 @@ 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;
     }
 
-  if (! reread || this_command_key_count == 0
-      || this_command_key_count_reset)
+  if ((! reread || this_command_key_count == 0
+       || this_command_key_count_reset)
+      && !end_time)
     {
 
       /* Don't echo mouse motion events.  */
@@ -3210,7 +3313,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);
@@ -3220,7 +3323,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));
        }
     }
@@ -3448,72 +3551,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.  */
@@ -3531,9 +3568,11 @@ readable_events (flags)
      READABLE_EVENTS_FILTER_EVENTS is set, report it as empty.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
     {
-      int have_live_event = 1;
-
-      if (flags & READABLE_EVENTS_FILTER_EVENTS)
+      if (flags & (READABLE_EVENTS_FILTER_EVENTS
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                  | READABLE_EVENTS_IGNORE_SQUEEZABLES
+#endif
+                  ))
         {
           struct input_event *event;
 
@@ -3541,16 +3580,29 @@ readable_events (flags)
                    ? kbd_fetch_ptr
                    : kbd_buffer);
 
-          while (have_live_event && event->kind == FOCUS_IN_EVENT)
-            {
-              event++;
+         do
+           {
+             if (!(
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                   (flags & READABLE_EVENTS_FILTER_EVENTS) &&
+#endif
+                   event->kind == FOCUS_IN_EVENT)
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                 && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+                      && event->kind == SCROLL_BAR_CLICK_EVENT
+                      && event->part == scroll_bar_handle
+                      && event->modifiers == 0)
+#endif
+                 )
+               return 1;
+             event++;
               if (event == kbd_buffer + KBD_BUFFER_SIZE)
                 event = kbd_buffer;
-              if (event == kbd_store_ptr)
-                have_live_event = 0;
-            }
+           }
+         while (event != kbd_store_ptr);
         }
-      if (have_live_event) return 1;
+      else
+       return 1;
     }
 
 #ifdef HAVE_MOUSE
@@ -3884,9 +3936,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;
@@ -3930,13 +3983,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 */
     }
 
@@ -4004,7 +4070,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          kbd_fetch_ptr = event + 1;
        }
 #endif
-#if defined (HAVE_X11) || defined (HAVE_NTGUI)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
       else if (event->kind == ICONIFY_EVENT)
        {
          /* Make an event (iconify-frame (FRAME)).  */
@@ -4036,11 +4102,16 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
       else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
+#ifdef MAC_OS
+         /* Make an event (language-change (KEY_SCRIPT)).  */
+         obj = Fcons (make_number (event->code), Qnil);
+#else
          /* Make an event (language-change (FRAME CHARSET LCID)).  */
          obj = Fcons (event->frame_or_window, Qnil);
+#endif
          obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
@@ -4493,6 +4564,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;
@@ -5055,7 +5152,11 @@ make_lispy_position (f, x, y, time)
       XSETINT (*x, wx);
       XSETINT (*y, wy);
 
-      if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
+      if (part == ON_TEXT)
+       {
+         wx += WINDOW_LEFT_MARGIN_WIDTH (w);
+       }
+      else if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
        {
          /* Mode line or header line.  Look for a string under
             the mouse that may have a `local-map' property.  */
@@ -5091,20 +5192,37 @@ make_lispy_position (f, x, y, time)
                                         &object, &dx, &dy, &width, &height);
          if (STRINGP (string))
            string_info = Fcons (string, make_number (charpos));
+         if (part == ON_LEFT_MARGIN)
+           wx = 0;
+         else
+           wx = window_box_right_offset (w, TEXT_AREA) - 1;
+       }
+      else if (part == ON_LEFT_FRINGE)
+       {
+         posn = Qleft_fringe;
+         rx = 0;
+         dx = wx;
+         wx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+               ? 0
+               : window_box_width (w, LEFT_MARGIN_AREA));
+         dx -= wx;
        }
-      else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+      else if (part == ON_RIGHT_FRINGE)
        {
-         posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : Qright_fringe;
+         posn = Qright_fringe;
          rx = 0;
          dx = wx;
-         if (part == ON_RIGHT_FRINGE)
-           dx -= (window_box_width (w, LEFT_MARGIN_AREA)
-                  + window_box_width (w, TEXT_AREA)
-                  + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-                     ? window_box_width (w, RIGHT_MARGIN_AREA)
-                     : 0));
-         else if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
-           dx -= window_box_width (w, LEFT_MARGIN_AREA);
+         wx = (window_box_width (w, LEFT_MARGIN_AREA)
+               + window_box_width (w, TEXT_AREA)
+               + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                  ? window_box_width (w, RIGHT_MARGIN_AREA)
+                  : 0));
+         dx -= wx;
+       }
+      else
+       {
+         /* Note: We have no special posn for part == ON_SCROLL_BAR.  */
+         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
        }
 
       if (textpos < 0)
@@ -5113,7 +5231,6 @@ make_lispy_position (f, x, y, time)
          struct display_pos p;
          int dx2, dy2;
          int width2, height2;
-         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
          string2 = buffer_posn_from_coords (w, &wx, &wy, &p,
                                             &object2, &dx2, &dy2,
                                             &width2, &height2);
@@ -5508,13 +5625,23 @@ make_lispy_event (event)
                if (CONSP (down)
                    && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down)))
                  {
-                   xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down));
-                   ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down));
+                   xdiff = XINT (event->x) - XINT (XCAR (down));
+                   ydiff = XINT (event->y) - XINT (XCDR (down));
                  }
 
                if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz
-                   && ydiff < double_click_fuzz
-                   && ydiff > - double_click_fuzz)
+                   && ydiff < double_click_fuzz && ydiff > - double_click_fuzz
+                 /* Maybe the mouse has moved a lot, caused scrolling, and
+                    eventually ended up at the same screen position (but
+                    not buffer position) in which case it is a drag, not
+                    a click.  */
+                   /* FIXME: OTOH if the buffer position has changed
+                      because of a timer or process filter rather than
+                      because of mouse movement, it should be considered as
+                      a click.  But mouse-drag-region completely ignores
+                      this case and it hasn't caused any real problem, so
+                      it's probably OK to ignore it as well.  */
+                   && EQ (Fcar (Fcdr (start_pos)), Fcar (Fcdr (position))))
                  /* Mouse hasn't moved (much).  */
                  event->modifiers |= click_modifier;
                else
@@ -5775,14 +5902,8 @@ make_lispy_event (event)
        Lisp_Object head, position;
        Lisp_Object files;
 
-       /* The frame_or_window field should be a cons of the frame in
-          which the event occurred and a list of the filenames
-          dropped.  */
-       if (! CONSP (event->frame_or_window))
-         abort ();
-
-       f = XFRAME (XCAR (event->frame_or_window));
-       files = XCDR (event->frame_or_window);
+       f = XFRAME (event->frame_or_window);
+       files = event->arg;
 
        /* Ignore mouse events that were made on frames that
           have been deleted.  */
@@ -5837,6 +5958,19 @@ make_lispy_event (event)
     case SAVE_SESSION_EVENT:
       return Qsave_session;
 
+#ifdef MAC_OS
+    case MAC_APPLE_EVENT:
+      {
+       Lisp_Object spec[2];
+
+       spec[0] = event->x;
+       spec[1] = event->y;
+       return Fcons (Qmac_apple_event,
+                     Fcons (Fvector (2, spec),
+                            Fcons (event->arg, Qnil)));
+      }
+#endif
+
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -6540,7 +6674,7 @@ lucid_event_type_list_p (object)
    If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal
    events (FOCUS_IN_EVENT).
    If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
-   movements. */
+   movements and toolkit scroll bar thumb drags. */
 
 static void
 get_input_pending (addr, flags)
@@ -6915,8 +7049,6 @@ menu_bar_items (old)
 
   int i;
 
-  struct gcpro gcpro1;
-
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -6932,8 +7064,6 @@ menu_bar_items (old)
     menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
   menu_bar_items_index = 0;
 
-  GCPRO1 (menu_bar_items_vector);
-
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -7037,7 +7167,6 @@ menu_bar_items (old)
   menu_bar_items_index = i;
 
   Vinhibit_quit = oquit;
-  UNGCPRO;
   return menu_bar_items_vector;
 }
 \f
@@ -7232,7 +7361,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;
        }
     }
@@ -7261,7 +7392,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
@@ -7394,7 +7530,7 @@ parse_menu_item (item, notreal, inmenubar)
       Lisp_Object prefix;
 
       if (!NILP (tem))
-       tem = Fkey_binding (tem, Qnil, Qnil);
+       tem = Fkey_binding (tem, Qnil, Qnil, Qnil);
 
       prefix = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
       if (CONSP (prefix))
@@ -7405,9 +7541,7 @@ parse_menu_item (item, notreal, inmenubar)
       else
        def = AREF (item_properties, ITEM_PROPERTY_DEF);
 
-      if (!update_menu_bindings)
-       chkcache = 0;
-      else if (NILP (XCAR (cachelist))) /* Have no saved key.  */
+      if (NILP (XCAR (cachelist))) /* Have no saved key.  */
        {
          if (newcache          /* Always check first time.  */
              /* Should we check everything when precomputing key
@@ -7532,7 +7666,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));
 
@@ -7610,17 +7744,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;
@@ -7632,8 +7756,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;
@@ -7783,8 +7908,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
@@ -8243,7 +8373,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;
 
@@ -8314,7 +8444,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;
 
@@ -8343,7 +8481,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;
 
@@ -8387,7 +8525,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
@@ -8585,9 +8727,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)
     {
@@ -8616,7 +8757,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);
@@ -8638,17 +8779,25 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      the initial keymaps from the current buffer.  */
   nmaps = 0;
 
-  if (!NILP (current_kboard->Voverriding_terminal_local_map)
-      || !NILP (Voverriding_local_map))
+  if (!NILP (current_kboard->Voverriding_terminal_local_map))
     {
-      if (3 > nmaps_allocated)
+      if (2 > nmaps_allocated)
        {
-         submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
-         defs    = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
-         nmaps_allocated = 3;
+         submaps = (Lisp_Object *) alloca (2 * sizeof (submaps[0]));
+         defs    = (Lisp_Object *) alloca (2 * sizeof (defs[0]));
+         nmaps_allocated = 2;
        }
       if (!NILP (current_kboard->Voverriding_terminal_local_map))
        submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+    }
+  else if (!NILP (Voverriding_local_map))
+    {
+      if (2 > nmaps_allocated)
+       {
+         submaps = (Lisp_Object *) alloca (2 * sizeof (submaps[0]));
+         defs    = (Lisp_Object *) alloca (2 * sizeof (defs[0]));
+         nmaps_allocated = 2;
+       }
       if (!NILP (Voverriding_local_map))
        submaps[nmaps++] = Voverriding_local_map;
     }
@@ -8819,7 +8968,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.
@@ -8998,16 +9147,19 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                          if (!EQ (map_here, orig_local_map))
                            {
                              orig_local_map = map_here;
-                             keybuf[t] = key;
-                             mock_input = t + 1;
-
-                             goto replay_sequence;
+                             ++localized_local_map;
                            }
+
                          map_here = get_local_map (XINT (pos),
                                                     current_buffer, Qkeymap);
                          if (!EQ (map_here, orig_keymap))
                            {
                              orig_keymap = map_here;
+                             ++localized_local_map;
+                           }
+
+                         if (localized_local_map > 1)
+                           {
                              keybuf[t] = key;
                              mock_input = t + 1;
 
@@ -9415,8 +9567,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;
            }
@@ -9434,6 +9586,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;
 
@@ -9663,7 +9816,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)))
        {
@@ -9723,7 +9876,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;
 {
@@ -9812,7 +9971,7 @@ 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)
+      && NILP (Vexecuting_kbd_macro)
       && SYMBOLP (function))
     bindings = Fwhere_is_internal (function, Voverriding_local_map,
                                   Qt, Qnil, Qnil);
@@ -9829,19 +9988,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 (Vsuggest_key_bindings, 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;
@@ -9861,10 +10019,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);
@@ -9953,7 +10113,9 @@ Actually, the value is nil only if we can be sure that no input is available;
 if there is a doubt, the value is t.  */)
      ()
 {
-  if (!NILP (Vunread_command_events) || unread_command_char != -1)
+  if (!NILP (Vunread_command_events) || unread_command_char != -1
+      || !NILP (Vunread_post_input_method_events)
+      || !NILP (Vunread_input_method_events))
     return (Qt);
 
   get_input_pending (&input_pending,
@@ -10550,7 +10712,7 @@ The elements of this list correspond to the arguments of
 DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
        doc: /* Return position information for pixel coordinates X and Y.
 By default, X and Y are relative to text area of the selected window.
-Optional third arg FRAME_OR_WINDOW non-nil specifies frame or window.
+Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window.
 If optional fourth arg WHOLE is non-nil, X is relative to the left
 edge of the window.
 
@@ -10574,11 +10736,11 @@ The `posn-' functions access elements of such lists.  */)
       CHECK_LIVE_WINDOW (frame_or_window);
 
       w = XWINDOW (frame_or_window);
-      XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x))
+      XSETINT (x, (XINT (x)
+                  + WINDOW_LEFT_EDGE_X (w)
                   + (NILP (whole)
                      ? window_box_left_offset (w, TEXT_AREA)
-                     : - (WINDOW_LEFT_SCROLL_BAR_COLS (w)
-                          * WINDOW_FRAME_COLUMN_WIDTH (w)))));
+                     : 0)));
       XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y)));
       frame_or_window = w->frame;
     }
@@ -10604,9 +10766,21 @@ The `posn-' functions access elements of such lists.  */)
 {
   Lisp_Object tem;
 
+  if (NILP (window))
+    window = selected_window;
+
   tem = Fpos_visible_in_window_p (pos, window, Qt);
   if (!NILP (tem))
-    tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window, Qnil);
+    {
+      Lisp_Object x = XCAR (tem);
+      Lisp_Object y = XCAR (XCDR (tem));
+
+      /* Point invisible due to hscrolling?  */
+      if (XINT (x) < 0)
+       return Qnil;
+      tem = Fposn_at_x_y (x, y, window, Qnil);
+    }
+
   return tem;
 }
 
@@ -10751,11 +10925,6 @@ init_keyboard ()
   poll_suppress_count = 1;
   start_polling ();
 #endif
-
-#ifdef MAC_OSX
-  /* At least provide an escape route since C-g doesn't work.  */
-  signal (SIGINT, interrupt_signal);
-#endif
 }
 
 /* This type's only use is in syms_of_keyboard, to initialize the
@@ -10832,9 +11001,6 @@ syms_of_keyboard ()
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
-  Qpost_command_idle_hook = intern ("post-command-idle-hook");
-  staticpro (&Qpost_command_idle_hook);
-
   Qdeferred_action_function = intern ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
@@ -10845,7 +11011,7 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
   Qlanguage_change = intern ("language-change");
   staticpro (&Qlanguage_change);
 #endif
@@ -10853,7 +11019,12 @@ syms_of_keyboard ()
   staticpro (&Qdrag_n_drop);
 
   Qsave_session = intern ("save-session");
-  staticpro(&Qsave_session);
+  staticpro (&Qsave_session);
+
+#ifdef MAC_OS
+  Qmac_apple_event = intern ("mac-apple-event");
+  staticpro (&Qmac_apple_event);
+#endif
 
   Qusr1_signal = intern ("usr1-signal");
   staticpro (&Qusr1_signal);
@@ -10945,6 +11116,7 @@ syms_of_keyboard ()
   Fset (Qinput_method_use_echo_area, Qnil);
 
   last_point_position_buffer = Qnil;
+  last_point_position_window = Qnil;
 
   {
     struct event_head *p;
@@ -11012,6 +11184,10 @@ syms_of_keyboard ()
   menu_bar_one_keymap_changed_items = Qnil;
   staticpro (&menu_bar_one_keymap_changed_items);
 
+  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);
@@ -11061,7 +11237,10 @@ so that you can determine whether the command was run by mouse or not.  */);
 
   DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
               doc: /* List of events to be read as the command input.
-These events are processed first, before actual keyboard input.  */);
+These events are processed first, before actual keyboard input.
+Events read from this list are not normally added to `this-command-keys',
+as they will already have been added once as they were read for the first time.
+An element of the form (t . EVENT) forces EVENT to be added to that list.  */);
   Vunread_command_events = Qnil;
 
   DEFVAR_INT ("unread-command-char", &unread_command_char,
@@ -11069,14 +11248,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,
@@ -11280,21 +11461,12 @@ the hook value is set to nil, since otherwise the error
 might happen repeatedly and make Emacs nonfunctional.  */);
   Vpost_command_hook = Qnil;
 
-  DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
-              doc: /* Normal hook run after each command is executed, if idle.
-Errors running the hook are caught and ignored.  */);
-  Vpost_command_idle_hook = Qnil;
-
-  DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
-             doc: /* Delay time before running `post-command-idle-hook'.
-This is measured in microseconds.  */);
-  post_command_idle_delay = 100000;
-
 #if 0
   DEFVAR_LISP ("echo-area-clear-hook", ...,
               doc: /* Normal hook run when clearing the echo area.  */);
 #endif
   Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+  staticpro (&Qecho_area_clear_hook);
   SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
 
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
@@ -11420,12 +11592,6 @@ suppressed only after special commands that set
 `disable-point-adjustment' (which see) to non-nil.  */);
   Vglobal_disable_point_adjustment = Qnil;
 
-  DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings,
-              doc: /* Non-nil means updating menu bindings is allowed.
-A value of nil means menu bindings should not be updated.
-Used during Emacs' startup.  */);
-  update_menu_bindings = 1;
-
   DEFVAR_LISP ("minibuffer-message-timeout", &Vminibuffer_message_timeout,
               doc: /* *How long to display an echo-area message when the minibuffer is active.
 If the value is not a number, such messages don't time out.  */);
@@ -11436,6 +11602,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