]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
Merge from trunk after a lot of time.
[gnu-emacs] / src / keyboard.c
index 8df0006eeb812836b59b07f42819a7ecf767a779..c90ddba81c7ae6bef16378f6f990627e96a9bb6f 100644 (file)
@@ -1,6 +1,7 @@
 /* Keyboard and mouse input; editor command loop.
 
-Copyright (C) 1985-1989, 1993-1997, 1999-2012  Free Software Foundation, Inc.
+Copyright (C) 1985-1989, 1993-1997, 1999-2013 Free Software Foundation,
+Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,9 +19,12 @@ You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
-#include <signal.h>
-#include <stdio.h>
-#include <setjmp.h>
+
+#define BLOCKINPUT_INLINE EXTERN_INLINE
+#define KEYBOARD_INLINE EXTERN_INLINE
+
+#include "sysstdio.h"
+
 #include "lisp.h"
 #include "termchar.h"
 #include "termopts.h"
@@ -30,8 +34,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "keyboard.h"
 #include "window.h"
 #include "commands.h"
-#include "buffer.h"
 #include "character.h"
+#include "buffer.h"
 #include "disptab.h"
 #include "dispextern.h"
 #include "syntax.h"
@@ -54,42 +58,28 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/ioctl.h>
 #endif /* not MSDOS */
 
+#if defined USABLE_FIONREAD && defined USG5_4
+# include <sys/filio.h>
+#endif
+
 #include "syssignal.h"
 
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
 
-/* This is to get the definitions of the XK_ symbols.  */
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#endif
-
-#ifdef HAVE_NTGUI
-#include "w32term.h"
-#endif /* HAVE_NTGUI */
-
-#ifdef HAVE_NS
-#include "nsterm.h"
-#endif
+#ifdef HAVE_WINDOW_SYSTEM
+#include TERM_HEADER
+#endif /* HAVE_WINDOW_SYSTEM */
 
 /* Variables for blockinput.h:  */
 
-/* Non-zero if interrupt input is blocked right now.  */
+/* Positive if interrupt input is blocked right now.  */
 volatile int interrupt_input_blocked;
 
-/* Nonzero means an input interrupt has arrived
-   during the current critical section.  */
-int interrupt_input_pending;
-
-/* This var should be (interrupt_input_pending || pending_atimers).
-   The QUIT macro checks this instead of interrupt_input_pending and
-   pending_atimers separately, to reduce code size.  So, any code that
-   changes interrupt_input_pending or pending_atimers should update
-   this too.  */
-#ifdef SYNC_INPUT
-int pending_signals;
-#endif
+/* True means an input interrupt or alarm signal has arrived.
+   The QUIT macro checks this.  */
+volatile bool pending_signals;
 
 #define KBD_BUFFER_SIZE 4096
 
@@ -97,8 +87,8 @@ KBOARD *initial_kboard;
 KBOARD *current_kboard;
 KBOARD *all_kboards;
 
-/* Nonzero in the single-kboard state, 0 in the any-kboard state.  */
-static int single_kboard;
+/* True in the single-kboard state, false in the any-kboard state.  */
+static bool single_kboard;
 
 /* Non-nil disable property on a command means
    do not execute it; call disabled-command-function's value instead.  */
@@ -124,9 +114,9 @@ static Lisp_Object recent_keys;
 Lisp_Object this_command_keys;
 ptrdiff_t this_command_key_count;
 
-/* 1 after calling Freset_this_command_lengths.
-   Usually it is 0.  */
-static int this_command_key_count_reset;
+/* True after calling Freset_this_command_lengths.
+   Usually it is false.  */
+static bool this_command_key_count_reset;
 
 /* This vector is used as a buffer to record the events that were actually read
    by read_key_sequence.  */
@@ -148,14 +138,14 @@ static ptrdiff_t before_command_echo_length;
 
 /* For longjmp to where kbd input is being done.  */
 
-static jmp_buf getcjmp;
+static sys_jmp_buf getcjmp;
 
 /* True while doing kbd input.  */
-int waiting_for_input;
+bool waiting_for_input;
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
 
-static int echoing;
+static bool echoing;
 
 /* Non-null means we can start echoing at the next input pause even
    though there is something in the echo area.  */
@@ -174,8 +164,8 @@ struct kboard *echo_kboard;
 
 Lisp_Object echo_message_buffer;
 
-/* Nonzero means C-g should cause immediate error-signal.  */
-int immediate_quit;
+/* True means C-g should cause immediate error-signal.  */
+bool immediate_quit;
 
 /* Character that causes a quit.  Normally C-g.
 
@@ -217,23 +207,18 @@ uintmax_t num_input_events;
 
 static EMACS_INT last_auto_save;
 
-/* This is like Vthis_command, except that commands never set it.  */
-Lisp_Object real_this_command;
-
 /* 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
    like Fselect_frame, to make sure that a switch-frame event is
-   generated by the next character.  */
+   generated by the next character.
+
+   FIXME: This is modified by a signal handler so it should be volatile.
+   It's exported to Lisp, though, so it can't simply be marked
+   'volatile' here.  */
 Lisp_Object internal_last_event_frame;
 
 /* The timestamp of the last input event we received from the X server.
@@ -280,7 +265,7 @@ static Lisp_Object Qhelp_form_show;
 static FILE *dribble;
 
 /* Nonzero if input is available.  */
-int input_pending;
+bool input_pending;
 
 /* Circular buffer for pre-read keyboard input.  */
 
@@ -310,20 +295,19 @@ 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;
 static Lisp_Object Qselect_window;
 Lisp_Object Qhelp_echo;
 
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
 static Lisp_Object Qmouse_fixup_help_message;
-#endif
 
 /* Symbols to denote kinds of events.  */
 static Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-#if defined (WINDOWSNT)
+#ifdef HAVE_NTGUI
 Lisp_Object Qlanguage_change;
 #endif
 static Lisp_Object Qdrag_n_drop;
@@ -331,6 +315,9 @@ static Lisp_Object Qsave_session;
 #ifdef HAVE_DBUS
 static Lisp_Object Qdbus_event;
 #endif
+#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 */
@@ -370,58 +357,44 @@ 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;
-EMACS_TIME timer_check (void);
+static Lisp_Object Qcommand_execute;
+struct timespec timer_check (void);
 
-static void record_menu_key (Lisp_Object c);
 static void echo_now (void);
 static ptrdiff_t echo_length (void);
 
 static Lisp_Object Qpolling_period;
 
 /* Incremented whenever a timer is run.  */
-int timers_run;
+unsigned timers_run;
 
-/* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
+/* Address (if not 0) of struct timespec to zero out if a SIGIO interrupt
    happens.  */
-EMACS_TIME *input_available_clear_time;
+struct timespec *input_available_clear_time;
 
-/* Nonzero means use SIGIO interrupts; zero means use CBREAK mode.
-   Default is 1 if INTERRUPT_INPUT is defined.  */
-int interrupt_input;
+/* True means use SIGIO interrupts; false means use CBREAK mode.
+   Default is true if INTERRUPT_INPUT is defined.  */
+bool interrupt_input;
 
 /* Nonzero while interrupts are temporarily deferred during redisplay.  */
-int interrupts_deferred;
-
-/* Allow m- file to inhibit use of FIONREAD.  */
-#ifdef BROKEN_FIONREAD
-#undef FIONREAD
-#endif
-
-/* We are unable to use interrupts if FIONREAD is not available,
-   so flush SIGIO so we won't try.  */
-#if !defined (FIONREAD)
-#ifdef SIGIO
-#undef SIGIO
-#endif
-#endif
+bool interrupts_deferred;
 
 /* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (USE_ASYNC_EVENTS)
+#ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
 
 /* The time when Emacs started being idle.  */
 
-static EMACS_TIME timer_idleness_start_time;
+static struct timespec timer_idleness_start_time;
 
 /* After Emacs stops being idle, this saves the last value
    of timer_idleness_start_time from when it was idle.  */
 
-static EMACS_TIME timer_last_idleness_start_time;
+static struct timespec timer_last_idleness_start_time;
 
 \f
 /* Global variable declarations.  */
@@ -434,137 +407,188 @@ static EMACS_TIME timer_last_idleness_start_time;
 /* Function for init_keyboard to call with no args (if nonzero).  */
 static void (*keyboard_init_hook) (void);
 
-static int read_avail_input (int);
-static void get_input_pending (int *, int);
-static int readable_events (int);
-static Lisp_Object read_char_x_menu_prompt (ptrdiff_t, Lisp_Object *,
-                                            Lisp_Object, int *);
-static Lisp_Object read_char_minibuf_menu_prompt (int, ptrdiff_t,
-                                                  Lisp_Object *);
+static bool get_input_pending (int);
+static bool readable_events (int);
+static Lisp_Object read_char_x_menu_prompt (Lisp_Object,
+                                            Lisp_Object, bool *);
+static Lisp_Object read_char_minibuf_menu_prompt (int, Lisp_Object);
 static Lisp_Object make_lispy_event (struct input_event *);
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
 static Lisp_Object make_lispy_movement (struct frame *, Lisp_Object,
                                         enum scroll_bar_part,
                                         Lisp_Object, Lisp_Object,
                                        Time);
-#endif
 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 int help_char_p (Lisp_Object);
-static void save_getcjmp (jmp_buf);
-static void restore_getcjmp (jmp_buf);
+static Lisp_Object make_lispy_focus_in (Lisp_Object);
+#ifdef HAVE_WINDOW_SYSTEM
+static Lisp_Object make_lispy_focus_out (Lisp_Object);
+#endif /* HAVE_WINDOW_SYSTEM */
+static bool help_char_p (Lisp_Object);
+static void save_getcjmp (sys_jmp_buf);
+static void restore_getcjmp (sys_jmp_buf);
 static Lisp_Object apply_modifiers (int, Lisp_Object);
 static void clear_event (struct input_event *);
-static Lisp_Object restore_kboard_configuration (Lisp_Object);
-static void interrupt_signal (int signalnum);
-#ifdef SIGIO
-static void input_available_signal (int signo);
+static void restore_kboard_configuration (int);
+#ifdef USABLE_SIGIO
+static void deliver_input_available_signal (int signo);
 #endif
-static Lisp_Object (Fcommand_execute) (Lisp_Object, Lisp_Object, Lisp_Object,
-                                      Lisp_Object);
-static void handle_interrupt (void);
-static void quit_throw_to_read_char (int) NO_RETURN;
+static void handle_interrupt (bool);
+static _Noreturn void quit_throw_to_read_char (bool);
 static void process_special_events (void);
 static void timer_start_idle (void);
 static void timer_stop_idle (void);
 static void timer_resume_idle (void);
-static void handle_user_signal (int);
+static void deliver_user_signal (int);
 static char *find_user_signal_name (int);
-static int store_user_signal_events (void);
+static void store_user_signal_events (void);
+
+/* These setters are used only in this file, so they can be private.  */
+static void
+kset_echo_string (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (echo_string) = val;
+}
+static void
+kset_kbd_queue (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (kbd_queue) = val;
+}
+static void
+kset_keyboard_translate_table (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Vkeyboard_translate_table) = val;
+}
+static void
+kset_last_prefix_arg (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Vlast_prefix_arg) = val;
+}
+static void
+kset_last_repeatable_command (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Vlast_repeatable_command) = val;
+}
+static void
+kset_local_function_key_map (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Vlocal_function_key_map) = val;
+}
+static void
+kset_overriding_terminal_local_map (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Voverriding_terminal_local_map) = val;
+}
+static void
+kset_real_last_command (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (Vreal_last_command) = val;
+}
+static void
+kset_system_key_syms (struct kboard *kb, Lisp_Object val)
+{
+  kb->INTERNAL_FIELD (system_key_syms) = val;
+}
 
 \f
-/* Add C to the echo string, if echoing is going on.
-   C can be a character, which is printed prettily ("M-C-x" and all that
-   jazz), or a symbol, whose name is printed.  */
+/* Add C to the echo string, without echoing it immediately.  C can be
+   a character, which is pretty-printed, or a symbol, whose name is
+   printed.  */
 
 static void
-echo_char (Lisp_Object c)
+echo_add_key (Lisp_Object c)
 {
-  if (current_kboard->immediate_echo)
-    {
-      int size = KEY_DESCRIPTION_SIZE + 100;
-      char *buffer = (char *) alloca (size);
-      char *ptr = buffer;
-      Lisp_Object echo_string;
+  int size = KEY_DESCRIPTION_SIZE + 100;
+  char *buffer = alloca (size);
+  char *ptr = buffer;
+  Lisp_Object echo_string;
 
-      echo_string = KVAR (current_kboard, echo_string);
+  echo_string = KVAR (current_kboard, echo_string);
 
-      /* If someone has passed us a composite event, use its head symbol.  */
-      c = EVENT_HEAD (c);
+  /* If someone has passed us a composite event, use its head symbol.  */
+  c = EVENT_HEAD (c);
 
-      if (INTEGERP (c))
+  if (INTEGERP (c))
+    ptr = push_key_description (XINT (c), ptr);
+  else if (SYMBOLP (c))
+    {
+      Lisp_Object name = SYMBOL_NAME (c);
+      int nbytes = SBYTES (name);
+
+      if (size - (ptr - buffer) < nbytes)
        {
-         ptr = push_key_description (XINT (c), ptr, 1);
+         int offset = ptr - buffer;
+         size = max (2 * size, size + nbytes);
+         buffer = alloca (size);
+         ptr = buffer + offset;
        }
-      else if (SYMBOLP (c))
-       {
-         Lisp_Object name = SYMBOL_NAME (c);
-         int nbytes = SBYTES (name);
 
-         if (size - (ptr - buffer) < nbytes)
-           {
-             int offset = ptr - buffer;
-             size = max (2 * size, size + nbytes);
-             buffer = (char *) alloca (size);
-             ptr = buffer + offset;
-           }
+      ptr += copy_text (SDATA (name), (unsigned char *) ptr, nbytes,
+                       STRING_MULTIBYTE (name), 1);
+    }
 
-         ptr += copy_text (SDATA (name), (unsigned char *) ptr, nbytes,
-                           STRING_MULTIBYTE (name), 1);
-       }
+  if ((NILP (echo_string) || SCHARS (echo_string) == 0)
+      && help_char_p (c))
+    {
+      const char *text = " (Type ? for further options)";
+      int len = strlen (text);
 
-      if ((NILP (echo_string) || SCHARS (echo_string) == 0)
-         && help_char_p (c))
+      if (size - (ptr - buffer) < len)
        {
-         const char *text = " (Type ? for further options)";
-         int len = strlen (text);
-
-         if (size - (ptr - buffer) < len)
-           {
-             int offset = ptr - buffer;
-             size += len;
-             buffer = (char *) alloca (size);
-             ptr = buffer + offset;
-           }
-
-         memcpy (ptr, text, len);
-         ptr += len;
+         int offset = ptr - buffer;
+         size += len;
+         buffer = alloca (size);
+         ptr = buffer + offset;
        }
 
-      /* Replace a dash from echo_dash with a space, otherwise
-        add a space at the end as a separator between keys.  */
-      if (STRINGP (echo_string)
-         && SCHARS (echo_string) > 1)
-       {
-         Lisp_Object last_char, prev_char, idx;
+      memcpy (ptr, text, len);
+      ptr += len;
+    }
+
+  /* Replace a dash from echo_dash with a space, otherwise add a space
+     at the end as a separator between keys.  */
+  if (STRINGP (echo_string) && SCHARS (echo_string) > 1)
+    {
+      Lisp_Object last_char, prev_char, idx;
 
-         idx = make_number (SCHARS (echo_string) - 2);
-         prev_char = Faref (echo_string, idx);
+      idx = make_number (SCHARS (echo_string) - 2);
+      prev_char = Faref (echo_string, idx);
 
-         idx = make_number (SCHARS (echo_string) - 1);
-         last_char = Faref (echo_string, idx);
+      idx = make_number (SCHARS (echo_string) - 1);
+      last_char = Faref (echo_string, idx);
 
-         /* We test PREV_CHAR to make sure this isn't the echoing
-            of a minus-sign.  */
-         if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
-           Faset (echo_string, idx, make_number (' '));
-         else
-           echo_string = concat2 (echo_string, build_string (" "));
-       }
-      else if (STRINGP (echo_string))
+      /* We test PREV_CHAR to make sure this isn't the echoing of a
+        minus-sign.  */
+      if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
+       Faset (echo_string, idx, make_number (' '));
+      else
        echo_string = concat2 (echo_string, build_string (" "));
+    }
+  else if (STRINGP (echo_string) && SCHARS (echo_string) > 0)
+    echo_string = concat2 (echo_string, build_string (" "));
+
+  kset_echo_string
+    (current_kboard,
+     concat2 (echo_string, make_string (buffer, ptr - buffer)));
+}
 
-      KVAR (current_kboard, echo_string)
-       = concat2 (echo_string, make_string (buffer, ptr - buffer));
+/* Add C to the echo string, if echoing is going on.  C can be a
+   character or a symbol.  */
 
+static void
+echo_char (Lisp_Object c)
+{
+  if (current_kboard->immediate_echo)
+    {
+      echo_add_key (c);
       echo_now ();
     }
 }
 
 /* Temporarily add a dash to the end of the echo string if it's not
-   empty, so that it serves as a mini-prompt for the very next character.  */
+   empty, so that it serves as a mini-prompt for the very next
+   character.  */
 
 static void
 echo_dash (void)
@@ -602,8 +626,9 @@ echo_dash (void)
 
   /* Put a dash at the end of the buffer temporarily,
      but make it go away when the next character is added.  */
-  KVAR (current_kboard, echo_string) = concat2 (KVAR (current_kboard, echo_string),
-                                        build_string ("-"));
+  kset_echo_string
+    (current_kboard,
+     concat2 (KVAR (current_kboard, echo_string), build_string ("-")));
   echo_now ();
 }
 
@@ -628,7 +653,7 @@ echo_now (void)
          if (i == this_single_command_key_start)
            before_command_echo_length = echo_length ();
 
-         c = XVECTOR (this_command_keys)->contents[i];
+         c = AREF (this_command_keys, i);
          if (! (EVENT_HAS_PARAMETERS (c)
                 && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
            echo_char (c);
@@ -645,9 +670,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.  */
@@ -665,7 +689,7 @@ cancel_echoing (void)
 {
   current_kboard->immediate_echo = 0;
   current_kboard->echo_after_prompt = -1;
-  KVAR (current_kboard, echo_string) = Qnil;
+  kset_echo_string (current_kboard, Qnil);
   ok_to_echo_at_next_pause = NULL;
   echo_kboard = NULL;
   echo_message_buffer = Qnil;
@@ -689,9 +713,9 @@ static void
 echo_truncate (ptrdiff_t nchars)
 {
   if (STRINGP (KVAR (current_kboard, echo_string)))
-    KVAR (current_kboard, echo_string)
-      = Fsubstring (KVAR (current_kboard, echo_string),
-                   make_number (0), make_number (nchars));
+    kset_echo_string (current_kboard,
+                     Fsubstring (KVAR (current_kboard, echo_string),
+                                 make_number (0), make_number (nchars)));
   truncate_echo_area (nchars);
 }
 
@@ -798,14 +822,14 @@ This function is called by the editor initialization to begin editing.  */)
 
   /* If we enter while input is blocked, don't lock up here.
      This may happen through the debugger during redisplay.  */
-  if (INPUT_BLOCKED_P)
+  if (input_blocked_p ())
     return Qnil;
 
   command_loop_level++;
   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;
@@ -822,7 +846,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))
@@ -830,7 +854,6 @@ recursive_edit_unwind (Lisp_Object buffer)
 
   command_loop_level--;
   update_mode_lines = 1;
-  return Qnil;
 }
 
 \f
