]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Drop FRAME_PTR typedef.
[gnu-emacs] / src / keyboard.c
index 7594a4f72fcc0a49c4368dddff59c618becafe60..c026b16e68959d88083e958ff0d6b41dea45851f 100644 (file)
@@ -23,7 +23,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define BLOCKINPUT_INLINE EXTERN_INLINE
 #define KEYBOARD_INLINE EXTERN_INLINE
 
-#include <stdio.h>
+#include "sysstdio.h"
 
 #include "lisp.h"
 #include "termchar.h"
@@ -72,7 +72,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
-/* Variables for blockinput.h: */
+/* Variables for blockinput.h:  */
 
 /* Positive if interrupt input is blocked right now.  */
 volatile int interrupt_input_blocked;
@@ -210,12 +210,6 @@ static EMACS_INT last_auto_save;
 /* The value of point when the last command was started.  */
 static ptrdiff_t last_point_position;
 
-/* The buffer that was current when the last command was started.  */
-static Lisp_Object last_point_position_buffer;
-
-/* The window that was selected when the last command was started.  */
-static Lisp_Object last_point_position_window;
-
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
@@ -301,6 +295,7 @@ static struct input_event * volatile kbd_store_ptr;
 static Lisp_Object Qmouse_movement;
 static Lisp_Object Qscroll_bar_movement;
 Lisp_Object Qswitch_frame;
+static Lisp_Object Qfocus_in, Qfocus_out;
 static Lisp_Object Qdelete_frame;
 static Lisp_Object Qiconify_frame;
 static Lisp_Object Qmake_frame_visible;
@@ -314,18 +309,15 @@ static Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
 #ifdef HAVE_NTGUI
 Lisp_Object Qlanguage_change;
-#ifdef WINDOWSNT
-Lisp_Object Qfile_w32notify;
-#endif
 #endif
 static Lisp_Object Qdrag_n_drop;
 static Lisp_Object Qsave_session;
 #ifdef HAVE_DBUS
 static Lisp_Object Qdbus_event;
 #endif
-#ifdef HAVE_INOTIFY
-static Lisp_Object Qfile_inotify;
-#endif /* HAVE_INOTIFY */
+#ifdef USE_FILE_NOTIFY
+static Lisp_Object Qfile_notify;
+#endif /* USE_FILE_NOTIFY */
 static Lisp_Object Qconfig_changed_event;
 
 /* Lisp_Object Qmouse_movement; - also an event header */
@@ -365,9 +357,9 @@ Lisp_Object Qvertical_line;
 static Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 
-static Lisp_Object recursive_edit_unwind (Lisp_Object buffer);
+static void recursive_edit_unwind (Lisp_Object buffer);
 static Lisp_Object command_loop (void);
-static Lisp_Object Qextended_command_history;
+static Lisp_Object Qcommand_execute;
 EMACS_TIME timer_check (void);
 
 static void echo_now (void);
@@ -417,10 +409,9 @@ static void (*keyboard_init_hook) (void);
 
 static bool get_input_pending (int);
 static bool readable_events (int);
-static Lisp_Object read_char_x_menu_prompt (ptrdiff_t, Lisp_Object *,
+static Lisp_Object read_char_x_menu_prompt (Lisp_Object,
                                             Lisp_Object, bool *);
-static Lisp_Object read_char_minibuf_menu_prompt (int, ptrdiff_t,
-                                                  Lisp_Object *);
+static Lisp_Object read_char_minibuf_menu_prompt (int, Lisp_Object);
 static Lisp_Object make_lispy_event (struct input_event *);
 static Lisp_Object make_lispy_movement (struct frame *, Lisp_Object,
                                         enum scroll_bar_part,
@@ -430,12 +421,14 @@ static Lisp_Object modify_event_symbol (ptrdiff_t, int, Lisp_Object,
                                         Lisp_Object, const char *const *,
                                         Lisp_Object *, ptrdiff_t);
 static Lisp_Object make_lispy_switch_frame (Lisp_Object);
+static Lisp_Object make_lispy_focus_in (Lisp_Object);
+static Lisp_Object make_lispy_focus_out (Lisp_Object);
 static bool help_char_p (Lisp_Object);
 static void save_getcjmp (sys_jmp_buf);
 static void restore_getcjmp (sys_jmp_buf);
 static Lisp_Object apply_modifiers (int, Lisp_Object);
 static void clear_event (struct input_event *);
-static Lisp_Object restore_kboard_configuration (Lisp_Object);
+static void restore_kboard_configuration (int);
 #ifdef USABLE_SIGIO
 static void deliver_input_available_signal (int signo);
 #endif
@@ -675,9 +668,8 @@ echo_now (void)
     }
 
   echoing = 1;
-  message3_nolog (KVAR (current_kboard, echo_string),
-                 SBYTES (KVAR (current_kboard, echo_string)),
-                 STRING_MULTIBYTE (KVAR (current_kboard, echo_string)));
+  /* FIXME: Use call (Qmessage) so it can be advised (e.g. emacspeak).  */
+  message3_nolog (KVAR (current_kboard, echo_string));
   echoing = 0;
 
   /* Record in what buffer we echoed, and from which kboard.  */
@@ -835,7 +827,7 @@ This function is called by the editor initialization to begin editing.  */)
   update_mode_lines = 1;
 
   if (command_loop_level
-      && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
+      && current_buffer != XBUFFER (XWINDOW (selected_window)->contents))
     buffer = Fcurrent_buffer ();
   else
     buffer = Qnil;
@@ -852,7 +844,7 @@ This function is called by the editor initialization to begin editing.  */)
   return unbind_to (count, Qnil);
 }
 
-Lisp_Object
+void
 recursive_edit_unwind (Lisp_Object buffer)
 {
   if (BUFFERP (buffer))
@@ -860,7 +852,6 @@ recursive_edit_unwind (Lisp_Object buffer)
 
   command_loop_level--;
   update_mode_lines = 1;
-  return Qnil;
 }
 
 \f
@@ -957,7 +948,7 @@ pop_kboard (void)
   from which further input is accepted.  If F is non-nil, set its
   KBOARD as the current keyboard.
 
-  This function uses record_unwind_protect to return to the previous
+  This function uses record_unwind_protect_int to return to the previous
   state later.
 
   If Emacs is already in single_kboard mode, and F's keyboard is
@@ -988,8 +979,7 @@ temporarily_switch_to_single_kboard (struct frame *f)
   else if (f != NULL)
     current_kboard = FRAME_KBOARD (f);
   single_kboard = 1;
-  record_unwind_protect (restore_kboard_configuration,
-                         (was_locked ? Qt : Qnil));
+  record_unwind_protect_int (restore_kboard_configuration, was_locked);
 }
 
 #if 0 /* This function is not needed anymore.  */
@@ -998,26 +988,22 @@ record_single_kboard_state ()
 {
   if (single_kboard)
     push_kboard (current_kboard);
-  record_unwind_protect (restore_kboard_configuration,
-                         (single_kboard ? Qt : Qnil));
+  record_unwind_protect_int (restore_kboard_configuration, single_kboard);
 }
 #endif
 
-static Lisp_Object
-restore_kboard_configuration (Lisp_Object was_locked)
+static void
+restore_kboard_configuration (int was_locked)
 {
-  if (NILP (was_locked))
-    single_kboard = 0;
-  else
+  single_kboard = was_locked;
+  if (was_locked)
     {
       struct kboard *prev = current_kboard;
-      single_kboard = 1;
       pop_kboard ();
       /* The pop should not change the kboard.  */
       if (single_kboard && current_kboard != prev)
         emacs_abort ();
     }
-  return Qnil;
 }
 
 \f
@@ -1187,13 +1173,13 @@ top_level_2 (void)
 static Lisp_Object
 top_level_1 (Lisp_Object ignore)
 {
-  /* On entry to the outer level, run the startup file */
+  /* On entry to the outer level, run the startup file */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
   else if (!NILP (Vpurify_flag))
-    message ("Bare impure Emacs (standard Lisp code not loaded)");
+    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
-    message ("Bare Emacs (standard Lisp code not loaded)");
+    message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
 }
 
@@ -1245,7 +1231,7 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 /* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
    of this function.  */
 
-static Lisp_Object
+static void
 tracking_off (Lisp_Object old_value)
 {
   do_mouse_tracking = old_value;
@@ -1262,7 +1248,6 @@ tracking_off (Lisp_Object old_value)
          get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
        }
     }
-  return Qnil;
 }
 
 DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
@@ -1296,7 +1281,7 @@ static
 #endif
 bool ignore_mouse_drag_p;
 
-static FRAME_PTR
+static struct frame *
 some_mouse_moved (void)
 {
   Lisp_Object tail, frame;
@@ -1325,17 +1310,6 @@ static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
 void safe_run_hooks (Lisp_Object);
 static void adjust_point_for_property (ptrdiff_t, bool);
 
-/* Cancel hourglass from protect_unwind.
-   ARG is not used.  */
-#ifdef HAVE_WINDOW_SYSTEM
-static Lisp_Object
-cancel_hourglass_unwind (Lisp_Object arg)
-{
-  cancel_hourglass ();
-  return Qnil;
-}
-#endif
-
 /* The last boundary auto-added to buffer-undo-list.  */
 Lisp_Object last_undo_boundary;
 
@@ -1397,7 +1371,7 @@ command_loop_1 (void)
        Fkill_emacs (Qnil);
 
       /* Make sure the current window's buffer is selected.  */
-      set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+      set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents));
 
       /* Display any malloc warning that just came out.  Use while because
         displaying one warning can cause another.  */
@@ -1429,7 +1403,7 @@ command_loop_1 (void)
          sit_for (Vminibuffer_message_timeout, 0, 2);
 
          /* Clear the echo area.  */
-         message2 (0, 0, 0);
+         message1 (0);
          safe_run_hooks (Qecho_area_clear_hook);
 
          unbind_to (count, Qnil);
@@ -1438,7 +1412,7 @@ command_loop_1 (void)
          if (!NILP (Vquit_flag))
            {
              Vquit_flag = Qnil;
-             Vunread_command_events = Fcons (make_number (quit_char), Qnil);
+             Vunread_command_events = list1 (make_number (quit_char));
            }
        }
 
@@ -1463,7 +1437,7 @@ command_loop_1 (void)
       /* A filter may have run while we were reading the input.  */
       if (! FRAME_LIVE_P (XFRAME (selected_frame)))
        Fkill_emacs (Qnil);
-      set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+      set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents));
 
       ++num_input_keys;
 
@@ -1494,7 +1468,7 @@ command_loop_1 (void)
        {
          struct buffer *b;
          XWINDOW (selected_window)->force_start = 0;
-         b = XBUFFER (XWINDOW (selected_window)->buffer);
+         b = XBUFFER (XWINDOW (selected_window)->contents);
          BUF_BEG_UNCHANGED (b) = BUF_END_UNCHANGED (b) = 0;
        }
 
@@ -1514,8 +1488,6 @@ command_loop_1 (void)
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
-      last_point_position_window = selected_window;
-      XSETBUFFER (last_point_position_buffer, prev_buffer);
 
       /* By default, we adjust point to a boundary of a region that
          has such a property that should be treated intangible
@@ -1572,7 +1544,7 @@ command_loop_1 (void)
             if (display_hourglass_p
                 && NILP (Vexecuting_kbd_macro))
               {
-                record_unwind_protect (cancel_hourglass_unwind, Qnil);
+                record_unwind_protect_void (cancel_hourglass);
                 start_hourglass ();
               }
 #endif
@@ -1585,11 +1557,11 @@ command_loop_1 (void)
                  = (EQ (undo, BVAR (current_buffer, undo_list))
                     ? Qnil : BVAR (current_buffer, undo_list));
              }
-            Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
+            call1 (Qcommand_execute, Vthis_command);
 
 #ifdef HAVE_WINDOW_SYSTEM
          /* Do not check display_hourglass_p here, because
-            Fcommand_execute could change it, but we should cancel
+            `command-execute' could change it, but we should cancel
             hourglass cursor anyway.
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
@@ -1895,7 +1867,7 @@ safe_run_hooks_error (Lisp_Object error_data)
     = 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[0] = build_string ("Error in %s (%S): %S");
   args[1] = hook;
   args[2] = fun;
   args[3] = error_data;
@@ -2191,7 +2163,7 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
         This causes trouble if we are trying to read a mouse motion
         event (i.e., if we are inside a `track-mouse' form), so we
         restore the mouse_moved flag.  */
