]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(x_encode_text): Declare static. Add FREEP arg.
[gnu-emacs] / src / keyboard.c
index dd8b751c8d5d358a7b986ea38c1b25c929c31099..a39e2699d5f3c07780c5d09761c8e6d75c224bea 100644 (file)
@@ -1,6 +1,7 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
-     Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
+                 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
+                 2005 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>
@@ -45,6 +46,9 @@ Boston, MA 02111-1307, USA.  */
 #include <setjmp.h>
 #include <errno.h>
 
+#ifdef HAVE_GTK_AND_PTHREAD
+#include <pthread.h>
+#endif
 #ifdef MSDOS
 #include "msdos.h"
 #include <time.h>
@@ -62,6 +66,10 @@ Boston, MA 02111-1307, USA.  */
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
 /* This is to get the definitions of the XK_ symbols.  */
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -117,6 +125,8 @@ struct backtrace
                           args points to slot holding list of
                           unevalled args */
     char evalargs;
+    /* Nonzero means call value of debugger when done with this operation. */
+    char debug_on_exit;
   };
 
 #ifdef MULTI_KBOARD
@@ -129,8 +139,8 @@ KBOARD the_only_kboard;
 #endif
 
 /* Non-nil disable property on a command means
-   do not execute it; call disabled-command-hook's value instead.  */
-Lisp_Object Qdisabled, Qdisabled_command_hook;
+   do not execute it; call disabled-command-function's value instead.  */
+Lisp_Object Qdisabled, Qdisabled_command_function;
 
 #define NUM_RECENT_KEYS (100)
 int recent_keys_index; /* Index for storing next element into recent_keys */
@@ -441,11 +451,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.  */
@@ -479,36 +484,6 @@ extern char *pending_malloc_warning;
 
 static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
 
-/* Vector to GCPRO the Lisp objects referenced from kbd_buffer.
-
-   The interrupt-level event handlers will never enqueue an event on a
-   frame which is not in Vframe_list, and once an event is dequeued,
-   internal_last_event_frame or the event itself points to the frame.
-   So that's all fine.
-
-   But while the event is sitting in the queue, it's completely
-   unprotected.  Suppose the user types one command which will run for
-   a while and then delete a frame, and then types another event at
-   the frame that will be deleted, before the command gets around to
-   it.  Suppose there are no references to this frame elsewhere in
-   Emacs, and a GC occurs before the second event is dequeued.  Now we
-   have an event referring to a freed frame, which will crash Emacs
-   when it is dequeued.
-
-   Similar things happen when an event on a scroll bar is enqueued; the
-   window may be deleted while the event is in the queue.
-
-   So, we use this vector to protect the Lisp_Objects in the event
-   queue.  That way, they'll be dequeued as dead frames or windows,
-   but still valid Lisp objects.
-
-   If kbd_buffer[i].kind != NO_EVENT, then
-
-   AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window.
-   AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg.  */
-
-static Lisp_Object kbd_buffer_gcpro;
-
 /* Pointer to next available character in kbd_buffer.
    If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty.
    This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the
@@ -544,13 +519,14 @@ Lisp_Object Qmake_frame_visible;
 Lisp_Object Qselect_window;
 Lisp_Object Qhelp_echo;
 
+#ifdef HAVE_MOUSE
+Lisp_Object Qmouse_fixup_help_message;
+#endif
+
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-Lisp_Object Qmouse_wheel;
-#endif
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
 Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
@@ -589,6 +565,8 @@ Lisp_Object Qvertical_line;
 Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 extern Lisp_Object Qleft_margin, Qright_margin;
+extern Lisp_Object Qleft_fringe, Qright_fringe;
+extern Lisp_Object QCmap;
 
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
@@ -636,7 +614,7 @@ int flow_control;
 
 /* We are unable to use interrupts if FIONREAD is not available,
    so flush SIGIO so we won't try.  */
-#ifndef FIONREAD
+#if !defined (FIONREAD)
 #ifdef SIGIO
 #undef SIGIO
 #endif
@@ -672,14 +650,17 @@ static EMACS_TIME timer_last_idleness_start_time;
 \f
 /* Global variable declarations.  */
 
+/* Flags for readable_events.  */
+#define READABLE_EVENTS_DO_TIMERS_NOW          (1 << 0)
+#define READABLE_EVENTS_FILTER_EVENTS          (1 << 1)
+#define READABLE_EVENTS_IGNORE_SQUEEZABLES     (1 << 2)
+
 /* Function for init_keyboard to call with no args (if nonzero).  */
 void (*keyboard_init_hook) ();
 
 static int read_avail_input P_ ((int));
 static void get_input_pending P_ ((int *, int));
-static void get_filtered_input_pending P_ ((int *, int, int));
 static int readable_events P_ ((int));
-static int readable_filtered_events P_ ((int, int));
 static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
                                                Lisp_Object, int *));
 static Lisp_Object read_char_x_menu_prompt ();
@@ -705,11 +686,16 @@ static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 static void clear_event P_ ((struct input_event *));
 static void any_kboard_state P_ ((void));
 static SIGTYPE interrupt_signal P_ ((int signalnum));
+static void timer_start_idle P_ ((void));
+static void timer_stop_idle P_ ((void));
+static void timer_resume_idle P_ ((void));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
 static int cannot_suspend;
 
+extern Lisp_Object Qidentity, Qonly;
+\f
 /* Install the string STR as the beginning of the string of echoing,
    so that it serves as a prompt for the next character.
    Also start echoing.  */
@@ -829,6 +815,21 @@ echo_dash ()
       == SCHARS (current_kboard->echo_string))
     return;
 
+  /* 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;
+
+         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);
+
+         if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
+           return;
+    }
+
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
   current_kboard->echo_string = concat2 (current_kboard->echo_string,
@@ -1020,13 +1021,18 @@ 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.  */)
      ()
 {
   int count = SPECPDL_INDEX ();
   Lisp_Object buffer;
 
+  /* If we enter while input is blocked, don't lock up here.
+     This may happen through the debugger during redisplay.  */
+  if (INPUT_BLOCKED_P)
+    return Qnil;
+
   command_loop_level++;
   update_mode_lines = 1;
 
@@ -1096,6 +1102,19 @@ single_kboard_state ()
 #endif
 }
 
+/* If we're in single_kboard state for kboard KBOARD,
+   get out of it.  */
+
+void
+not_single_kboard_state (kboard)
+     KBOARD *kboard;
+{
+#ifdef MULTI_KBOARD
+  if (kboard == current_kboard)
+    single_kboard = 0;
+#endif
+}
+
 /* Maintain a stack of kboards, so other parts of Emacs
    can switch temporarily to the kboard of a given frame
    and then revert to the previous status.  */
@@ -1150,21 +1169,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 ();
@@ -1182,7 +1201,8 @@ cmd_error (data)
 
   Vinhibit_quit = Qnil;
 #ifdef MULTI_KBOARD
-  any_kboard_state ();
+  if (command_loop_level == 0 && minibuf_level == 0)
+    any_kboard_state ();
 #endif
 
   return make_number (0);
@@ -1264,15 +1284,19 @@ command_loop ()
     {
       Lisp_Object val;
       val = internal_catch (Qexit, command_loop_2, Qnil);
-      executing_macro = Qnil;
+      executing_kbd_macro = Qnil;
       return val;
     }
   else
     while (1)
       {
        internal_catch (Qtop_level, top_level_1, Qnil);
+       /* Reset single_kboard in case top-level set it while
+          evaluating an -f option, or we are stuck there for some
+          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)
@@ -1325,6 +1349,12 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
   if (display_hourglass_p)
     cancel_hourglass ();
 #endif
+
+  /* Unblock input if we enter with input blocked.  This may happen if
+     redisplay traps e.g. during tool-bar update with input blocked.  */
+  while (INPUT_BLOCKED_P)
+    UNBLOCK_INPUT;
+
   return Fthrow (Qtop_level, Qnil);
 }
 
@@ -1366,6 +1396,7 @@ cancel_hourglass_unwind (arg)
      Lisp_Object arg;
 {
   cancel_hourglass ();
+  return Qnil;
 }
 #endif
 
@@ -1411,17 +1442,7 @@ command_loop_1 ()
        resize_echo_area_exactly ();
 
       if (!NILP (Vdeferred_action_list))
-       call0 (Vdeferred_action_function);
-
-      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
-       {
-         if (NILP (Vunread_command_events)
-             && NILP (Vunread_input_method_events)
-             && NILP (Vunread_post_input_method_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
+       safe_run_hooks (Qdeferred_action_function);
     }
 
   Vmemory_full = Qnil;
@@ -1489,7 +1510,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.  */
@@ -1502,6 +1523,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],
@@ -1547,11 +1569,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,7 +1619,10 @@ command_loop_1 ()
       if (NILP (Vthis_command))
        {
          /* nil means key is undefined.  */
+         Lisp_Object keys = Fvector (i, keybuf);
+         keys = Fkey_description (keys, Qnil);
          bitch_at_user ();
+         message_with_string ("%s is undefined", keys, 0);
          current_kboard->defining_kbd_macro = Qnil;
          update_mode_lines = 1;
          current_kboard->Vprefix_arg = Qnil;
@@ -1647,7 +1672,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;
                }
@@ -1682,7 +1707,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;
                }
@@ -1695,7 +1720,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)
@@ -1717,7 +1742,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);
 
@@ -1745,7 +1770,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 ();
@@ -1763,7 +1788,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
           }
@@ -1784,16 +1809,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,
@@ -1819,6 +1834,14 @@ command_loop_1 ()
 
       if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
