]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Merge branch 'emacs-24'.
[gnu-emacs] / src / keyboard.c
index 29bf9ed9e1ab8758e7d6fd7510e52785e5c64cd4..6dc0b820eb92be7a333aa0a48b2efe4f0f7b3ec1 100644 (file)
@@ -133,6 +133,19 @@ static ptrdiff_t this_single_command_key_start;
 static ptrdiff_t before_command_key_count;
 static ptrdiff_t before_command_echo_length;
 
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+
+/* For longjmp to recover from C stack overflow.  */
+sigjmp_buf return_to_command_loop;
+
+/* Message displayed by Vtop_level when recovering from C stack overflow.  */
+static Lisp_Object recover_top_level_message;
+
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
+
+/* Message normally displayed by Vtop_level.  */
+static Lisp_Object regular_top_level_message;
+
 /* For longjmp to where kbd input is being done.  */
 
 static sys_jmp_buf getcjmp;
@@ -218,7 +231,7 @@ static ptrdiff_t last_point_position;
    'volatile' here.  */
 Lisp_Object internal_last_event_frame;
 
-static Lisp_Object Qx_set_selection, Qhandle_switch_frame;
+static Lisp_Object Qgui_set_selection, Qhandle_switch_frame;
 static Lisp_Object Qhandle_select_window;
 Lisp_Object QPRIMARY;
 
@@ -228,7 +241,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;
@@ -348,7 +361,6 @@ static Lisp_Object Qmodifier_cache;
 Lisp_Object Qmode_line;
 Lisp_Object Qvertical_line;
 Lisp_Object Qright_divider, Qbottom_divider;
-static Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 
 static Lisp_Object Qecho_keystrokes;
@@ -356,7 +368,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 +388,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;
@@ -495,10 +500,12 @@ kset_system_key_syms (struct kboard *kb, Lisp_Object val)
 static void
 echo_add_key (Lisp_Object c)
 {
-  int size = KEY_DESCRIPTION_SIZE + 100;
-  char *buffer = alloca (size);
+  char initbuf[KEY_DESCRIPTION_SIZE + 100];
+  ptrdiff_t size = sizeof initbuf;
+  char *buffer = initbuf;
   char *ptr = buffer;
   Lisp_Object echo_string;
+  USE_SAFE_ALLOCA;
 
   echo_string = KVAR (current_kboard, echo_string);
 
@@ -510,13 +517,13 @@ echo_add_key (Lisp_Object c)
   else if (SYMBOLP (c))
     {
       Lisp_Object name = SYMBOL_NAME (c);
-      int nbytes = SBYTES (name);
+      ptrdiff_t nbytes = SBYTES (name);
 
       if (size - (ptr - buffer) < nbytes)
        {
-         int offset = ptr - buffer;
+         ptrdiff_t offset = ptr - buffer;
          size = max (2 * size, size + nbytes);
-         buffer = alloca (size);
+         buffer = SAFE_ALLOCA (size);
          ptr = buffer + offset;
        }
 
@@ -527,14 +534,14 @@ echo_add_key (Lisp_Object c)
   if ((NILP (echo_string) || SCHARS (echo_string) == 0)
       && help_char_p (c))
     {
-      const char *text = " (Type ? for further options)";
-      int len = strlen (text);
+      static const char text[] = " (Type ? for further options)";
+      int len = sizeof text - 1;
 
       if (size - (ptr - buffer) < len)
        {
-         int offset = ptr - buffer;
+         ptrdiff_t offset = ptr - buffer;
          size += len;
-         buffer = alloca (size);
+         buffer = SAFE_ALLOCA (size);
          ptr = buffer + offset;
        }
 
@@ -544,6 +551,7 @@ echo_add_key (Lisp_Object c)
 
   /* Replace a dash from echo_dash with a space, otherwise add a space
      at the end as a separator between keys.  */
+  AUTO_STRING (space, " ");
   if (STRINGP (echo_string) && SCHARS (echo_string) > 1)
     {
       Lisp_Object last_char, prev_char, idx;
@@ -559,14 +567,15 @@ echo_add_key (Lisp_Object c)
       if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
        Faset (echo_string, idx, make_number (' '));
       else
-       echo_string = concat2 (echo_string, build_string (" "));
+       echo_string = concat2 (echo_string, space);
     }
   else if (STRINGP (echo_string) && SCHARS (echo_string) > 0)
-    echo_string = concat2 (echo_string, build_string (" "));
+    echo_string = concat2 (echo_string, space);
 
   kset_echo_string
     (current_kboard,
      concat2 (echo_string, make_string (buffer, ptr - buffer)));
+  SAFE_FREE ();
 }
 
 /* Add C to the echo string, if echoing is going on.  C can be a
@@ -622,9 +631,9 @@ echo_dash (void)
 
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
-  kset_echo_string
-    (current_kboard,
-     concat2 (KVAR (current_kboard, echo_string), build_string ("-")));
+  AUTO_STRING (dash, "-");
+  kset_echo_string (current_kboard,
+                   concat2 (KVAR (current_kboard, echo_string), dash));
   echo_now ();
 }
 
@@ -1117,7 +1126,7 @@ Default value of `command-error-function'.  */)
     {
       print_error_message (data, Qexternal_debugging_output,
                           SSDATA (context), signal);
-      Fterpri (Qexternal_debugging_output);
+      Fterpri (Qexternal_debugging_output, Qnil);
       Fkill_emacs (make_number (-1));
     }
   else
@@ -1142,6 +1151,17 @@ static Lisp_Object top_level_1 (Lisp_Object);
 Lisp_Object
 command_loop (void)
 {
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+  /* At least on GNU/Linux, saving signal mask is important here.  */
+  if (sigsetjmp (return_to_command_loop, 1) != 0)
+    {
+      /* Comes here from handle_sigsegv, see sysdep.c.  */
+      init_eval ();
+      Vinternal__top_level_message = recover_top_level_message;
+    }
+  else
+    Vinternal__top_level_message = regular_top_level_message;
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
   if (command_loop_level > 0 || minibuf_level > 0)
     {
       Lisp_Object val;
@@ -1222,7 +1242,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 +1253,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)
@@ -1266,13 +1286,9 @@ tracking_off (Lisp_Object old_value)
     }
 }
 
-DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
-       doc: /* Evaluate BODY with mouse movement events enabled.
-Within a `track-mouse' form, mouse motion generates input events that
-you can read with `read-event'.
-Normally, mouse motion is ignored.
-usage: (track-mouse BODY...)  */)
-  (Lisp_Object args)
+DEFUN ("internal--track-mouse", Ftrack_mouse, Strack_mouse, 1, 1, 0,
+       doc: /* Call BODYFUN with mouse movement events enabled.  */)
+  (Lisp_Object bodyfun)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object val;
@@ -1281,7 +1297,7 @@ usage: (track-mouse BODY...)  */)
 
   do_mouse_tracking = Qt;
 
-  val = Fprogn (args);
+  val = call0 (bodyfun);
   return unbind_to (count, val);
 }
 
@@ -1292,9 +1308,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 +1336,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, ...  */
@@ -1449,7 +1459,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.  */
@@ -1524,6 +1534,13 @@ command_loop_1 (void)
 
       /* Execute the command.  */
 
+      {
+       total_keys += total_keys < NUM_RECENT_KEYS;
+       ASET (recent_keys, recent_keys_index,
+             Fcons (Qnil, cmd));
+       if (++recent_keys_index >= NUM_RECENT_KEYS)
+         recent_keys_index = 0;
+      }
       Vthis_command = cmd;
       Vreal_this_command = cmd;
       safe_run_hooks (Qpre_command_hook);
@@ -1643,7 +1660,7 @@ command_loop_1 (void)
                    = call1 (Fsymbol_value (Qregion_extract_function), Qnil);
                  if (XINT (Flength (txt)) > 0)
                    /* Don't set empty selections.  */
-                   call2 (Qx_set_selection, QPRIMARY, txt);
+                   call2 (Qgui_set_selection, QPRIMARY, txt);
                }
 
              if (current_buffer != prev_buffer || MODIFF != prev_modiff)
@@ -1697,7 +1714,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);
@@ -1866,30 +1883,27 @@ adjust_point_for_property (ptrdiff_t last_pt, bool modified)
     }
 }
 
-/* Subroutine for safe_run_hooks: run the hook HOOK.  */
+/* Subroutine for safe_run_hooks: run the hook, which is ARGS[1].  */
 
 static Lisp_Object
-safe_run_hooks_1 (void)
+safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args)
 {
-  eassert (CONSP (Vinhibit_quit));
-  return call0 (XCDR (Vinhibit_quit));
+  eassert (nargs == 2);
+  return call0 (args[1]);
 }
 
 /* Subroutine for safe_run_hooks: handle an error by clearing out the function
    from the hook.  */
 
 static Lisp_Object
