]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Fix hang with large yanks This should fix the bug fixed by Mike
[gnu-emacs] / src / keyboard.c
index bf65df1584c628bbb950e9b0a365abd4016f3c87..6bd123c67109358d669f70a814a0a2894ef31e1d 100644 (file)
@@ -288,18 +288,18 @@ static bool input_was_pending;
 
 /* Circular buffer for pre-read keyboard input.  */
 
-static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
+static union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
 
 /* 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
    next available char is in kbd_buffer[0].  */
-static struct input_event *kbd_fetch_ptr;
+static union buffered_input_event *kbd_fetch_ptr;
 
 /* Pointer to next place to store character in kbd_buffer.  This
    may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
    character should go in kbd_buffer[0].  */
-static struct input_event * volatile kbd_store_ptr;
+static union buffered_input_event *volatile kbd_store_ptr;
 
 /* The above pair of variables forms a "queue empty" flag.  When we
    enqueue a non-hook event, we increment kbd_store_ptr.  When we
@@ -372,14 +372,9 @@ static bool help_char_p (Lisp_Object);
 static void save_getcjmp (sys_jmp_buf);
 static void restore_getcjmp (sys_jmp_buf);
 static Lisp_Object apply_modifiers (int, Lisp_Object);
-static void clear_event (struct input_event *);
 static void restore_kboard_configuration (int);
-#ifdef USABLE_SIGIO
-static void deliver_input_available_signal (int signo);
-#endif
 static void handle_interrupt (bool);
 static _Noreturn void quit_throw_to_read_char (bool);
-static void process_special_events (void);
 static void timer_start_idle (void);
 static void timer_stop_idle (void);
 static void timer_resume_idle (void);
@@ -391,47 +386,47 @@ static void store_user_signal_events (void);
 static void
 kset_echo_string (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (echo_string) = val;
+  kb->echo_string_ = val;
 }
 static void
 kset_kbd_queue (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (kbd_queue) = val;
+  kb->kbd_queue_ = val;
 }
 static void
 kset_keyboard_translate_table (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Vkeyboard_translate_table) = val;
+  kb->Vkeyboard_translate_table_ = val;
 }
 static void
 kset_last_prefix_arg (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Vlast_prefix_arg) = val;
+  kb->Vlast_prefix_arg_ = val;
 }
 static void
 kset_last_repeatable_command (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Vlast_repeatable_command) = val;
+  kb->Vlast_repeatable_command_ = val;
 }
 static void
 kset_local_function_key_map (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Vlocal_function_key_map) = val;
+  kb->Vlocal_function_key_map_ = val;
 }
 static void
 kset_overriding_terminal_local_map (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Voverriding_terminal_local_map) = val;
+  kb->Voverriding_terminal_local_map_ = val;
 }
 static void
 kset_real_last_command (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (Vreal_last_command) = val;
+  kb->Vreal_last_command_ = val;
 }
 static void
 kset_system_key_syms (struct kboard *kb, Lisp_Object val)
 {
-  kb->INTERNAL_FIELD (system_key_syms) = val;
+  kb->system_key_syms_ = val;
 }
 
 \f
@@ -758,11 +753,11 @@ force_auto_save_soon (void)
 \f
 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 throw to `exit' -- for
-instance `(throw 'exit nil)'.
-If you throw a value other than t, `recursive-edit' returns normally
+To get out of the recursive edit, a command can throw to ‘exit’ -- for
+instance ‘(throw 'exit nil)’.
+If you throw a value other than t, ‘recursive-edit’ returns normally
 to the function that called it.  Throwing a t value causes
-`recursive-edit' to quit, so that control returns to the command loop
+‘recursive-edit’ to quit, so that control returns to the command loop
 one level up.
 
 This function is called by the editor initialization to begin editing.  */)
@@ -1618,6 +1613,7 @@ command_loop_1 (void)
     finalize:
 
       if (current_buffer == prev_buffer
+         && XBUFFER (XWINDOW (selected_window)->contents) == current_buffer
          && last_point_position != PT
          && NILP (Vdisable_point_adjustment)
          && NILP (Vglobal_disable_point_adjustment))
@@ -1686,6 +1682,8 @@ adjust_point_for_property (ptrdiff_t last_pt, bool modified)
   bool check_composition = ! modified, check_display = 1, check_invisible = 1;
   ptrdiff_t orig_pt = PT;
 