+         /* Setting transient-mark-mode to `only' is a way of
+            turning it on for just one command.  */
+
+         if (EQ (Vtransient_mark_mode, Qidentity))
+           Vtransient_mark_mode = Qnil;
+         if (EQ (Vtransient_mark_mode, Qonly))
+           Vtransient_mark_mode = Qidentity;
+
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
            {
              /* We could also call `deactivate'mark'.  */
@@ -1901,10 +1924,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;
@@ -1959,7 +1985,12 @@ adjust_point_for_property (last_pt, modified)
                      : (PT < last_pt ? beg : end));
              check_composition = check_display = 1;
            }
+#if 0 /* This assertion isn't correct, because SET_PT may end up setting
+        the point to something other than its argument, due to
+        point-motion hooks, intangibility, etc.  */
          xassert (PT == beg || PT == end);
+#endif
+
          /* Pretend the area doesn't exist if the buffer is not
             modified.  */
          if (!modified && !ellipsis && beg < end)
@@ -2064,7 +2095,11 @@ poll_for_input (timer)
      struct atimer *timer;
 {
   if (poll_suppress_count == 0)
+#ifdef SYNC_INPUT
+    interrupt_input_pending = 1;
+#else
     poll_for_input_1 ();
+#endif
 }
 
 #endif /* POLL_FOR_INPUT */
@@ -2207,12 +2242,16 @@ make_ctrl_char (c)
   return c;
 }
 
-/* Display help echo in the echo area.
+/* Display the help-echo property of the character after the mouse pointer.
+   Either show it in the echo area, or call show-help-function to display
+   it by other means (maybe in a tooltip).
+
+   If HELP is nil, that means clear the previous help echo.
 
-   HELP a string means display that string, HELP nil means clear the
-   help echo.  If HELP is a function, call it with OBJECT and POS as
-   arguments; the function should return a help string or nil for
-   none.  For all other types of HELP evaluate it to obtain a string.
+   If HELP is a string, display that string.  If HELP is a function,
+   call it with OBJECT and POS as arguments; the function should
+   return a help string or nil for none.  For all other types of HELP,
+   evaluate it to obtain a string.
 
    WINDOW is the window in which the help was generated, if any.
    It is nil if not in a window.
@@ -2257,6 +2296,11 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
        return;
     }
 
+#ifdef HAVE_MOUSE
+  if (!noninteractive && STRINGP (help))
+    help = call1 (Qmouse_fixup_help_message, help);
+#endif
+
   if (STRINGP (help) || NILP (help))
     {
       if (!NILP (Vshow_help_function))
@@ -2354,7 +2398,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   volatile Lisp_Object also_record;
   volatile int reread;
   struct gcpro gcpro1, gcpro2;
-  EMACS_TIME last_idle_start;
   int polling_stopped_here = 0;
 
   also_record = Qnil;
@@ -2436,7 +2479,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
@@ -2453,19 +2496,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)
-         && (XINT (c) & 0x80))
+      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;
     }
@@ -2574,6 +2617,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (_setjmp (local_getcjmp))
     {
+      /* We must have saved the outer value of getcjmp here,
+        so restore it now.  */
+      restore_getcjmp (save_jump);
       XSETINT (c, quit_char);
       internal_last_event_frame = selected_frame;
       Vlast_event_frame = internal_last_event_frame;
@@ -2861,9 +2907,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
-  /* Record the last idle start time so that we can reset it
-     should the next event read be a help-echo.  */
-  last_idle_start = timer_idleness_start_time;
   timer_stop_idle ();
   RESUME_POLLING;
 
@@ -2903,7 +2946,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
           prevents automatic window selection (under
           mouse_autoselect_window from acting as a real input event, for
           example banishing the mouse under mouse-avoidance-mode.  */
-       timer_idleness_start_time = last_idle_start;
+       timer_resume_idle ();
 
       /* Resume allowing input from any kboard, if that was true before.  */
       if (!was_locked)
@@ -2944,13 +2987,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       Lisp_Object posn;
 
-      posn = POSN_BUFFER_POSN (EVENT_START (c));
+      posn = POSN_POSN (EVENT_START (c));
       /* Handle menu-bar events:
         insert the dummy prefix event `menu-bar'.  */
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
+         POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -3008,6 +3051,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Save the echo status.  */
       int saved_immediate_echo = current_kboard->immediate_echo;
       struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+      Lisp_Object saved_echo_string = current_kboard->echo_string;
       int saved_echo_after_prompt = current_kboard->echo_after_prompt;
 
 #if 0
@@ -3062,6 +3106,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       cancel_echoing ();
       ok_to_echo_at_next_pause = saved_ok_to_echo;
+      current_kboard->echo_string = saved_echo_string;
       current_kboard->echo_after_prompt = saved_echo_after_prompt;
       if (saved_immediate_echo)
        echo_now ();
@@ -3102,7 +3147,7 @@ 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_idleness_start_time = last_idle_start;
+      timer_resume_idle ();
       goto retry;
     }
 
@@ -3403,10 +3448,11 @@ tracking_off (old_value)
         input has been processed.  If the only input available was
         the sort that we have just disabled, then we need to call
         redisplay.  */
-      if (!readable_events (1))
+      if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
        {
          redisplay_preserve_echo_area (6);
-         get_input_pending (&input_pending, 1);
+         get_input_pending (&input_pending,
+                            READABLE_EVENTS_DO_TIMERS_NOW);
        }
     }
   return Qnil;
@@ -3458,20 +3504,21 @@ some_mouse_moved ()
 /* Return true iff there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
 static int
-readable_filtered_events (do_timers_now, filter_events)
-     int do_timers_now;
-     int filter_events;
+readable_events (flags)
+     int flags;
 {
-  if (do_timers_now)
-    timer_check (do_timers_now);
+  if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
+    timer_check (1);
 
-  /* If the buffer contains only FOCUS_IN_EVENT events,
-     and FILTER_EVENTS is nonzero, report it as empty.  */
+  /* If the buffer contains only FOCUS_IN_EVENT events, and
+     READABLE_EVENTS_FILTER_EVENTS is set, report it as empty.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
     {
-      int have_live_event = 1;
-
-      if (filter_events)
+      if (flags & (READABLE_EVENTS_FILTER_EVENTS
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                  | READABLE_EVENTS_IGNORE_SQUEEZABLES
+#endif
+                  ))
         {
           struct input_event *event;
 
@@ -3479,20 +3526,34 @@ readable_filtered_events (do_timers_now, filter_events)
                    ? 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
-  if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+      && !NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
 #endif
   if (single_kboard)
@@ -3510,15 +3571,6 @@ readable_filtered_events (do_timers_now, filter_events)
   return 0;
 }
 
-/* Return true iff there are any events in the queue that read-char
-   would return.  If this returns false, a read-char would block.  */
-static int
-readable_events (do_timers_now)
-     int do_timers_now;
-{
-  return readable_filtered_events (do_timers_now, 0);
-}
-
 /* Set this for debugging, to have a way to get out */
 int stop_character;
 
@@ -3544,15 +3596,41 @@ event_to_kboard (event)
 }
 #endif
 
+
+Lisp_Object Vthrow_on_input;
+
 /* Store an event obtained at interrupt level into kbd_buffer, fifo */
 
 void
 kbd_buffer_store_event (event)
      register struct input_event *event;
+{
+  kbd_buffer_store_event_hold (event, 0);
+}
+
+/* Store EVENT obtained at interrupt level into kbd_buffer, fifo.
+
+   If HOLD_QUIT is 0, just stuff EVENT into the fifo.
+   Else, if HOLD_QUIT.kind != NO_EVENT, discard EVENT.
+   Else, if EVENT is a quit event, store the quit event
+   in HOLD_QUIT, and return (thus ignoring further events).
+
+   This is used in read_avail_input to postpone the processing
+   of the quit event until all subsequent input events have been
+   parsed (and discarded).
+ */
+
+void
+kbd_buffer_store_event_hold (event, hold_quit)
+     register struct input_event *event;
+     struct input_event *hold_quit;
 {
   if (event->kind == NO_EVENT)
     abort ();
 
+  if (hold_quit && hold_quit->kind != NO_EVENT)
+    return;
+
   if (event->kind == ASCII_KEYSTROKE_EVENT)
     {
       register int c = event->code & 0377;
@@ -3594,6 +3672,12 @@ kbd_buffer_store_event (event)
            }
 #endif
 
+         if (hold_quit)
+           {
+             bcopy (event, (char *) hold_quit, sizeof (*event));
+             return;
+           }
+
          /* If this results in a quit_char being returned to Emacs as
             input, set Vlast_event_frame properly.  If this doesn't
             get returned to Emacs as an event, the next event read
@@ -3623,7 +3707,9 @@ kbd_buffer_store_event (event)
      Just ignore the second one.  */
   else if (event->kind == BUFFER_SWITCH_EVENT
           && kbd_fetch_ptr != kbd_store_ptr
-          && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT)
+          && ((kbd_store_ptr == kbd_buffer
+               ? kbd_buffer + KBD_BUFFER_SIZE - 1
+               : kbd_store_ptr - 1)->kind) == BUFFER_SWITCH_EVENT)
     return;
 
   if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
@@ -3635,40 +3721,44 @@ kbd_buffer_store_event (event)
      Discard the event if it would fill the last slot.  */
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
-      int idx;
+      *kbd_store_ptr = *event;
+      ++kbd_store_ptr;
+    }
 