@@ -889,8 +912,7 @@ static struct kboard_stack *kboard_stack;
 void
 push_kboard (struct kboard *k)
 {
-  struct kboard_stack *p
-    = (struct kboard_stack *) xmalloc (sizeof (struct kboard_stack));
+  struct kboard_stack *p = xmalloc (sizeof *p);
 
   p->next = kboard_stack;
   p->kboard = current_kboard;
@@ -904,7 +926,7 @@ pop_kboard (void)
 {
   struct terminal *t;
   struct kboard_stack *p = kboard_stack;
-  int found = 0;
+  bool found = 0;
   for (t = terminal_list; t; t = t->next_terminal)
     {
       if (t->kboard == p->kboard)
@@ -928,7 +950,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
@@ -937,7 +959,7 @@ pop_kboard (void)
 void
 temporarily_switch_to_single_kboard (struct frame *f)
 {
-  int was_locked = single_kboard;
+  bool was_locked = single_kboard;
   if (was_locked)
     {
       if (f != NULL && FRAME_KBOARD (f) != current_kboard)
@@ -959,8 +981,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.  */
@@ -969,26 +990,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)
-        abort ();
+        emacs_abort ();
     }
-  return Qnil;
 }
 
 \f
@@ -1022,8 +1039,8 @@ cmd_error (Lisp_Object data)
   Vstandard_input = Qt;
   Vexecuting_kbd_macro = Qnil;
   executing_kbd_macro = Qnil;
-  KVAR (current_kboard, Vprefix_arg) = Qnil;
-  KVAR (current_kboard, Vlast_prefix_arg) = Qnil;
+  kset_prefix_arg (current_kboard, Qnil);
+  kset_last_prefix_arg (current_kboard, Qnil);
   cancel_echoing ();
 
   /* Avoid unquittable loop if data contains a circular list.  */
@@ -1036,12 +1053,7 @@ cmd_error (Lisp_Object data)
   Vprint_length = old_length;
 
   Vquit_flag = Qnil;
-
   Vinhibit_quit = Qnil;
-#if 0 /* This shouldn't be necessary anymore.  --lorentey  */
-  if (command_loop_level == 0 && minibuf_level == 0)
-    any_kboard_state ();
-#endif
 
   return make_number (0);
 }
@@ -1105,8 +1117,7 @@ cmd_error_internal (Lisp_Object data, const char *context)
 
   Vsignaling_function = Qnil;
 }
-\f
-Lisp_Object command_loop_1 (void);
+
 static Lisp_Object command_loop_2 (Lisp_Object);
 static Lisp_Object top_level_1 (Lisp_Object);
 
@@ -1128,12 +1139,6 @@ command_loop (void)
     while (1)
       {
        internal_catch (Qtop_level, top_level_1, Qnil);
-#if 0 /* This shouldn't be necessary anymore.  --lorentey  */
-        /* Reset single_kboard in case top-level set it while
-           evaluating an -f option, or we are stuck there for some
-           other reason.  */
-        any_kboard_state ();
-#endif
        internal_catch (Qtop_level, command_loop_2, Qnil);
        executing_kbd_macro = Qnil;
 
@@ -1149,7 +1154,7 @@ command_loop (void)
    value to us.  A value of nil means that command_loop_1 itself
    returned due to end of file (or end of kbd macro).  */
 
-Lisp_Object
+static Lisp_Object
 command_loop_2 (Lisp_Object ignore)
 {
   register Lisp_Object val;
@@ -1167,16 +1172,16 @@ top_level_2 (void)
   return Feval (Vtop_level, Qnil);
 }
 
-Lisp_Object
+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;
 }
 
@@ -1192,19 +1197,18 @@ This also exits all active minibuffers.  */)
 
   /* Unblock input if we enter with input blocked.  This may happen if
      redisplay traps e.g. during tool-bar update with input blocked.  */
-  while (INPUT_BLOCKED_P)
-    UNBLOCK_INPUT;
+  totally_unblock_input ();
 
   Fthrow (Qtop_level, Qnil);
 }
 
-static void user_error (const char*) NO_RETURN;
-static void user_error (const char *msg)
+static _Noreturn void
+user_error (const char *msg)
 {
   xsignal1 (Quser_error, build_string (msg));
 }
 
-static Lisp_Object Fexit_recursive_edit (void) NO_RETURN;
+_Noreturn
 DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
        doc: /* Exit from the innermost recursive edit or minibuffer.  */)
   (void)
@@ -1215,7 +1219,7 @@ DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0,
   user_error ("No recursive edit is in progress");
 }
 
-static Lisp_Object Fabort_recursive_edit (void) NO_RETURN;
+_Noreturn
 DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
        doc: /* Abort the command that requested this recursive edit or minibuffer input.  */)
   (void)
@@ -1226,12 +1230,10 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
   user_error ("No recursive edit is in progress");
 }
 \f
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
-
 /* 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;
@@ -1245,11 +1247,9 @@ tracking_off (Lisp_Object old_value)
       if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
        {
          redisplay_preserve_echo_area (6);
-         get_input_pending (&input_pending,
-                            READABLE_EVENTS_DO_TIMERS_NOW);
+         get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
        }
     }
-  return Qnil;
 }
 
 DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
@@ -1281,9 +1281,9 @@ usage: (track-mouse BODY...)  */)
 #if !defined HAVE_WINDOW_SYSTEM || defined USE_GTK || defined HAVE_NS
 static
 #endif
-int ignore_mouse_drag_p;
+bool ignore_mouse_drag_p;
 
-static FRAME_PTR
+static struct frame *
 some_mouse_moved (void)
 {
   Lisp_Object tail, frame;
@@ -1303,31 +1303,21 @@ some_mouse_moved (void)
   return 0;
 }
 
-#endif /* HAVE_MOUSE || HAVE_GPM */
 \f
 /* This is the actual command reading loop,
    sans error-handling encapsulation.  */
 
 static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
-                              int, int, int);
+                              bool, bool, bool);
 void safe_run_hooks (Lisp_Object);
-static void adjust_point_for_property (ptrdiff_t, int);
+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;
 
 /* FIXME: This is wrong rather than test window-system, we should call
    a new set-selection, which will then dispatch to x-set-selection, or
    tty-set-selection, or w32-set-selection, ...  */
-EXFUN (Fwindow_system, 1);
 
 Lisp_Object
 command_loop_1 (void)
@@ -1337,13 +1327,10 @@ command_loop_1 (void)
   int i;
   EMACS_INT prev_modiff = 0;
   struct buffer *prev_buffer = NULL;
-#if 0 /* This shouldn't be necessary anymore.  --lorentey  */
-  int was_locked = single_kboard;
-#endif
-  int already_adjusted = 0;
+  bool already_adjusted = 0;
 
-  KVAR (current_kboard, Vprefix_arg) = Qnil;
-  KVAR (current_kboard, Vlast_prefix_arg) = Qnil;
+  kset_prefix_arg (current_kboard, Qnil);
+  kset_last_prefix_arg (current_kboard, Qnil);
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
   cancel_echoing ();
@@ -1375,10 +1362,10 @@ command_loop_1 (void)
     }
 
   /* Do this after running Vpost_command_hook, for consistency.  */
-  KVAR (current_kboard, Vlast_command) = Vthis_command;
-  KVAR (current_kboard, Vreal_last_command) = real_this_command;
+  kset_last_command (current_kboard, Vthis_command);
+  kset_real_last_command (current_kboard, Vreal_this_command);
   if (!CONSP (last_command_event))
-    KVAR (current_kboard, Vlast_repeatable_command) = real_this_command;
+    kset_last_repeatable_command (current_kboard, Vreal_this_command);
 
   while (1)
     {
@@ -1386,8 +1373,7 @@ command_loop_1 (void)
        Fkill_emacs (Qnil);
 
       /* Make sure the current window's buffer is selected.  */
-      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
-       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.  */
@@ -1397,6 +1383,12 @@ command_loop_1 (void)
 
       Vdeactivate_mark = Qnil;
 
+      /* Don't ignore mouse movements for more than a single command
+        loop.  (This flag is set in xdisp.c whenever the tool bar is
+        resized, because the resize moves text up or down, and would
+        generate false mouse drag events if we don't ignore them.)  */
+      ignore_mouse_drag_p = 0;
+
       /* If minibuffer on and echo area in use,
         wait a short time and redraw minibuffer.  */
 
@@ -1413,7 +1405,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);
@@ -1422,19 +1414,10 @@ 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));
            }
        }
 
-#if 0
-      /* Select the frame that the last event came from.  Usually,
-        switch-frame events will take care of this, but if some lisp
-        code swallows a switch-frame event, we'll fix things up here.
-        Is this a good idea?  */
-      if (FRAMEP (internal_last_event_frame)
-         && !EQ (internal_last_event_frame, selected_frame))
-       Fselect_frame (internal_last_event_frame, Qnil);
-#endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
       if (! NILP (Vlucid_menu_bar_dirty_flag)
@@ -1445,7 +1428,7 @@ command_loop_1 (void)
       before_command_echo_length = echo_length ();
 
       Vthis_command = Qnil;
-      real_this_command = Qnil;
+      Vreal_this_command = Qnil;
       Vthis_original_command = Qnil;
       Vthis_command_keys_shift_translated = Qnil;
 
@@ -1456,8 +1439,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);
-      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
-       set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+      set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents));
 
       ++num_input_keys;
 
@@ -1488,7 +1470,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;
        }
 
@@ -1508,8 +1490,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
@@ -1529,7 +1509,7 @@ command_loop_1 (void)
       /* Execute the command.  */
 
       Vthis_command = cmd;
-      real_this_command = cmd;
+      Vreal_this_command = cmd;
       safe_run_hooks (Qpre_command_hook);
 
       already_adjusted = 0;
@@ -1541,7 +1521,7 @@ command_loop_1 (void)
          keys = Fkey_description (keys, Qnil);
          bitch_at_user ();
          message_with_string ("%s is undefined", keys, 0);
-         KVAR (current_kboard, defining_kbd_macro) = Qnil;
+         kset_defining_kbd_macro (current_kboard, Qnil);
          update_mode_lines = 1;
          /* If this is a down-mouse event, don't reset prefix-arg;
             pass it to the command run by the up event.  */
@@ -1551,10 +1531,10 @@ command_loop_1 (void)
                = parse_modifiers (EVENT_HEAD (last_command_event));
              int modifiers = XINT (XCAR (XCDR (breakdown)));
              if (!(modifiers & down_modifier))
-               KVAR (current_kboard, Vprefix_arg) = Qnil;
+               kset_prefix_arg (current_kboard, Qnil);
            }
          else
-           KVAR (current_kboard, Vprefix_arg) = Qnil;
+           kset_prefix_arg (current_kboard, Qnil);
        }
       else
        {
@@ -1566,18 +1546,24 @@ 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
 
             if (NILP (KVAR (current_kboard, Vprefix_arg))) /* FIXME: Why?  --Stef  */
-              Fundo_boundary ();
-            Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
+              {
+               Lisp_Object undo = BVAR (current_buffer, undo_list);
+               Fundo_boundary ();
+               last_undo_boundary
+                 = (EQ (undo, BVAR (current_buffer, undo_list))
+                    ? Qnil : BVAR (current_buffer, undo_list));
+             }
+            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.  */
@@ -1585,7 +1571,7 @@ command_loop_1 (void)
             unbind_to (scount, Qnil);
 #endif
           }
-      KVAR (current_kboard, Vlast_prefix_arg) = Vcurrent_prefix_arg;
+      kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg);
 
       safe_run_hooks (Qpost_command_hook);
 
@@ -1613,12 +1599,13 @@ command_loop_1 (void)
         If the command didn't actually create a prefix arg,
         but is merely a frame event that is transparent to prefix args,
         then the above doesn't apply.  */
-      if (NILP (KVAR (current_kboard, Vprefix_arg)) || CONSP (last_command_event))
+      if (NILP (KVAR (current_kboard, Vprefix_arg))
+         || CONSP (last_command_event))
        {
-         KVAR (current_kboard, Vlast_command) = Vthis_command;
-         KVAR (current_kboard, Vreal_last_command) = real_this_command;
+         kset_last_command (current_kboard, Vthis_command);
+         kset_real_last_command (current_kboard, Vreal_this_command);
          if (!CONSP (last_command_event))
-           KVAR (current_kboard, Vlast_repeatable_command) = real_this_command;
+           kset_last_repeatable_command (current_kboard, Vreal_this_command);
          cancel_echoing ();
          this_command_key_count = 0;
          this_command_key_count_reset = 0;
@@ -1704,10 +1691,6 @@ command_loop_1 (void)
       if (!NILP (KVAR (current_kboard, defining_kbd_macro))
          && NILP (KVAR (current_kboard, Vprefix_arg)))
        finalize_kbd_macro_chars ();
-#if 0 /* This shouldn't be necessary anymore.  --lorentey  */
-      if (!was_locked)
-        any_kboard_state ();
-#endif
     }
 }
 
@@ -1717,7 +1700,7 @@ command_loop_1 (void)
    LAST_PT is the last position of point.  */
 
 static void
-adjust_point_for_property (ptrdiff_t last_pt, int modified)
+adjust_point_for_property (ptrdiff_t last_pt, bool modified)
 {
   ptrdiff_t beg, end;
   Lisp_Object val, overlay, tmp;
@@ -1725,7 +1708,7 @@ adjust_point_for_property (ptrdiff_t last_pt, int modified)
      suppress the point adjustment for automatic composition so that a
      user can keep inserting another character at point or keep
      deleting characters around point.  */
-  int check_composition = ! modified, check_display = 1, check_invisible = 1;
+  bool check_composition = ! modified, check_display = 1, check_invisible = 1;
   ptrdiff_t orig_pt = PT;
 
   /* FIXME: cycling is probably not necessary because these properties
@@ -1753,7 +1736,7 @@ adjust_point_for_property (ptrdiff_t last_pt, int modified)
          && (beg < PT /* && end > PT   <- It's always the case.  */
              || (beg <= PT && STRINGP (val) && SCHARS (val) == 0)))
        {
-         xassert (end > PT);
+         eassert (end > PT);
          SET_PT (PT < last_pt
                  ? (STRINGP (val) && SCHARS (val) == 0
                     ? max (beg - 1, BEGV)
@@ -1764,7 +1747,8 @@ adjust_point_for_property (ptrdiff_t last_pt, int modified)
       check_display = 0;
       if (check_invisible && PT > BEGV && PT < ZV)
        {
-         int inv, ellipsis = 0;
+         int inv;
+         bool ellipsis = 0;
          beg = end = PT;
 
          /* Find boundaries `beg' and `end' of the invisible area, if any.  */
@@ -1835,7 +1819,7 @@ adjust_point_for_property (ptrdiff_t last_pt, int modified)
 #if 0 /* This assertion isn't correct, because SET_PT may end up setting
         the point to something other than its argument, due to
         point-motion hooks, intangibility, etc.  */
-         xassert (PT == beg || PT == end);
+         eassert (PT == beg || PT == end);
 #endif
 
          /* Pretend the area doesn't exist if the buffer is not
@@ -1885,7 +1869,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;
@@ -1893,7 +1877,7 @@ safe_run_hooks_error (Lisp_Object error_data)
   if (SYMBOLP (hook))
     {
       Lisp_Object val;
-      int found = 0;
+      bool found = 0;
       Lisp_Object newval = Qnil;
       for (val = find_symbol_value (hook); CONSP (val); val = XCDR (val))
        if (EQ (fun, XCAR (val)))
@@ -1954,12 +1938,12 @@ safe_run_hooks (Lisp_Object hook)
 
 int poll_suppress_count;
 
-/* Asynchronous timer for polling.  */
 
-static struct atimer *poll_timer;
+#ifdef POLL_FOR_INPUT
 
+/* Asynchronous timer for polling.  */
 
-#ifdef POLL_FOR_INPUT
+static struct atimer *poll_timer;
 
 /* Poll for input, so that we catch a C-g if it comes in.  This
    function is called from x_make_frame_visible, see comment
@@ -1968,17 +1952,9 @@ static struct atimer *poll_timer;
 void
 poll_for_input_1 (void)
 {
-/* Tell ns_read_socket() it is being called asynchronously so it can avoid
-   doing anything dangerous.  */
-#ifdef HAVE_NS
-  ++handling_signal;
-#endif
-  if (interrupt_input_blocked == 0
+  if (! input_blocked_p ()
       && !waiting_for_input)
-    read_avail_input (0);
-#ifdef HAVE_NS
-  --handling_signal;
-#endif
+    gobble_input ();
 }
 
 /* Timer callback function for poll_timer.  TIMER is equal to
@@ -1988,14 +1964,7 @@ static void
 poll_for_input (struct atimer *timer)
 {
   if (poll_suppress_count == 0)
-    {
-#ifdef SYNC_INPUT
-      interrupt_input_pending = 1;
-      pending_signals = 1;
-#else
-      poll_for_input_1 ();
-#endif
-    }
+    pending_signals = 1;
 }
 
 #endif /* POLL_FOR_INPUT */
@@ -2019,14 +1988,14 @@ start_polling (void)
       /* If poll timer doesn't exist, are we need one with
         a different interval, start a new one.  */
       if (poll_timer == NULL
-         || EMACS_SECS (poll_timer->interval) != polling_period)
+         || poll_timer->interval.tv_sec != polling_period)
        {
-         EMACS_TIME interval;
+         time_t period = max (1, min (polling_period, TYPE_MAXIMUM (time_t)));
+         struct timespec interval = make_timespec (period, 0);
 
          if (poll_timer)
            cancel_atimer (poll_timer);
 
-         EMACS_SET_SECS_USECS (interval, polling_period, 0);
          poll_timer = start_atimer (ATIMER_CONTINUOUS, interval,
                                     poll_for_input, NULL);
        }
@@ -2038,9 +2007,9 @@ start_polling (void)
 #endif
 }
 
-/* Nonzero if we are using polling to handle input asynchronously.  */
+/* True if we are using polling to handle input asynchronously.  */
 
-int
+bool
 input_polling_used (void)
 {
 #ifdef POLL_FOR_INPUT
@@ -2094,7 +2063,7 @@ void
 bind_polling_period (int n)
 {
 #ifdef POLL_FOR_INPUT
-  int new = polling_period;
+  EMACS_INT new = polling_period;
 
   if (n > new)
     new = n;
@@ -2181,14 +2150,7 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
   if (!NILP (help) && !STRINGP (help))
     {
       if (FUNCTIONP (help))
-       {
-         Lisp_Object args[4];
-         args[0] = help;
-         args[1] = window;
-         args[2] = object;
-         args[3] = pos;
-         help = safe_call (4, args);
-       }
+       help = safe_call (4, help, window, object, pos);
       else
        help = safe_eval (help);
 
@@ -2196,7 +2158,6 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
        return;
     }
 
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   if (!noninteractive && STRINGP (help))
     {
       /* The mouse-fixup-help-message Lisp function can call
@@ -2204,12 +2165,11 @@ 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;
     }
-#endif
 
   if (STRINGP (help) || NILP (help))
     {
@@ -2223,19 +2183,18 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
 \f
 /* Input of single characters from keyboard */
 
-static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, int *used_mouse_menu,
-                                        struct timeval *end_time);
+static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu,
+                                        struct timespec *end_time);
 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                                   \
@@ -2246,14 +2205,166 @@ 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 (struct timespec *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 && timespec_cmp (*end_time, current_timespec ()) <= 0)
+    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 (struct timespec *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.
    -2 means do neither.
    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).
@@ -2261,35 +2372,34 @@ do { if (polling_stopped_here) start_polling ();        \
    not to run input methods, but in other respects to act as if
    not reading a key sequence.
 
-   If USED_MOUSE_MENU is non-null, then we set *USED_MOUSE_MENU to 1
-   if we used a mouse menu to read the input, or zero otherwise.  If
-   USED_MOUSE_MENU is null, we don't dereference it.
+   If USED_MOUSE_MENU is non-null, then set *USED_MOUSE_MENU to true
+   if we used a mouse menu to read the input, or false otherwise.  If
+   USED_MOUSE_MENU is null, don't dereference it.
 
    Value is -2 when we find input on another keyboard.  A second call
    to read_char will read it.
 
-   If END_TIME is non-null, it is a pointer to an EMACS_TIME
+   If END_TIME is non-null, it is a pointer to a struct timespec
    specifying the maximum time to wait until.  If no input arrives by
    that time, stop waiting and return nil.
 
    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,
-          int *used_mouse_menu, struct timeval *end_time)
+          bool *used_mouse_menu, struct timespec *end_time)
 {
-  volatile Lisp_Object c;
+  Lisp_Object c;
   ptrdiff_t jmpcount;
-  jmp_buf local_getcjmp;
-  jmp_buf save_jump;
-  volatile int key_already_recorded = 0;
+  sys_jmp_buf local_getcjmp;
+  sys_jmp_buf save_jump;
   Lisp_Object tem, save;
   volatile Lisp_Object previous_echo_area_message;
   volatile Lisp_Object also_record;
-  volatile int reread;
+  volatile bool reread;
   struct gcpro gcpro1, gcpro2;
-  int volatile polling_stopped_here = 0;
+  bool volatile polling_stopped_here = 0;
   struct kboard *orig_kboard = current_kboard;
 
   also_record = Qnil;
@@ -2323,18 +2433,9 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       goto reread_first;
     }
 
-  if (unread_command_char != -1)
-    {
-      XSETINT (c, unread_command_char);
-      unread_command_char = -1;
-
-      reread = 1;
-      goto reread_first;
-    }
-
   if (CONSP (Vunread_command_events))
     {
-      int was_disabled = 0;
+      bool was_disabled = 0;
 
       c = XCAR (Vunread_command_events);
       Vunread_command_events = XCDR (Vunread_command_events);
@@ -2433,16 +2534,16 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       goto reread_first;
     }
 
-  /* if redisplay was requested */
+  /* If redisplay was requested.  */
   if (commandflag >= 0)
     {
-      int echo_current = EQ (echo_message_buffer, echo_area_buffer[0]);
+      bool echo_current = EQ (echo_message_buffer, echo_area_buffer[0]);
 
        /* If there is pending input, process any events which are not
           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)
@@ -2512,23 +2613,19 @@ 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)
-      && unread_command_char < 0
       && !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 */
 
       if (! NILP (c))
-       {
-         key_already_recorded = 1;
-         goto non_reread_1;
-       }
+       goto exit;
     }
 
   /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
@@ -2538,7 +2635,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
      it *must not* be in effect when we call redisplay.  */
 
   jmpcount = SPECPDL_INDEX ();
-  if (_setjmp (local_getcjmp))
+  if (sys_setjmp (local_getcjmp))
     {
       /* Handle quits while reading the keyboard.  */
       /* We must have saved the outer value of getcjmp here,
@@ -2560,18 +2657,18 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
            Lisp_Object last = KVAR (kb, kbd_queue);
            /* We shouldn't get here if we were in single-kboard mode!  */
            if (single_kboard)
-             abort ();
+             emacs_abort ();
            if (CONSP (last))
              {
                while (CONSP (XCDR (last)))
                  last = XCDR (last);
                if (!NILP (XCDR (last)))
-                 abort ();
+                 emacs_abort ();
              }
            if (!CONSP (last))
-             KVAR (kb, kbd_queue) = 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
@@ -2646,16 +2743,15 @@ 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)
       && !EQ (XCAR (prev_event), Qtool_bar)
       /* Don't bring up a menu if we already have another event.  */
-      && NILP (Vunread_command_events)
-      && unread_command_char < 0)
+      && 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)
@@ -2690,9 +2786,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);
@@ -2702,17 +2799,13 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
              && ! CONSP (Vunread_command_events))
            {
              Fdo_auto_save (Qnil, Qnil);
-
-             /* If we have auto-saved and there is still no input
-                available, garbage collect if there has been enough
-                consing going on to make it worthwhile.  */
-             if (!detect_input_pending_run_timers (0)
-                 && consing_since_gc > gc_cons_threshold / 2)
-               Fgarbage_collect ();
-
              redisplay ();
            }
        }
