use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / keyboard.c
index 439a40f..20498d0 100644 (file)
@@ -1,7 +1,6 @@
 /* Keyboard and mouse input; editor command loop.
 
-Copyright (C) 1985-1989, 1993-1997, 1999-2014 Free Software Foundation,
-Inc.
+Copyright (C) 1985-1989, 1993-1997, 1999-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,6 +20,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #include "sysstdio.h"
+#include <sys/stat.h>
 
 #include "lisp.h"
 #include "termchar.h"
@@ -69,6 +69,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#include <gc.h> /* for GC_collect_a_little */
+
 /* Variables for blockinput.h:  */
 
 /* Positive if interrupt input is blocked right now.  */
@@ -228,7 +230,7 @@ static Lisp_Object Qbackward_char;
 Lisp_Object Qundefined;
 static Lisp_Object Qtimer_event_handler;
 
-/* read_key_sequence stores here the command definition of the
+/* `read_key_sequence' stores here the command definition of the
    key sequence that it reads.  */
 static Lisp_Object read_key_sequence_cmd;
 static Lisp_Object read_key_sequence_remapped;
@@ -356,7 +358,6 @@ static Lisp_Object Qecho_keystrokes;
 static void recursive_edit_unwind (Lisp_Object buffer);
 static Lisp_Object command_loop (void);
 static Lisp_Object Qcommand_execute;
-struct timespec timer_check (void);
 
 static void echo_now (void);
 static ptrdiff_t echo_length (void);
@@ -377,12 +378,6 @@ bool interrupt_input;
 /* Nonzero while interrupts are temporarily deferred during redisplay.  */
 bool interrupts_deferred;
 
-/* If we support a window system, turn on the code to poll periodically
-   to detect C-g.  It isn't actually used when doing interrupt input.  */
-#ifdef HAVE_WINDOW_SYSTEM
-#define POLL_FOR_INPUT
-#endif
-
 /* The time when Emacs started being idle.  */
 
 static struct timespec timer_idleness_start_time;
@@ -422,8 +417,8 @@ static Lisp_Object make_lispy_focus_in (Lisp_Object);
 static Lisp_Object make_lispy_focus_out (Lisp_Object);
 #endif /* HAVE_WINDOW_SYSTEM */
 static bool help_char_p (Lisp_Object);
-static void save_getcjmp (sys_jmp_buf);
-static void restore_getcjmp (sys_jmp_buf);
+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);
@@ -745,7 +740,7 @@ add_command_key (Lisp_Object key)
 Lisp_Object
 recursive_edit_1 (void)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
 
   if (command_loop_level > 0)
@@ -782,7 +777,8 @@ recursive_edit_1 (void)
   if (STRINGP (val))
     xsignal1 (Qerror, val);
 
-  return unbind_to (count, Qnil);
+  dynwind_end ();
+  return Qnil;
 }
 
 /* When an auto-save happens, record the "time", and don't do again soon.  */
@@ -817,33 +813,39 @@ one level up.
 This function is called by the editor initialization to begin editing.  */)
   (void)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   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 ())
+  if (input_blocked_p ()) {
+    dynwind_end ();
     return Qnil;
+  }
 
-  command_loop_level++;
-  update_mode_lines = 17;
-
-  if (command_loop_level
+  if (command_loop_level >= 0
       && current_buffer != XBUFFER (XWINDOW (selected_window)->contents))
     buffer = Fcurrent_buffer ();
   else
     buffer = Qnil;
 
+  /* Don't do anything interesting between the increment and the
+     record_unwind_protect!  Otherwise, we could get distracted and
+     never decrement the counter again.  */
+  command_loop_level++;
+  update_mode_lines = 17;
+  record_unwind_protect (recursive_edit_unwind, buffer);
+
   /* If we leave recursive_edit_1 below with a `throw' for instance,
      like it is done in the splash screen display, we have to
      make sure that we restore single_kboard as command_loop_1
      would have done if it were left normally.  */
   if (command_loop_level > 0)
     temporarily_switch_to_single_kboard (SELECTED_FRAME ());
-  record_unwind_protect (recursive_edit_unwind, buffer);
 
   recursive_edit_1 ();
-  return unbind_to (count, Qnil);
+  dynwind_end ();
+  return Qnil;
 }
 
 void
@@ -1219,7 +1221,7 @@ user_error (const char *msg)
   xsignal1 (Quser_error, build_string (msg));
 }
 
-_Noreturn
+/* _Noreturn will be added to prototype by make-docfile.  */
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
        doc: /* Exit from the innermost recursive edit or minibuffer.  */)
   (void)
@@ -1230,7 +1232,7 @@ DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0,
   user_error ("No recursive edit is in progress");
 }
 
-_Noreturn
+/* _Noreturn will be added to prototype by make-docfile.  */
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
        doc: /* Abort the command that requested this recursive edit or minibuffer input.  */)
   (void)
@@ -1271,7 +1273,7 @@ Normally, mouse motion is ignored.
 usage: (track-mouse BODY...)  */)
   (Lisp_Object args)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
 
   record_unwind_protect (tracking_off, do_mouse_tracking);
@@ -1279,7 +1281,8 @@ usage: (track-mouse BODY...)  */)
   do_mouse_tracking = Qt;
 
   val = Fprogn (args);
-  return unbind_to (count, val);
+  dynwind_end ();
+  return val;
 }
 
 /* If mouse has moved on some frame, return one of those frames.
@@ -1289,9 +1292,6 @@ usage: (track-mouse BODY...)  */)
    If ignore_mouse_drag_p is non-zero, ignore (implicit) mouse movement
    after resizing the tool-bar window.  */
 
-#if !defined HAVE_WINDOW_SYSTEM || defined USE_GTK || defined HAVE_NS
-static
-#endif
 bool ignore_mouse_drag_p;
 
 static struct frame *
@@ -1320,14 +1320,11 @@ some_mouse_moved (void)
 
 static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
                               bool, bool, bool, bool);
-void safe_run_hooks (Lisp_Object);
 static void adjust_point_for_property (ptrdiff_t, bool);
 
 /* The last boundary auto-added to buffer-undo-list.  */
 Lisp_Object last_undo_boundary;
 
