]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(command_loop_1): Call start_busy_cursor before
[gnu-emacs] / src / keyboard.c
index 6c068dfd04339a0c6eeaae0f29312bc1f9d9bb6b..ff94b42677cc84ba2d9da1b9f005ce2c53a025a7 100644 (file)
@@ -1,5 +1,6 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000
+     Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,10 +19,8 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* Allow config.h to undefine symbols found here.  */
-#include <signal.h>
-
 #include <config.h>
+#include <signal.h>
 #include <stdio.h>
 #include "termchar.h"
 #include "termopts.h"
@@ -36,8 +35,12 @@ Boston, MA 02111-1307, USA.  */
 #include "disptab.h"
 #include "dispextern.h"
 #include "keyboard.h"
+#include "syntax.h"
 #include "intervals.h"
 #include "blockinput.h"
+#include "puresize.h"
+#include "systime.h"
+#include "atimer.h"
 #include <setjmp.h>
 #include <errno.h>
 
@@ -53,6 +56,11 @@ Boston, MA 02111-1307, USA.  */
 #include "syssignal.h"
 #include "systty.h"
 
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 /* This is to get the definitions of the XK_ symbols.  */
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -82,7 +90,12 @@ extern int input_fd;
 
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
+#ifdef macintosh
+/* But not too big (local data > 32K error) if on macintosh */
+#define KBD_BUFFER_SIZE 512
+#else
 #define KBD_BUFFER_SIZE 4096
+#endif
 #else  /* No X-windows, character input */
 #define KBD_BUFFER_SIZE 256
 #endif /* No X-windows */
@@ -126,6 +139,22 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* This vector is used as a buffer to record the events that were actually read
+   by read_key_sequence.  */
+Lisp_Object raw_keybuf;
+int raw_keybuf_count;
+
+#define GROW_RAW_KEYBUF                                                        \
+if (raw_keybuf_count == XVECTOR (raw_keybuf)->size)                    \
+  {                                                                    \
+    int newsize = 2 * XVECTOR (raw_keybuf)->size;                      \
+    Lisp_Object new;                                                   \
+    new = Fmake_vector (make_number (newsize), Qnil);                  \
+    bcopy (XVECTOR (raw_keybuf)->contents, XVECTOR (new)->contents,    \
+          raw_keybuf_count * sizeof (Lisp_Object));                    \
+    raw_keybuf = new;                                                  \
+  }
+
 /* Number of elements of this_command_keys
    that precede this key sequence.  */
 int this_single_command_key_start;
@@ -144,8 +173,15 @@ static int before_command_restore_flag;
 
 extern int minbuf_level;
 
+extern int message_enable_multibyte;
+
 extern struct backtrace *backtrace_list;
 
+/* If non-nil, the function that implements the display of help.
+   It's called with one argument, the help string to display.  */
+
+Lisp_Object Vshow_help_function;
+
 /* Nonzero means do menu prompting.  */
 static int menu_prompting;
 
@@ -159,11 +195,20 @@ static jmp_buf getcjmp;
 int waiting_for_input;
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
+
 static int echoing;
 
-/* True means we can start echoing at the next input pause
-   even though there is something in the echo area.  */
-static char *ok_to_echo_at_next_pause;
+/* Non-null means we can start echoing at the next input pause even
+   though there is something in the echo area.  */
+
+static struct kboard *ok_to_echo_at_next_pause;
+
+/* The kboard currently echoing, or null for none.  Set in echo_now to
+   the kboard echoing.  Reset to 0 in cancel_echoing.  If non-null,
+   and a current echo area message exists, we know that it comes from
+   echoing.  */
+
+static struct kboard *echo_kboard;
 
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
@@ -245,6 +290,14 @@ Lisp_Object last_input_char;
 /* If not Qnil, a list of objects to be read as subsequent command input.  */
 Lisp_Object Vunread_command_events;
 
+/* If not Qnil, a list of objects to be read as subsequent command input
+   including input method processing.  */
+Lisp_Object Vunread_input_method_events;
+
+/* If not Qnil, a list of objects to be read as subsequent command input
+   but NOT including input method processing.  */
+Lisp_Object Vunread_post_input_method_events;
+
 /* If not -1, an event to be read as subsequent command input.  */
 int unread_command_char;
 
@@ -289,7 +342,10 @@ int last_auto_save;
 /* The command being executed by the command loop.
    Commands may set this, and the value set will be copied into
    current_kboard->Vlast_command instead of the actual command.  */
-Lisp_Object this_command;
+Lisp_Object Vthis_command;
+
+/* 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 executed.  */
 int last_point_position;
@@ -323,6 +379,9 @@ Lisp_Object Qtimer_event_handler;
    key sequence that it reads.  */
 Lisp_Object read_key_sequence_cmd;
 
+/* Echo unfinished commands after this many seconds of pause.  */
+Lisp_Object Vecho_keystrokes;
+
 /* Form to evaluate (if non-nil) when Emacs is started.  */
 Lisp_Object Vtop_level;
 
@@ -336,6 +395,14 @@ extern Lisp_Object Vfunction_key_map;
    This one takes precedence over ordinary definitions.  */
 extern Lisp_Object Vkey_translation_map;
 
+/* If non-nil, this implements the current input method.  */
+Lisp_Object Vinput_method_function;
+Lisp_Object Qinput_method_function;
+
+/* When we call Vinput_method_function,
+   this holds the echo area message that was just erased.  */
+Lisp_Object Vinput_method_previous_message;
+
 /* Non-nil means deactivate the mark at end of this command.  */
 Lisp_Object Vdeactivate_mark;
 
@@ -364,6 +431,9 @@ Lisp_Object Vdeferred_action_list;
 Lisp_Object Vdeferred_action_function;
 Lisp_Object Qdeferred_action_function;
 
+Lisp_Object Qinput_method_exit_on_first_char;
+Lisp_Object Qinput_method_use_echo_area;
+
 /* File in which we write all commands we read.  */
 FILE *dribble;
 
@@ -417,7 +487,7 @@ static struct input_event *kbd_fetch_ptr;
 /* Pointer to next place to store character in kbd_buffer.  This
    may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
    character should go in kbd_buffer[0].  */
-static volatile struct input_event *kbd_store_ptr;
+static struct input_event * volatile kbd_store_ptr;
 
 /* The above pair of variables forms a "queue empty" flag.  When we
    enqueue a non-hook event, we increment kbd_store_ptr.  When we
@@ -440,17 +510,29 @@ Lisp_Object Qswitch_frame;
 Lisp_Object Qdelete_frame;
 Lisp_Object Qiconify_frame;
 Lisp_Object Qmake_frame_visible;
+Lisp_Object Qhelp_echo;
 
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
+#ifdef WINDOWSNT
+Lisp_Object Qmouse_wheel;
+Lisp_Object Qlanguage_change;
+#endif
+Lisp_Object Qdrag_n_drop;
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
 Lisp_Object Qevent_kind;
 Lisp_Object Qevent_symbol_elements;
 
+/* menu item parts */
+Lisp_Object Qmenu_alias;
 Lisp_Object Qmenu_enable;
+Lisp_Object QCenable, QCvisible, QChelp, QCfilter, QCkeys, QCkey_sequence;
+Lisp_Object QCbutton, QCtoggle, QCradio;
+extern Lisp_Object Vdefine_key_rebound_commands;
+extern Lisp_Object Qmenu_item;
 
 /* An event header symbol HEAD may have a property named
    Qevent_symbol_element_mask, which is of the form (BASE MODIFIERS);
@@ -471,19 +553,17 @@ Lisp_Object Qvertical_line;
 Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 
-extern Lisp_Object Qmenu_enable;
-
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
 EMACS_TIME timer_check ();
 
+extern Lisp_Object Vhistory_length;
+
 extern char *x_get_keysym_name ();
 
 static void record_menu_key ();
 
-void swallow_events ();
-
 Lisp_Object Qpolling_period;
 
 /* List of absolute timers.  Appears in order of next scheduled event.  */
@@ -529,6 +609,17 @@ int flow_control;
 #ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
+
+/* After a command is executed, if point is moved into a region that
+   has specific properties (e.g. composition, display), we adjust
+   point to the boundary of the region.  But, if a command sets this
+   valiable to non-nil, we suppress this point adjustment.  This
+   variable is set to nil before reading a command.  */
+Lisp_Object Vdisable_point_adjustment;
+
+/* If non-nil, always disable point adjustment.  */
+Lisp_Object Vglobal_disable_point_adjustment;
+
 \f
 /* Global variable declarations.  */
 
@@ -547,9 +638,9 @@ static Lisp_Object make_lispy_movement ();
 static Lisp_Object modify_event_symbol ();
 static Lisp_Object make_lispy_switch_frame ();
 static int parse_solitary_modifier ();
-
-/* > 0 if we are to echo keystrokes.  */
-static int echo_keystrokes;
+static void save_getcjmp ();
+static void restore_getcjmp ();
+static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 
 /* Nonzero means don't try to suspend even if the operating system seems
    to support it.  */
@@ -562,6 +653,7 @@ static int cannot_suspend;
    so that it serves as a prompt for the next character.
    Also start echoing.  */
 
