]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
*** empty log message ***
[gnu-emacs] / src / keyboard.c
index b33392e5dd61764d26486411bd984f7cbd51fc10..ba9db5b6e94bb862d73172ace8be0c7e1408f049 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03,04
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -117,6 +117,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 +131,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 */
@@ -479,36 +481,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
@@ -587,6 +559,7 @@ 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 ();
@@ -634,7 +607,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) || defined(HAVE_CARBON)
 #ifdef SIGIO
 #undef SIGIO
 #endif
@@ -703,11 +676,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.  */
@@ -827,6 +805,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,
@@ -1025,6 +1018,11 @@ 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;
 
@@ -1094,6 +1092,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.  */
@@ -1180,7 +1191,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);
@@ -1269,6 +1281,10 @@ command_loop ()
     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;
 
@@ -1323,6 +1339,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);
 }
 
@@ -1364,6 +1386,7 @@ cancel_hourglass_unwind (arg)
      Lisp_Object arg;
 {
   cancel_hourglass ();
+  return Qnil;
 }
 #endif
 
@@ -1832,6 +1855,16 @@ command_loop_1 ()
            call1 (Vrun_hooks, intern ("activate-mark-hook"));
        }
 
+      /* Setting transient-mark-mode to `only' is a way of
+        turning it on for just one command.  */
+      if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
+       {
+         if (EQ (Vtransient_mark_mode, Qidentity))
+           Vtransient_mark_mode = Qnil;
+         if (EQ (Vtransient_mark_mode, Qonly))
+           Vtransient_mark_mode = Qidentity;
+       }
+
     finalize:
 
       if (current_buffer == prev_buffer
@@ -1957,7 +1990,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)
@@ -2352,7 +2390,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;
@@ -2859,9 +2896,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;
 
@@ -2901,7 +2935,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)
@@ -2942,13 +2976,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);
@@ -3100,7 +3134,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;
     }
 
@@ -3547,10 +3581,33 @@ event_to_kboard (event)
 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;
@@ -3592,6 +3649,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
@@ -3621,7 +3684,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)
@@ -3633,7 +3698,6 @@ 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;
 
 #if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error
         prone to assign individual members for other events, in case
@@ -3663,9 +3727,6 @@ kbd_buffer_store_event (event)
       *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;
     }
 }
@@ -3684,24 +3745,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);
 }
 
 
@@ -3781,9 +3840,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;
 }
 
@@ -3842,10 +3898,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.  */
@@ -3969,9 +4022,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
          /* 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);
          obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
          kbd_fetch_ptr = event + 1;
        }
@@ -4200,7 +4251,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;
@@ -4228,12 +4279,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;
 
@@ -4981,8 +5043,11 @@ make_lispy_position (f, x, y, time)
     {
       /* It's a click in window window at frame coordinates (x,y)  */
       struct window *w = XWINDOW (window);
-      Lisp_Object object = Qnil;
+      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.  */
@@ -4998,9 +5063,10 @@ make_lispy_position (f, x, y, time)
 
          posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
          rx = wx, ry = wy;
-         string = mode_line_string (w, &rx, &ry, part, &charpos);
+         string = mode_line_string (w, part, &rx, &ry, &charpos,
+                                    &object, &dx, &dy, &width, &height);
          if (STRINGP (string))
-           object = Fcons (string, make_number (charpos));
+           string_info = Fcons (string, make_number (charpos));
          if (w == XWINDOW (selected_window))
            textpos = PT;
          else
@@ -5010,50 +5076,92 @@ make_lispy_position (f, x, y, time)
        {
          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, &rx, &ry, part, &charpos);
+         string = marginal_area_string (w, part, &rx, &ry, &charpos,
+                                        &object, &dx, &dy, &width, &height);
          if (STRINGP (string))
-           object = Fcons (string, make_number (charpos));
+           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 string;
+         Lisp_Object string2, object2 = Qnil;
          struct display_pos p;
+         int dx2, dy2;
+         int width2, height2;
          wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
-         buffer_posn_from_coords (w, &wx, &wy, &string, &p);
+         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 (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 (string))
-               object = Fcons (string,
-                               make_number (CHARPOS (p.string_pos)));
+             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)),
-                                       Qnil)));
+                                       extra_info)));
     }
   else if (f != 0)
     {
@@ -5458,7 +5566,7 @@ make_lispy_event (event)
       {
        Lisp_Object position;
        Lisp_Object head;
-       
+
        /* Build the position as appropriate for this mouse click.  */
        struct frame *f = XFRAME (event->frame_or_window);
 
@@ -6201,12 +6309,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])
@@ -6562,16 +6666,27 @@ static int
 read_avail_input (expected)
      int expected;
 {
-  struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
-  int nread;
-
-  for (i = 0; i < KBD_BUFFER_SIZE; i++)
-    EVENT_INIT (buf[i]);
+  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 discard = 0;
+      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
@@ -6672,34 +6787,56 @@ 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.  */
 
@@ -6709,9 +6846,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;
@@ -6726,20 +6860,11 @@ input_available_signal (signo)
   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 */
+#ifdef SYNC_INPUT
+  interrupt_input_pending = 1;
+#else
+  handle_async_input ();
 #endif
-    }
 
 #ifdef BSD4_1
   sigfree ();
@@ -6758,7 +6883,7 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (getpid (), SIGIO);
+  handle_async_input ();
 #endif
 }
 
@@ -7342,7 +7467,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)))
@@ -8216,7 +8341,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.  */
@@ -8231,7 +8356,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.  */
@@ -8732,14 +8857,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
@@ -8813,6 +8931,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))
@@ -8820,7 +8939,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)
@@ -8878,7 +8997,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)
@@ -8929,11 +9048,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
@@ -8952,16 +9071,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
@@ -8988,7 +9107,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))
@@ -9000,8 +9119,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;
@@ -9244,7 +9363,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;
            }
        }
@@ -9546,9 +9665,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);
        }
     }
 
@@ -9600,6 +9719,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);
 
@@ -9636,23 +9756,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
@@ -9740,7 +9846,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))
@@ -9814,7 +9920,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.  */
@@ -10013,7 +10119,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;
@@ -10083,9 +10188,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))
@@ -10101,25 +10204,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
@@ -10428,6 +10529,61 @@ 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, 3, 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.
+
+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)
+     Lisp_Object x, y, frame_or_window;
+{
+  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))
+                  + window_box_left_offset (w, TEXT_AREA)));
+      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);
+  return tem;
+}
+
 \f
 /*
  * Set up a new kboard object with reasonable initial values.
@@ -10514,7 +10670,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
@@ -10627,8 +10782,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);
@@ -10805,9 +10960,6 @@ 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);
 
@@ -10855,6 +11007,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.  */);
@@ -11025,11 +11179,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'.  */);
@@ -11124,6 +11280,7 @@ 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 overrides `overriding-local-map'.
 This variable is intended to let commands such as `universal-argument'
 set up a different keymap for reading the next command.  */);
 
@@ -11215,8 +11372,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.  */);
@@ -11261,7 +11418,7 @@ keys_of_keyboard ()
   /* 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",
@@ -11299,8 +11456,11 @@ mark_kboards ()
       {
        if (event == kbd_buffer + KBD_BUFFER_SIZE)
          event = kbd_buffer;
-       mark_object (event->x);
-       mark_object (event->y);
+       if (event->kind != SELECTION_REQUEST_EVENT)
+         {
+           mark_object (event->x);
+           mark_object (event->y);
+         }
        mark_object (event->frame_or_window);
        mark_object (event->arg);
       }