-#if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error
-        prone to assign individual members for other events, in case
-        the input_event structure is changed.  --2000-07-13, gerd.  */
-      struct input_event *sp = kbd_store_ptr;
-      sp->kind = event->kind;
-      if (event->kind == SELECTION_REQUEST_EVENT)
+  /* If we're inside while-no-input, and this event qualifies
+     as input, set quit-flag to cause an interrupt.  */
+  if (!NILP (Vthrow_on_input)
+      && event->kind != FOCUS_IN_EVENT
+      && event->kind != HELP_EVENT
+      && event->kind != DEICONIFY_EVENT)
+    {
+      Vquit_flag = Vthrow_on_input;
+      /* If we're inside a function that wants immediate quits,
+        do it now.  */
+      if (immediate_quit && NILP (Vinhibit_quit))
        {
-         /* We must not use the ordinary copying code for this case,
-            since `part' is an enum and copying it might not copy enough
-            in this case.  */
-         bcopy (event, (char *) sp, sizeof (*event));
+         immediate_quit = 0;
+         sigfree ();
+         QUIT;
        }
-      else
+    }
+}
 
-       {
-         sp->code = event->code;
-         sp->part = event->part;
-         sp->frame_or_window = event->frame_or_window;
-         sp->arg = event->arg;
-         sp->modifiers = event->modifiers;
-         sp->x = event->x;
-         sp->y = event->y;
-         sp->timestamp = event->timestamp;
-       }
-#else
-      *kbd_store_ptr = *event;
-#endif
 
-      idx = 2 * (kbd_store_ptr - kbd_buffer);
-      ASET (kbd_buffer_gcpro, idx, event->frame_or_window);
-      ASET (kbd_buffer_gcpro, idx + 1, event->arg);
-      ++kbd_store_ptr;
+/* Put an input event back in the head of the event queue.  */
+
+void
+kbd_buffer_unget_event (event)
+     register struct input_event *event;
+{
+  if (kbd_fetch_ptr == kbd_buffer)
+    kbd_fetch_ptr = kbd_buffer + KBD_BUFFER_SIZE;
+
+  /* Don't let the very last slot in the buffer become full,  */
+  if (kbd_fetch_ptr - 1 != kbd_store_ptr)
+    {
+      --kbd_fetch_ptr;
+      *kbd_fetch_ptr = *event;
     }
 }
 
@@ -3686,24 +3776,22 @@ kbd_buffer_store_event (event)
 
    Value is the number of input_events generated.  */
 
-int
-gen_help_event (bufp, size, help, frame, window, object, pos)
-     struct input_event *bufp;
-     int size;
+void
+gen_help_event (help, frame, window, object, pos)
      Lisp_Object help, frame, object, window;
      int pos;
 {
-  if (size >= 1)
-    {
-      bufp->kind = HELP_EVENT;
-      bufp->frame_or_window = frame;
-      bufp->arg = object;
-      bufp->x = WINDOWP (window) ? window : frame;
-      bufp->y = help;
-      bufp->code = pos;
-      return 1;
-    }
-  return 0;
+  struct input_event event;
+
+  EVENT_INIT (event);
+
+  event.kind = HELP_EVENT;
+  event.frame_or_window = frame;
+  event.arg = object;
+  event.x = WINDOWP (window) ? window : frame;
+  event.y = help;
+  event.code = pos;
+  kbd_buffer_store_event (&event);
 }
 
 
@@ -3737,6 +3825,7 @@ discard_mouse_events ()
        sp = kbd_buffer;
 
       if (sp->kind == MOUSE_CLICK_EVENT
+         || sp->kind == WHEEL_EVENT
 #ifdef WINDOWSNT
          || sp->kind == W32_SCROLL_BAR_CLICK_EVENT
 #endif
@@ -3782,9 +3871,6 @@ static INLINE void
 clear_event (event)
      struct input_event *event;
 {
-  int idx = 2 * (event - kbd_buffer);
-  ASET (kbd_buffer_gcpro, idx, Qnil);
-  ASET (kbd_buffer_gcpro, idx + 1, Qnil);
   event->kind = NO_EVENT;
 }
 
@@ -3843,10 +3929,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        break;
 #endif
       {
-       Lisp_Object minus_one;
-
-       XSETINT (minus_one, -1);
-       wait_reading_process_input (0, 0, minus_one, 1);
+       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.  */
@@ -3890,7 +3973,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       /* These two kinds of events get special handling
         and don't actually appear to the command loop.
         We return nil for them.  */
-      if (event->kind == SELECTION_REQUEST_EVENT)
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -3901,7 +3985,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          copy = *event;
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
-         x_handle_selection_request (&copy);
+         x_handle_selection_event (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -3909,22 +3993,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif
        }
 
-      else if (event->kind == SELECTION_CLEAR_EVENT)
-       {
-#ifdef HAVE_X11
-         struct input_event copy;
-
-         /* Remove it from the buffer before processing it.  */
-         copy = *event;
-         kbd_fetch_ptr = event + 1;
-         input_pending = readable_events (0);
-         x_handle_selection_clear (&copy);
-#else
-         /* We're getting selection request events, but we don't have
-             a window system.  */
-         abort ();
-#endif
-       }
 #if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
       else if (event->kind == DELETE_WINDOW_EVENT)
        {
@@ -3934,7 +4002,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)).  */
@@ -3966,13 +4034,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->modifiers, Qnil);
-         obj = Fcons (event->code, obj);
-         obj = Fcons (event->frame_or_window, obj);
+         obj = Fcons (event->frame_or_window, Qnil);
+#endif
          obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
@@ -4151,7 +4222,8 @@ swallow_events (do_display)
 
       /* These two kinds of events get special handling
         and don't actually appear to the command loop.  */
-      if (event->kind == SELECTION_REQUEST_EVENT)
+      if (event->kind == SELECTION_REQUEST_EVENT
+         || event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
          struct input_event copy;
@@ -4162,25 +4234,7 @@ swallow_events (do_display)
          copy = *event;
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
-         x_handle_selection_request (&copy);
-#else
-         /* We're getting selection request events, but we don't have
-             a window system.  */
-         abort ();
-#endif
-       }
-
-      else if (event->kind == SELECTION_CLEAR_EVENT)
-       {
-#ifdef HAVE_X11
-         struct input_event copy;
-
-         /* Remove it from the buffer before processing it,  */
-         copy = *event;
-
-         kbd_fetch_ptr = event + 1;
-         input_pending = readable_events (0);
-         x_handle_selection_clear (&copy);
+         x_handle_selection_event (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
@@ -4192,7 +4246,7 @@ swallow_events (do_display)
     }
 
   old_timers_run = timers_run;
-  get_input_pending (&input_pending, 1);
+  get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
 
   if (timers_run != old_timers_run && do_display)
     redisplay_preserve_echo_area (7);
@@ -4201,7 +4255,7 @@ swallow_events (do_display)
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
-void
+static void
 timer_start_idle ()
 {
   Lisp_Object timers;
@@ -4229,12 +4283,23 @@ timer_start_idle ()
 
 /* Record that Emacs is no longer idle, so stop running idle-time timers.  */
 
-void
+static void
 timer_stop_idle ()
 {
   EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
 }
 
+/* Resume idle timer from last idle start time.  */
+
+static void
+timer_resume_idle ()
+{
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    return;
+
+  timer_idleness_start_time = timer_last_idleness_start_time;
+}
+
 /* This is only for debugging.  */
 struct input_event last_timer_event;
 
@@ -4436,9 +4501,7 @@ timer_check (do_it_now)
 static Lisp_Object accent_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-static Lisp_Object mouse_wheel_syms;
-#endif
+static Lisp_Object wheel_syms;
 static Lisp_Object drag_n_drop_syms;
 
 /* This is a list of keysym codes for special "accent" characters.
@@ -4892,21 +4955,11 @@ static char *iso_lispy_function_keys[] =
 
 Lisp_Object Vlispy_mouse_stem;
 
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-/* mouse-wheel events are generated by the wheel on devices such as
-   the MS Intellimouse.  The wheel sits in between the left and right
-   mouse buttons, and is typically used to scroll or zoom the window
-   underneath the pointer.  mouse-wheel events specify the object on
-   which they operate, and a delta corresponding to the amount and
-   direction that the wheel is rotated.  Clicking the mouse-wheel
-   generates a mouse-2 event.  */
-static char *lispy_mouse_wheel_names[] =
-{
-  "mouse-wheel"
+static char *lispy_wheel_names[] =
+{
+  "wheel-up", "wheel-down"
 };
 
-#endif /* WINDOWSNT */
-
 /* drag-n-drop events are generated when a set of selected files are
    dragged from another application and dropped onto an Emacs window.  */
 static char *lispy_drag_n_drop_names[] =
@@ -4969,6 +5022,169 @@ EMACS_INT double_click_fuzz;
 
 int double_click_count;
 
+/* Return position of a mouse click or wheel event */
+
+static Lisp_Object
+make_lispy_position (f, x, y, time)
+     struct frame *f;
+     Lisp_Object *x, *y;
+     unsigned long time;
+{
+  Lisp_Object window;
+  enum window_part part;
+  Lisp_Object posn = Qnil;
+  Lisp_Object extra_info = Qnil;
+  int wx, wy;
+
+  /* Set `window' to the window under frame pixel coordinates (x,y)  */
+  if (f)
+    window = window_from_coordinates (f, XINT (*x), XINT (*y),
+                                     &part, &wx, &wy, 0);
+  else
+    window = Qnil;
+
+  if (WINDOWP (window))
+    {
+      /* It's a click in window window at frame coordinates (x,y)  */
+      struct window *w = XWINDOW (window);
+      Lisp_Object string_info = Qnil;
+      int textpos = -1, rx = -1, ry = -1;
+      int dx = -1, dy = -1;
+      int width = -1, height = -1;
+      Lisp_Object object = Qnil;
+
+      /* Set event coordinates to window-relative coordinates
+        for constructing the Lisp event below.  */
+      XSETINT (*x, wx);
+      XSETINT (*y, wy);
+
+      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.  */
+         Lisp_Object string;
+         int charpos;
+
+         posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+         rx = wx, ry = wy;
+         string = mode_line_string (w, part, &rx, &ry, &charpos,
+                                    &object, &dx, &dy, &width, &height);
+         if (STRINGP (string))
+           string_info = Fcons (string, make_number (charpos));
+         if (w == XWINDOW (selected_window))
+           textpos = PT;
+         else
+           textpos = XMARKER (w->pointm)->charpos;
+       }
+      else if (part == ON_VERTICAL_BORDER)
+       {
+         posn = Qvertical_line;
+         wx = -1;
+         dx = 0;
+         width = 1;
+       }
+      else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+       {
+         Lisp_Object string;
+         int charpos;
+
+         posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
+         rx = wx, ry = wy;
+         string = marginal_area_string (w, part, &rx, &ry, &charpos,
+                                        &object, &dx, &dy, &width, &height);
+         if (STRINGP (string))
+           string_info = Fcons (string, make_number (charpos));
+       }
+      else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+       {
+         posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : 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);
+       }
+
+      if (textpos < 0)
+       {
+         Lisp_Object string2, object2 = Qnil;
+         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);
+         textpos = CHARPOS (p.pos);
+         if (rx < 0) rx = wx;
+         if (ry < 0) ry = wy;
+         if (dx < 0) dx = dx2;
+         if (dy < 0) dy = dy2;
+         if (width < 0) width = width2;
+         if (height < 0) height = height2;
+
+         if (NILP (posn))
+           {
+             posn = make_number (textpos);
+             if (STRINGP (string2))
+               string_info = Fcons (string2,
+                                    make_number (CHARPOS (p.string_pos)));
+           }
+         if (NILP (object))
+           object = object2;
+       }
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (IMAGEP (object))
+       {
+         Lisp_Object image_map, hotspot;
+         if ((image_map = Fplist_get (XCDR (object), QCmap),
+              !NILP (image_map))
+             && (hotspot = find_hot_spot (image_map, dx, dy),
+                 CONSP (hotspot))
+             && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+           posn = XCAR (hotspot);
+       }
+#endif
+
+      /* Object info */
+      extra_info = Fcons (object,
+                         Fcons (Fcons (make_number (dx),
+                                       make_number (dy)),
+                                Fcons (Fcons (make_number (width),
+                                              make_number (height)),
+                                       Qnil)));
+
+      /* String info */
+      extra_info = Fcons (string_info,
+                         Fcons (make_number (textpos),
+                                Fcons (Fcons (make_number (rx),
+                                              make_number (ry)),
+                                       extra_info)));
+    }
+  else if (f != 0)
+    {
+      XSETFRAME (window, f);
+    }
+  else
+    {
+      window = Qnil;
+      XSETFASTINT (*x, 0);
+      XSETFASTINT (*y, 0);
+    }
+
+  return Fcons (window,
+               Fcons (posn,
+                      Fcons (Fcons (*x, *y),
+                             Fcons (make_number (time),
+                                    extra_info))));
+}
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -5103,24 +5319,23 @@ make_lispy_event (event)
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
-       Lisp_Object window;
 
        position = Qnil;
 
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == MOUSE_CLICK_EVENT)
          {
-           enum window_part part;
            struct frame *f = XFRAME (event->frame_or_window);
-           Lisp_Object posn;
-           Lisp_Object string_info = Qnil;
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            int row, column;
+#endif
 
            /* Ignore mouse events that were made on frame that
               have been deleted.  */
            if (! FRAME_LIVE_P (f))
              return Qnil;
 
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* EVENT->x and EVENT->y are frame-relative pixel
               coordinates at this place.  Under old redisplay, COLUMN
               and ROW are set to frame relative glyph coordinates
@@ -5129,7 +5344,6 @@ make_lispy_event (event)
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                                   &column, &row, NULL, 1);
 
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* In the non-toolkit version, clicks on the menu bar
               are ordinary button events in the event buffer.
               Distinguish them, and invoke the menu.