-extern Lisp_Object Qregion_extract_function;
-
 /* FIXME: This is wrong rather than test window-system, we should call
    a new set-selection, which will then dispatch to x-set-selection, or
    tty-set-selection, or w32-set-selection, ...  */
@@ -1412,7 +1409,7 @@ command_loop_1 (void)
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
-         ptrdiff_t count = SPECPDL_INDEX ();
+          dynwind_begin ();
          specbind (Qinhibit_quit, Qt);
 
          sit_for (Vminibuffer_message_timeout, 0, 2);
@@ -1421,7 +1418,7 @@ command_loop_1 (void)
          message1 (0);
          safe_run_hooks (Qecho_area_clear_hook);
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
 
          /* If a C-g came in before, treat it as input now.  */
          if (!NILP (Vquit_flag))
@@ -1446,7 +1443,7 @@ command_loop_1 (void)
       Vthis_command_keys_shift_translated = Qnil;
 
       /* Read next key sequence; i gets its length.  */
-      i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+      i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
                             Qnil, 0, 1, 1, 0);
 
       /* A filter may have run while we were reading the input.  */
@@ -1535,7 +1532,7 @@ command_loop_1 (void)
          /* Here for a command that isn't executed directly.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
-            ptrdiff_t scount = SPECPDL_INDEX ();
+            dynwind_begin ();
 
             if (display_hourglass_p
                 && NILP (Vexecuting_kbd_macro))
@@ -1561,8 +1558,7 @@ command_loop_1 (void)
             hourglass cursor anyway.
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
-         if (NILP (Vexecuting_kbd_macro))
-            unbind_to (scount, Qnil);
+            dynwind_end ();
 #endif
           }
       kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg);
@@ -1694,7 +1690,7 @@ read_menu_command (void)
      menus.  */
   specbind (Qecho_keystrokes, make_number (0));
 
-  i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+  i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
                         Qnil, 0, 1, 1, 1);
 
   unbind_to (count, Qnil);
@@ -1938,12 +1934,12 @@ safe_run_hooks (Lisp_Object hook)
   /* FIXME: our `internal_condition_case' does not provide any way to pass data
      to its body or to its handlers other than via globals such as
      dynamically-bound variables ;-)  */
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   specbind (Qinhibit_quit, hook);
 
   run_hook_with_args (1, &hook, safe_run_hook_funcall);
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 \f
@@ -2088,16 +2084,13 @@ bind_polling_period (int n)
 \f
 /* Apply the control modifier to CHARACTER.  */
 
-#ifndef HAVE_NTGUI
-static
-#endif
 int
 make_ctrl_char (int c)
 {
   /* Save the upper bits here.  */
   int upper = c & ~0177;
 
-  if (! ASCII_BYTE_P (c))
+  if (! ASCII_CHAR_P (c))
     return c |= ctrl_modifier;
 
   c &= 0177;
@@ -2194,7 +2187,7 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
 
 
 \f
-/* Input of single characters from keyboard */
+/* Input of single characters from keyboard */
 
 static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu,
                                         struct timespec *end_time);