-safe_run_hooks_error (Lisp_Object error_data)
+safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
 {
-  Lisp_Object hook
-    = CONSP (Vinhibit_quit) ? XCAR (Vinhibit_quit) : Vinhibit_quit;
-  Lisp_Object fun = CONSP (Vinhibit_quit) ? XCDR (Vinhibit_quit) : Qnil;
-  Lisp_Object args[4];
-  args[0] = build_string ("Error in %s (%S): %S");
-  args[1] = hook;
-  args[2] = fun;
-  args[3] = error_data;
-  Fmessage (4, args);
+  eassert (nargs == 2);
+  AUTO_STRING (format, "Error in %s (%S): %S");
+  Lisp_Object hook = args[0];
+  Lisp_Object fun = args[1];
+  Fmessage (4, (Lisp_Object []) {format, hook, fun, error});
+
   if (SYMBOLP (hook))
     {
       Lisp_Object val;
@@ -1921,13 +1935,14 @@ safe_run_hooks_error (Lisp_Object error_data)
 static Lisp_Object
 safe_run_hook_funcall (ptrdiff_t nargs, Lisp_Object *args)
 {
-  eassert (nargs == 1);
-  if (CONSP (Vinhibit_quit))
-    XSETCDR (Vinhibit_quit, args[0]);
-  else
-    Vinhibit_quit = Fcons (Vinhibit_quit, args[0]);
+  Lisp_Object iargs[2];
 
-  internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
+  eassert (nargs == 2);
+  /* Yes, run_hook_with_args works this way.  */
+  iargs[0] = args[1];
+  iargs[1] = args[0];
+  internal_condition_case_n (safe_run_hooks_1, 2, iargs,
+                            Qt, safe_run_hooks_error);
   return Qnil;
 }
 
@@ -1938,15 +1953,18 @@ safe_run_hook_funcall (ptrdiff_t nargs, Lisp_Object *args)
 void
 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 ;-)  */
+  Lisp_Object args[2];
+  struct gcpro gcpro1;
   ptrdiff_t count = SPECPDL_INDEX ();
-  specbind (Qinhibit_quit, hook);
 
-  run_hook_with_args (1, &hook, safe_run_hook_funcall);
+  args[0] = hook;
+  args[1] = hook;
 
+  GCPRO1 (hook);
+  specbind (Qinhibit_quit, Qt);
+  run_hook_with_args (2, args, safe_run_hook_funcall);
   unbind_to (count, Qnil);
+  UNGCPRO;
 }
 
 \f
@@ -2091,16 +2109,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;
@@ -2302,8 +2317,10 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
                                     bool *used_mouse_menu)
 {
 #define MAX_ENCODED_BYTES 16
+#ifndef WINDOWSNT
   Lisp_Object events[MAX_ENCODED_BYTES];
   int n = 0;
+#endif
   while (true)
     {
       Lisp_Object nextevt
@@ -2336,15 +2353,16 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
            { /* An encoded byte sequence, let's try to decode it.  */
              struct coding_system *coding
                = TERMINAL_KEYBOARD_CODING (terminal);
-             unsigned char *src = alloca (n);
+             unsigned char src[MAX_ENCODED_BYTES];
+             unsigned char dest[MAX_ENCODED_BYTES * MAX_MULTIBYTE_LENGTH];
              int i;
              for (i = 0; i < n; i++)
                src[i] = XINT (events[i]);
              if (meta_key != 2)
                for (i = 0; i < n; i++)
                  src[i] &= ~0x80;
-             coding->destination = alloca (n * 4);
-             coding->dst_bytes = n * 4;
+             coding->destination = dest;
+             coding->dst_bytes = sizeof dest;
              decode_coding_c_string (coding, src, n, Qnil);
              eassert (coding->produced_char <= n);
              if (coding->produced_char == 0)
@@ -2374,6 +2392,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.
@@ -2431,7 +2456,6 @@ read_char (int commandflag, Lisp_Object map,
 
  retry:
 
-  reread = 0;
   if (CONSP (Vunread_post_input_method_events))
     {
       c = XCAR (Vunread_post_input_method_events);
@@ -2445,9 +2469,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))
     {
@@ -2456,17 +2483,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.  */
@@ -2500,7 +2523,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;
     }
 
@@ -2655,6 +2678,7 @@ read_char (int commandflag, Lisp_Object map,
       /* We must have saved the outer value of getcjmp here,
         so restore it now.  */
       restore_getcjmp (save_jump);
+      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
       unbind_to (jmpcount, Qnil);
       XSETINT (c, quit_char);
       internal_last_event_frame = selected_frame;
@@ -2709,8 +2733,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.  */
@@ -2841,6 +2864,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.  */
@@ -2894,8 +2922,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;
         }
@@ -3171,8 +3199,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)))
        {
@@ -3248,8 +3275,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);
 
@@ -3471,11 +3497,13 @@ readable_events (int flags)
                    event->kind == FOCUS_IN_EVENT)
 #ifdef USE_TOOLKIT_SCROLL_BARS
                  && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
-                      && event->kind == SCROLL_BAR_CLICK_EVENT
+                      && (event->kind == SCROLL_BAR_CLICK_EVENT
+                          || event->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
                       && event->part == scroll_bar_handle
                       && event->modifiers == 0)
 #endif
-                 )
+                 && !((flags & READABLE_EVENTS_FILTER_EVENTS)
+                      && event->kind == BUFFER_SWITCH_EVENT))
                return 1;
              event++;
               if (event == kbd_buffer + KBD_BUFFER_SIZE)
@@ -3704,6 +3732,34 @@ kbd_buffer_unget_event (register struct input_event *event)
     }
 }
 