+
+      /* If there is still no input available, ask for GC.  */
+      if (!detect_input_pending_run_timers (0))
+       maybe_gc ();
     }
 
   /* Notify the caller if an autosave hook, or a timer, sentinel or
@@ -2743,10 +2836,10 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       if (current_kboard->kbd_queue_has_data)
        {
          if (!CONSP (KVAR (current_kboard, kbd_queue)))
-           abort ();
+           emacs_abort ();
          c = XCAR (KVAR (current_kboard, kbd_queue));
-         KVAR (current_kboard, kbd_queue)
-           = XCDR (KVAR (current_kboard, kbd_queue));
+         kset_kbd_queue (current_kboard,
+                         XCDR (KVAR (current_kboard, kbd_queue)));
          if (NILP (KVAR (current_kboard, kbd_queue)))
            current_kboard->kbd_queue_has_data = 0;
          input_pending = readable_events (0);
@@ -2783,73 +2876,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);
-
-      if (end_time)
-       {
-         EMACS_TIME now;
-         EMACS_GET_TIME (now);
-         if (EMACS_TIME_GE (now, *end_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)))
-               abort ();
-           }
-         if (!CONSP (last))
-           KVAR (kb, kbd_queue) = 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;
+      c = read_decoded_event_from_main_queue (end_time, local_getcjmp,
+                                              prev_event, used_mouse_menu);
+      if (end_time && timespec_cmp (*end_time, current_timespec ()) <= 0)
+        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:
 
@@ -2866,12 +2906,10 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
       goto wrong_kboard;
     }
 
- non_reread_1:
-
   /* Buffer switch events are only for internal wakeups
      so don't show them to the user.
      Also, don't record a key if we already did.  */
-  if (BUFFERP (c) || key_already_recorded)
+  if (BUFFERP (c))
     goto exit;
 
   /* Process special events within read_char
@@ -2884,14 +2922,8 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
   if (!NILP (tem))
     {
       struct buffer *prev_buffer = current_buffer;
-#if 0 /* This shouldn't be necessary anymore. --lorentey  */
-      int was_locked = single_kboard;
-      ptrdiff_t count = SPECPDL_INDEX ();
-      record_single_kboard_state ();
-#endif
-
       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
@@ -2900,13 +2932,6 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
           example banishing the mouse under mouse-avoidance-mode.  */
        timer_resume_idle ();
 
-#if 0 /* This shouldn't be necessary anymore. --lorentey  */
-      /* Resume allowing input from any kboard, if that was true before.  */
-      if (!was_locked)
-       any_kboard_state ();
-      unbind_to (count, Qnil);
-#endif
-
       if (current_buffer != prev_buffer)
        {
          /* The command may have changed the keymaps.  Pretend there
@@ -2961,7 +2986,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);
@@ -3014,15 +3039,15 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
     {
       Lisp_Object keys;
       ptrdiff_t key_count;
-      int key_count_reset;
+      bool key_count_reset;
       struct gcpro gcpro1;
       ptrdiff_t count = SPECPDL_INDEX ();
 
       /* Save the echo status.  */
-      int saved_immediate_echo = current_kboard->immediate_echo;
+      bool saved_immediate_echo = current_kboard->immediate_echo;
       struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
       Lisp_Object saved_echo_string = KVAR (current_kboard, echo_string);
-      int saved_echo_after_prompt = current_kboard->echo_after_prompt;
+      ptrdiff_t saved_echo_after_prompt = current_kboard->echo_after_prompt;
 
 #if 0
       if (before_command_restore_flag)
@@ -3057,7 +3082,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);
        }
@@ -3076,7 +3101,7 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
 
       cancel_echoing ();
       ok_to_echo_at_next_pause = saved_ok_to_echo;
-      KVAR (current_kboard, echo_string) = saved_echo_string;
+      kset_echo_string (current_kboard, saved_echo_string);
       current_kboard->echo_after_prompt = saved_echo_after_prompt;
       if (saved_immediate_echo)
        echo_now ();
@@ -3150,7 +3175,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 ();
@@ -3158,19 +3183,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 ();
@@ -3178,7 +3203,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));
        }
     }
@@ -3188,6 +3213,8 @@ read_char (int commandflag, ptrdiff_t nmaps, Lisp_Object *maps,
   RETURN_UNGCPRO (c);
 }
 
+#ifdef HAVE_MENUS
+
 /* Record a key that came from a mouse menu.
    Record it for echoing, for this-command-keys, and so on.  */
 
@@ -3223,9 +3250,11 @@ record_menu_key (Lisp_Object c)
   num_input_events++;
 }
 
-/* Return 1 if should recognize C as "the help character".  */
+#endif /* HAVE_MENUS */
 
-static int
+/* Return true if should recognize C as "the help character".  */
+
+static bool
 help_char_p (Lisp_Object c)
 {
   Lisp_Object tail;
@@ -3344,7 +3373,7 @@ record_char (Lisp_Object c)
      If you, dear reader, have a better idea, you've got the source.  :-) */
   if (dribble)
     {
-      BLOCK_INPUT;
+      block_input ();
       if (INTEGERP (c))
        {
          if (XUINT (c) < 0x100)
@@ -3370,7 +3399,7 @@ record_char (Lisp_Object c)
        }
 
       fflush (dribble);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -3380,13 +3409,13 @@ record_char (Lisp_Object c)
    See read_process_output.  */
 
 static void
-save_getcjmp (jmp_buf temp)
+save_getcjmp (sys_jmp_buf temp)
 {
   memcpy (temp, getcjmp, sizeof getcjmp);
 }
 
 static void
-restore_getcjmp (jmp_buf temp)
+restore_getcjmp (sys_jmp_buf temp)
 {
   memcpy (getcjmp, temp, sizeof getcjmp);
 }
@@ -3397,7 +3426,7 @@ restore_getcjmp (jmp_buf temp)
 
 /* Return true if there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
-static int
+static bool
 readable_events (int flags)
 {
   if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
@@ -3444,11 +3473,9 @@ readable_events (int flags)
        return 1;
     }
 
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
       && !NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
-#endif
   if (single_kboard)
     {
       if (current_kboard->kbd_queue_has_data)
@@ -3470,20 +3497,20 @@ int stop_character EXTERNALLY_VISIBLE;
 static KBOARD *
 event_to_kboard (struct input_event *event)
 {
-  Lisp_Object frame;
-  frame = event->frame_or_window;
-  if (CONSP (frame))
-    frame = XCAR (frame);
-  else if (WINDOWP (frame))
-    frame = WINDOW_FRAME (XWINDOW (frame));
-
-  /* There are still some events that don't set this field.
-     For now, just ignore the problem.
-     Also ignore dead frames here.  */
-  if (!FRAMEP (frame) || !FRAME_LIVE_P (XFRAME (frame)))
-    return 0;
+  /* Not applicable for these special events.  */
+  if (event->kind == SELECTION_REQUEST_EVENT
+      || event->kind == SELECTION_CLEAR_EVENT)
+    return NULL;
   else
-    return FRAME_KBOARD (XFRAME (frame));
+    {
+      Lisp_Object obj = event->frame_or_window;
+      /* There are some events that set this field to nil or string.  */
+      if (WINDOWP (obj))
+       obj = WINDOW_FRAME (XWINDOW (obj));
+      /* Also ignore dead frames here.  */
+      return ((FRAMEP (obj) && FRAME_LIVE_P (XFRAME (obj)))
+             ? FRAME_KBOARD (XFRAME (obj)) : NULL);
+    }
 }
 
 #ifdef subprocesses
@@ -3514,17 +3541,15 @@ kbd_buffer_store_event (register struct input_event *event)
    Else, if EVENT is a quit event, store the quit event
    in HOLD_QUIT, and return (thus ignoring further events).
 
-   This is used in read_avail_input to postpone the processing
-   of the quit event until all subsequent input events have been
-   parsed (and discarded).
- */
+   This is used to postpone the processing of the quit event until all
+   subsequent input events have been parsed (and discarded).  */
 
 void
 kbd_buffer_store_event_hold (register struct input_event *event,
                             struct input_event *hold_quit)
 {
   if (event->kind == NO_EVENT)
-    abort ();
+    emacs_abort ();
 
   if (hold_quit && hold_quit->kind != NO_EVENT)
     return;
@@ -3547,9 +3572,9 @@ kbd_buffer_store_event_hold (register struct input_event *event,
 
          if (single_kboard && kb != current_kboard)
            {
-             KVAR (kb, kbd_queue)
-               = Fcons (make_lispy_switch_frame (event->frame_or_window),
-                        Fcons (make_number (c), Qnil));
+             kset_kbd_queue
+               (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++)
                {
@@ -3568,7 +3593,7 @@ kbd_buffer_store_event_hold (register struct input_event *event,
 
          if (hold_quit)
            {
-             memcpy (hold_quit, event, sizeof (*event));
+             *hold_quit = *event;
              return;
            }
 
@@ -3587,7 +3612,8 @@ kbd_buffer_store_event_hold (register struct input_event *event,
          }
 
          last_event_timestamp = event->timestamp;
-         handle_interrupt ();
+
+         handle_interrupt (0);
          return;
        }
 
@@ -3623,10 +3649,8 @@ kbd_buffer_store_event_hold (register struct input_event *event,
           /* Don't read keyboard input until we have processed kbd_buffer.
              This happens when pasting text longer than KBD_BUFFER_SIZE/2.  */
           hold_keyboard_input ();
-#ifdef SIGIO
           if (!noninteractive)
-            signal (SIGIO, SIG_IGN);
-#endif
+            ignore_sigio ();
           stop_polling ();
         }
 #endif /* subprocesses */
@@ -3645,7 +3669,6 @@ kbd_buffer_store_event_hold (register struct input_event *event,
       if (immediate_quit && NILP (Vinhibit_quit))
        {
          immediate_quit = 0;
-         sigfree ();
          QUIT;
        }
     }
@@ -3740,15 +3763,14 @@ discard_mouse_events (void)
 }
 
 
-/* Return non-zero if there are any real events waiting in the event
+/* Return true if there are any real events waiting in the event
    buffer, not counting `NO_EVENT's.
 
-   If DISCARD is non-zero, discard NO_EVENT events at the front of
-   the input queue, possibly leaving the input queue empty if there
-   are no real input events.  */
+   Discard NO_EVENT events at the front of the input queue, possibly
+   leaving the input queue empty if there are no real input events.  */
 
-int
-kbd_buffer_events_waiting (int discard)
+bool
+kbd_buffer_events_waiting (void)
 {
   struct input_event *sp;
 
@@ -3760,16 +3782,14 @@ kbd_buffer_events_waiting (int discard)
        sp = kbd_buffer;
     }
 
-  if (discard)
-    kbd_fetch_ptr = sp;
-
+  kbd_fetch_ptr = sp;
   return sp != kbd_store_ptr && sp->kind != NO_EVENT;
 }
 
 \f
 /* Clear input event EVENT.  */
 
-static inline void
+static void
 clear_event (struct input_event *event)
 {
   event->kind = NO_EVENT;
@@ -3784,21 +3804,17 @@ clear_event (struct input_event *event)
 
 static Lisp_Object
 kbd_buffer_get_event (KBOARD **kbp,
-                      int *used_mouse_menu,
-                      struct timeval *end_time)
+                      bool *used_mouse_menu,
+                      struct timespec *end_time)
 {
   Lisp_Object obj;
 
 #ifdef subprocesses
   if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE/4)
     {
-      /* Start reading input again, we have processed enough so we can
-         accept new events again.  */
+      /* Start reading input again because we have processed enough to
+         be able to accept new events again.  */
       unhold_keyboard_input ();
-#ifdef SIGIO
-      if (!noninteractive)
-        signal (SIGIO, input_available_signal);
-#endif /* SIGIO */
       start_polling ();
     }
 #endif /* subprocesses */
@@ -3827,10 +3843,8 @@ kbd_buffer_get_event (KBOARD **kbp,
 
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
       if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
-#endif
 
       /* If the quit flag is set, then read_char will return
         quit_char, so that counts as "available input."  */
@@ -3840,27 +3854,24 @@ kbd_buffer_get_event (KBOARD **kbp,
       /* One way or another, wait until input is available; then, if
         interrupt handlers have not read it, read it now.  */
 
-/* Note SIGIO has been undef'd if FIONREAD is missing.  */
-#ifdef SIGIO
-      gobble_input (0);
-#endif /* SIGIO */
+#ifdef USABLE_SIGIO
+      gobble_input ();
+#endif
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
       if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
-#endif
       if (end_time)
        {
-         EMACS_TIME duration;
-         EMACS_GET_TIME (duration);
-         if (EMACS_TIME_GE (duration, *end_time))
-           return Qnil;        /* finished waiting */
+         struct timespec now = current_timespec ();
+         if (timespec_cmp (*end_time, now) <= 0)
+           return Qnil;        /* Finished waiting.  */
          else
            {
-             EMACS_SUB_TIME (duration, *end_time, duration);
-             wait_reading_process_output (EMACS_SECS (duration),
-                                          EMACS_USECS (duration),
+             struct timespec duration = timespec_sub (*end_time, now);
+             wait_reading_process_output (min (duration.tv_sec,
+                                               WAIT_READING_MAX),
+                                          duration.tv_nsec,
                                           -1, 1, Qnil, NULL, 0);
            }
        }
@@ -3868,8 +3879,7 @@ kbd_buffer_get_event (KBOARD **kbp,
        wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
 
       if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
-       /* Pass 1 for EXPECT since we just waited to have input.  */
-       read_avail_input (1);
+       gobble_input ();
     }
 
   if (CONSP (Vunread_command_events))
@@ -3919,7 +3929,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
-         abort ();
+         emacs_abort ();
 #endif
        }
 
@@ -3927,9 +3937,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;
@@ -3941,8 +3951,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
@@ -3951,15 +3960,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
@@ -3979,18 +3986,36 @@ kbd_buffer_get_event (KBOARD **kbp,
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
-#if defined (WINDOWSNT)
+#ifdef HAVE_NTGUI
       else if (event->kind == LANGUAGE_CHANGE_EVENT)
        {
-         /* Make an event (language-change (FRAME CHARSET LCID)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
+         /* 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 USE_FILE_NOTIFY
+      else if (event->kind == FILE_NOTIFY_EVENT)
+       {
+#ifdef HAVE_W32NOTIFY
+         /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK).  */
+         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 /* 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.
@@ -4027,17 +4052,43 @@ 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)
        {
@@ -4093,7 +4144,7 @@ kbd_buffer_get_event (KBOARD **kbp,
                *used_mouse_menu = 1;
 #endif
 #ifdef HAVE_NS
-             /* certain system events are non-key events */
+             /* Certain system events are non-key events.  */
              if (used_mouse_menu
                   && event->kind == NS_NONKEY_EVENT)
                *used_mouse_menu = 1;
@@ -4105,11 +4156,10 @@ kbd_buffer_get_event (KBOARD **kbp,
            }
        }
     }
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   /* 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;
@@ -4121,7 +4171,7 @@ kbd_buffer_get_event (KBOARD **kbp,
         so x remains nil.  */
       x = Qnil;
 
-      /* XXX Can f or mouse_position_hook be NULL here? */
+      /* XXX Can f or mouse_position_hook be NULL here?  */
       if (f && FRAME_TERMINAL (f)->mouse_position_hook)
         (*FRAME_TERMINAL (f)->mouse_position_hook) (&f, 0, &bar_window,
                                                     &part, &x, &y, &t);
@@ -4150,11 +4200,10 @@ kbd_buffer_get_event (KBOARD **kbp,
       if (!NILP (x) && NILP (obj))
        obj = make_lispy_movement (f, bar_window, part, x, y, t);
     }
-#endif /* HAVE_MOUSE || HAVE GPM */
   else
     /* We were promised by the above while loop that there was
        something for us to read!  */
-    abort ();
+    emacs_abort ();
 
   input_pending = readable_events (0);
 
@@ -4223,7 +4272,7 @@ process_special_events (void)
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
-         abort ();
+         emacs_abort ();
 #endif
        }
     }
@@ -4233,14 +4282,14 @@ process_special_events (void)
    are ripe, and return, without reading any user-visible events.  */
 
 void
-swallow_events (int do_display)
+swallow_events (bool do_display)
 {
-  int old_timers_run;
+  unsigned old_timers_run;
 
   process_special_events ();
 
   old_timers_run = timers_run;
-  get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
+  get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
 
   if (timers_run != old_timers_run && do_display)
     redisplay_preserve_echo_area (7);
@@ -4252,27 +4301,15 @@ swallow_events (int do_display)
 static void
 timer_start_idle (void)
 {
-  Lisp_Object timers;
-
   /* If we are already in the idle state, do nothing.  */
-  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+  if (timespec_valid_p (timer_idleness_start_time))
     return;
 
-  EMACS_GET_TIME (timer_idleness_start_time);
-
+  timer_idleness_start_time = current_timespec ();
   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) != 8)
-       continue;
-      XVECTOR (timer)->contents[0] = Qnil;
-    }
+  call0 (intern ("internal-timer-start-idle"));
 }
 
 /* Record that Emacs is no longer idle, so stop running idle-time timers.  */
@@ -4280,7 +4317,7 @@ timer_start_idle (void)
 static void
 timer_stop_idle (void)
 {
-  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+  timer_idleness_start_time = invalid_timespec ();
 }
 
 /* Resume idle timer from last idle start time.  */
@@ -4288,7 +4325,7 @@ timer_stop_idle (void)
 static void
 timer_resume_idle (void)
 {
-  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+  if (timespec_valid_p (timer_idleness_start_time))
     return;
 
   timer_idleness_start_time = timer_last_idleness_start_time;
@@ -4302,6 +4339,23 @@ struct input_event last_timer_event EXTERNALLY_VISIBLE;
    ...).  Each element has the form (FUN . ARGS).  */
 Lisp_Object pending_funcalls;
 
+/* Return true if TIMER is a valid timer, placing its value into *RESULT.  */
+static bool
+decode_timer (Lisp_Object timer, struct timespec *result)
+{
+  Lisp_Object *vector;
+
+  if (! (VECTORP (timer) && ASIZE (timer) == 9))
+    return 0;
+  vector = XVECTOR (timer)->contents;
+  if (! NILP (vector[0]))
+    return 0;
+
+  return decode_time_components (vector[1], vector[2], vector[3], vector[8],
+                                result, 0);
+}
+
+
 /* Check whether a timer has fired.  To prevent larger problems we simply
    disregard elements that are not proper timers.  Do not make a circular
    timer list for the time being.
@@ -4314,27 +4368,19 @@ Lisp_Object pending_funcalls;
    In that case we return 0 to indicate that a new timer_check_2 call
    should be done.  */
 
-static EMACS_TIME
-timer_check_2 (void)
+static struct timespec
+timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
 {
-  EMACS_TIME nexttime;
-  EMACS_TIME now;
-  EMACS_TIME idleness_now IF_LINT (= {0});
-  Lisp_Object timers, idle_timers, chosen_timer;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  struct timespec nexttime;
+  struct timespec now;
+  struct timespec idleness_now;
+  Lisp_Object chosen_timer;
+  struct gcpro gcpro1;
 
-  EMACS_SET_SECS (nexttime, -1);
-  EMACS_SET_USECS (nexttime, -1);
+  nexttime = invalid_timespec ();
 
-  /* Always consider the ordinary timers.  */
-  timers = Vtimer_list;
-  /* Consider the idle timers only if Emacs is idle.  */
-  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
-    idle_timers = Vtimer_idle_list;
-  else
-    idle_timers = Qnil;
   chosen_timer = Qnil;
-  GCPRO3 (timers, idle_timers, chosen_timer);
+  GCPRO1 (chosen_timer);
 
   /* First run the code that was delayed.  */
   while (CONSP (pending_funcalls))
@@ -4346,132 +4392,98 @@ timer_check_2 (void)
 
   if (CONSP (timers) || CONSP (idle_timers))
     {
-      EMACS_GET_TIME (now);
-      if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
-       EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+      now = current_timespec ();
+      idleness_now = (timespec_valid_p (timer_idleness_start_time)
+                     ? timespec_sub (now, timer_idleness_start_time)
+                     : make_timespec (0, 0));
     }
 
   while (CONSP (timers) || CONSP (idle_timers))
     {
-      Lisp_Object *vector;
       Lisp_Object timer = Qnil, idle_timer = Qnil;
-      EMACS_TIME timer_time, idle_timer_time;
-      EMACS_TIME difference;
-      EMACS_TIME timer_difference IF_LINT (= {0});
-      EMACS_TIME idle_timer_difference IF_LINT (= {0});
+      struct timespec timer_time, idle_timer_time;
+      struct timespec difference;
+      struct timespec timer_difference = invalid_timespec ();
+      struct timespec idle_timer_difference = invalid_timespec ();
+      bool ripe, timer_ripe = 0, idle_timer_ripe = 0;
 
-      /* Skip past invalid timers and timers already handled.  */
+      /* Set TIMER and TIMER_DIFFERENCE
+        based on the next ordinary timer.
+        TIMER_DIFFERENCE is the distance in time from NOW to when
+        this timer becomes ripe (negative if it's already ripe).
+         Skip past invalid timers and timers already handled.  */
       if (CONSP (timers))
        {
          timer = XCAR (timers);
-         if (!VECTORP (timer) || ASIZE (timer) != 8)
+         if (! decode_timer (timer, &timer_time))
            {
              timers = XCDR (timers);
              continue;
            }
-         vector = XVECTOR (timer)->contents;
-
-         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
-             || !INTEGERP (vector[3])
-             || ! NILP (vector[0]))
-           {
-             timers = XCDR (timers);
-             continue;
-           }
-       }
-      if (CONSP (idle_timers))
-       {
-         timer = XCAR (idle_timers);
-         if (!VECTORP (timer) || ASIZE (timer) != 8)
-           {
-             idle_timers = XCDR (idle_timers);
-             continue;
-           }
-         vector = XVECTOR (timer)->contents;
 
-         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
-             || !INTEGERP (vector[3])
-             || ! NILP (vector[0]))
-           {
-             idle_timers = XCDR (idle_timers);
-             continue;
-           }
-       }
-
-      /* Set TIMER, TIMER_TIME and TIMER_DIFFERENCE
-        based on the next ordinary timer.
-        TIMER_DIFFERENCE is the distance in time from NOW to when
-        this timer becomes ripe (negative if it's already ripe).  */
-      if (CONSP (timers))
-       {
-         timer = XCAR (timers);
-         vector = XVECTOR (timer)->contents;
-         EMACS_SET_SECS (timer_time,
-                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
-         EMACS_SET_USECS (timer_time, XINT (vector[3]));
-         EMACS_SUB_TIME (timer_difference, timer_time, now);
+         timer_ripe = timespec_cmp (timer_time, now) <= 0;
+         timer_difference = (timer_ripe
+                             ? timespec_sub (now, timer_time)
+                             : timespec_sub (timer_time, now));
        }
 
-      /* Set IDLE_TIMER, IDLE_TIMER_TIME and IDLE_TIMER_DIFFERENCE
+      /* Likewise for IDLE_TIMER and IDLE_TIMER_DIFFERENCE
         based on the next idle timer.  */
       if (CONSP (idle_timers))
        {
-         idle_timer = XCAR (idle_timers);
-         vector = XVECTOR (idle_timer)->contents;
-         EMACS_SET_SECS (idle_timer_time,
-                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
-         EMACS_SET_USECS (idle_timer_time, XINT (vector[3]));
-         EMACS_SUB_TIME (idle_timer_difference, idle_timer_time, idleness_now);
-       }
-
-      /* Decide which timer is the next timer,
-        and set CHOSEN_TIMER, VECTOR and DIFFERENCE accordingly.
-        Also step down the list where we found that timer.  */
-
-      if (CONSP (timers) && CONSP (idle_timers))
-       {
-         EMACS_TIME temp;
-         EMACS_SUB_TIME (temp, timer_difference, idle_timer_difference);
-         if (EMACS_TIME_NEG_P (temp))
-           {
-             chosen_timer = timer;
-             timers = XCDR (timers);
-             difference = timer_difference;
-           }
-         else
+         idle_timer = XCAR (idle_timers);
+         if (! decode_timer (idle_timer, &idle_timer_time))
            {
-             chosen_timer = idle_timer;
              idle_timers = XCDR (idle_timers);
-             difference = idle_timer_difference;
+             continue;
            }
+
+         idle_timer_ripe = timespec_cmp (idle_timer_time, idleness_now) <= 0;
+         idle_timer_difference
+           = (idle_timer_ripe
+              ? timespec_sub (idleness_now, idle_timer_time)
+              : timespec_sub (idle_timer_time, idleness_now));
        }
-      else if (CONSP (timers))
+
+      /* Decide which timer is the next timer,
+        and set CHOSEN_TIMER, DIFFERENCE, and RIPE accordingly.
+        Also step down the list where we found that timer.  */
+
+      if (timespec_valid_p (timer_difference)
+         && (! timespec_valid_p (idle_timer_difference)
+             || idle_timer_ripe < timer_ripe
+             || (idle_timer_ripe == timer_ripe
+                 && ((timer_ripe
+                      ? timespec_cmp (idle_timer_difference,
+                                      timer_difference)
+                      : timespec_cmp (timer_difference,
+                                      idle_timer_difference))
+                     < 0))))
        {
          chosen_timer = timer;
          timers = XCDR (timers);
          difference = timer_difference;
+         ripe = timer_ripe;
        }
       else
        {
          chosen_timer = idle_timer;
          idle_timers = XCDR (idle_timers);
          difference = idle_timer_difference;
+         ripe = idle_timer_ripe;
        }
-      vector = XVECTOR (chosen_timer)->contents;
 
       /* If timer is ripe, run it if it hasn't been run.  */
-      if (EMACS_TIME_NEG_P (difference)
-         || (EMACS_SECS (difference) == 0
-             && EMACS_USECS (difference) == 0))
+      if (ripe)
        {
-         if (NILP (vector[0]))
+         if (NILP (AREF (chosen_timer, 0)))
            {
              ptrdiff_t count = SPECPDL_INDEX ();
              Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
-             vector[0] = Qt;
+             ASET (chosen_timer, 0, Qt);
 
              specbind (Qinhibit_quit, Qt);
 
@@ -4486,8 +4498,8 @@ timer_check_2 (void)
                  return 0 to indicate that.  */
            }
 
-          EMACS_SET_SECS (nexttime, 0);
-          EMACS_SET_USECS (nexttime, 0);
+         nexttime = make_timespec (0, 0);
+          break;
        }
       else
        /* When we encounter a timer that is still waiting,
@@ -4510,47 +4522,59 @@ timer_check_2 (void)
    timer list for the time being.
 
    Returns the time to wait until the next timer fires.
-   If no timer is active, return -1.
+   If no timer is active, return an invalid value.
 
    As long as any timer is ripe, we run it.  */
 
-EMACS_TIME
+struct timespec
 timer_check (void)
 {
-  EMACS_TIME nexttime;
+  struct timespec nexttime;
+  Lisp_Object timers, idle_timers;
+  struct gcpro gcpro1, gcpro2;
+
+  Lisp_Object tem = Vinhibit_quit;
+  Vinhibit_quit = Qt;
+
+  /* We use copies of the timers' lists to allow a timer to add itself
+     again, without locking up Emacs if the newly added timer is
+     already ripe when added.  */
+
+  /* Always consider the ordinary timers.  */
+  timers = Fcopy_sequence (Vtimer_list);
+  /* Consider the idle timers only if Emacs is idle.  */
+  if (timespec_valid_p (timer_idleness_start_time))
+    idle_timers = Fcopy_sequence (Vtimer_idle_list);
+  else
+    idle_timers = Qnil;
+
+  Vinhibit_quit = tem;
+
+  GCPRO2 (timers, idle_timers);
 
   do
     {
-      nexttime = timer_check_2 ();
+      nexttime = timer_check_2 (timers, idle_timers);
     }
-  while (EMACS_SECS (nexttime) == 0 && EMACS_USECS (nexttime) == 0);
+  while (nexttime.tv_sec == 0 && nexttime.tv_nsec == 0);
 
+  UNGCPRO;
   return nexttime;
 }
 
 DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0,
        doc: /* Return the current length of Emacs idleness, or nil.
-The value when Emacs is idle is a list of three integers.  The first has
-the most significant 16 bits of the seconds, while the second has the least
-significant 16 bits.  The third integer gives the microsecond count.
+The value when Emacs is idle is a list of four integers (HIGH LOW USEC PSEC)
+in the same style as (current-time).
 
 The value when Emacs is not idle is nil.
 
-The microsecond count is zero on systems that do not provide
-resolution finer than a second.  */)
+PSEC is a multiple of the system clock resolution.  */)
   (void)
 {
-  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
-    {
-      EMACS_TIME now, idleness_now;
-
-      EMACS_GET_TIME (now);
-      EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
-
-      return list3 (make_number ((EMACS_SECS (idleness_now) >> 16) & 0xffff),
-                   make_number ((EMACS_SECS (idleness_now) >> 0)  & 0xffff),
-                   make_number (EMACS_USECS (idleness_now)));
-    }
+  if (timespec_valid_p (timer_idleness_start_time))
+    return make_lisp_time (timespec_sub (current_timespec (),
+                                        timer_idleness_start_time));
 
   return Qnil;
 }
@@ -5213,8 +5237,8 @@ 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))
-           ? PT : XMARKER (w->pointm)->charpos;
+                    && current_buffer == XBUFFER (w->contents))
+           ? PT : marker_position (w->pointm);
 
          xret = wx;
          yret = wy;