@@ -5183,81 +5397,14 @@ make_lispy_event (event)
              }
 #endif /* not USE_X_TOOLKIT && not USE_GTK */
 
-           /* Set `window' to the window under frame pixel coordinates
-              event->x/event->y.  */
-           window = window_from_coordinates (f, XINT (event->x),
-                                             XINT (event->y), &part, 0);
-
-           if (!WINDOWP (window))
-             {
-               window = event->frame_or_window;
-               posn = Qnil;
-             }
-           else
-             {
-               /* It's a click in window window at frame coordinates
-                  event->x/ event->y.  */
-               struct window *w = XWINDOW (window);
-
-               /* Get window relative coordinates.  Original code
-                  `rounded' this to glyph boundaries.  */
-               int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
-               int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
-               /* Set event coordinates to window-relative coordinates
-                  for constructing the Lisp event below.  */
-               XSETINT (event->x, wx);
-               XSETINT (event->y, wy);
-
-               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.  */
-                   Lisp_Object string;
-                   int charpos;
-
-                   posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
-                   string = mode_line_string (w, wx, wy, part, &charpos);
-                   if (STRINGP (string))
-                     string_info = Fcons (string, make_number (charpos));
-                 }
-               else if (part == ON_VERTICAL_BORDER)
-                 posn = Qvertical_line;
-               else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
-                 {
-                   int charpos;
-                   Lisp_Object object = marginal_area_string (w, wx, wy, part,
-                                                              &charpos);
-                   posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
-                   if (STRINGP (object))
-                     string_info = Fcons (object, make_number (charpos));
-                 }
-               else
-                 {
-                   Lisp_Object object;
-                   struct display_pos p;
-                   buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-                   posn = make_number (CHARPOS (p.pos));
-                   if (STRINGP (object))
-                     string_info
-                       = Fcons (object,
-                                make_number (CHARPOS (p.string_pos)));
-                 }
-             }
-
-           position
-             = Fcons (window,
-                      Fcons (posn,
-                             Fcons (Fcons (event->x, event->y),
-                                    Fcons (make_number (event->timestamp),
-                                           (NILP (string_info)
-                                            ? Qnil
-                                            : Fcons (string_info, Qnil))))));
+           position = make_lispy_position (f, &event->x, &event->y,
+                                           event->timestamp);
          }
 #ifndef USE_TOOLKIT_SCROLL_BARS
        else
          {
            /* It's a scrollbar click.  */
+           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -5393,32 +5540,139 @@ make_lispy_event (event)
          abort ();
 
        {
-         /* Get the symbol we should use for the mouse click.  */
-         Lisp_Object head;
+         /* Get the symbol we should use for the mouse click.  */
+         Lisp_Object head;
+
+         head = modify_event_symbol (button,
+                                     event->modifiers,
+                                     Qmouse_click, Vlispy_mouse_stem,
+                                     NULL,
+                                     &mouse_syms,
+                                     XVECTOR (mouse_syms)->size);
+         if (event->modifiers & drag_modifier)
+           return Fcons (head,
+                         Fcons (start_pos,
+                                Fcons (position,
+                                       Qnil)));
+         else if (event->modifiers & (double_modifier | triple_modifier))
+           return Fcons (head,
+                         Fcons (position,
+                                Fcons (make_number (double_click_count),
+                                       Qnil)));
+         else
+           return Fcons (head,
+                         Fcons (position,
+                                Qnil));
+       }
+      }
+
+    case WHEEL_EVENT:
+      {
+       Lisp_Object position;
+       Lisp_Object head;
+
+       /* Build the position as appropriate for this mouse click.  */
+       struct frame *f = XFRAME (event->frame_or_window);
+
+       /* Ignore wheel events that were made on frame that have been
+          deleted.  */
+       if (! FRAME_LIVE_P (f))
+         return Qnil;
+
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
+
+       /* Set double or triple modifiers to indicate the wheel speed.  */
+       {
+         /* On window-system frames, use the value of
+            double-click-fuzz as is.  On other frames, interpret it
+            as a multiple of 1/8 characters.  */
+         struct frame *f;
+         int fuzz;
+         int is_double;
+
+         if (WINDOWP (event->frame_or_window))
+           f = XFRAME (XWINDOW (event->frame_or_window)->frame);
+         else if (FRAMEP (event->frame_or_window))
+           f = XFRAME (event->frame_or_window);
+         else
+           abort ();
+
+         if (FRAME_WINDOW_P (f))
+           fuzz = double_click_fuzz;
+         else
+           fuzz = double_click_fuzz / 8;
+
+         is_double = (last_mouse_button < 0
+                      && (abs (XINT (event->x) - last_mouse_x) <= fuzz)
+                      && (abs (XINT (event->y) - last_mouse_y) <= fuzz)
+                      && button_down_time != 0
+                      && (EQ (Vdouble_click_time, Qt)
+                          || (INTEGERP (Vdouble_click_time)
+                              && ((int)(event->timestamp - button_down_time)
+                                  < XINT (Vdouble_click_time)))));
+         if (is_double)
+           {
+             double_click_count++;
+             event->modifiers |= ((double_click_count > 2)
+                                  ? triple_modifier
+                                  : double_modifier);
+           }
+         else
+           {
+             double_click_count = 1;
+             event->modifiers |= click_modifier;
+           }
+
+         button_down_time = event->timestamp;
+         /* Use a negative value to distinguish wheel from mouse button.  */
+         last_mouse_button = -1;
+         last_mouse_x = XINT (event->x);
+         last_mouse_y = XINT (event->y);
+       }
+
+       {
+         int symbol_num;
 
-         head = modify_event_symbol (button,
-                                     event->modifiers,
-                                     Qmouse_click, Vlispy_mouse_stem,
-                                     NULL,
-                                     &mouse_syms,
-                                     XVECTOR (mouse_syms)->size);
-         if (event->modifiers & drag_modifier)
-           return Fcons (head,
-                         Fcons (start_pos,
-                                Fcons (position,
-                                       Qnil)));
-         else if (event->modifiers & (double_modifier | triple_modifier))
-           return Fcons (head,
-                         Fcons (position,
-                                Fcons (make_number (double_click_count),
-                                       Qnil)));
+         if (event->modifiers & up_modifier)
+           {
+             /* Emit a wheel-up event.  */
+             event->modifiers &= ~up_modifier;
+             symbol_num = 0;
+           }
+         else if (event->modifiers & down_modifier)
+           {
+             /* Emit a wheel-down event.  */
+             event->modifiers &= ~down_modifier;
+             symbol_num = 1;
+           }
          else
-           return Fcons (head,
-                         Fcons (position,
-                                Qnil));
+           /* Every wheel event should either have the down_modifier or
+              the up_modifier set.  */
+           abort ();
+
+         /* Get the symbol we should use for the wheel event.  */
+         head = modify_event_symbol (symbol_num,
+                                     event->modifiers,
+                                     Qmouse_click,
+                                     Qnil,
+                                     lispy_wheel_names,
+                                     &wheel_syms,
+                                     ASIZE (wheel_syms));
        }
+
+       if (event->modifiers & (double_modifier | triple_modifier))
+         return Fcons (head,
+                       Fcons (position,
+                              Fcons (make_number (double_click_count),
+                                     Qnil)));
+       else
+         return Fcons (head,
+                       Fcons (position,
+                              Qnil));
       }
 