@@ -2220,11 +2213,11 @@ do { if (polling_stopped_here) start_polling ();        \
 
 static Lisp_Object
 read_event_from_main_queue (struct timespec *end_time,
-                            sys_jmp_buf local_getcjmp,
+                            sys_jmp_buf *local_getcjmp,
                             bool *used_mouse_menu)
 {
   Lisp_Object c = Qnil;
-  sys_jmp_buf save_jump;
+  sys_jmp_buf *save_jump = xmalloc (sizeof *save_jump);
   KBOARD *kb IF_LINT (= NULL);
 
  start:
@@ -2294,7 +2287,7 @@ read_event_from_main_queue (struct timespec *end_time,
    to tty input.  */
 static Lisp_Object
 read_decoded_event_from_main_queue (struct timespec *end_time,
-                                    sys_jmp_buf local_getcjmp,
+                                    sys_jmp_buf *local_getcjmp,
                                     Lisp_Object prev_event,
                                     bool *used_mouse_menu)
 {
@@ -2373,13 +2366,20 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
     }
 }
 
+static bool
+echo_keystrokes_p (void)
+{
+  return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0
+         : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0 : false);
+}
+
 /* Read a character from the keyboard; call the redisplay if needed.  */
 /* commandflag 0 means do not autosave, but do redisplay.
    -1 means do not redisplay, but do autosave.
    -2 means do neither.
    1 means do both.  */
 
-/* The arguments MAP is for menu prompting.  MAP is a keymap.
+/* The argument MAP is a keymap for menu prompting.
 
    PREV_EVENT is the previous input event, or nil if we are reading
    the first event of a key sequence (or not reading a key sequence).
@@ -2400,37 +2400,128 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
 
    Value is t if we showed a menu and the user rejected it.  */
 
+struct read_char_state
+{
+  int commandflag;
+  Lisp_Object map;
+  Lisp_Object prev_event;
+  bool *used_mouse_menu;
+  struct timespec *end_time;
+  Lisp_Object c;
+  ptrdiff_t jmpcount;
+  sys_jmp_buf *local_getcjmp;
+  sys_jmp_buf *save_jump;
+  Lisp_Object previous_echo_area_message;
+  Lisp_Object also_record;
+  bool reread;
+  bool polling_stopped_here;
+  struct kboard *orig_kboard;
+};
+
+static Lisp_Object read_char_1 (bool, volatile struct read_char_state *);
+
+/* {{coccinelle:skip_start}} */
 Lisp_Object
 read_char (int commandflag, Lisp_Object map,
           Lisp_Object prev_event,
           bool *used_mouse_menu, struct timespec *end_time)
 {
-  Lisp_Object c;
-  ptrdiff_t jmpcount;
-  sys_jmp_buf local_getcjmp;
-  sys_jmp_buf save_jump;
-  Lisp_Object tem, save;
-  volatile Lisp_Object previous_echo_area_message;
-  volatile Lisp_Object also_record;
-  volatile bool reread;
-  struct gcpro gcpro1, gcpro2;
-  bool volatile polling_stopped_here = 0;
-  struct kboard *orig_kboard = current_kboard;
+  volatile struct read_char_state *state = xmalloc (sizeof *state);
+
+  state->commandflag = commandflag;
+  state->map = map;
+  state->prev_event = prev_event;
+  state->used_mouse_menu = used_mouse_menu;
+  state->end_time = end_time;
+  state->c = Qnil;
+  state->local_getcjmp = xmalloc (sizeof (*state->local_getcjmp));
+  state->save_jump = xmalloc (sizeof (*state->save_jump));
+  state->previous_echo_area_message = Qnil;
+  state->also_record = Qnil;
+  state->reread = false;
+  state->polling_stopped_here = false;
+  state->orig_kboard = current_kboard;
 
-  also_record = Qnil;
+  /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
+     We will do that below, temporarily for short sections of code,
+     when appropriate.  local_getcjmp must be in effect
+     around any call to sit_for or kbd_buffer_get_event;
+     it *must not* be in effect when we call redisplay.  */
 
-#if 0  /* This was commented out as part of fixing echo for C-u left.  */
-  before_command_key_count = this_command_key_count;
-  before_command_echo_length = echo_length ();
-#endif
-  c = Qnil;
-  previous_echo_area_message = Qnil;
+  state->jmpcount = SPECPDL_INDEX ();
+  if (sys_setjmp (*state->local_getcjmp))
+    {
+      /* Handle quits while reading the keyboard.  */
+      /* We must have saved the outer value of getcjmp here,
+        so restore it now.  */
+      restore_getcjmp (state->save_jump);
+      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+      unbind_to (state->jmpcount, Qnil);
+      XSETINT (state->c, quit_char);
+      internal_last_event_frame = selected_frame;
+      Vlast_event_frame = internal_last_event_frame;
+      /* If we report the quit char as an event,
+        don't do so more than once.  */
+      if (!NILP (Vinhibit_quit))
+       Vquit_flag = Qnil;
+
+      {
+       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
+       if (kb != current_kboard)
+         {
+           Lisp_Object last = KVAR (kb, kbd_queue);
+           /* We shouldn't get here if we were in single-kboard mode!  */
+           if (single_kboard)
+             emacs_abort ();
+           if (CONSP (last))
+             {
+               while (CONSP (XCDR (last)))
+                 last = XCDR (last);
+               if (!NILP (XCDR (last)))
+                 emacs_abort ();
+             }
+           if (!CONSP (last))
+             kset_kbd_queue (kb, list1 (state->c));
+           else
+             XSETCDR (last, list1 (state->c));
+           kb->kbd_queue_has_data = 1;
+           current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
+            return make_number (-2); /* wrong_kboard_jmpbuf */
+         }
+      }
+      return read_char_1 (true, state);
+    }
 
-  GCPRO2 (c, previous_echo_area_message);
+  return read_char_1 (false, state);
+}
+
+static Lisp_Object
+read_char_1 (bool jump, volatile struct read_char_state *state)
+{
+#define commandflag state->commandflag
+#define map state->map
+#define prev_event state->prev_event
+#define used_mouse_menu state->used_mouse_menu
+#define end_time state->end_time
+#define c state->c
+#define jmpcount state->jmpcount
+#define local_getcjmp state->local_getcjmp
+#define save_jump state->save_jump
+#define previous_echo_area_message state->previous_echo_area_message
+#define also_record state->also_record
+#define reread state->reread
+#define polling_stopped_here state->polling_stopped_here
+#define orig_kboard state->orig_kboard
+  Lisp_Object tem, save;
+
+  if (jump)
+    goto non_reread;
 
  retry:
 
-  reread = 0;
   if (CONSP (Vunread_post_input_method_events))
     {
       c = XCAR (Vunread_post_input_method_events);
@@ -2444,9 +2535,12 @@ read_char (int commandflag, Lisp_Object map,
          && NILP (XCDR (c)))
        c = XCAR (c);
 
-      reread = 1;
+      reread = true;
       goto reread_first;
     }
+  else
+    reread = false;
+
 
   if (CONSP (Vunread_command_events))
     {
@@ -2455,17 +2549,13 @@ read_char (int commandflag, Lisp_Object map,
       c = XCAR (Vunread_command_events);
       Vunread_command_events = XCDR (Vunread_command_events);
 
-      reread = 1;
-
       /* Undo what sit-for did when it unread additional keys
         inside universal-argument.  */
 
-      if (CONSP (c)
-         && EQ (XCAR (c), Qt))
-       {
-         reread = 0;
-         c = XCDR (c);
-       }
+      if (CONSP (c) && EQ (XCAR (c), Qt))
+       c = XCDR (c);
+      else
+       reread = true;
 
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
@@ -2499,7 +2589,7 @@ read_char (int commandflag, Lisp_Object map,
          && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
          && NILP (XCDR (c)))
        c = XCAR (c);
-      reread = 1;
+      reread = true;
       goto reread_for_input_method;
     }
 
@@ -2641,58 +2731,6 @@ read_char (int commandflag, Lisp_Object map,
        goto exit;
     }
 
-  /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
-     We will do that below, temporarily for short sections of code,
-     when appropriate.  local_getcjmp must be in effect
-     around any call to sit_for or kbd_buffer_get_event;
-     it *must not* be in effect when we call redisplay.  */
-
-  jmpcount = SPECPDL_INDEX ();
-  if (sys_setjmp (local_getcjmp))
-    {
-      /* Handle quits while reading the keyboard.  */
-      /* We must have saved the outer value of getcjmp here,
-        so restore it now.  */
-      restore_getcjmp (save_jump);
-      unbind_to (jmpcount, Qnil);
-      XSETINT (c, quit_char);
-      internal_last_event_frame = selected_frame;
-      Vlast_event_frame = internal_last_event_frame;
-      /* If we report the quit char as an event,
-        don't do so more than once.  */
-      if (!NILP (Vinhibit_quit))
-       Vquit_flag = Qnil;
-
-      {
-       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
-       if (kb != current_kboard)
-         {
-           Lisp_Object last = KVAR (kb, kbd_queue);
-           /* We shouldn't get here if we were in single-kboard mode!  */
-           if (single_kboard)
-             emacs_abort ();
-           if (CONSP (last))
-             {
-               while (CONSP (XCDR (last)))
-                 last = XCDR (last);
-               if (!NILP (XCDR (last)))
-                 emacs_abort ();
-             }
-           if (!CONSP (last))
-             kset_kbd_queue (kb, list1 (c));
-           else
-             XSETCDR (last, list1 (c));
-           kb->kbd_queue_has_data = 1;
-           current_kboard = kb;
-           /* This is going to exit from read_char
-              so we had better get rid of this frame's stuff.  */
-           UNGCPRO;
-            return make_number (-2); /* wrong_kboard_jmpbuf */
-         }
-      }
-      goto non_reread;
-    }
-
   /* Start idle timers if no time limit is supplied.  We don't do it
      if a time limit is supplied to avoid an infinite recursion in the
      situation where an idle timer calls `sit-for'.  */
@@ -2708,8 +2746,7 @@ read_char (int commandflag, Lisp_Object map,
       && !current_kboard->immediate_echo
       && this_command_key_count > 0
       && ! noninteractive
-      && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-      && NILP (Fzerop (Vecho_keystrokes))
+      && echo_keystrokes_p ()
       && (/* No message.  */
          NILP (echo_area_buffer[0])
          /* Or empty message.  */
@@ -2818,7 +2855,7 @@ read_char (int commandflag, Lisp_Object map,
 
       /* If there is still no input available, ask for GC.  */
       if (!detect_input_pending_run_timers (0))
-       maybe_gc ();
+       GC_collect_a_little ();
     }
 
   /* Notify the caller if an autosave hook, or a timer, sentinel or
@@ -2840,6 +2877,11 @@ read_char (int commandflag, Lisp_Object map,
     {
       c = XCAR (Vunread_command_events);
       Vunread_command_events = XCDR (Vunread_command_events);
+
+      if (CONSP (c) && EQ (XCAR (c), Qt))
+       c = XCDR (c);
+      else
+       reread = true;
     }
 
   /* Read something from current KBOARD's side queue, if possible.  */
@@ -2893,8 +2935,8 @@ read_char (int commandflag, Lisp_Object map,
     {
       c = read_decoded_event_from_main_queue (end_time, local_getcjmp,
                                               prev_event, used_mouse_menu);
-      if (NILP(c) && end_time &&
-          timespec_cmp (*end_time, current_timespec ()) <= 0)
+      if (NILP (c) && end_time
+         && timespec_cmp (*end_time, current_timespec ()) <= 0)
         {
           goto exit;
         }
@@ -3058,7 +3100,6 @@ read_char (int commandflag, Lisp_Object map,
       ptrdiff_t key_count;
       bool key_count_reset;
       struct gcpro gcpro1;
-      ptrdiff_t count = SPECPDL_INDEX ();
 
       /* Save the echo status.  */
       bool saved_immediate_echo = current_kboard->immediate_echo;
@@ -3066,6 +3107,8 @@ read_char (int commandflag, Lisp_Object map,
       Lisp_Object saved_echo_string = KVAR (current_kboard, echo_string);
       ptrdiff_t saved_echo_after_prompt = current_kboard->echo_after_prompt;
 
+      dynwind_begin ();
+
 #if 0
       if (before_command_restore_flag)
        {
@@ -3107,7 +3150,7 @@ read_char (int commandflag, Lisp_Object map,
       /* Call the input method.  */
       tem = call1 (Vinput_method_function, c);
 
-      tem = unbind_to (count, tem);
+      dynwind_end ();
 
       /* Restore the saved echoing state
         and this_command_keys state.  */
@@ -3170,8 +3213,7 @@ read_char (int commandflag, Lisp_Object map,
     {
 
       /* Don't echo mouse motion events.  */
-      if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-         && NILP (Fzerop (Vecho_keystrokes))
+      if (echo_keystrokes_p ()
          && ! (EVENT_HAS_PARAMETERS (c)
                && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
        {
@@ -3195,7 +3237,7 @@ read_char (int commandflag, Lisp_Object map,
   /* Process the help character specially if enabled.  */
   if (!NILP (Vhelp_form) && help_char_p (c))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
 
       help_form_saved_window_configs
        = Fcons (Fcurrent_window_configuration (Qnil),
@@ -3213,7 +3255,7 @@ read_char (int commandflag, Lisp_Object map,
        }
       while (BUFFERP (c));
       /* Remove the help from the frame.  */
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       redisplay ();
       if (EQ (c, make_number (040)))
@@ -3228,7 +3270,22 @@ read_char (int commandflag, Lisp_Object map,
  exit:
   RESUME_POLLING;
   RETURN_UNGCPRO (c);
-}
+#undef commandflag
+#undef map
+#undef prev_event
+#undef used_mouse_menu
+#undef end_time
+#undef c
+#undef jmpcount
+#undef local_getcjmp
+#undef save_jump
+#undef previous_echo_area_message
+#undef also_record
+#undef reread
+#undef polling_stopped_here
+#undef orig_kboard
+}
+/* {{coccinelle:skip_end}} */
 
 /* Record a key that came from a mouse menu.
    Record it for echoing, for this-command-keys, and so on.  */
@@ -3247,8 +3304,7 @@ record_menu_key (Lisp_Object c)
 #endif
 
   /* Don't echo mouse motion events.  */
-  if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-      && NILP (Fzerop (Vecho_keystrokes)))
+  if (echo_keystrokes_p ())
     {
       echo_char (c);
 
@@ -3422,15 +3478,15 @@ record_char (Lisp_Object c)
    See read_process_output.  */
 
 static void
-save_getcjmp (sys_jmp_buf temp)
+save_getcjmp (sys_jmp_buf *temp)
 {
-  memcpy (temp, getcjmp, sizeof getcjmp);
+  memcpy (*temp, getcjmp, sizeof getcjmp);
 }
 
 static void
-restore_getcjmp (sys_jmp_buf temp)
+restore_getcjmp (sys_jmp_buf *temp)
 {
-  memcpy (getcjmp, temp, sizeof getcjmp);
+  memcpy (getcjmp, *temp, sizeof getcjmp);
 }
 \f
 /* Low level keyboard/mouse input.
@@ -3655,7 +3711,8 @@ kbd_buffer_store_event_hold (register struct input_event *event,
       *kbd_store_ptr = *event;
       ++kbd_store_ptr;
 #ifdef subprocesses
-      if (kbd_buffer_nr_stored () > KBD_BUFFER_SIZE/2 && ! kbd_on_hold_p ())
+      if (kbd_buffer_nr_stored () > KBD_BUFFER_SIZE / 2
+         && ! kbd_on_hold_p ())
         {
           /* Don't read keyboard input until we have processed kbd_buffer.
              This happens when pasting text longer than KBD_BUFFER_SIZE/2.  */
@@ -4500,7 +4557,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
        {
          if (NILP (AREF (chosen_timer, 0)))
            {
-             ptrdiff_t count = SPECPDL_INDEX ();
+             dynwind_begin ();
              Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
@@ -4512,7 +4569,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
              call1 (Qtimer_event_handler, chosen_timer);
              Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
-             unbind_to (count, Qnil);
+             dynwind_end ();
 
              /* Since we have handled the event,
                 we don't need to tell the caller to wake up and do it.  */
@@ -5223,7 +5280,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
       /* It's a click in window WINDOW at frame coordinates (X,Y)  */
       struct window *w = XWINDOW (window);
       Lisp_Object string_info = Qnil;
-      ptrdiff_t textpos = -1;
+      ptrdiff_t textpos = 0;
       int col = -1, row = -1;
       int dx  = -1, dy  = -1;
       int width = -1, height = -1;
@@ -5258,9 +5315,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
                                     &object, &dx, &dy, &width, &height);
          if (STRINGP (string))
            string_info = Fcons (string, make_number (charpos));
-         textpos = (w == XWINDOW (selected_window)
-                    && current_buffer == XBUFFER (w->contents))
-           ? PT : marker_position (w->pointm);
+         textpos = -1;
 
          xret = wx;
          yret = wy;
@@ -5328,7 +5383,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
       /* For clicks in the text area, fringes, or margins, call
         buffer_posn_from_coords to extract TEXTPOS, the buffer
         position nearest to the click.  */
-      if (textpos < 0)
+      if (!textpos)
        {
          Lisp_Object string2, object2 = Qnil;
          struct display_pos p;
@@ -5379,15 +5434,15 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
        }
 #endif
 
-      /* Object info */
+      /* Object info */
       extra_info
        = list3 (object,
                 Fcons (make_number (dx), make_number (dy)),
                 Fcons (make_number (width), make_number (height)));
 
-      /* String info */
+      /* String info */
       extra_info = Fcons (string_info,
-                         Fcons (make_number (textpos),
+                         Fcons (textpos < 0 ? Qnil : make_number (textpos),
                                 Fcons (Fcons (make_number (col),
                                               make_number (row)),
                                        extra_info)));
@@ -5478,14 +5533,13 @@ make_lispy_event (struct input_event *event)
     case NON_ASCII_KEYSTROKE_EVENT:
       button_down_time = 0;
 
-      for (i = 0; i < sizeof (lispy_accent_codes) / sizeof (int); i++)
+      for (i = 0; i < ARRAYELTS (lispy_accent_codes); i++)
        if (event->code == lispy_accent_codes[i])
          return modify_event_symbol (i,
                                      event->modifiers,
                                      Qfunction_key, Qnil,
                                      lispy_accent_keys, &accent_key_syms,
-                                     (sizeof (lispy_accent_keys)
-                                      / sizeof (lispy_accent_keys[0])));
+                                      ARRAYELTS (lispy_accent_keys));
 
 #if 0
 #ifdef XK_kana_A
@@ -5494,8 +5548,7 @@ make_lispy_event (struct input_event *event)
                                    event->modifiers & ~shift_modifier,
                                    Qfunction_key, Qnil,
                                    lispy_kana_keys, &func_key_syms,
-                                   (sizeof (lispy_kana_keys)
-                                    / sizeof (lispy_kana_keys[0])));
+                                    ARRAYELTS (lispy_kana_keys));
 #endif /* XK_kana_A */
 #endif /* 0 */
 
@@ -5506,15 +5559,14 @@ make_lispy_event (struct input_event *event)
                                    event->modifiers,
                                    Qfunction_key, Qnil,
                                    iso_lispy_function_keys, &func_key_syms,
-                                   (sizeof (iso_lispy_function_keys)
-                                    / sizeof (iso_lispy_function_keys[0])));
+                                    ARRAYELTS (iso_lispy_function_keys));
 #endif
 
       /* Handle system-specific or unknown keysyms.  */
       if (event->code & (1 << 28)
          || event->code - FUNCTION_KEY_OFFSET < 0
          || (event->code - FUNCTION_KEY_OFFSET
-             >= sizeof lispy_function_keys / sizeof *lispy_function_keys)
+             >= ARRAYELTS (lispy_function_keys))
          || !lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
        {
          /* We need to use an alist rather than a vector as the cache
@@ -5533,20 +5585,17 @@ make_lispy_event (struct input_event *event)
                                  event->modifiers,
                                  Qfunction_key, Qnil,
                                  lispy_function_keys, &func_key_syms,
-                                 (sizeof (lispy_function_keys)
-                                  / sizeof (lispy_function_keys[0])));
+                                  ARRAYELTS (lispy_function_keys));
 
 #ifdef HAVE_NTGUI
     case MULTIMEDIA_KEY_EVENT:
-      if (event->code < (sizeof (lispy_multimedia_keys)
-                         / sizeof (lispy_multimedia_keys[0]))
+      if (event->code < ARRAYELTS (lispy_multimedia_keys)
           && event->code > 0 && lispy_multimedia_keys[event->code])
         {
           return modify_event_symbol (event->code, event->modifiers,
                                       Qfunction_key, Qnil,
                                       lispy_multimedia_keys, &func_key_syms,
-                                      (sizeof (lispy_multimedia_keys)
-                                       / sizeof (lispy_multimedia_keys[0])));
+                                      ARRAYELTS (lispy_multimedia_keys));
         }
       return Qnil;
 #endif
@@ -6268,7 +6317,7 @@ static const char *const modifier_names[] =
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, "alt", "super", "hyper", "shift", "control", "meta"
 };
-#define NUM_MOD_NAMES (sizeof (modifier_names) / sizeof (modifier_names[0]))
+#define NUM_MOD_NAMES ARRAYELTS (modifier_names)
 
 static Lisp_Object modifier_symbols;
 
@@ -6876,6 +6925,20 @@ gobble_input (void)
              }
             }
 
+         /* If there was no error, make sure the pointer
+            is visible for all frames on this terminal.  */
+         if (nr >= 0)
+           {
+             Lisp_Object tail, frame;
+
+             FOR_EACH_FRAME (tail, frame)
+               {
+                 struct frame *f = XFRAME (frame);
+                 if (FRAME_TERMINAL (f) == t)
+                   frame_make_pointer_visible (f);
+               }
+           }
+
           if (hold_quit.kind != NO_EVENT)
             kbd_buffer_store_event (&hold_quit);
         }
@@ -6886,8 +6949,6 @@ gobble_input (void)
   if (err && !nread)
     nread = -1;
 
-  frame_make_pointer_visible ();
-
   return nread;
 }
 
@@ -7123,7 +7184,12 @@ unblock_input_to (int level)
 /* End critical section.
 
    If doing signal-driven input, and a signal came in when input was
-   blocked, reinvoke the signal handler now to deal with it.  */
+   blocked, reinvoke the signal handler now to deal with it.
+
+   It will also process queued input, if it was not read before.
+   When a longer code sequence does not use block/unblock input
+   at all, the whole input gathered up to the next call to
+   unblock_input will be processed inside that call. */
 
 void
 unblock_input (void)
@@ -7288,7 +7354,7 @@ store_user_signal_events (void)
 }
 
 \f
-static void menu_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void*);
+static void menu_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void *);
 static Lisp_Object menu_bar_one_keymap_changed_items;
 
 /* These variables hold the vector under construction within
@@ -7298,7 +7364,7 @@ static Lisp_Object menu_bar_items_vector;
 static int menu_bar_items_index;
 
 
-static const charseparator_names[] = {
+static const char *separator_names[] = {
   "space",
   "no-line",
   "single-line",
@@ -7473,8 +7539,8 @@ menu_bar_items (Lisp_Object old)
   {
     int i = menu_bar_items_index;
     if (i + 4 > ASIZE (menu_bar_items_vector))
-      menu_bar_items_vector =
-       larger_vector (menu_bar_items_vector, 4, -1);
+      menu_bar_items_vector
+       larger_vector (menu_bar_items_vector, 4, -1);
     /* Add this item.  */
     ASET (menu_bar_items_vector, i, Qnil); i++;
     ASET (menu_bar_items_vector, i, Qnil); i++;
@@ -7590,12 +7656,13 @@ eval_dyn (Lisp_Object form)
 Lisp_Object
 menu_item_eval_property (Lisp_Object sexpr)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
   specbind (Qinhibit_redisplay, Qt);
   val = internal_condition_case_1 (eval_dyn, sexpr, Qerror,
                                   menu_item_eval_property_1);
-  return unbind_to (count, val);
+  dynwind_end ();
+  return val;
 }
 
 /* This function parses a menu item and leaves the result in the
@@ -7906,7 +7973,8 @@ static Lisp_Object QCrtl;
 /* Function prototypes.  */
 
 static void init_tool_bar_items (Lisp_Object);
-static void process_tool_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void*);
+static void process_tool_bar_item (Lisp_Object, Lisp_Object, Lisp_Object,
+                                  void *);
 static bool parse_tool_bar_item (Lisp_Object, Lisp_Object);
 static void append_tool_bar_item (void);
 
@@ -8243,7 +8311,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
       const char *capt = STRINGP (tcapt) ? SSDATA (tcapt) : "";
       ptrdiff_t max_lbl =
        2 * max (0, min (tool_bar_max_label_size, STRING_BYTES_BOUND / 2));
-      char *buf = xmalloc (max_lbl + 1);
+      char *buf = xmalloc_atomic (max_lbl + 1);
       Lisp_Object new_lbl;
       ptrdiff_t caption_len = strlen (capt);
 
@@ -8841,8 +8909,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                   bool dont_downcase_last, bool can_return_switch_frame,
                   bool fix_current_buffer, bool prevent_redisplay)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
-
   /* How many keys there are in the current key sequence.  */
   int t;
 
@@ -8909,6 +8975,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
   struct gcpro gcpro1;
 
+  dynwind_begin ();
+
   GCPRO1 (fake_prefixed_keys);
   raw_keybuf_count = 0;
 
@@ -8928,8 +8996,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          echo_now ();
        }
       else if (cursor_in_echo_area
-              && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-              && NILP (Fzerop (Vecho_keystrokes)))
+              && echo_keystrokes_p ())
        /* This doesn't put in a dash if the echo buffer is empty, so
           you don't always see a dash hanging out in the minibuffer.  */
        echo_dash ();
@@ -9061,8 +9128,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
        {
          key = keybuf[t];
          add_command_key (key);
-         if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-             && NILP (Fzerop (Vecho_keystrokes))
+         if (echo_keystrokes_p ()
              && current_kboard->immediate_echo)
            {
              echo_add_key (key);
@@ -9142,7 +9208,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
             Just return -1.  */
          if (EQ (key, Qt))
            {
-             unbind_to (count, Qnil);
+              dynwind_end ();
              UNGCPRO;
              return -1;
            }
@@ -9378,16 +9444,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          first_unbound = min (t, first_unbound);
 
          head = EVENT_HEAD (key);
-         if (help_char_p (head) && t > 0)
-           {
-             read_key_sequence_cmd = Vprefix_help_command;
-             keybuf[t++] = key;
-             last_nonmenu_event = key;
-             /* The Microsoft C compiler can't handle the goto that
-                would go here.  */
-             dummyflag = 1;
-             break;
-           }
 
          if (SYMBOLP (head))
            {
@@ -9645,6 +9701,17 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
          goto replay_sequence;
        }
+
+      if (NILP (current_binding)
+         && help_char_p (EVENT_HEAD (key)) && t > 1)
+           {
+             read_key_sequence_cmd = Vprefix_help_command;
+             /* The Microsoft C compiler can't handle the goto that
+                would go here.  */
+             dummyflag = 1;
+             break;
+           }
+
       /* If KEY is not defined in any of the keymaps,
         and cannot be part of a function key or translation,
         and is a shifted function key,
@@ -9700,7 +9767,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
     : Qnil;
 
   unread_switch_frame = delayed_switch_frame;
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
@@ -9726,8 +9793,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
      Better ideas?  */
   for (; t < mock_input; t++)
     {
-      if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-         && NILP (Fzerop (Vecho_keystrokes)))
+      if (echo_keystrokes_p ())
        echo_char (keybuf[t]);
       add_command_key (keybuf[t]);
     }
@@ -9745,7 +9811,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
   Lisp_Object keybuf[30];
   register int i;
   struct gcpro gcpro1;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   if (!NILP (prompt))
     CHECK_STRING (prompt);
@@ -9758,7 +9824,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
 
   memset (keybuf, 0, sizeof keybuf);
   GCPRO1 (keybuf[0]);
-  gcpro1.nvars = (sizeof keybuf / sizeof (keybuf[0]));
+  gcpro1.nvars = ARRAYELTS (keybuf);
 
   if (NILP (continue_echo))
     {
@@ -9772,7 +9838,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
     cancel_hourglass ();
 #endif
 
-  i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
+  i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
                         prompt, ! NILP (dont_downcase_last),
                         ! NILP (can_return_switch_frame), 0, 0);
 
@@ -9791,9 +9857,9 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
       QUIT;
     }
   UNGCPRO;
-  return unbind_to (count,
-                   ((allow_string ? make_event_array : Fvector)
-                    (i, keybuf)));
+  Lisp_Object tem0 = ((allow_string ? make_event_array : Fvector) (i, keybuf));
+  dynwind_end ();
+  return tem0;
 }
 
 DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
@@ -10073,7 +10139,10 @@ DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
        "FOpen dribble file: ",
        doc: /* Start writing all keyboard characters to a dribble file called FILE.
 If FILE is nil, close any open dribble file.
-The file will be closed when Emacs exits.  */)
+The file will be closed when Emacs exits.
+
+Be aware that this records ALL characters you type!
+This may include sensitive information such as passwords.  */)
   (Lisp_Object file)
 {
   if (dribble)
@@ -10085,8 +10154,15 @@ The file will be closed when Emacs exits.  */)
     }
   if (!NILP (file))
     {
+      int fd;
+      Lisp_Object encfile;
+
       file = Fexpand_file_name (file, Qnil);
-      dribble = emacs_fopen (SSDATA (file), "w");
+      encfile = ENCODE_FILE (file);
+      fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
+      if (fd < 0 && errno == EEXIST && unlink (SSDATA (encfile)) == 0)
+       fd = emacs_open (SSDATA (encfile), O_WRONLY | O_CREAT | O_EXCL, 0600);
+      dribble = fd < 0 ? 0 : fdopen (fd, "w");
       if (dribble == 0)
        report_file_error ("Opening dribble", file);
     }
@@ -10130,7 +10206,7 @@ Some operating systems cannot stop the Emacs process and resume it later.
 On such systems, Emacs starts a subshell instead of suspending.  */)
   (Lisp_Object stuffstring)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   int old_height, old_width;
   int width, height;
   struct gcpro gcpro1;