@@ -5358,7 +5382,7 @@ make_lispy_event (struct input_event *event)
 {
   int i;
 
-  switch (SWITCH_ENUM_CAST (event->kind))
+  switch (event->kind)
     {
       /* A simple keystroke.  */
     case ASCII_KEYSTROKE_EVENT:
@@ -5446,7 +5470,7 @@ make_lispy_event (struct input_event *event)
          /* We need to use an alist rather than a vector as the cache
             since we can't make a vector long enough.  */
          if (NILP (KVAR (current_kboard, system_key_syms)))
-           KVAR (current_kboard, system_key_syms) = Fcons (Qnil, Qnil);
+           kset_system_key_syms (current_kboard, Fcons (Qnil, Qnil));
          return modify_event_symbol (event->code,
                                      event->modifiers,
                                      Qfunction_key,
@@ -5462,7 +5486,7 @@ make_lispy_event (struct input_event *event)
                                  (sizeof (lispy_function_keys)
                                   / sizeof (lispy_function_keys[0])));
 
-#ifdef WINDOWSNT
+#ifdef HAVE_NTGUI
     case MULTIMEDIA_KEY_EVENT:
       if (event->code < (sizeof (lispy_multimedia_keys)
                          / sizeof (lispy_multimedia_keys[0]))
@@ -5477,7 +5501,6 @@ make_lispy_event (struct input_event *event)
       return Qnil;
 #endif
 
-#ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
     case MOUSE_CLICK_EVENT:
@@ -5486,7 +5509,7 @@ make_lispy_event (struct input_event *event)
 #endif
       {
        int button = event->code;
-       int is_double;
+       bool is_double;
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
@@ -5547,14 +5570,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 */
 
@@ -5573,12 +5594,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 */
 
@@ -5590,7 +5608,7 @@ make_lispy_event (struct input_event *event)
            mouse_syms = larger_vector (mouse_syms, incr, -1);
          }
 
-       start_pos_ptr = &AREF (button_down_location, button);
+       start_pos_ptr = aref_addr (button_down_location, button);
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
@@ -5606,7 +5624,7 @@ make_lispy_event (struct input_event *event)
          else if (FRAMEP (event->frame_or_window))
            f = XFRAME (event->frame_or_window);
          else
-           abort ();
+           emacs_abort ();
 
          if (FRAME_WINDOW_P (f))
            fuzz = double_click_fuzz;
@@ -5713,7 +5731,7 @@ make_lispy_event (struct input_event *event)
        else
          /* Every mouse event should either have the down_modifier or
              the up_modifier set.  */
-         abort ();
+         emacs_abort ();
 
        {
          /* Get the symbol we should use for the mouse click.  */
@@ -5726,19 +5744,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 +5777,14 @@ make_lispy_event (struct input_event *event)
          struct frame *fr;
          int fuzz;
          int symbol_num;
-         int is_double;
+         bool is_double;
 
          if (WINDOWP (event->frame_or_window))
            fr = XFRAME (XWINDOW (event->frame_or_window)->frame);
          else if (FRAMEP (event->frame_or_window))
            fr = XFRAME (event->frame_or_window);
          else
-           abort ();
+           emacs_abort ();
 
          fuzz = FRAME_WINDOW_P (fr)
            ? double_click_fuzz : double_click_fuzz / 8;
@@ -5794,7 +5804,7 @@ make_lispy_event (struct input_event *event)
          else
            /* Every wheel event should either have the down_modifier or
               the up_modifier set.  */
-           abort ();
+           emacs_abort ();
 
           if (event->kind == HORIZ_WHEEL_EVENT)
             symbol_num += 2;
@@ -5837,14 +5847,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);
       }
 
 
@@ -5875,12 +5880,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;
@@ -5898,14 +5899,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;
 
@@ -5924,12 +5925,8 @@ 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);
       }
-#endif /* HAVE_MOUSE */
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
     || defined (HAVE_NS) || defined (USE_GTK)
@@ -5938,22 +5935,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;
@@ -5963,7 +5958,7 @@ make_lispy_event (struct input_event *event)
       {
        char *name = find_user_signal_name (event->code);
        if (!name)
-         abort ();
+         emacs_abort ();
        return intern (name);
       }
 
@@ -5977,14 +5972,20 @@ make_lispy_event (struct input_event *event)
       }
 #endif /* HAVE_DBUS */
 
+#if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY
+    case FILE_NOTIFY_EVENT:
+      {
+        return Fcons (Qfile_notify, event->arg);
+      }
+#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;
@@ -5998,7 +5999,7 @@ make_lispy_event (struct input_event *event)
            mouse_syms = larger_vector (mouse_syms, incr, -1);
          }
 
-       start_pos_ptr = &AREF (button_down_location, button);
+       start_pos_ptr = aref_addr (button_down_location, button);
        start_pos = *start_pos_ptr;
 
        position = make_lispy_position (f, event->x, event->y,
@@ -6021,37 +6022,24 @@ 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 */
 
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
-      abort ();
+      emacs_abort ();
     }
 }
 
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
-
 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?  */
@@ -6060,13 +6048,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
@@ -6077,15 +6064,29 @@ make_lispy_movement (FRAME_PTR frame, Lisp_Object bar_window, enum scroll_bar_pa
     }
 }
 
-#endif /* HAVE_MOUSE || HAVE GPM */
-
 /* Construct a switch frame event.  */
 static Lisp_Object
 make_lispy_switch_frame (Lisp_Object frame)
 {
-  return Fcons (Qswitch_frame, Fcons (frame, Qnil));
+  return list2 (Qswitch_frame, frame);
 }