+/* 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, \
+                                     MOST_POSITIVE_FIXNUM)))
+#define INPUT_EVENT_POS_MIN (-1 - INPUT_EVENT_POS_MAX)
+
+/* Return a Time that encodes position POS.  POS must be in range.  */
+
+static Time
+position_to_Time (ptrdiff_t pos)
+{
+  eassert (INPUT_EVENT_POS_MIN <= pos && pos <= INPUT_EVENT_POS_MAX);
+  return pos;
+}
+
+/* Return the position that ENCODED_POS encodes.
+   Avoid signed integer overflow.  */
+
+static ptrdiff_t
+Time_to_position (Time encoded_pos)
+{
+  if (encoded_pos <= INPUT_EVENT_POS_MAX)
+    return encoded_pos;
+  Time encoded_pos_min = INPUT_EVENT_POS_MIN;
+  eassert (encoded_pos_min <= encoded_pos);
+  ptrdiff_t notpos = -1 - encoded_pos;
+  return -1 - notpos;
+}
 
 /* Generate a HELP_EVENT input_event and store it in the keyboard
    buffer.
@@ -3722,14 +3778,12 @@ gen_help_event (Lisp_Object help, Lisp_Object frame, Lisp_Object window,
 {
   struct input_event event;
 
-  EVENT_INIT (event);
-
   event.kind = HELP_EVENT;
   event.frame_or_window = frame;
   event.arg = object;
   event.x = WINDOWP (window) ? window : frame;
   event.y = help;
-  event.code = pos;
+  event.timestamp = position_to_Time (pos);
   kbd_buffer_store_event (&event);
 }
 
@@ -3746,7 +3800,7 @@ kbd_buffer_store_help_event (Lisp_Object frame, Lisp_Object help)
   event.arg = Qnil;
   event.x = Qnil;
   event.y = help;
-  event.code = 0;
+  event.timestamp = 0;
   kbd_buffer_store_event (&event);
 }
 
@@ -3768,7 +3822,8 @@ discard_mouse_events (void)
 #ifdef HAVE_GPM
          || sp->kind == GPM_CLICK_EVENT
 #endif
-         || sp->kind == SCROLL_BAR_CLICK_EVENT)
+         || sp->kind == SCROLL_BAR_CLICK_EVENT
+         || sp->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
        {
          sp->kind = NO_EVENT;
        }
@@ -4060,7 +4115,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 
          frame = event->frame_or_window;
          object = event->arg;
-         position = make_number (event->code);
+         position = make_number (Time_to_position (event->timestamp));
          window = event->x;
          help = event->y;
          clear_event (event);
@@ -4374,9 +4429,15 @@ decode_timer (Lisp_Object timer, struct timespec *result)
   vector = XVECTOR (timer)->contents;
   if (! NILP (vector[0]))
     return 0;
+  if (! INTEGERP (vector[2]))
+    return false;
 
-  return decode_time_components (vector[1], vector[2], vector[3], vector[8],
-                                result, 0);
+  struct lisp_time t;
+  if (! decode_time_components (vector[1], vector[2], vector[3], vector[8],
+                               &t, 0))
+    return false;
+  *result = lisp_to_timespec (t);
+  return timespec_valid_p (*result);
 }
 
 
@@ -5167,15 +5228,20 @@ static const char *const lispy_drag_n_drop_names[] =
 
 /* Scroll bar parts.  */
 static Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
-Lisp_Object Qup, Qdown, Qbottom;
+static Lisp_Object Qbefore_handle, Qhorizontal_handle, Qafter_handle;
+Lisp_Object Qup, Qdown, Qtop, Qbottom;
+static Lisp_Object Qleftmost, Qrightmost;
 static Lisp_Object Qend_scroll;
-Lisp_Object Qtop;
 static Lisp_Object Qratio;
 