+void
 echo_prompt (str)
      char *str;
 {
@@ -582,6 +674,7 @@ echo_prompt (str)
    C can be a character, which is printed prettily ("M-C-x" and all that
    jazz), or a symbol, whose name is printed.  */
 
+void
 echo_char (c)
      Lisp_Object c;
 {
@@ -599,7 +692,8 @@ echo_char (c)
 
       if (INTEGERP (c))
        {
-         if (ptr - current_kboard->echobuf > ECHOBUFSIZE - 6)
+         if (ptr - current_kboard->echobuf
+             > ECHOBUFSIZE - KEY_DESCRIPTION_SIZE)
            return;
 
          ptr = push_key_description (XINT (c), ptr);
@@ -607,10 +701,11 @@ echo_char (c)
       else if (SYMBOLP (c))
        {
          struct Lisp_String *name = XSYMBOL (c)->name;
-         if ((ptr - current_kboard->echobuf) + name->size + 4 > ECHOBUFSIZE)
+         if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
+             > ECHOBUFSIZE)
            return;
-         bcopy (name->data, ptr, name->size);
-         ptr += name->size;
+         bcopy (name->data, ptr, STRING_BYTES (name));
+         ptr += STRING_BYTES (name);
        }
 
       if (current_kboard->echoptr == current_kboard->echobuf
@@ -630,6 +725,7 @@ echo_char (c)
 /* 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.  */
 
+void
 echo_dash ()
 {
   if (!current_kboard->immediate_echo
@@ -654,6 +750,7 @@ echo_dash ()
 /* Display the current echo string, and begin echoing if not already
    doing so.  */
 
+void
 echo_now ()
 {
   if (!current_kboard->immediate_echo)
@@ -673,7 +770,9 @@ echo_now ()
     }
 
   echoing = 1;
-  message1_nolog (current_kboard->echobuf);
+  echo_kboard = current_kboard;
+  message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
+                 ! NILP (current_buffer->enable_multibyte_characters));
   echoing = 0;
 
   if (waiting_for_input && !NILP (Vquit_flag))
@@ -682,12 +781,14 @@ echo_now ()
 
 /* Turn off echoing, for the start of a new command.  */
 
+void
 cancel_echoing ()
 {
   current_kboard->immediate_echo = 0;
   current_kboard->echoptr = current_kboard->echobuf;
   current_kboard->echo_after_prompt = -1;
   ok_to_echo_at_next_pause = 0;
+  echo_kboard = 0;
 }
 
 /* Return the length of the current echo string.  */
@@ -770,6 +871,7 @@ recursive_edit_1 ()
 
 /* When an auto-save happens, record the "time", and don't do again soon.  */
 
+void
 record_auto_save ()
 {
   last_auto_save = num_nonmacro_input_events;
@@ -777,6 +879,7 @@ record_auto_save ()
 
 /* Make an auto save happen as soon as possible at command level.  */
 
+void
 force_auto_save_soon ()
 {
   last_auto_save = - auto_save_interval - 1;
@@ -793,7 +896,6 @@ This function is called by the editor initialization to begin editing.")
   ()
 {
   int count = specpdl_ptr - specpdl;
-  Lisp_Object val;
 
   command_loop_level++;
   update_mode_lines = 1;
@@ -915,6 +1017,7 @@ cmd_error (data)
   Vexecuting_macro = Qnil;
   executing_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
+  current_kboard->Vlast_prefix_arg = Qnil;
   cancel_echoing ();
 
   /* Avoid unquittable loop if data contains a circular list.  */
@@ -936,22 +1039,41 @@ cmd_error (data)
   return make_number (0);
 }
 
+/* Take actions on handling an error.  DATA is the data that describes
+   the error.
+
+   CONTEXT is a C-string containing ASCII characters only which
+   describes the context in which the error happened.  If we need to
+   generalize CONTEXT to allow multibyte characters, make it a Lisp
+   string.  */
+
+void
 cmd_error_internal (data, context)
      Lisp_Object data;
      char *context;
 {
   Lisp_Object stream;
+  int kill_emacs_p = 0;
+  struct frame *sf = SELECTED_FRAME ();
 
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
-  echo_area_glyphs = 0;
+  clear_message (1, 0);
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're not interactive, it's best to dump this message out
      to stderr and exit.  */
-  if (! FRAME_MESSAGE_BUF (selected_frame)
+  if (!sf->glyphs_initialized_p
+      /* This is the case of the frame dumped with Emacs, when we're
+        running under a window system.  */
+      || (!NILP (Vwindow_system)
+         && !inhibit_window_system
+         && FRAME_TERMCAP_P (sf))
       || noninteractive)
-    stream = Qexternal_debugging_output;
+    {
+      stream = Qexternal_debugging_output;
+      kill_emacs_p = 1;
+    }
   else
     {
       Fdiscard_input ();
@@ -966,8 +1088,7 @@ cmd_error_internal (data, context)
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're in -batch mode, this error should cause Emacs to exit.  */
-  if (! FRAME_MESSAGE_BUF (selected_frame)
-      || noninteractive)
+  if (kill_emacs_p)
     {
       Fterpri (stream);
       Fkill_emacs (make_number (-1));
@@ -987,13 +1108,17 @@ command_loop ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     {
-      return internal_catch (Qexit, command_loop_2, Qnil);
+      Lisp_Object val;
+      val = internal_catch (Qexit, command_loop_2, Qnil);
+      executing_macro = Qnil;
+      return val;
     }
   else
     while (1)
       {
        internal_catch (Qtop_level, top_level_1, Qnil);
        internal_catch (Qtop_level, command_loop_2, Qnil);
+       executing_macro = Qnil;
 
        /* End of file in -batch run causes exit here.  */
        if (noninteractive)
@@ -1071,16 +1196,16 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 Lisp_Object Fcommand_execute ();
 static int read_key_sequence ();
 void safe_run_hooks ();
+static void adjust_point_for_property ();
 
 Lisp_Object
 command_loop_1 ()
 {
-  Lisp_Object cmd, tem;
-  int lose, lose2;
+  Lisp_Object cmd;
+  int lose;
   int nonundocount;
   Lisp_Object keybuf[30];
   int i;
-  int no_redisplay;
   int no_direct;
   int prev_modiff;
   struct buffer *prev_buffer;
@@ -1089,12 +1214,12 @@ command_loop_1 ()
 #endif
 
   current_kboard->Vprefix_arg = Qnil;
+  current_kboard->Vlast_prefix_arg = Qnil;
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
   cancel_echoing ();
 
   nonundocount = 0;
-  no_redisplay = 0;
   this_command_key_count = 0;
   this_single_command_key_start = 0;
 
@@ -1105,22 +1230,33 @@ command_loop_1 ()
   if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
     safe_run_hooks (Qpost_command_hook);
 
+  /* If displaying a message, resize the echo area window to fit
+     that message's size exactly.  */
+  if (!NILP (echo_area_buffer[0]))
+    resize_echo_area_axactly ();
+
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
 
   if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
     {
       if (NILP (Vunread_command_events)
+         && NILP (Vunread_input_method_events)
+         && NILP (Vunread_post_input_method_events)
          && NILP (Vexecuting_macro)
          && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
        safe_run_hooks (Qpost_command_idle_hook);
     }
 
   /* Do this after running Vpost_command_hook, for consistency.  */
-  current_kboard->Vlast_command = this_command;
+  current_kboard->Vlast_command = Vthis_command;
+  current_kboard->Vreal_last_command = real_this_command;
 
   while (1)
     {
+      if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+       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));
@@ -1138,7 +1274,8 @@ command_loop_1 ()
       /* If minibuffer on and echo area in use,
         wait 2 sec and redraw minibuffer.  */
 
-      if (minibuf_level && echo_area_glyphs
+      if (minibuf_level
+         && !NILP (echo_area_buffer[0])
          && EQ (minibuf_window, echo_area_window))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
@@ -1148,7 +1285,7 @@ command_loop_1 ()
 
          Fsit_for (make_number (2), Qnil, Qnil);
          /* Clear the echo area.  */
-         message2 (0, 0);
+         message2 (0, 0, 0);
          safe_run_hooks (Qecho_area_clear_hook);
 
          unbind_to (count, Qnil);
@@ -1172,7 +1309,7 @@ command_loop_1 ()
         code swallows a switch-frame event, we'll fix things up here.
         Is this a good idea?  */
       if (FRAMEP (internal_last_event_frame)
-         && XFRAME (internal_last_event_frame) != selected_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,
@@ -1184,13 +1321,16 @@ command_loop_1 ()
       before_command_key_count = this_command_key_count;
       before_command_echo_length = echo_length ();
 
-      this_command = Qnil;
+      Vthis_command = Qnil;
+      real_this_command = Qnil;
 
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
                             Qnil, 0, 1, 1);
 
       /* 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));
 
@@ -1220,8 +1360,10 @@ command_loop_1 ()
         update the whole window properly.  */
       if (!NILP (XWINDOW (selected_window)->force_start))
        {
+         struct buffer *b;
          XWINDOW (selected_window)->force_start = Qnil;
-         beg_unchanged = end_unchanged = 0;
+         b = XBUFFER (XWINDOW (selected_window)->buffer);
+         BUF_BEG_UNCHANGED (b) = BUF_END_UNCHANGED (b) = 0;
        }
 
       cmd = read_key_sequence_cmd;
@@ -1236,26 +1378,28 @@ command_loop_1 ()
        }
 
       /* Do redisplay processing after this command except in special
-        cases identified below that set no_redisplay to 1.
-        (actually, there's currently no way to prevent the redisplay,
-        and no_redisplay is ignored.
-        Perhaps someday we will really implement it.)  */
-      no_redisplay = 0;
-
+        cases identified below.  */
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
       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
+         (e.g. composition, display).  But, some commands will set
+         this variable differently.  */
+      Vdisable_point_adjustment = Qnil;
+
       /* Execute the command.  */
 
-      this_command = cmd;
+      Vthis_command = cmd;
+      real_this_command = cmd;
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
       if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpre_command_hook);
-
-      if (NILP (this_command))
+      
+      if (NILP (Vthis_command))
        {
          /* nil means key is undefined.  */
          bitch_at_user ();
@@ -1267,14 +1411,17 @@ command_loop_1 ()
        {
          if (NILP (current_kboard->Vprefix_arg) && ! no_direct)
            {
+             /* In case we jump to directly_done.  */
+             Vcurrent_prefix_arg = current_kboard->Vprefix_arg;
+
              /* Recognize some common commands in common situations and
                 do them directly.  */
-             if (EQ (this_command, Qforward_char) && PT < ZV)
+             if (EQ (Vthis_command, Qforward_char) && PT < ZV)
                {
                   struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
-                 lose = FETCH_BYTE (PT);
-                 SET_PT (forward_point (1));
+                 lose = FETCH_CHAR (PT_BYTE);
+                 SET_PT (PT + 1);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
                          ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
@@ -1283,7 +1430,7 @@ command_loop_1 ()
                       : (lose >= 0x20 && lose < 0x7f))
                      /* To extract the case of continuation on
                          wide-column characters.  */
-                     && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT)) == 1)
+                     && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT_BYTE)) == 1)
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1295,15 +1442,15 @@ command_loop_1 ()
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
-                   no_redisplay = direct_output_forward_char (1);
+                   direct_output_forward_char (1);
                  goto directly_done;
                }
-             else if (EQ (this_command, Qbackward_char) && PT > BEGV)
+             else if (EQ (Vthis_command, Qbackward_char) && PT > BEGV)
                {
                   struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
-                 SET_PT (forward_point (-1));
-                 lose = FETCH_BYTE (PT);
+                 SET_PT (PT - 1);
+                 lose = FETCH_CHAR (PT_BYTE);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
                          ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
@@ -1321,16 +1468,15 @@ command_loop_1 ()
                      && !detect_input_pending ()
                      && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
-                   no_redisplay = direct_output_forward_char (-1);
+                   direct_output_forward_char (-1);
                  goto directly_done;
                }
-             else if (EQ (this_command, Qself_insert_command)
+             else if (EQ (Vthis_command, Qself_insert_command)
                       /* Try this optimization only on ascii keystrokes.  */
                       && INTEGERP (last_command_char))
                {
                  unsigned int c = XINT (last_command_char);
                  int value;
-
                  if (NILP (Vexecuting_macro)
                      && !EQ (minibuf_window, selected_window))
                    {
@@ -1341,6 +1487,7 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
+                 
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1353,59 +1500,63 @@ command_loop_1 ()
                          || detect_input_pending ()
                          || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_macro));
+                 
                  value = internal_self_insert (c, 0);
-                 if (value)
-                   lose = 1;
+
                  if (value == 2)
                    nonundocount = 0;
 
-                 if (!lose
-                     && (PT == ZV || FETCH_BYTE (PT) == '\n'))
-                   {
-                     struct Lisp_Char_Table *dp
-                       = window_display_table (XWINDOW (selected_window));
-                     int lose = c;
-
-                     if (dp)
-                       {
-                         Lisp_Object obj;
-
-                         obj = DISP_CHAR_VECTOR (dp, lose);
-                         if (NILP (obj))
-                           {
-                             /* Do it only for char codes
-                                that by default display as themselves.  */
-                             if (lose >= 0x20 && lose <= 0x7e)
-                               no_redisplay = direct_output_for_insert (lose);
-                           }
-                         else if (VECTORP (obj)
-                                  && XVECTOR (obj)->size == 1
-                                  && (obj = XVECTOR (obj)->contents[0],
-                                      INTEGERP (obj))
-                                  /* Insist face not specified in glyph.  */
-                                  && (XINT (obj) & ((-1) << 8)) == 0)
-                           no_redisplay
-                             = direct_output_for_insert (XINT (obj));
-                       }
-                     else
-                       {
-                         if (lose >= 0x20 && lose <= 0x7e)
-                           no_redisplay = direct_output_for_insert (lose);
-                       }
-                   }
+                 /* VALUE == 1 when AFTER-CHANGE functions are
+                    installed which is the case most of the time
+                    because FONT-LOCK installs one.  */
+                 if (!lose && !value)
+                   direct_output_for_insert (c);
                  goto directly_done;
                }
            }
 
          /* Here for a command that isn't executed directly */
 
+#ifdef HAVE_X_WINDOWS
+         if (display_busy_cursor_p)
+           start_busy_cursor ();
+#endif
+
          nonundocount = 0;
          if (NILP (current_kboard->Vprefix_arg))
            Fundo_boundary ();
-         Fcommand_execute (this_command, Qnil, Qnil, Qnil);
+         Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
+#ifdef HAVE_X_WINDOWS
+         if (display_busy_cursor_p)
+           cancel_busy_cursor ();
+#endif
        }
     directly_done: ;
+      current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg;
+
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpost_command_hook);
+
+      /* If displaying a message, resize the echo area window to fit
+        that message's size exactly.  */
+      if (!NILP (echo_area_buffer[0]))
+       resize_echo_area_axactly ();
+
+      if (!NILP (Vdeferred_action_list))
+       safe_run_hooks (Qdeferred_action_function);
+
+      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+       {
+         if (NILP (Vunread_command_events)
+             && NILP (Vunread_input_method_events)
+             && NILP (Vunread_post_input_method_events)
+             && NILP (Vexecuting_macro)
+             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
+           safe_run_hooks (Qpost_command_idle_hook);
+       }
 
       /* If there is a prefix argument,
         1) We don't want Vlast_command to be ``universal-argument''
@@ -1422,28 +1573,13 @@ command_loop_1 ()
         then the above doesn't apply.  */
       if (NILP (current_kboard->Vprefix_arg) || CONSP (last_command_char))
        {
-         current_kboard->Vlast_command = this_command;
+         current_kboard->Vlast_command = Vthis_command;
+         current_kboard->Vreal_last_command = real_this_command;
          cancel_echoing ();
          this_command_key_count = 0;
          this_single_command_key_start = 0;
        }
 
-      /* Note that the value cell will never directly contain nil
-        if the symbol is a local variable.  */
-      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-       safe_run_hooks (Qpost_command_hook);
-
-      if (!NILP (Vdeferred_action_list))
-       safe_run_hooks (Qdeferred_action_function);
-
-      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
-       {
-         if (NILP (Vunread_command_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
-
       if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
@@ -1456,6 +1592,13 @@ command_loop_1 ()
        }
 
     finalize:
+
+      if (current_buffer == prev_buffer
+         && last_point_position != PT
+         && NILP (Vdisable_point_adjustment)
+         && NILP (Vglobal_disable_point_adjustment))
+       adjust_point_for_property (last_point_position);
+
       /* Install chars successfully executed in kbd macro.  */
 
       if (!NILP (current_kboard->defining_kbd_macro)
@@ -1469,6 +1612,53 @@ command_loop_1 ()
     }
 }
 
+extern Lisp_Object Qcomposition, Qdisplay;
+
+/* Adjust point to a boundary of a region that has such a property
+   that should be treated intangible.  For the moment, we check
+   `composition' and `display' property.  LAST_PT is the last position
+   of point.  */
+
+static void
+adjust_point_for_property (last_pt)
+     int last_pt;
+{
+  int start, end;
+  Lisp_Object val;
+  int check_composition = 1, check_display = 1;
+
+  while (check_composition || check_display)
+    {
+      if (check_composition
+         && PT > BEGV && PT < ZV
+         && get_property_and_range (PT, Qcomposition, &val, &start, &end, Qnil)
+         && COMPOSITION_VALID_P (start, end, val)
+         && start < PT && end > PT
+         && (last_pt <= start || last_pt >= end))
+       {
+         if (PT < last_pt)
+           SET_PT (start);
+         else
+           SET_PT (end);
+         check_display = 1;
+       }
+      check_composition = 0;
+      if (check_display
+         && PT > BEGV && PT < ZV
+         && get_property_and_range (PT, Qdisplay, &val, &start, &end, Qnil)
+         && start < PT && end > PT
+         && (last_pt <= start || last_pt >= end))
+       {
+         if (PT < last_pt)
+           SET_PT (start);
+         else
+           SET_PT (end);
+         check_composition = 1;
+       }
+      check_display = 0;
+    }
+}
+
 /* Subroutine for safe_run_hooks: run the hook HOOK.  */
 
 static Lisp_Object
@@ -1495,7 +1685,6 @@ void
 safe_run_hooks (hook)
      Lisp_Object hook;
 {
-  Lisp_Object value;
   int count = specpdl_ptr - specpdl;
   specbind (Qinhibit_quit, hook);
 
@@ -1503,53 +1692,80 @@ safe_run_hooks (hook)
 
   unbind_to (count, Qnil);
 }
+
 \f
-/* Number of seconds between polling for input.  */
+/* Number of seconds between polling for input.  This is a Lisp
+   variable that can be bound.  */
+
 int polling_period;
 
 /* Nonzero means polling for input is temporarily suppressed.  */
+
 int poll_suppress_count;
 
-/* Nonzero if polling_for_input is actually being used.  */
-int polling_for_input;
+/* Asynchronous timer for polling.  */
+
+struct atimer *poll_timer;
+
 
 #ifdef POLL_FOR_INPUT
 
-/* Handle an alarm once each second and read pending input
-   so as to handle a C-g if it comces in.  */
+/* Poll for input, so what we catch a C-g if it comes in.  This
+   function is called from x_make_frame_visible, see comment
+   there.  */
 
-SIGTYPE
-input_poll_signal (signalnum)  /* If we don't have an argument, */
-     int signalnum;            /* some compilers complain in signal calls. */
+void
+poll_for_input_1 ()
 {
-  /* This causes the call to start_polling at the end
-     to do its job.  It also arranges for a quit or error
-     from within read_avail_input to resume polling.  */
-  poll_suppress_count++;
   if (interrupt_input_blocked == 0
       && !waiting_for_input)
     read_avail_input (0);
-  /* Turn on the SIGALRM handler and request another alarm.  */
-  start_polling ();
 }
 
-#endif
+/* Timer callback function for poll_timer.  TIMER is equal to
+   poll_timer.  */
+
+void
+poll_for_input (timer)
+     struct atimer *timer;
+{
+  if (poll_suppress_count == 0)
+    poll_for_input_1 ();
+}
+
+#endif /* POLL_FOR_INPUT */
 
 /* Begin signals to poll for input, if they are appropriate.
    This function is called unconditionally from various places.  */
 
+void
 start_polling ()
 {
 #ifdef POLL_FOR_INPUT
   if (read_socket_hook && !interrupt_input)
     {
-      poll_suppress_count--;
-      if (poll_suppress_count == 0)
+      /* Turn alarm handling on unconditionally.  It might have
+        been turned off in process.c.  */
+      turn_on_atimers (1);
+      
+      /* 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)
        {
-         signal (SIGALRM, input_poll_signal);
-         polling_for_input = 1;
-         alarm (polling_period);
+         EMACS_TIME interval;
+
+         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);
        }
+
+      /* Let the timer's callback function poll for input
+        if this becomes zero.  */
+      --poll_suppress_count;
     }
 #endif
 }
@@ -1568,18 +1784,12 @@ input_polling_used ()
 
 /* Turn off polling.  */
 
+void
 stop_polling ()
 {
 #ifdef POLL_FOR_INPUT
   if (read_socket_hook && !interrupt_input)
-    {
-      if (poll_suppress_count == 0)
-       {
-         polling_for_input = 0;
-         alarm (0);
-       }
-      poll_suppress_count++;
-    }
+    ++poll_suppress_count;
 #endif
 }
 
@@ -1607,6 +1817,7 @@ set_poll_suppress_count (count)
 /* Bind polling_period to a value at least N.
    But don't decrease it.  */
 
+void
 bind_polling_period (n)
      int n;
 {
@@ -1616,6 +1827,7 @@ bind_polling_period (n)
   if (n > new)
     new = n;
 
+  stop_other_atimers (poll_timer);
   stop_polling ();
   specbind (Qpolling_period, make_number (new));
   /* Start a new alarm with the new period.  */
@@ -1682,7 +1894,10 @@ static jmp_buf wrong_kboard_jmpbuf;
    MAPS is an array of keymaps;  NMAPS is the length of MAPS.
 
    PREV_EVENT is the previous input event, or nil if we are reading
-   the first event of a key sequence.
+   the first event of a key sequence (or not reading a key sequence).
+   If PREV_EVENT is t, that is a "magic" value that says
+   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
@@ -1704,34 +1919,38 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   jmp_buf save_jump;
   int key_already_recorded = 0;
   Lisp_Object tem, save;
+  Lisp_Object previous_echo_area_message;
   Lisp_Object also_record;
-  struct gcpro gcpro1;
+  int reread;
+  struct gcpro gcpro1, gcpro2;
 
   also_record = Qnil;
 
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
+  c = Qnil;
+  previous_echo_area_message = Qnil;
 
-  GCPRO1 (c);
+  GCPRO2 (c, previous_echo_area_message);
 
  retry:
 
-  if (CONSP (Vunread_command_events))
+  reread = 0;
+  if (CONSP (Vunread_post_input_method_events))
     {
-      c = XCONS (Vunread_command_events)->car;
-      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+      c = XCAR (Vunread_post_input_method_events);
+      Vunread_post_input_method_events
+       = XCDR (Vunread_post_input_method_events);
 
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
       if (CONSP (c)
-         && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
-         && NILP (XCONS (c)->cdr))
-       c = XCONS (c)->car;
+         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
+         && NILP (XCDR (c)))
+       c = XCAR (c);
 
-      if (this_command_key_count == 0)
-       goto reread_first;
-      else
-       goto reread;
+      reread = 1;
+      goto reread_first;
     }
 
   if (unread_command_char != -1)
@@ -1739,10 +1958,39 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       XSETINT (c, unread_command_char);
       unread_command_char = -1;
 
-      if (this_command_key_count == 0)
-       goto reread_first;
-      else
-       goto reread;
+      reread = 1;
+      goto reread_first;
+    }
+
+  if (CONSP (Vunread_command_events))
+    {
+      c = XCAR (Vunread_command_events);
+      Vunread_command_events = XCDR (Vunread_command_events);
+
+      /* Undo what read_char_x_menu_prompt did when it unread
+        additional keys returned by Fx_popup_menu.  */
+      if (CONSP (c)
+         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
+         && NILP (XCDR (c)))
+       c = XCAR (c);
+
+      reread = 1;
+      goto reread_for_input_method;
+    }
+
+  if (CONSP (Vunread_input_method_events))
+    {
+      c = XCAR (Vunread_input_method_events);
+      Vunread_input_method_events = XCDR (Vunread_input_method_events);
+
+      /* Undo what read_char_x_menu_prompt did when it unread
+        additional keys returned by Fx_popup_menu.  */
+      if (CONSP (c)
+         && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
+         && NILP (XCDR (c)))
+       c = XCAR (c);
+      reread = 1;
+      goto reread_for_input_method;
     }
 
   /* If there is no function key translated before
@@ -1789,24 +2037,43 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       unread_switch_frame = Qnil;
 
       /* This event should make it into this_command_keys, and get echoed
-        again, so we go to reread_first, rather than reread.  */
+        again, so we do not set `reread'.  */
       goto reread_first;
     }
 
+  /* if redisplay was requested */
   if (commandflag >= 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);
+       swallow_events (0);             /* may clear input_pending */
 
-      if (!input_pending)
-       redisplay ();
+      /* Redisplay if no pending input.  */
+      while (!input_pending)
+       {
+         redisplay ();
+
+         if (!input_pending)
+           /* Normal case: no input arrived during redisplay.  */
+           break;
+
+         /* Input arrived and pre-empted redisplay.
+            Process any events which are not user-visible.  */
+         swallow_events (0);
+         /* If that cleared input_pending, try again to redisplay.  */
+       }
     }
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
-  if (echo_area_glyphs && *echo_area_glyphs
-      && echo_area_glyphs != current_kboard->echobuf
-      && ok_to_echo_at_next_pause != echo_area_glyphs)
+  if (/* There is a current message.  */
+      !NILP (echo_area_buffer[0])
+      /* And we're not echoing from this kboard.  */
+      && echo_kboard != current_kboard
+      /* And it's either not ok to echo (ok_to_echo == NULL), or the
+        last char echoed was from a different kboard.  */
+      && ok_to_echo_at_next_pause != echo_kboard)
     cancel_echoing ();
   else
     /* If already echoing, continue.  */
@@ -1842,7 +2109,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (_setjmp (local_getcjmp))
     {
       XSETINT (c, quit_char);
-      XSETFRAME (internal_last_event_frame, selected_frame);
+      internal_last_event_frame = selected_frame;
       Vlast_event_frame = internal_last_event_frame;
       /* If we report the quit char as an event,
         don't do so more than once.  */
@@ -1851,7 +2118,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
 #ifdef MULTI_KBOARD
       {
-       KBOARD *kb = FRAME_KBOARD (selected_frame);
+       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
        if (kb != current_kboard)
          {
            Lisp_Object *tailp = &kb->kbd_queue;
@@ -1859,12 +2126,15 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            if (single_kboard)
              abort ();
            while (CONSP (*tailp))
-             tailp = &XCONS (*tailp)->cdr;
+             tailp = &XCDR (*tailp);
            if (!NILP (*tailp))
              abort ();
            *tailp = Fcons (c, Qnil);
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
            longjmp (wrong_kboard_jmpbuf, 1);
          }
       }
@@ -1877,15 +2147,24 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
-  if (minibuf_level == 0 && !current_kboard->immediate_echo
+  if (minibuf_level == 0 
+      && !current_kboard->immediate_echo
       && this_command_key_count > 0
       && ! noninteractive
-      && echo_keystrokes > 0
-      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
-         || ok_to_echo_at_next_pause == echo_area_glyphs))
+      && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+      && NILP (Fzerop (Vecho_keystrokes))
+      && (/* No message.  */
+         NILP (echo_area_buffer[0])
+         /* Or empty message.  */
+         || (BUF_BEG (XBUFFER (echo_area_buffer[0]))
+             == BUF_Z (XBUFFER (echo_area_buffer[0])))
+         /* Or already echoing from same kboard.  */
+         || (echo_kboard && ok_to_echo_at_next_pause == echo_kboard)
+         /* Or not echoing before and echoing allowed.  */
+         || (!echo_kboard && ok_to_echo_at_next_pause)))
     {
       Lisp_Object tem0;
-
+      
       /* After a mouse event, start echoing right away.
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
@@ -1893,9 +2172,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        echo_now ();
       else
        {
+         int sec, usec;
+         double duration = extract_float (Vecho_keystrokes);
+         sec = (int) duration;
+         usec += (duration - sec) * 1000000;
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (echo_keystrokes, 0, 1, 1, 0);
+         tem0 = sit_for (sec, usec, 1, 1, 0);
          restore_getcjmp (save_jump);
          if (EQ (tem0, Qt)
              && ! CONSP (Vunread_command_events))
@@ -1923,7 +2206,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (nmaps > 0 && INTERACTIVE
       && !NILP (prev_event)
       && EVENT_HAS_PARAMETERS (prev_event)
-      && !EQ (XCONS (prev_event)->car, Qmenu_bar)
+      && !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)
@@ -1989,8 +2273,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      or sentinel or filter.  */
   if (CONSP (Vunread_command_events))
     {
-      c = XCONS (Vunread_command_events)->car;
-      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+      c = XCAR (Vunread_command_events);
+      Vunread_command_events = XCDR (Vunread_command_events);
     }
 
   /* Read something from current KBOARD's side queue, if possible.  */
@@ -2001,15 +2285,15 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        {
          if (!CONSP (current_kboard->kbd_queue))
            abort ();
-         c = XCONS (current_kboard->kbd_queue)->car;
+         c = XCAR (current_kboard->kbd_queue);
          current_kboard->kbd_queue
-           = XCONS (current_kboard->kbd_queue)->cdr;
+           = XCDR (current_kboard->kbd_queue);
          if (NILP (current_kboard->kbd_queue))
            current_kboard->kbd_queue_has_data = 0;
          input_pending = readable_events (0);
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
-           internal_last_event_frame = XCONS (XCONS (c)->cdr)->car;
+           internal_last_event_frame = XCAR (XCDR (c));
          Vlast_event_frame = internal_last_event_frame;
        }
     }
@@ -2030,6 +2314,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        if (kb->kbd_queue_has_data)
          {
            current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
            longjmp (wrong_kboard_jmpbuf, 1);
          }
     }
@@ -2058,7 +2345,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        {
          Lisp_Object *tailp = &kb->kbd_queue;
          while (CONSP (*tailp))
-           tailp = &XCONS (*tailp)->cdr;
+           tailp = &XCDR (*tailp);
          if (!NILP (*tailp))
            abort ();
          *tailp = Fcons (c, Qnil);
@@ -2067,6 +2354,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          if (single_kboard)
            goto wrong_kboard;
          current_kboard = kb;
+         /* This is going to exit from read_char
+            so we had better get rid of this frame's stuff.  */
+         UNGCPRO;
          longjmp (wrong_kboard_jmpbuf, 1);
        }
 #endif
@@ -2135,11 +2425,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto retry;
     }
 
-  /* Wipe the echo area.  */
-  if (echo_area_glyphs)
-    safe_run_hooks (Qecho_area_clear_hook);
-  echo_area_glyphs = 0;
-
   /* Handle things that only apply to characters.  */
   if (INTEGERP (c))
     {
@@ -2147,13 +2432,12 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (XINT (c) == -1)
        RETURN_UNGCPRO (c);
 
-      if (STRINGP (Vkeyboard_translate_table)
-         && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
-       XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
-      else if ((VECTORP (Vkeyboard_translate_table)
-               && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
-              || (CHAR_TABLE_P (Vkeyboard_translate_table)
-                  && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c)))
+      if ((STRINGP (Vkeyboard_translate_table)
+          && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
+         || (VECTORP (Vkeyboard_translate_table)
+             && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
+         || (CHAR_TABLE_P (Vkeyboard_translate_table)
+             && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c)))
        {
          Lisp_Object d;
          d = Faref (Vkeyboard_translate_table, c);
@@ -2167,16 +2451,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      return just menu-bar for now.  Modify the mouse click event
      so we won't do this twice, then queue it up.  */
   if (EVENT_HAS_PARAMETERS (c)
-      && CONSP (XCONS (c)->cdr)
+      && CONSP (XCDR (c))
       && CONSP (EVENT_START (c))
-      && CONSP (XCONS (EVENT_START (c))->cdr))
+      && CONSP (XCDR (EVENT_START (c))))
     {
       Lisp_Object posn;
 
       posn = POSN_BUFFER_POSN (EVENT_START (c));
       /* Handle menu-bar events:
         insert the dummy prefix event `menu-bar'.  */
-      if (EQ (posn, Qmenu_bar))
+      if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
          POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
@@ -2187,38 +2471,163 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+  /* Store these characters into recent_keys, the dribble file if any,
+     and the keyboard macro being defined, if any.  */
   record_char (c);
   if (! NILP (also_record))
     record_char (also_record);
 
-  UNGCPRO;
+  /* Wipe the echo area.
+     But first, if we are about to use an input method,
+     save the echo area contents for it to refer to.  */
+  if (INTEGERP (c)
+      && ! NILP (Vinput_method_function)
+      && (unsigned) XINT (c) >= ' '
+      && (unsigned) XINT (c) < 127)
+    {
+      previous_echo_area_message = Fcurrent_message ();
+      Vinput_method_previous_message = previous_echo_area_message;
+    }
+
+  /* Now wipe the echo area.  */
+  if (!NILP (echo_area_buffer[0]))
+    safe_run_hooks (Qecho_area_clear_hook);
+  clear_message (1, 0);
 
+ reread_for_input_method:
  from_macro:
+  /* Pass this to the input method, if appropriate.  */
+  if (INTEGERP (c)
+      && ! NILP (Vinput_method_function)
+      /* Don't run the input method within a key sequence,
+        after the first event of the key sequence.  */
+      && NILP (prev_event)
+      && (unsigned) XINT (c) >= ' '
+      && (unsigned) XINT (c) < 127)
+    {
+      Lisp_Object keys; 
+      int key_count;
+      struct gcpro gcpro1;
+      int count = specpdl_ptr - specpdl;
+
+      /* Save the echo status.  */
+      int saved_immediate_echo = current_kboard->immediate_echo;
+      struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+      int saved_echo_after_prompt = current_kboard->echo_after_prompt;
+
+      if (before_command_restore_flag)
+       {
+         this_command_key_count = before_command_key_count_1;
+         if (this_command_key_count < this_single_command_key_start)
+           this_single_command_key_start = this_command_key_count;
+         echo_truncate (before_command_echo_length_1);
+         before_command_restore_flag = 0;
+       }
+
+      /* Save the this_command_keys status.  */
+      key_count = this_command_key_count;
+
+      if (key_count > 0)
+       keys = Fcopy_sequence (this_command_keys);
+      else
+       keys = Qnil;
+      GCPRO1 (keys);
+
+      /* Clear out this_command_keys.  */
+      this_command_key_count = 0;
+
+      /* Now wipe the echo area.  */
+      if (!NILP (echo_area_buffer[0]))
+       safe_run_hooks (Qecho_area_clear_hook);
+      clear_message (1, 0);
+      echo_truncate (0);
+
+      /* If we are not reading a key sequence,
+        never use the echo area.  */
+      if (maps == 0)
+       {
+         specbind (Qinput_method_use_echo_area, Qt);
+       }
+
+      /* Call the input method.  */
+      tem = call1 (Vinput_method_function, c);
+
+      tem = unbind_to (count, tem);
+
+      /* Restore the saved echoing state
+        and this_command_keys state.  */
+      this_command_key_count = key_count;
+      if (key_count > 0)
+       this_command_keys = keys;
+
+      cancel_echoing ();
+      ok_to_echo_at_next_pause = saved_ok_to_echo;
+      current_kboard->echo_after_prompt = saved_echo_after_prompt;
+      if (saved_immediate_echo)
+       echo_now ();
+
+      UNGCPRO;
+
+      /* The input method can return no events.  */
+      if (! CONSP (tem))
+       {
+         /* Bring back the previous message, if any.  */
+         if (! NILP (previous_echo_area_message))
+           message_with_string ("%s", previous_echo_area_message, 0);
+         goto retry;
+       }
+      /* It returned one event or more.  */
+      c = XCAR (tem);
+      Vunread_post_input_method_events
+       = nconc2 (XCDR (tem), Vunread_post_input_method_events);
+    }
+
  reread_first:
 
-  before_command_key_count = this_command_key_count;
-  before_command_echo_length = echo_length ();
+  /* Display help if not echoing.  */
+  if (CONSP (c)
+      && EQ (XCAR (c), Qhelp_echo))
+    {
+      Lisp_Object msg = XCDR (XCDR (c));
 
-  /* Don't echo mouse motion events.  */
-  if (echo_keystrokes
-      && ! (EVENT_HAS_PARAMETERS (c)
-           && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+      if (!NILP (Vshow_help_function))
+       call1 (Vshow_help_function, msg);
+      else if (!echoing && !MINI_WINDOW_P (XWINDOW (selected_window)))
+       {
+         if (STRINGP (msg))
+           message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg));
+         else
+           message (0);
+       }
+      
+      goto retry;
+    }
+  
+  if (this_command_key_count == 0 || ! reread)
     {
-      echo_char (c);
+      before_command_key_count = this_command_key_count;
+      before_command_echo_length = echo_length ();
+
+      /* Don't echo mouse motion events.  */
+      if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+         && NILP (Fzerop (Vecho_keystrokes))
+         && ! (EVENT_HAS_PARAMETERS (c)
+               && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+       {
+         echo_char (c);
+         if (! NILP (also_record))
+           echo_char (also_record);
+         /* Once we reread a character, echoing can happen
+            the next time we pause to read a new one.  */
+         ok_to_echo_at_next_pause = current_kboard;
+       }
+
+      /* Record this character as part of the current key.  */
+      add_command_key (c);
       if (! NILP (also_record))
-       echo_char (also_record);
-      /* Once we reread a character, echoing can happen
-        the next time we pause to read a new one.  */
-      ok_to_echo_at_next_pause = echo_area_glyphs;
+       add_command_key (also_record);
     }
 
-  /* Record this character as part of the current key.  */
-  add_command_key (c);
-  if (! NILP (also_record))
-    add_command_key (also_record);
-
-  /* Re-reading in the middle of a command */
- reread:
   last_input_char = c;
   num_input_events++;
 
@@ -2263,7 +2672,7 @@ record_menu_key (c)
      Lisp_Object c;
 {
   /* Wipe the echo area.  */
-  echo_area_glyphs = 0;
+  clear_message (1, 0);
 
   record_char (c);
 
@@ -2271,7 +2680,8 @@ record_menu_key (c)
   before_command_echo_length = echo_length ();
 
   /* Don't echo mouse motion events.  */
-  if (echo_keystrokes)
+  if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+      && NILP (Fzerop (Vecho_keystrokes)))
     {
       echo_char (c);
 
@@ -2298,8 +2708,8 @@ help_char_p (c)
 
   if (EQ (c, Vhelp_char))
     return 1;
-  for (tail = Vhelp_event_list; CONSP (tail); tail = XCONS (tail)->cdr)
-    if (EQ (c, XCONS (tail)->car))
+  for (tail = Vhelp_event_list; CONSP (tail); tail = XCDR (tail))
+    if (EQ (c, XCAR (tail)))
       return 1;
   return 0;
 }
@@ -2338,7 +2748,7 @@ record_char (c)
            {
              putc ('<', dribble);
              fwrite (XSYMBOL (dribblee)->name->data, sizeof (char),
-                     XSYMBOL (dribblee)->name->size,
+                     STRING_BYTES (XSYMBOL (dribblee)->name),
                      dribble);
              putc ('>', dribble);
            }
@@ -2369,12 +2779,14 @@ print_help (object)
    in case get_char is called recursively.
    See read_process_output.  */
 
+static void
 save_getcjmp (temp)
      jmp_buf temp;
 {
   bcopy (getcjmp, temp, sizeof getcjmp);
 }
 
+static void
 restore_getcjmp (temp)
      jmp_buf temp;
 {
@@ -2489,7 +2901,7 @@ event_to_kboard (event)
   Lisp_Object frame;
   frame = event->frame_or_window;
   if (CONSP (frame))
-    frame = XCONS (frame)->car;
+    frame = XCAR (frame);
   else if (WINDOWP (frame))
     frame = WINDOW_FRAME (XWINDOW (frame));
 
@@ -2594,7 +3006,7 @@ kbd_buffer_store_event (event)
      Discard the event if it would fill the last slot.  */
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
-      volatile struct input_event *sp = kbd_store_ptr;
+      struct input_event *sp = kbd_store_ptr;
       sp->kind = event->kind;
       if (event->kind == selection_request_event)
        {
@@ -2621,6 +3033,28 @@ kbd_buffer_store_event (event)
     }
 }
 \f
+/* Discard any mouse events in the event buffer by setting them to
+   no_event.  */
+void
+discard_mouse_events ()
+{
+  struct input_event *sp;
+  for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++)
+    {
+      if (sp == kbd_buffer + KBD_BUFFER_SIZE)
+       sp = kbd_buffer;
+
+      if (sp->kind == mouse_click
+#ifdef WINDOWSNT
+         || sp->kind == w32_scroll_bar_click
+#endif
+         || sp->kind == scroll_bar_click)
+       {
+         sp->kind = no_event;
+       }
+    }
+}
+\f
 /* Read one event from the event buffer, waiting if necessary.
    The value is a Lisp object representing the event.
    The value is nil for an event that should be ignored,
@@ -2634,7 +3068,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 {
   register int c;
   Lisp_Object obj;
-  EMACS_TIME next_timer_delay;
 
   if (noninteractive)
     {
@@ -2691,8 +3124,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
   if (CONSP (Vunread_command_events))
     {
       Lisp_Object first;
-      first = XCONS (Vunread_command_events)->car;
-      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+      first = XCAR (Vunread_command_events);
+      Vunread_command_events = XCDR (Vunread_command_events);
       *kbp = current_kboard;
       return first;
     }
@@ -2787,7 +3220,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
       else if (event->kind == menu_bar_activate_event)
        {
          kbd_fetch_ptr = event + 1;
@@ -2796,15 +3229,34 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
-      /* Just discard these, by returning nil.
-        With MULTI_KBOARD, these events are used as placeholders
-        when we need to randomly delete events from the queue.
+#ifdef WINDOWSNT
+      else if (event->kind == language_change_event)
+       {
+         /* Make an event (language-change (FRAME CHARSET LCID)).  */
+         obj = Fcons (event->modifiers, Qnil);
+         obj = Fcons (event->code, Qnil);
+         obj = Fcons (event->frame_or_window, obj);
+         obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
+         kbd_fetch_ptr = event + 1;
+       }
+#endif
+      /* Just discard these, by returning nil.
+        With MULTI_KBOARD, these events are used as placeholders
+        when we need to randomly delete events from the queue.
         (They shouldn't otherwise be found in the buffer,
         but on some machines it appears they do show up
         even without MULTI_KBOARD.)  */
+      /* On Windows NT/9X, no_event is used to delete extraneous
+         mouse events during a popup-menu call.  */
       else if (event->kind == no_event)
        kbd_fetch_ptr = event + 1;
-
+      else if (event->kind == HELP_EVENT)
+       {
+         /* The car of event->frame_or_window is a frame,
+            the cdr is the help to display.  */
+         obj = Fcons (Qhelp_echo, event->frame_or_window);
+         kbd_fetch_ptr = event + 1;
+       }
       /* If this event is on a different frame, return a switch-frame this
         time, and leave the event in the queue for next time.  */
       else
@@ -2814,7 +3266,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
          frame = event->frame_or_window;
          if (CONSP (frame))
-           frame = XCONS (frame)->car;
+           frame = XCAR (frame);
          else if (WINDOWP (frame))
            frame = WINDOW_FRAME (XWINDOW (frame));
 
@@ -2823,7 +3275,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            frame = focus;
 
          if (! EQ (frame, internal_last_event_frame)
-             && XFRAME (frame) != selected_frame)
+             && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
 
@@ -2839,8 +3291,10 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
                 we're returning is (menu-bar), though; that indicates the
                 beginning of the menu sequence, and we might as well leave
                 that as the `event with parameters' for this selection.  */
-             if (event->kind == menu_bar_event
-                 && !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar))
+             if ((event->kind == menu_bar_event
+                  || event->kind == TOOL_BAR_EVENT)
+                 && !(CONSP (obj) && EQ (XCAR (obj), Qmenu_bar))
+                 && !(CONSP (obj) && EQ (XCAR (obj), Qtool_bar))
                  && used_mouse_menu)
                *used_mouse_menu = 1;
 #endif
@@ -2884,7 +3338,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            XSETFRAME (frame, f);
 
          if (! EQ (frame, internal_last_event_frame)
-             && XFRAME (frame) != selected_frame)
+             && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
@@ -2980,6 +3434,7 @@ static EMACS_TIME timer_idleness_start_time;
 /* Record the start of when Emacs is idle,
    for the sake of running idle-time timers.  */
 
+void
 timer_start_idle ()
 {
   Lisp_Object timers;
@@ -2991,11 +3446,11 @@ timer_start_idle ()
   EMACS_GET_TIME (timer_idleness_start_time);
 
   /* Mark all idle-time timers as once again candidates for running.  */
-  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCDR (timers))
     {
       Lisp_Object timer;
 
-      timer = XCONS (timers)->car;
+      timer = XCAR (timers);
 
       if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
        continue;
@@ -3005,6 +3460,7 @@ timer_start_idle ()
 
 /* Record that Emacs is no longer idle, so stop running idle-time timers.  */
 
+void
 timer_stop_idle ()
 {
   EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
@@ -3058,7 +3514,6 @@ timer_check (do_it_now)
 
   while (CONSP (timers) || CONSP (idle_timers))
     {
-      int triggertime = EMACS_SECS (now);
       Lisp_Object *vector;
       Lisp_Object timer, idle_timer;
       EMACS_TIME timer_time, idle_timer_time;
@@ -3067,10 +3522,10 @@ timer_check (do_it_now)
       /* Skip past invalid timers and timers already handled.  */
       if (!NILP (timers))
        {
-         timer = XCONS (timers)->car;
+         timer = XCAR (timers);
          if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
            {
-             timers = XCONS (timers)->cdr;
+             timers = XCDR (timers);
              continue;
            }
          vector = XVECTOR (timer)->contents;
@@ -3079,16 +3534,16 @@ timer_check (do_it_now)
              || !INTEGERP (vector[3])
              || ! NILP (vector[0]))
            {
-             timers = XCONS (timers)->cdr;
+             timers = XCDR (timers);
              continue;
            }
        }
       if (!NILP (idle_timers))
        {
-         timer = XCONS (idle_timers)->car;
+         timer = XCAR (idle_timers);
          if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
            {
-             idle_timers = XCONS (idle_timers)->cdr;
+             idle_timers = XCDR (idle_timers);
              continue;
            }
          vector = XVECTOR (timer)->contents;
@@ -3097,7 +3552,7 @@ timer_check (do_it_now)
              || !INTEGERP (vector[3])
              || ! NILP (vector[0]))
            {
-             idle_timers = XCONS (idle_timers)->cdr;
+             idle_timers = XCDR (idle_timers);
              continue;
            }
        }
@@ -3108,7 +3563,7 @@ timer_check (do_it_now)
         this timer becomes ripe (negative if it's already ripe).  */
       if (!NILP (timers))
        {
-         timer = XCONS (timers)->car;
+         timer = XCAR (timers);
          vector = XVECTOR (timer)->contents;
          EMACS_SET_SECS (timer_time,
                          (XINT (vector[1]) << 16) | (XINT (vector[2])));
@@ -3120,7 +3575,7 @@ timer_check (do_it_now)
         based on the next idle timer.  */
       if (!NILP (idle_timers))
        {
-         idle_timer = XCONS (idle_timers)->car;
+         idle_timer = XCAR (idle_timers);
          vector = XVECTOR (idle_timer)->contents;
          EMACS_SET_SECS (idle_timer_time,
                          (XINT (vector[1]) << 16) | (XINT (vector[2])));
@@ -3139,26 +3594,26 @@ timer_check (do_it_now)
          if (EMACS_TIME_NEG_P (temp))
            {
              chosen_timer = timer;
-             timers = XCONS (timers)->cdr;
+             timers = XCDR (timers);
              difference = timer_difference;
            }
          else
            {
              chosen_timer = idle_timer;
-             idle_timers = XCONS (idle_timers)->cdr;
+             idle_timers = XCDR (idle_timers);
              difference = idle_timer_difference;
            }
        }
       else if (! NILP (timers))
        {
          chosen_timer = timer;
-         timers = XCONS (timers)->cdr;
+         timers = XCDR (timers);
          difference = timer_difference;
        }
       else
        {
          chosen_timer = idle_timer;
-         idle_timers = XCONS (idle_timers)->cdr;
+         idle_timers = XCDR (idle_timers);
          difference = idle_timer_difference;
        }
       vector = XVECTOR (chosen_timer)->contents;
@@ -3170,7 +3625,6 @@ timer_check (do_it_now)
        {
          if (NILP (vector[0]))
            {
-             Lisp_Object tem;
              int was_locked = single_kboard;
              int count = specpdl_ptr - specpdl;
 
@@ -3212,6 +3666,10 @@ timer_check (do_it_now)
 static Lisp_Object accent_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
+#ifdef WINDOWSNT
+static Lisp_Object mouse_wheel_syms;
+#endif
+static Lisp_Object drag_n_drop_syms;
 
 /* This is a list of keysym codes for special "accent" characters.
    It parallels lispy_accent_keys.  */
@@ -3329,15 +3787,15 @@ char *lispy_function_keys[] =
     
     0, 0,             /*    0x0E .. 0x0F        */
   
-    "shift",          /* VK_SHIFT          0x10 */
-    "control",        /* VK_CONTROL        0x11 */
-    "menu",           /* VK_MENU           0x12 */
+    0,                /* VK_SHIFT          0x10 */
+    0,                /* VK_CONTROL        0x11 */
+    0,                /* VK_MENU           0x12 */
     "pause",          /* VK_PAUSE          0x13 */
-    "capital",        /* VK_CAPITAL        0x14 */
+    "capslock",       /* VK_CAPITAL        0x14 */
     
     0, 0, 0, 0, 0, 0, /*    0x15 .. 0x1A        */
     
-    0,                /* VK_ESCAPE         0x1B */
+    "escape",         /* VK_ESCAPE         0x1B */
     
     0, 0, 0, 0,       /*    0x1C .. 0x1F        */
     
@@ -3440,7 +3898,7 @@ char *lispy_function_keys[] =
 
     /*
      * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
-     * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+     * Used only as parameters to GetAsyncKeyState and GetKeyState.
      * No other API or message will distinguish left and right keys this way.
      */
     /* 0xA0 .. 0xEF */
@@ -3464,6 +3922,7 @@ char *lispy_function_keys[] =
     "noname",        /* VK_NONAME         0xFC */
     "pa1",           /* VK_PA1            0xFD */
     "oem_clear",     /* VK_OEM_CLEAR      0xFE */
+    0 /* 0xFF */
   };
 
 #else /* not HAVE_NTGUI */
@@ -3511,35 +3970,23 @@ static char *lispy_function_keys[] =
   {
     /* X Keysym value */
 
-    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xff00 */
-    "backspace",
-    "tab",
-    "linefeed",
-    "clear",
-    0,
-    "return",
-    0, 0,
-    0, 0, 0,                   /* 0xff10 */
-    "pause",
-    0, 0, 0, 0, 0, 0, 0,
-    "escape",
+    0, 0, 0, 0, 0, 0, 0, 0,                          /* 0xff00...0f */
+    "backspace", "tab", "linefeed", "clear",
+    0, "return", 0, 0,
+    0, 0, 0, "pause",                                /* 0xff10...1f */
+    0, 0, 0, 0, 0, 0, 0, "escape",
     0, 0, 0, 0,
-    0, "kanji", "muhenkan", 
-             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff20...2f */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff30...3f */
+    0, "kanji", "muhenkan", "henkan",                /* 0xff20...2f */
+    "romaji", "hiragana", "katakana", "hiragana-katakana",
+    "zenkaku", "hankaku", "zenkaku-hankaku", "touroku",
+    "massyo", "kana-lock", "kana-shift", "eisu-shift",
+    "eisu-toggle",                                   /* 0xff30...3f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff40...4f */
 
-    "home",                    /* 0xff50 */    /* IsCursorKey */
-    "left",
-    "up",
-    "right",
-    "down",
-    "prior",
-    "next",
-    "end",
-    "begin",
-    0,                         /* 0xff59 */
-    0, 0, 0, 0, 0, 0,
+    "home", "left", "up", "right", /* 0xff50 */        /* IsCursorKey */
+    "down", "prior", "next", "end",
+    "begin", 0, 0, 0, 0, 0, 0, 0,
     "select",                  /* 0xff60 */    /* IsMiscFunctionKey */
     "print",
     "execute",
@@ -3553,9 +4000,9 @@ static char *lispy_function_keys[] =
     "help",
     "break",                   /* 0xff6b */
 
-    0, 0, 0, 0, 0, 0, 0, 0, "backtab", 0,
-    0,                         /* 0xff76 */
-    0, 0, 0, 0, 0, 0, 0, 0, "kp-numlock",      /* 0xff7f */
+    0, 0, 0, 0,
+    0, 0, 0, 0, "backtab", 0, 0, 0,            /* 0xff70... */
+    0, 0, 0, 0, 0, 0, 0, "kp-numlock",         /* 0xff78... */
     "kp-space",                        /* 0xff80 */    /* IsKeypadKey */
     0, 0, 0, 0, 0, 0, 0, 0,
     "kp-tab",                  /* 0xff89 */
@@ -3631,14 +4078,45 @@ static char *lispy_mouse_names[] =
   "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
 };
 
+#ifdef WINDOWSNT
+/* mouse-wheel events are generated by the wheel on devices such as
+   the MS Intellimouse.  The wheel sits in between the left and right
+   mouse buttons, and is typically used to scroll or zoom the window
+   underneath the pointer.  mouse-wheel events specify the object on
+   which they operate, and a delta corresponding to the amount and
+   direction that the wheel is rotated.  Clicking the mouse-wheel
+   generates a mouse-2 event.  */
+static char *lispy_mouse_wheel_names[] = 
+{
+  "mouse-wheel"
+};
+
+#endif /* WINDOWSNT */
+
+/* drag-n-drop events are generated when a set of selected files are
+   dragged from another application and dropped onto an Emacs window.  */
+static char *lispy_drag_n_drop_names[] =
+{
+  "drag-n-drop"
+};
+
 /* Scroll bar parts.  */
 Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
-Lisp_Object Qup, Qdown;
+Lisp_Object Qup, Qdown, Qbottom, Qend_scroll;
+Lisp_Object Qtop, Qratio;
 
 /* An array of scroll bar parts, indexed by an enum scroll_bar_part value.  */
 Lisp_Object *scroll_bar_parts[] = {
   &Qabove_handle, &Qhandle, &Qbelow_handle,
-  &Qup, &Qdown,
+  &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio
+};
+
+/* User signal events.  */
+Lisp_Object Qusr1_signal, Qusr2_signal;
+
+Lisp_Object *lispy_user_signals[] =
+{
+  &Qusr1_signal, &Qusr2_signal
 };
 
 
@@ -3774,7 +4252,9 @@ make_lispy_event (event)
       /* 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:
+#ifndef USE_TOOLKIT_SCROLL_BARS
     case scroll_bar_click:
+#endif
       {
        int button = event->code;
        int is_double;
@@ -3792,6 +4272,7 @@ make_lispy_event (event)
            FRAME_PTR f = XFRAME (event->frame_or_window);
            Lisp_Object window;
            Lisp_Object posn;
+           Lisp_Object string_info = Qnil;
            int row, column;
 
            /* Ignore mouse events that were made on frame that
@@ -3799,8 +4280,13 @@ make_lispy_event (event)
            if (! FRAME_LIVE_P (f))
              return Qnil;
 
-           pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                                  &column, &row, NULL, 1);
+           /* EVENT->x and EVENT->y are frame-relative pixel
+              coordinates at this place.  Under old redisplay, COLUMN
+              and ROW are set to frame relative glyph coordinates
+              which are then used to determine whether this click is
+              in a menu (non-toolkit version).  */
+           pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                                  &column, &row, NULL, 1);
 
 #ifndef USE_X_TOOLKIT
            /* In the non-toolkit version, clicks on the menu bar
@@ -3825,6 +4311,7 @@ make_lispy_event (event)
                  return Qnil;
 #endif
 
+               /* Find the menu bar item under `column'.  */
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
                for (i = 0; i < XVECTOR (items)->size; i += 4)
@@ -3842,6 +4329,8 @@ make_lispy_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,
@@ -3853,7 +4342,10 @@ make_lispy_event (event)
              }
 #endif /* not USE_X_TOOLKIT */
 
-           window = window_from_coordinates (f, column, row, &part);
+           /* Set `window' to the window under frame pixel coordinates
+              event->x/event->y.  */
+           window = window_from_coordinates (f, XINT (event->x),
+                                             XINT (event->y), &part, 0);
 
            if (!WINDOWP (window))
              {
@@ -3862,21 +4354,36 @@ make_lispy_event (event)
              }
            else
              {
-               int pixcolumn, pixrow;
-               column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
-               row -= XINT (XWINDOW (window)->top);
-               glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
-               XSETINT (event->x, pixcolumn);
-               XSETINT (event->y, pixrow);
-
-               if (part == 1)
-                 posn = Qmode_line;
+               /* It's a click in window window at frame coordinates
+                  event->x/ event->y.  */
+               struct window *w = XWINDOW (window);
+
+               /* Get window relative coordinates.  Original code
+                  `rounded' this to glyph boundaries.  */
+               int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+               int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+               /* Set event coordinates to window-relative coordinates
+                  for constructing the Lisp event below.  */
+               XSETINT (event->x, wx);
+               XSETINT (event->y, wy);
+
+               if (part == 1 || part == 3)
+                 {
+                   /* Mode line or top line.  Look for a string under
+                      the mouse that may have a `local-map' property.  */
+                   Lisp_Object string;
+                   int charpos;
+                   
+                   posn = part == 1 ? Qmode_line : Qheader_line;
+                   string = mode_line_string (w, wx, wy, part == 1, &charpos);
+                   if (STRINGP (string))
+                     string_info = Fcons (string, make_number (charpos));
+                 }
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSETINT (posn,
-                          buffer_posn_from_coords (XWINDOW (window),
-                                                   column, row));
+                 XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
              }
 
            position
@@ -3884,10 +4391,14 @@ make_lispy_event (event)
                       Fcons (posn,
                              Fcons (Fcons (event->x, event->y),
                                     Fcons (make_number (event->timestamp),
-                                           Qnil))));
+                                           (NILP (string_info)
+                                            ? Qnil
+                                            : Fcons (string_info, Qnil))))));
          }