+
 #ifdef USE_TOOLKIT_SCROLL_BARS
 
       /* We don't have down and up events if using toolkit scroll bars,
@@ -5517,86 +5771,11 @@ make_lispy_event (event)
        }
       }
 #endif /* WINDOWSNT */
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-    case MOUSE_WHEEL_EVENT:
-      {
-       enum window_part part;
-       FRAME_PTR f = XFRAME (event->frame_or_window);
-       Lisp_Object window;
-       Lisp_Object posn;
-       Lisp_Object head, position;
-       int row, column;
-
-       /* Ignore mouse events that were made on frame that
-          have been deleted.  */
-       if (! FRAME_LIVE_P (f))
-         return Qnil;
-       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                              &column, &row, NULL, 1);
-       window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y), &part, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = event->frame_or_window;
-           posn = Qnil;
-         }
-       else
-         {
-           int pixcolumn, pixrow;
-           column -= XINT (XWINDOW (window)->left);
-           row -= XINT (XWINDOW (window)->top);
-           glyph_to_pixel_coords (XWINDOW(window), column, row,
-                                   &pixcolumn, &pixrow);
-           XSETINT (event->x, pixcolumn);
-           XSETINT (event->y, pixrow);
-
-           if (part == ON_MODE_LINE)
-             posn = Qmode_line;
-           else if (part == ON_VERTICAL_BORDER)
-             posn = Qvertical_line;
-           else if (part == ON_HEADER_LINE)
-             posn = Qheader_line;
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (XWINDOW (window), &column, &row,
-                                        &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-             }
-         }
-
-       {
-         Lisp_Object head, position;
-
-         position
-           = Fcons (window,
-                    Fcons (posn,
-                           Fcons (Fcons (event->x, event->y),
-                                  Fcons (make_number (event->timestamp),
-                                         Qnil))));
-
-         head = modify_event_symbol (0, event->modifiers,
-                                     Qmouse_wheel, Qnil,
-                                     lispy_mouse_wheel_names,
-                                     &mouse_wheel_syms, 1);
-         return Fcons (head,
-                       Fcons (position,
-                              /* Insert 1 here so event-click-count works.  */
-                              Fcons (make_number (1),
-                                     Fcons (make_number (event->code),
-                                            Qnil))));
-       }
-      }
-#endif /* WINDOWSNT || MAC_OSX */
 
     case DRAG_N_DROP_EVENT:
       {
-       enum window_part part;
        FRAME_PTR f;
-       Lisp_Object window;
-       Lisp_Object posn;
+       Lisp_Object head, position;
        Lisp_Object files;
 
        /* The frame_or_window field should be a cons of the frame in
@@ -5613,63 +5792,17 @@ make_lispy_event (event)
        if (! FRAME_LIVE_P (f))
          return Qnil;
 
-       window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y), &part, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = XCAR (event->frame_or_window);
-           posn = Qnil;
-         }
-       else
-         {
-           /* It's an event in window `window' at frame coordinates
-              event->x/ event->y.  */
-           struct window *w = XWINDOW (window);
-
-           /* Get window relative coordinates.  */
-           int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
-           int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
-           /* Set event coordinates to window-relative coordinates
-              for constructing the Lisp event below.  */
-           XSETINT (event->x, wx);
-           XSETINT (event->y, wy);
-
-           if (part == ON_MODE_LINE)
-             posn = Qmode_line;
-           else if (part == ON_VERTICAL_BORDER)
-             posn = Qvertical_line;
-           else if (part == ON_HEADER_LINE)
-             posn = Qheader_line;
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-             }
-         }
-
-       {
-         Lisp_Object head, position;
-
-         position
-           = Fcons (window,
-                    Fcons (posn,
-                           Fcons (Fcons (event->x, event->y),
-                                  Fcons (make_number (event->timestamp),
-                                         Qnil))));
-
-         head = modify_event_symbol (0, event->modifiers,
-                                     Qdrag_n_drop, Qnil,
-                                     lispy_drag_n_drop_names,
-                                     &drag_n_drop_syms, 1);
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (files,
-                                     Qnil)));
-       }
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
+
+       head = modify_event_symbol (0, event->modifiers,
+                                   Qdrag_n_drop, Qnil,
+                                   lispy_drag_n_drop_names,
+                                   &drag_n_drop_syms, 1);
+       return Fcons (head,
+                     Fcons (position,
+                            Fcons (files,
+                                   Qnil)));
       }
 #endif /* HAVE_MOUSE */
 
@@ -5742,60 +5875,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Or is it an ordinary mouse movement?  */
   else
     {
-      enum window_part area;
-      Lisp_Object window;
-      Lisp_Object posn;
+      Lisp_Object position;
 
-      if (frame)
-       /* It's in a frame; which window on that frame?  */
-       window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
-      else
-       window = Qnil;
-
-      if (WINDOWP (window))
-       {
-         struct window *w = XWINDOW (window);
-         int wx, wy;
-
-         /* Get window relative coordinates.  */
-         wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
-         wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
-         XSETINT (x, wx);
-         XSETINT (y, wy);
-
-         if (area == ON_MODE_LINE)
-           posn = Qmode_line;
-         else if (area == ON_VERTICAL_BORDER)
-           posn = Qvertical_line;
-         else if (area == ON_HEADER_LINE)
-           posn = Qheader_line;
-         else
-           {
-             Lisp_Object object;
-             struct display_pos p;
-             buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-             posn = make_number (CHARPOS (p.pos));
-           }
-       }
-      else if (frame != 0)
-       {
-         XSETFRAME (window, frame);
-         posn = Qnil;
-       }
-      else
-       {
-         window = Qnil;
-         posn = Qnil;
-         XSETFASTINT (x, 0);
-         XSETFASTINT (y, 0);
-       }
+      position = make_lispy_position (frame, &x, &y, time);
 
       return Fcons (Qmouse_movement,
-                   Fcons (Fcons (window,
-                                 Fcons (posn,
-                                        Fcons (Fcons (x, y),
-                                               Fcons (make_number (time),
-                                                      Qnil)))),
+                   Fcons (position,
                           Qnil));
     }
 }
@@ -6033,7 +6118,7 @@ parse_modifiers (symbol)
                                         SBYTES (SYMBOL_NAME (symbol)) - end),
                            Qnil);
 
-      if (modifiers & ~VALMASK)
+      if (modifiers & ~INTMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -6070,7 +6155,7 @@ apply_modifiers (modifiers, base)
   Lisp_Object cache, index, entry, new_symbol;
 
   /* Mask out upper bits.  We don't know where this value's been.  */
-  modifiers &= VALMASK;
+  modifiers &= INTMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -6228,12 +6313,8 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem,
        {
          int len = SBYTES (name_alist_or_stem);
          char *buf = (char *) alloca (len + 50);
-         if (sizeof (int) == sizeof (EMACS_INT))
-           sprintf (buf, "%s-%d", SDATA (name_alist_or_stem),
-                    XINT (symbol_int) + 1);
-         else if (sizeof (long) == sizeof (EMACS_INT))
-           sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
-                    XINT (symbol_int) + 1);
+         sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
+                  (long) XINT (symbol_int) + 1);
          value = intern (buf);
        }
       else if (name_table != 0 && name_table[symbol_num])
@@ -6457,18 +6538,20 @@ lucid_event_type_list_p (object)
    but works even if FIONREAD does not exist.
    (In fact, this may actually read some input.)
 
-   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
-   If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
+   If READABLE_EVENTS_DO_TIMERS_NOW is set in FLAGS, actually run
+   timer events that are ripe.
+   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 and toolkit scroll bar thumb drags. */
 
 static void
-get_filtered_input_pending (addr, do_timers_now, filter_events)
+get_input_pending (addr, flags)
      int *addr;