-/* An array of scroll bar parts, indexed by an enum scroll_bar_part value.  */
+/* An array of scroll bar parts, indexed by an enum scroll_bar_part value.
+   Note that Qnil corresponds to scroll_bar_nowhere and should not appear
+   in Lisp events.  */
 static Lisp_Object *const scroll_bar_parts[] = {
-  &Qabove_handle, &Qhandle, &Qbelow_handle,
-  &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio
+  &Qnil, &Qabove_handle, &Qhandle, &Qbelow_handle,
+  &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio,
+  &Qbefore_handle, &Qhorizontal_handle, &Qafter_handle,
+  &Qleft, &Qright, &Qleftmost, &Qrightmost, &Qend_scroll, &Qratio
 };
 
 /* A vector, indexed by button number, giving the down-going location
@@ -5225,7 +5291,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;
@@ -5260,9 +5326,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;
@@ -5281,12 +5345,14 @@ 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));
+         xret = wx;
          yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
        }
       else if (part == ON_LEFT_FRINGE)
        {
          posn = Qleft_fringe;
          col = 0;
+         xret = wx;
          dx = wx
            - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
               ? 0 : window_box_width (w, LEFT_MARGIN_AREA));
@@ -5296,6 +5362,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
        {
          posn = Qright_fringe;
          col = 0;
+         xret = wx;
          dx = wx
            - window_box_width (w, LEFT_MARGIN_AREA)
            - window_box_width (w, TEXT_AREA)
@@ -5309,9 +5376,23 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
          posn = Qvertical_line;
          width = 1;
          dx = 0;
+         xret = wx;
+         dy = yret = wy;
+       }
+      else if (part == ON_VERTICAL_SCROLL_BAR)
+       {
+         posn = Qvertical_scroll_bar;
+         width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+         dx = xret = wx;
+         dy = yret = wy;
+       }
+      else if (part == ON_HORIZONTAL_SCROLL_BAR)
+       {
+         posn = Qhorizontal_scroll_bar;
+         width = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
+         dx = xret = wx;
          dy = yret = wy;
        }
-      /* Nothing special for part == ON_SCROLL_BAR.  */
       else if (part == ON_RIGHT_DIVIDER)
        {
          posn = Qright_divider;
@@ -5330,7 +5411,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;
@@ -5381,21 +5462,26 @@ 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)));
     }
   else if (f != 0)
-    XSETFRAME (window, f);
+    {
+      /* Return mouse pixel coordinates here.  */
+      XSETFRAME (window, f);
+      xret = XINT (x);
+      yret = XINT (y);
+    }
   else
     window = Qnil;
 
@@ -5421,6 +5507,16 @@ toolkit_menubar_in_use (struct frame *f)
 #endif
 }
 
+/* Build the part of Lisp event which represents scroll bar state from
+   EV.  TYPE is one of Qvertical_scroll_bar or Qhorizontal_scroll_bar.  */
+
+static Lisp_Object
+make_scroll_bar_position (struct input_event *ev, Lisp_Object type)
+{
+  return list5 (ev->frame_or_window, type, Fcons (ev->x, ev->y),
+               make_number (ev->timestamp), *scroll_bar_parts[ev->part]);
+}
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -5480,14 +5576,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
@@ -5496,8 +5591,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 */
 
@@ -5508,47 +5602,40 @@ 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)
-         || !lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
-       {
-         /* We need to use an alist rather than a vector as the cache
-            since we can't make a vector long enough.  */
-         if (NILP (KVAR (current_kboard, system_key_syms)))
-           kset_system_key_syms (current_kboard, Fcons (Qnil, Qnil));
-         return modify_event_symbol (event->code,
-                                     event->modifiers,
-                                     Qfunction_key,
-                                     KVAR (current_kboard, Vsystem_key_alist),
-                                     0, &KVAR (current_kboard, system_key_syms),
-                                     PTRDIFF_MAX);
-       }
-
-      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+      if ((FUNCTION_KEY_OFFSET <= event->code
+          && (event->code
+              < FUNCTION_KEY_OFFSET + ARRAYELTS (lispy_function_keys)))
+         && lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
+       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                   event->modifiers,
+                                   Qfunction_key, Qnil,
+                                   lispy_function_keys, &func_key_syms,
+                                   ARRAYELTS (lispy_function_keys));
+
+      /* Handle system-specific or unknown keysyms.
+        We need to use an alist rather than a vector as the cache
+        since we can't make a vector long enough.  */
+      if (NILP (KVAR (current_kboard, system_key_syms)))
+       kset_system_key_syms (current_kboard, Fcons (Qnil, Qnil));
+      return modify_event_symbol (event->code,
                                  event->modifiers,
-                                 Qfunction_key, Qnil,
-                                 lispy_function_keys, &func_key_syms,
-                                 (sizeof (lispy_function_keys)
-                                  / sizeof (lispy_function_keys[0])));
+                                 Qfunction_key,
+                                 KVAR (current_kboard, Vsystem_key_alist),
+                                 0, &KVAR (current_kboard, system_key_syms),
+                                 PTRDIFF_MAX);
 
 #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
@@ -5561,6 +5648,7 @@ make_lispy_event (struct input_event *event)
 #endif
 #ifndef USE_TOOLKIT_SCROLL_BARS
     case SCROLL_BAR_CLICK_EVENT:
+    case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
 #endif
       {
        int button = event->code;
@@ -5643,20 +5731,8 @@ make_lispy_event (struct input_event *event)
          }
 #ifndef USE_TOOLKIT_SCROLL_BARS
        else
-         {
-           /* It's a scrollbar click.  */
-           Lisp_Object window;
-           Lisp_Object portion_whole;
-           Lisp_Object part;
-
-           window = event->frame_or_window;
-           portion_whole = Fcons (event->x, event->y);
-           part = *scroll_bar_parts[(int) event->part];
-
-           position = list5 (window, Qvertical_scroll_bar,
-                             portion_whole, make_number (event->timestamp),
-                             part);
-         }
+         /* It's a scrollbar click.  */
+         position = make_scroll_bar_position (event, Qvertical_scroll_bar);
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
        if (button >= ASIZE (button_down_location))