@@ -10157,7 +10233,7 @@ On such systems, Emacs starts a subshell instead of suspending.  */)
     sys_subshell ();
   else
     sys_suspend ();
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Check if terminal/window size has changed.
      Note that this is not useful when we are running directly
@@ -10297,9 +10373,6 @@ static void
 handle_interrupt (bool in_signal_handler)
 {
   char c;
-  sigset_t blocked;
-  sigemptyset (&blocked);
-  sigaddset (&blocked, SIGINT);
 
   cancel_echoing ();
 
@@ -10311,6 +10384,9 @@ handle_interrupt (bool in_signal_handler)
          /* If SIGINT isn't blocked, don't let us be interrupted by
             a SIGINT.  It might be harmful due to non-reentrancy
             in I/O functions.  */
+         sigset_t blocked;
+         sigemptyset (&blocked);
+         sigaddset (&blocked, SIGINT);
          pthread_sigmask (SIG_BLOCK, &blocked, 0);
        }
 
@@ -10338,34 +10414,18 @@ handle_interrupt (bool in_signal_handler)
         is used.  Note that [Enter] is not echoed by dos.  */
       cursor_to (SELECTED_FRAME (), 0, 0);
 #endif
-      /* It doesn't work to autosave while GC is in progress;
-        the code used for auto-saving doesn't cope with the mark bit.  */
-      if (!gc_in_progress)
-       {
-         printf ("Auto-save? (y or n) ");
-         fflush (stdout);
-         if (((c = getchar ()) & ~040) == 'Y')
-           {
-             Fdo_auto_save (Qt, Qnil);
+      printf ("Auto-save? (y or n) ");
+      fflush (stdout);
+      if (((c = getchar ()) & ~040) == 'Y')
+        {
+          Fdo_auto_save (Qt, Qnil);
 #ifdef MSDOS
-             printf ("\r\nAuto-save done");
+          printf ("\r\nAuto-save done");
 #else /* not MSDOS */
-             printf ("Auto-save done\n");
+          printf ("Auto-save done\n");
 #endif /* not MSDOS */
-           }
-         while (c != '\n') c = getchar ();
-       }
-      else
-       {
-         /* During GC, it must be safe to reenable quitting again.  */
-         Vinhibit_quit = Qnil;
-#ifdef MSDOS
-         printf ("\r\n");
-#endif /* not MSDOS */
-         printf ("Garbage collection in progress; cannot auto-save now\r\n");
-         printf ("but will instead do a real quit after garbage collection ends\r\n");
-         fflush (stdout);
-       }
+        }
+      while (c != '\n') c = getchar ();
 
 #ifdef MSDOS
       printf ("\r\nAbort?  (y or n) ");