-     int do_timers_now;
-     int filter_events;
+     int flags;
 {
   /* First of all, have we already counted some input?  */
-  *addr = (!NILP (Vquit_flag)
-           || readable_filtered_events (do_timers_now, filter_events));
+  *addr = (!NILP (Vquit_flag) || readable_events (flags));
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -6476,23 +6559,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events)
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = (!NILP (Vquit_flag)
-           || readable_filtered_events (do_timers_now, filter_events));
-}
-
-/* Store into *addr a value nonzero if terminal input chars are available.
-   Serves the purpose of ioctl (0, FIONREAD, addr)
-   but works even if FIONREAD does not exist.
-   (In fact, this may actually read some input.)
-
-   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
-
-static void
-get_input_pending (addr, do_timers_now)
-     int *addr;
-     int do_timers_now;
-{
-  get_filtered_input_pending (addr, do_timers_now, 0);
+  *addr = (!NILP (Vquit_flag) || readable_events (flags));
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -6534,6 +6601,7 @@ record_asynch_buffer_change ()
 {
   struct input_event event;
   Lisp_Object tem;
+  EVENT_INIT (event);
 
   event.kind = BUFFER_SWITCH_EVENT;
   event.frame_or_window = Qnil;
@@ -6588,13 +6656,26 @@ static int
 read_avail_input (expected)
      int expected;
 {
-  struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
-  int nread;
+  int nread = 0;
 
   if (read_socket_hook)
-    /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
+    {
+      int nr;
+      struct input_event hold_quit;
+
+      EVENT_INIT (hold_quit);
+      hold_quit.kind = NO_EVENT;
+
+      /* No need for FIONREAD or fcntl; just say don't wait.  */
+      while (nr = (*read_socket_hook) (input_fd, expected, &hold_quit), nr > 0)
+       {
+         nread += nr;
+         expected = 0;
+       }
+      if (hold_quit.kind != NO_EVENT)
+       kbd_buffer_store_event (&hold_quit);
+    }
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -6621,7 +6702,12 @@ read_avail_input (expected)
        /* ??? Is it really right to send the signal just to this process
           rather than to the whole process group?
           Perhaps on systems with FIONREAD Emacs is alone in its group.  */
-       kill (getpid (), SIGHUP);
+       {
+         if (! noninteractive)
+           kill (getpid (), SIGHUP);
+         else
+           n_to_read = 0;
+       }
       if (n_to_read == 0)
        return 0;
       if (n_to_read > sizeof cbuf)
@@ -6690,34 +6776,57 @@ read_avail_input (expected)
 #endif /* no FIONREAD */
       for (i = 0; i < nread; i++)
        {
-         buf[i].kind = ASCII_KEYSTROKE_EVENT;
-         buf[i].modifiers = 0;
+         struct input_event buf;
+         EVENT_INIT (buf);
+         buf.kind = ASCII_KEYSTROKE_EVENT;
+         buf.modifiers = 0;
          if (meta_key == 1 && (cbuf[i] & 0x80))
-           buf[i].modifiers = meta_modifier;
+           buf.modifiers = meta_modifier;
          if (meta_key != 2)
            cbuf[i] &= ~0x80;
 
-         buf[i].code = cbuf[i];
-         buf[i].frame_or_window = selected_frame;
-         buf[i].arg = Qnil;
-       }
-    }
+         buf.code = cbuf[i];
+         buf.frame_or_window = selected_frame;
+         buf.arg = Qnil;
 
-  /* Scan the chars for C-g and store them in kbd_buffer.  */
-  for (i = 0; i < nread; i++)
-    {
-      kbd_buffer_store_event (&buf[i]);
-      /* Don't look at input that follows a C-g too closely.
-        This reduces lossage due to autorepeat on C-g.  */
-      if (buf[i].kind == ASCII_KEYSTROKE_EVENT
-         && buf[i].code == quit_char)
-       break;
+         kbd_buffer_store_event (&buf);
+         /* Don't look at input that follows a C-g too closely.
+            This reduces lossage due to autorepeat on C-g.  */
+         if (buf.kind == ASCII_KEYSTROKE_EVENT
+             && buf.code == quit_char)
+           break;
+       }
     }
 
   return nread;
 }
 #endif /* not VMS */
 \f
+void
+handle_async_input ()
+{
+#ifdef BSD4_1
+  extern int select_alarmed;
+#endif
+
+  interrupt_input_pending = 0;
+
+  while (1)
+    {
+      int nread;
+      nread = read_avail_input (1);
+      /* -1 means it's not ok to read the input now.
+        UNBLOCK_INPUT will read it later; now, avoid infinite loop.
+        0 means there was no keyboard input available.  */
+      if (nread <= 0)
+       break;
+
+#ifdef BSD4_1
+      select_alarmed = 1;  /* Force the select emulator back to life */
+#endif
+    }
+}
+
 #ifdef SIGIO   /* for entire page */
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 
@@ -6727,10 +6836,6 @@ input_available_signal (signo)
 {
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
-#ifdef BSD4_1
-  extern int select_alarmed;
-#endif
-
 #if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
@@ -6741,23 +6846,18 @@ input_available_signal (signo)
   sigisheld (SIGIO);
 #endif
 
+#ifdef SYNC_INPUT
+  interrupt_input_pending = 1;
+#else
+  SIGNAL_THREAD_CHECK (signo);
+#endif
+
   if (input_available_clear_time)
     EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
 
-  while (1)
-    {
-      int nread;
-      nread = read_avail_input (1);
-      /* -1 means it's not ok to read the input now.
-        UNBLOCK_INPUT will read it later; now, avoid infinite loop.
-        0 means there was no keyboard input available.  */
-      if (nread <= 0)
-       break;
-
-#ifdef BSD4_1
-      select_alarmed = 1;  /* Force the select emulator back to life */
+#ifndef SYNC_INPUT
+  handle_async_input ();
 #endif
-    }
 
 #ifdef BSD4_1
   sigfree ();
@@ -6776,7 +6876,7 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (getpid (), SIGIO);
+  handle_async_input ();
 #endif
 }
 
@@ -6818,8 +6918,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
@@ -6835,8 +6933,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
@@ -6940,7 +7036,6 @@ menu_bar_items (old)
   menu_bar_items_index = i;
 
   Vinhibit_quit = oquit;
-  UNGCPRO;
   return menu_bar_items_vector;
 }
 \f
@@ -7360,7 +7455,7 @@ parse_menu_item (item, notreal, inmenubar)
       newcache = chkcache;
       if (chkcache)
        {
-         tem = Fkey_description (tem);
+         tem = Fkey_description (tem, Qnil);
          if (CONSP (prefix))
            {
              if (STRINGP (XCAR (prefix)))
@@ -7929,7 +8024,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   register Lisp_Object name;
   int nlength;
   /* FIXME: Use the minibuffer's frame width.  */
-  int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
+  int width = FRAME_COLS (SELECTED_FRAME ()) - 4;
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
@@ -8234,7 +8329,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall)
      int do_funcall;
 {
   Lisp_Object next;
-  
+
   next = access_keymap (map, key, 1, 0, 1);
 
   /* Handle symbol with autoload definition.  */
@@ -8249,7 +8344,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall)
       && (!NILP (Farrayp (XSYMBOL (next)->function))
          || KEYMAPP (XSYMBOL (next)->function)))
     next = XSYMBOL (next)->function;
-           
+
   /* If the keymap gives a function, not an
      array, then call the function with one arg and use
      its value instead.  */