+#ifndef USE_TOOLKIT_SCROLL_BARS
        else
          {
+           /* It's a scrollbar click.  */
            Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
@@ -3903,6 +4414,7 @@ make_lispy_event (event)
                                     Fcons (make_number (event->timestamp),
                                            Fcons (part, Qnil)))));
          }
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 
        start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
 
@@ -3964,8 +4476,8 @@ make_lispy_event (event)
                Lisp_Object down;
 
                down = Fnth (make_number (2), start_pos);
-               if (EQ (event->x, XCONS (down)->car)
-                   && EQ (event->y, XCONS (down)->cdr))
+               if (EQ (event->x, XCAR (down))
+                   && EQ (event->y, XCDR (down)))
                  {
                    event->modifiers |= click_modifier;
                  }
@@ -4014,6 +4526,55 @@ make_lispy_event (event)
        }
       }
 
+#if USE_TOOLKIT_SCROLL_BARS
+
+      /* We don't have down and up events if using toolkit scroll bars,
+        so make this always a click event.  Store in the `part' of
+        the Lisp event a symbol which maps to the following actions:
+
+        `above_handle'         page up
+        `below_handle'         page down
+        `up'                   line up
+        `down'                 line down
+        `top'                  top of buffer
+        `bottom'               bottom of buffer
+        `handle'               thumb has been dragged.
+        `end-scroll'           end of interaction with scroll bar
+
+        The incoming input_event contains in its `part' member an
+        index of type `enum scroll_bar_part' which we can use as an
+        index in scroll_bar_parts to get the appropriate symbol.  */
+        
+    case scroll_bar_click:
+      {
+       Lisp_Object position, head, window, portion_whole, part;
+
+       window = event->frame_or_window;
+       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)))));
+
+       /* Always treat scroll bar events as clicks. */
+       event->modifiers |= click_modifier;
+
+       /* Get the symbol we should use for the mouse click.  */
+       head = modify_event_symbol (event->code,
+                                   event->modifiers,
+                                   Qmouse_click, Qnil,
+                                   lispy_mouse_names, &mouse_syms,
+                                   (sizeof (lispy_mouse_names)
+                                    / sizeof (lispy_mouse_names[0])));
+       return Fcons (head, Fcons (position, Qnil));
+      }
+      
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
 #ifdef WINDOWSNT
     case w32_scroll_bar_click:
       {
@@ -4035,12 +4596,12 @@ make_lispy_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
+           Fcons (window,
+                    Fcons (Qvertical_scroll_bar,
+                           Fcons (portion_whole,
+                                  Fcons (make_number (event->timestamp),
+                                         Fcons (part, Qnil)))));
        }
 
        /* Always treat W32 scroll bar events as clicks. */
