use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / keyboard.c
index 26afc02..20498d0 100644 (file)
@@ -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.  */
@@ -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,13 +813,15 @@ 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;
+  }
 
   if (command_loop_level >= 0
       && current_buffer != XBUFFER (XWINDOW (selected_window)->contents))
@@ -846,7 +844,8 @@ This function is called by the editor initialization to begin editing.  */)
     temporarily_switch_to_single_kboard (SELECTED_FRAME ());
 
   recursive_edit_1 ();
-  return unbind_to (count, Qnil);
+  dynwind_end ();
+  return Qnil;
 }
 
 void
@@ -1222,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)
@@ -1233,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)
@@ -1274,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);
@@ -1282,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.
@@ -1292,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 *
@@ -1323,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, ...  */
@@ -1415,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);
@@ -1424,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))
@@ -1538,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))
@@ -1564,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);
@@ -1941,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
@@ -2091,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;
@@ -2197,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);
@@ -2223,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:
@@ -2297,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)
 {
@@ -2376,6 +2366,13 @@ 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.
@@ -2403,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;
 
-  GCPRO2 (c, previous_echo_area_message);
+      {
+       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);
+    }
+
+  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);
@@ -2447,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))
     {
@@ -2458,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.  */
@@ -2502,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;
     }
 
@@ -2644,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'.  */
@@ -2711,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.  */
@@ -2821,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
@@ -2843,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.  */
@@ -2896,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;
         }
@@ -3061,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;
@@ -3069,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)
        {
@@ -3110,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.  */
@@ -3173,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)))
        {
@@ -3198,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),
@@ -3216,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)))
@@ -3231,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.  */
@@ -3250,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);
 
@@ -3425,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.
@@ -3658,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.  */
@@ -4503,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
@@ -4515,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.  */
@@ -5226,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;
@@ -5261,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;
@@ -5331,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;
@@ -5382,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)));
@@ -6873,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);
         }
@@ -6883,8 +6949,6 @@ gobble_input (void)
   if (err && !nread)
     nread = -1;
 
-  frame_make_pointer_visible ();
-
   return nread;
 }
 
@@ -7475,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++;
@@ -7592,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
@@ -8246,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);
 
@@ -8844,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;
 
@@ -8912,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;
 
@@ -8931,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 ();
@@ -9064,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);
@@ -9145,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;
            }
@@ -9381,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))
            {
@@ -9648,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,
@@ -9703,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.  */
@@ -9729,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]);
     }
@@ -9748,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);
@@ -9794,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,
@@ -10143,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;
@@ -10170,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
@@ -10310,9 +10373,6 @@ static void
 handle_interrupt (bool in_signal_handler)
 {
   char c;
-  sigset_t blocked;
-  sigemptyset (&blocked);
-  sigaddset (&blocked, SIGINT);
 
   cancel_echoing ();
 
@@ -10324,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);
        }
 
@@ -10351,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");
-#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");
+          printf ("Auto-save done\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) ");
@@ -10408,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);
@@ -10429,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
@@ -10948,6 +10995,8 @@ static const struct event_head head_table[] = {
 void
 syms_of_keyboard (void)
 {
+#include "keyboard.x"
+
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
@@ -11127,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.  */);
 
@@ -11758,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);
-         }
-      }
-  }
-}