@@ -8750,14 +8845,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
             keymap may have changed, so replay the sequence.  */
          if (BUFFERP (key))
            {
-             EMACS_TIME initial_idleness_start_time;
-             EMACS_SET_SECS_USECS (initial_idleness_start_time,
-                                   EMACS_SECS (timer_last_idleness_start_time),
-                                   EMACS_USECS (timer_last_idleness_start_time));
-
-             /* Resume idle state, using the same start-time as before.  */
-             timer_start_idle ();
-             timer_idleness_start_time = initial_idleness_start_time;
+             timer_resume_idle ();
 
              mock_input = t;
              /* Reset the current buffer from the selected window
@@ -8831,6 +8919,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (EVENT_HAS_PARAMETERS (key))
        {
          Lisp_Object kind;
+         Lisp_Object string;
 
          kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
@@ -8838,7 +8927,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              Lisp_Object window, posn;
 
              window = POSN_WINDOW      (EVENT_START (key));
-             posn   = POSN_BUFFER_POSN (EVENT_START (key));
+             posn   = POSN_POSN (EVENT_START (key));
 
              if (CONSP (posn)
                  || (!NILP (fake_prefixed_keys)
@@ -8896,7 +8985,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  localized_local_map = 1;
                  start = EVENT_START (key);
 
-                 if (CONSP (start) && CONSP (XCDR (start)))
+                 if (CONSP (start) && POSN_INBUFFER_P (start))
                    {
                      pos = POSN_BUFFER_POSN (start);
                      if (INTEGERP (pos)
@@ -8947,11 +9036,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* If on a mode line string with a local keymap,
                     reconsider the key sequence with that keymap.  */
-                 if (CONSP (POSN_STRING (EVENT_START (key))))
+                 if (string = POSN_STRING (EVENT_START (key)),
+                     (CONSP (string) && STRINGP (XCAR (string))))
                    {
-                     Lisp_Object string, pos, map, map2;
+                     Lisp_Object pos, map, map2;
 
-                     string = POSN_STRING (EVENT_START (key));
                      pos = XCDR (string);
                      string = XCAR (string);
                       if (XINT (pos) >= 0
@@ -8970,16 +9059,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  goto replay_key;
                }
-             else if (CONSP (POSN_STRING (EVENT_START (key)))
-                      && NILP (from_string))
+             else if (NILP (from_string)
+                      && (string = POSN_STRING (EVENT_START (key)),
+                          (CONSP (string) && STRINGP (XCAR (string)))))
                {
                  /* For a click on a string, i.e. overlay string or a
                     string displayed via the `display' property,
                     consider `local-map' and `keymap' properties of
                     that string.  */
-                 Lisp_Object string, pos, map, map2;
+                 Lisp_Object pos, map, map2;
 
-                 string = POSN_STRING (EVENT_START (key));
                  pos = XCDR (string);
                  string = XCAR (string);
                  if (XINT (pos) >= 0
@@ -9006,7 +9095,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            {
              Lisp_Object posn;
 
-             posn = POSN_BUFFER_POSN (EVENT_START (key));
+             posn = POSN_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
              if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
@@ -9018,8 +9107,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
-                 POSN_BUFFER_SET_POSN (EVENT_START (key),
-                                       Fcons (posn, Qnil));
+                 POSN_SET_POSN (EVENT_START (key),
+                                Fcons (posn, Qnil));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -9138,6 +9227,27 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                             xterm-mouse-mode.  -stef
 
                             Isn't this just the most wonderful code ever?  */
+
+                         /* If mock_input > t + 1, the above simplification
+                            will actually end up dropping keys on the floor.
+                            This is probably OK for now, but even
+                            if mock_input <= t + 1, we need to adjust fkey
+                            and keytran.
+                            Typical case [header-line down-mouse-N]:
+                            mock_input = 2, t = 1, fkey.end = 1,
+                            last_real_key_start = 0.  */
+                         if (fkey.end > last_real_key_start)
+                           {
+                             fkey.end = fkey.start
+                               = min (last_real_key_start, fkey.start);
+                             fkey.map = fkey.parent;
+                             if (keytran.end > last_real_key_start)
+                               {
+                                 keytran.end = keytran.start
+                                   = min (last_real_key_start, keytran.start);
+                                 keytran.map = keytran.parent;
+                               }
+                           }
                          if (t == last_real_key_start)
                            {
                              mock_input = 0;
@@ -9241,7 +9351,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              /* Adjust the function-key-map counters.  */
              fkey.end += diff;
              fkey.start += diff;
-             
+
              goto replay_sequence;
            }
        }
@@ -9303,6 +9413,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;
 
              goto replay_sequence;
            }
@@ -9541,9 +9653,9 @@ a special event, so ignore the prefix argument and don't clear it.  */)
       tem = Fget (cmd, Qdisabled);
       if (!NILP (tem) && !NILP (Vrun_hooks))
        {
-         tem = Fsymbol_value (Qdisabled_command_hook);
+         tem = Fsymbol_value (Qdisabled_command_function);
          if (!NILP (tem))
-           return call1 (Vrun_hooks, Qdisabled_command_hook);
+           return call1 (Vrun_hooks, Qdisabled_command_function);
        }
     }
 
@@ -9595,6 +9707,7 @@ a special event, so ignore the prefix argument and don't clear it.  */)
       backtrace.args = &cmd;
       backtrace.nargs = 1;
       backtrace.evalargs = 0;
+      backtrace.debug_on_exit = 0;
 
       tem = Fcall_interactively (cmd, record_flag, keys);
 
@@ -9618,6 +9731,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object saved_keys, saved_last_point_position_buffer;
   Lisp_Object bindings, value;
   struct gcpro gcpro1, gcpro2, gcpro3;
+#ifdef HAVE_X_WINDOWS
+  /* The call to Fcompleting_read wil start and cancel the hourglass,
+     but if the hourglass was already scheduled, this means that no
+     hourglass will be shown for the actual M-x command itself.
+     So we restart it if it is already scheduled.  Note that checking
+     hourglass_shown_p is not enough,  normally the hourglass is not shown,
+     just scheduled to be shown.  */
+  int hstarted = hourglass_started ();
+#endif
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
@@ -9631,23 +9753,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   else if (CONSP (prefixarg) && XINT (XCAR (prefixarg)) == 4)
     strcpy (buf, "C-u ");
   else if (CONSP (prefixarg) && INTEGERP (XCAR (prefixarg)))
-    {
-      if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d ", XINT (XCAR (prefixarg)));
-      else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
-      else
-       abort ();
-    }
+    sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
   else if (INTEGERP (prefixarg))
-    {
-      if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d ", XINT (prefixarg));
-      else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", (long) XINT (prefixarg));
-      else
-       abort ();
-    }
+    sprintf (buf, "%ld ", (long) XINT (prefixarg));
 
   /* This isn't strictly correct if execute-extended-command
      is bound to anything else.  Perhaps it should use
@@ -9663,6 +9771,10 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                               Qt, Qnil, Qextended_command_history, Qnil,
                               Qnil);
 
+#ifdef HAVE_X_WINDOWS
+  if (hstarted) start_hourglass ();
+#endif
+
   if (STRINGP (function) && SCHARS (function) == 0)
     error ("No command name given");
 
@@ -9698,7 +9810,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);
@@ -9735,7 +9847,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
          int count = SPECPDL_INDEX ();
 
          record_unwind_protect (pop_message_unwind, Qnil);
-         binding = Fkey_description (bindings);
+         binding = Fkey_description (bindings, Qnil);
 
          newmessage
            = (char *) alloca (SCHARS (SYMBOL_NAME (function))
@@ -9772,6 +9884,18 @@ detect_input_pending ()
   return input_pending;
 }
 
+/* Return nonzero if input events other than mouse movements are
+   pending.  */
+
+int
+detect_input_pending_ignore_squeezables ()
+{
+  if (!input_pending)
+    get_input_pending (&input_pending, READABLE_EVENTS_IGNORE_SQUEEZABLES);
+
+  return input_pending;
+}
+
 /* Return nonzero if input events are pending, and run any pending timers.  */
 
 int
@@ -9781,7 +9905,7 @@ detect_input_pending_run_timers (do_display)
   int old_timers_run = timers_run;
 
   if (!input_pending)
-    get_input_pending (&input_pending, 1);
+    get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
 
   if (old_timers_run != timers_run && do_display)
     {
@@ -9809,7 +9933,7 @@ clear_input_pending ()
 }
 
 /* Return nonzero if there are pending requeued events.
-   This isn't used yet.  The hope is to make wait_reading_process_input
+   This isn't used yet.  The hope is to make wait_reading_process_output
    call it, and return if it runs Lisp code that unreads something.
    The problem is, kbd_buffer_get_event needs to be fixed to know what
    to do in that case.  It isn't trivial.  */
@@ -9830,7 +9954,9 @@ if there is a doubt, the value is t.  */)
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  get_filtered_input_pending (&input_pending, 1, 1);
+  get_input_pending (&input_pending,
+                    READABLE_EVENTS_DO_TIMERS_NOW
+                    | READABLE_EVENTS_FILTER_EVENTS);
   return input_pending > 0 ? Qt : Qnil;
 }
 
@@ -10008,7 +10134,6 @@ Also end any kbd macro being defined.  */)
   discard_tty_input ();
 
   kbd_fetch_ptr =  kbd_store_ptr;
-  Ffillarray (kbd_buffer_gcpro, Qnil);
   input_pending = 0;
 
   return Qnil;
@@ -10078,9 +10203,7 @@ void
 stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
-/* stuff_char works only in BSD, versions 4.2 and up.  */
-#ifdef BSD_SYSTEM
-#ifndef BSD4_1
+#ifdef SIGTSTP  /* stuff_char is defined if SIGTSTP.  */
   register unsigned char *p;
 
   if (STRINGP (stuffstring))
@@ -10096,25 +10219,23 @@ stuff_buffered_input (stuffstring)
 
   /* Anything we have read ahead, put back for the shell to read.  */
   /* ?? What should this do when we have multiple keyboards??
-     Should we ignore anything that was typed in at the "wrong" kboard?  */
+     Should we ignore anything that was typed in at the "wrong" kboard?
+
+     rms: we should stuff everything back into the kboard
+     it came from.  */
   for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++)
     {
-      int idx;
 
       if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
        kbd_fetch_ptr = kbd_buffer;
       if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT)
        stuff_char (kbd_fetch_ptr->code);
 
-      kbd_fetch_ptr->kind = NO_EVENT;
-      idx = 2 * (kbd_fetch_ptr - kbd_buffer);
-      ASET (kbd_buffer_gcpro, idx, Qnil);
-      ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+      clear_event (kbd_fetch_ptr);
     }
 
   input_pending = 0;
-#endif
-#endif /* BSD_SYSTEM and not BSD4_1 */
+#endif /* SIGTSTP */
 }
 \f
 void
@@ -10172,6 +10293,7 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
     }
 #endif /* USG */
 
+  SIGNAL_THREAD_CHECK (signalnum);
   cancel_echoing ();
 
   if (!NILP (Vquit_flag)
@@ -10423,6 +10545,69 @@ The elements of this list correspond to the arguments of
   return Flist (sizeof (val) / sizeof (val[0]), val);
 }
 