@@ -4061,8 +4622,147 @@ make_lispy_event (event)
                               Qnil));
        }
       }
-#endif
+    case mouse_wheel:
+      {
+       int part;
+       FRAME_PTR f = XFRAME (event->frame_or_window);
+       Lisp_Object window;
+       Lisp_Object posn;
+       Lisp_Object head, position;
+       int row, column;
+
+       /* Ignore mouse events that were made on frame that
+          have been deleted.  */
+       if (! FRAME_LIVE_P (f))
+         return Qnil;
+       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                              &column, &row, NULL, 1);
+       window = window_from_coordinates (f, column, row, &part, 0);
+
+       if (!WINDOWP (window))
+         {
+           window = event->frame_or_window;
+           posn = Qnil;
+         }
+       else
+         {
+           int pixcolumn, pixrow;
+           column -= XINT (XWINDOW (window)->left);
+           row -= XINT (XWINDOW (window)->top);
+           glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+           XSETINT (event->x, pixcolumn);
+           XSETINT (event->y, pixrow);
+
+           if (part == 1)
+             posn = Qmode_line;
+           else if (part == 2)
+             posn = Qvertical_line;
+           else if (part == 3)
+             posn = Qheader_line;
+           else
+             XSETINT (posn,
+                      buffer_posn_from_coords (XWINDOW (window),
+                                               column, row));
+         }
+
+       {
+         Lisp_Object head, position;
+
+         position
+           = Fcons (window,
+                    Fcons (posn,
+                           Fcons (Fcons (event->x, event->y),
+                                  Fcons (make_number (event->timestamp),
+                                         Qnil))));
+
+         head = modify_event_symbol (0, event->modifiers,
+                                     Qmouse_wheel, Qnil,
+                                     lispy_mouse_wheel_names,
+                                     &mouse_wheel_syms, 1);
+         return Fcons (head,
+                       Fcons (position,
+                              Fcons (make_number (event->code),
+                                     Qnil)));
+       }
+      }
+#endif /* WINDOWSNT */
 
+    case drag_n_drop:
+      {
+       int part;
+       FRAME_PTR f;
+       Lisp_Object window;
+       Lisp_Object posn;
+       Lisp_Object files;
+       int row, column;
+
+       /* The frame_or_window field should be a cons of the frame in
+          which the event occurred and a list of the filenames
+          dropped.  */
+       if (! CONSP (event->frame_or_window))
+         abort ();
+
+       f = XFRAME (XCAR (event->frame_or_window));
+       files = XCDR (event->frame_or_window);
+
+       /* Ignore mouse events that were made on frames that
+          have been deleted.  */
+       if (! FRAME_LIVE_P (f))
+         return Qnil;
+       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                              &column, &row, NULL, 1);
+       window = window_from_coordinates (f, column, row, &part, 0);
+
+       if (!WINDOWP (window))
+         {
+           window = XCAR (event->frame_or_window);
+           posn = Qnil;
+         }
+       else
+         {
+           /* It's an event in window `window' at frame coordinates
+              event->x/ event->y.  */
+           struct window *w = XWINDOW (window);
+
+           /* Get window relative coordinates.  */
+           int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+           int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+           /* Set event coordinates to window-relative coordinates
+              for constructing the Lisp event below.  */
+           XSETINT (event->x, wx);
+           XSETINT (event->y, wy);
+
+           if (part == 1)
+             posn = Qmode_line;
+           else if (part == 2)
+             posn = Qvertical_line;
+           else if (part == 3)
+             posn = Qheader_line;
+           else
+             XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+         }
+
+       {
+         Lisp_Object head, position;
+
+         position
+           = Fcons (window,
+                    Fcons (posn,
+                           Fcons (Fcons (event->x, event->y),
+                                  Fcons (make_number (event->timestamp),
+                                         Qnil))));
+
+         head = modify_event_symbol (0, event->modifiers,
+                                     Qdrag_n_drop, Qnil,
+                                     lispy_drag_n_drop_names,
+                                     &drag_n_drop_syms, 1);
+         return Fcons (head,
+                       Fcons (position,
+                              Fcons (files,
+                                     Qnil)));
+       }
+      }
 #endif /* HAVE_MOUSE */
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
@@ -4070,9 +4770,24 @@ make_lispy_event (event)
       /* The event value is in the cdr of the frame_or_window slot.  */
       if (!CONSP (event->frame_or_window))
        abort ();
-      return XCONS (event->frame_or_window)->cdr;
+      return XCDR (event->frame_or_window);
 #endif
 
+    case TOOL_BAR_EVENT:
+      {
+       Lisp_Object key;
+       if (!CONSP (event->frame_or_window))
+         abort ();
+       key = XCDR (event->frame_or_window);
+       if (SYMBOLP (key))
+         key = apply_modifiers (event->modifiers, key);
+       return key;
+      }
+
+    case user_signal:
+      /* A user signal.  */
+      return *lispy_user_signals[event->code];
+      
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -4111,34 +4826,32 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
       int area;
       Lisp_Object window;
       Lisp_Object posn;
-      int column, row;
 
       if (frame)
-       {
-         /* It's in a frame; which window on that frame?  */
-         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
-                                NULL, 1);
-         window = window_from_coordinates (frame, column, row, &area);
-       }
+       /* It's in a frame; which window on that frame?  */
+       window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
       else
        window = Qnil;
 
       if (WINDOWP (window))
        {
-         int pixcolumn, pixrow;
-         column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
-         row -= XINT (XWINDOW (window)->top);
-         glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
-         XSETINT (x, pixcolumn);
-         XSETINT (y, pixrow);
-
+         struct window *w = XWINDOW (window);
+         int wx, wy;
+         
+         /* Get window relative coordinates.  */
+         wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
+         wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
+         XSETINT (x, wx);
+         XSETINT (y, wy);
+         
          if (area == 1)
            posn = Qmode_line;
          else if (area == 2)
            posn = Qvertical_line;
+         else if (area == 3)
+           posn = Qheader_line;
          else
-           XSETINT (posn,
-                    buffer_posn_from_coords (XWINDOW (window), column, row));
+           XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
        }
       else if (frame != 0)
        {
@@ -4197,7 +4910,7 @@ parse_modifiers_uncached (symbol, modifier_end)
   modifiers = 0;
   name = XSYMBOL (symbol)->name;
 
-  for (i = 0; i+2 <= name->size; )
+  for (i = 0; i+2 <= STRING_BYTES (name); )
     {
       int this_mod_end = 0;
       int this_mod = 0;
@@ -4244,7 +4957,8 @@ parse_modifiers_uncached (symbol, modifier_end)
 
       /* Check there is a dash after the modifier, so that it
         really is a modifier.  */
-      if (this_mod_end >= name->size || name->data[this_mod_end] != '-')
+      if (this_mod_end >= STRING_BYTES (name)
+         || name->data[this_mod_end] != '-')
        break;
 
       /* This modifier is real; look for another.  */
@@ -4255,7 +4969,7 @@ parse_modifiers_uncached (symbol, modifier_end)
   /* Should we include the `click' modifier?  */
   if (! (modifiers & (down_modifier | drag_modifier
                      | double_modifier | triple_modifier))
-      && i + 7 == name->size
+      && i + 7 == STRING_BYTES (name)
       && strncmp (name->data + i, "mouse-", 6) == 0
       && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9'))
     modifiers |= click_modifier;
@@ -4270,16 +4984,16 @@ parse_modifiers_uncached (symbol, modifier_end)
    prepended to the string BASE[0..BASE_LEN-1].
    This doesn't use any caches.  */
 static Lisp_Object
-apply_modifiers_uncached (modifiers, base, base_len)
+apply_modifiers_uncached (modifiers, base, base_len, base_len_byte)
      int modifiers;
      char *base;
-     int base_len;
+     int base_len, base_len_byte;
 {
   /* 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
+    (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-"));
   int mod_len;
 
   {
@@ -4310,9 +5024,10 @@ apply_modifiers_uncached (modifiers, base, base_len)
   {
     Lisp_Object new_name;
 
-    new_name = make_uninit_string (mod_len + base_len);
+    new_name = make_uninit_multibyte_string (mod_len + base_len,
+                                            mod_len + base_len_byte);
     bcopy (new_mods, XSTRING (new_name)->data,        mod_len);
-    bcopy (base,     XSTRING (new_name)->data + mod_len, base_len);
+    bcopy (base,     XSTRING (new_name)->data + mod_len, base_len_byte);
 
     return Fintern (new_name, Qnil);
   }
@@ -4354,7 +5069,7 @@ lispy_modifier_list (modifiers)
    SYMBOL's Qevent_symbol_element_mask property, and maintains the
    Qevent_symbol_elements property.  */
 
-static Lisp_Object
+Lisp_Object
 parse_modifiers (symbol)
      Lisp_Object symbol;
 {
@@ -4371,7 +5086,7 @@ parse_modifiers (symbol)
       Lisp_Object mask;
 
       unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
-                                        XSYMBOL (symbol)->name->size - end),
+                                        STRING_BYTES (XSYMBOL (symbol)->name) - end),
                            Qnil);
 
       if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1))
@@ -4419,13 +5134,14 @@ apply_modifiers (modifiers, base)
   entry = assq_no_quit (index, cache);
 
   if (CONSP (entry))