-      FRAME_PTR f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved ();
+      struct frame *f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved ();
       help = call1 (Qmouse_fixup_help_message, help);
       if (f)
        f->mouse_moved = 1;
@@ -2214,14 +2186,13 @@ static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu,
 static void record_char (Lisp_Object c);
 
 static Lisp_Object help_form_saved_window_configs;
-static Lisp_Object
-read_char_help_form_unwind (Lisp_Object arg)
+static void
+read_char_help_form_unwind (void)
 {
   Lisp_Object window_config = XCAR (help_form_saved_window_configs);
   help_form_saved_window_configs = XCDR (help_form_saved_window_configs);
   if (!NILP (window_config))
     Fset_window_configuration (window_config);
-  return Qnil;
 }
 
 #define STOP_POLLING                                   \
@@ -2232,13 +2203,165 @@ do { if (! polling_stopped_here) stop_polling ();      \
 do { if (polling_stopped_here) start_polling ();       \
        polling_stopped_here = 0; } while (0)
 
-/* read a character from the keyboard; call the redisplay if needed */
+static Lisp_Object
+read_event_from_main_queue (EMACS_TIME *end_time,
+                            sys_jmp_buf local_getcjmp,
+                            bool *used_mouse_menu)
+{
+  Lisp_Object c = Qnil;
+  sys_jmp_buf save_jump;
+  KBOARD *kb IF_LINT (= NULL);
+
+ start:
+
+  /* Read from the main queue, and if that gives us something we can't use yet,
+     we put it on the appropriate side queue and try again.  */
+
+  if (end_time && EMACS_TIME_LE (*end_time, current_emacs_time ()))
+    return c;
+
+  /* Actually read a character, waiting if necessary.  */
+  save_getcjmp (save_jump);
+  restore_getcjmp (local_getcjmp);
+  if (!end_time)
+       timer_start_idle ();
+  c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time);
+  restore_getcjmp (save_jump);
+
+  if (! NILP (c) && (kb != current_kboard))
+    {
+      Lisp_Object last = KVAR (kb, kbd_queue);
+      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;
+      c = Qnil;
+      if (single_kboard)
+        goto start;
+      current_kboard = kb;
+      /* This is going to exit from read_char
+         so we had better get rid of this frame's stuff.  */
+      return make_number (-2);
+    }
+
+  /* Terminate Emacs in batch mode if at eof.  */
+  if (noninteractive && INTEGERP (c) && XINT (c) < 0)
+    Fkill_emacs (make_number (1));
+
+  if (INTEGERP (c))
+    {
+      /* Add in any extra modifiers, where appropriate.  */
+      if ((extra_keyboard_modifiers & CHAR_CTL)
+         || ((extra_keyboard_modifiers & 0177) < ' '
+             && (extra_keyboard_modifiers & 0177) != 0))
+       XSETINT (c, make_ctrl_char (XINT (c)));
+
+      /* Transfer any other modifier bits directly from
+        extra_keyboard_modifiers to c.  Ignore the actual character code
+        in the low 16 bits of extra_keyboard_modifiers.  */
+      XSETINT (c, XINT (c) | (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL));
+    }
+
+  return c;
+}
+
+
+
+/* Like `read_event_from_main_queue' but applies keyboard-coding-system
+   to tty input.  */
+static Lisp_Object
+read_decoded_event_from_main_queue (EMACS_TIME *end_time,
+                                    sys_jmp_buf local_getcjmp,
+                                    Lisp_Object prev_event,
+                                    bool *used_mouse_menu)
+{
+#define MAX_ENCODED_BYTES 16
+  Lisp_Object events[MAX_ENCODED_BYTES];
+  int n = 0;
+  while (true)
+    {
+      Lisp_Object nextevt
+        = read_event_from_main_queue (end_time, local_getcjmp,
+                                      used_mouse_menu);
+#ifdef WINDOWSNT
+      /* w32_console already returns decoded events.  It either reads
+        Unicode characters from the Windows keyboard input, or
+        converts characters encoded in the current codepage into
+        Unicode.  See w32inevt.c:key_event, near its end.  */
+      return nextevt;
+#else
+      struct frame *frame = XFRAME (selected_frame);
+      struct terminal *terminal = frame->terminal;
+      if (!((FRAME_TERMCAP_P (frame) || FRAME_MSDOS_P (frame))
+            /* Don't apply decoding if we're just reading a raw event
+               (e.g. reading bytes sent by the xterm to specify the position
+               of a mouse click).  */
+            && (!EQ (prev_event, Qt))
+           && (TERMINAL_KEYBOARD_CODING (terminal)->common_flags
+               & CODING_REQUIRE_DECODING_MASK)))
+       return nextevt;         /* No decoding needed.  */
+      else
+       {
+         int meta_key = terminal->display_info.tty->meta_key;
+         eassert (n < MAX_ENCODED_BYTES);
+         events[n++] = nextevt;
+         if (NATNUMP (nextevt)
+             && XINT (nextevt) < (meta_key == 1 ? 0x80 : 0x100))
+           { /* An encoded byte sequence, let's try to decode it.  */
+             struct coding_system *coding
+               = TERMINAL_KEYBOARD_CODING (terminal);
+             unsigned char *src = alloca (n);
+             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;
+             decode_coding_c_string (coding, src, n, Qnil);
+             eassert (coding->produced_char <= n);
+             if (coding->produced_char == 0)
+               { /* The encoded sequence is incomplete.  */
+                 if (n < MAX_ENCODED_BYTES) /* Avoid buffer overflow.  */
+                   continue;                /* Read on!  */
+               }
+             else
+               {
+                 const unsigned char *p = coding->destination;
+                 eassert (coding->carryover_bytes == 0);
+                 n = 0;
+                 while (n < coding->produced_char)
+                   events[n++] = make_number (STRING_CHAR_ADVANCE (p));
+               }
+           }
+         /* Now `events' should hold decoded events.
+            Normally, n should be equal to 1, but better not rely on it.
+            We can only return one event here, so return the first we
+            had and keep the others (if any) for later.  */
+         while (n > 1)
+           Vunread_command_events
+             = Fcons (events[--n], Vunread_command_events);
+         return events[0];
+       }
+#endif
+    }
+}
+
+/* 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.
    1 means do both.  */
 
-/* The arguments MAPS and NMAPS are for menu prompting.
-   MAPS is an array of keymaps;  NMAPS is the length of MAPS.
+/* The arguments MAP is for menu prompting.  MAP is a keymap.
 
    PREV_EVENT is the previous input event, or nil if we are reading
    the first event of a key sequence (or not reading a key sequence).
@@ -2260,7 +2383,7 @@ do { if (polling_stopped_here) start_polling ();  \
    Value is t if we showed a menu and the user rejected it.  */
 
 Lisp_Object
-read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
+read_char (int commandflag, Lisp_Object map,
           Lisp_Object prev_event,
           bool *used_mouse_menu, EMACS_TIME *end_time)
 {
@@ -2408,7 +2531,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       goto reread_first;
     }
 
-  /* if redisplay was requested */
+  /* If redisplay was requested.  */
   if (commandflag >= 0)
     {
       bool echo_current = EQ (echo_message_buffer, echo_area_buffer[0]);
@@ -2417,7 +2540,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
           user-visible, such as X selection_request events.  */
       if (input_pending
          || detect_input_pending_run_timers (0))
-       swallow_events (0);             /* may clear input_pending */
+       swallow_events (0);             /* May clear input_pending.  */
 
       /* Redisplay if no pending input.  */
       while (!input_pending)
@@ -2487,13 +2610,13 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
      menu prompting. If EVENT_HAS_PARAMETERS then we are reading
      after a mouse event so don't try a minibuf menu.  */
   c = Qnil;
-  if (nmaps > 0 && INTERACTIVE
+  if (KEYMAPP (map) && INTERACTIVE
       && !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event)
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events)
       && !detect_input_pending_run_timers (0))
     {
-      c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
+      c = read_char_minibuf_menu_prompt (commandflag, map);
 
       if (INTEGERP (c) && XINT (c) == -2)
         return c;               /* wrong_kboard_jmpbuf */
@@ -2540,9 +2663,9 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
                  emacs_abort ();
              }
            if (!CONSP (last))
-             kset_kbd_queue (kb, Fcons (c, Qnil));
+             kset_kbd_queue (kb, list1 (c));
            else
-             XSETCDR (last, Fcons (c, Qnil));
+             XSETCDR (last, list1 (c));
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
            /* This is going to exit from read_char
@@ -2617,7 +2740,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
      because the recursive call of read_char in read_char_minibuf_menu_prompt
      does not pass on any keymaps.  */
 
-  if (nmaps > 0 && INTERACTIVE
+  if (KEYMAPP (map) && INTERACTIVE
       && !NILP (prev_event)
       && EVENT_HAS_PARAMETERS (prev_event)
       && !EQ (XCAR (prev_event), Qmenu_bar)
@@ -2625,7 +2748,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events))
     {
-      c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+      c = read_char_x_menu_prompt (map, prev_event, used_mouse_menu);
 
       /* Now that we have read an event, Emacs is not idle.  */
       if (!end_time)
@@ -2660,9 +2783,10 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
-         EMACS_INT timeout = (delay_level
-                              * min (XFASTINT (Vauto_save_timeout) / 4,
-                                     MOST_POSITIVE_FIXNUM / delay_level));
+         EMACS_INT timeout = XFASTINT (Vauto_save_timeout);
+
+         timeout = min (timeout, MOST_POSITIVE_FIXNUM / delay_level * 4);
+         timeout = delay_level * timeout / 4;
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
          tem0 = sit_for (make_number (timeout), 1, 1);
@@ -2749,68 +2873,20 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
 
   STOP_POLLING;
 
-  /* Finally, we read from the main queue,
-     and if that gives us something we can't use yet, we put it on the
-     appropriate side queue and try again.  */
-
   if (NILP (c))
     {
-      KBOARD *kb IF_LINT (= NULL);
-
+      c = read_decoded_event_from_main_queue (end_time, local_getcjmp,
+                                              prev_event, used_mouse_menu);
       if (end_time && EMACS_TIME_LE (*end_time, current_emacs_time ()))
-       goto exit;
-
-      /* Actually read a character, waiting if necessary.  */
-      save_getcjmp (save_jump);
-      restore_getcjmp (local_getcjmp);
-      if (!end_time)
-       timer_start_idle ();
-      c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time);
-      restore_getcjmp (save_jump);
-
-      if (! NILP (c) && (kb != current_kboard))
-       {
-         Lisp_Object last = KVAR (kb, kbd_queue);
-         if (CONSP (last))
-           {
-             while (CONSP (XCDR (last)))
-               last = XCDR (last);
-             if (!NILP (XCDR (last)))
-               emacs_abort ();
-           }
-         if (!CONSP (last))
-           kset_kbd_queue (kb, Fcons (c, Qnil));
-         else
-           XSETCDR (last, Fcons (c, Qnil));
-         kb->kbd_queue_has_data = 1;
-         c = Qnil;
-         if (single_kboard)
-           goto wrong_kboard;
-         current_kboard = kb;
+        goto exit;
+      if (EQ (c, make_number (-2)))
+        {
          /* This is going to exit from read_char
             so we had better get rid of this frame's stuff.  */
          UNGCPRO;
-          return make_number (-2);
-       }
-    }
-
-  /* Terminate Emacs in batch mode if at eof.  */
-  if (noninteractive && INTEGERP (c) && XINT (c) < 0)
-    Fkill_emacs (make_number (1));
-
-  if (INTEGERP (c))
-    {
-      /* Add in any extra modifiers, where appropriate.  */
-      if ((extra_keyboard_modifiers & CHAR_CTL)
-         || ((extra_keyboard_modifiers & 0177) < ' '
-             && (extra_keyboard_modifiers & 0177) != 0))
-       XSETINT (c, make_ctrl_char (XINT (c)));
-
-      /* Transfer any other modifier bits directly from
-        extra_keyboard_modifiers to c.  Ignore the actual character code
-        in the low 16 bits of extra_keyboard_modifiers.  */
-      XSETINT (c, XINT (c) | (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL));
-    }
+          return c;
+        }
+  }
 
  non_reread:
 