-\f
+
+static Lisp_Object
+make_lispy_focus_in (Lisp_Object frame)
+{
+  return list2 (Qfocus_in, frame);
+}
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+static Lisp_Object
+make_lispy_focus_out (Lisp_Object frame)
+{
+  return list2 (Qfocus_out, frame);
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
 /* Manipulating modifiers.  */
 
 /* Parse the name of SYMBOL, and return the set of modifiers it contains.
@@ -6150,7 +6151,7 @@ parse_modifiers_uncached (Lisp_Object symbol, ptrdiff_t *modifier_end)
 
 #define MULTI_LETTER_MOD(BIT, NAME, LEN)                       \
          if (i + LEN + 1 <= SBYTES (name)                      \
-             && ! strncmp (SSDATA (name) + i, NAME, LEN))      \
+             && ! memcmp (SDATA (name) + i, NAME, LEN))        \
            {                                                   \
              this_mod_end = i + LEN;                           \
              this_mod = BIT;                                   \
@@ -6188,13 +6189,13 @@ parse_modifiers_uncached (Lisp_Object symbol, ptrdiff_t *modifier_end)
   if (! (modifiers & (down_modifier | drag_modifier
                      | double_modifier | triple_modifier))
       && i + 7 == SBYTES (name)
-      && strncmp (SSDATA (name) + i, "mouse-", 6) == 0
+      && memcmp (SDATA (name) + i, "mouse-", 6) == 0
       && ('0' <= SREF (name, i + 6) && SREF (name, i + 6) <= '9'))
     modifiers |= click_modifier;
 
   if (! (modifiers & (double_modifier | triple_modifier))
       && i + 6 < SBYTES (name)
-      && strncmp (SSDATA (name) + i, "wheel-", 6) == 0)
+      && memcmp (SDATA (name) + i, "wheel-", 6) == 0)
     modifiers |= click_modifier;
 
   if (modifier_end)
@@ -6212,8 +6213,7 @@ apply_modifiers_uncached (int modifiers, char *base, int base_len, int base_len_
   /* Since BASE could contain nulls, we can't use intern here; we have
      to use Fintern, which expects a genuine Lisp_String, and keeps a
      reference to it.  */
-  char *new_mods
-    = (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-"));
+  char new_mods[sizeof "A-C-H-M-S-s-down-drag-double-triple-"];
   int mod_len;
 
   {
@@ -6222,7 +6222,7 @@ apply_modifiers_uncached (int modifiers, char *base, int base_len, int base_len_
     /* Only the event queue may use the `up' modifier; it should always
        be turned into a click or drag event before presented to lisp code.  */
     if (modifiers & up_modifier)
-      abort ();
+      emacs_abort ();
 
     if (modifiers & alt_modifier)   { *p++ = 'A'; *p++ = '-'; }
     if (modifiers & ctrl_modifier)  { *p++ = 'C'; *p++ = '-'; }
@@ -6274,7 +6274,7 @@ lispy_modifier_list (int modifiers)
   modifier_list = Qnil;
   for (i = 0; (1<<i) <= modifiers && i < NUM_MOD_NAMES; i++)
     if (modifiers & (1<<i))
-      modifier_list = Fcons (XVECTOR (modifier_symbols)->contents[i],
+      modifier_list = Fcons (AREF (modifier_symbols, i),
                             modifier_list);
 
   return modifier_list;
@@ -6296,9 +6296,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;
 
@@ -6317,9 +6315,9 @@ parse_modifiers (Lisp_Object symbol)
                            Qnil);
 
       if (modifiers & ~INTMASK)
-       abort ();
+       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,
@@ -6392,7 +6390,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,
@@ -6505,7 +6503,7 @@ modify_event_symbol (ptrdiff_t symbol_num, int modifiers, Lisp_Object symbol_kin
          *symbol_table = Fmake_vector (size, Qnil);
        }
 
-      value = XVECTOR (*symbol_table)->contents[symbol_num];
+      value = AREF (*symbol_table, symbol_num);
     }
 
   /* Have we already used this symbol before?  */
@@ -6520,7 +6518,7 @@ modify_event_symbol (ptrdiff_t symbol_num, int modifiers, Lisp_Object symbol_kin
          ptrdiff_t len = (SBYTES (name_alist_or_stem)
                           + sizeof "-" + INT_STRLEN_BOUND (EMACS_INT));
          USE_SAFE_ALLOCA;
-         SAFE_ALLOCA (buf, char *, len);
+         buf = SAFE_ALLOCA (len);
          esprintf (buf, "%s-%"pI"d", SDATA (name_alist_or_stem),
                    XINT (symbol_int) + 1);
          value = intern (buf);
@@ -6548,7 +6546,7 @@ modify_event_symbol (ptrdiff_t symbol_num, int modifiers, Lisp_Object symbol_kin
       if (CONSP (*symbol_table))
         *symbol_table = Fcons (Fcons (symbol_int, value), *symbol_table);
       else
-       XVECTOR (*symbol_table)->contents[symbol_num] = value;
+       ASET (*symbol_table, symbol_num, value);
 
       /* Fill in the cache entries for this symbol; this also
         builds the Qevent_symbol_elements property, which the user
@@ -6625,10 +6623,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.
@@ -6647,7 +6642,7 @@ parse_solitary_modifier (Lisp_Object symbol)
 
 #define MULTI_LETTER_MOD(BIT, NAME, LEN)               \
       if (LEN == SBYTES (name)                         \
-         && ! strncmp (SSDATA (name), NAME, LEN))      \
+         && ! memcmp (SDATA (name), NAME, LEN))        \
        return BIT;
 
     case 'A':
@@ -6710,11 +6705,11 @@ parse_solitary_modifier (Lisp_Object symbol)
   return 0;
 }
 
-/* Return 1 if EVENT is a list whose elements are all integers or symbols.
+/* Return true if EVENT is a list whose elements are all integers or symbols.
    Such a list is not valid as an event,
    but it can be a Lucid-style event type list.  */
 
-int
+bool
 lucid_event_type_list_p (Lisp_Object object)
 {
   Lisp_Object tail;
@@ -6739,8 +6734,10 @@ lucid_event_type_list_p (Lisp_Object object)
   return NILP (tail);
 }
 \f
-/* Store into *addr a value nonzero if terminal input chars are available.
-   Serves the purpose of ioctl (0, FIONREAD, addr)
+/* Return true if terminal input chars are available.
+   Also, store the return value into INPUT_PENDING.
+
+   Serves the purpose of ioctl (0, FIONREAD, ...)
    but works even if FIONREAD does not exist.
    (In fact, this may actually read some input.)
 
@@ -6751,50 +6748,21 @@ lucid_event_type_list_p (Lisp_Object object)
    If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
    movements and toolkit scroll bar thumb drags.  */
 
-static void
-get_input_pending (int *addr, int flags)
+static bool
+get_input_pending (int flags)
 {
   /* First of all, have we already counted some input?  */
-  *addr = (!NILP (Vquit_flag) || readable_events (flags));
+  input_pending = (!NILP (Vquit_flag) || readable_events (flags));
 
   /* If input is being read as it arrives, and we have none, there is none.  */
-  if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
-    return;
-
-  /* Try to read some input and see how much we get.  */
-  gobble_input (0);
-  *addr = (!NILP (Vquit_flag) || readable_events (flags));
-}
-
-/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
-
-void
-gobble_input (int expected)
-{
-#ifdef SIGIO
-  if (interrupt_input)
+  if (!input_pending && (!interrupt_input || interrupts_deferred))
     {
-      SIGMASKTYPE mask;
-      mask = sigblock (sigmask (SIGIO));
-      read_avail_input (expected);
-      sigsetmask (mask);
+      /* Try to read some input and see how much we get.  */
+      gobble_input ();
+      input_pending = (!NILP (Vquit_flag) || readable_events (flags));
     }
-  else
-#ifdef POLL_FOR_INPUT
-  /* XXX This condition was (read_socket_hook && !interrupt_input),
-     but read_socket_hook is not global anymore.  Let's pretend that
-     it's always set.  */
-  if (!interrupt_input && poll_suppress_count == 0)
-    {
-      SIGMASKTYPE mask;
-      mask = sigblock (sigmask (SIGALRM));
-      read_avail_input (expected);
-      sigsetmask (mask);
-    }
-  else
-#endif
-#endif
-    read_avail_input (expected);
+
+  return input_pending;
 }
 
 /* Put a BUFFER_SWITCH_EVENT in the buffer
@@ -6803,60 +6771,50 @@ gobble_input (int expected)
 void
 record_asynch_buffer_change (void)
 {
-  struct input_event event;
-  Lisp_Object tem;
-  EVENT_INIT (event);
-
-  event.kind = BUFFER_SWITCH_EVENT;
-  event.frame_or_window = Qnil;
-  event.arg = Qnil;
-
   /* We don't need a buffer-switch event unless Emacs is waiting for input.
      The purpose of the event is to make read_key_sequence look up the
      keymaps again.  If we aren't in read_key_sequence, we don't need one,
      and the event could cause trouble by messing up (input-pending-p).
      Note: Fwaiting_for_user_input_p always returns nil when async
      subprocesses aren't supported.  */
-  tem = Fwaiting_for_user_input_p ();
-  if (NILP (tem))
-    return;
-
-  /* Make sure no interrupt happens while storing the event.  */
-#ifdef SIGIO
-  if (interrupt_input)
+  if (!NILP (Fwaiting_for_user_input_p ()))
     {
-      SIGMASKTYPE mask;
-      mask = sigblock (sigmask (SIGIO));
-      kbd_buffer_store_event (&event);
-      sigsetmask (mask);
-    }
-  else
+      struct input_event event;
+
+      EVENT_INIT (event);
+      event.kind = BUFFER_SWITCH_EVENT;
+      event.frame_or_window = Qnil;
+      event.arg = Qnil;
+
+      /* Make sure no interrupt happens while storing the event.  */
+#ifdef USABLE_SIGIO
+      if (interrupt_input)
+       kbd_buffer_store_event (&event);
+      else
 #endif
-    {
-      stop_polling ();
-      kbd_buffer_store_event (&event);
-      start_polling ();
+       {
+         stop_polling ();
+         kbd_buffer_store_event (&event);
+         start_polling ();
+       }
     }
 }
-\f
+
 /* Read any terminal input already buffered up by the system
    into the kbd_buffer, but do not wait.
 
-   EXPECTED should be nonzero if the caller knows there is some input.
-
-   Returns the number of keyboard chars read, or -1 meaning
+   Return the number of keyboard chars read, or -1 meaning
    this is a bad time to try to read input.  */
 
-static int
-read_avail_input (int expected)
+int
+gobble_input (void)
 {
   int nread = 0;
-  int err = 0;
+  bool err = 0;
   struct terminal *t;
 
   /* Store pending user signal events, if any.  */
-  if (store_user_signal_events ())
-    expected = 0;
+  store_user_signal_events ();
 
   /* Loop through the available terminals, and call their input hooks.  */
   t = terminal_list;
@@ -6869,15 +6827,18 @@ read_avail_input (int expected)
           int nr;
           struct input_event hold_quit;
 
+         if (input_blocked_p ())
+           {
+             pending_signals = 1;
+             break;
+           }
+
           EVENT_INIT (hold_quit);
           hold_quit.kind = NO_EVENT;
 
           /* No need for FIONREAD or fcntl; just say don't wait.  */
-          while (nr = (*t->read_socket_hook) (t, expected, &hold_quit), nr > 0)
-            {
-              nread += nr;
-              expected = 0;
-            }
+         while ((nr = (*t->read_socket_hook) (t, &hold_quit)) > 0)
+           nread += nr;
 
           if (nr == -1)          /* Not OK to read input now.  */
             {
@@ -6897,7 +6858,7 @@ read_avail_input (int expected)
                    this process rather than to the whole process
                    group?  Perhaps on systems with FIONREAD Emacs is
                    alone in its group.  */
-                kill (getpid (), SIGHUP);
+               terminate_due_to_signal (SIGHUP, 10);
 
               /* XXX Is calling delete_terminal safe here?  It calls delete_frame.  */
              {
@@ -6922,48 +6883,6 @@ read_avail_input (int expected)
   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,
@@ -6972,7 +6891,6 @@ decode_keyboard_code (struct tty_display_info *tty,
 
 int
 tty_read_avail_input (struct terminal *terminal,
-                      int expected,
                       struct input_event *hold_quit)
 {
   /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -6994,11 +6912,13 @@ tty_read_avail_input (struct terminal *terminal,
 
   if (terminal->type != output_termcap
       && terminal->type != output_msdos_raw)
-    abort ();
+    emacs_abort ();
 
   /* 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.  */
@@ -7046,7 +6966,7 @@ tty_read_avail_input (struct terminal *terminal,
 #endif /* HAVE_GPM */
 
 /* Determine how many characters we should *try* to read.  */
-#ifdef FIONREAD
+#ifdef USABLE_FIONREAD
   /* Find out how much input is available.  */
   if (ioctl (fileno (tty->input), FIONREAD, &n_to_read) < 0)
     {
@@ -7059,14 +6979,12 @@ tty_read_avail_input (struct terminal *terminal,
     return 0;
   if (n_to_read > sizeof cbuf)
     n_to_read = sizeof cbuf;
-#else /* no FIONREAD */
-#if defined (USG) || defined (CYGWIN)
+#elif defined USG || defined CYGWIN
   /* Read some input if available, but don't wait.  */
   n_to_read = sizeof cbuf;
-  fcntl (fileno (tty->input), F_SETFL, O_NDELAY);
+  fcntl (fileno (tty->input), F_SETFL, O_NONBLOCK);
 #else
-  you lose;
-#endif
+# error "Cannot read without possibly delaying"
 #endif
 
 #ifdef subprocesses
@@ -7081,7 +6999,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.  */
@@ -7098,14 +7016,11 @@ tty_read_avail_input (struct terminal *terminal,
     }
   while (
          /* We used to retry the read if it was interrupted.
-            But this does the wrong thing when O_NDELAY causes
+            But this does the wrong thing when O_NONBLOCK causes
             an EAGAIN error.  Does anybody know of a situation
             where a retry is actually needed?  */
 #if 0
-         nread < 0 && (errno == EAGAIN
-#ifdef EFAULT
-                       || errno == EFAULT
-#endif
+         nread < 0 && (errno == EAGAIN || errno == EFAULT
 #ifdef EBADSLT
                        || errno == EBADSLT
 #endif
@@ -7115,7 +7030,7 @@ tty_read_avail_input (struct terminal *terminal,
 #endif
          );
 
-#ifndef FIONREAD
+#ifndef USABLE_FIONREAD
 #if defined (USG) || defined (CYGWIN)
   fcntl (fileno (tty->input), F_SETFL, 0);
 #endif /* USG or CYGWIN */
@@ -7127,36 +7042,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;
@@ -7186,85 +7071,83 @@ tty_read_avail_input (struct terminal *terminal,
   return nread;
 }
 \f
-#if defined SYNC_INPUT || defined SIGIO
 static void
 handle_async_input (void)
 {
-  interrupt_input_pending = 0;
-#ifdef SYNC_INPUT
-  pending_signals = pending_atimers;
-#endif
-/* Tell ns_read_socket() it is being called asynchronously so it can avoid
-   doing anything dangerous.  */
-#ifdef HAVE_NS
-  ++handling_signal;
-#endif
+#ifdef USABLE_SIGIO
   while (1)
     {
-      int nread;
-      nread = read_avail_input (1);
+      int nread = gobble_input ();
       /* -1 means it's not ok to read the input now.
         UNBLOCK_INPUT will read it later; now, avoid infinite loop.
         0 means there was no keyboard input available.  */
       if (nread <= 0)
        break;
     }
-#ifdef HAVE_NS
-  --handling_signal;
 #endif
 }
-#endif /* SYNC_INPUT || SIGIO */
 
-#ifdef SYNC_INPUT
 void
 process_pending_signals (void)
 {
-  if (interrupt_input_pending)
-    handle_async_input ();
+  pending_signals = 0;
+  handle_async_input ();
   do_pending_atimers ();
 }
-#endif
 
-#ifdef SIGIO   /* for entire page */
-/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+/* Undo any number of BLOCK_INPUT calls down to level LEVEL,
+   and also (if the level is now 0) reinvoke any pending signal.  */
 
-static void
-input_available_signal (int signo)
+void
+unblock_input_to (int level)
 {
-  /* Must preserve main program's value of errno.  */
-  int old_errno = errno;
-  SIGNAL_THREAD_CHECK (signo);
+  interrupt_input_blocked = level;
+  if (level == 0)
+    {
+      if (pending_signals)
+       process_pending_signals ();
+    }
+  else if (level < 0)
+    emacs_abort ();
+}
 
-#ifdef SYNC_INPUT
-  interrupt_input_pending = 1;
-  pending_signals = 1;
-#endif
+/* End critical section.
 
-  if (input_available_clear_time)
-    EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
+   If doing signal-driven input, and a signal came in when input was
+   blocked, reinvoke the signal handler now to deal with it.  */
 
-#ifndef SYNC_INPUT
-  handle_async_input ();
-#endif
+void
+unblock_input (void)
+{
+  unblock_input_to (interrupt_input_blocked - 1);
+}
+
+/* Undo any number of BLOCK_INPUT calls,
+   and also reinvoke any pending signal.  */
 
-  errno = old_errno;
+void
+totally_unblock_input (void)
+{
+  unblock_input_to (0);
 }
-#endif /* SIGIO */
 
-/* Send ourselves a SIGIO.
+#ifdef USABLE_SIGIO
 
-   This function exists so that the UNBLOCK_INPUT macro in
-   blockinput.h can have some way to take care of input we put off
-   dealing with, without assuming that every file which uses
-   UNBLOCK_INPUT also has #included the files necessary to get SIGIO.  */
 void
-reinvoke_input_signal (void)
+handle_input_available_signal (int sig)
 {
-#ifdef SIGIO
-  handle_async_input ();
-#endif
+  pending_signals = 1;
+
+  if (input_available_clear_time)
+    *input_available_clear_time = make_timespec (0, 0);
 }
 
+static void
+deliver_input_available_signal (int sig)
+{
+  deliver_process_signal (sig, handle_input_available_signal);
+}
+#endif /* USABLE_SIGIO */
 
 \f
 /* User signal events.  */
@@ -7289,6 +7172,7 @@ static struct user_signal_info *user_signals = NULL;
 void
 add_user_signal (int sig, const char *name)
 {
+  struct sigaction action;
   struct user_signal_info *p;
 
   for (p = user_signals; p; p = p->next)
@@ -7296,33 +7180,31 @@ add_user_signal (int sig, const char *name)
       /* Already added.  */
       return;
 
-  p = xmalloc (sizeof (struct user_signal_info));
+  p = xmalloc (sizeof *p);
   p->sig = sig;
   p->name = xstrdup (name);
   p->npending = 0;
   p->next = user_signals;
   user_signals = p;
 
-  signal (sig, handle_user_signal);
+  emacs_sigaction_init (&action, deliver_user_signal);
+  sigaction (sig, &action, 0);
 }
 
 static void
 handle_user_signal (int sig)
 {
-  int old_errno = errno;
   struct user_signal_info *p;
   const char *special_event_name = NULL;
 
-  SIGNAL_THREAD_CHECK (sig);
-
   if (SYMBOLP (Vdebug_on_event))
     special_event_name = SSDATA (SYMBOL_NAME (Vdebug_on_event));
 
   for (p = user_signals; p; p = p->next)
     if (p->sig == sig)
       {
-        if (special_event_name &&
-            strcmp (special_event_name, p->name) == 0)
+        if (special_event_name
+           && strcmp (special_event_name, p->name) == 0)
           {
             /* Enter the debugger in many ways.  */
             debug_on_next_call = 1;
@@ -7335,21 +7217,25 @@ handle_user_signal (int sig)
           }
 
        p->npending++;
-#ifdef SIGIO
+#ifdef USABLE_SIGIO
        if (interrupt_input)
-         kill (getpid (), SIGIO);
+         handle_input_available_signal (sig);
        else
 #endif
          {
            /* Tell wait_reading_process_output that it needs to wake
               up and look around.  */
            if (input_available_clear_time)
-             EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
+             *input_available_clear_time = make_timespec (0, 0);
          }
        break;
       }
+}
 
-  errno = old_errno;
+static void
+deliver_user_signal (int sig)
+{
+  deliver_process_signal (sig, handle_user_signal);
 }
 
 static char *
@@ -7364,27 +7250,24 @@ find_user_signal_name (int sig)
   return NULL;
 }
 
-static int
+static void
 store_user_signal_events (void)
 {
   struct user_signal_info *p;
   struct input_event buf;
-  int nstored = 0;
+  bool buf_initialized = 0;
 
   for (p = user_signals; p; p = p->next)
     if (p->npending > 0)
       {
-       SIGMASKTYPE mask;
-
-       if (nstored == 0)
+       if (! buf_initialized)
          {
            memset (&buf, 0, sizeof buf);
            buf.kind = USER_SIGNAL_EVENT;
            buf.frame_or_window = selected_frame;
+           buf_initialized = 1;
          }
-       nstored += p->npending;
 
-       mask = sigblock (sigmask (p->sig));
        do
          {
            buf.code = p->sig;
@@ -7392,10 +7275,7 @@ store_user_signal_events (void)
            p->npending--;
          }
        while (p->npending > 0);
-       sigsetmask (mask);
       }
-
-  return nstored;
 }
 
 \f
@@ -7427,15 +7307,15 @@ static const char* separator_names[] = {
   0,
 };
 
-/* Return non-zero if LABEL specifies a separator.  */
+/* Return true if LABEL specifies a separator.  */
 
-int
+bool
 menu_separator_name_p (const char *label)
 {
   if (!label)
     return 0;
   else if (strlen (label) > 3
-          && strncmp (label, "--", 2) == 0
+          && memcmp (label, "--", 2) == 0
           && label[2] != '-')
     {
       int i;
@@ -7502,10 +7382,11 @@ 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 = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+       maps = alloca (3 * sizeof (maps[0]));
        nmaps = 0;
        if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
          maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -7522,8 +7403,11 @@ menu_bar_items (Lisp_Object old)
        Lisp_Object tem;
        ptrdiff_t nminor;
        nminor = current_minor_maps (NULL, &tmaps);
-       maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0]));
+       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]));
@@ -7555,23 +7439,23 @@ menu_bar_items (Lisp_Object old)
       int end = menu_bar_items_index;
 
       for (i = 0; i < end; i += 4)
-       if (EQ (XCAR (tail), XVECTOR (menu_bar_items_vector)->contents[i]))
+       if (EQ (XCAR (tail), AREF (menu_bar_items_vector, i)))
          {
            Lisp_Object tem0, tem1, tem2, tem3;
            /* Move the item at index I to the end,
               shifting all the others forward.  */
-           tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
-           tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
-           tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
-           tem3 = XVECTOR (menu_bar_items_vector)->contents[i + 3];
+           tem0 = AREF (menu_bar_items_vector, i + 0);
+           tem1 = AREF (menu_bar_items_vector, i + 1);
+           tem2 = AREF (menu_bar_items_vector, i + 2);
+           tem3 = AREF (menu_bar_items_vector, i + 3);
            if (end > i + 4)
-             memmove (&XVECTOR (menu_bar_items_vector)->contents[i],
-                      &XVECTOR (menu_bar_items_vector)->contents[i + 4],
-                      (end - i - 4) * sizeof (Lisp_Object));
-           XVECTOR (menu_bar_items_vector)->contents[end - 4] = tem0;
-           XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem1;
-           XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem2;
-           XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem3;
+             memmove (aref_addr (menu_bar_items_vector, i),
+                      aref_addr (menu_bar_items_vector, i + 4),
+                      (end - i - 4) * word_size);
+           ASET (menu_bar_items_vector, end - 4, tem0);
+           ASET (menu_bar_items_vector, end - 3, tem1);
+           ASET (menu_bar_items_vector, end - 2, tem2);
+           ASET (menu_bar_items_vector, end - 1, tem3);
            break;
          }
     }
@@ -7583,10 +7467,10 @@ menu_bar_items (Lisp_Object old)
       menu_bar_items_vector =
        larger_vector (menu_bar_items_vector, 4, -1);
     /* Add this item.  */
-    XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
-    XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
-    XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
-    XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+    ASET (menu_bar_items_vector, i, Qnil); i++;
+    ASET (menu_bar_items_vector, i, Qnil); i++;
+    ASET (menu_bar_items_vector, i, Qnil); i++;
+    ASET (menu_bar_items_vector, i, Qnil); i++;
     menu_bar_items_index = i;
   }
 
@@ -7604,6 +7488,7 @@ menu_bar_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy1, void *dumm
 {
   struct gcpro gcpro1;
   int i;
+  bool parsed;
   Lisp_Object tem;
 
   if (EQ (item, Qundefined))
@@ -7612,12 +7497,12 @@ menu_bar_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy1, void *dumm
         discard any previously made menu bar item.  */
 
       for (i = 0; i < menu_bar_items_index; i += 4)
-       if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+       if (EQ (key, AREF (menu_bar_items_vector, i)))
          {
            if (menu_bar_items_index > i + 4)
-             memmove (&XVECTOR (menu_bar_items_vector)->contents[i],
-                      &XVECTOR (menu_bar_items_vector)->contents[i + 4],
-                      (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
+             memmove (aref_addr (menu_bar_items_vector, i),
+                      aref_addr (menu_bar_items_vector, i + 4),
+                      (menu_bar_items_index - i - 4) * word_size);
            menu_bar_items_index -= 4;
          }
     }
@@ -7635,16 +7520,16 @@ menu_bar_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy1, void *dumm
      parse_menu_item, so that if it turns out it wasn't a menu item,
      it still correctly hides any further menu item.  */
   GCPRO1 (key);
-  i = parse_menu_item (item, 1);
+  parsed = parse_menu_item (item, 1);
   UNGCPRO;
-  if (!i)
+  if (!parsed)
     return;
 
-  item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+  item = AREF (item_properties, ITEM_PROPERTY_DEF);
 
   /* Find any existing item for this KEY.  */
   for (i = 0; i < menu_bar_items_index; i += 4)
-    if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+    if (EQ (key, AREF (menu_bar_items_vector, i)))
       break;
 
   /* If we did not find this KEY, add it at the end.  */
@@ -7654,22 +7539,22 @@ menu_bar_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy1, void *dumm
       if (i + 4 > ASIZE (menu_bar_items_vector))
        menu_bar_items_vector = larger_vector (menu_bar_items_vector, 4, -1);
       /* Add this item.  */
-      XVECTOR (menu_bar_items_vector)->contents[i++] = key;
-      XVECTOR (menu_bar_items_vector)->contents[i++]
-       = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
-      XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (item, Qnil);
-      XVECTOR (menu_bar_items_vector)->contents[i++] = make_number (0);
+      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, list1 (item)); i++;
+      ASET (menu_bar_items_vector, i, make_number (0)); i++;
       menu_bar_items_index = i;
     }
   /* We did find an item for this KEY.  Add ITEM to its list of maps.  */
   else
     {
       Lisp_Object old;
-      old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+      old = AREF (menu_bar_items_vector, i + 2);
       /* If the new and the old items are not both keymaps,
         the lookup will only find `item'.  */
       item = Fcons (item, KEYMAPP (item) && KEYMAPP (XCAR (old)) ? old : Qnil);
-      XVECTOR (menu_bar_items_vector)->contents[i + 2] = item;
+      ASET (menu_bar_items_vector, i + 2, item);
     }
 }
 \f
@@ -7713,7 +7598,7 @@ menu_item_eval_property (Lisp_Object sexpr)
    parse_menu_item returns true if the item is a menu item and false
    otherwise.  */
 
-int
+bool
 parse_menu_item (Lisp_Object item, int inmenubar)
 {
   Lisp_Object def, tem, item_string, start;
@@ -7934,7 +7819,8 @@ parse_menu_item (Lisp_Object item, int inmenubar)
                    /* If the command is an alias for another
                       (such as lmenu.el set it up), check if the
                       original command matches the cached command.  */
-                   && !(SYMBOLP (def) && EQ (tem, XSYMBOL (def)->function))))
+                   && !(SYMBOLP (def)
+                        && EQ (tem, XSYMBOL (def)->function))))
              keys = Qnil;
          }
 
@@ -8012,7 +7898,7 @@ static Lisp_Object QCrtl;
 
 static void init_tool_bar_items (Lisp_Object);
 static void process_tool_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void*);
-static int parse_tool_bar_item (Lisp_Object, Lisp_Object);
+static bool parse_tool_bar_item (Lisp_Object, Lisp_Object);
 static void append_tool_bar_item (void);
 
 
@@ -8046,10 +7932,11 @@ 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 = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+      maps = alloca (3 * sizeof *maps);
       nmaps = 0;
       if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
        maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
@@ -8066,8 +7953,11 @@ tool_bar_items (Lisp_Object reuse, int *nitems)
       Lisp_Object tem;
       ptrdiff_t nminor;
       nminor = current_minor_maps (NULL, &tmaps);
-      maps = (Lisp_Object *) alloca ((nminor + 3) * sizeof (maps[0]));
+      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]));
@@ -8121,7 +8011,7 @@ process_tool_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void
              if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS)
                memmove (v, v + TOOL_BAR_ITEM_NSLOTS,
                         ((ntool_bar_items - i - TOOL_BAR_ITEM_NSLOTS)
-                         * sizeof (Lisp_Object)));
+                         * word_size));
              ntool_bar_items -= TOOL_BAR_ITEM_NSLOTS;
              break;
            }