+  eassert (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer);
+
   /* FIXME: cycling is probably not necessary because these properties
      can't be usefully combined anyway.  */
   while (check_composition || check_display || check_invisible)
@@ -1702,7 +1700,8 @@ adjust_point_for_property (ptrdiff_t last_pt, bool modified)
       if (check_display
          && PT > BEGV && PT < ZV
          && !NILP (val = get_char_property_and_overlay
-                             (make_number (PT), Qdisplay, Qnil, &overlay))
+                             (make_number (PT), Qdisplay, selected_window,
+                              &overlay))
          && display_prop_intangible_p (val, overlay, PT, PT_BYTE)
          && (!OVERLAYP (overlay)
              ? get_property_and_range (PT, Qdisplay, &val, &beg, &end, Qnil)
@@ -2192,7 +2191,7 @@ read_event_from_main_queue (struct timespec *end_time,
   save_getcjmp (save_jump);
   restore_getcjmp (local_getcjmp);
   if (!end_time)
-       timer_start_idle ();
+    timer_start_idle ();
   c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time);
   restore_getcjmp (save_jump);
 
@@ -3442,7 +3441,7 @@ readable_events (int flags)
 #endif
                   ))
         {
-          struct input_event *event;
+          union buffered_input_event *event;
 
           event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
                    ? kbd_fetch_ptr
@@ -3459,8 +3458,8 @@ readable_events (int flags)
                  && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
                       && (event->kind == SCROLL_BAR_CLICK_EVENT
                           || event->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
-                      && event->part == scroll_bar_handle
-                      && event->modifiers == 0)
+                      && event->ie.part == scroll_bar_handle
+                      && event->ie.modifiers == 0)
 #endif
                  && !((flags & READABLE_EVENTS_FILTER_EVENTS)
                       && event->kind == BUFFER_SWITCH_EVENT))
@@ -3547,8 +3546,8 @@ kbd_buffer_store_event (register struct input_event *event)
    subsequent input events have been parsed (and discarded).  */
 
 void