-    new_symbol = XCONS (entry)->cdr;
+    new_symbol = XCDR (entry);
   else
     {
       /* We have to create the symbol ourselves.  */
       new_symbol = apply_modifiers_uncached (modifiers,
                                             XSYMBOL (base)->name->data,
-                                            XSYMBOL (base)->name->size);
+                                            XSYMBOL (base)->name->size,
+                                            STRING_BYTES (XSYMBOL (base)->name));
 
       /* Add the new symbol to the base's cache.  */
       entry = Fcons (index, new_symbol);
@@ -4476,8 +5192,8 @@ reorder_modifiers (symbol)
   Lisp_Object parsed;
 
   parsed = parse_modifiers (symbol);
-  return apply_modifiers ((int) XINT (XCONS (XCONS (parsed)->cdr)->car),
-                         XCONS (parsed)->car);
+  return apply_modifiers ((int) XINT (XCAR (XCDR (parsed))),
+                         XCAR (parsed));
 }
 
 
@@ -4618,8 +5334,8 @@ has the same base event type and all the specified modifiers.")
       Lisp_Object elt;
       int this = 0;
 
-      elt = XCONS (rest)->car;
-      rest = XCONS (rest)->cdr;
+      elt = XCAR (rest);
+      rest = XCDR (rest);
 
       /* Given a symbol, see if it is a modifier name.  */
       if (SYMBOLP (elt) && CONSP (rest))
@@ -4673,11 +5389,11 @@ parse_solitary_modifier (symbol)
   switch (name->data[0])
     {
 #define SINGLE_LETTER_MOD(BIT)                         \
-      if (name->size == 1)                             \
+      if (STRING_BYTES (name) == 1)                    \
        return BIT;
 
 #define MULTI_LETTER_MOD(BIT, NAME, LEN)               \
-      if (LEN == name->size                            \
+      if (LEN == STRING_BYTES (name)                   \
          && ! strncmp (name->data, NAME, LEN))         \
        return BIT;
 
@@ -4754,10 +5470,10 @@ lucid_event_type_list_p (object)
   if (! CONSP (object))
     return 0;
 
-  for (tail = object; CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = object; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object elt;
-      elt = XCONS (tail)->car;
+      elt = XCAR (tail);
       if (! (INTEGERP (elt) || SYMBOLP (elt)))
        return 0;
     }
@@ -4791,7 +5507,7 @@ get_input_pending (addr, do_timers_now)
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
 
-int
+void
 gobble_input (expected)
      int expected;
 {
@@ -4823,6 +5539,7 @@ gobble_input (expected)
 /* Put a buffer_switch_event in the buffer
    so that read_key_sequence will notice the new current buffer.  */
 
+void
 record_asynch_buffer_change ()
 {
   struct input_event event;
@@ -4938,11 +5655,11 @@ read_avail_input (expected)
          cbuf[0] = dos_keyread ();
          nread = 1;
 #else
-         nread = read (input_fd, cbuf, n_to_read);
+         nread = emacs_read (input_fd, cbuf, n_to_read);
 #endif
          /* 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
-            this part standard and returns -1 from read(0) with errno==EIO
+            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.  */
          if (nread == -1 && errno == EIO)
@@ -4990,7 +5707,7 @@ read_avail_input (expected)
            cbuf[i] &= ~0x80;
 
          buf[i].code = cbuf[i];
-         XSETFRAME (buf[i].frame_or_window, selected_frame);
+         buf[i].frame_or_window = selected_frame;
        }
     }
 
@@ -5172,11 +5889,7 @@ menu_bar_items (old)
        nmaps = current_minor_maps (NULL, &tmaps);
        maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
        bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-#ifdef USE_TEXT_PROPERTIES
        maps[nmaps++] = get_local_map (PT, current_buffer);
-#else
-       maps[nmaps++] = current_buffer->keymap;
-#endif
       }
     maps[nmaps++] = current_global_map;
   }
@@ -5199,13 +5912,13 @@ menu_bar_items (old)
 
   /* Move to the end those items that should be at the end.  */
 
-  for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCDR (tail))
     {
       int i;
       int end = menu_bar_items_index;
 
       for (i = 0; i < end; i += 4)
-       if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
+       if (EQ (XCAR (tail), XVECTOR (menu_bar_items_vector)->contents[i]))
          {
            Lisp_Object tem0, tem1, tem2, tem3;
            /* Move the item at index I to the end,
@@ -5231,7 +5944,6 @@ menu_bar_items (old)
   if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
     {
       Lisp_Object tem;
-      int newsize = 2 * i;
       tem = Fmake_vector (make_number (2 * i), Qnil);
       bcopy (XVECTOR (menu_bar_items_vector)->contents,
             XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
@@ -5252,29 +5964,22 @@ menu_bar_items (old)
 /* Scan one map KEYMAP, accumulating any menu items it defines
    in menu_bar_items_vector.  */
 
+static Lisp_Object menu_bar_one_keymap_changed_items;
+
 static void
 menu_bar_one_keymap (keymap)
      Lisp_Object keymap;
 {
-  Lisp_Object tail, item, key, binding, item_string, table;
+  Lisp_Object tail, item;
+
+  menu_bar_one_keymap_changed_items = Qnil;
 
   /* Loop over all keymap entries that have menu strings.  */
-  for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = keymap; CONSP (tail); tail = XCDR (tail))
     {
-      item = XCONS (tail)->car;
+      item = XCAR (tail);
       if (CONSP (item))
-       {
-         key = XCONS (item)->car;
-         binding = XCONS (item)->cdr;
-         if (CONSP (binding))
-           {
-             item_string = XCONS (binding)->car;
-             if (STRINGP (item_string))
-               menu_bar_item (key, item_string, Fcdr (binding));
-           }
-         else if (EQ (binding, Qundefined))
-           menu_bar_item (key, Qnil, binding);
-       }
+       menu_bar_item (XCAR (item), XCDR (item));
       else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
@@ -5284,117 +5989,855 @@ menu_bar_one_keymap (keymap)
            {
              Lisp_Object character;
              XSETFASTINT (character, c);
-             binding = XVECTOR (item)->contents[c];
-             if (CONSP (binding))
+             menu_bar_item (character, XVECTOR (item)->contents[c]);
+           }
+       }
+    }
+}
+
+/* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
+   If there's already an item for KEY, add this DEF to it.  */
+
+Lisp_Object item_properties;
+
+static void
+menu_bar_item (key, item)
+     Lisp_Object key, item;
+{
+  struct gcpro gcpro1;
+  int i;
+  Lisp_Object tem;
+
+  if (EQ (item, Qundefined))
+    {
+      /* If a map has an explicit `undefined' as definition,
+        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 (menu_bar_items_index > i + 4)
+             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
+                    &XVECTOR (menu_bar_items_vector)->contents[i],
+                    (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
+           menu_bar_items_index -= 4;
+           return;
+         }
+
+      /* If there's no definition for this key yet,
+        just ignore `undefined'.  */
+      return;
+    }
+
+  GCPRO1 (key);                        /* Is this necessary? */
+  i = parse_menu_item (item, 0, 1);
+  UNGCPRO;
+  if (!i)
+    return;
+
+  /* If this keymap has already contributed to this KEY,
+     don't contribute to it a second time.  */
+  tem = Fmemq (key, menu_bar_one_keymap_changed_items);
+  if (!NILP (tem))
+    return;
+
+  menu_bar_one_keymap_changed_items
+    = Fcons (key, menu_bar_one_keymap_changed_items);
+
+  item = XVECTOR (item_properties)->contents[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]))
+      break;
+
+  /* If we did not find this KEY, add it at the end.  */
+  if (i == menu_bar_items_index)
+    {
+      /* If vector is too small, get a bigger one.  */
+      if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
+       {
+         Lisp_Object tem;
+         tem = Fmake_vector (make_number (2 * i), Qnil);
+         bcopy (XVECTOR (menu_bar_items_vector)->contents,
+                XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+         menu_bar_items_vector = tem;
+       }
+
+      /* 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);
+      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];
+      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old);
+    }
+}
+\f
+ /* This is used as the handler when calling menu_item_eval_property.  */
+static Lisp_Object
+menu_item_eval_property_1 (arg)
+     Lisp_Object arg;
+{
+  /* If we got a quit from within the menu computation,
+     quit all the way out of it.  This takes care of C-] in the debugger.  */
+  if (CONSP (arg) && EQ (XCAR (arg), Qquit))
+    Fsignal (Qquit, Qnil);
+
+  return Qnil;
+}
+
+/* Evaluate an expression and return the result (or nil if something 
+   went wrong).  Used to evaluate dynamic parts of menu items.  */
+Lisp_Object
+menu_item_eval_property (sexpr)
+     Lisp_Object sexpr;
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object val;
+  specbind (Qinhibit_redisplay, Qt);
+  val = internal_condition_case_1 (Feval, sexpr, Qerror,
+                                  menu_item_eval_property_1);
+  return unbind_to (count, val);
+}
+
+/* This function parses a menu item and leaves the result in the
+   vector item_properties.
+   ITEM is a key binding, a possible menu item.
+   If NOTREAL is nonzero, only check for equivalent key bindings, don't
+   evaluate dynamic expressions in the menu item.
+   INMENUBAR is > 0 when this is considered for an entry in a menu bar
+   top level.
+   INMENUBAR is < 0 when this is considered for an entry in a keyboard menu.
+   parse_menu_item returns true if the item is a menu item and false
+   otherwise.  */
+
+int
+parse_menu_item (item, notreal, inmenubar)
+     Lisp_Object item;
+     int notreal, inmenubar;
+{
+  Lisp_Object def, tem, item_string, start;
+  Lisp_Object cachelist;
+  Lisp_Object filter;
+  Lisp_Object keyhint;
+  int i;
+  int newcache = 0;
+
+  cachelist = Qnil;
+  filter = Qnil;
+  keyhint = Qnil;
+
+  if (!CONSP (item))
+    return 0;
+
+  /* Create item_properties vector if necessary.  */
+  if (NILP (item_properties))
+    item_properties
+      = Fmake_vector (make_number (ITEM_PROPERTY_ENABLE + 1), Qnil);
+
+  /* Initialize optional entries.  */
+  for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
+    XVECTOR (item_properties)->contents[i] = Qnil;
+  XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = Qt;
+        
+  /* Save the item here to protect it from GC.  */
+  XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item;
+
+  item_string = XCAR (item);
+
+  start = item;
+  item = XCDR (item);
+  if (STRINGP (item_string))
+    {
+      /* Old format menu item.  */
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+
+      /* Maybe help string.  */
+      if (CONSP (item) && STRINGP (XCAR (item)))
+       {
+         XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+           = XCAR (item);
+         start = item;
+         item = XCDR (item);
+       }
+         
+      /* Maybee key binding cache.  */
+      if (CONSP (item) && CONSP (XCAR (item))
+         && (NILP (XCAR (XCAR (item)))
+             || VECTORP (XCAR (XCAR (item)))))
+       {
+         cachelist = XCAR (item);
+         item = XCDR (item);
+       }
+      
+      /* This is the real definition--the function to run.  */
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = item;
+
+      /* Get enable property, if any.  */
+      if (SYMBOLP (item))
+       {
+         tem = Fget (item, Qmenu_enable);
+         if (!NILP (tem))
+           XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+       }
+    }
+  else if (EQ (item_string, Qmenu_item) && CONSP (item))
+    {
+      /* New format menu item.  */
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]
+       = XCAR (item);
+      start = XCDR (item);
+      if (CONSP (start))
+       {
+         /* We have a real binding.  */
+         XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]
+           = XCAR (start);
+
+         item = XCDR (start);
+         /* Is there a cache list with key equivalences. */
+         if (CONSP (item) && CONSP (XCAR (item)))
+           {
+             cachelist = XCAR (item);
+             item = XCDR (item);
+           }
+
+         /* Parse properties.  */
+         while (CONSP (item) && CONSP (XCDR (item)))
+           {
+             tem = XCAR (item);
+             item = XCDR (item);
+
+             if (EQ (tem, QCenable))
+               XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]
+                 = XCAR (item);
+             else if (EQ (tem, QCvisible) && !notreal)
+               {
+                 /* If got a visible property and that evaluates to nil
+                    then ignore this item.  */
+                 tem = menu_item_eval_property (XCAR (item));
+                 if (NILP (tem))
+                   return 0;
+               }
+             else if (EQ (tem, QChelp))
+               XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+                 = XCAR (item);
+             else if (EQ (tem, QCfilter))
+               filter = item;
+             else if (EQ (tem, QCkey_sequence))
                {
-                 item_string = XCONS (binding)->car;
-                 if (STRINGP (item_string))
-                   menu_bar_item (key, item_string, Fcdr (binding));
+                 tem = XCAR (item);
+                 if (NILP (cachelist)
+                     && (SYMBOLP (tem) || STRINGP (tem) || VECTORP (tem)))
+                   /* Be GC protected. Set keyhint to item instead of tem. */
+                   keyhint = item;
+               }
+             else if (EQ (tem, QCkeys))
+               {
+                 tem = XCAR (item);
+                 if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
+                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
+                     = tem;
+               }
+             else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
+               {
+                 Lisp_Object type;
+                 tem = XCAR (item);
+                 type = XCAR (tem);
+                 if (EQ (type, QCtoggle) || EQ (type, QCradio))
+                   {
+                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+                       = XCDR (tem);
+                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+                       = type;
+                   }
                }
-             else if (EQ (binding, Qundefined))
-               menu_bar_item (key, Qnil, binding);
+             item = XCDR (item);
+           }
+       }
+      else if (inmenubar || !NILP (start))
+       return 0;
+    }
+  else
+    return 0;                  /* not a menu item */
+
+  /* If item string is not a string, evaluate it to get string.
+     If we don't get a string, skip this item.  */
+  item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+  if (!(STRINGP (item_string) || notreal))
+    {
+      item_string = menu_item_eval_property (item_string);
+      if (!STRINGP (item_string))
+       return 0;
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+    }
+     
+  /* If got a filter apply it on definition.  */
+  def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+  if (!NILP (filter))
+    {
+      def = menu_item_eval_property (list2 (XCAR (filter),
+                                           list2 (Qquote, def)));
+
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = def;
+    }
+
+  /* If we got no definition, this item is just unselectable text which
+     is OK in a submenu but not in the menubar.  */
+  if (NILP (def))
+    return (inmenubar ? 0 : 1);
+  /* Enable or disable selection of item.  */
+  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+  if (!EQ (tem, Qt))
+    {
+      if (notreal)
+       tem = Qt;
+      else
+       tem = menu_item_eval_property (tem);
+      if (inmenubar && NILP (tem))
+       return 0;               /* Ignore disabled items in menu bar.  */
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+    }
+
+  /* See if this is a separate pane or a submenu.  */
+  def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+  tem = get_keymap_1 (def, 0, 1);
+  /* For a subkeymap, just record its details and exit.  */
+  if (!NILP (tem))
+    {
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
+      return 1;
+    }
+  /* At the top level in the menu bar, do likewise for commands also.
+     The menu bar does not display equivalent key bindings anyway.
+     ITEM_PROPERTY_DEF is already set up properly.  */
+  if (inmenubar > 0)
+    return 1;
+
+  /* This is a command.  See if there is an equivalent key binding. */
+  if (NILP (cachelist))
+    {
+      /* We have to create a cachelist.  */
+      CHECK_IMPURE (start);
+      XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
+      cachelist = XCAR (XCDR (start));
+      newcache = 1;
+      tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+      if (!NILP (keyhint))
+       {
+         XCAR (cachelist) = XCAR (keyhint);
+         newcache = 0;
+       }
+      else if (STRINGP (tem))
+       {
+         XCDR (cachelist) = Fsubstitute_command_keys (tem);
+         XCAR (cachelist) = Qt;
+       }
+    }
+  tem = XCAR (cachelist);
+  if (!EQ (tem, Qt))
+    {
+      int chkcache = 0;
+      Lisp_Object prefix;
+
+      if (!NILP (tem))
+       tem = Fkey_binding (tem, Qnil);
+
+      prefix = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+      if (CONSP (prefix))
+       {
+         def = XCAR (prefix);
+         prefix = XCDR (prefix);
+       }
+      else
+       def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+
+      if (NILP (XCAR (cachelist))) /* Have no saved key.  */
+       {
+         if (newcache          /* Always check first time.  */
+             /* Should we check everything when precomputing key
+                bindings?  */
+             /* || notreal */
+             /* If something had no key binding before, don't recheck it
+                because that is too slow--except if we have a list of
+                rebound commands in Vdefine_key_rebound_commands, do
+                recheck any command that appears in that list. */
+             || (CONSP (Vdefine_key_rebound_commands)
+                 && !NILP (Fmemq (def, Vdefine_key_rebound_commands))))
+           chkcache = 1;
+       }
+      /* We had a saved key. Is it still bound to the command?  */
+      else if (NILP (tem)
+              || (!EQ (tem, def)
+                  /* 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))))
+       chkcache = 1;           /* Need to recompute key binding.  */
+
+      if (chkcache)
+       {
+         /* Recompute equivalent key binding.  If the command is an alias
+            for another (such as lmenu.el set it up), see if the original
+            command name has equivalent keys.  Otherwise look up the
+            specified command itself.  We don't try both, because that
+            makes lmenu menus slow. */
+         if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+             && ! NILP (Fget (def, Qmenu_alias)))
+           def = XSYMBOL (def)->function;
+         tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
+         XCAR (cachelist) = tem;
+         if (NILP (tem))
+           {
+             XCDR (cachelist) = Qnil;
+             chkcache = 0;
+           }
+       }
+      else if (!NILP (keyhint) && !NILP (XCAR (cachelist)))
+       {
+         tem = XCAR (cachelist);
+         chkcache = 1;
+       }
+
+      newcache = chkcache;
+      if (chkcache)
+       {
+         tem = Fkey_description (tem);
+         if (CONSP (prefix))
+           {
+             if (STRINGP (XCAR (prefix)))
+               tem = concat2 (XCAR (prefix), tem);
+             if (STRINGP (XCDR (prefix)))
+               tem = concat2 (tem, XCDR (prefix));
+           }
+         XCDR (cachelist) = tem;
+       }
+    }
+
+  tem = XCDR (cachelist);
+  if (newcache && !NILP (tem))
+    {
+      tem = concat3 (build_string ("  ("), tem, build_string (")"));
+      XCDR (cachelist) = tem;
+    }
+
+  /* If we only want to precompute equivalent key bindings, stop here. */
+  if (notreal)
+    return 1;
+
+  /* If we have an equivalent key binding, use that.  */
+  XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] = tem;
+
+  /* Include this when menu help is implemented.
+  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP];
+  if (!(NILP (tem) || STRINGP (tem)))
+    {
+      tem = menu_item_eval_property (tem);
+      if (!STRINGP (tem))
+       tem = Qnil;
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP] = tem;
+    }
+  */
+
+  /* Handle radio buttons or toggle boxes.  */ 
+  tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+  if (!NILP (tem))
+    XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+      = menu_item_eval_property (tem);
+
+  return 1;
+}
+
+
+\f
+/***********************************************************************
+                              Tool-bars
+ ***********************************************************************/
+
+/* A vector holding tool bar items while they are parsed in function
+   tool_bar_items runs Each item occupies TOOL_BAR_ITEM_NSCLOTS elements
+   in the vector.  */
+
+static Lisp_Object tool_bar_items_vector;
+
+/* A vector holding the result of parse_tool_bar_item.  Layout is like
+   the one for a single item in tool_bar_items_vector.  */
+
+static Lisp_Object tool_bar_item_properties;
+
+/* Next free index in tool_bar_items_vector.  */
+
+static int ntool_bar_items;
+
+/* The symbols `tool-bar', and `:image'.  */
+
+extern Lisp_Object Qtool_bar;
+Lisp_Object QCimage;
+
+/* Function prototypes.  */
+
+static void init_tool_bar_items P_ ((Lisp_Object));
+static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void append_tool_bar_item P_ ((void));
+
+
+/* Return a vector of tool bar items for keymaps currently in effect.
+   Reuse vector REUSE if non-nil.  Return in *NITEMS the number of
+   tool bar items found.  */
+
+Lisp_Object
+tool_bar_items (reuse, nitems)
+     Lisp_Object reuse;
+     int *nitems;
+{
+  Lisp_Object *maps;
+  int nmaps, i;
+  Lisp_Object oquit;
+  Lisp_Object *tmaps;
+  extern Lisp_Object Voverriding_local_map_menu_flag;
+  extern Lisp_Object Voverriding_local_map;
+
+  *nitems = 0;
+
+  /* In order to build the menus, we need to call the keymap
+     accessors.  They all call QUIT.  But this function is called
+     during redisplay, during which a quit is fatal.  So inhibit
+     quitting while building the menus.  We do this instead of
+     specbind because (1) errors will clear it anyway and (2) this
+     avoids risk of specpdl overflow.  */
+  oquit = Vinhibit_quit;
+  Vinhibit_quit = Qt;
+  
+  /* Initialize tool_bar_items_vector and protect it from GC.  */
+  init_tool_bar_items (reuse);
+
+  /* Build list of keymaps in maps.  Set nmaps to the number of maps
+     to process.  */
+  
+  /* Should overriding-terminal-local-map and overriding-local-map apply?  */
+  if (!NILP (Voverriding_local_map_menu_flag))
+    {
+      /* Yes, use them (if non-nil) as well as the global map.  */
+      maps = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+      nmaps = 0;
+      if (!NILP (current_kboard->Voverriding_terminal_local_map))
+       maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+      if (!NILP (Voverriding_local_map))
+       maps[nmaps++] = Voverriding_local_map;
+    }
+  else
+    {
+      /* No, so use major and minor mode keymaps.  */
+      nmaps = current_minor_maps (NULL, &tmaps);
+      maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+      maps[nmaps++] = get_local_map (PT, current_buffer);
+    }
+
+  /* Add global keymap at the end.  */
+  maps[nmaps++] = current_global_map;
+
+  /* Process maps in reverse order and look up in each map the prefix
+     key `tool-bar'.  */
+  for (i = nmaps - 1; i >= 0; --i)
+    if (!NILP (maps[i]))
+      {
+       Lisp_Object keymap;
+      
+       keymap = get_keyelt (access_keymap (maps[i], Qtool_bar, 1, 1), 0);
+       if (!NILP (Fkeymapp (keymap)))
+         {
+           Lisp_Object tail;
+           
+           /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
+           for (tail = keymap; CONSP (tail); tail = XCDR (tail))
+             {
+               Lisp_Object keydef = XCAR (tail);
+               if (CONSP (keydef))
+                 process_tool_bar_item (XCAR (keydef), XCDR (keydef));
+             }
+         }
+      }
+
+  Vinhibit_quit = oquit;
+  *nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+  return tool_bar_items_vector;
+}
+
+
+/* Process the definition of KEY which is DEF.  */
+
+static void
+process_tool_bar_item (key, def)
+     Lisp_Object key, def;
+{
+  int i;
+  extern Lisp_Object Qundefined;
+  struct gcpro gcpro1, gcpro2;
+
+  /* Protect KEY and DEF from GC because parse_tool_bar_item may call
+     eval.  */
+  GCPRO2 (key, def);
+
+  if (EQ (def, Qundefined))
+    {
+      /* If a map has an explicit `undefined' as definition,
+        discard any previously made item.  */
+      for (i = 0; i < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS)
+       {
+         Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i;
+         
+         if (EQ (key, v[TOOL_BAR_ITEM_KEY]))
+           {
+             if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS)
+               bcopy (v + TOOL_BAR_ITEM_NSLOTS, v,
+                      ((ntool_bar_items - i - TOOL_BAR_ITEM_NSLOTS)
+                       * sizeof (Lisp_Object)));
+             ntool_bar_items -= TOOL_BAR_ITEM_NSLOTS;
+             break;
            }
        }
     }