@@ -2844,7 +2920,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
     {
       struct buffer *prev_buffer = current_buffer;
       last_input_event = c;
-      Fcommand_execute (tem, Qnil, Fvector (1, &last_input_event), Qt);
+      call4 (Qcommand_execute, tem, Qnil, Fvector (1, &last_input_event), Qt);
 
       if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time)
        /* We stopped being idle for this event; undo that.  This
@@ -2907,7 +2983,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
-         POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
+         POSN_SET_POSN (EVENT_START (c), list1 (posn));
 
          also_record = c;
          Vunread_command_events = Fcons (c, Vunread_command_events);
@@ -3003,7 +3079,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
 
       /* If we are not reading a key sequence,
         never use the echo area.  */
-      if (maps == 0)
+      if (!KEYMAPP (map))
        {
          specbind (Qinput_method_use_echo_area, Qt);
        }
@@ -3096,7 +3172,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
   last_input_event = c;
   num_input_events++;
 
-  /* Process the help character specially if enabled */
+  /* Process the help character specially if enabled */
   if (!NILP (Vhelp_form) && help_char_p (c))
     {
       ptrdiff_t count = SPECPDL_INDEX ();
@@ -3104,19 +3180,19 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       help_form_saved_window_configs
        = Fcons (Fcurrent_window_configuration (Qnil),
                 help_form_saved_window_configs);
-      record_unwind_protect (read_char_help_form_unwind, Qnil);
+      record_unwind_protect_void (read_char_help_form_unwind);
       call0 (Qhelp_form_show);
 
       cancel_echoing ();
       do
        {
-         c = read_char (0, 0, 0, Qnil, 0, NULL);
+         c = read_char (0, Qnil, Qnil, 0, NULL);
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_click))
            XSETCAR (help_form_saved_window_configs, Qnil);
        }
       while (BUFFERP (c));
-      /* Remove the help from the frame */
+      /* Remove the help from the frame */
       unbind_to (count, Qnil);
 
       redisplay ();
@@ -3124,7 +3200,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
        {
          cancel_echoing ();
          do
-           c = read_char (0, 0, 0, Qnil, 0, NULL);
+           c = read_char (0, Qnil, Qnil, 0, NULL);
          while (BUFFERP (c));
        }
     }
@@ -3490,8 +3566,8 @@ kbd_buffer_store_event_hold (register struct input_event *event,
          if (single_kboard && kb != current_kboard)
            {
              kset_kbd_queue
-               (kb, Fcons (make_lispy_switch_frame (event->frame_or_window),
-                           Fcons (make_number (c), Qnil)));
+               (kb, list2 (make_lispy_switch_frame (event->frame_or_window),
+                           make_number (c)));
              kb->kbd_queue_has_data = 1;
              for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++)
                {
@@ -3854,9 +3930,9 @@ kbd_buffer_get_event (KBOARD **kbp,
       else if (event->kind == NS_TEXT_EVENT)
         {
           if (event->code == KEY_NS_PUT_WORKING_TEXT)
-            obj = Fcons (intern ("ns-put-working-text"), Qnil);
+            obj = list1 (intern ("ns-put-working-text"));
           else
-            obj = Fcons (intern ("ns-unput-working-text"), Qnil);
+            obj = list1 (intern ("ns-unput-working-text"));
          kbd_fetch_ptr = event + 1;
           if (used_mouse_menu)
             *used_mouse_menu = 1;
@@ -3868,8 +3944,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       else if (event->kind == DELETE_WINDOW_EVENT)
        {
          /* Make an event (delete-frame (FRAME)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qdelete_frame, Fcons (obj, Qnil));
+         obj = list2 (Qdelete_frame, list1 (event->frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
 #endif
@@ -3878,15 +3953,13 @@ kbd_buffer_get_event (KBOARD **kbp,
       else if (event->kind == ICONIFY_EVENT)
        {
          /* Make an event (iconify-frame (FRAME)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qiconify_frame, Fcons (obj, Qnil));
+         obj = list2 (Qiconify_frame, list1 (event->frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
       else if (event->kind == DEICONIFY_EVENT)
        {
          /* Make an event (make-frame-visible (FRAME)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qmake_frame_visible, Fcons (obj, Qnil));
+         obj = list2 (Qmake_frame_visible, list1 (event->frame_or_window));
          kbd_fetch_ptr = event + 1;
        }
 #endif
@@ -3909,29 +3982,33 @@ kbd_buffer_get_event (KBOARD **kbp,
 #ifdef HAVE_NTGUI
       else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
-         /* Make an event (language-change (FRAME CODEPAGE LANGUAGE-ID)).  */
-         obj = Fcons (Qlanguage_change,
-                      list3 (event->frame_or_window,
-                             make_number (event->code),
-                             make_number (event->modifiers)));
+         /* Make an event (language-change FRAME CODEPAGE LANGUAGE-ID).  */
+         obj = list4 (Qlanguage_change,
+                      event->frame_or_window,
+                      make_number (event->code),
+                      make_number (event->modifiers));
          kbd_fetch_ptr = event + 1;
        }
 #endif
-#ifdef WINDOWSNT
+#ifdef USE_FILE_NOTIFY
       else if (event->kind == FILE_NOTIFY_EVENT)
        {
+#ifdef HAVE_W32NOTIFY
          /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK).  */
-         obj = Fcons (Qfile_w32notify,
-                      list2 (list3 (make_number (event->code),
-                                    XCAR (event->arg),
-                                    XCDR (event->arg)),
-                             event->frame_or_window));
+         obj = list3 (Qfile_notify,
+                      list3 (make_number (event->code),
+                             XCAR (event->arg),
+                             XCDR (event->arg)),
+                      event->frame_or_window);
+#else
+          obj = make_lispy_event (event);
+#endif
          kbd_fetch_ptr = event + 1;
        }
-#endif
+#endif /* USE_FILE_NOTIFY */
       else if (event->kind == SAVE_SESSION_EVENT)
         {
-          obj = Fcons (Qsave_session, Fcons (event->arg, Qnil));
+          obj = list2 (Qsave_session, event->arg);
          kbd_fetch_ptr = event + 1;
         }
       /* Just discard these, by returning nil.
@@ -3968,30 +4045,49 @@ kbd_buffer_get_event (KBOARD **kbp,
             switch-frame event if necessary.  */
          Lisp_Object frame, focus;
 
-         frame = event->frame_or_window;
-         focus = FRAME_FOCUS_FRAME (XFRAME (frame));
-         if (FRAMEP (focus))
-           frame = focus;
+          frame = event->frame_or_window;
+          focus = FRAME_FOCUS_FRAME (XFRAME (frame));
+          if (FRAMEP (focus))
+            frame = focus;
 
-         if (!EQ (frame, internal_last_event_frame)
-             && !EQ (frame, selected_frame))
-           obj = make_lispy_switch_frame (frame);
-         internal_last_event_frame = frame;
-         kbd_fetch_ptr = event + 1;
-       }
+          if (
+#ifdef HAVE_X11
+              ! NILP (event->arg)
+              &&
+#endif
+              !EQ (frame, internal_last_event_frame)
+              && !EQ (frame, selected_frame))
+            obj = make_lispy_switch_frame (frame);
+          else
+            obj = make_lispy_focus_in (frame);
+
+          internal_last_event_frame = frame;
+          kbd_fetch_ptr = event + 1;
+        }
+      else if (event->kind == FOCUS_OUT_EVENT)
+        {
+#ifdef HAVE_WINDOW_SYSTEM
+
+          Display_Info *di;
+          Lisp_Object frame = event->frame_or_window;
+          bool focused = false;
+
+          for (di = x_display_list; di && ! focused; di = di->next)
+            focused = di->x_highlight_frame != 0;
+
+          if (!focused)
+           obj = make_lispy_focus_out (frame);
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+          kbd_fetch_ptr = event + 1;
+        }
 #ifdef HAVE_DBUS
       else if (event->kind == DBUS_EVENT)
        {
          obj = make_lispy_event (event);
          kbd_fetch_ptr = event + 1;
        }
-#endif
-#ifdef HAVE_INOTIFY
-      else if (event->kind == FILE_NOTIFY_EVENT)
-        {
-          obj = make_lispy_event (event);
-          kbd_fetch_ptr = event + 1;
-        }
 #endif
       else if (event->kind == CONFIG_CHANGED_EVENT)
        {
@@ -4056,7 +4152,7 @@ kbd_buffer_get_event (KBOARD **kbp,
   /* Try generating a mouse motion event.  */
   else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     {
-      FRAME_PTR f = some_mouse_moved ();
+      struct frame *f = some_mouse_moved ();
       Lisp_Object bar_window;
       enum scroll_bar_part part;
       Lisp_Object x, y;
@@ -4198,8 +4294,6 @@ swallow_events (bool do_display)
 static void
 timer_start_idle (void)
 {
-  Lisp_Object timers;
-
   /* If we are already in the idle state, do nothing.  */
   if (EMACS_TIME_VALID_P (timer_idleness_start_time))
     return;
@@ -4208,16 +4302,7 @@ timer_start_idle (void)
   timer_last_idleness_start_time = timer_idleness_start_time;
 
   /* Mark all idle-time timers as once again candidates for running.  */
-  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCDR (timers))
-    {
-      Lisp_Object timer;
-
-      timer = XCAR (timers);
-
-      if (!VECTORP (timer) || ASIZE (timer) != 9)
-       continue;
-      ASET (timer, 0, Qnil);
-    }
+  call0 (intern ("internal-timer-start-idle"));
 }
 
 /* Record that Emacs is no longer idle, so stop running idle-time timers.  */
@@ -4347,10 +4432,10 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
            }
 
          idle_timer_ripe = EMACS_TIME_LE (idle_timer_time, idleness_now);
-         idle_timer_difference =
-           (idle_timer_ripe
-            ? sub_emacs_time (idleness_now, idle_timer_time)
-            : sub_emacs_time (idle_timer_time, idleness_now));
+         idle_timer_difference
+           (idle_timer_ripe
+              ? sub_emacs_time (idleness_now, idle_timer_time)
+              : sub_emacs_time (idle_timer_time, idleness_now));
        }
 
       /* Decide which timer is the next timer,
@@ -5144,7 +5229,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
          if (STRINGP (string))
            string_info = Fcons (string, make_number (charpos));
          textpos = (w == XWINDOW (selected_window)
-                    && current_buffer == XBUFFER (w->buffer))
+                    && current_buffer == XBUFFER (w->contents))
            ? PT : marker_position (w->pointm);
 
          xret = wx;
@@ -5477,14 +5562,12 @@ make_lispy_event (struct input_event *event)
 
                /* ELisp manual 2.4b says (x y) are window relative but
                   code says they are frame-relative.  */
-               position
-                 = Fcons (event->frame_or_window,
-                          Fcons (Qmenu_bar,
-                                 Fcons (Fcons (event->x, event->y),
-                                        Fcons (make_number (event->timestamp),
-                                               Qnil))));
-
-               return Fcons (item, Fcons (position, Qnil));
+               position = list4 (event->frame_or_window,
+                                 Qmenu_bar,
+                                 Fcons (event->x, event->y),
+                                 make_number (event->timestamp));
+
+               return list2 (item, position);
              }
 #endif /* not USE_X_TOOLKIT && not USE_GTK && not HAVE_NS */
 
@@ -5503,12 +5586,9 @@ make_lispy_event (struct input_event *event)
            portion_whole = Fcons (event->x, event->y);
            part = *scroll_bar_parts[(int) event->part];
 
-           position
-             = Fcons (window,
-                      Fcons (Qvertical_scroll_bar,
-                             Fcons (portion_whole,
-                                    Fcons (make_number (event->timestamp),
-                                           Fcons (part, Qnil)))));
+           position = list5 (window, Qvertical_scroll_bar,
+                             portion_whole, make_number (event->timestamp),
+                             part);
          }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
 
@@ -5656,19 +5736,11 @@ make_lispy_event (struct input_event *event)
                                      &mouse_syms,
                                      ASIZE (mouse_syms));
          if (event->modifiers & drag_modifier)
-           return Fcons (head,
-                         Fcons (start_pos,
-                                Fcons (position,
-                                       Qnil)));
+           return list3 (head, start_pos, position);
          else if (event->modifiers & (double_modifier | triple_modifier))