+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.
+If optional fourth arg WHOLE is non-nil, X is relative to the left
+edge of the window.
+
+The return value is similar to a mouse click position:
+   (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+    IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists.  */)
+  (x, y, frame_or_window, whole)
+     Lisp_Object x, y, frame_or_window, whole;
+{
+  CHECK_NATNUM (x);
+  CHECK_NATNUM (y);
+
+  if (NILP (frame_or_window))
+    frame_or_window = selected_window;
+
+  if (WINDOWP (frame_or_window))
+    {
+      struct window *w;
+
+      CHECK_LIVE_WINDOW (frame_or_window);
+
+      w = XWINDOW (frame_or_window);
+      XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x))
+                  + (NILP (whole)
+                     ? window_box_left_offset (w, TEXT_AREA)
+                     : - (WINDOW_LEFT_SCROLL_BAR_COLS (w)
+                          * WINDOW_FRAME_COLUMN_WIDTH (w)))));
+      XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y)));
+      frame_or_window = w->frame;
+    }
+
+  CHECK_LIVE_FRAME (frame_or_window);
+
+  return make_lispy_position (XFRAME (frame_or_window), &x, &y, 0);
+}
+
+DEFUN ("posn-at-point", Fposn_at_point, Sposn_at_point, 0, 2, 0,
+       doc: /* Return position information for buffer POS in WINDOW.
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.
+
+Return nil if position is not visible in window.  Otherwise,
+the return value is similar to that returned by `event-start' for
+a mouse click at the upper left corner of the glyph corresponding
+to the given buffer position:
+   (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+    IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists.  */)
+  (pos, window)
+     Lisp_Object pos, window;
+{
+  Lisp_Object tem;
+
+  tem = Fpos_visible_in_window_p (pos, window, Qt);
+  if (!NILP (tem))
+    tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window, Qnil);
+  return tem;
+}
+
 \f
 /*
  * Set up a new kboard object with reasonable initial values.
@@ -10509,7 +10694,6 @@ init_keyboard ()
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
 #ifdef HAVE_MOUSE
   do_mouse_tracking = Qnil;
 #endif
@@ -10622,8 +10806,8 @@ syms_of_keyboard ()
   Qtimer_event_handler = intern ("timer-event-handler");
   staticpro (&Qtimer_event_handler);
 
-  Qdisabled_command_hook = intern ("disabled-command-hook");
-  staticpro (&Qdisabled_command_hook);
+  Qdisabled_command_function = intern ("disabled-command-function");
+  staticpro (&Qdisabled_command_function);
 
   Qself_insert_command = intern ("self-insert-command");
   staticpro (&Qself_insert_command);
@@ -10646,9 +10830,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);
 
@@ -10659,11 +10840,7 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-  Qmouse_wheel = intern ("mouse-wheel");
-  staticpro (&Qmouse_wheel);
-#endif
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
   Qlanguage_change = intern ("language-change");
   staticpro (&Qlanguage_change);
 #endif
@@ -10671,7 +10848,7 @@ syms_of_keyboard ()
   staticpro (&Qdrag_n_drop);
 
   Qsave_session = intern ("save-session");
-  staticpro(&Qsave_session);
+  staticpro (&Qsave_session);
 
   Qusr1_signal = intern ("usr1-signal");
   staticpro (&Qusr1_signal);
@@ -10710,6 +10887,11 @@ syms_of_keyboard ()
   Qmenu_bar = intern ("menu-bar");
   staticpro (&Qmenu_bar);
 
+#ifdef HAVE_MOUSE
+  Qmouse_fixup_help_message = intern ("mouse-fixup-help-message");
+  staticpro (&Qmouse_fixup_help_message);
+#endif
+
   Qabove_handle = intern ("above-handle");
   staticpro (&Qabove_handle);
   Qhandle = intern ("handle");
@@ -10777,6 +10959,8 @@ syms_of_keyboard ()
   staticpro (&button_down_location);
   mouse_syms = Fmake_vector (make_number (1), Qnil);
   staticpro (&mouse_syms);
+  wheel_syms = Fmake_vector (make_number (2), Qnil);
+  staticpro (&wheel_syms);
 
   {
     int i;
@@ -10802,21 +10986,14 @@ syms_of_keyboard ()
   Fset (Qextended_command_history, Qnil);
   staticpro (&Qextended_command_history);
 
-  kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
-  staticpro (&kbd_buffer_gcpro);
-
   accent_key_syms = Qnil;
   staticpro (&accent_key_syms);
 
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
-#if defined(WINDOWSNT) || defined(MAC_OSX)
-  mouse_wheel_syms = Qnil;
-  staticpro (&mouse_wheel_syms);
   drag_n_drop_syms = Qnil;
   staticpro (&drag_n_drop_syms);
-#endif
 
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
@@ -10830,6 +11007,9 @@ 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 (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
@@ -10856,6 +11036,8 @@ syms_of_keyboard ()
   defsubr (&Sset_input_mode);
   defsubr (&Scurrent_input_mode);
   defsubr (&Sexecute_extended_command);
+  defsubr (&Sposn_at_point);
+  defsubr (&Sposn_at_x_y);
 
   DEFVAR_LISP ("last-command-char", &last_command_char,
               doc: /* Last input event that was part of a command.  */);
@@ -11026,11 +11208,13 @@ Useful to set before you dump a modified Emacs.  */);
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
               doc: /* Translate table for keyboard input, or nil.
-Each character is looked up in this string and the contents used instead.
-The value may be a string, a vector, or a char-table.
-If it is a string or vector of length N,
-character codes N and up are untranslated.
-In a vector or a char-table, an element which is nil means "no translation".
+If non-nil, the value should be a char-table.  Each character read
+from the keyboard is looked up in this char-table.  If the value found
+there is non-nil, then it is used instead of the actual input character.
+
+The value can also be a string or vector, but this is considered obsolete.
+If it is a string or vector of length N, character codes N and up are left
+untranslated.  In a vector, an element which is nil means "no translation".
 
 This is applied to the characters supplied to input methods, not their
 output.  See also `translation-table-for-input'.  */);
@@ -11094,21 +11278,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,
@@ -11125,13 +11300,15 @@ The elements of the list are event types that may have menu bar bindings.  */);
                 doc: /* Per-terminal keymap that overrides all other local keymaps.
 If this variable is non-nil, it is used as a keymap instead of the
 buffer's local map, and the minor mode keymaps and text property keymaps.
+It also replaces `overriding-local-map'.
+
 This variable is intended to let commands such as `universal-argument'
 set up a different keymap for reading the next command.  */);
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
               doc: /* Keymap that overrides all other local keymaps.
-If this variable is non-nil, it is used as a keymap instead of the
-buffer's local map, and the minor mode keymaps and text property keymaps.  */);
+If this variable is non-nil, it is used as a keymap--replacing the
+buffer's local map, the minor mode keymaps, and char property keymaps.  */);
   Voverriding_local_map = Qnil;
 
   DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
@@ -11216,8 +11393,8 @@ It's called with one argument, the help string to display.  */);
 
 After a command is executed, if point is moved into a region that has
 special properties (e.g. composition, display), we adjust point to
-the boundary of the region.  But, several special commands sets this
-variable to non-nil, then we suppress the point adjustment.
+the boundary of the region.  But, when a command sets this variable to
+non-nil, we suppress the point adjustment.
 
 This variable is set to nil before reading a command, and is checked
 just after executing the command.  */);
@@ -11242,6 +11419,12 @@ Used during Emacs' startup.  */);
               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.  */);
   Vminibuffer_message_timeout = make_number (2);
+
+  DEFVAR_LISP ("throw-on-input", &Vthrow_on_input,
+              doc: /* If non-nil, any keyboard input throws to this symbol.
+The value of that variable is passed to `quit-flag' and later causes a
+peculiar kind of quitting.  */);
+  Vthrow_on_input = Qnil;
 }
 
 void
@@ -11255,16 +11438,81 @@ keys_of_keyboard ()
 
   initial_define_lispy_key (Vspecial_event_map, "delete-frame",
                            "handle-delete-frame");
+  /* Here we used to use `ignore-event' which would simple set prefix-arg to
+     current-prefix-arg, as is done in `handle-switch-frame'.
+     But `handle-switch-frame is not run from the special-map.
+     Commands from that map are run in a special way that automatically
+     preserves the prefix-arg.  Restoring the prefix arg here is not just
+     redundant but harmful:
+     - C-u C-x v =
+     - current-prefix-arg is set to non-nil, prefix-arg is set to nil.
+     - after the first prompt, the exit-minibuffer-hook is run which may
+       iconify a frame and thus push a `iconify-frame' event.
+     - after running exit-minibuffer-hook, current-prefix-arg is
+       restored to the non-nil value it had before the prompt.
+     - we enter the second prompt.
+       current-prefix-arg is non-nil, prefix-arg is nil.
+     - before running the first real event, we run the special iconify-frame
+       event, but we pass the `special' arg to execute-command so
+       current-prefix-arg and prefix-arg are left untouched.
+     - here we foolishly copy the non-nil current-prefix-arg to prefix-arg.
+     - the next key event will have a spuriously non-nil current-prefix-arg.  */
   initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
-                           "ignore-event");
+                           "ignore");
   initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
-                           "ignore-event");
+                           "ignore");
   /* Handling it at such a low-level causes read_key_sequence to get
    * confused because it doesn't realize that the current_buffer was
    * changed by read_char.
-   * 
+   *
    * initial_define_lispy_key (Vspecial_event_map, "select-window",
    *                       "handle-select-window"); */
   initial_define_lispy_key (Vspecial_event_map, "save-session",
                            "handle-save-session");
 }
+
+/* Mark the pointers in the kboard objects.
+   Called by the Fgarbage_collector.  */
+void
+mark_kboards ()
+{
+  KBOARD *kb;
+  Lisp_Object *p;
+  for (kb = all_kboards; kb; kb = kb->next_kboard)
+    {
+      if (kb->kbd_macro_buffer)
+       for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++)
+         mark_object (*p);
+      mark_object (kb->Voverriding_terminal_local_map);
+      mark_object (kb->Vlast_command);
+      mark_object (kb->Vreal_last_command);
+      mark_object (kb->Vprefix_arg);
+      mark_object (kb->Vlast_prefix_arg);
+      mark_object (kb->kbd_queue);
+      mark_object (kb->defining_kbd_macro);
+      mark_object (kb->Vlast_kbd_macro);
+      mark_object (kb->Vsystem_key_alist);
+      mark_object (kb->system_key_syms);
+      mark_object (kb->Vdefault_minibuffer_frame);
+      mark_object (kb->echo_string);
+    }
+  {
+    struct input_event *event;
+    for (event = kbd_fetch_ptr; event != kbd_store_ptr; event++)
+      {
+       if (event == kbd_buffer + KBD_BUFFER_SIZE)
+         event = kbd_buffer;
+       if (event->kind != SELECTION_REQUEST_EVENT
+           && event->kind != SELECTION_CLEAR_EVENT)
+         {
+           mark_object (event->x);
+           mark_object (event->y);
+         }
+       mark_object (event->frame_or_window);
+       mark_object (event->arg);
+      }
+  }
+}
+
+/* arch-tag: 774e34d7-6d31-42f3-8397-e079a4e4c9ca
+   (do not change this comment) */