@@ -8135,9 +8025,17 @@ process_tool_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void
   UNGCPRO;
 }
 
+/* Access slot with index IDX of vector tool_bar_item_properties.  */
+#define PROP(IDX) AREF (tool_bar_item_properties, (IDX))
+static void
+set_prop (ptrdiff_t idx, Lisp_Object val)
+{
+  ASET (tool_bar_item_properties, idx, val);
+}
+
 
 /* Parse a tool bar item specification ITEM for key KEY and return the
-   result in tool_bar_item_properties.  Value is zero if ITEM is
+   result in tool_bar_item_properties.  Value is false if ITEM is
    invalid.
 
    ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
@@ -8182,15 +8080,13 @@ process_tool_bar_item (Lisp_Object key, Lisp_Object def, Lisp_Object data, void
 
    A text label to show with the tool bar button if labels are enabled.  */
 
-static int
+static bool
 parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
 {
-  /* Access slot with index IDX of vector tool_bar_item_properties.  */
-#define PROP(IDX) XVECTOR (tool_bar_item_properties)->contents[IDX]
-
   Lisp_Object filter = Qnil;
   Lisp_Object caption;
-  int i, have_label = 0;
+  int i;
+  bool have_label = 0;
 
   /* Definition looks like `(menu-item CAPTION BINDING PROPS...)'.
      Rule out items that aren't lists, don't start with
@@ -8201,7 +8097,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;
@@ -8211,15 +8107,15 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
   if (VECTORP (tool_bar_item_properties))
     {
       for (i = 0; i < TOOL_BAR_ITEM_NSLOTS; ++i)
-       PROP (i) = Qnil;
+       set_prop (i, Qnil);
     }
   else
     tool_bar_item_properties
       = Fmake_vector (make_number (TOOL_BAR_ITEM_NSLOTS), Qnil);
 
   /* Set defaults.  */
-  PROP (TOOL_BAR_ITEM_KEY) = key;
-  PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
+  set_prop (TOOL_BAR_ITEM_KEY, key);
+  set_prop (TOOL_BAR_ITEM_ENABLED_P, Qt);
 
   /* Get the caption of the item.  If the caption is not a string,
      evaluate it to get a string.  If we don't get a string, skip this
@@ -8231,7 +8127,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
       if (!STRINGP (caption))
        return 0;
     }
-  PROP (TOOL_BAR_ITEM_CAPTION) = caption;
+  set_prop (TOOL_BAR_ITEM_CAPTION, caption);
 
   /* If the rest following the caption is not a list, the menu item is
      either a separator, or invalid.  */
@@ -8240,15 +8136,16 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
     {
       if (menu_separator_name_p (SSDATA (caption)))
        {
-         PROP (TOOL_BAR_ITEM_TYPE) = Qt;
+         set_prop (TOOL_BAR_ITEM_TYPE, Qt);
 #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;
        }
@@ -8256,7 +8153,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
     }
 
   /* Store the binding.  */
-  PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
+  set_prop (TOOL_BAR_ITEM_BINDING, XCAR (item));
   item = XCDR (item);
 
   /* Ignore cached key binding, if any.  */
@@ -8275,9 +8172,9 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
        {
          /* `:enable FORM'.  */
          if (!NILP (Venable_disabled_menus_and_buttons))
-           PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
+           set_prop (TOOL_BAR_ITEM_ENABLED_P, Qt);
          else
-           PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+           set_prop (TOOL_BAR_ITEM_ENABLED_P, value);
        }
       else if (EQ (ikey, QCvisible))
        {
@@ -8288,17 +8185,16 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
        }
       else if (EQ (ikey, QChelp))
         /* `:help HELP-STRING'.  */
-        PROP (TOOL_BAR_ITEM_HELP) = value;
+        set_prop (TOOL_BAR_ITEM_HELP, value);
       else if (EQ (ikey, QCvert_only))
         /* `:vert-only t/nil'.  */
-        PROP (TOOL_BAR_ITEM_VERT_ONLY) = value;
+        set_prop (TOOL_BAR_ITEM_VERT_ONLY, value);
       else if (EQ (ikey, QClabel))
         {
           const char *bad_label = "!!?GARBLED ITEM?!!";
           /* `:label LABEL-STRING'.  */
-          PROP (TOOL_BAR_ITEM_LABEL) = STRINGP (value)
-            ? value
-            : build_string (bad_label);
+          set_prop (TOOL_BAR_ITEM_LABEL,
+                   STRINGP (value) ? value : build_string (bad_label));
           have_label = 1;
         }
       else if (EQ (ikey, QCfilter))
@@ -8313,8 +8209,8 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
          selected = XCDR (value);
          if (EQ (type, QCtoggle) || EQ (type, QCradio))
            {
-             PROP (TOOL_BAR_ITEM_SELECTED_P) = selected;
-             PROP (TOOL_BAR_ITEM_TYPE) = type;
+             set_prop (TOOL_BAR_ITEM_SELECTED_P, selected);
+             set_prop (TOOL_BAR_ITEM_TYPE, type);
            }
        }
       else if (EQ (ikey, QCimage)
@@ -8322,10 +8218,10 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
                   || (VECTORP (value) && ASIZE (value) == 4)))
        /* Value is either a single image specification or a vector
           of 4 such specifications for the different button states.  */
-       PROP (TOOL_BAR_ITEM_IMAGES) = value;
+       set_prop (TOOL_BAR_ITEM_IMAGES, value);
       else if (EQ (ikey, QCrtl))
         /* ':rtl STRING' */
-       PROP (TOOL_BAR_ITEM_RTL_IMAGE) = value;
+       set_prop (TOOL_BAR_ITEM_RTL_IMAGE, value);
     }
 
 
@@ -8338,7 +8234,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
       const char *capt = STRINGP (tcapt) ? SSDATA (tcapt) : "";
       ptrdiff_t max_lbl =
        2 * max (0, min (tool_bar_max_label_size, STRING_BYTES_BOUND / 2));
-      char *buf = (char *) xmalloc (max_lbl + 1);
+      char *buf = xmalloc (max_lbl + 1);
       Lisp_Object new_lbl;
       ptrdiff_t caption_len = strlen (capt);
 
@@ -8367,18 +8263,19 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
 
       new_lbl = Fupcase_initials (build_string (label));
       if (SCHARS (new_lbl) <= tool_bar_max_label_size)
-        PROP (TOOL_BAR_ITEM_LABEL) = new_lbl;
+        set_prop (TOOL_BAR_ITEM_LABEL, new_lbl);
       else
-        PROP (TOOL_BAR_ITEM_LABEL) = make_string ("", 0);
+        set_prop (TOOL_BAR_ITEM_LABEL, empty_unibyte_string);
       xfree (buf);
     }
 
   /* If got a filter apply it on binding.  */
   if (!NILP (filter))
-    PROP (TOOL_BAR_ITEM_BINDING)
-      = menu_item_eval_property (list2 (filter,
-                                       list2 (Qquote,
-                                              PROP (TOOL_BAR_ITEM_BINDING))));
+    set_prop (TOOL_BAR_ITEM_BINDING,
+             (menu_item_eval_property
+              (list2 (filter,
+                      list2 (Qquote,
+                             PROP (TOOL_BAR_ITEM_BINDING))))));
 
   /* See if the binding is a keymap.  Give up if it is.  */
   if (CONSP (get_keymap (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
@@ -8386,13 +8283,13 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
 
   /* Enable or disable selection of item.  */
   if (!EQ (PROP (TOOL_BAR_ITEM_ENABLED_P), Qt))
-    PROP (TOOL_BAR_ITEM_ENABLED_P)
-      = menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P));
+    set_prop (TOOL_BAR_ITEM_ENABLED_P,
+             menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P)));
 
   /* Handle radio buttons or toggle boxes.  */
   if (!NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)))
-    PROP (TOOL_BAR_ITEM_SELECTED_P)
-      = menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P));
+    set_prop (TOOL_BAR_ITEM_SELECTED_P,
+             menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P)));
 
   return 1;
 
@@ -8420,21 +8317,18 @@ init_tool_bar_items (Lisp_Object reuse)
 static void
 append_tool_bar_item (void)
 {
-  Lisp_Object *to, *from;
-  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.  */
-  to = XVECTOR (tool_bar_items_vector)->contents + ntool_bar_items;
-  from = XVECTOR (tool_bar_item_properties)->contents;
-  memcpy (to, from, TOOL_BAR_ITEM_NSLOTS * sizeof *to);
+  vcopy (tool_bar_items_vector, ntool_bar_items,
+        XVECTOR (tool_bar_item_properties)->contents, TOOL_BAR_ITEM_NSLOTS);
   ntool_bar_items += TOOL_BAR_ITEM_NSLOTS;
 }
 
@@ -8442,16 +8336,16 @@ 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
    the first event of a key sequence.
 
-   If USED_MOUSE_MENU is non-null, then we set *USED_MOUSE_MENU to 1
-   if we used a mouse menu to read the input, or zero otherwise.  If
-   USED_MOUSE_MENU is null, we don't dereference it.
+   If USED_MOUSE_MENU is non-null, set *USED_MOUSE_MENU to true
+   if we used a mouse menu to read the input, or false otherwise.  If
+   USED_MOUSE_MENU is null, don't dereference it.
 
    The prompting is done based on the prompt-string of the map
    and the strings associated with various map elements.
@@ -8463,26 +8357,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,
-                        Lisp_Object prev_event, int *used_mouse_menu)
+read_char_x_menu_prompt (Lisp_Object map,
+                        Lisp_Object prev_event, bool *used_mouse_menu)
 {
-  ptrdiff_t mapno;
-
   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.  */
@@ -8491,17 +8376,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
-       = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
       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;
@@ -8541,71 +8418,46 @@ 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.  */
   ptrdiff_t width = FRAME_COLS (SELECTED_FRAME ()) - 4;
   ptrdiff_t idx = -1;
-  int nobindings = 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
-       = (char *) 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 (build_unibyte_string (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)
     {
-      int notfirst = 0;
+      bool notfirst = 0;
+      Lisp_Object menu_strings = prompt_strings;
       ptrdiff_t i = nlength;
       Lisp_Object obj;
       Lisp_Object orig_defn_macro;
@@ -8615,23 +8467,21 @@ 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.  */
          if (idx >= 0)
-           elt = XVECTOR (vector)->contents[idx];
+           elt = AREF (vector, idx);
          else
            elt = Fcar_safe (rest);
 
@@ -8661,12 +8511,12 @@ read_char_minibuf_menu_prompt (int commandflag,
              /* Ignore the element if it has no prompt string.  */
              if (INTEGERP (event) && parse_menu_item (elt, -1))
                {
-                 /* 1 if the char to type matches the string.  */
-                 int char_matches;
+                 /* True if the char to type matches the string.  */
+                 bool char_matches;
                  Lisp_Object upcased_event, downcased_event;
                  Lisp_Object desc = Qnil;
                  Lisp_Object s
-                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+                   = AREF (item_properties, ITEM_PROPERTY_NAME);
 
                  upcased_event = Fupcase (event);
                  downcased_event = Fdowncase (event);
@@ -8684,12 +8534,12 @@ read_char_minibuf_menu_prompt (int commandflag,
                    s = concat2 (s, tem);
 #endif
                  tem
-                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
+                   = AREF (item_properties, ITEM_PROPERTY_TYPE);
                  if (EQ (tem, QCradio) || EQ (tem, QCtoggle))
                    {
                      /* Insert button prefix.  */
                      Lisp_Object selected
-                       = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+                       = AREF (item_properties, ITEM_PROPERTY_SELECTED);
                      if (EQ (tem, QCradio))
                        tem = build_string (NILP (selected) ? "(*) " : "( ) ");
                      else
@@ -8710,11 +8560,11 @@ read_char_minibuf_menu_prompt (int commandflag,
                      /* Punctuate between strings.  */
                      if (notfirst)
                        {
-                         strcpy (menu + i, ", ");
+                         PUSH_C_STR (", ", menu_strings);
                          i += 2;
                        }
                      notfirst = 1;
-                     nobindings = 0 ;
+                     nobindings = 0;
 
                      /* If the char to type doesn't match the string's
                         first char, explicitly show what char to type.  */
@@ -8722,23 +8572,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;
                    }
                }
@@ -8755,23 +8610,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);
-      KVAR (current_kboard, defining_kbd_macro) = Qnil;
+      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));
-      KVAR (current_kboard, defining_kbd_macro) = orig_defn_macro;
+      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)
@@ -8782,52 +8633,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
@@ -8848,36 +8672,30 @@ typedef struct keyremap
 
 /* Lookup KEY in MAP.
    MAP is a keymap mapping keys to key vectors or functions.
-   If the mapping is a function and DO_FUNCTION is non-zero, then
+   If the mapping is a function and DO_FUNCALL is true,
    the function is called with PROMPT as parameter and its return
    value is used as the return value of this function (after checking
    that it is indeed a vector).  */
 
 static Lisp_Object
 access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt,
-                       int do_funcall)
+                       bool do_funcall)
 {
   Lisp_Object next;
 
   next = access_keymap (map, key, 1, 0, 1);
 
-  /* Handle symbol with autoload definition.  */
-  if (SYMBOLP (next) && !NILP (Ffboundp (next))
-      && CONSP (XSYMBOL (next)->function)
-      && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
-    do_autoload (XSYMBOL (next)->function, next);
-
   /* Handle a symbol whose function definition is a keymap
      or an array.  */
   if (SYMBOLP (next) && !NILP (Ffboundp (next))
       && (ARRAYP (XSYMBOL (next)->function)
          || KEYMAPP (XSYMBOL (next)->function)))
-    next = XSYMBOL (next)->function;
+    next = Fautoload_do_load (XSYMBOL (next)->function, next, Qnil);
 
   /* If the keymap gives a function, not an
      array, then call the function with one arg and use
      its value instead.  */
-  if (SYMBOLP (next) && !NILP (Ffboundp (next)) && do_funcall)
+  if (do_funcall && FUNCTIONP (next))
     {
       Lisp_Object tem;
       tem = next;
@@ -8887,7 +8705,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)));
     }