-           return Fcons (head,
-                         Fcons (position,
-                                Fcons (make_number (double_click_count),
-                                       Qnil)));
+           return list3 (head, position, make_number (double_click_count));
          else
-           return Fcons (head,
-                         Fcons (position,
-                                Qnil));
+           return list2 (head, position);
        }
       }
 
@@ -5767,14 +5839,9 @@ make_lispy_event (struct input_event *event)
        }
 
        if (event->modifiers & (double_modifier | triple_modifier))
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (make_number (double_click_count),
-                                     Qnil)));
+         return list3 (head, position, make_number (double_click_count));
        else
-         return Fcons (head,
-                       Fcons (position,
-                              Qnil));
+         return list2 (head, position);
       }
 
 
@@ -5805,12 +5872,8 @@ make_lispy_event (struct input_event *event)
        portion_whole = Fcons (event->x, event->y);
        part = *scroll_bar_parts[(int) event->part];
 
-       position
-         = Fcons (window,
-                  Fcons (Qvertical_scroll_bar,
-                         Fcons (portion_whole,
-                                Fcons (make_number (event->timestamp),
-                                       Fcons (part, Qnil)))));
+       position = list5 (window, Qvertical_scroll_bar, portion_whole,
+                         make_number (event->timestamp), part);
 
        /* Always treat scroll bar events as clicks.  */
        event->modifiers |= click_modifier;
@@ -5828,14 +5891,14 @@ make_lispy_event (struct input_event *event)
                                    Vlispy_mouse_stem,
                                    NULL, &mouse_syms,
                                    ASIZE (mouse_syms));
-       return Fcons (head, Fcons (position, Qnil));
+       return list2 (head, position);
       }
 
 #endif /* USE_TOOLKIT_SCROLL_BARS */
 
     case DRAG_N_DROP_EVENT:
       {
-       FRAME_PTR f;
+       struct frame *f;
        Lisp_Object head, position;
        Lisp_Object files;
 
@@ -5854,10 +5917,7 @@ make_lispy_event (struct input_event *event)
                                    Qdrag_n_drop, Qnil,
                                    lispy_drag_n_drop_names,
                                    &drag_n_drop_syms, 1);
-       return Fcons (head,
-                     Fcons (position,
-                            Fcons (files,
-                                   Qnil)));
+       return list3 (head, position, files);
       }
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
@@ -5867,22 +5927,20 @@ make_lispy_event (struct input_event *event)
        /* This is the prefix key.  We translate this to
           `(menu_bar)' because the code in keyboard.c for menu
           events, which we use, relies on this.  */
-       return Fcons (Qmenu_bar, Qnil);
+       return list1 (Qmenu_bar);
       return event->arg;
 #endif
 
     case SELECT_WINDOW_EVENT:
       /* Make an event (select-window (WINDOW)).  */
-      return Fcons (Qselect_window,
-                   Fcons (Fcons (event->frame_or_window, Qnil),
-                          Qnil));
+      return list2 (Qselect_window, list1 (event->frame_or_window));
 
     case TOOL_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
           `(tool_bar)' because the code in keyboard.c for tool bar
           events, which we use, relies on this.  */
-       return Fcons (Qtool_bar, Qnil);
+       return list1 (Qtool_bar);
       else if (SYMBOLP (event->arg))
        return apply_modifiers (event->modifiers, event->arg);
       return event->arg;
@@ -5906,21 +5964,20 @@ make_lispy_event (struct input_event *event)
       }
 #endif /* HAVE_DBUS */
 
-#ifdef HAVE_INOTIFY
+#if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY
     case FILE_NOTIFY_EVENT:
       {
-        return Fcons (Qfile_inotify, event->arg);
+        return Fcons (Qfile_notify, event->arg);
       }
-#endif /* HAVE_INOTIFY */
+#endif /* defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY */
 
     case CONFIG_CHANGED_EVENT:
-       return Fcons (Qconfig_changed_event,
-                      Fcons (event->arg,
-                             Fcons (event->frame_or_window, Qnil)));
+       return list3 (Qconfig_changed_event,
+                     event->arg, event->frame_or_window);
 #ifdef HAVE_GPM
     case GPM_CLICK_EVENT:
       {
-       FRAME_PTR f = XFRAME (event->frame_or_window);
+       struct frame *f = XFRAME (event->frame_or_window);
        Lisp_Object head, position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
@@ -5957,24 +6014,13 @@ make_lispy_event (struct input_event *event)
                                    ASIZE (mouse_syms));
 
        if (event->modifiers & drag_modifier)
-         return Fcons (head,
-                       Fcons (start_pos,
-                              Fcons (position,
-                                     Qnil)));
+         return list3 (head, start_pos, position);
        else if (event->modifiers & double_modifier)
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (make_number (2),
-                                     Qnil)));
+         return list3 (head, position, make_number (2));
        else if (event->modifiers & triple_modifier)
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (make_number (3),
-                                     Qnil)));
+         return list3 (head, position, make_number (3));
        else
-         return Fcons (head,
-                       Fcons (position,
-                              Qnil));
+         return list2 (head, position);
        }
 #endif /* HAVE_GPM */
 
@@ -5985,7 +6031,7 @@ make_lispy_event (struct input_event *event)
 }
 
 static Lisp_Object
-make_lispy_movement (FRAME_PTR frame, Lisp_Object bar_window, enum scroll_bar_part part,
+make_lispy_movement (struct frame *frame, Lisp_Object bar_window, enum scroll_bar_part part,
                     Lisp_Object x, Lisp_Object y, Time t)
 {
   /* Is it a scroll bar movement?  */
@@ -5994,13 +6040,12 @@ make_lispy_movement (FRAME_PTR frame, Lisp_Object bar_window, enum scroll_bar_pa
       Lisp_Object part_sym;
 
       part_sym = *scroll_bar_parts[(int) part];
-      return Fcons (Qscroll_bar_movement,
-                   Fcons (list5 (bar_window,
-                                 Qvertical_scroll_bar,
-                                 Fcons (x, y),
-                                 make_number (t),
-                                 part_sym),
-                          Qnil));
+      return list2 (Qscroll_bar_movement,
+                   list5 (bar_window,
+                          Qvertical_scroll_bar,
+                          Fcons (x, y),
+                          make_number (t),
+                          part_sym));
     }
   /* Or is it an ordinary mouse movement?  */
   else
@@ -6015,7 +6060,18 @@ make_lispy_movement (FRAME_PTR frame, Lisp_Object bar_window, enum scroll_bar_pa
 static Lisp_Object
 make_lispy_switch_frame (Lisp_Object frame)
 {
-  return Fcons (Qswitch_frame, Fcons (frame, Qnil));
+  return list2 (Qswitch_frame, frame);
+}
+
+static Lisp_Object
+make_lispy_focus_in (Lisp_Object frame)
+{
+  return list2 (Qfocus_in, frame);
+}
+static Lisp_Object
+make_lispy_focus_out (Lisp_Object frame)
+{
+  return list2 (Qfocus_out, frame);
 }
 \f
 /* Manipulating modifiers.  */
@@ -6227,9 +6283,7 @@ parse_modifiers (Lisp_Object symbol)
   Lisp_Object elements;
 
   if (INTEGERP (symbol))
-    return (Fcons (make_number (KEY_TO_CHAR (symbol)),
-                  Fcons (make_number (XINT (symbol) & CHAR_MODIFIER_MASK),
-                         Qnil)));
+    return list2i (KEY_TO_CHAR (symbol), XINT (symbol) & CHAR_MODIFIER_MASK);
   else if (!SYMBOLP (symbol))
     return Qnil;
 
@@ -6250,7 +6304,7 @@ parse_modifiers (Lisp_Object symbol)
       if (modifiers & ~INTMASK)
        emacs_abort ();
       XSETFASTINT (mask, modifiers);
-      elements = Fcons (unmodified, Fcons (mask, Qnil));
+      elements = list2 (unmodified, mask);
 
       /* Cache the parsing results on SYMBOL.  */
       Fput (symbol, Qevent_symbol_element_mask,
@@ -6323,7 +6377,7 @@ apply_modifiers (int modifiers, Lisp_Object base)
         the caches:
          XSETFASTINT (idx, modifiers);
          Fput (new_symbol, Qevent_symbol_element_mask,
-               Fcons (base, Fcons (idx, Qnil)));
+               list2 (base, idx));
          Fput (new_symbol, Qevent_symbol_elements,
                Fcons (base, lispy_modifier_list (modifiers)));
         Sadly, this is only correct if `base' is indeed a base event,
@@ -6556,10 +6610,7 @@ has the same base event type and all the specified modifiers.  */)
   else if (SYMBOLP (base))
     return apply_modifiers (modifiers, base);
   else
-    {
-      error ("Invalid base event");
-      return Qnil;
-    }
+    error ("Invalid base event");
 }
 
 /* Try to recognize SYMBOL as a modifier name.
@@ -6773,7 +6824,7 @@ gobble_input (void)
           hold_quit.kind = NO_EVENT;
 
           /* No need for FIONREAD or fcntl; just say don't wait.  */
-         while (0 < (nr = (*t->read_socket_hook) (t, &hold_quit)))
+         while ((nr = (*t->read_socket_hook) (t, &hold_quit)) > 0)
            nread += nr;
 
           if (nr == -1)          /* Not OK to read input now.  */
@@ -6819,48 +6870,6 @@ gobble_input (void)
   return nread;
 }
 
-static void
-decode_keyboard_code (struct tty_display_info *tty,
-                     struct coding_system *coding,
-                     unsigned char *buf, int nbytes)
-{
-  unsigned char *src = buf;
-  const unsigned char *p;
-  int i;
-
-  if (nbytes == 0)
-    return;
-  if (tty->meta_key != 2)
-    for (i = 0; i < nbytes; i++)
-      buf[i] &= ~0x80;
-  if (coding->carryover_bytes > 0)
-    {
-      src = alloca (coding->carryover_bytes + nbytes);
-      memcpy (src, coding->carryover, coding->carryover_bytes);
-      memcpy (src + coding->carryover_bytes, buf, nbytes);
-      nbytes += coding->carryover_bytes;
-    }
-  coding->destination = alloca (nbytes * 4);
-  coding->dst_bytes = nbytes * 4;
-  decode_coding_c_string (coding, src, nbytes, Qnil);
-  if (coding->produced_char == 0)
-    return;
-  for (i = 0, p = coding->destination; i < coding->produced_char; i++)
-    {
-      struct input_event event_buf;
-
-      EVENT_INIT (event_buf);
-      event_buf.code = STRING_CHAR_ADVANCE (p);
-      event_buf.kind =
-       (ASCII_CHAR_P (event_buf.code)
-        ? ASCII_KEYSTROKE_EVENT : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
-      /* See the comment in tty_read_avail_input.  */
-      event_buf.frame_or_window = tty->top_frame;
-      event_buf.arg = Qnil;
-      kbd_buffer_store_event (&event_buf);
-    }
-}
-
 /* This is the tty way of reading available input.
 
    Note that each terminal device has its own `struct terminal' object,
@@ -6895,6 +6904,8 @@ tty_read_avail_input (struct terminal *terminal,
   /* XXX I think the following code should be moved to separate hook
      functions in system-dependent files.  */
 #ifdef WINDOWSNT
+  /* FIXME: AFAIK, tty_read_avail_input is not used under w32 since the non-GUI
+     code sets read_socket_hook to w32_console_read_socket instead!  */
   return 0;
 #else /* not WINDOWSNT */
   if (! tty->term_initted)      /* In case we get called during bootstrap.  */
@@ -6975,7 +6986,7 @@ tty_read_avail_input (struct terminal *terminal,
     {
       nread = emacs_read (fileno (tty->input), (char *) cbuf, n_to_read);
       /* POSIX infers that processes which are not in the session leader's
-         process group won't get SIGHUP's at logout time.  BSDI adheres to
+         process group won't get SIGHUPs at logout time.  BSDI adheres to
          this part standard and returns -1 from read (0) with errno==EIO
          when the control tty is taken away.
          Jeffrey Honig <jch@bsdi.com> says this is generally safe.  */
@@ -7018,36 +7029,6 @@ tty_read_avail_input (struct terminal *terminal,
 #endif /* not MSDOS */
 #endif /* not WINDOWSNT */
 
-  if (TERMINAL_KEYBOARD_CODING (terminal)->common_flags
-      & CODING_REQUIRE_DECODING_MASK)
-    {
-      struct coding_system *coding = TERMINAL_KEYBOARD_CODING (terminal);
-      int from;
-
-      /* Decode the key sequence except for those with meta
-        modifiers.  */
-      for (i = from = 0; ; i++)
-       if (i == nread || (tty->meta_key == 1 && (cbuf[i] & 0x80)))
-         {
-           struct input_event buf;
-
-           decode_keyboard_code (tty, coding, cbuf + from, i - from);
-           if (i == nread)
-             break;
-
-           EVENT_INIT (buf);
-           buf.kind = ASCII_KEYSTROKE_EVENT;
-           buf.modifiers = meta_modifier;
-           buf.code = cbuf[i] & ~0x80;
-           /* See the comment below.  */
-           buf.frame_or_window = tty->top_frame;
-           buf.arg = Qnil;
-           kbd_buffer_store_event (&buf);
-           from = i + 1;
-         }
-      return nread;
-    }
-
   for (i = 0; i < nread; i++)
     {
       struct input_event buf;
@@ -7388,7 +7369,8 @@ menu_bar_items (Lisp_Object old)
     Lisp_Object *tmaps;
 
     /* Should overriding-terminal-local-map and overriding-local-map apply?  */
-    if (!NILP (Voverriding_local_map_menu_flag))
+    if (!NILP (Voverriding_local_map_menu_flag)
+       && !NILP (Voverriding_local_map))
       {
        /* Yes, use them (if non-nil) as well as the global map.  */
        maps = alloca (3 * sizeof (maps[0]));
@@ -7408,8 +7390,11 @@ menu_bar_items (Lisp_Object old)
        Lisp_Object tem;
        ptrdiff_t nminor;
        nminor = current_minor_maps (NULL, &tmaps);
-       maps = alloca ((nminor + 3) * sizeof *maps);
+       maps = alloca ((nminor + 4) * sizeof *maps);
        nmaps = 0;
+       tem = KVAR (current_kboard, Voverriding_terminal_local_map);
+       if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
+         maps[nmaps++] = tem;
        if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem))
          maps[nmaps++] = tem;
        memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0]));
@@ -7544,7 +7529,7 @@ menu_bar_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy1, void *dumm
       ASET (menu_bar_items_vector, i, key); i++;
       ASET (menu_bar_items_vector, i,
            AREF (item_properties, ITEM_PROPERTY_NAME)); i++;
-      ASET (menu_bar_items_vector, i, Fcons (item, Qnil)); i++;
+      ASET (menu_bar_items_vector, i, list1 (item)); i++;
       ASET (menu_bar_items_vector, i, make_number (0)); i++;
       menu_bar_items_index = i;
     }