@@ -10395,7 +10455,7 @@ handle_interrupt (bool in_signal_handler)
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
          immediate_quit = 0;
-         pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
+         pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
          saved = gl_state;
          GCPRO4 (saved.object, saved.global_code,
                  saved.current_syntax_table, saved.old_prop);
@@ -10416,7 +10476,7 @@ handle_interrupt (bool in_signal_handler)
         }
     }
 
-  pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
 
 /* TODO: The longjmp in this call throws the NS event loop integration off,
          and it seems to do fine without this.  Probably some attention
@@ -10675,7 +10735,7 @@ The elements of this list correspond to the arguments of
     }
   XSETFASTINT (val[3], quit_char);
 
-  return Flist (sizeof (val) / sizeof (val[0]), val);
+  return Flist (ARRAYELTS (val), val);
 }
 
 DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
@@ -10935,6 +10995,8 @@ static const struct event_head head_table[] = {
 void
 syms_of_keyboard (void)
 {
+#include "keyboard.x"
+
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
@@ -11043,7 +11105,7 @@ syms_of_keyboard (void)
 
   {
     int i;
-    int len = sizeof (head_table) / sizeof (head_table[0]);
+    int len = ARRAYELTS (head_table);
 
     for (i = 0; i < len; i++)
       {
@@ -11059,14 +11121,13 @@ syms_of_keyboard (void)
   staticpro (&button_down_location);
   mouse_syms = Fmake_vector (make_number (5), Qnil);
   staticpro (&mouse_syms);
-  wheel_syms = Fmake_vector (make_number (sizeof (lispy_wheel_names)
-                                         / sizeof (lispy_wheel_names[0])),
+  wheel_syms = Fmake_vector (make_number (ARRAYELTS (lispy_wheel_names)),
                             Qnil);
   staticpro (&wheel_syms);
 
   {
     int i;
-    int len = sizeof (modifier_names) / sizeof (modifier_names[0]);
+    int len = ARRAYELTS (modifier_names);
 
     modifier_symbols = Fmake_vector (make_number (len), Qnil);
     for (i = 0; i < len; i++)
@@ -11115,38 +11176,6 @@ syms_of_keyboard (void)
   help_form_saved_window_configs = Qnil;
   staticpro (&help_form_saved_window_configs);
 
-  defsubr (&Scurrent_idle_time);
-  defsubr (&Sevent_symbol_parse_modifiers);
-  defsubr (&Sevent_convert_list);
-  defsubr (&Sread_key_sequence);
-  defsubr (&Sread_key_sequence_vector);
-  defsubr (&Srecursive_edit);
-  defsubr (&Strack_mouse);
-  defsubr (&Sinput_pending_p);
-  defsubr (&Srecent_keys);
-  defsubr (&Sthis_command_keys);
-  defsubr (&Sthis_command_keys_vector);
-  defsubr (&Sthis_single_command_keys);
-  defsubr (&Sthis_single_command_raw_keys);
-  defsubr (&Sreset_this_command_lengths);
-  defsubr (&Sclear_this_command_keys);
-  defsubr (&Ssuspend_emacs);
-  defsubr (&Sabort_recursive_edit);
-  defsubr (&Sexit_recursive_edit);
-  defsubr (&Srecursion_depth);
-  defsubr (&Scommand_error_default_function);
-  defsubr (&Stop_level);
-  defsubr (&Sdiscard_input);
-  defsubr (&Sopen_dribble_file);
-  defsubr (&Sset_input_interrupt_mode);
-  defsubr (&Sset_output_flow_control);
-  defsubr (&Sset_input_meta_mode);
-  defsubr (&Sset_quit_char);
-  defsubr (&Sset_input_mode);
-  defsubr (&Scurrent_input_mode);
-  defsubr (&Sposn_at_point);
-  defsubr (&Sposn_at_x_y);
-
   DEFVAR_LISP ("last-command-event", last_command_event,
                     doc: /* Last input event that was part of a command.  */);
 