@@ -8900,15 +8718,15 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt,
    BUFSIZE is its maximum size.
    FKEY is a pointer to the keyremap structure to use.
    INPUT is the index of the last element in KEYBUF.
-   DOIT if non-zero says that the remapping can actually take place.
+   DOIT if true says that the remapping can actually take place.
    DIFF is used to return the number of keys added/removed by the remapping.
    PARENT is the root of the keymap.
    PROMPT is the prompt to use if the remapping happens through a function.
-   The return value is non-zero if the remapping actually took place.  */
+   Return true if the remapping actually took place.  */
 
-static int
+static bool
 keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey,
-              int input, int doit, int *diff, Lisp_Object prompt)
+              int input, bool doit, int *diff, Lisp_Object prompt)
 {
   Lisp_Object next, key;
 
@@ -8962,11 +8780,12 @@ keyremap_step (Lisp_Object *keybuf, int bufsize, volatile keyremap *fkey,
   return 0;
 }
 
-static int
+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)));
 }
 
@@ -9004,15 +8823,14 @@ test_undefined (Lisp_Object binding)
    off the switch-frame event until later; the next call to
    read_char will return it.
 
-   If FIX_CURRENT_BUFFER is nonzero, we restore current_buffer
+   If FIX_CURRENT_BUFFER, we restore current_buffer
    from the selected window's buffer.  */
 
 static int
 read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
-                  int dont_downcase_last, int can_return_switch_frame,
-                  int fix_current_buffer)
+                  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.  */
@@ -9023,34 +8841,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;
-
-  /* The map from the `keymap' property to start out with at start of
-     key sequence.  */
-  Lisp_Object orig_keymap;
+  Lisp_Object current_binding = Qnil;
+  Lisp_Object first_event = Qnil;
 
-  /* 1 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;
@@ -9083,36 +8876,27 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   /* Likewise, for key_translation_map and input-decode-map.  */
   keyremap keytran, indec;
 
-  /* Non-zero if we are trying to map a key by changing an upper-case
+  /* True if we are trying to map a key by changing an upper-case
      letter to lower case, or a shifted function key to an unshifted
      one.  */
-  int shift_translated = 0;
+  bool shift_translated = 0;
 
   /* If we receive a `switch-frame' or `select-window' event in the middle of
      a key sequence, we put it off for later.
      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;
 
   /* Gets around Microsoft compiler limitations.  */
-  int dummyflag = 0;
+  bool dummyflag = 0;
 
   struct buffer *starting_buffer;
 
   /* 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);
@@ -9129,7 +8913,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          /* Install the string STR as the beginning of the string of
             echoing, so that it serves as a prompt for the next
             character.  */
-         KVAR (current_kboard, echo_string) = prompt;
+         kset_echo_string (current_kboard, prompt);
          current_kboard->echo_after_prompt = SCHARS (prompt);
          echo_now ();
        }
@@ -9148,21 +8932,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:
@@ -9187,59 +8956,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 = (Lisp_Object *) alloca (2 * sizeof (submaps[0]));
-         defs    = (Lisp_Object *) alloca (2 * sizeof (defs[0]));
-         nmaps_allocated = 2;
-       }
-      submaps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
-    }
-  else if (!NILP (Voverriding_local_map))
-    {
-      if (2 > nmaps_allocated)
-       {
-         submaps = (Lisp_Object *) alloca (2 * sizeof (submaps[0]));
-         defs    = (Lisp_Object *) alloca (2 * sizeof (defs[0]));
-         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 = (Lisp_Object *) alloca (total * sizeof (submaps[0]));
-         defs    = (Lisp_Object *) alloca (total * sizeof (defs[0]));
-         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;
@@ -9253,9 +8970,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
@@ -9264,7 +8981,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
         : (/* indec.start < t || fkey.start < t || */ keytran.start < t))
     {
       Lisp_Object key;
-      int used_mouse_menu = 0;
+      bool used_mouse_menu = 0;
 
       /* Where the last real key started.  If we need to throw away a
          key that has expanded into more than one element of keybuf
@@ -9279,7 +8996,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);
@@ -9316,7 +9033,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
@@ -9326,7 +9042,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;
@@ -9337,8 +9052,12 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
          key = keybuf[t];
          add_command_key (key);
          if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
-             && NILP (Fzerop (Vecho_keystrokes)))
-           echo_char (key);
+             && NILP (Fzerop (Vecho_keystrokes))
+             && current_kboard->immediate_echo)
+           {
+             echo_add_key (key);
+             echo_dash ();
+           }
        }
 
       /* If not, we should actually read a character.  */
@@ -9347,9 +9066,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
@@ -9358,7 +9077,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                   return.  Any better way to fix this? -- cyd  */
                || (interrupted_kboard != current_kboard))
              {
-               int found = 0;
+               bool found = 0;
                struct kboard *k;
 
                for (k = all_kboards; k; k = k->next_kboard)
@@ -9375,15 +9094,17 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
                if (!NILP (delayed_switch_frame))
                  {
-                   KVAR (interrupted_kboard, kbd_queue)
-                     = Fcons (delayed_switch_frame,
-                              KVAR (interrupted_kboard, kbd_queue));
+                   kset_kbd_queue
+                     (interrupted_kboard,
+                      Fcons (delayed_switch_frame,
+                             KVAR (interrupted_kboard, kbd_queue)));
                    delayed_switch_frame = Qnil;
                  }
 
                while (t > 0)
-                 KVAR (interrupted_kboard, kbd_queue)
-                   = Fcons (keybuf[--t], KVAR (interrupted_kboard, kbd_queue));
+                 kset_kbd_queue
+                   (interrupted_kboard,
+                    Fcons (keybuf[--t], KVAR (interrupted_kboard, kbd_queue)));
 
                /* If the side queue is non-empty, ensure it begins with a
                   switch-frame, so we'll replay it in the right context.  */
@@ -9395,13 +9116,12 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                  {
                    Lisp_Object frame;
                    XSETFRAME (frame, interrupted_frame);
-                   KVAR (interrupted_kboard, kbd_queue)
-                     = Fcons (make_lispy_switch_frame (frame),
-                              KVAR (interrupted_kboard, kbd_queue));
+                   kset_kbd_queue
+                     (interrupted_kboard,
+                      Fcons (make_lispy_switch_frame (frame),
+                             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;
              }
          }
@@ -9442,12 +9162,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;
            }
 
@@ -9459,12 +9178,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
              && current_buffer != starting_buffer)
            {
              GROW_RAW_KEYBUF;
-             XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
+             ASET (raw_keybuf, raw_keybuf_count, key);
+             raw_keybuf_count++;
              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;
            }
 
@@ -9484,6 +9202,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++;
@@ -9505,16 +9239,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)
@@ -9534,10 +9263,11 @@ 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)
                    {
-                     XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
+                     ASET (raw_keybuf, raw_keybuf_count, key);
+                     raw_keybuf_count++;
                      keybuf[t] = key;
                      mock_input = t + 1;
 
@@ -9551,63 +9281,13 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                         because we may get input from a subprocess which
                         wants to change the selected window and stuff (say,
                         emacsclient).  */
-                     record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+                     record_unwind_current_buffer ();
 
                      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:
@@ -9628,63 +9308,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))
@@ -9700,12 +9325,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;
@@ -9723,15 +9347,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.
@@ -9865,23 +9484,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;
                        }
@@ -9890,6 +9501,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.
@@ -9907,7 +9519,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
       while (indec.end < t)
        {
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-         int done, diff;
+         bool done;
+         int diff;
 
          GCPRO4 (indec.map, fkey.map, keytran.map, delayed_switch_frame);
          done = keyremap_step (keybuf, bufsize, &indec, max (t, mock_input),
@@ -9920,9 +9533,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).
@@ -9941,7 +9553,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
        while (fkey.end < indec.start)
          {
            struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-           int done, diff;
+           bool done;
+           int diff;
 
            GCPRO4 (indec.map, fkey.map, keytran.map, delayed_switch_frame);
            done = keyremap_step (keybuf, bufsize, &fkey,
@@ -9950,8 +9563,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)
@@ -9970,7 +9582,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
       while (keytran.end < fkey.start)
        {
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-         int done, diff;
+         bool done;
+         int diff;
 
          GCPRO4 (indec.map, fkey.map, keytran.map, delayed_switch_frame);
          done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input),
@@ -9993,7 +9606,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))
@@ -10024,7 +9637,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);
@@ -10065,9 +9678,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
@@ -10081,7 +9692,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)
     {
@@ -10113,54 +9724,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
   return t;
 }
 
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
-       doc: /* Read a sequence of keystrokes and return as a string or vector.
-The sequence is sufficient to specify a non-prefix command in the
-current local and global maps.
-
-First arg PROMPT is a prompt string.  If nil, do not prompt specially.
-Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
-as a continuation of the previous key.
-
-The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
-convert the last event to lower case.  (Normally any upper case event
-is converted to lower case if the original event is undefined and the lower
-case equivalent is defined.)  A non-nil value is appropriate for reading
-a key sequence to be defined.
-
-A C-g typed while in this function is treated like any other character,
-and `quit-flag' is not set.
-
-If the key sequence starts with a mouse click, then the sequence is read
-using the keymaps of the buffer of the window clicked in, not the buffer
-of the selected window as normal.
-
-`read-key-sequence' drops unbound button-down events, since you normally
-only care about the click or drag events which follow them.  If a drag
-or multi-click event is unbound, but the corresponding click event would
-be bound, `read-key-sequence' turns the event into a click event at the
-drag's starting position.  This means that you don't have to distinguish
-between click and drag, double, or triple events unless you want to.
-
-`read-key-sequence' prefixes mouse events on mode lines, the vertical
-lines separating windows, and scroll bars with imaginary keys
-`mode-line', `vertical-line', and `vertical-scroll-bar'.
-
-Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this
-function will process a switch-frame event if the user switches frames
-before typing anything.  If the user switches frames in the middle of a
-key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME
-is nil, then the event will be put off until after the current key sequence.
-
-`read-key-sequence' checks `function-key-map' for function key
-sequences, where they wouldn't conflict with ordinary bindings.  See
-`function-key-map' for more details.
-
-The optional fifth argument CMD-LOOP, if non-nil, means
-that this key sequence is being read by something that will
-read commands one after another.  It should be nil if the caller
-will read just one key sequence.  */)
-  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
+static Lisp_Object
+read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
+                     Lisp_Object dont_downcase_last,
+                     Lisp_Object can_return_switch_frame,
+                     Lisp_Object cmd_loop, bool allow_string)
 {
   Lisp_Object keybuf[30];
   register int i;
@@ -10178,7 +9746,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))
     {
@@ -10192,7 +9760,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);
 
@@ -10211,183 +9779,99 @@ will read just one key sequence.  */)
       QUIT;
     }
   UNGCPRO;
-  return unbind_to (count, make_event_array (i, keybuf));
+  return unbind_to (count,
+                   ((allow_string ? make_event_array : Fvector)
+                    (i, keybuf)));
 }
 
-DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
-       Sread_key_sequence_vector, 1, 5, 0,
-       doc: /* Like `read-key-sequence' but always return a vector.  */)
-  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
-{
-  Lisp_Object keybuf[30];
-  register int i;
-  struct gcpro gcpro1;
-  ptrdiff_t count = SPECPDL_INDEX ();
-
-  if (!NILP (prompt))
-    CHECK_STRING (prompt);
-  QUIT;
-
-  specbind (Qinput_method_exit_on_first_char,
-           (NILP (cmd_loop) ? Qt : Qnil));
-  specbind (Qinput_method_use_echo_area,
-           (NILP (cmd_loop) ? Qt : Qnil));
-
-  memset (keybuf, 0, sizeof keybuf);
-  GCPRO1 (keybuf[0]);
-  gcpro1.nvars = (sizeof keybuf / sizeof (keybuf[0]));
-
-  if (NILP (continue_echo))
-    {
-      this_command_key_count = 0;
-      this_command_key_count_reset = 0;
-      this_single_command_key_start = 0;
-    }
-
-#ifdef HAVE_WINDOW_SYSTEM
-  if (display_hourglass_p)
-    cancel_hourglass ();
-#endif
-
-  i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
-                        prompt, ! NILP (dont_downcase_last),
-                        ! NILP (can_return_switch_frame), 0);
-
-#ifdef HAVE_WINDOW_SYSTEM
-  if (display_hourglass_p)
-    start_hourglass ();
-#endif
-
-  if (i == -1)
-    {
-      Vquit_flag = Qt;
-      QUIT;
-    }
-  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 `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;
-      KVAR (current_kboard, Vprefix_arg) = Qnil;
-    }
-  else
-    prefixarg = Qnil;
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
+       doc: /* Read a sequence of keystrokes and return as a string or vector.
+The sequence is sufficient to specify a non-prefix command in the
+current local and global maps.
 
-  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);
-       }
-    }
+First arg PROMPT is a prompt string.  If nil, do not prompt specially.
+Second (optional) arg CONTINUE-ECHO, if non-nil, means this key echos
+as a continuation of the previous key.
 
-  while (1)
-    {
-      final = Findirect_function (cmd, Qnil);
+The third (optional) arg DONT-DOWNCASE-LAST, if non-nil, means do not
+convert the last event to lower case.  (Normally any upper case event
+is converted to lower case if the original event is undefined and the lower
+case equivalent is defined.)  A non-nil value is appropriate for reading
+a key sequence to be defined.
 
-      if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
-       {
-         struct gcpro gcpro1, gcpro2;
+A C-g typed while in this function is treated like any other character,
+and `quit-flag' is not set.
 
-         GCPRO2 (cmd, prefixarg);
-         do_autoload (final, cmd);
-         UNGCPRO;
-       }
-      else
-       break;
-    }
+If the key sequence starts with a mouse click, then the sequence is read
+using the keymaps of the buffer of the window clicked in, not the buffer
+of the selected window as normal.
 
-  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);
+`read-key-sequence' drops unbound button-down events, since you normally
+only care about the click or drag events which follow them.  If a drag
+or multi-click event is unbound, but the corresponding click event would
+be bound, `read-key-sequence' turns the event into a click event at the
+drag's starting position.  This means that you don't have to distinguish
+between click and drag, double, or triple events unless you want to.
 
-         /* 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);
-           }
-       }
+`read-key-sequence' prefixes mouse events on mode lines, the vertical
+lines separating windows, and scroll bars with imaginary keys
+`mode-line', `vertical-line', and `vertical-scroll-bar'.
 
-      return Fexecute_kbd_macro (final, prefixarg, Qnil);
-    }
+Optional fourth argument CAN-RETURN-SWITCH-FRAME non-nil means that this
+function will process a switch-frame event if the user switches frames
+before typing anything.  If the user switches frames in the middle of a
+key sequence, or at the start of the sequence but CAN-RETURN-SWITCH-FRAME
+is nil, then the event will be put off until after the current key sequence.
 
-  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);
+`read-key-sequence' checks `function-key-map' for function key
+sequences, where they wouldn't conflict with ordinary bindings.  See
+`function-key-map' for more details.
 
-  return Qnil;
+The optional fifth argument CMD-LOOP, if non-nil, means
+that this key sequence is being read by something that will
+read commands one after another.  It should be nil if the caller
+will read just one key sequence.  */)
+  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
+{
+  return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
+                              can_return_switch_frame, cmd_loop, true);
 }
 
-
+DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
+       Sread_key_sequence_vector, 1, 5, 0,
+       doc: /* Like `read-key-sequence' but always return a vector.  */)
+  (Lisp_Object prompt, Lisp_Object continue_echo, Lisp_Object dont_downcase_last, Lisp_Object can_return_switch_frame, Lisp_Object cmd_loop)
+{
+  return read_key_sequence_vs (prompt, continue_echo, dont_downcase_last,
+                              can_return_switch_frame, cmd_loop, false);
+}
 \f
-/* Return nonzero if input events are pending.  */
+/* Return true if input events are pending.  */
 
-int
+bool
 detect_input_pending (void)
 {
-  if (!input_pending)
-    get_input_pending (&input_pending, 0);
-
-  return input_pending;
+  return input_pending || get_input_pending (0);
 }
 
-/* Return nonzero if input events other than mouse movements are
+/* Return true if input events other than mouse movements are
    pending.  */
 
-int
+bool
 detect_input_pending_ignore_squeezables (void)
 {
-  if (!input_pending)
-    get_input_pending (&input_pending, READABLE_EVENTS_IGNORE_SQUEEZABLES);
-
-  return input_pending;
+  return input_pending || get_input_pending (READABLE_EVENTS_IGNORE_SQUEEZABLES);
 }
 
-/* Return nonzero if input events are pending, and run any pending timers.  */
+/* Return true if input events are pending, and run any pending timers.  */
 
-int
-detect_input_pending_run_timers (int do_display)
+bool
+detect_input_pending_run_timers (bool do_display)
 {
-  int old_timers_run = timers_run;
+  unsigned old_timers_run = timers_run;
 
   if (!input_pending)
-    get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
+    get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
 
   if (old_timers_run != timers_run && do_display)
     {
@@ -10418,16 +9902,16 @@ clear_input_pending (void)
   input_pending = 0;
 }
 
-/* Return nonzero if there are pending requeued events.
+/* Return true if there are pending requeued events.
    This isn't used yet.  The hope is to make wait_reading_process_output
    call it, and return if it runs Lisp code that unreads something.
    The problem is, kbd_buffer_get_event needs to be fixed to know what
    to do in that case.  It isn't trivial.  */
 
-int
+bool
 requeued_events_pending_p (void)
 {
-  return (!NILP (Vunread_command_events) || unread_command_char != -1);
+  return (!NILP (Vunread_command_events));
 }
 
 
@@ -10437,7 +9921,7 @@ Actually, the value is nil only if we can be sure that no input is available;
 if there is a doubt, the value is t.  */)
   (void)
 {
-  if (!NILP (Vunread_command_events) || unread_command_char != -1
+  if (!NILP (Vunread_command_events)
       || !NILP (Vunread_post_input_method_events)
       || !NILP (Vunread_input_method_events))
     return (Qt);
@@ -10445,10 +9929,9 @@ if there is a doubt, the value is t.  */)
   /* Process non-user-visible events (Bug#10195).  */
   process_special_events ();
 
-  get_input_pending (&input_pending,
-                    READABLE_EVENTS_DO_TIMERS_NOW
-                    | READABLE_EVENTS_FILTER_EVENTS);
-  return input_pending > 0 ? Qt : Qnil;
+  return (get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW
+                            | READABLE_EVENTS_FILTER_EVENTS)
+         ? Qt : Qnil);
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
@@ -10463,10 +9946,10 @@ DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
   else
     {
       val = Fvector (NUM_RECENT_KEYS, keys);
-      memcpy (XVECTOR (val)->contents, keys + recent_keys_index,
-             (NUM_RECENT_KEYS - recent_keys_index) * sizeof (Lisp_Object));
-      memcpy (XVECTOR (val)->contents + NUM_RECENT_KEYS - recent_keys_index,
-             keys, recent_keys_index * sizeof (Lisp_Object));
+      vcopy (val, 0, keys + recent_keys_index,
+            NUM_RECENT_KEYS - recent_keys_index);
+      vcopy (val, NUM_RECENT_KEYS - recent_keys_index,
+            keys, recent_keys_index);
       return val;
     }
 }
@@ -10568,7 +10051,7 @@ KEEP-RECORD is non-nil.  */)
   if (NILP (keep_record))
     {
       for (i = 0; i < ASIZE (recent_keys); ++i)
-       XVECTOR (recent_keys)->contents[i] = Qnil;
+       ASET (recent_keys, i, Qnil);
       total_keys = 0;
       recent_keys_index = 0;
     }
@@ -10595,17 +10078,17 @@ The file will be closed when Emacs exits.  */)
 {
   if (dribble)
     {
-      BLOCK_INPUT;
+      block_input ();
       fclose (dribble);
-      UNBLOCK_INPUT;
+      unblock_input ();
       dribble = 0;
     }
   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;
 }
@@ -10622,10 +10105,7 @@ Also end any kbd macro being defined.  */)
       end_kbd_macro ();
     }
 
-  update_mode_lines++;
-
   Vunread_command_events = Qnil;
-  unread_command_char = -1;
 
   discard_tty_input ();
 