@@ -5933,14 +6009,34 @@ make_lispy_event (struct input_event *event)
 
     case SCROLL_BAR_CLICK_EVENT:
       {
-       Lisp_Object position, head, window, portion_whole, part;
+       Lisp_Object position, head;
+
+       position = make_scroll_bar_position (event, Qvertical_scroll_bar);
 
-       window = event->frame_or_window;
-       portion_whole = Fcons (event->x, event->y);
-       part = *scroll_bar_parts[(int) event->part];
+       /* Always treat scroll bar events as clicks.  */
+       event->modifiers |= click_modifier;
+       event->modifiers &= ~up_modifier;
 
-       position = list5 (window, Qvertical_scroll_bar, portion_whole,
-                         make_number (event->timestamp), part);
+       if (event->code >= ASIZE (mouse_syms))
+          mouse_syms = larger_vector (mouse_syms,
+                                     event->code - ASIZE (mouse_syms) + 1,
+                                     -1);
+
+       /* Get the symbol we should use for the mouse click.  */
+       head = modify_event_symbol (event->code,
+                                   event->modifiers,
+                                   Qmouse_click,
+                                   Vlispy_mouse_stem,
+                                   NULL, &mouse_syms,
+                                   ASIZE (mouse_syms));
+       return list2 (head, position);
+      }
+
+    case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
+      {
+       Lisp_Object position, head;
+
+       position = make_scroll_bar_position (event, Qhorizontal_scroll_bar);
 
        /* Always treat scroll bar events as clicks.  */
        event->modifiers |= click_modifier;
@@ -6270,7 +6366,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;
 
@@ -6878,6 +6974,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);
         }
@@ -6888,8 +6998,6 @@ gobble_input (void)
   if (err && !nread)
     nread = -1;
 
-  frame_make_pointer_visible ();
-
   return nread;
 }
 
@@ -7295,7 +7403,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
@@ -7305,7 +7413,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",
@@ -7369,11 +7477,14 @@ menu_bar_items (Lisp_Object old)
      in the current keymaps, or nil where it is not a prefix.  */
   Lisp_Object *maps;
 
+  Lisp_Object mapsbuf[3];
   Lisp_Object def, tail;
 
   ptrdiff_t mapno;
   Lisp_Object oquit;
 
+  USE_SAFE_ALLOCA;
+
   /* In order to build the menus, we need to call the keymap
      accessors.  They all call QUIT.  But this function is called
      during redisplay, during which a quit is fatal.  So inhibit
@@ -7402,7 +7513,7 @@ menu_bar_items (Lisp_Object old)
        && !NILP (Voverriding_local_map))
       {
        /* Yes, use them (if non-nil) as well as the global map.  */
-       maps = alloca (3 * sizeof (maps[0]));
+       maps = mapsbuf;
        nmaps = 0;
        if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
          maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -7419,7 +7530,7 @@ menu_bar_items (Lisp_Object old)
        Lisp_Object tem;
        ptrdiff_t nminor;
        nminor = current_minor_maps (NULL, &tmaps);
-       maps = alloca ((nminor + 4) * sizeof *maps);
+       SAFE_NALLOCA (maps, 1, nminor + 4);
        nmaps = 0;
        tem = KVAR (current_kboard, Voverriding_terminal_local_map);
        if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
@@ -7480,8 +7591,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++;
@@ -7491,6 +7602,7 @@ menu_bar_items (Lisp_Object old)
   }
 
   Vinhibit_quit = oquit;
+  SAFE_FREE ();
   return menu_bar_items_vector;
 }
 \f
@@ -7806,11 +7918,12 @@ parse_menu_item (Lisp_Object item, int inmenubar)
 
   { /* This is a command.  See if there is an equivalent key binding.  */
     Lisp_Object keyeq = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
+    AUTO_STRING (space_space, "  ");
 
     /* The previous code preferred :key-sequence to :keys, so we
        preserve this behavior.  */
     if (STRINGP (keyeq) && !CONSP (keyhint))
-      keyeq = concat2 (build_string ("  "), Fsubstitute_command_keys (keyeq));
+      keyeq = concat2 (space_space, Fsubstitute_command_keys (keyeq));
     else
       {
        Lisp_Object prefix = keyeq;
@@ -7853,8 +7966,7 @@ parse_menu_item (Lisp_Object item, int inmenubar)
                if (STRINGP (XCDR (prefix)))
                  tem = concat2 (tem, XCDR (prefix));
              }
-           keyeq = concat2 (build_string ("  "), tem);
-           /* keyeq = concat3(build_string("  ("),tem,build_string(")")); */
+           keyeq = concat2 (space_space, tem);
          }
        else
          keyeq = Qnil;