+  else if (parse_tool_bar_item (key, def))
+    /* Append a new tool bar item to tool_bar_items_vector.  Accept
+       more than one definition for the same key.  */
+    append_tool_bar_item ();
+
+  UNGCPRO;
+}
+
+
+/* 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
+   invalid.
+
+   ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
+   
+   CAPTION is the caption of the item,  If it's not a string, it is
+   evaluated to get a string.
+   
+   BINDING is the tool bar item's binding.  Tool-bar items with keymaps
+   as binding are currently ignored.
+
+   The following properties are recognized:
+
+   - `:enable FORM'.
+   
+   FORM is evaluated and specifies whether the tool bar item is
+   enabled or disabled.
+   
+   - `:visible FORM'
+   
+   FORM is evaluated and specifies whether the tool bar item is visible.
+   
+   - `:filter FUNCTION'
+
+   FUNCTION is invoked with one parameter `(quote BINDING)'.  Its
+   result is stored as the new binding.
+   
+   - `:button (TYPE SELECTED)'
+
+   TYPE must be one of `:radio' or `:toggle'.  SELECTED is evaluated
+   and specifies whether the button is selected (pressed) or not.
+   
+   - `:image IMAGES'
+
+   IMAGES is either a single image specification or a vector of four
+   image specifications.  See enum tool_bar_item_images.
+   
+   - `:help HELP-STRING'.
+   
+   Gives a help string to display for the tool bar item.  */
+
+static int
+parse_tool_bar_item (key, item)
+     Lisp_Object key, 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;
+  extern Lisp_Object QCenable, QCvisible, QChelp, QCfilter;
+  extern Lisp_Object QCbutton, QCtoggle, QCradio;
+  int i;
+
+  /* Defininition looks like `(tool-bar-item CAPTION BINDING
+     PROPS...)'.  Rule out items that aren't lists, don't start with
+     `tool-bar-item' or whose rest following `tool-bar-item' is not a
+     list.  */
+  if (!CONSP (item)
+      || !EQ (XCAR (item), Qmenu_item)
+      || (item = XCDR (item),
+         !CONSP (item)))
+    return 0;
+
+  /* Create tool_bar_item_properties vector if necessary.  Reset it to
+     defaults.  */
+  if (VECTORP (tool_bar_item_properties))
+    {
+      for (i = 0; i < TOOL_BAR_ITEM_NSLOTS; ++i)
+       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;
+        
+  /* 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
+     item.  */
+  caption = XCAR (item);
+  if (!STRINGP (caption))
+    {
+      caption = menu_item_eval_property (caption);
+      if (!STRINGP (caption))
+       return 0;
+    }
+  PROP (TOOL_BAR_ITEM_CAPTION) = caption;
+
+  /* Give up if rest following the caption is not a list.  */
+  item = XCDR (item);
+  if (!CONSP (item))
+    return 0;
+
+  /* Store the binding.  */
+  PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
+  item = XCDR (item);
+
+  /* Process the rest of the properties.  */
+  for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
+    {
+      Lisp_Object key, value;
+
+      key = XCAR (item);
+      value = XCAR (XCDR (item));
+
+      if (EQ (key, QCenable))
+       /* `:enable FORM'.  */
+       PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+      else if (EQ (key, QCvisible))
+       {
+         /* `:visible FORM'.  If got a visible property and that
+            evaluates to nil then ignore this item.  */
+         if (NILP (menu_item_eval_property (value)))
+           return 0;
+       }
+      else if (EQ (key, QChelp))
+       /* `:help HELP-STRING'.  */
+       PROP (TOOL_BAR_ITEM_HELP) = value;
+      else if (EQ (key, QCfilter))
+       /* ':filter FORM'.  */
+       filter = value;
+      else if (EQ (key, QCbutton) && CONSP (value))
+       {
+         /* `:button (TYPE . SELECTED)'.  */
+         Lisp_Object type, selected;
+
+         type = XCAR (value);
+         selected = XCDR (value);
+         if (EQ (type, QCtoggle) || EQ (type, QCradio))
+           {
+             PROP (TOOL_BAR_ITEM_SELECTED_P) = selected;
+             PROP (TOOL_BAR_ITEM_TYPE) = type;
+           }
+       }
+      else if (EQ (key, QCimage)
+              && (CONSP (value)
+                  || (VECTORP (value) && XVECTOR (value)->size == 4)))
+       /* Value is either a single image specification or a vector
+          of 4 such specifications for the different buttion states.  */
+       PROP (TOOL_BAR_ITEM_IMAGES) = value;
+    }
+
+  /* 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))));
+
+  /* See if the binding is a keymap.  Give up if it is.  */
+  if (!NILP (get_keymap_1 (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
+    return 0;
+
+  /* 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));
+
+  /* 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));
+
+  return 1;
+  
+#undef PROP
 }
 
-/* This is used as the handler when calling internal_condition_case_1.  */
 
-static Lisp_Object
-menu_bar_item_1 (arg)
-     Lisp_Object arg;
+/* Initialize tool_bar_items_vector.  REUSE, if non-nil, is a vector
+   that can be reused.  */
+
+static void
+init_tool_bar_items (reuse)
+     Lisp_Object reuse;
 {
-  return Qnil;
+  if (VECTORP (reuse))
+    tool_bar_items_vector = reuse;
+  else
+    tool_bar_items_vector = Fmake_vector (make_number (64), Qnil);
+  ntool_bar_items = 0;
 }
 
-/* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
-   If there's already an item for KEY, add this DEF to it.  */
+
+/* Append parsed tool bar item properties from
+   tool_bar_item_properties */
 
 static void
-menu_bar_item (key, item_string, def)
-     Lisp_Object key, item_string, def;
+append_tool_bar_item ()
 {
-  Lisp_Object tem;
-  Lisp_Object enabled;
-  int i;
-
-  /* Skip menu-bar equiv keys data.  */
-  if (CONSP (def) && CONSP (XCONS (def)->car))
-    def = XCONS (def)->cdr;
-
-  if (EQ (def, Qundefined))
+  Lisp_Object *to, *from;
+  
+  /* Enlarge tool_bar_items_vector if necessary.  */
+  if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS
+      >= XVECTOR (tool_bar_items_vector)->size)
     {
-      /* If a map has an explicit `undefined' as definition,
-        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 (menu_bar_items_index > i + 4)
-             bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
-                    &XVECTOR (menu_bar_items_vector)->contents[i],
-                    (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
-           menu_bar_items_index -= 4;
-           return;
-         }
-
-      /* If there's no definition for this key yet,
-        just ignore `undefined'.  */
-      return;
+      Lisp_Object new_vector;
+      int old_size = XVECTOR (tool_bar_items_vector)->size;
+
+      new_vector = Fmake_vector (make_number (2 * old_size), Qnil);
+      bcopy (XVECTOR (tool_bar_items_vector)->contents,
+            XVECTOR (new_vector)->contents,
+            old_size * sizeof (Lisp_Object));
+      tool_bar_items_vector = new_vector;
     }
 
-  /* See if this entry is enabled.  */
-  enabled = Qt;
+  /* 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;
+  bcopy (from, to, TOOL_BAR_ITEM_NSLOTS * sizeof *to);
+  ntool_bar_items += TOOL_BAR_ITEM_NSLOTS;
+}
 
-  if (SYMBOLP (def))
-    {
-      /* No property, or nil, means enable.
-        Otherwise, enable if value is not nil.  */
-      tem = Fget (def, Qmenu_enable);
-      if (!NILP (tem))
-       /* (condition-case nil (eval tem)
-            (error nil))  */
-       enabled = internal_condition_case_1 (Feval, tem, Qerror,
-                                            menu_bar_item_1);
-    }
 
-  /* Ignore this item if it's not enabled.  */
-  if (NILP (enabled))
-    return;
 
-  /* 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]))
-      break;
 
-  /* If we did not find this KEY, add it at the end.  */
-  if (i == menu_bar_items_index)
-    {
-      /* If vector is too small, get a bigger one.  */
-      if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
-       {
-         Lisp_Object tem;
-         int newsize = 2 * i;
-         tem = Fmake_vector (make_number (2 * i), Qnil);
-         bcopy (XVECTOR (menu_bar_items_vector)->contents,
-                XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
-         menu_bar_items_vector = tem;
-       }
-      /* Add this item.  */
-      XVECTOR (menu_bar_items_vector)->contents[i++] = key;
-      XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
-      XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
-      XVECTOR (menu_bar_items_vector)->contents[i++] = make_number (0);
-      menu_bar_items_index = i;
-    }
-  /* We did find an item for this KEY.  Add DEF to its list of maps.  */
-  else
-    {
-      Lisp_Object old;
-      old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
-      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (def, old);
-    }
-}
 \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.
@@ -5425,7 +6868,6 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
 {
   int mapno;
   register Lisp_Object name;
-  Lisp_Object rest, vector;
 
   if (used_mouse_menu)
     *used_mouse_menu = 0;
@@ -5458,7 +6900,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
   if (EVENT_HAS_PARAMETERS (prev_event)
-      && !EQ (XCONS (prev_event)->car, Qmenu_bar))
+      && !EQ (XCAR (prev_event), Qmenu_bar)
+      && !EQ (XCAR (prev_event), Qtool_bar))
     {
       /* Display the menu and get the selection.  */
       Lisp_Object *realmaps
@@ -5476,7 +6919,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
        {
          Lisp_Object tem;
 
-         record_menu_key (XCONS (value)->car);
+         record_menu_key (XCAR (value));
 
          /* If we got multiple events, unread all but
             the first.
@@ -5486,22 +6929,22 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
             to indicate that they came from a mouse menu,
             so that when present in last_nonmenu_event
             they won't confuse things.  */
-         for (tem = XCONS (value)->cdr; !NILP (tem);
-              tem = XCONS (tem)->cdr)
+         for (tem = XCDR (value); !NILP (tem);
+              tem = XCDR (tem))
            {
-             record_menu_key (XCONS (tem)->car);
-             if (SYMBOLP (XCONS (tem)->car)
-                 || INTEGERP (XCONS (tem)->car))
-               XCONS (tem)->car
-                 = Fcons (XCONS (tem)->car, Qnil);
+             record_menu_key (XCAR (tem));
+             if (SYMBOLP (XCAR (tem))
+                 || INTEGERP (XCAR (tem)))
+               XCAR (tem)
+                 = Fcons (XCAR (tem), Qnil);
            }
 
          /* If we got more than one event, put all but the first
             onto this list to be read later.
             Return just the first event now.  */
          Vunread_command_events
-           = nconc2 (XCONS (value)->cdr, Vunread_command_events);
-         value = XCONS (value)->car;
+           = nconc2 (XCDR (value), Vunread_command_events);
+         value = XCAR (value);
        }
       else if (NILP (value))
        value = Qt;
@@ -5528,7 +6971,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   int mapno;
   register Lisp_Object name;
   int nlength;
-  int width = FRAME_WIDTH (selected_frame) - 4;
+  int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
@@ -5565,7 +7008,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
 
   /* Prompt string always starts with map's prompt, and a space.  */
   strcpy (menu, XSTRING (name)->data);
-  nlength = XSTRING (name)->size;
+  nlength = STRING_BYTES (XSTRING (name));
   menu[nlength++] = ':';
   menu[nlength++] = ' ';
   menu[nlength] = 0;
@@ -5586,7 +7029,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
       /* Loop over elements of map.  */
       while (i < width)
        {
-         Lisp_Object s, elt;
+         Lisp_Object elt;
 
          /* If reached end of map, start at beginning of next map.  */
          if (NILP (rest))
@@ -5619,26 +7062,27 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
          else
            {
              /* An ordinary element.  */
-             Lisp_Object event;
+             Lisp_Object event, tem;
 
              if (idx < 0)
                {
-                 s = Fcar_safe (Fcdr_safe (elt));      /* alist */
-                 event = Fcar_safe (elt);
+                 event = Fcar_safe (elt); /* alist */
+                 elt = Fcdr_safe (elt);
                }
              else
                {
-                 s = Fcar_safe (elt);                  /* vector */
-                 XSETINT (event, idx);
+                 XSETINT (event, idx); /* vector */
                }
 
              /* Ignore the element if it has no prompt string.  */
-             if (STRINGP (s) && INTEGERP (event))
+             if (INTEGERP (event) && parse_menu_item (elt, 0, -1))
                {
                  /* 1 if the char to type matches the string.  */
                  int char_matches;
                  Lisp_Object upcased_event, downcased_event;
                  Lisp_Object desc;
+                 Lisp_Object s
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
 
                  upcased_event = Fupcase (event);
                  downcased_event = Fdowncase (event);
@@ -5647,6 +7091,27 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
                  if (! char_matches)
                    desc = Fsingle_key_description (event);
 
+                 tem
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+                 if (!NILP (tem))
+                   /* Insert equivalent keybinding. */
+                   s = concat2 (s, tem);
+
+                 tem
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
+                 if (EQ (tem, QCradio) || EQ (tem, QCtoggle))
+                   {
+                     /* Insert button prefix. */
+                     Lisp_Object selected
+                       = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+                     if (EQ (tem, QCradio))
+                       tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+                     else
+                       tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+                     s = concat2 (tem, s);
+                   }
+                 
+
                  /* If we have room for the prompt string, add it to this line.
                     If this is the first on the line, always add it.  */
                  if ((XSTRING (s)->size + i + 2
@@ -5708,7 +7173,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
        }
 
       /* Prompt with that and read response.  */
-      message1 (menu);
+      message2_nolog (menu, strlen (menu), 
+                     ! NILP (current_buffer->enable_multibyte_characters));
 
       /* Make believe its not a keyboard macro in case the help char
         is pressed.  Help characters are not recorded because menu prompting
@@ -5960,7 +7426,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int prev_keytran_start;
   int prev_keytran_end;
 
+#if defined (GOBBLE_FIRST_EVENT)
   int junk;
+#endif
+
+  raw_keybuf_count = 0;
 
   last_nonmenu_event = Qnil;
 
@@ -5980,7 +7450,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
     {
       if (!NILP (prompt))
        echo_prompt (XSTRING (prompt)->data);
-      else if (cursor_in_echo_area && echo_keystrokes)
+      else if (cursor_in_echo_area
+              && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+              && NILP (Fzerop (Vecho_keystrokes)))
        /* This doesn't put in a dash if the echo buffer is empty, so
           you don't always see a dash hanging out in the minibuffer.  */
        echo_dash ();
@@ -6048,11 +7520,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            nmaps_allocated = nmaps + 2;
          }
        bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
-#ifdef USE_TEXT_PROPERTIES
        submaps[nmaps++] = orig_local_map;
-#else
-       submaps[nmaps++] = current_buffer->keymap;
-#endif
       }
     submaps[nmaps++] = current_global_map;
   }
@@ -6130,19 +7598,18 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
        {
          key = keybuf[t];
          add_command_key (key);
-         if (echo_keystrokes)
+         if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+             && NILP (Fzerop (Vecho_keystrokes)))
            echo_char (key);
        }
 
       /* If not, we should actually read a character.  */
       else
        {
-         struct buffer *buf = current_buffer;
-
          {
 #ifdef MULTI_KBOARD
            KBOARD *interrupted_kboard = current_kboard;
-           struct frame *interrupted_frame = selected_frame;
+           struct frame *interrupted_frame = SELECTED_FRAME ();
            if (setjmp (wrong_kboard_jmpbuf))
              {
                if (!NILP (delayed_switch_frame))
@@ -6159,7 +7626,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                /* If the side queue is non-empty, ensure it begins with a
                   switch-frame, so we'll replay it in the right context.  */
                if (CONSP (interrupted_kboard->kbd_queue)
-                   && (key = XCONS (interrupted_kboard->kbd_queue)->car,
+                   && (key = XCAR (interrupted_kboard->kbd_queue),
                        !(EVENT_HAS_PARAMETERS (key)
                          && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)),
                                 Qswitch_frame))))
@@ -6182,7 +7649,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          /* read_char returns t when it shows a menu and the user rejects it.
             Just return -1.  */
          if (EQ (key, Qt))
-           return -1;
+           {
+             unbind_to (count, Qnil);
+             return -1;
+           }
 
          /* read_char returns -1 at the end of a macro.
             Emacs 18 handles this by returning immediately with a
@@ -6206,8 +7676,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                 This is to be more consistent with the behavior
                 of the command_loop_1.  */
              if (fix_current_buffer)
-               if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
-                 Fset_buffer (XWINDOW (selected_window)->buffer);
+               {
+                 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+                   Fkill_emacs (Qnil);
+                 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+                   Fset_buffer (XWINDOW (selected_window)->buffer);
+               }
 
              orig_local_map = get_local_map (PT, current_buffer);
              goto replay_sequence;
@@ -6218,6 +7692,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
             replay to get the right keymap.  */
          if (XINT (key) == quit_char && current_buffer != starting_buffer)
            {
+             GROW_RAW_KEYBUF;
+             XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
              keybuf[t++] = key;
              mock_input = t;
              Vquit_flag = Qnil;
@@ -6226,6 +7702,22 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
            }
 
          Vquit_flag = Qnil;
+
+         if (EVENT_HAS_PARAMETERS (key)
+             && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
+           {
+             /* If we're at the beginning of a key sequence, and the caller
+                says it's okay, go ahead and return this event.  If we're
+                in the midst of a key sequence, delay it until the end. */
+             if (t > 0 || !can_return_switch_frame)
+               {
+                 delayed_switch_frame = key;
+                 goto replay_key;
+               }
+           }
+
+         GROW_RAW_KEYBUF;
+         XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
        }
 
       /* Clicks in non-text areas get prefixed by the symbol
@@ -6253,6 +7745,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
+
              if (CONSP (posn))
                {
                  /* We're looking at the second event of a
@@ -6271,6 +7764,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  && BUFFERP (XWINDOW (window)->buffer)
                  && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
                {
+                 XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
                  keybuf[t] = key;
                  mock_input = t + 1;
 
@@ -6286,20 +7780,25 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                     emacsclient).  */
                  record_unwind_protect (Fset_buffer, Fcurrent_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);
                  goto replay_sequence;
                }
+             
              /* For a mouse click, get the local text-property keymap
                 of the place clicked on, rather than point.  */
-             if (last_real_key_start == 0 && CONSP (XCONS (key)->cdr)
+             if (last_real_key_start == 0
+                 && CONSP (XCDR (key))
                  && ! localized_local_map)
                {
                  Lisp_Object map_here, start, pos;
 
                  localized_local_map = 1;
                  start = EVENT_START (key);
-                 if (CONSP (start) && CONSP (XCONS (start)->cdr))
+                 
+                 if (CONSP (start) && CONSP (XCDR (start)))
                    {
                      pos = POSN_BUFFER_POSN (start);
                      if (INTEGERP (pos)
@@ -6327,35 +7826,46 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
                  mock_input = t + 2;
-
+                 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
                  POSN_BUFFER_POSN (EVENT_START (key))
                    = Fcons (posn, Qnil);
+
+                 /* If on a mode line string with a local keymap,
+                    reconsider the key sequence with that keymap.  */
+                 if (CONSP (POSN_STRING (EVENT_START (key))))
+                   {
+                     Lisp_Object string, pos, map;
+
+                     string = POSN_STRING (EVENT_START (key));
+                     pos = XCDR (string);
+                     string = XCAR (string);
+                     
+                     if (pos >= 0
+                         && pos < XSTRING (string)->size
+                         && (map = Fget_text_property (pos, Qlocal_map,
+                                                       string),
+                             !NILP (map)))
+                       {
+                         orig_local_map = map;
+                         goto replay_sequence;
+                       }
+                   }
+
                  goto replay_key;
                }
            }
-         else if (EQ (kind, Qswitch_frame))
-           {
-             /* If we're at the beginning of a key sequence, and the caller
-                says it's okay, go ahead and return this event.  If we're
-                in the midst of a key sequence, delay it until the end. */
-             if (t > 0 || !can_return_switch_frame)
-               {
-                 delayed_switch_frame = key;
-                 goto replay_key;
-               }
-           }
-         else if (CONSP (XCONS (key)->cdr)
+         else if (CONSP (XCDR (key))
                   && CONSP (EVENT_START (key))
-                  && CONSP (XCONS (EVENT_START (key))->cdr))
+                  && CONSP (XCDR (EVENT_START (key))))
            {
              Lisp_Object posn;
 
              posn = POSN_BUFFER_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
-             if (EQ (posn, Qmenu_bar))
+             if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
@@ -6413,7 +7923,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              int modifiers;
 
              breakdown = parse_modifiers (head);
-             modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+             modifiers = XINT (XCAR (XCDR (breakdown)));
              /* Attempt to reduce an unbound mouse event to a simpler
                 event that is bound:
                   Drags reduce to clicks.
@@ -6482,7 +7992,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                        }
 
                      new_head
-                       = apply_modifiers (modifiers, XCONS (breakdown)->car);
+                       = apply_modifiers (modifiers, XCAR (breakdown));
                      new_click
                        = Fcons (new_head, Fcons (EVENT_START (key), Qnil));
 
@@ -6560,7 +8070,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                fkey_next = fkey_map;
 
              fkey_next
-               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 0);
+               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 1);
+
+             /* Handle symbol with autoload definition.  */
+             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+                 && CONSP (XSYMBOL (fkey_next)->function)
+                 && EQ (XCAR (XSYMBOL (fkey_next)->function), Qautoload))
+               do_autoload (XSYMBOL (fkey_next)->function,
+                            fkey_next);
+
+             /* Handle a symbol whose function definition is a keymap
+                or an array.  */
+             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+                 && (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
+                     || !NILP (Fkeymapp (XSYMBOL (fkey_next)->function))))
+               fkey_next = XSYMBOL (fkey_next)->function;
 
 #if 0 /* I didn't turn this on, because it might cause trouble
         for the mapping of return into C-m and tab into C-i.  */
@@ -6623,8 +8147,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  fkey_start = fkey_end = t;
                  fkey_map = Vfunction_key_map;
 
-                 /* Do pass the results through key-translation-map.  */
-                 keytran_start = keytran_end = 0;
+                 /* Do pass the results through key-translation-map.
+                    But don't retranslate what key-translation-map
+                    has already translated.  */
+                 keytran_end = keytran_start;
                  keytran_map = Vkey_translation_map;
 
                  goto replay_sequence;
@@ -6668,10 +8194,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              keytran_next = keytran_map;
 
            keytran_next
-             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 0);
+             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 1);
 
+           /* Handle symbol with autoload definition.  */
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+               && CONSP (XSYMBOL (keytran_next)->function)
+               && EQ (XCAR (XSYMBOL (keytran_next)->function), Qautoload))
+             do_autoload (XSYMBOL (keytran_next)->function,
+                          keytran_next);
+
+           /* Handle a symbol whose function definition is a keymap
+              or an array.  */
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+               && (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
+                   || !NILP (Fkeymapp (XSYMBOL (keytran_next)->function))))
+             keytran_next = XSYMBOL (keytran_next)->function;
+           
            /* If the key translation map gives a function, not an
-              array, then call the function with no args and use
+              array, then call the function with one arg and use
               its value instead.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
                && keytran_end == t)
@@ -6726,7 +8266,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                /* Don't pass the results of key-translation-map
                   through function-key-map.  */
                fkey_start = fkey_end = t;
-               fkey_map = Vkey_translation_map;
+               fkey_map = Vfunction_key_map;
 
                goto replay_sequence;
              }