-kbd_buffer_store_event_hold (register struct input_event *event,
-                            struct input_event *hold_quit)
+kbd_buffer_store_buffered_event (union buffered_input_event *event,
+                                struct input_event *hold_quit)
 {
   if (event->kind == NO_EVENT)
     emacs_abort ();
@@ -3558,36 +3557,36 @@ kbd_buffer_store_event_hold (register struct input_event *event,
 
   if (event->kind == ASCII_KEYSTROKE_EVENT)
     {
-      register int c = event->code & 0377;
+      int c = event->ie.code & 0377;
 
-      if (event->modifiers & ctrl_modifier)
+      if (event->ie.modifiers & ctrl_modifier)
        c = make_ctrl_char (c);
 
-      c |= (event->modifiers
+      c |= (event->ie.modifiers
            & (meta_modifier | alt_modifier
               | hyper_modifier | super_modifier));
 
       if (c == quit_char)
        {
-         KBOARD *kb = FRAME_KBOARD (XFRAME (event->frame_or_window));
-         struct input_event *sp;
+         KBOARD *kb = FRAME_KBOARD (XFRAME (event->ie.frame_or_window));
 
          if (single_kboard && kb != current_kboard)
            {
              kset_kbd_queue
-               (kb, list2 (make_lispy_switch_frame (event->frame_or_window),
+               (kb, list2 (make_lispy_switch_frame (event->ie.frame_or_window),
                            make_number (c)));
              kb->kbd_queue_has_data = 1;
+             union buffered_input_event *sp;
              for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++)
                {
                  if (sp == kbd_buffer + KBD_BUFFER_SIZE)
                    sp = kbd_buffer;
 
-                 if (event_to_kboard (sp) == kb)
+                 if (event_to_kboard (&sp->ie) == kb)
                    {
-                     sp->kind = NO_EVENT;
-                     sp->frame_or_window = Qnil;
-                     sp->arg = Qnil;
+                     sp->ie.kind = NO_EVENT;
+                     sp->ie.frame_or_window = Qnil;
+                     sp->ie.arg = Qnil;
                    }
                }
              return;
@@ -3595,7 +3594,7 @@ kbd_buffer_store_event_hold (register struct input_event *event,
 
          if (hold_quit)
            {
-             *hold_quit = *event;
+             *hold_quit = event->ie;
              return;
            }
 
@@ -3606,9 +3605,9 @@ kbd_buffer_store_event_hold (register struct input_event *event,
          {
            Lisp_Object focus;
 
-           focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
+           focus = FRAME_FOCUS_FRAME (XFRAME (event->ie.frame_or_window));
            if (NILP (focus))
-             focus = event->frame_or_window;
+             focus = event->ie.frame_or_window;
            internal_last_event_frame = focus;
            Vlast_event_frame = focus;
          }
@@ -3650,8 +3649,7 @@ kbd_buffer_store_event_hold (register struct input_event *event,
           /* Don't read keyboard input until we have processed kbd_buffer.
              This happens when pasting text longer than KBD_BUFFER_SIZE/2.  */
           hold_keyboard_input ();
-          if (!noninteractive)
-            ignore_sigio ();
+          unrequest_sigio ();
           stop_polling ();
         }
 #endif /* subprocesses */
@@ -3678,22 +3676,27 @@ kbd_buffer_store_event_hold (register struct input_event *event,
 }
 
 
-/* Put an input event back in the head of the event queue.  */
+#ifdef HAVE_X11
+
+/* Put a selection input event back in the head of the event queue.  */
 
 void
-kbd_buffer_unget_event (register struct input_event *event)
+kbd_buffer_unget_event (struct selection_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)
+  union buffered_input_event *kp = kbd_fetch_ptr - 1;
+  if (kp != kbd_store_ptr)
     {
-      --kbd_fetch_ptr;
-      *kbd_fetch_ptr = *event;
+      kp->sie = *event;
+      kbd_fetch_ptr = kp;
     }
 }
 
+#endif
+
 /* Limit help event positions to this range, to avoid overflow problems.  */
 #define INPUT_EVENT_POS_MAX \
   ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \
@@ -3772,7 +3775,7 @@ kbd_buffer_store_help_event (Lisp_Object frame, Lisp_Object help)
 void
 discard_mouse_events (void)
 {
-  struct input_event *sp;
+  union buffered_input_event *sp;
   for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++)
     {
       if (sp == kbd_buffer + KBD_BUFFER_SIZE)
@@ -3802,7 +3805,7 @@ discard_mouse_events (void)
 bool
 kbd_buffer_events_waiting (void)
 {
-  struct input_event *sp;
+  union buffered_input_event *sp;
 
   for (sp = kbd_fetch_ptr;
        sp != kbd_store_ptr && sp->kind == NO_EVENT;
@@ -3820,7 +3823,7 @@ kbd_buffer_events_waiting (void)
 /* Clear input event EVENT.  */
 
 static void
-clear_event (struct input_event *event)
+clear_event (union buffered_input_event *event)
 {
   event->kind = NO_EVENT;
 }
@@ -3845,6 +3848,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       /* Start reading input again because we have processed enough to
          be able to accept new events again.  */
       unhold_keyboard_input ();
+      request_sigio ();
       start_polling ();
     }
 #endif /* subprocesses */
@@ -3941,13 +3945,13 @@ kbd_buffer_get_event (KBOARD **kbp,
      mouse movement enabled and available.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
     {
-      struct input_event *event;
+      union buffered_input_event *event;
 
       event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
               ? kbd_fetch_ptr
               : kbd_buffer);
 
-      *kbp = event_to_kboard (event);
+      *kbp = event_to_kboard (&event->ie);
       if (*kbp == 0)
        *kbp = current_kboard;  /* Better than returning null ptr?  */
 
@@ -3960,12 +3964,10 @@ kbd_buffer_get_event (KBOARD **kbp,
          || event->kind == SELECTION_CLEAR_EVENT)
        {
 #ifdef HAVE_X11
-         struct input_event copy;
-
          /* Remove it from the buffer before processing it,
             since otherwise swallow_events will see it
             and process it again.  */
-         copy = *event;
+         struct selection_input_event copy = event->sie;
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
          x_handle_selection_event (&copy);
@@ -3979,7 +3981,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #if defined (HAVE_NS)
       else if (event->kind == NS_TEXT_EVENT)
         {
-          if (event->code == KEY_NS_PUT_WORKING_TEXT)
+          if (event->ie.code == KEY_NS_PUT_WORKING_TEXT)
             obj = list1 (intern ("ns-put-working-text"));
           else
             obj = list1 (intern ("ns-unput-working-text"));
@@ -3994,7 +3996,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       else if (event->kind == DELETE_WINDOW_EVENT)
        {
          /* Make an event (delete-frame (FRAME)).  */
-         obj = list2 (Qdelete_frame, list1 (event->frame_or_window));
+         obj = list2 (Qdelete_frame, list1 (event->ie.frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
 #endif
@@ -4003,13 +4005,13 @@ kbd_buffer_get_event (KBOARD **kbp,
       else if (event->kind == ICONIFY_EVENT)
        {
          /* Make an event (iconify-frame (FRAME)).  */
-         obj = list2 (Qiconify_frame, list1 (event->frame_or_window));
+         obj = list2 (Qiconify_frame, list1 (event->ie.frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
       else if (event->kind == DEICONIFY_EVENT)
        {
          /* Make an event (make-frame-visible (FRAME)).  */
-         obj = list2 (Qmake_frame_visible, list1 (event->frame_or_window));
+         obj = list2 (Qmake_frame_visible, list1 (event->ie.frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
 #endif
@@ -4025,8 +4027,8 @@ kbd_buffer_get_event (KBOARD **kbp,
        {
          kbd_fetch_ptr = event + 1;
          input_pending = readable_events (0);
-         if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
-           x_activate_menubar (XFRAME (event->frame_or_window));
+         if (FRAME_LIVE_P (XFRAME (event->ie.frame_or_window)))
+           x_activate_menubar (XFRAME (event->ie.frame_or_window));
        }
 #endif
 #ifdef HAVE_NTGUI
@@ -4034,9 +4036,9 @@ kbd_buffer_get_event (KBOARD **kbp,
        {
          /* Make an event (language-change FRAME CODEPAGE LANGUAGE-ID).  */
          obj = list4 (Qlanguage_change,
-                      event->frame_or_window,
-                      make_number (event->code),
-                      make_number (event->modifiers));
+                      event->ie.frame_or_window,
+                      make_number (event->ie.code),
+                      make_number (event->ie.modifiers));
          kbd_fetch_ptr = event + 1;
        }
 #endif
@@ -4045,16 +4047,16 @@ kbd_buffer_get_event (KBOARD **kbp,
        {
 #ifdef HAVE_W32NOTIFY
          /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK).  */
-         obj = list3 (Qfile_notify, event->arg, event->frame_or_window);
+         obj = list3 (Qfile_notify, event->ie.arg, event->ie.frame_or_window);
 #else
-          obj = make_lispy_event (event);
+          obj = make_lispy_event (&event->ie);
 #endif
          kbd_fetch_ptr = event + 1;
        }
 #endif /* USE_FILE_NOTIFY */
       else if (event->kind == SAVE_SESSION_EVENT)
         {
-          obj = list2 (Qsave_session, event->arg);
+          obj = list2 (Qsave_session, event->ie.arg);
          kbd_fetch_ptr = event + 1;
         }
       /* Just discard these, by returning nil.
@@ -4071,11 +4073,11 @@ kbd_buffer_get_event (KBOARD **kbp,
        {
          Lisp_Object object, position, help, frame, window;
 
-         frame = event->frame_or_window;
-         object = event->arg;
-         position = make_number (Time_to_position (event->timestamp));
-         window = event->x;
-         help = event->y;
+         frame = event->ie.frame_or_window;
+         object = event->ie.arg;
+         position = make_number (Time_to_position (event->ie.timestamp));
+         window = event->ie.x;
+         help = event->ie.y;
          clear_event (event);
 
          kbd_fetch_ptr = event + 1;
@@ -4091,14 +4093,14 @@ kbd_buffer_get_event (KBOARD **kbp,
             switch-frame event if necessary.  */
          Lisp_Object frame, focus;
 
-          frame = event->frame_or_window;
+          frame = event->ie.frame_or_window;
           focus = FRAME_FOCUS_FRAME (XFRAME (frame));
           if (FRAMEP (focus))
             frame = focus;
 
           if (
 #ifdef HAVE_X11
-              ! NILP (event->arg)
+              ! NILP (event->ie.arg)
               &&
 #endif
               !EQ (frame, internal_last_event_frame)
@@ -4115,7 +4117,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #ifdef HAVE_WINDOW_SYSTEM
 
           Display_Info *di;
-          Lisp_Object frame = event->frame_or_window;
+          Lisp_Object frame = event->ie.frame_or_window;
           bool focused = false;
 
           for (di = x_display_list; di && ! focused; di = di->next)
@@ -4131,13 +4133,13 @@ kbd_buffer_get_event (KBOARD **kbp,
 #ifdef HAVE_DBUS
       else if (event->kind == DBUS_EVENT)
        {
-         obj = make_lispy_event (event);
+         obj = make_lispy_event (&event->ie);
          kbd_fetch_ptr = event + 1;
        }
 #endif
       else if (event->kind == CONFIG_CHANGED_EVENT)
        {
-         obj = make_lispy_event (event);
+         obj = make_lispy_event (&event->ie);
          kbd_fetch_ptr = event + 1;
        }
       else
@@ -4147,7 +4149,7 @@ kbd_buffer_get_event (KBOARD **kbp,
          Lisp_Object frame;
          Lisp_Object focus;
 
-         frame = event->frame_or_window;
+         frame = event->ie.frame_or_window;
          if (CONSP (frame))
            frame = XCAR (frame);
          else if (WINDOWP (frame))
@@ -4167,7 +4169,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 
          if (NILP (obj))
            {
-             obj = make_lispy_event (event);
+             obj = make_lispy_event (&event->ie);
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
     || defined (HAVE_NS) || defined (USE_GTK)
@@ -4177,7 +4179,7 @@ kbd_buffer_get_event (KBOARD **kbp,
                 beginning of the menu sequence, and we might as well leave
                 that as the `event with parameters' for this selection.  */
              if (used_mouse_menu
-                 && !EQ (event->frame_or_window, event->arg)
+                 && !EQ (event->ie.frame_or_window, event->ie.arg)
                  && (event->kind == MENU_BAR_EVENT
                      || event->kind == TOOL_BAR_EVENT))
                *used_mouse_menu = 1;
@@ -4257,7 +4259,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 static void
 process_special_events (void)
 {
-  struct input_event *event;
+  union buffered_input_event *event;
 
   for (event = kbd_fetch_ptr; event != kbd_store_ptr; ++event)
     {
@@ -4280,23 +4282,22 @@ process_special_events (void)
             between kbd_fetch_ptr and EVENT one slot to the right,
             cyclically.  */
 
-         struct input_event copy = *event;
-         struct input_event *beg
+         struct selection_input_event copy = event->sie;
+         union buffered_input_event *beg
            = (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
            ? kbd_buffer : kbd_fetch_ptr;
 
          if (event > beg)
-           memmove (beg + 1, beg, (event - beg) * sizeof (struct input_event));
+           memmove (beg + 1, beg, (event - beg) * sizeof *beg);
          else if (event < beg)
            {
              if (event > kbd_buffer)
                memmove (kbd_buffer + 1, kbd_buffer,
-                        (event - kbd_buffer) * sizeof (struct input_event));
+                        (event - kbd_buffer) * sizeof *kbd_buffer);
              *kbd_buffer = *(kbd_buffer + KBD_BUFFER_SIZE - 1);
              if (beg < kbd_buffer + KBD_BUFFER_SIZE - 1)
                memmove (beg + 1, beg,
-                        (kbd_buffer + KBD_BUFFER_SIZE - 1 - beg)
-                        * sizeof (struct input_event));
+                        (kbd_buffer + KBD_BUFFER_SIZE - 1 - beg) * sizeof *beg);
            }
 
          if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
@@ -4368,9 +4369,6 @@ timer_resume_idle (void)
   timer_idleness_start_time = timer_last_idleness_start_time;
 }
 
-/* This is only for debugging.  */
-struct input_event last_timer_event EXTERNALLY_VISIBLE;
-
 /* List of elisp functions to call, delayed because they were generated in
    a context where Elisp could not be safely run (e.g. redisplay, signal,
    ...).  Each element has the form (FUN . ARGS).  */
@@ -8707,12 +8705,10 @@ read_char_minibuf_menu_prompt (int commandflag,
       while (BUFFERP (obj));
       kset_defining_kbd_macro (current_kboard, orig_defn_macro);
 
-      if (!INTEGERP (obj) || XINT (obj) == -2)
-        return obj;
-
-      if (! EQ (obj, menu_prompt_more_char)
-         && (!INTEGERP (menu_prompt_more_char)
-             || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char))))))
+      if (!INTEGERP (obj) || XINT (obj) == -2
+         || (! EQ (obj, menu_prompt_more_char)
+             && (!INTEGERP (menu_prompt_more_char)
+                 || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char)))))))
        {
          if (!NILP (KVAR (current_kboard, defining_kbd_macro)))
            store_kbd_macro_char (obj);
@@ -9591,6 +9587,18 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
       /* Record what part of this_command_keys is the current key sequence.  */
       this_single_command_key_start = this_command_key_count - t;
+      /* When 'input-method-function' called above causes events to be
+        put on 'unread-post-input-method-events', and as result
+        'reread' is set to 'true', the value of 't' can become larger
+        than 'this_command_key_count', because 'add_command_key' is
+        not called to update 'this_command_key_count'.  If this
+        happens, 'this_single_command_key_start' will become negative
+        above, and any call to 'this-single-command-keys' will return
+        a garbled vector.  See bug #20223 for one such situation.
+        Here we force 'this_single_command_key_start' to never become
+        negative, to avoid that.  */
+      if (this_single_command_key_start < 0)
+       this_single_command_key_start = 0;
 
       /* Look for this sequence in input-decode-map.
         Scan from indec.end until we find a bound suffix.  */
@@ -10300,7 +10308,7 @@ stuff_buffered_input (Lisp_Object stuffstring)
       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);
+       stuff_char (kbd_fetch_ptr->ie.code);
 
       clear_event (kbd_fetch_ptr);
     }
@@ -10787,7 +10795,11 @@ The return value is similar to a mouse click position:
 The `posn-' functions access elements of such lists.  */)
   (Lisp_Object x, Lisp_Object y, Lisp_Object frame_or_window, Lisp_Object whole)
 {
-  CHECK_NATNUM (x);
+  CHECK_NUMBER (x);
+  /* We allow X of -1, for the newline in a R2L line that overflowed
+     into the left fringe.  */
+  if (XINT (x) != -1)
+    CHECK_NATNUM (x);
   CHECK_NATNUM (y);
 
   if (NILP (frame_or_window))
@@ -10835,8 +10847,9 @@ The `posn-' functions access elements of such lists.  */)
       Lisp_Object x = XCAR (tem);
       Lisp_Object y = XCAR (XCDR (tem));
 
-      /* Point invisible due to hscrolling?  */
-      if (XINT (x) < 0)
+      /* Point invisible due to hscrolling?  X can be -1 when a
+        newline in a R2L line overflows into the left fringe.  */
+      if (XINT (x) < -1)
        return Qnil;
       tem = Fposn_at_x_y (x, y, window, Qnil);
     }
@@ -11063,10 +11076,6 @@ syms_of_keyboard (void)
   tool_bar_items_vector = Qnil;
 
   DEFSYM (Qtimer_event_handler, "timer-event-handler");
-  DEFSYM (Qdisabled_command_function, "disabled-command-function");
-  DEFSYM (Qself_insert_command, "self-insert-command");
-  DEFSYM (Qforward_char, "forward-char");
-  DEFSYM (Qbackward_char, "backward-char");
 
   /* Non-nil disable property on a command means do not execute it;
      call disabled-command-function's value instead.  */
@@ -11174,7 +11183,6 @@ syms_of_keyboard (void)
   DEFSYM (Qhandle_switch_frame, "handle-switch-frame");
   DEFSYM (Qhandle_select_window, "handle-select-window");
 
-  DEFSYM (Qinput_method_function, "input-method-function");
   DEFSYM (Qinput_method_exit_on_first_char, "input-method-exit-on-first-char");
   DEFSYM (Qinput_method_use_echo_area, "input-method-use-echo-area");
 
@@ -11480,6 +11488,7 @@ for that character after that prefix key.  */);
               doc: /* Form to evaluate when Emacs starts up.
 Useful to set before you dump a modified Emacs.  */);
   Vtop_level = Qnil;
+  XSYMBOL (Qtop_level)->declared_special = false;
 
   DEFVAR_KBOARD ("keyboard-translate-table", Vkeyboard_translate_table,
                  doc: /* Translate table for local keyboard input, or nil.
@@ -11930,7 +11939,7 @@ mark_kboards (void)
       mark_object (KVAR (kb, echo_string));
     }
   {
-    struct input_event *event;
+    union buffered_input_event *event;
     for (event = kbd_fetch_ptr; event != kbd_store_ptr; event++)
       {
        if (event == kbd_buffer + KBD_BUFFER_SIZE)
@@ -11939,10 +11948,10 @@ mark_kboards (void)
        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);
+           mark_object (event->ie.x);
+           mark_object (event->ie.y);
+           mark_object (event->ie.frame_or_window);
+           mark_object (event->ie.arg);
          }
       }
   }