@@ -7913,7 +8025,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);
 
@@ -7926,9 +8039,11 @@ Lisp_Object
 tool_bar_items (Lisp_Object reuse, int *nitems)
 {
   Lisp_Object *maps;
+  Lisp_Object mapsbuf[3];
   ptrdiff_t nmaps, i;
   Lisp_Object oquit;
   Lisp_Object *tmaps;
+  USE_SAFE_ALLOCA;
 
   *nitems = 0;
 
@@ -7952,7 +8067,7 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
       && !NILP (Voverriding_local_map))
     {
       /* Yes, use them (if non-nil) as well as the global map.  */
-      maps = alloca (3 * sizeof *maps);
+      maps = mapsbuf;
       nmaps = 0;
       if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
        maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -7969,7 +8084,7 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
       Lisp_Object tem;
       ptrdiff_t nminor;
       nminor = current_minor_maps (NULL, &tmaps);
-      maps = alloca ((nminor + 4) * sizeof *maps);
+      SAFE_NALLOCA (maps, 1, nminor + 4);
       nmaps = 0;
       tem = KVAR (current_kboard, Voverriding_terminal_local_map);
       if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
@@ -7998,6 +8113,7 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
 
   Vinhibit_quit = oquit;
   *nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+  SAFE_FREE ();
   return tool_bar_items_vector;
 }
 
@@ -8436,7 +8552,7 @@ static Lisp_Object
 read_char_minibuf_menu_prompt (int commandflag,
                               Lisp_Object map)
 {
-  register Lisp_Object name;
+  Lisp_Object name;
   ptrdiff_t nlength;
   /* FIXME: Use the minibuffer's frame width.  */
   ptrdiff_t width = FRAME_COLS (SELECTED_FRAME ()) - 4;
@@ -8554,10 +8670,14 @@ read_char_minibuf_menu_prompt (int commandflag,
                      /* Insert button prefix.  */
                      Lisp_Object selected
                        = AREF (item_properties, ITEM_PROPERTY_SELECTED);
+                     AUTO_STRING (radio_yes, "(*) ");
+                     AUTO_STRING (radio_no , "( ) ");
+                     AUTO_STRING (check_yes, "[X] ");
+                     AUTO_STRING (check_no , "[ ] ");
                      if (EQ (tem, QCradio))
-                       tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+                       tem = NILP (selected) ? radio_yes : radio_no;
                      else
-                       tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+                       tem = NILP (selected) ? check_yes : check_no;
                      s = concat2 (tem, s);
                    }
 
@@ -8935,8 +9055,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 ();
@@ -9068,8 +9187,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);
@@ -9734,8 +9852,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]);
     }
@@ -9766,7 +9883,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))
     {
@@ -9780,7 +9897,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);
 
@@ -9943,23 +10060,34 @@ If CHECK-TIMERS is non-nil, timers that are ready to run will do so.  */)
          ? Qt : Qnil);
 }
 
-DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
-       doc: /* Return vector of last 300 events, not counting those from keyboard macros.  */)
-  (void)
+DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 1, 0,
+       doc: /* Return vector of last few events, not counting those from keyboard macros.
+If INCLUDE-CMDS is non-nil, include the commands that were run,
+represented as events of the form (nil . COMMAND).  */)
+  (Lisp_Object include_cmds)
 {
-  Lisp_Object *keys = XVECTOR (recent_keys)->contents;
-  Lisp_Object val;
+  bool cmds = !NILP (include_cmds);
 
-  if (total_keys < NUM_RECENT_KEYS)
-    return Fvector (total_keys, keys);
+  if (!total_keys
+      || (cmds && total_keys < NUM_RECENT_KEYS))
+    return Fvector (total_keys,
+                   XVECTOR (recent_keys)->contents);
   else
     {
-      val = Fvector (NUM_RECENT_KEYS, keys);
-      vcopy (val, 0, keys + recent_keys_index,
-            NUM_RECENT_KEYS - recent_keys_index);
-      vcopy (val, NUM_RECENT_KEYS - recent_keys_index,
-            keys, recent_keys_index);
-      return val;
+      Lisp_Object es = Qnil;
+      int i = (total_keys < NUM_RECENT_KEYS
+              ? 0 : recent_keys_index);
+      eassert (recent_keys_index < NUM_RECENT_KEYS);
+      do
+       {
+         Lisp_Object e = AREF (recent_keys, i);
+         if (cmds || !CONSP (e) || !NILP (XCAR (e)))
+           es = Fcons (e, es);
+         if (++i >= NUM_RECENT_KEYS)
+           i = 0;
+       } while (i != recent_keys_index);
+      es = Fnreverse (es);
+      return Fvconcat (1, &es);
     }
 }
 
@@ -10182,7 +10310,9 @@ On such systems, Emacs starts a subshell instead of suspending.  */)
      with a window system; but suspend should be disabled in that case.  */
   get_tty_size (fileno (CURTTY ()->input), &width, &height);
   if (width != old_width || height != old_height)