@@ -6752,7 +8292,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          && ! key_translation_possible
          && INTEGERP (key)
          && ((((XINT (key) & 0x3ffff)
-               < XSTRING (current_buffer->downcase_table)->size)
+               < XCHAR_TABLE (current_buffer->downcase_table)->size)
               && UPPERCASEP (XINT (key) & 0x3ffff))
              || (XINT (key) & shift_modifier)))
        {
@@ -6795,7 +8335,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          int modifiers;
 
          breakdown = parse_modifiers (key);
-         modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+         modifiers = XINT (XCAR (XCDR (breakdown)));
          if (modifiers & shift_modifier)
            {
              Lisp_Object new_key;
@@ -6805,7 +8345,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              modifiers &= ~shift_modifier;
              new_key = apply_modifiers (modifiers,
-                                        XCONS (breakdown)->car);
+                                        XCAR (breakdown));
 
              keybuf[t - 1] = new_key;
              mock_input = t;
@@ -6848,11 +8388,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      Better ideas?  */
   for (; t < mock_input; t++)
     {
-      if (echo_keystrokes)
+      if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
+         && NILP (Fzerop (Vecho_keystrokes)))
        echo_char (keybuf[t]);
       add_command_key (keybuf[t]);
     }
 
+  
+
   return t;
 }
 
@@ -6899,24 +8442,91 @@ is nil, then the event will be put off until after the current key sequence.\n\
 \n\
 `read-key-sequence' checks `function-key-map' for function key\n\
 sequences, where they wouldn't conflict with ordinary bindings.  See\n\
-`function-key-map' for more details.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+`function-key-map' for more details.\n\
+\n\
+The optional fifth argument COMMAND-LOOP, if non-nil, means\n\
+that this key sequence is being read by something that will\n\
+read commands one after another.  It should be nil if the caller\n\
+will read just one key sequence.")
+  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
 #endif
 
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
   0)
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+   command_loop)
      Lisp_Object prompt, continue_echo, dont_downcase_last;
-     Lisp_Object can_return_switch_frame;
+     Lisp_Object can_return_switch_frame, command_loop;
 {
   Lisp_Object keybuf[30];
   register int i;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
+  int count = specpdl_ptr - specpdl;
+
+  if (!NILP (prompt))
+    CHECK_STRING (prompt, 0);
+  QUIT;
+
+  specbind (Qinput_method_exit_on_first_char,
+           (NILP (command_loop) ? Qt : Qnil));
+  specbind (Qinput_method_use_echo_area,
+           (NILP (command_loop) ? Qt : Qnil));
+
+  bzero (keybuf, sizeof keybuf);
+  GCPRO1 (keybuf[0]);
+  gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
+
+  if (NILP (continue_echo))
+    {
+      this_command_key_count = 0;
+      this_single_command_key_start = 0;
+    }
+
+#ifdef HAVE_X_WINDOWS
+  if (display_busy_cursor_p)
+    cancel_busy_cursor ();
+#endif
+
+  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+                        prompt, ! NILP (dont_downcase_last),
+                        ! NILP (can_return_switch_frame), 0);
+
+#ifdef HAVE_X_WINDOWS
+  if (display_busy_cursor_p)
+    start_busy_cursor ();
+#endif
+
+  if (i == -1)
+    {
+      Vquit_flag = Qt;
+      QUIT;
+    }
+  UNGCPRO;
+  return unbind_to (count, make_event_array (i, keybuf));
+}
+
+DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
+       Sread_key_sequence_vector, 1, 5, 0,
+  "Like `read-key-sequence' but always return a vector.")
+  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+   command_loop)
+     Lisp_Object prompt, continue_echo, dont_downcase_last;
+     Lisp_Object can_return_switch_frame, command_loop;
+{
+  Lisp_Object keybuf[30];
+  register int i;
+  struct gcpro gcpro1;
+  int count = specpdl_ptr - specpdl;
 
   if (!NILP (prompt))
     CHECK_STRING (prompt, 0);
   QUIT;
 
+  specbind (Qinput_method_exit_on_first_char,
+           (NILP (command_loop) ? Qt : Qnil));
+  specbind (Qinput_method_use_echo_area,
+           (NILP (command_loop) ? Qt : Qnil));
+
   bzero (keybuf, sizeof keybuf);
   GCPRO1 (keybuf[0]);
   gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
@@ -6927,17 +8537,27 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
       this_single_command_key_start = 0;
     }
 
+#ifdef HAVE_X_WINDOWS
+  if (display_busy_cursor_p)
+    cancel_busy_cursor ();
+#endif
+
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
                         ! NILP (can_return_switch_frame), 0);
 
+#ifdef HAVE_X_WINDOWS
+  if (display_busy_cursor_p)
+    start_busy_cursor ();
+#endif
+
   if (i == -1)
     {
       Vquit_flag = Qt;
       QUIT;
     }
   UNGCPRO;
-  return make_event_array (i, keybuf);
+  return unbind_to (count, Fvector (i, keybuf));
 }
 \f
 DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
@@ -7003,13 +8623,24 @@ a special event, so ignore the prefix argument and don't clear it.")
         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);
+       {
+         Vcommand_history
+           = Fcons (Fcons (Qexecute_kbd_macro,
+                           Fcons (final, Fcons (prefixarg, Qnil))),
+                    Vcommand_history);
+
+         /* Don't keep command history around forever.  */
+         if (NUMBERP (Vhistory_length) && XINT (Vhistory_length) > 0)
+           {
+             tem = Fnthcdr (Vhistory_length, Vcommand_history);
+             if (CONSP (tem))
+               XCDR (tem) = Qnil;
+           }
+       }
 
       return Fexecute_kbd_macro (final, prefixarg);
     }
+
   if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
     {
       backtrace.next = backtrace_list;
@@ -7046,14 +8677,14 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 
   if (EQ (prefixarg, Qminus))
     strcpy (buf, "- ");
-  else if (CONSP (prefixarg) && XINT (XCONS (prefixarg)->car) == 4)
+  else if (CONSP (prefixarg) && XINT (XCAR (prefixarg)) == 4)
     strcpy (buf, "C-u ");
-  else if (CONSP (prefixarg) && INTEGERP (XCONS (prefixarg)->car))
+  else if (CONSP (prefixarg) && INTEGERP (XCAR (prefixarg)))
     {
       if (sizeof (int) == sizeof (EMACS_INT))
-       sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car));
+       sprintf (buf, "%d ", XINT (XCAR (prefixarg)));
       else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", XINT (XCONS (prefixarg)->car));
+       sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
       else
        abort ();
     }
@@ -7062,7 +8693,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
       if (sizeof (int) == sizeof (EMACS_INT))
        sprintf (buf, "%d ", XINT (prefixarg));
       else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", XINT (prefixarg));
+       sprintf (buf, "%ld ", (long) XINT (prefixarg));
       else
        abort ();
     }
@@ -7078,7 +8709,8 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
      history list. */
   function = Fcompleting_read (build_string (buf),
                               Vobarray, Qcommandp,
-                              Qt, Qnil, Qextended_command_history, Qnil);
+                              Qt, Qnil, Qextended_command_history, Qnil,
+                              Qnil);
 
   if (STRINGP (function) && XSTRING (function)->size == 0)
     error ("No command name given");
@@ -7089,7 +8721,6 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     struct Lisp_String *str;
     Lisp_Object *keys;
     int i;
-    Lisp_Object tem;
 
     this_command_key_count = 0;
     this_single_command_key_start = 0;
@@ -7100,20 +8731,17 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 
     str = XSTRING (function);
     for (i = 0; i < str->size; i++)
-      {
-       XSETFASTINT (tem, str->data[i]);
-       add_command_key (tem);
-      }
+      add_command_key (Faref (function, make_number (i)));
 
-    XSETFASTINT (tem, '\015');
-    add_command_key (tem);
+    add_command_key (make_number ('\015'));
   }
 
   UNGCPRO;
 
   function = Fintern (function, Qnil);
   current_kboard->Vprefix_arg = prefixarg;
-  this_command = function;
+  Vthis_command = function;
+  real_this_command = function;
 
   /* If enabled, show which key runs this command.  */
   if (!NILP (Vsuggest_key_bindings)
@@ -7129,33 +8757,48 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   value = Fcommand_execute (function, Qt, Qnil, Qnil);
 
   /* If the command has a key binding, print it now.  */
-  if (!NILP (bindings))
+  if (!NILP (bindings)
+      && ! (VECTORP (bindings) && EQ (Faref (bindings, make_number (0)),
+                                     Qmouse_movement)))
     {
       /* But first wait, and skip the message if there is input.  */
-      if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
-                           ? Vsuggest_key_bindings : make_number (2)),
-                          Qnil, Qnil))
+      int delay_time;
+      if (!NILP (echo_area_buffer[0]))
+       /* This command displayed something in the echo area;
+          so wait a few seconds, then display our suggestion message.  */
+       delay_time = (NUMBERP (Vsuggest_key_bindings)
+                     ? XINT (Vsuggest_key_bindings) : 2);
+      else
+       /* This command left the echo area empty,
+          so display our message immediately.  */
+       delay_time = 0;
+
+      if (!NILP (Fsit_for (make_number (delay_time), Qnil, Qnil))
          && ! CONSP (Vunread_command_events))
        {
          Lisp_Object binding;
          char *newmessage;
-         char *oldmessage = echo_area_glyphs;
-         int oldmessage_len = echo_area_glyphs_length;
+         int message_p = push_message ();
 
          binding = Fkey_description (bindings);
 
          newmessage
            = (char *) alloca (XSYMBOL (function)->name->size
-                              + XSTRING (binding)->size
+                              + STRING_BYTES (XSTRING (binding))
                               + 100);
-         sprintf (newmessage, "You can run the command `%s' by typing %s",
+         sprintf (newmessage, "You can run the command `%s' with %s",
                   XSYMBOL (function)->name->data,
                   XSTRING (binding)->data);
-         message1_nolog (newmessage);
+         message2_nolog (newmessage,
+                         strlen (newmessage),
+                         STRING_MULTIBYTE (binding));
          if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
                                ? Vsuggest_key_bindings : make_number (2)),
-                              Qnil, Qnil)))
-           message2_nolog (oldmessage, oldmessage_len);
+                              Qnil, Qnil))
+             && message_p)
+           restore_message ();
+
+         pop_message ();
        }
     }
 
@@ -7191,11 +8834,7 @@ current_active_maps (maps_p)
       nmaps = current_minor_maps (NULL, &tmaps);
       maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0]));
       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
-#ifdef USE_TEXT_PROPERTIES
       maps[nmaps++] = get_local_map (PT, current_buffer);
-#else
-      maps[nmaps++] = current_buffer->keymap;
-#endif
     }
   maps[nmaps++] = current_global_map;
 
@@ -7205,6 +8844,7 @@ current_active_maps (maps_p)
 \f
 /* Return nonzero if input events are pending.  */
 