@@ -10671,8 +10151,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 ();
@@ -10737,7 +10216,7 @@ stuff_buffered_input (Lisp_Object stuffstring)
 }
 \f
 void
-set_waiting_for_input (struct timeval *time_to_clear)
+set_waiting_for_input (struct timespec *time_to_clear)
 {
   input_available_clear_time = time_to_clear;
 
@@ -10765,17 +10244,10 @@ clear_waiting_for_input (void)
    Otherwise, tell QUIT to kill Emacs.  */
 
 static void
-interrupt_signal (int signalnum)       /* If we don't have an argument, some */
-                                       /* compilers complain in signal calls.  */
+handle_interrupt_signal (int sig)
 {
-  /* Must preserve main program's value of errno.  */
-  int old_errno = errno;
-  struct terminal *terminal;
-
-  SIGNAL_THREAD_CHECK (signalnum);
-
   /* See if we have an active terminal on our controlling tty.  */
-  terminal = get_named_tty ("/dev/tty");
+  struct terminal *terminal = get_named_tty ("/dev/tty");
   if (!terminal)
     {
       /* If there are no frames there, let's pretend that we are a
@@ -10794,16 +10266,21 @@ interrupt_signal (int signalnum)      /* If we don't have an argument, some */
          from the controlling tty.  */
       internal_last_event_frame = terminal->display_info.tty->top_frame;
 
-      handle_interrupt ();
+      handle_interrupt (1);
     }
+}
 
-  errno = old_errno;
+static void
+deliver_interrupt_signal (int sig)
+{
+  deliver_process_signal (sig, handle_interrupt_signal);
 }
 
+
 /* If Emacs is stuck because `inhibit-quit' is true, then keep track
    of the number of times C-g has been requested.  If C-g is pressed
    enough times, then quit anyway.  See bug#6585.  */
-static int force_quit_count;
+static int volatile force_quit_count;
 
 /* This routine is called at interrupt level in response to C-g.
 
@@ -10817,7 +10294,7 @@ static int force_quit_count;
    non-nil, it stops the job right away.  */
 
 static void
-handle_interrupt (void)
+handle_interrupt (bool in_signal_handler)
 {
   char c;
 
@@ -10826,15 +10303,21 @@ handle_interrupt (void)
   /* XXX This code needs to be revised for multi-tty support.  */
   if (!NILP (Vquit_flag) && get_named_tty ("/dev/tty"))
     {
-      /* If SIGINT isn't blocked, don't let us be interrupted by
-        another SIGINT, it might be harmful due to non-reentrancy
-        in I/O functions.  */
-      sigblock (sigmask (SIGINT));
+      if (! in_signal_handler)
+       {
+         /* If SIGINT isn't blocked, don't let us be interrupted by
+            a SIGINT.  It might be harmful due to non-reentrancy
+            in I/O functions.  */
+         sigset_t blocked;
+         sigemptyset (&blocked);
+         sigaddset (&blocked, SIGINT);
+         pthread_sigmask (SIG_BLOCK, &blocked, 0);
+       }
 
       fflush (stdout);
       reset_all_sys_modes ();
 
-#ifdef SIGTSTP                 /* Support possible in later USG versions */
+#ifdef SIGTSTP
 /*
  * On systems which can suspend the current process and return to the original
  * shell, this command causes the user to end up back at the shell.
@@ -10891,7 +10374,7 @@ handle_interrupt (void)
 #endif /* not MSDOS */
       fflush (stdout);
       if (((c = getchar ()) & ~040) == 'Y')
-       abort ();
+       emacs_abort ();
       while (c != '\n') c = getchar ();
 #ifdef MSDOS
       printf ("\r\nContinuing...\r\n");
@@ -10900,7 +10383,6 @@ handle_interrupt (void)
 #endif /* not MSDOS */
       fflush (stdout);
       init_all_sys_modes ();
-      sigfree ();
     }
   else
     {
@@ -10913,20 +10395,19 @@ handle_interrupt (void)
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
          immediate_quit = 0;
-          sigfree ();
+         pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
          saved = gl_state;
          GCPRO4 (saved.object, saved.global_code,
                  saved.current_syntax_table, saved.old_prop);
          Fsignal (Qquit, Qnil);
-         /* FIXME: AFAIK, `quit' can never return, so this code is dead!  */
          gl_state = saved;
          UNGCPRO;
        }
       else
         { /* Else request quit when it's safe.  */
-          if (NILP (Vquit_flag))
-           force_quit_count = 0;
-         if (++force_quit_count == 3)
+         int count = NILP (Vquit_flag) ? 1 : force_quit_count + 1;
+         force_quit_count = count;
+         if (count == 3)
             {
               immediate_quit = 1;
               Vinhibit_quit = Qnil;
@@ -10935,6 +10416,8 @@ handle_interrupt (void)
         }
     }
 
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+
 /* TODO: The longjmp in this call throws the NS event loop integration off,
          and it seems to do fine without this.  Probably some attention
         needs to be paid to the setting of waiting_for_input in
@@ -10944,43 +10427,32 @@ handle_interrupt (void)
          separate event loop thread like W32.  */
 #ifndef HAVE_NS
   if (waiting_for_input && !echoing)
-      quit_throw_to_read_char (1);
+    quit_throw_to_read_char (in_signal_handler);
 #endif
 }
 
 /* Handle a C-g by making read_char return C-g.  */
 
 static void
-quit_throw_to_read_char (int from_signal)
+quit_throw_to_read_char (bool from_signal)
 {
   /* When not called from a signal handler it is safe to call
      Lisp.  */
   if (!from_signal && EQ (Vquit_flag, Qkill_emacs))
     Fkill_emacs (Qnil);
 
-  sigfree ();
   /* Prevent another signal from doing this before we finish.  */
   clear_waiting_for_input ();
   input_pending = 0;
 
   Vunread_command_events = Qnil;
-  unread_command_char = -1;
 
-#if 0 /* Currently, sit_for is called from read_char without turning
-        off polling.  And that can call set_waiting_for_input.
-        It seems to be harmless.  */
-#ifdef POLL_FOR_INPUT
-  /* May be > 1 if in recursive minibuffer.  */
-  if (poll_suppress_count == 0)
-    abort ();
-#endif
-#endif
   if (FRAMEP (internal_last_event_frame)
       && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     0, 0, Qnil);
 
-  _longjmp (getcjmp, 1);
+  sys_longjmp (getcjmp, 1);
 }
 \f
 DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode,
@@ -10992,9 +10464,8 @@ otherwise Emacs uses CBREAK mode.
 See also `current-input-mode'.  */)
   (Lisp_Object interrupt)
 {
-  int new_interrupt_input;
-#ifdef SIGIO
-/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+  bool new_interrupt_input;
+#ifdef USABLE_SIGIO
 #ifdef HAVE_X_WINDOWS
   if (x_display_list != NULL)
     {
@@ -11005,9 +10476,9 @@ See also `current-input-mode'.  */)
   else
 #endif /* HAVE_X_WINDOWS */
     new_interrupt_input = !NILP (interrupt);
-#else /* not SIGIO */
+#else /* not USABLE_SIGIO */
   new_interrupt_input = 0;
-#endif /* not SIGIO */
+#endif /* not USABLE_SIGIO */
 
   if (new_interrupt_input != interrupt_input)
     {
@@ -11051,7 +10522,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
 
@@ -11228,11 +10699,8 @@ The `posn-' functions access elements of such lists.  */)
 
   if (WINDOWP (frame_or_window))
     {
-      struct window *w;
+      struct window *w = decode_live_window (frame_or_window);
 
-      CHECK_LIVE_WINDOW (frame_or_window);
-
-      w = XWINDOW (frame_or_window);
       XSETINT (x, (XINT (x)
                   + WINDOW_LEFT_EDGE_X (w)
                   + (NILP (whole)
@@ -11287,30 +10755,30 @@ The `posn-' functions access elements of such lists.  */)
 void
 init_kboard (KBOARD *kb)
 {
-  KVAR (kb, Voverriding_terminal_local_map) = Qnil;
-  KVAR (kb, Vlast_command) = Qnil;
-  KVAR (kb, Vreal_last_command) = Qnil;
-  KVAR (kb, Vkeyboard_translate_table) = Qnil;
-  KVAR (kb, Vlast_repeatable_command) = Qnil;
-  KVAR (kb, Vprefix_arg) = Qnil;
-  KVAR (kb, Vlast_prefix_arg) = Qnil;
-  KVAR (kb, kbd_queue) = Qnil;
+  kset_overriding_terminal_local_map (kb, Qnil);
+  kset_last_command (kb, Qnil);
+  kset_real_last_command (kb, Qnil);
+  kset_keyboard_translate_table (kb, Qnil);
+  kset_last_repeatable_command (kb, Qnil);
+  kset_prefix_arg (kb, Qnil);
+  kset_last_prefix_arg (kb, Qnil);
+  kset_kbd_queue (kb, Qnil);
   kb->kbd_queue_has_data = 0;
   kb->immediate_echo = 0;
-  KVAR (kb, echo_string) = Qnil;
+  kset_echo_string (kb, Qnil);
   kb->echo_after_prompt = -1;
   kb->kbd_macro_buffer = 0;
   kb->kbd_macro_bufsize = 0;
-  KVAR (kb, defining_kbd_macro) = Qnil;
-  KVAR (kb, Vlast_kbd_macro) = Qnil;
+  kset_defining_kbd_macro (kb, Qnil);
+  kset_last_kbd_macro (kb, Qnil);
   kb->reference_count = 0;
-  KVAR (kb, Vsystem_key_alist) = Qnil;
-  KVAR (kb, system_key_syms) = Qnil;
-  KVAR (kb, Vwindow_system) = Qt;      /* Unset.  */
-  KVAR (kb, Vinput_decode_map) = Fmake_sparse_keymap (Qnil);
-  KVAR (kb, Vlocal_function_key_map) = Fmake_sparse_keymap (Qnil);
+  kset_system_key_alist (kb, Qnil);
+  kset_system_key_syms (kb, Qnil);
+  kset_window_system (kb, Qt); /* Unset.  */
+  kset_input_decode_map (kb, Fmake_sparse_keymap (Qnil));
+  kset_local_function_key_map (kb, Fmake_sparse_keymap (Qnil));
   Fset_keymap_parent (KVAR (kb, Vlocal_function_key_map), Vfunction_key_map);
-  KVAR (kb, Vdefault_minibuffer_frame) = Qnil;
+  kset_default_minibuffer_frame (kb, Qnil);
 }
 
 /*
@@ -11333,7 +10801,7 @@ delete_kboard (KBOARD *kb)
 
   for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
     if (*kbp == NULL)
-      abort ();
+      emacs_abort ();
   *kbp = kb->next_kboard;
 
   /* Prevent a dangling reference to KB.  */
@@ -11344,7 +10812,7 @@ delete_kboard (KBOARD *kb)
       current_kboard = FRAME_KBOARD (XFRAME (selected_frame));
       single_kboard = 0;
       if (current_kboard == kb)
-       abort ();
+       emacs_abort ();
     }
 
   wipe_kboard (kb);
@@ -11354,26 +10822,20 @@ delete_kboard (KBOARD *kb)
 void
 init_keyboard (void)
 {
-  /* This is correct before outermost invocation of the editor loop */
+  /* This is correct before outermost invocation of the editor loop */
   command_loop_level = -1;
   immediate_quit = 0;
   quit_char = Ctl ('g');
   Vunread_command_events = Qnil;
-  unread_command_char = -1;
-  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+  timer_idleness_start_time = invalid_timespec ();
   total_keys = 0;
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   do_mouse_tracking = Qnil;
-#endif
   input_pending = 0;
   interrupt_input_blocked = 0;
-  interrupt_input_pending = 0;
-#ifdef SYNC_INPUT
   pending_signals = 0;
-#endif
 
   /* This means that command_loop_1 won't try to select anything the first
      time through.  */
@@ -11386,28 +10848,33 @@ init_keyboard (void)
   init_kboard (current_kboard);
   /* A value of nil for Vwindow_system normally means a tty, but we also use
      it for the initial terminal since there is no window system there.  */
-  KVAR (current_kboard, Vwindow_system) = Qnil;
+  kset_window_system (current_kboard, Qnil);
 
   if (!noninteractive)
     {
       /* Before multi-tty support, these handlers used to be installed
          only if the current session was a tty session.  Now an Emacs
          session may have multiple display types, so we always handle
-         SIGINT.  There is special code in interrupt_signal to exit
+         SIGINT.  There is special code in handle_interrupt_signal to exit
          Emacs on SIGINT when there are no termcap frames on the
          controlling terminal.  */
-      signal (SIGINT, interrupt_signal);
+      struct sigaction action;
+      emacs_sigaction_init (&action, deliver_interrupt_signal);
+      sigaction (SIGINT, &action, 0);
 #ifndef DOS_NT
       /* For systems with SysV TERMIO, C-g is set up for both SIGINT and
         SIGQUIT and we can't tell which one it will give us.  */
-      signal (SIGQUIT, interrupt_signal);
+      sigaction (SIGQUIT, &action, 0);
 #endif /* not DOS_NT */
     }
-/* Note SIGIO has been undef'd if FIONREAD is missing.  */
-#ifdef SIGIO
+#ifdef USABLE_SIGIO
   if (!noninteractive)
-    signal (SIGIO, input_available_signal);
-#endif /* SIGIO */
+    {
+      struct sigaction action;
+      emacs_sigaction_init (&action, deliver_input_available_signal);
+      sigaction (SIGIO, &action, 0);
+    }
+#endif
 
 /* Use interrupt input by default, if it works and noninterrupt input
    has deficiencies.  */
@@ -11418,7 +10885,7 @@ init_keyboard (void)
   interrupt_input = 0;
 #endif
 
-  sigfree ();
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
   dribble = 0;
 
   if (keyboard_init_hook)
@@ -11443,6 +10910,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},
@@ -11457,7 +10926,7 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = make_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_pure_c_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
   /* Tool-bars.  */
@@ -11473,9 +10942,6 @@ syms_of_keyboard (void)
   staticpro (&tool_bar_items_vector);
   tool_bar_items_vector = Qnil;
 
-  staticpro (&real_this_command);
-  real_this_command = Qnil;
-
   DEFSYM (Qtimer_event_handler, "timer-event-handler");
   DEFSYM (Qdisabled_command_function, "disabled-command-function");
   DEFSYM (Qself_insert_command, "self-insert-command");
@@ -11494,7 +10960,7 @@ syms_of_keyboard (void)
   DEFSYM (Qconfig_changed_event, "config-changed-event");
   DEFSYM (Qmenu_enable, "menu-enable");
 
-#if defined (WINDOWSNT)
+#ifdef HAVE_NTGUI
   DEFSYM (Qlanguage_change, "language-change");
 #endif
 
@@ -11502,6 +10968,10 @@ syms_of_keyboard (void)
   DEFSYM (Qdbus_event, "dbus-event");
 #endif
 
+#ifdef USE_FILE_NOTIFY
+  DEFSYM (Qfile_notify, "file-notify");
+#endif /* USE_FILE_NOTIFY */
+
   DEFSYM (QCenable, ":enable");
   DEFSYM (QCvisible, ":visible");
   DEFSYM (QChelp, ":help");
@@ -11519,9 +10989,7 @@ syms_of_keyboard (void)
   DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
   DEFSYM (Qmenu_bar, "menu-bar");
 
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   DEFSYM (Qmouse_fixup_help_message, "mouse-fixup-help-message");
-#endif
 
   DEFSYM (Qabove_handle, "above-handle");
   DEFSYM (Qhandle, "handle");
@@ -11557,9 +11025,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]);
@@ -11570,7 +11035,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));
       }
   }
 
@@ -11590,7 +11055,7 @@ syms_of_keyboard (void)
     modifier_symbols = Fmake_vector (make_number (len), Qnil);
     for (i = 0; i < len; i++)
       if (modifier_names[i])
-       XVECTOR (modifier_symbols)->contents[i] = intern_c_string (modifier_names[i]);
+       ASET (modifier_symbols, i, intern_c_string (modifier_names[i]));
     staticpro (&modifier_symbols);
   }
 
@@ -11603,8 +11068,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);
@@ -11641,11 +11105,8 @@ syms_of_keyboard (void)
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
   defsubr (&Srecursive_edit);
-#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
   defsubr (&Strack_mouse);
-#endif
   defsubr (&Sinput_pending_p);
-  defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
   defsubr (&Sthis_command_keys_vector);
@@ -11689,9 +11150,6 @@ as they will already have been added once as they were read for the first time.
 An element of the form (t . EVENT) forces EVENT to be added to that list.  */);
   Vunread_command_events = Qnil;
 
-  DEFVAR_INT ("unread-command-char", unread_command_char,
-             doc: /* If not -1, an object to be read as next command input event.  */);
-
   DEFVAR_LISP ("unread-post-input-method-events", Vunread_post_input_method_events,
               doc: /* List of events to be processed as input by input methods.
 These events are processed before `unread-command-events'
@@ -11729,12 +11187,14 @@ was a kill command.
 See Info node `(elisp)Multiple Terminals'.  */);
 
   DEFVAR_KBOARD ("real-last-command", Vreal_last_command,
-                doc: /* Same as `last-command', but never altered by Lisp code.  */);
+                doc: /* Same as `last-command', but never altered by Lisp code.
+Taken from the previous value of `real-this-command'.  */);
 
   DEFVAR_KBOARD ("last-repeatable-command", Vlast_repeatable_command,
                 doc: /* Last command that may be repeated.
 The last command executed that was not bound to an input event.
-This is the command `repeat' will try to repeat.  */);
+This is the command `repeat' will try to repeat.
+Taken from a previous value of `real-this-command'.  */);
 
   DEFVAR_LISP ("this-command", Vthis_command,
               doc: /* The command now being executed.
@@ -11742,6 +11202,10 @@ The command can set this variable; whatever is put here
 will be in `last-command' during the following command.  */);
   Vthis_command = Qnil;
 
+  DEFVAR_LISP ("real-this-command", Vreal_this_command,
+              doc: /* This is like `this-command', except that commands should never modify it.  */);
+  Vreal_this_command = Qnil;
+
   DEFVAR_LISP ("this-command-keys-shift-translated",
               Vthis_command_keys_shift_translated,
               doc: /* Non-nil if the key sequence activating this command was shift-translated.
@@ -11800,10 +11264,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.
@@ -11947,10 +11407,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.
@@ -11960,7 +11417,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;
@@ -11973,7 +11430,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.  */);
@@ -12031,9 +11488,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.
@@ -12045,9 +11500,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,
@@ -12172,8 +11626,8 @@ This takes effect only when Transient Mark mode is enabled.  */);
               Vsaved_region_selection,
               doc: /* Contents of active region prior to buffer modification.
 If `select-active-regions' is non-nil, Emacs sets this to the
-text in the region before modifying the buffer.  The next
-`deactivate-mark' call uses this to set the window selection.  */);
+text in the region before modifying the buffer.  The next call to
+the function `deactivate-mark' uses this to set the window selection.  */);
   Vsaved_region_selection = Qnil;
 
   DEFVAR_LISP ("selection-inhibit-update-commands",
@@ -12198,7 +11652,7 @@ variable are `sigusr1' and `sigusr2'.  */);
   Vdebug_on_event = intern_c_string ("sigusr2");
 
   /* Create the initial keyboard.  */
-  initial_kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
+  initial_kboard = xmalloc (sizeof *initial_kboard);
   init_kboard (initial_kboard);
   /* Vwindow_system is left at t for now.  */
   initial_kboard->next_kboard = all_kboards;
@@ -12259,8 +11713,23 @@ keys_of_keyboard (void)
                            "dbus-handle-event");
 #endif
 
+#ifdef USE_FILE_NOTIFY
+  /* Define a special event which is raised for notification callback
+     functions.  */
+  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");
+#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.
@@ -12299,14 +11768,15 @@ mark_kboards (void)
       {
        if (event == kbd_buffer + KBD_BUFFER_SIZE)
          event = kbd_buffer;
+       /* These two special event types has no Lisp_Objects to mark.  */
        if (event->kind != SELECTION_REQUEST_EVENT
            && event->kind != SELECTION_CLEAR_EVENT)
          {
            mark_object (event->x);
            mark_object (event->y);
+           mark_object (event->frame_or_window);
+           mark_object (event->arg);
          }
-       mark_object (event->frame_or_window);
-       mark_object (event->arg);
       }
   }
 }