-    change_frame_size (SELECTED_FRAME (), width, height, 0, 0, 0, 0);
+    change_frame_size (SELECTED_FRAME (), width,
+                      height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()),
+                      0, 0, 0, 0);
 
   /* Run suspend-resume-hook.  */
   hook = intern ("suspend-resume-hook");
@@ -10265,7 +10395,7 @@ static void
 handle_interrupt_signal (int sig)
 {
   /* See if we have an active terminal on our controlling tty.  */
-  struct terminal *terminal = get_named_tty ("/dev/tty");
+  struct terminal *terminal = get_named_terminal ("/dev/tty");
   if (!terminal)
     {
       /* If there are no frames there, let's pretend that we are a
@@ -10319,7 +10449,7 @@ handle_interrupt (bool in_signal_handler)
   cancel_echoing ();
 
   /* XXX This code needs to be revised for multi-tty support.  */
-  if (!NILP (Vquit_flag) && get_named_tty ("/dev/tty"))
+  if (!NILP (Vquit_flag) && get_named_terminal ("/dev/tty"))
     {
       if (! in_signal_handler)
        {
@@ -10531,9 +10661,10 @@ Emacs reads input in CBREAK mode; see `set-input-interrupt-mode'.
 See also `current-input-mode'.  */)
   (Lisp_Object flow, Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_tty_terminal (terminal);
   struct tty_display_info *tty;
-  if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+
+  if (!t)
     return Qnil;
   tty = t->display_info.tty;
 
@@ -10573,11 +10704,11 @@ the currently selected frame.
 See also `current-input-mode'.  */)
   (Lisp_Object meta, Lisp_Object terminal)
 {
-  struct terminal *t = get_terminal (terminal, 1);
+  struct terminal *t = decode_tty_terminal (terminal);
   struct tty_display_info *tty;
   int new_meta;
 
-  if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+  if (!t)
     return Qnil;
   tty = t->display_info.tty;
 
@@ -10614,9 +10745,10 @@ process.
 See also `current-input-mode'.  */)
   (Lisp_Object quit)
 {
-  struct terminal *t = get_named_tty ("/dev/tty");
+  struct terminal *t = get_named_terminal ("/dev/tty");
   struct tty_display_info *tty;
-  if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+
+  if (!t)
     return Qnil;
   tty = t->display_info.tty;
 
@@ -10693,7 +10825,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,
@@ -10959,6 +11091,15 @@ syms_of_keyboard (void)
   Vlispy_mouse_stem = build_pure_c_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
+  regular_top_level_message = build_pure_c_string ("Back to top level");
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+  recover_top_level_message
+    = build_pure_c_string ("Re-entering top level after C stack overflow");
+#endif
+  DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
+              doc: /* Message displayed by `normal-top-level'.  */);
+  Vinternal__top_level_message = regular_top_level_message;
+
   /* Tool-bars.  */
   DEFSYM (QCimage, ":image");
   DEFSYM (Qhelp_echo, "help-echo");
@@ -11016,7 +11157,6 @@ syms_of_keyboard (void)
 
   DEFSYM (Qmode_line, "mode-line");
   DEFSYM (Qvertical_line, "vertical-line");
-  DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
   DEFSYM (Qmenu_bar, "menu-bar");
   DEFSYM (Qright_divider, "right-divider");
   DEFSYM (Qbottom_divider, "bottom-divider");
@@ -11032,6 +11172,13 @@ syms_of_keyboard (void)
   DEFSYM (Qbottom, "bottom");
   DEFSYM (Qend_scroll, "end-scroll");
   DEFSYM (Qratio, "ratio");
+  DEFSYM (Qbefore_handle, "before-handle");
+  DEFSYM (Qhorizontal_handle, "horizontal-handle");
+  DEFSYM (Qafter_handle, "after-handle");
+  DEFSYM (Qleft, "left");
+  DEFSYM (Qright, "right");
+  DEFSYM (Qleftmost, "leftmost");
+  DEFSYM (Qrightmost, "rightmost");
 
   DEFSYM (Qevent_kind, "event-kind");
   DEFSYM (Qevent_symbol_elements, "event-symbol-elements");
@@ -11043,7 +11190,7 @@ syms_of_keyboard (void)
 
   DEFSYM (Qpolling_period, "polling-period");
 
-  DEFSYM (Qx_set_selection, "x-set-selection");
+  DEFSYM (Qgui_set_selection, "gui-set-selection");
   DEFSYM (QPRIMARY, "PRIMARY");
   DEFSYM (Qhandle_switch_frame, "handle-switch-frame");
   DEFSYM (Qhandle_select_window, "handle-select-window");
@@ -11061,7 +11208,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++)
       {
@@ -11077,14 +11224,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++)
@@ -11403,6 +11549,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.