+int
 detect_input_pending ()
 {
   if (!input_pending)
@@ -7215,6 +8855,7 @@ detect_input_pending ()
 
 /* Return nonzero if input events are pending, and run any pending timers.  */
 
+int
 detect_input_pending_run_timers (do_display)
      int do_display;
 {
@@ -7224,7 +8865,16 @@ detect_input_pending_run_timers (do_display)
     get_input_pending (&input_pending, 1);
 
   if (old_timers_run != timers_run && do_display)
-    redisplay_preserve_echo_area ();
+    {
+      redisplay_preserve_echo_area ();
+      /* The following fixes a bug when using lazy-lock with
+        lazy-lock-defer-on-the-fly set to t, i.e.  when fontifying
+        from an idle timer function.  The symptom of the bug is that
+        the cursor sometimes doesn't become visible until the next X
+        event is processed.  --gerd.  */
+      if (rif)
+       rif->flush_display (NULL);
+    }
 
   return input_pending;
 }
@@ -7232,6 +8882,8 @@ detect_input_pending_run_timers (do_display)
 /* This is called in some cases before a possible quit.
    It cases the next call to detect_input_pending to recompute input_pending.
    So calling this function unnecessarily can't do any harm.  */
+
+void
 clear_input_pending ()
 {
   input_pending = 0;
@@ -7243,6 +8895,7 @@ clear_input_pending ()
    The problem is, kbd_buffer_get_event needs to be fixed to know what
    to do in that case.  It isn't trivial.  */
 
+int
 requeued_events_pending_p ()
 {
   return (!NILP (Vunread_command_events) || unread_command_char != -1);
@@ -7292,18 +8945,38 @@ The value is a string or a vector.")
                           XVECTOR (this_command_keys)->contents);
 }
 
+DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
+  "Return the key sequence that invoked this command, as a vector.")
+  ()
+{
+  return Fvector (this_command_key_count,
+                 XVECTOR (this_command_keys)->contents);
+}
+
 DEFUN ("this-single-command-keys", Fthis_single_command_keys,
        Sthis_single_command_keys, 0, 0, 0,
   "Return the key sequence that invoked this command.\n\
 Unlike `this-command-keys', this function's value\n\
 does not include prefix arguments.\n\
-The value is a string or a vector.")
+The value is always a vector.")
+  ()
+{
+  return Fvector (this_command_key_count
+                 - this_single_command_key_start,
+                 (XVECTOR (this_command_keys)->contents
+                  + this_single_command_key_start));
+}
+
+DEFUN ("this-single-command-raw-keys", Fthis_single_command_raw_keys,
+       Sthis_single_command_raw_keys, 0, 0, 0,
+  "Return the raw events that were read for this command.\n\
+Unlike `this-single-command-keys', this function's value\n\
+shows the events before all translations (except for input methods).\n\
+The value is always a vector.")
   ()
 {
-  return make_event_array (this_command_key_count
-                          - this_single_command_key_start,
-                          (XVECTOR (this_command_keys)->contents
-                           + this_single_command_key_start));
+  return Fvector (raw_keybuf_count,
+                 (XVECTOR (raw_keybuf)->contents));
 }
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
@@ -7324,6 +8997,24 @@ appears in the echo area and in the value of `this-command-keys.'.")
   before_command_restore_flag = 1;
   before_command_key_count_1 = before_command_key_count;
   before_command_echo_length_1 = before_command_echo_length;
+  return Qnil;
+}
+
+DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
+  Sclear_this_command_keys, 0, 0, 0,
+  "Clear out the vector that `this-command-keys' returns.\n\
+Clear vector containing last 100 events.")
+  ()
+{
+  int i;
+  
+  this_command_key_count = 0;
+
+  for (i = 0; i < XVECTOR (recent_keys)->size; ++i)
+    XVECTOR (recent_keys)->contents[i] = Qnil;
+  total_keys = 0;
+  recent_keys_index = 0;
+  return Qnil;
 }
 
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
@@ -7370,10 +9061,7 @@ Also cancel any kbd macro being defined.")
 
   discard_tty_input ();
 
-  /* Without the cast, GCC complains that this assignment loses the
-     volatile qualifier of kbd_store_ptr.  Is there anything wrong
-     with that?  */
-  kbd_fetch_ptr = (struct input_event *) kbd_store_ptr;
+  kbd_fetch_ptr =  kbd_store_ptr;
   Ffillarray (kbd_buffer_frame_or_window, Qnil);
   input_pending = 0;
 
@@ -7395,12 +9083,10 @@ On such systems, Emacs starts a subshell instead of suspending.")
   (stuffstring)
      Lisp_Object stuffstring;
 {
-  Lisp_Object tem;
   int count = specpdl_ptr - specpdl;
   int old_height, old_width;
   int width, height;
-  struct gcpro gcpro1, gcpro2;
-  extern init_sys_modes ();
+  struct gcpro gcpro1;
 
   if (!NILP (stuffstring))
     CHECK_STRING (stuffstring, 0);
@@ -7414,7 +9100,8 @@ On such systems, Emacs starts a subshell instead of suspending.")
   reset_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 (init_sys_modes, 0);
+  record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes,
+                        Qnil);
   stuff_buffered_input (stuffstring);
   if (cannot_suspend)
     sys_subshell ();
@@ -7427,7 +9114,7 @@ On such systems, Emacs starts a subshell instead of suspending.")
      with a window system; but suspend should be disabled in that case.  */
   get_frame_size (&width, &height);
   if (width != old_width || height != old_height)
-    change_frame_size (selected_frame, height, width, 0, 0);
+    change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);
 
   /* Run suspend-resume-hook.  */
   if (!NILP (Vrun_hooks))
@@ -7440,6 +9127,7 @@ On such systems, Emacs starts a subshell instead of suspending.")
 /* If STUFFSTRING is a string, stuff its contents as pending terminal input.
    Then in any case stuff anything Emacs has read ahead and not used.  */
 
+void
 stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
@@ -7453,7 +9141,7 @@ stuff_buffered_input (stuffstring)
       register int count;
 
       p = XSTRING (stuffstring)->data;
-      count = XSTRING (stuffstring)->size;
+      count = STRING_BYTES (XSTRING (stuffstring));
       while (count-- > 0)
        stuff_char (*p++);
       stuff_char ('\n');
@@ -7477,6 +9165,7 @@ stuff_buffered_input (stuffstring)
 #endif /* BSD_SYSTEM and not BSD4_1 */
 }
 \f
+void
 set_waiting_for_input (time_to_clear)
      EMACS_TIME *time_to_clear;
 {
@@ -7491,6 +9180,7 @@ set_waiting_for_input (time_to_clear)
     quit_throw_to_read_char ();
 }
 
+void
 clear_waiting_for_input ()
 {
   /* Tell interrupt_signal not to throw back to read_char,  */
@@ -7517,6 +9207,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   char c;
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
+  struct frame *sf = SELECTED_FRAME ();
 
 #if defined (USG) && !defined (POSIX_SIGNALS)
   if (!read_socket_hook && NILP (Vwindow_system))
@@ -7531,7 +9222,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   cancel_echoing ();
 
   if (!NILP (Vquit_flag)
-      && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
+      && (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)))
     {
       /* If SIGINT isn't blocked, don't let us be interrupted by
         another SIGINT, it might be harmful due to non-reentrancy
@@ -7628,9 +9319,17 @@ interrupt_signal (signalnum)     /* If we don't have an argument, */
         then quit right away.  */
       if (immediate_quit && NILP (Vinhibit_quit))
        {
+         struct gl_state_s saved;
+         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
          immediate_quit = 0;
           sigfree ();
+         saved = gl_state;
+         GCPRO4 (saved.object, saved.global_code,
+                 saved.current_syntax_table, saved.old_prop);
          Fsignal (Qquit, Qnil);
+         gl_state = saved;
+         UNGCPRO;
        }
       else
        /* Else request quit when it's safe */
@@ -7645,9 +9344,9 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
 
 /* Handle a C-g by making read_char return C-g.  */
 
+void
 quit_throw_to_read_char ()
 {
-  quit_error_check ();
   sigfree ();
   /* Prevent another signal from doing this before we finish.  */
   clear_waiting_for_input ();
@@ -7666,7 +9365,7 @@ quit_throw_to_read_char ()
 #endif
 #endif
   if (FRAMEP (internal_last_event_frame)
-      && XFRAME (internal_last_event_frame) != selected_frame)
+      && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     Qnil, 0);
 
@@ -7695,7 +9394,7 @@ See also `current-input-mode'.")
   stop_polling ();
 #endif
 
-#ifndef MSDOS
+#ifndef DOS_NT
   /* this causes startup screen to be restored and messes with the mouse */
   reset_sys_modes ();
 #endif
@@ -7734,7 +9433,7 @@ See also `current-input-mode'.")
     /* Don't let this value be out of range.  */
     quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
 
-#ifndef MSDOS
+#ifndef DOS_NT
   init_sys_modes ();
 #endif
 
@@ -7781,7 +9480,9 @@ init_kboard (kb)
 {
   kb->Voverriding_terminal_local_map = Qnil;
   kb->Vlast_command = Qnil;
+  kb->Vreal_last_command = Qnil;
   kb->Vprefix_arg = Qnil;
+  kb->Vlast_prefix_arg = Qnil;
   kb->kbd_queue = Qnil;
   kb->kbd_queue_has_data = 0;
   kb->immediate_echo = 0;
@@ -7825,6 +9526,7 @@ delete_kboard (kb)
 }
 #endif
 
+void
 init_keyboard ()
 {
   /* This is correct before outermost invocation of the editor loop */
@@ -7919,8 +9621,27 @@ struct event_head head_table[] = {
   &Qmake_frame_visible,        "make-frame-visible",   &Qmake_frame_visible,
 };
 
+void
 syms_of_keyboard ()
 {
+  /* Tool-bars.  */
+  QCimage = intern (":image");
+  staticpro (&QCimage);
+
+  staticpro (&Qhelp_echo);
+  Qhelp_echo = intern ("help-echo");
+
+  staticpro (&item_properties);
+  item_properties = Qnil;
+
+  staticpro (&tool_bar_item_properties);
+  tool_bar_item_properties = Qnil;
+  staticpro (&tool_bar_items_vector);
+  tool_bar_items_vector = Qnil;
+
+  staticpro (&real_this_command);
+  real_this_command = Qnil;
+
   Qtimer_event_handler = intern ("timer-event-handler");
   staticpro (&Qtimer_event_handler);
 
@@ -7961,9 +9682,42 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
+#ifdef WINDOWSNT
+  Qmouse_wheel = intern ("mouse-wheel");
+  staticpro (&Qmouse_wheel);
+  Qlanguage_change = intern ("language-change");
+  staticpro (&Qlanguage_change);
+#endif
+  Qdrag_n_drop = intern ("drag-n-drop");
+  staticpro (&Qdrag_n_drop);
+
+  Qusr1_signal = intern ("usr1-signal");
+  staticpro (&Qusr1_signal);
+  Qusr2_signal = intern ("usr2-signal");
+  staticpro (&Qusr2_signal);
 
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
+  Qmenu_alias = intern ("menu-alias");
+  staticpro (&Qmenu_alias);
+  QCenable = intern (":enable");
+  staticpro (&QCenable);
+  QCvisible = intern (":visible");
+  staticpro (&QCvisible);
+  QChelp = intern (":help");
+  staticpro (&QChelp);
+  QCfilter = intern (":filter");
+  staticpro (&QCfilter);
+  QCbutton = intern (":button");
+  staticpro (&QCbutton);
+  QCkeys = intern (":keys");
+  staticpro (&QCkeys);
+  QCkey_sequence = intern (":key-sequence");
+  staticpro (&QCkey_sequence);
+  QCtoggle = intern (":toggle");
+  staticpro (&QCtoggle);
+  QCradio = intern (":radio");
+  staticpro (&QCradio);
 
   Qmode_line = intern ("mode-line");
   staticpro (&Qmode_line);
@@ -7984,6 +9738,14 @@ syms_of_keyboard ()
   staticpro (&Qup);
   Qdown = intern ("down");
   staticpro (&Qdown);
+  Qtop = intern ("top");
+  staticpro (&Qtop);
+  Qbottom = intern ("bottom");
+  staticpro (&Qbottom);
+  Qend_scroll = intern ("end-scroll");
+  staticpro (&Qend_scroll);
+  Qratio = intern ("ratio");
+  staticpro (&Qratio);
 
   Qevent_kind = intern ("event-kind");
   staticpro (&Qevent_kind);
@@ -8002,6 +9764,17 @@ syms_of_keyboard ()
   Qpolling_period = intern ("polling-period");
   staticpro (&Qpolling_period);
 
+  Qinput_method_function = intern ("input-method-function");
+  staticpro (&Qinput_method_function);
+
+  Qinput_method_exit_on_first_char = intern ("input-method-exit-on-first-char");
+  staticpro (&Qinput_method_exit_on_first_char);
+  Qinput_method_use_echo_area = intern ("input-method-use-echo-area");
+  staticpro (&Qinput_method_use_echo_area);
+
+  Fset (Qinput_method_exit_on_first_char, Qnil);
+  Fset (Qinput_method_use_echo_area, Qnil);
+
   {
     struct event_head *p;
 
@@ -8036,6 +9809,9 @@ syms_of_keyboard ()
   this_command_keys = Fmake_vector (make_number (40), Qnil);
   staticpro (&this_command_keys);
 
+  raw_keybuf = Fmake_vector (make_number (30), Qnil);
+  staticpro (&raw_keybuf);
+
   Qextended_command_history = intern ("extended-command-history");
   Fset (Qextended_command_history, Qnil);
   staticpro (&Qextended_command_history);
@@ -8053,6 +9829,14 @@ syms_of_keyboard ()
   mouse_syms = Qnil;
   staticpro (&mouse_syms);
 
+#ifdef WINDOWSNT
+  mouse_wheel_syms = Qnil;
+  staticpro (&mouse_wheel_syms);
+  
+  drag_n_drop_syms = Qnil;
+  staticpro (&drag_n_drop_syms);
+#endif
+
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
 
@@ -8062,8 +9846,12 @@ syms_of_keyboard ()
   read_key_sequence_cmd = Qnil;
   staticpro (&read_key_sequence_cmd);
 
+  menu_bar_one_keymap_changed_items = Qnil;
+  staticpro (&menu_bar_one_keymap_changed_items);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
+  defsubr (&Sread_key_sequence_vector);
   defsubr (&Srecursive_edit);
 #ifdef HAVE_MOUSE
   defsubr (&Strack_mouse);
@@ -8072,8 +9860,11 @@ syms_of_keyboard ()
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
+  defsubr (&Sthis_command_keys_vector);
   defsubr (&Sthis_single_command_keys);
+  defsubr (&Sthis_single_command_raw_keys);
   defsubr (&Sreset_this_command_lengths);
+  defsubr (&Sclear_this_command_keys);
   defsubr (&Ssuspend_emacs);
   defsubr (&Sabort_recursive_edit);
   defsubr (&Sexit_recursive_edit);
@@ -8104,20 +9895,35 @@ so that you can determine whether the command was run by mouse or not.");
     "Last input event.");
 
   DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
-    "List of objects to be read as next command input events.");
+    "List of events to be read as the command input.\n\
+These events are processed first, before actual keyboard input.");
+  Vunread_command_events = Qnil;
 
   DEFVAR_INT ("unread-command-char", &unread_command_char,
     "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,
+    "List of events to be processed as input by input methods.\n\
+These events are processed after `unread-command-events', but\n\
+before actual keyboard input.");
+  Vunread_post_input_method_events = Qnil;
+
+  DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,
+    "List of events to be processed as input by input methods.\n\
+These events are processed after `unread-command-events', but\n\
+before actual keyboard input.");
+  Vunread_input_method_events = Qnil;
+
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
-    "Meta-prefix character code.  Meta-foo as command input\n\
-turns into this character followed by foo.");
+    "Meta-prefix character code.\n\
+Meta-foo as command input turns into this character followed by foo.");
   XSETINT (meta_prefix_char, 033);
 
   DEFVAR_KBOARD ("last-command", Vlast_command,
-    "The last command executed.  Normally a symbol with a function definition,\n\
-but can be whatever was found in the keymap, or whatever the variable\n\
-`this-command' was set to by that command.\n\
+    "The last command executed.\n\
+Normally a symbol with a function definition, but can be whatever was found\n\
+in the keymap, or whatever the variable `this-command' was set to by that\n\
+command.\n\
 \n\
 The value `mode-exit' is special; it means that the previous command\n\
 read an event that told it to exit, and it did so and unread that event.\n\
@@ -8127,14 +9933,17 @@ command exit.\n\
 The value `kill-region' is special; it means that the previous command\n\
 was a kill command.");
 
-  DEFVAR_LISP ("this-command", &this_command,
+  DEFVAR_KBOARD ("real-last-command", Vreal_last_command,
+    "Same as `last-command', but never altered by Lisp code.");
+
+  DEFVAR_LISP ("this-command", &Vthis_command,
     "The command now being executed.\n\
 The command can set this variable; whatever is put here\n\
 will be in `last-command' during the following command.");
-  this_command = Qnil;
+  Vthis_command = Qnil;
 
   DEFVAR_INT ("auto-save-interval", &auto_save_interval,
-    "*Number of keyboard input characters between auto-saves.\n\
+    "*Number of input events between auto-saves.\n\
 Zero means disable autosaving due to number of characters typed.");
   auto_save_interval = 300;
 
@@ -8145,9 +9954,10 @@ After auto-saving due to this many seconds of idle time,\n\
 Emacs also does a garbage collection if that seems to be warranted.");
   XSETFASTINT (Vauto_save_timeout, 30);
 
-  DEFVAR_INT ("echo-keystrokes", &echo_keystrokes,
-    "*Nonzero means echo unfinished commands after this many seconds of pause.");
-  echo_keystrokes = 1;
+  DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes,
+    "*Nonzero means echo unfinished commands after this many seconds of pause.\n\
+The value may be integer or floating point.");
+  Vecho_keystrokes = make_number (1);
 
   DEFVAR_INT ("polling-period", &polling_period,
     "*Interval between polling for input during Lisp execution.\n\
@@ -8225,8 +10035,8 @@ In a vector or a char-table, an element which is nil means \"no translation\".")
   Vkeyboard_translate_table = Qnil;
 
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
-    "Non-nil means to always spawn a subshell instead of suspending,\n\
-even if the operating system has support for stopping a process.");
+    "Non-nil means to always spawn a subshell instead of suspending.\n\
+\(Even if the operating system has support for stopping a process.\)");
   cannot_suspend = 0;
 
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
@@ -8270,12 +10080,16 @@ Buffer modification stores t in this variable.");
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
     "Normal hook run before each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
     "Normal hook run after each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
@@ -8350,7 +10164,7 @@ whenever `deferred-action-list' is non-nil.");
   Vdeferred_action_function = Qnil;
 
   DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
-    "Non-nil means show the equivalent key-binding when M-x command has one.\n\
+    "*Non-nil means show the equivalent key-binding when M-x command has one.\n\
 The value can be a length of time to show the message for.\n\
 If the value is non-nil and not a number, we wait 2 seconds.");
   Vsuggest_key_bindings = Qt;
@@ -8362,8 +10176,63 @@ If the value is non-nil and not a number, we wait 2 seconds.");
   DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
     "List of active idle-time timers in order of increasing time");
   Vtimer_idle_list = Qnil;
+
+  DEFVAR_LISP ("input-method-function", &Vinput_method_function,
+    "If non-nil, the function that implements the current input method.\n\
+It's called with one argument, a printing character that was just read.\n\
+\(That means a character with code 040...0176.)\n\
+Typically this function uses `read-event' to read additional events.\n\
+When it does so, it should first bind `input-method-function' to nil\n\
+so it will not be called recursively.\n\
+\n\
+The function should return a list of zero or more events\n\
+to be used as input.  If it wants to put back some events\n\
+to be reconsidered, separately, by the input method,\n\
+it can add them to the beginning of `unread-command-events'.\n\
+\n\
+The input method function can find in `input-method-previous-method'\n\
+the previous echo area message.\n\
+\n\
+The input method function should refer to the variables\n\
+`input-method-use-echo-area' and `input-method-exit-on-first-char'\n\
+for guidance on what to do.");
+  Vinput_method_function = Qnil;
+
+  DEFVAR_LISP ("input-method-previous-message",
+              &Vinput_method_previous_message,
+    "When `input-method-function' is called, hold the previous echo area message.\n\
+This variable exists because `read-event' clears the echo area\n\
+before running the input method.  It is nil if there was no message.");
+  Vinput_method_previous_message = Qnil;
+
+  DEFVAR_LISP ("show-help-function", &Vshow_help_function,
+    "If non-nil, the function that implements the display of help.\n\
+It's called with one argument, the help string to display.");
+  Vshow_help_function = Qnil;
+
+  DEFVAR_LISP ("disable-point-adjustment", &Vdisable_point_adjustment,
+    "If non-nil, suppress point adjustment after executing a command.\n\
+\n\
+After a command is executed, if point is moved into a region that has\n\
+special properties (e.g. composition, display), we adjust point to\n\
+the boundary of the region.  But, several special commands sets this\n\
+variable to non-nil, then we suppress the point adjustment.\n\
+\n\
+This variable is set to nil before reading a command, and is checked\n\
+just after executing the command");
+  Vdisable_point_adjustment = Qnil;
+
+  DEFVAR_LISP ("global-disable-point-adjustment",
+              &Vglobal_disable_point_adjustment,
+    "*If non-nil, always suppress point adjustment.\n\
+\n\
+The default value is nil, in which case, point adjustment are\n\
+suppressed only after special commands that set\n\
+`disable-point-adjustment' (which see) to non-nil.");
+  Vglobal_disable_point_adjustment = Qnil;
 }
 
+void
 keys_of_keyboard ()
 {
   initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");