@@ -11385,6 +11414,7 @@ and tests the value when the command returns.
 Buffer modification stores t in this variable.  */);
   Vdeactivate_mark = Qnil;
   DEFSYM (Qdeactivate_mark, "deactivate-mark");
+  Fmake_variable_buffer_local (Qdeactivate_mark);
 
   DEFVAR_LISP ("pre-command-hook", Vpre_command_hook,
               doc: /* Normal hook run before each command is executed.
@@ -11745,52 +11775,3 @@ keys_of_keyboard (void)
   initial_define_lispy_key (Vspecial_event_map, "focus-out",
                            "handle-focus-out");
 }
-
-/* Mark the pointers in the kboard objects.
-   Called by Fgarbage_collect.  */
-void
-mark_kboards (void)
-{
-  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 (KVAR (kb, Voverriding_terminal_local_map));
-      mark_object (KVAR (kb, Vlast_command));
-      mark_object (KVAR (kb, Vreal_last_command));
-      mark_object (KVAR (kb, Vkeyboard_translate_table));
-      mark_object (KVAR (kb, Vlast_repeatable_command));
-      mark_object (KVAR (kb, Vprefix_arg));
-      mark_object (KVAR (kb, Vlast_prefix_arg));
-      mark_object (KVAR (kb, kbd_queue));
-      mark_object (KVAR (kb, defining_kbd_macro));
-      mark_object (KVAR (kb, Vlast_kbd_macro));
-      mark_object (KVAR (kb, Vsystem_key_alist));
-      mark_object (KVAR (kb, system_key_syms));
-      mark_object (KVAR (kb, Vwindow_system));
-      mark_object (KVAR (kb, Vinput_decode_map));
-      mark_object (KVAR (kb, Vlocal_function_key_map));
-      mark_object (KVAR (kb, Vdefault_minibuffer_frame));
-      mark_object (KVAR (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;
-       /* These two special event types has no Lisp_Objects to mark.  */
-       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);
-         }
-      }
-  }
-}