@@ -7934,7 +7919,8 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
      to process.  */
 
   /* Should overriding-terminal-local-map and overriding-local-map apply?  */
-  if (!NILP (Voverriding_local_map_menu_flag))
+  if (!NILP (Voverriding_local_map_menu_flag)
+      && !NILP (Voverriding_local_map))
     {
       /* Yes, use them (if non-nil) as well as the global map.  */
       maps = alloca (3 * sizeof *maps);
@@ -7954,8 +7940,11 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
       Lisp_Object tem;
       ptrdiff_t nminor;
       nminor = current_minor_maps (NULL, &tmaps);
-      maps = alloca ((nminor + 3) * sizeof *maps);
+      maps = alloca ((nminor + 4) * sizeof *maps);
       nmaps = 0;
+      tem = KVAR (current_kboard, Voverriding_terminal_local_map);
+      if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
+       maps[nmaps++] = tem;
       if (tem = get_local_map (PT, current_buffer, Qkeymap), !NILP (tem))
        maps[nmaps++] = tem;
       memcpy (maps + nmaps, tmaps, nminor * sizeof (maps[0]));
@@ -8095,7 +8084,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
 
   /* As an exception, allow old-style menu separators.  */
   if (STRINGP (XCAR (item)))
-    item = Fcons (XCAR (item), Qnil);
+    item = list1 (XCAR (item));
   else if (!EQ (XCAR (item), Qmenu_item)
           || (item = XCDR (item), !CONSP (item)))
     return 0;
@@ -8138,11 +8127,12 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
 #if !defined (USE_GTK) && !defined (HAVE_NS)
          /* If we use build_desired_tool_bar_string to render the
             tool bar, the separator is rendered as an image.  */
-         PROP (TOOL_BAR_ITEM_IMAGES)
-           = menu_item_eval_property (Vtool_bar_separator_image_expression);
-         PROP (TOOL_BAR_ITEM_ENABLED_P) = Qnil;
-         PROP (TOOL_BAR_ITEM_SELECTED_P) = Qnil;
-         PROP (TOOL_BAR_ITEM_CAPTION) = Qnil;
+         set_prop (TOOL_BAR_ITEM_IMAGES,
+                   (menu_item_eval_property
+                    (Vtool_bar_separator_image_expression)));
+         set_prop (TOOL_BAR_ITEM_ENABLED_P, Qnil);
+         set_prop (TOOL_BAR_ITEM_SELECTED_P, Qnil);
+         set_prop (TOOL_BAR_ITEM_CAPTION, Qnil);
 #endif
          return 1;
        }
@@ -8314,14 +8304,13 @@ init_tool_bar_items (Lisp_Object reuse)
 static void
 append_tool_bar_item (void)
 {
-  ptrdiff_t incr =
-    (ntool_bar_items
-     - (ASIZE (tool_bar_items_vector) - TOOL_BAR_ITEM_NSLOTS));
+  ptrdiff_t incr
+    (ntool_bar_items
+       - (ASIZE (tool_bar_items_vector) - TOOL_BAR_ITEM_NSLOTS));
 
   /* Enlarge tool_bar_items_vector if necessary.  */
-  if (0 < incr)
-    tool_bar_items_vector
-      = larger_vector (tool_bar_items_vector, incr, -1);
+  if (incr > 0)
+    tool_bar_items_vector = larger_vector (tool_bar_items_vector, incr, -1);
 
   /* Append entries from tool_bar_item_properties to the end of
      tool_bar_items_vector.  */
@@ -8334,8 +8323,8 @@ append_tool_bar_item (void)
 
 
 \f
-/* Read a character using menus based on maps in the array MAPS.
-   NMAPS is the length of MAPS.  Return nil if there are no menus in the maps.
+/* Read a character using menus based on the keymap MAP.
+   Return nil if there are no menus in the maps.
    Return t if we displayed a menu but the user rejected it.
 
    PREV_EVENT is the previous input event, or nil if we are reading
@@ -8355,28 +8344,17 @@ append_tool_bar_item (void)
    and do auto-saving in the inner call of read_char.  */
 
 static Lisp_Object
-read_char_x_menu_prompt (ptrdiff_t nmaps, Lisp_Object *maps,
+read_char_x_menu_prompt (Lisp_Object map,
                         Lisp_Object prev_event, bool *used_mouse_menu)
 {
-#ifdef HAVE_MENUS
-  ptrdiff_t mapno;
-#endif
-
   if (used_mouse_menu)
     *used_mouse_menu = 0;
 
-  /* Use local over global Menu maps */
+  /* Use local over global Menu maps */
 
   if (! menu_prompting)
     return Qnil;
 
-  /* Optionally disregard all but the global map.  */
-  if (inhibit_local_menu_bar_menus)
-    {
-      maps += (nmaps - 1);
-      nmaps = 1;
-    }
-
 #ifdef HAVE_MENUS
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
@@ -8385,16 +8363,9 @@ read_char_x_menu_prompt (ptrdiff_t nmaps, Lisp_Object *maps,
       && !EQ (XCAR (prev_event), Qtool_bar))
     {
       /* Display the menu and get the selection.  */
-      Lisp_Object *realmaps = alloca (nmaps * sizeof *realmaps);
       Lisp_Object value;
-      ptrdiff_t nmaps1 = 0;
 
-      /* Use the maps that are not nil.  */
-      for (mapno = 0; mapno < nmaps; mapno++)
-       if (!NILP (maps[mapno]))
-         realmaps[nmaps1++] = maps[mapno];
-
-      value = Fx_popup_menu (prev_event, Flist (nmaps1, realmaps));
+      value = Fx_popup_menu (prev_event, get_keymap (map, 0, 1));
       if (CONSP (value))
        {
          Lisp_Object tem;
@@ -8434,17 +8405,10 @@ read_char_x_menu_prompt (ptrdiff_t nmaps, Lisp_Object *maps,
   return Qnil ;
 }
 
-/* Buffer in use so far for the minibuf prompts for menu keymaps.
-   We make this bigger when necessary, and never free it.  */
-static char *read_char_minibuf_menu_text;
-/* Size of that buffer.  */
-static ptrdiff_t read_char_minibuf_menu_width;
-
 static Lisp_Object
 read_char_minibuf_menu_prompt (int commandflag,
-                              ptrdiff_t nmaps, Lisp_Object *maps)
+                              Lisp_Object map)
 {
-  ptrdiff_t mapno;
   register Lisp_Object name;
   ptrdiff_t nlength;
   /* FIXME: Use the minibuffer's frame width.  */
@@ -8452,53 +8416,35 @@ read_char_minibuf_menu_prompt (int commandflag,
   ptrdiff_t idx = -1;
   bool nobindings = 1;
   Lisp_Object rest, vector;
-  char *menu;
+  Lisp_Object prompt_strings = Qnil;
 
   vector = Qnil;
-  name = Qnil;
 
   if (! menu_prompting)
     return Qnil;
 
-  /* Get the menu name from the first map that has one (a prompt string).  */
-  for (mapno = 0; mapno < nmaps; mapno++)
-    {
-      name = Fkeymap_prompt (maps[mapno]);
-      if (!NILP (name))
-       break;
-    }
+  map = get_keymap (map, 0, 1);
+  name = Fkeymap_prompt (map);
 
   /* If we don't have any menus, just read a character normally.  */
   if (!STRINGP (name))
     return Qnil;
 
-  /* Make sure we have a big enough buffer for the menu text.  */
-  width = max (width, SBYTES (name));
-  if (STRING_BYTES_BOUND - 4 < width)
-    memory_full (SIZE_MAX);
-  if (width + 4 > read_char_minibuf_menu_width)
-    {
-      read_char_minibuf_menu_text
-       = xrealloc (read_char_minibuf_menu_text, width + 4);
-      read_char_minibuf_menu_width = width + 4;
-    }
-  menu = read_char_minibuf_menu_text;
+#define PUSH_C_STR(str, listvar) \
+  listvar = Fcons (make_unibyte_string (str, strlen (str)), listvar)
 
   /* Prompt string always starts with map's prompt, and a space.  */
-  strcpy (menu, SSDATA (name));
-  nlength = SBYTES (name);
-  menu[nlength++] = ':';
-  menu[nlength++] = ' ';
-  menu[nlength] = 0;
+  prompt_strings = Fcons (name, prompt_strings);
+  PUSH_C_STR (": ", prompt_strings);
+  nlength = SCHARS (name) + 2;
 
-  /* Start prompting at start of first map.  */
-  mapno = 0;
-  rest = maps[mapno];
+  rest = map;
 
   /* Present the documented bindings, a line at a time.  */
   while (1)
     {
       bool notfirst = 0;
+      Lisp_Object menu_strings = prompt_strings;
       ptrdiff_t i = nlength;
       Lisp_Object obj;
       Lisp_Object orig_defn_macro;
@@ -8508,18 +8454,16 @@ read_char_minibuf_menu_prompt (int commandflag,
        {
          Lisp_Object elt;
 
-         /* If reached end of map, start at beginning of next map.  */
+         /* FIXME: Use map_keymap to handle new keymap formats.  */
+
+         /* At end of map, wrap around if just starting,
+            or end this line if already have something on it.  */
          if (NILP (rest))
            {
-             mapno++;
-             /* At end of last map, wrap around to first map if just starting,
-                or end this line if already have something on it.  */
-             if (mapno == nmaps)
-               {
-                 mapno = 0;
-                 if (notfirst || nobindings) break;
-               }
-             rest = maps[mapno];
+             if (notfirst || nobindings)
+               break;
+             else
+               rest = map;
            }
 
          /* Look at the next element of the map.  */
@@ -8603,7 +8547,7 @@ read_char_minibuf_menu_prompt (int commandflag,
                      /* Punctuate between strings.  */
                      if (notfirst)
                        {
-                         strcpy (menu + i, ", ");
+                         PUSH_C_STR (", ", menu_strings);
                          i += 2;
                        }
                      notfirst = 1;
@@ -8615,23 +8559,28 @@ read_char_minibuf_menu_prompt (int commandflag,
                        {
                          /* Add as much of string as fits.  */
                          thiswidth = min (SCHARS (desc), width - i);
-                         memcpy (menu + i, SDATA (desc), thiswidth);
+                         menu_strings
+                           = Fcons (Fsubstring (desc, make_number (0),
+                                                make_number (thiswidth)),
+                                    menu_strings);
                          i += thiswidth;
-                         strcpy (menu + i, " = ");
+                         PUSH_C_STR (" = ", menu_strings);
                          i += 3;
                        }
 
                      /* Add as much of string as fits.  */
                      thiswidth = min (SCHARS (s), width - i);
-                     memcpy (menu + i, SDATA (s), thiswidth);
+                     menu_strings
+                       = Fcons (Fsubstring (s, make_number (0),
+                                            make_number (thiswidth)),
+                                menu_strings);
                      i += thiswidth;
-                     menu[i] = 0;
                    }
                  else
                    {
                      /* If this element does not fit, end the line now,
                         and save the element for the next line.  */
-                     strcpy (menu + i, "...");
+                     PUSH_C_STR ("...", menu_strings);
                      break;
                    }
                }
@@ -8648,23 +8597,19 @@ read_char_minibuf_menu_prompt (int commandflag,
        }
 
       /* Prompt with that and read response.  */
-      message2_nolog (menu, strlen (menu),
-                     ! NILP (BVAR (current_buffer, enable_multibyte_characters)));
+      message3_nolog (apply1 (intern ("concat"), Fnreverse (menu_strings)));
 
-      /* Make believe its not a keyboard macro in case the help char
+      /* Make believe it's not a keyboard macro in case the help char
         is pressed.  Help characters are not recorded because menu prompting
-        is not used on replay.
-        */
+        is not used on replay.  */
       orig_defn_macro = KVAR (current_kboard, defining_kbd_macro);
       kset_defining_kbd_macro (current_kboard, Qnil);
       do
-       obj = read_char (commandflag, 0, 0, Qt, 0, NULL);
+       obj = read_char (commandflag, Qnil, Qt, 0, NULL);
       while (BUFFERP (obj));
       kset_defining_kbd_macro (current_kboard, orig_defn_macro);
 
-      if (!INTEGERP (obj))
-       return obj;
-      else if (XINT (obj) == -2)
+      if (!INTEGERP (obj) || XINT (obj) == -2)
         return obj;
 
       if (! EQ (obj, menu_prompt_more_char)
@@ -8675,52 +8620,25 @@ read_char_minibuf_menu_prompt (int commandflag,
            store_kbd_macro_char (obj);
          return obj;
        }
-      /* Help char - go round again */
+      /* Help char - go round again */
     }
 }
 \f
 /* Reading key sequences.  */
 
-/* Follow KEY in the maps in CURRENT[0..NMAPS-1], placing its bindings
-   in DEFS[0..NMAPS-1].  Set NEXT[i] to DEFS[i] if DEFS[i] is a
-   keymap, or nil otherwise.  Return the index of the first keymap in
-   which KEY has any binding, or NMAPS if no map has a binding.
-
-   If KEY is a meta ASCII character, treat it like meta-prefix-char
-   followed by the corresponding non-meta character.  Keymaps in
-   CURRENT with non-prefix bindings for meta-prefix-char become nil in
-   NEXT.
-
-   If KEY has no bindings in any of the CURRENT maps, NEXT is left
-   unmodified.
-
-   NEXT may be the same array as CURRENT.  */
-
-static int
-follow_key (Lisp_Object key, ptrdiff_t nmaps, Lisp_Object *current,
-           Lisp_Object *defs, Lisp_Object *next)
+static Lisp_Object
+follow_key (Lisp_Object keymap, Lisp_Object key)
 {
-  ptrdiff_t i, first_binding;
-
-  first_binding = nmaps;
-  for (i = nmaps - 1; i >= 0; i--)
-    {
-      if (! NILP (current[i]))
-       {
-         defs[i] = access_keymap (current[i], key, 1, 0, 1);
-         if (! NILP (defs[i]))
-           first_binding = i;
-       }
-      else
-       defs[i] = Qnil;
-    }
-
-  /* Given the set of bindings we've found, produce the next set of maps.  */
-  if (first_binding < nmaps)
-    for (i = 0; i < nmaps; i++)
-      next[i] = NILP (defs[i]) ? Qnil : get_keymap (defs[i], 0, 1);
+  return access_keymap (get_keymap (keymap, 0, 1),
+                       key, 1, 0, 1);
+}
 
-  return first_binding;
+static Lisp_Object
+active_maps (Lisp_Object first_event)
+{
+  Lisp_Object position
+    = CONSP (first_event) ? CAR_SAFE (XCDR (first_event)) : Qnil;
+  return Fcons (Qkeymap, Fcurrent_active_maps (Qt, position));
 }
 
 /* Structure used to keep track of partial application of key remapping
@@ -8774,7 +8692,7 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt,
         barf--don't ignore it.
         (To ignore it safely, we would need to gcpro a bunch of
         other variables.)  */
-      if (! (VECTORP (next) || STRINGP (next)))
+      if (! (NILP (next) || VECTORP (next) || STRINGP (next)))
        error ("Function %s returns invalid key sequence",
               SSDATA (SYMBOL_NAME (tem)));
     }
@@ -8852,8 +8770,9 @@ keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey,
 static bool
 test_undefined (Lisp_Object binding)
 {
-  return (EQ (binding, Qundefined)
-         || (!NILP (binding) && SYMBOLP (binding)
+  return (NILP (binding)
+         || EQ (binding, Qundefined)
+         || (SYMBOLP (binding)
              && EQ (Fcommand_remapping (binding, Qnil, Qnil), Qundefined)));
 }
 
@@ -8899,7 +8818,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)
 {
-  Lisp_Object from_string;
   ptrdiff_t count = SPECPDL_INDEX ();
 
   /* How many keys there are in the current key sequence.  */
@@ -8910,34 +8828,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   ptrdiff_t echo_start IF_LINT (= 0);
   ptrdiff_t keys_start;
 
-  /* The number of keymaps we're scanning right now, and the number of
-     keymaps we have allocated space for.  */
-  ptrdiff_t nmaps;
-  ptrdiff_t nmaps_allocated = 0;
-
-  /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in
-     the current keymaps.  */
-  Lisp_Object *defs = NULL;
-
-  /* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1]
-     in the current keymaps, or nil where it is not a prefix.  */
-  Lisp_Object *submaps = NULL;
-
-  /* The local map to start out with at start of key sequence.  */
-  Lisp_Object orig_local_map;
+  Lisp_Object current_binding = Qnil;
+  Lisp_Object first_event = Qnil;
 
-  /* The map from the `keymap' property to start out with at start of
-     key sequence.  */
-  Lisp_Object orig_keymap;
-
-  /* Positive if we have already considered switching to the local-map property
-     of the place where a mouse click occurred.  */
-  int localized_local_map = 0;
-
-  /* The index in submaps[] of the first keymap that has a binding for
-     this key sequence.  In other words, the lowest i such that
-     submaps[i] is non-nil.  */
-  ptrdiff_t first_binding;
   /* Index of the first key that has no binding.
      It is useless to try fkey.start larger than that.  */
   int first_unbound;
@@ -8980,11 +8873,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
      While we're reading, we keep the event here.  */
   Lisp_Object delayed_switch_frame;
 
-  /* See the comment below...  */
-#if defined (GOBBLE_FIRST_EVENT)
-  Lisp_Object first_event;
-#endif
-
   Lisp_Object original_uppercase IF_LINT (= Qnil);
   int original_uppercase_position = -1;
 
@@ -8996,10 +8884,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   /* List of events for which a fake prefix key has been generated.  */
   Lisp_Object fake_prefixed_keys = Qnil;
 
-#if defined (GOBBLE_FIRST_EVENT)
-  int junk;
-#endif
-
   struct gcpro gcpro1;
 
   GCPRO1 (fake_prefixed_keys);
@@ -9035,21 +8919,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   keys_start = this_command_key_count;
   this_single_command_key_start = keys_start;
 
-#if defined (GOBBLE_FIRST_EVENT)
-  /* This doesn't quite work, because some of the things that read_char
-     does cannot safely be bypassed.  It seems too risky to try to make
-     this work right.  */
-
-  /* Read the first char of the sequence specially, before setting
-     up any keymaps, in case a filter runs and switches buffers on us.  */
-  first_event = read_char (NILP (prompt), 0, submaps, last_nonmenu_event,
-                          &junk, NULL);
-#endif /* GOBBLE_FIRST_EVENT */
-
-  orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
-  orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
-  from_string = Qnil;
-
   /* We jump here when we need to reinitialize fkey and keytran; this
      happens if we switch keyboards between rescans.  */
  replay_entire_sequence:
@@ -9074,59 +8943,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
      keybuf with its symbol, or if the sequence starts with a mouse
      click and we need to switch buffers, we jump back here to rebuild
      the initial keymaps from the current buffer.  */
-  nmaps = 0;
-
-  if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
-    {
-      if (2 > nmaps_allocated)
-       {
-         submaps = alloca (2 * sizeof *submaps);
-         defs    = alloca (2 * sizeof *defs);
-         nmaps_allocated = 2;
-       }
-      submaps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
-    }
-  else if (!NILP (Voverriding_local_map))
-    {
-      if (2 > nmaps_allocated)
-       {
-         submaps = alloca (2 * sizeof *submaps);
-         defs    = alloca (2 * sizeof *defs);
-         nmaps_allocated = 2;
-       }
-      submaps[nmaps++] = Voverriding_local_map;
-    }
-  else
-    {
-      ptrdiff_t nminor;
-      ptrdiff_t total;
-      Lisp_Object *maps;
-
-      nminor = current_minor_maps (0, &maps);
-      total = nminor + (!NILP (orig_keymap) ? 3 : 2);
-
-      if (total > nmaps_allocated)
-       {
-         submaps = alloca (total * sizeof *submaps);
-         defs    = alloca (total * sizeof *defs);
-         nmaps_allocated = total;
-       }
-
-      if (!NILP (orig_keymap))
-       submaps[nmaps++] = orig_keymap;
-
-      memcpy (submaps + nmaps, maps, nminor * sizeof (submaps[0]));
-
-      nmaps += nminor;
-
-      submaps[nmaps++] = orig_local_map;
-    }
-  submaps[nmaps++] = current_global_map;
-
-  /* Find an accurate initial value for first_binding.  */
-  for (first_binding = 0; first_binding < nmaps; first_binding++)
-    if (! NILP (submaps[first_binding]))
-      break;
+  current_binding = active_maps (first_event);
 
   /* Start from the beginning in keybuf.  */
   t = 0;
@@ -9140,9 +8957,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   /* If the best binding for the current key sequence is a keymap, or
      we may be looking at a function key's escape sequence, keep on
      reading.  */
-  while (first_binding < nmaps
+  while (!NILP (current_binding)
         /* Keep reading as long as there's a prefix binding.  */
-        ? !NILP (submaps[first_binding])
+        ? KEYMAPP (current_binding)
         /* Don't return in the middle of a possible function key sequence,
            if the only bindings we found were via case conversion.
            Thus, if ESC O a has a function-key-map translation
@@ -9166,7 +8983,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
         just one key.  */
       ptrdiff_t echo_local_start IF_LINT (= 0);
       int keys_local_start;
-      ptrdiff_t local_first_binding;
+      Lisp_Object new_binding;
 
       eassert (indec.end == t || (indec.end > t && indec.end <= mock_input));
       eassert (indec.start <= indec.end);
@@ -9203,7 +9020,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
       if (INTERACTIVE)
        echo_local_start = echo_length ();
       keys_local_start = this_command_key_count;
-      local_first_binding = first_binding;
 
     replay_key:
       /* These are no-ops, unless we throw away a keystroke below and
@@ -9213,7 +9029,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
       if (INTERACTIVE && t < mock_input)
        echo_truncate (echo_local_start);
       this_command_key_count = keys_local_start;
-      first_binding = local_first_binding;
 
       /* By default, assume each event is "real".  */
       last_real_key_start = t;
@@ -9238,9 +9053,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          {
            KBOARD *interrupted_kboard = current_kboard;
            struct frame *interrupted_frame = SELECTED_FRAME ();
-           key = read_char (NILP (prompt), nmaps,
-                            (Lisp_Object *) submaps, last_nonmenu_event,
-                            &used_mouse_menu, NULL);
+           key = read_char (NILP (prompt),
+                            current_binding, last_nonmenu_event,
+                             &used_mouse_menu, NULL);
            if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
                /* When switching to a new tty (with a new keyboard),
                   read_char returns the new buffer, rather than -2
@@ -9294,8 +9109,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                              KVAR (interrupted_kboard, kbd_queue)));
                  }
                mock_input = 0;
-               orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
-               orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
                goto replay_entire_sequence;
              }
          }
@@ -9336,12 +9149,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                {
                  if (! FRAME_LIVE_P (XFRAME (selected_frame)))
                    Fkill_emacs (Qnil);
-                 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
-                   Fset_buffer (XWINDOW (selected_window)->buffer);
+                 if (XBUFFER (XWINDOW (selected_window)->contents)
+                     != current_buffer)
+                   Fset_buffer (XWINDOW (selected_window)->contents);
                }
 
-             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
-             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
@@ -9358,8 +9170,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
-             orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
-             orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
              goto replay_sequence;
            }
 
@@ -9379,6 +9189,22 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                }
            }
 
+         if (NILP (first_event))
+           {
+             first_event = key;
+             /* Even if first_event does not specify a particular
+                window/position, it's important to recompute the maps here
+                since a long time might have passed since we entered
+                read_key_sequence, and a timer (or process-filter or
+                special-event-map, ...) might have switched the current buffer
+                or the selected window from under us in the mean time.  */
+             if (fix_current_buffer
+                 && (XBUFFER (XWINDOW (selected_window)->contents)
+                     != current_buffer))
+               Fset_buffer (XWINDOW (selected_window)->contents);
+             current_binding = active_maps (first_event);
+           }
+
          GROW_RAW_KEYBUF;
          ASET (raw_keybuf, raw_keybuf_count, key);
          raw_keybuf_count++;
@@ -9400,16 +9226,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
         or when user programs play with this-command-keys.  */
       if (EVENT_HAS_PARAMETERS (key))
        {
-         Lisp_Object kind;
-         Lisp_Object string;
-
-         kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+         Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
            {
-             Lisp_Object window, posn;
-
-             window = POSN_WINDOW (EVENT_START (key));
-             posn   = POSN_POSN (EVENT_START (key));
+             Lisp_Object window = POSN_WINDOW (EVENT_START (key));
+             Lisp_Object posn = POSN_POSN (EVENT_START (key));
 
              if (CONSP (posn)
                  || (!NILP (fake_prefixed_keys)
@@ -9429,8 +9250,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                     not the current buffer.  If we're at the
                     beginning of a key sequence, switch buffers.  */
                  if (WINDOWP (window)
-                     && BUFFERP (XWINDOW (window)->buffer)
-                     && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
+                     && BUFFERP (XWINDOW (window)->contents)
+                     && XBUFFER (XWINDOW (window)->contents) != current_buffer)
                    {
                      ASET (raw_keybuf, raw_keybuf_count, key);
                      raw_keybuf_count++;
@@ -9451,59 +9272,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
                      if (! FRAME_LIVE_P (XFRAME (selected_frame)))
                        Fkill_emacs (Qnil);
-                     set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
-                     orig_local_map = get_local_map (PT, current_buffer,
-                                                     Qlocal_map);
-                     orig_keymap = get_local_map (PT, current_buffer,
-                                                  Qkeymap);
+                     set_buffer_internal (XBUFFER (XWINDOW (window)->contents));
                      goto replay_sequence;
                    }
-
-                 /* For a mouse click, get the local text-property keymap
-                    of the place clicked on, rather than point.  */
-                 if (CONSP (XCDR (key))
-                     && ! localized_local_map)
-                   {
-                     Lisp_Object map_here, start, pos;
-
-                     localized_local_map = 1;
-                     start = EVENT_START (key);
-
-                     if (CONSP (start) && POSN_INBUFFER_P (start))
-                       {
-                         pos = POSN_BUFFER_POSN (start);
-                         if (INTEGERP (pos)
-                             && XINT (pos) >= BEGV
-                             && XINT (pos) <= ZV)
-                           {
-                             map_here = get_local_map (XINT (pos),
-                                                       current_buffer,
-                                                       Qlocal_map);
-                             if (!EQ (map_here, orig_local_map))
-                               {
-                                 orig_local_map = map_here;
-                                 ++localized_local_map;
-                               }
-
-                             map_here = get_local_map (XINT (pos),
-                                                       current_buffer,
-                                                       Qkeymap);
-                             if (!EQ (map_here, orig_keymap))
-                               {
-                                 orig_keymap = map_here;
-                                 ++localized_local_map;
-                               }
-
-                             if (localized_local_map > 1)
-                               {
-                                 keybuf[t] = key;
-                                 mock_input = t + 1;
-
-                                 goto replay_sequence;
-                               }
-                           }
-                       }
-                   }
                }
 
              /* Expand mode-line and scroll-bar events into two events:
@@ -9524,63 +9295,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                     prevent proper action when the event is pushed
                     back into unread-command-events.  */
                  fake_prefixed_keys = Fcons (key, fake_prefixed_keys);
-
-                 /* If on a mode line string with a local keymap,
-                    reconsider the key sequence with that keymap.  */
-                 if (string = POSN_STRING (EVENT_START (key)),
-                     (CONSP (string) && STRINGP (XCAR (string))))
-                   {
-                     Lisp_Object pos, map, map2;
-
-                     pos = XCDR (string);
-                     string = XCAR (string);
-                      if (XINT (pos) >= 0
-                         && XINT (pos) < SCHARS (string))
-                        {
-                          map = Fget_text_property (pos, Qlocal_map, string);
-                          if (!NILP (map))
-                            orig_local_map = map;
-                          map2 = Fget_text_property (pos, Qkeymap, string);
-                          if (!NILP (map2))
-                            orig_keymap = map2;
-                          if (!NILP (map) || !NILP (map2))
-                            goto replay_sequence;
-                        }
-                   }
-
                  goto replay_key;
                }
-             else if (NILP (from_string)
-                      && (string = POSN_STRING (EVENT_START (key)),
-                          (CONSP (string) && STRINGP (XCAR (string)))))
-               {
-                 /* For a click on a string, i.e. overlay string or a
-                    string displayed via the `display' property,
-                    consider `local-map' and `keymap' properties of
-                    that string.  */
-                 Lisp_Object pos, map, map2;
-
-                 pos = XCDR (string);
-                 string = XCAR (string);
-                 if (XINT (pos) >= 0
-                     && XINT (pos) < SCHARS (string))
-                   {
-                     map = Fget_text_property (pos, Qlocal_map, string);
-                     if (!NILP (map))
-                       orig_local_map = map;
-                     map2 = Fget_text_property (pos, Qkeymap, string);
-                     if (!NILP (map2))
-                       orig_keymap = map2;
-
-                     if (!NILP (map) || !NILP (map2))
-                       {
-                         from_string = string;
-                         keybuf[t++] = key;
-                         mock_input = t;
-                         goto replay_sequence;
-                       }
-                   }
-               }
            }
          else if (CONSP (XCDR (key))
                   && CONSP (EVENT_START (key))
@@ -9596,12 +9312,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                  if (bufsize - t <= 1)
                    error ("Key sequence too long");
                  keybuf[t] = posn;
-                 keybuf[t+1] = key;
+                 keybuf[t + 1] = key;
 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
-                 POSN_SET_POSN (EVENT_START (key),
-                                Fcons (posn, Qnil));
+                 POSN_SET_POSN (EVENT_START (key), list1 (posn));
 
                  mock_input = t + 2;
                  goto replay_sequence;
@@ -9619,15 +9334,10 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
       /* We have finally decided that KEY is something we might want
         to look up.  */
-      first_binding = (follow_key (key,
-                                  nmaps   - first_binding,
-                                  submaps + first_binding,
-                                  defs    + first_binding,
-                                  submaps + first_binding)
-                      + first_binding);
+      new_binding = follow_key (current_binding, key);
 
       /* If KEY wasn't bound, we'll try some fallbacks.  */
-      if (first_binding < nmaps)
+      if (!NILP (new_binding))
        /* This is needed for the following scenario:
           event 0: a down-event that gets dropped by calling replay_key.
           event 1: some normal prefix like C-h.
@@ -9761,23 +9471,15 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
                      new_head
                        = apply_modifiers (modifiers, XCAR (breakdown));
-                     new_click
-                       = Fcons (new_head, Fcons (EVENT_START (key), Qnil));
-
-                     /* Look for a binding for this new key.  follow_key
-                        promises that it didn't munge submaps the
-                        last time we called it, since key was unbound.  */
-                     first_binding
-                       = (follow_key (new_click,
-                                      nmaps   - local_first_binding,
-                                      submaps + local_first_binding,
-                                      defs    + local_first_binding,
-                                      submaps + local_first_binding)
-                          + local_first_binding);
+                     new_click = list2 (new_head, EVENT_START (key));
+
+                     /* Look for a binding for this new key.  */
+                     new_binding = follow_key (current_binding, new_click);
 
                      /* If that click is bound, go for it.  */
-                     if (first_binding < nmaps)
+                     if (!NILP (new_binding))
                        {
+                         current_binding = new_binding;
                          key = new_click;
                          break;
                        }
@@ -9786,6 +9488,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                }
            }
        }
+      current_binding = new_binding;
 
       keybuf[t++] = key;
       /* Normally, last_nonmenu_event gets the previous key we read.
@@ -9817,9 +9520,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
            }
        }
 
-      if (first_binding < nmaps
-         && NILP (submaps[first_binding])
-         && !test_undefined (defs[first_binding])
+      if (!KEYMAPP (current_binding)
+         && !test_undefined (current_binding)
          && indec.start >= t)
        /* There is a binding and it's not a prefix.
           (and it doesn't have any input-decode-map translation pending).
@@ -9848,8 +9550,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                                     first_binding >= nmaps) we don't want
                                     to apply this function-key-mapping.  */
                                  fkey.end + 1 == t
-                                 && (first_binding >= nmaps
-                                     || test_undefined (defs[first_binding])),
+                                 && (test_undefined (current_binding)),
                                  &diff, prompt);
            UNGCPRO;
            if (done)
@@ -9892,7 +9593,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
         and cannot be part of a function key or translation,
         and is an upper case letter
         use the corresponding lower-case letter instead.  */
-      if (first_binding >= nmaps
+      if (NILP (current_binding)
          && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
          && INTEGERP (key)
          && ((CHARACTERP (make_number (XINT (key) & ~CHAR_MODIFIER_MASK))
@@ -9923,7 +9624,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
         and cannot be part of a function key or translation,
         and is a shifted function key,
         use the corresponding unshifted function key instead.  */
-      if (first_binding >= nmaps
+      if (NILP (current_binding)
          && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t)
        {
          Lisp_Object breakdown = parse_modifiers (key);
@@ -9964,9 +9665,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
        }
     }
   if (!dummyflag)
-    read_key_sequence_cmd = (first_binding < nmaps
-                            ? defs[first_binding]
-                            : Qnil);
+    read_key_sequence_cmd = current_binding;
   read_key_sequence_remapped
     /* Remap command through active keymaps.
        Do the remapping here, before the unbind_to so it uses the keymaps
@@ -9980,7 +9679,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
-  if ((dont_downcase_last || first_binding >= nmaps)
+  if ((dont_downcase_last || NILP (current_binding))
       && t > 0
       && t - 1 == original_uppercase_position)
     {
@@ -10077,7 +9776,7 @@ will read just one key sequence.  */)
 
   memset (keybuf, 0, sizeof keybuf);
   GCPRO1 (keybuf[0]);
-  gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
+  gcpro1.nvars = (sizeof keybuf / sizeof (keybuf[0]));
 
   if (NILP (continue_echo))
     {
@@ -10091,7 +9790,7 @@ will read just one key sequence.  */)
     cancel_hourglass ();
 #endif
 
-  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+  i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
                         ! NILP (can_return_switch_frame), 0);
 
@@ -10165,95 +9864,6 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
   UNGCPRO;
   return unbind_to (count, Fvector (i, keybuf));
 }
-\f
-DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
-       doc: /* Execute CMD as an editor command.
-CMD must be a symbol that satisfies the `commandp' predicate.
-Optional second arg RECORD-FLAG non-nil
-means unconditionally put this command in the variable `command-history'.
-Otherwise, that is done only if an arg is read using the minibuffer.
-The argument KEYS specifies the value to use instead of (this-command-keys)
-when reading the arguments; if it is nil, (this-command-keys) is used.
-The argument SPECIAL, if non-nil, means that this command is executing
-a special event, so ignore the prefix argument and don't clear it.  */)
-  (Lisp_Object cmd, Lisp_Object record_flag, Lisp_Object keys, Lisp_Object special)
-{
-  register Lisp_Object final;
-  register Lisp_Object tem;
-  Lisp_Object prefixarg;
-
-  debug_on_next_call = 0;
-
-  if (NILP (special))
-    {
-      prefixarg = KVAR (current_kboard, Vprefix_arg);
-      Vcurrent_prefix_arg = prefixarg;
-      kset_prefix_arg (current_kboard, Qnil);
-    }
-  else
-    prefixarg = Qnil;
-
-  if (SYMBOLP (cmd))
-    {
-      tem = Fget (cmd, Qdisabled);
-      if (!NILP (tem))
-       {
-         tem = Fsymbol_value (Qdisabled_command_function);
-         if (!NILP (tem))
-           return Frun_hooks (1, &Qdisabled_command_function);
-       }
-    }
-
-  while (1)
-    {
-      final = Findirect_function (cmd, Qnil);
-
-      if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
-       {
-         struct gcpro gcpro1, gcpro2;
-
-         GCPRO2 (cmd, prefixarg);
-         Fautoload_do_load (final, cmd, Qnil);
-         UNGCPRO;
-       }
-      else
-       break;
-    }
-
-  if (STRINGP (final) || VECTORP (final))
-    {
-      /* If requested, place the macro in the command history.  For
-        other sorts of commands, call-interactively takes care of
-        this.  */
-      if (!NILP (record_flag))
-       {
-         Vcommand_history
-           = Fcons (Fcons (Qexecute_kbd_macro,
-                           Fcons (final, Fcons (prefixarg, Qnil))),
-                    Vcommand_history);
-
-         /* Don't keep command history around forever.  */
-         if (NUMBERP (Vhistory_length) && XINT (Vhistory_length) > 0)
-           {
-             tem = Fnthcdr (Vhistory_length, Vcommand_history);
-             if (CONSP (tem))
-               XSETCDR (tem, Qnil);
-           }
-       }
-
-      return Fexecute_kbd_macro (final, prefixarg, Qnil);
-    }
-
-  if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
-    /* Don't call Fcall_interactively directly because we want to make
-       sure the backtrace has an entry for `call-interactively'.
-       For the same reason, pass `cmd' rather than `final'.  */
-      return call3 (Qcall_interactively, cmd, record_flag, keys);
-
-  return Qnil;
-}
-
-
 \f
 /* Return true if input events are pending.  */
 
@@ -10495,9 +10105,9 @@ The file will be closed when Emacs exits.  */)
   if (!NILP (file))
     {
       file = Fexpand_file_name (file, Qnil);
-      dribble = fopen (SSDATA (file), "w");
+      dribble = emacs_fopen (SSDATA (file), "w");
       if (dribble == 0)
-       report_file_error ("Opening dribble", Fcons (file, Qnil));
+       report_file_error ("Opening dribble", file);
     }
   return Qnil;
 }
@@ -10562,8 +10172,7 @@ On such systems, Emacs starts a subshell instead of suspending.  */)
   reset_all_sys_modes ();
   /* sys_suspend can get an error if it tries to fork a subshell
      and the system resources aren't available for that.  */
-  record_unwind_protect ((Lisp_Object (*) (Lisp_Object)) init_all_sys_modes,
-                        Qnil);
+  record_unwind_protect_void (init_all_sys_modes);
   stuff_buffered_input (stuffstring);
   if (cannot_suspend)
     sys_subshell ();
@@ -10934,7 +10543,7 @@ See also `current-input-mode'.  */)
   if (tty->flow_control != !NILP (flow))
     {
 #ifndef DOS_NT
-      /* this causes startup screen to be restored and messes with the mouse */
+      /* This causes startup screen to be restored and messes with the mouse.  */
       reset_sys_modes (tty);
 #endif
 
@@ -11322,6 +10931,8 @@ static const struct event_head head_table[] = {
   {&Qmouse_movement,      "mouse-movement",      &Qmouse_movement},
   {&Qscroll_bar_movement, "scroll-bar-movement", &Qmouse_movement},
   {&Qswitch_frame,        "switch-frame",        &Qswitch_frame},
+  {&Qfocus_in,            "focus-in",            &Qfocus_in},
+  {&Qfocus_out,           "focus-out",          &Qfocus_out},
   {&Qdelete_frame,        "delete-frame",        &Qdelete_frame},
   {&Qiconify_frame,       "iconify-frame",       &Qiconify_frame},
   {&Qmake_frame_visible,  "make-frame-visible",  &Qmake_frame_visible},
@@ -11374,17 +10985,13 @@ syms_of_keyboard (void)
   DEFSYM (Qlanguage_change, "language-change");
 #endif
 
-#ifdef WINDOWSNT
-  DEFSYM (Qfile_w32notify, "file-w32notify");
-#endif
-
 #ifdef HAVE_DBUS
   DEFSYM (Qdbus_event, "dbus-event");
 #endif
 
-#ifdef HAVE_INOTIFY
-  DEFSYM (Qfile_inotify, "file-inotify");
-#endif /* HAVE_INOTIFY */
+#ifdef USE_FILE_NOTIFY
+  DEFSYM (Qfile_notify, "file-notify");
+#endif /* USE_FILE_NOTIFY */
 
   DEFSYM (QCenable, ":enable");
   DEFSYM (QCvisible, ":visible");
@@ -11439,9 +11046,6 @@ syms_of_keyboard (void)
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
 
-  last_point_position_buffer = Qnil;
-  last_point_position_window = Qnil;
-
   {
     int i;
     int len = sizeof (head_table) / sizeof (head_table[0]);
@@ -11452,7 +11056,7 @@ syms_of_keyboard (void)
        *p->var = intern_c_string (p->name);
        staticpro (p->var);
        Fput (*p->var, Qevent_kind, *p->kind);
-       Fput (*p->var, Qevent_symbol_elements, Fcons (*p->var, Qnil));
+       Fput (*p->var, Qevent_symbol_elements, list1 (*p->var));
       }
   }
 
@@ -11485,8 +11089,7 @@ syms_of_keyboard (void)
   raw_keybuf = Fmake_vector (make_number (30), Qnil);
   staticpro (&raw_keybuf);
 
-  DEFSYM (Qextended_command_history, "extended-command-history");
-  Fset (Qextended_command_history, Qnil);
+  DEFSYM (Qcommand_execute, "command-execute");
 
   accent_key_syms = Qnil;
   staticpro (&accent_key_syms);
@@ -11525,7 +11128,6 @@ syms_of_keyboard (void)
   defsubr (&Srecursive_edit);
   defsubr (&Strack_mouse);
   defsubr (&Sinput_pending_p);
-  defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
   defsubr (&Sthis_command_keys_vector);
@@ -11683,10 +11285,6 @@ This variable is also the threshold for motion of the mouse
 to count as a drag.  */);
   double_click_fuzz = 3;
 
-  DEFVAR_BOOL ("inhibit-local-menu-bar-menus", inhibit_local_menu_bar_menus,
-              doc: /* Non-nil means inhibit local map menu bar menus.  */);
-  inhibit_local_menu_bar_menus = 0;
-
   DEFVAR_INT ("num-input-keys", num_input_keys,
              doc: /* Number of complete key sequences read as input so far.
 This includes key sequences read from keyboard macros.
@@ -11830,10 +11428,7 @@ tool-bar separators natively.  Otherwise it is unused (e.g. on GTK).  */);
 
   DEFVAR_KBOARD ("overriding-terminal-local-map",
                 Voverriding_terminal_local_map,
-                doc: /* Per-terminal keymap that overrides all other local keymaps.
-If this variable is non-nil, it is used as a keymap instead of the
-buffer's local map, and the minor mode keymaps and text property keymaps.
-It also replaces `overriding-local-map'.
+                doc: /* Per-terminal keymap that takes precedence over all other keymaps.
 
 This variable is intended to let commands such as `universal-argument'
 set up a different keymap for reading the next command.
@@ -11843,7 +11438,7 @@ terminal device.
 See Info node `(elisp)Multiple Terminals'.  */);
 
   DEFVAR_LISP ("overriding-local-map", Voverriding_local_map,
-              doc: /* Keymap that overrides all other local keymaps.
+              doc: /* Keymap that overrides almost all other local keymaps.
 If this variable is non-nil, it is used as a keymap--replacing the
 buffer's local map, the minor mode keymaps, and char property keymaps.  */);
   Voverriding_local_map = Qnil;
@@ -11856,7 +11451,7 @@ and the minor mode maps regardless of `overriding-local-map'.  */);
 
   DEFVAR_LISP ("special-event-map", Vspecial_event_map,
               doc: /* Keymap defining bindings for special events to execute at low level.  */);
-  Vspecial_event_map = Fcons (intern_c_string ("keymap"), Qnil);
+  Vspecial_event_map = list1 (intern_c_string ("keymap"));
 
   DEFVAR_LISP ("track-mouse", do_mouse_tracking,
               doc: /* Non-nil means generate motion events for mouse motion.  */);
@@ -11914,9 +11509,7 @@ If the binding is a function, it is called with one argument (the prompt)
 and its return value (a key sequence) is used.
 
 The events that come from bindings in `input-decode-map' are not
-themselves looked up in `input-decode-map'.
-
-This variable is keyboard-local.  */);
+themselves looked up in `input-decode-map'.  */);
 
   DEFVAR_LISP ("function-key-map", Vfunction_key_map,
                doc: /* The parent keymap of all `local-function-key-map' instances.
@@ -11928,9 +11521,8 @@ definition will take precedence.  */);
 
   DEFVAR_LISP ("key-translation-map", Vkey_translation_map,
                doc: /* Keymap of key translations that can override keymaps.
-This keymap works like `function-key-map', but comes after that,
-and its non-prefix bindings override ordinary bindings.
-Another difference is that it is global rather than keyboard-local.  */);
+This keymap works like `input-decode-map', but comes after `function-key-map'.
+Another difference is that it is global rather than terminal-local.  */);
   Vkey_translation_map = Fmake_sparse_keymap (Qnil);
 
   DEFVAR_LISP ("deferred-action-list", Vdeferred_action_list,
@@ -12142,21 +11734,23 @@ keys_of_keyboard (void)
                            "dbus-handle-event");
 #endif
 
-#ifdef HAVE_INOTIFY
-  /* Define a special event which is raised for inotify callback
+#ifdef USE_FILE_NOTIFY
+  /* Define a special event which is raised for notification callback
      functions.  */
-  initial_define_lispy_key (Vspecial_event_map, "file-inotify",
-                            "inotify-handle-event");
-#endif /* HAVE_INOTIFY */
+  initial_define_lispy_key (Vspecial_event_map, "file-notify",
+                            "file-notify-handle-event");
+#endif /* USE_FILE_NOTIFY */
 
   initial_define_lispy_key (Vspecial_event_map, "config-changed-event",
                            "ignore");
 #if defined (WINDOWSNT)
   initial_define_lispy_key (Vspecial_event_map, "language-change",
                            "ignore");
-  initial_define_lispy_key (Vspecial_event_map, "file-w32notify",
-                           "w32notify-handle-event");
 #endif
+  initial_define_lispy_key (Vspecial_event_map, "focus-in",
+                           "handle-focus-in");
+  initial_define_lispy_key (Vspecial_event_map, "focus-out",
+                           "handle-focus-out");
 }
 
 /* Mark the pointers in the kboard objects.