(MULTIBYTE_BYTES_WIDTH): Delete the 2nd arg C. Use the
[bpt/emacs.git] / src / keyboard.c
index c6dbd5f..a50322f 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -32,11 +32,14 @@ Boston, MA 02111-1307, USA.  */
 #include "window.h"
 #include "commands.h"
 #include "buffer.h"
+#include "charset.h"
 #include "disptab.h"
 #include "dispextern.h"
 #include "keyboard.h"
+#include "syntax.h"
 #include "intervals.h"
 #include "blockinput.h"
+#include "puresize.h"
 #include <setjmp.h>
 #include <errno.h>
 
@@ -125,6 +128,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;
@@ -143,8 +162,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;
 
@@ -158,11 +184,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;
@@ -170,6 +205,9 @@ static int inhibit_local_menu_bar_menus;
 /* Nonzero means C-g should cause immediate error-signal.  */
 int immediate_quit;
 
+/* The user's ERASE setting.  */
+Lisp_Object Vtty_erase_char;
+
 /* Character to recognize as the help char.  */
 Lisp_Object Vhelp_char;
 
@@ -241,6 +279,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;
 
@@ -268,24 +314,27 @@ static int last_non_minibuf_size;
 static Lisp_Object Vauto_save_timeout;
 
 /* Total number of times read_char has returned.  */
-int num_input_chars;
+int num_input_events;
 
 /* Total number of times read_char has returned, outside of macros.  */
-int num_nonmacro_input_chars;
+int num_nonmacro_input_events;
 
 /* Auto-save automatically when this many characters have been typed
    since the last time.  */
 
 static int auto_save_interval;
 
-/* Value of num_nonmacro_input_chars as of last auto save.  */
+/* Value of num_nonmacro_input_events as of last auto save.  */
 
 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;
@@ -313,6 +362,7 @@ Lisp_Object Qself_insert_command;
 Lisp_Object Qforward_char;
 Lisp_Object Qbackward_char;
 Lisp_Object Qundefined;
+Lisp_Object Qtimer_event_handler;
 
 /* read_key_sequence stores here the command definition of the
    key sequence that it reads.  */
@@ -331,6 +381,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;
 
@@ -339,6 +397,8 @@ Lisp_Object Vdeactivate_mark;
 Lisp_Object Vlucid_menu_bar_dirty_flag;
 Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 
+Lisp_Object Qecho_area_clear_hook;
+
 /* Hooks to run before and after each command.  */
 Lisp_Object Qpre_command_hook, Vpre_command_hook;
 Lisp_Object Qpost_command_hook, Vpost_command_hook;
@@ -357,6 +417,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;
 
@@ -410,7 +473,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
@@ -433,18 +496,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;
-Lisp_Object Qtimer_event;
+#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);
@@ -465,15 +539,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 ();
+
 Lisp_Object Qpolling_period;
 
 /* List of absolute timers.  Appears in order of next scheduled event.  */
@@ -537,6 +613,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 ();
+static void save_getcjmp ();
+static void restore_getcjmp ();
+static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 
 /* > 0 if we are to echo keystrokes.  */
 static int echo_keystrokes;
@@ -552,6 +631,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;
 {
@@ -572,6 +652,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;
 {
@@ -597,10 +678,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
@@ -620,6 +702,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
@@ -644,6 +727,7 @@ echo_dash ()
 /* Display the current echo string, and begin echoing if not already
    doing so.  */
 
+void
 echo_now ()
 {
   if (!current_kboard->immediate_echo)
@@ -663,7 +747,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))
@@ -672,12 +758,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.  */
@@ -760,13 +848,15 @@ 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_chars;
+  last_auto_save = num_nonmacro_input_events;
 }
 
 /* Make an auto save happen as soon as possible at command level.  */
 
+void
 force_auto_save_soon ()
 {
   last_auto_save = - auto_save_interval - 1;
@@ -905,6 +995,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.  */
@@ -926,22 +1017,40 @@ 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;
 
   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 (!selected_frame->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 (selected_frame))
       || noninteractive)
-    stream = Qexternal_debugging_output;
+    {
+      stream = Qexternal_debugging_output;
+      kill_emacs_p = 1;
+    }
   else
     {
       Fdiscard_input ();
@@ -956,8 +1065,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));
@@ -977,13 +1085,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)
@@ -1066,7 +1178,7 @@ Lisp_Object
 command_loop_1 ()
 {
   Lisp_Object cmd, tem;
-  int lose;
+  int lose, lose2;
   int nonundocount;
   Lisp_Object keybuf[30];
   int i;
@@ -1079,6 +1191,7 @@ command_loop_1 ()
 #endif
 
   current_kboard->Vprefix_arg = Qnil;
+  current_kboard->Vlast_prefix_arg = Qnil;
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
   cancel_echoing ();
@@ -1101,16 +1214,22 @@ command_loop_1 ()
   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)))
+         && !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 (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));
@@ -1128,7 +1247,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
@@ -1138,7 +1258,8 @@ command_loop_1 ()
 
          Fsit_for (make_number (2), Qnil, Qnil);
          /* Clear the echo area.  */
-         message2 (0);
+         message2 (0, 0, 0);
+         safe_run_hooks (Qecho_area_clear_hook);
 
          unbind_to (count, Qnil);
 
@@ -1173,11 +1294,18 @@ 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);
+                            Qnil, 0, 1, 1);
+
+      /* A filter may have run while we were reading the input.  */
+      if (! FRAME_LIVE_P (selected_frame))
+       Fkill_emacs (Qnil);
+      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+       set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
 
       ++num_input_keys;
 
@@ -1205,8 +1333,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;
@@ -1234,13 +1364,14 @@ command_loop_1 ()
 
       /* 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 ();
@@ -1252,13 +1383,16 @@ 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_CHAR (PT);
+                 lose = FETCH_CHAR (PT_BYTE);
                  SET_PT (PT + 1);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
@@ -1266,6 +1400,9 @@ command_loop_1 ()
                           : (NILP (DISP_CHAR_VECTOR (dp, lose))
                              && (lose >= 0x20 && lose < 0x7f)))
                       : (lose >= 0x20 && lose < 0x7f))
+                     /* To extract the case of continuation on
+                         wide-column characters.  */
+                     && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT_BYTE)) == 1)
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1280,12 +1417,12 @@ command_loop_1 ()
                    no_redisplay = 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 (PT - 1);
-                 lose = FETCH_CHAR (PT);
+                 lose = FETCH_CHAR (PT_BYTE);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
                          ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
@@ -1306,13 +1443,12 @@ command_loop_1 ()
                    no_redisplay = 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 char c = XINT (last_command_char);
+                 unsigned int c = XINT (last_command_char);
                  int value;
-
                  if (NILP (Vexecuting_macro)
                      && !EQ (minibuf_window, selected_window))
                    {
@@ -1323,6 +1459,7 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
+                 
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1335,59 +1472,58 @@ 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_CHAR (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)
+                   no_redisplay = 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)
+           {
+             if (inhibit_busy_cursor != 2)
+               inhibit_busy_cursor = 0;
+             if (!inhibit_busy_cursor)
+               Fx_show_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);
        }
     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 (!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''
@@ -1404,28 +1540,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)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
-
       if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
@@ -1520,6 +1641,7 @@ input_poll_signal (signalnum)     /* If we don't have an argument, */
 /* 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
@@ -1550,6 +1672,7 @@ input_polling_used ()
 
 /* Turn off polling.  */
 
+void
 stop_polling ()
 {
 #ifdef POLL_FOR_INPUT
@@ -1589,6 +1712,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;
 {
@@ -1664,7 +1788,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
@@ -1680,24 +1807,34 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      Lisp_Object prev_event;
      int *used_mouse_menu;
 {
-  register Lisp_Object c;
+  Lisp_Object c;
   int count;
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   int key_already_recorded = 0;
   Lisp_Object tem, save;
+  Lisp_Object previous_echo_area_message;
   Lisp_Object also_record;
+  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;
+
+  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 = XCONS (Vunread_post_input_method_events)->car;
+      Vunread_post_input_method_events
+       = XCONS (Vunread_post_input_method_events)->cdr;
 
       /* Undo what read_char_x_menu_prompt did when it unread
         additional keys returned by Fx_popup_menu.  */
@@ -1706,10 +1843,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && NILP (XCONS (c)->cdr))
        c = XCONS (c)->car;
 
-      if (this_command_key_count == 0)
-       goto reread_first;
-      else
-       goto reread;
+      reread = 1;
+      goto reread_first;
     }
 
   if (unread_command_char != -1)
@@ -1717,10 +1852,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 = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+
+      /* 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;
+
+      reread = 1;
+      goto reread_for_input_method;
+    }
+
+  if (CONSP (Vunread_input_method_events))
+    {
+      c = XCONS (Vunread_input_method_events)->car;
+      Vunread_input_method_events = XCONS (Vunread_input_method_events)->cdr;
+
+      /* 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;
+      reread = 1;
+      goto reread_for_input_method;
     }
 
   /* If there is no function key translated before
@@ -1748,7 +1912,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
        {
          XSETINT (c, -1);
-         return c;
+         RETURN_UNGCPRO (c);
        }
 
       c = Faref (Vexecuting_macro, make_number (executing_macro_index));
@@ -1767,18 +1931,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 (commandflag >= 0 && !input_pending
-      && !detect_input_pending_run_timers (0))
-    redisplay ();
+  /* 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);             /* may clear input_pending */
+
+      /* 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.  */
@@ -1837,6 +2026,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            *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);
          }
       }
@@ -1849,15 +2041,23 @@ 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))
+      && (/* 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.  */
@@ -1867,9 +2067,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        {
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (echo_keystrokes, 0, 1, 1);
+         tem0 = sit_for (echo_keystrokes, 0, 1, 1, 0);
          restore_getcjmp (save_jump);
-         if (EQ (tem0, Qt))
+         if (EQ (tem0, Qt)
+             && ! CONSP (Vunread_command_events))
            echo_now ();
        }
     }
@@ -1878,7 +2079,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (commandflag != 0
       && auto_save_interval > 0
-      && num_nonmacro_input_chars - last_auto_save > max (auto_save_interval, 20)
+      && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20)
       && !detect_input_pending_run_timers (0))
     {
       Fdo_auto_save (Qnil, Qnil);
@@ -1895,10 +2096,18 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && !NILP (prev_event)
       && EVENT_HAS_PARAMETERS (prev_event)
       && !EQ (XCONS (prev_event)->car, Qmenu_bar)
+      && !EQ (XCONS (prev_event)->car, Qtoolbar)
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events)
       && unread_command_char < 0)
-    c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+    {
+      c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+
+      /* Now that we have read an event, Emacs is not idle.  */
+      timer_stop_idle ();
+
+      RETURN_UNGCPRO (c);
+    }
 
   /* Maybe autosave and/or garbage collect due to idleness.  */
 
@@ -1920,7 +2129,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       /* Auto save if enough time goes by without input.  */
       if (commandflag != 0
-         && num_nonmacro_input_chars > last_auto_save
+         && num_nonmacro_input_events > last_auto_save
          && INTEGERP (Vauto_save_timeout)
          && XINT (Vauto_save_timeout) > 0)
        {
@@ -1929,10 +2138,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
          tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
-                         0, 1, 1);
+                         0, 1, 1, 0);
          restore_getcjmp (save_jump);
 
-         if (EQ (tem0, Qt))
+         if (EQ (tem0, Qt)
+             && ! CONSP (Vunread_command_events))
            {
              Fdo_auto_save (Qnil, Qnil);
 
@@ -1948,6 +2158,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+  /* If this has become non-nil here, it has been set by a timer
+     or sentinel or filter.  */
+  if (CONSP (Vunread_command_events))
+    {
+      c = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+    }
+
   /* Read something from current KBOARD's side queue, if possible.  */
 
   if (NILP (c))
@@ -1985,6 +2203,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);
          }
     }
@@ -2022,6 +2243,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
@@ -2047,10 +2271,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
-  /* Now that we have read an event, Emacs is not idle--
-     unless the event was a timer event (not used now).  */
-  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
-    timer_stop_idle ();
+  timer_stop_idle ();
 
   start_polling ();
 
@@ -2066,12 +2287,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
  non_reread_1:
 
   /* Buffer switch events are only for internal wakeups
-     so don't show them to the user.  */
-  if (BUFFERP (c))
-    return c;
-
-  if (key_already_recorded)
-    return c;
+     so don't show them to the user.
+     Also, don't record a key if we already did.  */
+  if (BUFFERP (c) || key_already_recorded)
+    RETURN_UNGCPRO (c);
 
   /* Process special events within read_char
      and loop around to read another event.  */
@@ -2095,23 +2314,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto retry;
     }
 
-  /* Wipe the echo area.  */
-  echo_area_glyphs = 0;
-
   /* Handle things that only apply to characters.  */
   if (INTEGERP (c))
     {
       /* If kbd_buffer_get_event gave us an EOF, return that.  */
       if (XINT (c) == -1)
-       return 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)))
+       RETURN_UNGCPRO (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);
@@ -2134,7 +2349,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       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, Qtoolbar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
          POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
@@ -2145,37 +2360,164 @@ 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);
 
+  /* 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 = XCONS (tem)->car;
+      Vunread_post_input_method_events
+       = nconc2 (XCONS (tem)->cdr, Vunread_post_input_method_events);
+    }
+
  reread_first:
-  before_command_key_count = this_command_key_count;
-  before_command_echo_length = echo_length ();
 
-  /* Don't echo mouse motion events.  */
-  if (echo_keystrokes
-      && ! (EVENT_HAS_PARAMETERS (c)
-           && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+  /* Display help if not echoing.  */
+  if (CONSP (c)
+      && EQ (XCAR (c), Qhelp_echo))
     {
-      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 = echo_area_glyphs;
+      Lisp_Object msg = XCDR (XCDR (c));
+
+      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)
+    {
+      before_command_key_count = this_command_key_count;
+      before_command_echo_length = echo_length ();
 
-  /* Record this character as part of the current key.  */
-  add_command_key (c);
-  if (! NILP (also_record))
-    add_command_key (also_record);
+      /* Don't echo mouse motion events.  */
+      if (echo_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))
+       add_command_key (also_record);
+    }
 
-  /* Re-reading in the middle of a command */
- reread:
   last_input_char = c;
-  num_input_chars++;
+  num_input_events++;
 
   /* Process the help character specially if enabled */
   if (!NILP (Vhelp_form) && help_char_p (c))
@@ -2207,7 +2549,40 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
-  return c;
+  RETURN_UNGCPRO (c);
+}
+
+/* Record a key that came from a mouse menu.
+   Record it for echoing, for this-command-keys, and so on.  */
+
+static void
+record_menu_key (c)
+     Lisp_Object c;
+{
+  /* Wipe the echo area.  */
+  clear_message (1, 0);
+
+  record_char (c);
+
+  before_command_key_count = this_command_key_count;
+  before_command_echo_length = echo_length ();
+
+  /* Don't echo mouse motion events.  */
+  if (echo_keystrokes)
+    {
+      echo_char (c);
+
+      /* Once we reread a character, echoing can happen
+        the next time we pause to read a new one.  */
+      ok_to_echo_at_next_pause = 0;
+    }
+
+  /* Record this character as part of the current key.  */
+  add_command_key (c);
+
+  /* Re-reading in the middle of a command */
+  last_input_char = c;
+  num_input_events++;
 }
 
 /* Return 1 if should recognize C as "the help character".  */
@@ -2260,7 +2635,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);
            }
@@ -2271,7 +2646,7 @@ record_char (c)
 
   store_kbd_macro_char (c);
 
-  num_nonmacro_input_chars++;
+  num_nonmacro_input_events++;
 }
 
 Lisp_Object
@@ -2291,12 +2666,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;
 {
@@ -2516,7 +2893,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)
        {
@@ -2543,6 +2920,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,
@@ -2610,6 +3009,15 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif /* not VMS */
     }
 
+  if (CONSP (Vunread_command_events))
+    {
+      Lisp_Object first;
+      first = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+      *kbp = current_kboard;
+      return first;
+    }
+
   /* At this point, we know that there is a readable event available
      somewhere.  If the event queue is empty, then there must be a
      mouse movement enabled and available.  */
@@ -2700,7 +3108,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;
@@ -2709,15 +3117,34 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
-      /* Just discard these, by returning nil.
+#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
@@ -2752,8 +3179,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
+             if ((event->kind == menu_bar_event
+                  || event->kind == TOOLBAR_EVENT)
                  && !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar))
+                 && !(CONSP (obj) && EQ (XCONS (obj)->car, Qtoolbar))
                  && used_mouse_menu)
                *used_mouse_menu = 1;
 #endif
@@ -2877,29 +3306,6 @@ swallow_events (do_display)
          abort ();
 #endif
        }
-      /* Note that timer_event is currently never used.  */
-      else if (event->kind == timer_event)
-       {
-         Lisp_Object tem, lisp_event;
-         int was_locked = single_kboard;
-
-         tem = get_keymap_1 (Vspecial_event_map, 0, 0);
-         tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
-                           1);
-         lisp_event = Fcons (Qtimer_event,
-                             Fcons (Fcdr (event->frame_or_window), Qnil));
-         kbd_fetch_ptr = event + 1;
-         if (kbd_fetch_ptr == kbd_store_ptr)
-           input_pending = 0;
-         Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event), Qt);
-         timers_run++;
-         if (do_display)
-           redisplay_preserve_echo_area ();
-
-         /* Resume allowing input from any kboard, if that was true before.  */
-         if (!was_locked)
-           any_kboard_state ();
-       }
       else
        break;
     }
@@ -2916,6 +3322,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;
@@ -2941,6 +3348,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);
@@ -2970,8 +3378,6 @@ timer_check (do_it_now)
   EMACS_TIME nexttime;
   EMACS_TIME now, idleness_now;
   Lisp_Object timers, idle_timers, chosen_timer;
-  /* Nonzero if we generate some events.  */
-  int events_generated = 0;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   EMACS_SET_SECS (nexttime, -1);
@@ -3108,64 +3514,38 @@ timer_check (do_it_now)
        {
          if (NILP (vector[0]))
            {
+             Lisp_Object tem;
+             int was_locked = single_kboard;
+             int count = specpdl_ptr - specpdl;
+#ifdef HAVE_WINDOW_SYSTEM
+             int old_inhibit_busy_cursor = inhibit_busy_cursor;
+#endif
+
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
              vector[0] = Qt;
 
-             /* Run the timer or queue a timer event.  */
-             if (1)
-               {
-                 Lisp_Object tem, event;
-                 int was_locked = single_kboard;
-                 int count = specpdl_ptr - specpdl;
+             specbind (Qinhibit_quit, Qt);
 
-                 specbind (Qinhibit_quit, Qt);
+#ifdef HAVE_WINDOW_SYSTEM
+             inhibit_busy_cursor = 2;
+#endif
+             
+             call1 (Qtimer_event_handler, chosen_timer);
+             timers_run++;
 
-                 tem = get_keymap_1 (Vspecial_event_map, 0, 0);
-                 tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
-                                   1);
-                 event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
-                 Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
-                 timers_run++;
+#ifdef HAVE_WINDOW_SYSTEM
+             inhibit_busy_cursor = old_inhibit_busy_cursor;
+#endif
 
-                 unbind_to (count, Qnil);
+             unbind_to (count, Qnil);
 
-                 /* Resume allowing input from any kboard, if that was true before.  */
-                 if (!was_locked)
-                   any_kboard_state ();
+             /* Resume allowing input from any kboard, if that was true before.  */
+             if (!was_locked)
+               any_kboard_state ();
 
-                 /* Since we have handled the event,
-                    we don't need to tell the caller to wake up and do it.  */
-               }
-#if 0
-             else
-               {
-                 /* Generate a timer event so the caller will handle it.  */
-                 struct input_event event;
-
-                 event.kind = timer_event;
-                 event.modifiers = 0;
-                 event.x = event.y = Qnil;
-                 event.timestamp = triggertime;
-                 /* Store the timer in the frame slot.  */
-                 event.frame_or_window
-                   = Fcons (Fselected_frame (), chosen_timer);
-                 kbd_buffer_store_event (&event);
-
-                 last_timer_event = event;
-
-                 /* Tell caller to handle this event right away.  */
-                 events_generated = 1;
-                 EMACS_SET_SECS (nexttime, 0);
-                 EMACS_SET_USECS (nexttime, 0);
-
-                 /* Don't queue more than one event at once.
-                    When Emacs is ready for another, it will
-                    queue the next one.  */
-                 UNGCPRO;
-                 return nexttime;
-               }
-#endif /* 0 */
+             /* Since we have handled the event,
+                we don't need to tell the caller to wake up and do it.  */
            }
        }
       else
@@ -3173,10 +3553,6 @@ timer_check (do_it_now)
           return the amount of time to wait before it is ripe.  */
        {
          UNGCPRO;
-         /* But if we generated an event,
-            tell the caller to handle it now.  */
-         if (events_generated)
-           return nexttime;
          return difference;
        }
     }
@@ -3191,6 +3567,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.  */
@@ -3308,15 +3688,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        */
     
@@ -3419,7 +3799,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 */
@@ -3443,9 +3823,45 @@ char *lispy_function_keys[] =
     "noname",        /* VK_NONAME         0xFC */
     "pa1",           /* VK_PA1            0xFD */
     "oem_clear",     /* VK_OEM_CLEAR      0xFE */
+    0 /* 0xFF */
   };
 
-#else
+#else /* not HAVE_NTGUI */
+
+#ifdef XK_kana_A
+static char *lispy_kana_keys[] =
+  {
+    /* X Keysym value */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x400 .. 0x40f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x410 .. 0x41f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x420 .. 0x42f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x430 .. 0x43f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x440 .. 0x44f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x450 .. 0x45f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x460 .. 0x46f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,"overline",0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x480 .. 0x48f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x490 .. 0x49f */
+    0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket", 
+    "kana-comma", "kana-conjunctive", "kana-WO", "kana-a",
+    "kana-i", "kana-u", "kana-e", "kana-o",
+    "kana-ya", "kana-yu", "kana-yo", "kana-tsu",
+    "prolongedsound", "kana-A", "kana-I", "kana-U",
+    "kana-E", "kana-O", "kana-KA", "kana-KI",
+    "kana-KU", "kana-KE", "kana-KO", "kana-SA",
+    "kana-SHI", "kana-SU", "kana-SE", "kana-SO",
+    "kana-TA", "kana-CHI", "kana-TSU", "kana-TE",
+    "kana-TO", "kana-NA", "kana-NI", "kana-NU",
+    "kana-NE", "kana-NO", "kana-HA", "kana-HI",
+    "kana-FU", "kana-HE", "kana-HO", "kana-MA",
+    "kana-MI", "kana-MU", "kana-ME", "kana-MO",
+    "kana-YA", "kana-YU", "kana-YO", "kana-RA",
+    "kana-RI", "kana-RU", "kana-RE", "kana-RO",
+    "kana-WA", "kana-N", "voicedsound", "semivoicedsound",
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x4e0 .. 0x4ef */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x4f0 .. 0x4ff */
+  };
+#endif /* XK_kana_A */
 
 #define FUNCTION_KEY_OFFSET 0xff00
 
@@ -3455,34 +3871,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, 0, 0, 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",
@@ -3496,9 +3901,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 */
@@ -3543,23 +3948,76 @@ static char *lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,     /* 0xfff0 */
     0, 0, 0, 0, 0, 0, 0, "delete"
-    };
+  };
 
-#endif /* HAVE_NTGUI */
+/* ISO 9995 Function and Modifier Keys; the first byte is 0xFE.  */
+#define ISO_FUNCTION_KEY_OFFSET 0xfe00
+
+static char *iso_lispy_function_keys[] =
+  {
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe00 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe08 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe10 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe18 */
+    "iso-lefttab",             /* 0xfe20 */
+    "iso-move-line-up", "iso-move-line-down", 
+    "iso-partial-line-up", "iso-partial-line-down", 
+    "iso-partial-space-left", "iso-partial-space-right", 
+    "iso-set-margin-left", "iso-set-margin-right", /* 0xffe27, 28 */
+    "iso-release-margin-left", "iso-release-margin-right",
+    "iso-release-both-margins",
+    "iso-fast-cursor-left", "iso-fast-cursor-right",
+    "iso-fast-cursor-up", "iso-fast-cursor-down",
+    "iso-continuous-underline", "iso-discontinuous-underline", /* 0xfe30, 31 */
+    "iso-emphasize", "iso-center-object", "iso-enter", /* ... 0xfe34 */
+  };
+
+#endif /* not HAVE_NTGUI */
 
 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;
 
 /* 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
+};
+
+/* User signal events.  */
+Lisp_Object Qusr1_signal, Qusr2_signal;
+
+Lisp_Object *lispy_user_signals[] =
+{
+  &Qusr1_signal, &Qusr2_signal
 };
 
 
@@ -3625,6 +4083,10 @@ make_lispy_event (event)
        c |= (event->modifiers
              & (meta_modifier | alt_modifier
                 | hyper_modifier | super_modifier));
+       /* Distinguish Shift-SPC from SPC.  */
+       if ((event->code & 0377) == 040
+           && event->modifiers & shift_modifier)
+         c |= shift_modifier;
        button_down_time = 0;
        XSETFASTINT (lispy_c, c);
        return lispy_c;
@@ -3659,23 +4121,41 @@ make_lispy_event (event)
                                      (unsigned)-1);
        }
 
-      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
-                                 event->modifiers,
-                                 Qfunction_key, Qnil,
-                                 lispy_function_keys, &func_key_syms,
-                                 (sizeof (lispy_function_keys)
-                                  / sizeof (lispy_function_keys[0])));
-      break;
-
-      /* Note that timer_event is currently never used.  */
-    case timer_event:
-      return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+#ifdef XK_kana_A
+      if (event->code >= 0x400 && event->code < 0x500)
+       return modify_event_symbol (event->code - 0x400,
+                                   event->modifiers & ~shift_modifier,
+                                   Qfunction_key, Qnil,
+                                   lispy_kana_keys, &func_key_syms,
+                                   (sizeof (lispy_kana_keys)
+                                    / sizeof (lispy_kana_keys[0])));
+#endif /* XK_kana_A */
+
+#ifdef ISO_FUNCTION_KEY_OFFSET
+      if (event->code < FUNCTION_KEY_OFFSET
+         && event->code >= ISO_FUNCTION_KEY_OFFSET)
+       return modify_event_symbol (event->code - ISO_FUNCTION_KEY_OFFSET,
+                                   event->modifiers,
+                                   Qfunction_key, Qnil,
+                                   iso_lispy_function_keys, &func_key_syms,
+                                   (sizeof (iso_lispy_function_keys)
+                                    / sizeof (iso_lispy_function_keys[0])));
+      else
+#endif
+       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                   event->modifiers,
+                                   Qfunction_key, Qnil,
+                                   lispy_function_keys, &func_key_syms,
+                                   (sizeof (lispy_function_keys)
+                                    / sizeof (lispy_function_keys[0])));
 
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
     case mouse_click:
+#ifndef USE_TOOLKIT_SCROLL_BARS
     case scroll_bar_click:
+#endif
       {
        int button = event->code;
        int is_double;
@@ -3693,6 +4173,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
@@ -3700,8 +4181,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
@@ -3726,6 +4212,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)
@@ -3743,6 +4230,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,
@@ -3754,7 +4243,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))
              {
@@ -3763,21 +4255,36 @@ make_lispy_event (event)
              }
            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;
+               /* 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 : Qtop_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
@@ -3785,10 +4292,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;
@@ -3804,6 +4315,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];
 
@@ -3915,8 +4427,57 @@ 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 win32_scroll_bar_click:
+    case w32_scroll_bar_click:
       {
        int button = event->code;
        int is_double;
@@ -3936,15 +4497,15 @@ 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 Win32 scroll bar events as clicks. */
+       /* Always treat W32 scroll bar events as clicks. */
        event->modifiers |= click_modifier;
 
        {
@@ -3962,8 +4523,148 @@ 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 = Qtop_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 head, position;
+       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 (XCONS (event->frame_or_window)->car);
+       files = XCONS (event->frame_or_window)->cdr;
+
+       /* 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 = XCONS (event->frame_or_window)->car;
+           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 = Qtop_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)
@@ -3974,6 +4675,21 @@ make_lispy_event (event)
       return XCONS (event->frame_or_window)->cdr;
 #endif
 
+    case TOOLBAR_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 ();
@@ -4012,34 +4728,34 @@ 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 -= XINT (XWINDOW (window)->left);
-         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 hpos, vpos;
+         int wx, wy;
+         int pos;
+         
+         /* 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 = Qtop_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)
        {
@@ -4098,7 +4814,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;
@@ -4145,7 +4861,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.  */
@@ -4156,7 +4873,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;
@@ -4171,16 +4888,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;
 
   {
@@ -4211,9 +4928,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);
   }
@@ -4255,7 +4973,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;
 {
@@ -4272,7 +4990,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))
@@ -4326,7 +5044,8 @@ apply_modifiers (modifiers, base)
       /* 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);
@@ -4459,7 +5178,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
       /* No; let's create it.  */
       if (!NILP (name_alist))
        value = Fcdr_safe (Fassq (symbol_int, name_alist));
-      else if (name_table[symbol_num])
+      else if (name_table != 0 && name_table[symbol_num])
        value = intern (name_table[symbol_num]);
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -4574,11 +5293,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;
 
@@ -4692,7 +5411,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;
 {
@@ -4724,6 +5443,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;
@@ -4787,8 +5507,7 @@ read_avail_input (expected)
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE,
-                                expected, expected);
+    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -4842,6 +5561,13 @@ read_avail_input (expected)
 #else
          nread = 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
+            when the control tty is taken away.
+            Jeffrey Honig <jch@bsdi.com> says this is generally safe.  */
+         if (nread == -1 && errno == EIO)
+           kill (0, SIGHUP);
 #if defined (AIX) && (! defined (aix386) && defined (_BSD))
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
             This looks incorrect, but it isn't, because _BSD causes
@@ -5083,7 +5809,7 @@ menu_bar_items (old)
   for (mapno = nmaps - 1; mapno >= 0; mapno--)
     {
       if (! NILP (maps[mapno]))
-       def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0));
+       def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0), 0);
       else
        def = Qnil;
 
@@ -5147,29 +5873,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, table;
+
+  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)
     {
       item = XCONS (tail)->car;
       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 (XCONS (item)->car, XCONS (item)->cdr);
       else if (VECTORP (item))
        {
          /* Loop over the char values represented in the vector.  */
@@ -5177,119 +5896,862 @@ menu_bar_one_keymap (keymap)
          int c;
          for (c = 0; c < len; c++)
            {
-             Lisp_Object character;
-             XSETFASTINT (character, c);
-             binding = XVECTOR (item)->contents[c];
-             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);
+             Lisp_Object character;
+             XSETFASTINT (character, c);
+             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;
+         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++]
+       = 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 (XCONS (arg)->car, 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 = XCONS (item)->car;
+
+  start = item;
+  item = XCONS (item)->cdr;
+  if (STRINGP (item_string))
+    {
+      /* Old format menu item.  */
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+
+      /* Maybe help string.  */
+      if (CONSP (item) && STRINGP (XCONS (item)->car))
+       {
+         XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+           = XCONS (item)->car;
+         start = item;
+         item = XCONS (item)->cdr;
+       }
+         
+      /* Maybee key binding cache.  */
+      if (CONSP (item) && CONSP (XCONS (item)->car)
+         && (NILP (XCONS (XCONS (item)->car)->car)
+             || VECTORP (XCONS (XCONS (item)->car)->car)))
+       {
+         cachelist = XCONS (item)->car;
+         item = XCONS (item)->cdr;
+       }
+      
+      /* 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]
+       = XCONS (item)->car;
+      start = XCONS (item)->cdr;
+      if (CONSP (start))
+       {
+         /* We have a real binding.  */
+         XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]
+           = XCONS (start)->car;
+
+         item = XCONS (start)->cdr;
+         /* Is there a cache list with key equivalences. */
+         if (CONSP (item) && CONSP (XCONS (item)->car))
+           {
+             cachelist = XCONS (item)->car;
+             item = XCONS (item)->cdr;
+           }
+
+         /* Parse properties.  */
+         while (CONSP (item) && CONSP (XCONS (item)->cdr))
+           {
+             tem = XCONS (item)->car;
+             item = XCONS (item)->cdr;
+
+             if (EQ (tem, QCenable))
+               XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]
+                 = XCONS (item)->car;
+             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 (XCONS (item)->car);
+                 if (NILP (tem))
+                   return 0;
+               }
+             else if (EQ (tem, QChelp))
+               XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+                 = XCONS (item)->car;
+             else if (EQ (tem, QCfilter))
+               filter = item;
+             else if (EQ (tem, QCkey_sequence))
+               {
+                 tem = XCONS (item)->car;
+                 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 = XCONS (item)->car;
+                 if (CONSP (tem) || STRINGP (tem) && NILP (cachelist))
+                   XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
+                     = tem;
+               }
+             else if (EQ (tem, QCbutton) && CONSP (XCONS (item)->car))
+               {
+                 Lisp_Object type;
+                 tem = XCONS (item)->car;
+                 type = XCONS (tem)->car;
+                 if (EQ (type, QCtoggle) || EQ (type, QCradio))
+                   {
+                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+                       = XCONS (tem)->cdr;
+                     XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+                       = type;
+                   }
+               }
+             item = XCONS (item)->cdr;
+           }
+       }
+      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 (XCONS (filter)->car,
+                                           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);
+      XCONS (start)->cdr = Fcons (Fcons (Qnil, Qnil), XCONS (start)->cdr);
+      cachelist = XCONS (XCONS (start)->cdr)->car;
+      newcache = 1;
+      tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+      if (!NILP (keyhint))
+       {
+         XCONS (cachelist)->car = XCONS (keyhint)->car;
+         newcache = 0;
+       }
+      else if (STRINGP (tem))
+       {
+         XCONS (cachelist)->cdr = Fsubstitute_command_keys (tem);
+         XCONS (cachelist)->car = Qt;
+       }
+    }
+  tem = XCONS (cachelist)->car;
+  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 = XCONS (prefix)->car;
+         prefix = XCONS (prefix)->cdr;
+       }
+      else
+       def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+
+      if (NILP (XCONS (cachelist)->car)) /* 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);
+         XCONS (cachelist)->car = tem;
+         if (NILP (tem))
+           {
+             XCONS (cachelist)->cdr = Qnil;
+             chkcache = 0;
+           }
+       }
+      else if (!NILP (keyhint) && !NILP (XCONS (cachelist)->car))
+       {
+         tem = XCONS (cachelist)->car;
+         chkcache = 1;
+       }
+
+      newcache = chkcache;
+      if (chkcache)
+       {
+         tem = Fkey_description (tem);
+         if (CONSP (prefix))
+           {
+             if (STRINGP (XCONS (prefix)->car))
+               tem = concat2 (XCONS (prefix)->car, tem);
+             if (STRINGP (XCONS (prefix)->cdr))
+               tem = concat2 (tem, XCONS (prefix)->cdr);
+           }
+         XCONS (cachelist)->cdr = tem;
+       }
+    }
+
+  tem = XCONS (cachelist)->cdr;
+  if (newcache && !NILP (tem))
+    {
+      tem = concat3 (build_string ("  ("), tem, build_string (")"));
+      XCONS (cachelist)->cdr = 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 toolbar items while they are parsed in function
+   toolbar_items runs Each item occupies TOOLBAR_ITEM_NSCLOTS
+   elements in the vector.  */
+
+static Lisp_Object toolbar_items_vector;
+
+/* A vector holding the result of parse_toolbar_item.  Layout is like
+   the one for a single item in toolbar_items_vector.  */
+
+static Lisp_Object toolbar_item_properties;
+
+/* Next free index in toolbar_items_vector.  */
+
+static int ntoolbar_items;
+
+/* The symbols `toolbar', `toolbar-item', and `:image'.  */
+
+extern Lisp_Object Qtoolbar;
+Lisp_Object QCimage;
+
+/* Function prototypes.  */
+
+static void init_toolbar_items P_ ((Lisp_Object));
+static void process_toolbar_item P_ ((Lisp_Object, Lisp_Object));
+static int parse_toolbar_item P_ ((Lisp_Object, Lisp_Object));
+static void append_toolbar_item P_ ((void));
+
+
+/* Return a vector of toolbar items for keymaps currently in effect.
+   Reuse vector REUSE if non-nil.  Return in *NITEMS the number of
+   toolbar items found.  */
+
+Lisp_Object
+toolbar_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 toolbar_items_vector and protect it from GC.  */
+  init_toolbar_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]));
+#ifdef USE_TEXT_PROPERTIES
+      maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+      maps[nmaps++] = current_buffer->keymap;
+#endif
+    }
+
+  /* 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 `toolbar'.  */
+  for (i = nmaps - 1; i >= 0; --i)
+    if (!NILP (maps[i]))
+      {
+       Lisp_Object keymap;
+      
+       keymap = get_keyelt (access_keymap (maps[i], Qtoolbar, 1, 1), 0);
+       if (!NILP (Fkeymapp (keymap)))
+         {
+           Lisp_Object tail;
+           
+           /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
+           for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+             {
+               Lisp_Object keydef = XCAR (tail);
+               if (CONSP (keydef))
+                 process_toolbar_item (XCAR (keydef), XCDR (keydef));
+             }
+         }
+      }
+
+  Vinhibit_quit = oquit;
+  *nitems = ntoolbar_items / TOOLBAR_ITEM_NSLOTS;
+  return toolbar_items_vector;
+}
+
+
+/* Process the definition of KEY which is DEF.  */
+
+static void
+process_toolbar_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_toolbar_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 < ntoolbar_items; i += TOOLBAR_ITEM_NSLOTS)
+       {
+         Lisp_Object *v = XVECTOR (toolbar_items_vector)->contents + i;
+         
+         if (EQ (key, v[TOOLBAR_ITEM_KEY]))
+           {
+             if (ntoolbar_items > i + TOOLBAR_ITEM_NSLOTS)
+               bcopy (v + TOOLBAR_ITEM_NSLOTS, v,
+                      ((ntoolbar_items - i - TOOLBAR_ITEM_NSLOTS)
+                       * sizeof (Lisp_Object)));
+             ntoolbar_items -= TOOLBAR_ITEM_NSLOTS;
+             break;
+           }
+       }
+    }
+  else if (parse_toolbar_item (key, def))
+    /* Append a new toolbar item to toolbar_items_vector.  Accept
+       more than one definition for the same key.  */
+    append_toolbar_item ();
+
+  UNGCPRO;
+}
+
+
+/* Parse a toolbar item specification ITEM for key KEY and return the
+   result in toolbar_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 toolbar item's binding.  Toolbar items with keymaps
+   as binding are currently ignored.
+
+   The following properties are recognized:
+
+   - `:enable FORM'.
+   
+   FORM is evaluated and specifies whether the toolbar item is enabled
+   or disabled.
+   
+   - `:visible FORM'
+   
+   FORM is evaluated and specifies whether the toolbar 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 toolbar_item_images.
+   
+   - `:help HELP-STRING'.
+   
+   Gives a help string to display for the toolbar item.  */
+
+static int
+parse_toolbar_item (key, item)
+     Lisp_Object key, item;
+{
+  /* Access slot with index IDX of vector toolbar_item_properties.  */
+#define PROP(IDX) XVECTOR (toolbar_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;
+  struct gcpro gcpro1;
+
+  /* Defininition looks like `(toolbar-item CAPTION BINDING
+     PROPS...)'.  Rule out items that aren't lists, don't start with
+     `toolbar-item' or whose rest following `toolbar-item' is not a
+     list.  */
+  if (!CONSP (item)
+      || !EQ (XCAR (item), Qmenu_item)
+      || (item = XCDR (item),
+         !CONSP (item)))
+    return 0;
+
+  /* Create toolbar_item_properties vector if necessary.  Reset it to
+     defaults.  */
+  if (VECTORP (toolbar_item_properties))
+    {
+      for (i = 0; i < TOOLBAR_ITEM_NSLOTS; ++i)
+       PROP (i) = Qnil;
+    }
+  else
+    toolbar_item_properties
+      = Fmake_vector (make_number (TOOLBAR_ITEM_NSLOTS), Qnil);
+  
+  /* Set defaults.  */
+  PROP (TOOLBAR_ITEM_KEY) = key;
+  PROP (TOOLBAR_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 (TOOLBAR_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 (TOOLBAR_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 (TOOLBAR_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 (TOOLBAR_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 (TOOLBAR_ITEM_SELECTED_P) = selected;
+             PROP (TOOLBAR_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 (TOOLBAR_ITEM_IMAGES) = value;
     }
-}
 
-/* This is used as the handler when calling internal_condition_case_1.  */
+  /* If got a filter apply it on binding.  */
+  if (!NILP (filter))
+    PROP (TOOLBAR_ITEM_BINDING)
+      = menu_item_eval_property (list2 (filter,
+                                       list2 (Qquote,
+                                              PROP (TOOLBAR_ITEM_BINDING))));
 
-static Lisp_Object
-menu_bar_item_1 (arg)
-     Lisp_Object arg;
-{
-  return Qnil;
+  /* See if the binding is a keymap.  Give up if it is.  */
+  if (!NILP (get_keymap_1 (PROP (TOOLBAR_ITEM_BINDING), 0, 1)))
+    return 0;
+
+  /* Enable or disable selection of item.  */
+  if (!EQ (PROP (TOOLBAR_ITEM_ENABLED_P), Qt))
+    PROP (TOOLBAR_ITEM_ENABLED_P)
+      = menu_item_eval_property (PROP (TOOLBAR_ITEM_ENABLED_P));
+
+  /* Handle radio buttons or toggle boxes.  */ 
+  if (!NILP (PROP (TOOLBAR_ITEM_SELECTED_P)))
+    PROP (TOOLBAR_ITEM_SELECTED_P)
+      = menu_item_eval_property (PROP (TOOLBAR_ITEM_SELECTED_P));
+
+  return 1;
+  
+#undef PROP
 }
 
-/* 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.  */
+
+/* Initialize Vtoolbar_items.  REUSE, if non-nil, is a vector that can
+   be reused.  */
 
 static void
-menu_bar_item (key, item_string, def)
-     Lisp_Object key, item_string, def;
+init_toolbar_items (reuse)
+     Lisp_Object reuse;
 {
-  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 (VECTORP (reuse))
+    toolbar_items_vector = reuse;
+  else
+    toolbar_items_vector = Fmake_vector (make_number (64), Qnil);
+  ntoolbar_items = 0;
+}
 
-  if (EQ (def, 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;
-         }
+/* Append parsed toolbar item properties from toolbar_item_properties */
 
-      /* If there's no definition for this key yet,
-        just ignore `undefined'.  */
-      return;
+static void
+append_toolbar_item ()
+{
+  Lisp_Object *to, *from;
+  
+  /* Enlarge toolbar_items_vector if necessary.  */
+  if (ntoolbar_items + TOOLBAR_ITEM_NSLOTS
+      >= XVECTOR (toolbar_items_vector)->size)
+    {
+      Lisp_Object new_vector;
+      int old_size = XVECTOR (toolbar_items_vector)->size;
+
+      new_vector = Fmake_vector (make_number (2 * old_size), Qnil);
+      bcopy (XVECTOR (toolbar_items_vector)->contents,
+            XVECTOR (new_vector)->contents,
+            old_size * sizeof (Lisp_Object));
+      toolbar_items_vector = new_vector;
     }
 
-  /* See if this entry is enabled.  */
-  enabled = Qt;
+  /* Append entries from toolbar_item_properties to the end of
+     toolbar_items_vector.  */
+  to = XVECTOR (toolbar_items_vector)->contents + ntoolbar_items;
+  from = XVECTOR (toolbar_item_properties)->contents;
+  bcopy (from, to, TOOLBAR_ITEM_NSLOTS * sizeof *to);
+  ntoolbar_items += TOOLBAR_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.
@@ -5353,7 +6815,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 (XCONS (prev_event)->car, Qmenu_bar)
+      && !EQ (XCONS (prev_event)->car, Qtoolbar))
     {
       /* Display the menu and get the selection.  */
       Lisp_Object *realmaps
@@ -5371,6 +6834,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
        {
          Lisp_Object tem;
 
+         record_menu_key (XCONS (value)->car);
+
          /* If we got multiple events, unread all but
             the first.
             There is no way to prevent those unread events
@@ -5381,10 +6846,13 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
             they won't confuse things.  */
          for (tem = XCONS (value)->cdr; !NILP (tem);
               tem = XCONS (tem)->cdr)
-           if (SYMBOLP (XCONS (tem)->car)
-               || INTEGERP (XCONS (tem)->car))
-             XCONS (tem)->car
-               = Fcons (XCONS (tem)->car, Qnil);
+           {
+             record_menu_key (XCONS (tem)->car);
+             if (SYMBOLP (XCONS (tem)->car)
+                 || INTEGERP (XCONS (tem)->car))
+               XCONS (tem)->car
+                 = Fcons (XCONS (tem)->car, Qnil);
+           }
 
          /* If we got more than one event, put all but the first
             onto this list to be read later.
@@ -5455,7 +6923,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;
@@ -5476,7 +6944,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))
@@ -5509,26 +6977,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);
@@ -5537,6 +7006,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
@@ -5598,7 +7088,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
@@ -5665,7 +7156,7 @@ follow_key (key, nmaps, current, defs, next)
          {
            Lisp_Object def;
            def = get_keyelt (access_keymap (current[i],
-                                            meta_prefix_char, 1, 0));
+                                            meta_prefix_char, 1, 0), 0);
 
            /* Note that since we pass the resulting bindings through
               get_keymap_1, non-prefix bindings for meta-prefix-char
@@ -5690,7 +7181,7 @@ follow_key (key, nmaps, current, defs, next)
          else
            map = current[i];
 
-         defs[i] = get_keyelt (access_keymap (map, key, 1, 0));
+         defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 0);
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -5738,16 +7229,20 @@ follow_key (key, nmaps, current, defs, next)
 
    If the user switches frames in the midst of a key sequence, we put
    off the switch-frame event until later; the next call to
-   read_char will return it.  */
+   read_char will return it.
+
+   If FIX_CURRENT_BUFFER is nonzero, we restore current_buffer
+   from the selected window's buffer.  */
 
 static int
 read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
-                  can_return_switch_frame)
+                  can_return_switch_frame, fix_current_buffer)
      Lisp_Object *keybuf;
      int bufsize;
      Lisp_Object prompt;
      int dont_downcase_last;
      int can_return_switch_frame;
+     int fix_current_buffer;
 {
   int count = specpdl_ptr - specpdl;
 
@@ -5839,15 +7334,17 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Save the status of key translation before each step,
      so that we can restore this after downcasing.  */
   Lisp_Object prev_fkey_map;
-  Lisp_Object prev_fkey_start;
-  Lisp_Object prev_fkey_end;
+  int prev_fkey_start;
+  int prev_fkey_end;
 
   Lisp_Object prev_keytran_map;
-  Lisp_Object prev_keytran_start;
-  Lisp_Object prev_keytran_end;
+  int prev_keytran_start;
+  int prev_keytran_end;
 
   int junk;
 
+  raw_keybuf_count = 0;
+
   last_nonmenu_event = Qnil;
 
   delayed_switch_frame = Qnil;
@@ -6068,7 +7565,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
@@ -6087,6 +7587,18 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (BUFFERP (key))
            {
              mock_input = t;
+             /* Reset the current buffer from the selected window
+                in case something changed the former and not the latter.
+                This is to be more consistent with the behavior
+                of the command_loop_1.  */
+             if (fix_current_buffer)
+               {
+                 if (! FRAME_LIVE_P (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;
            }
@@ -6096,6 +7608,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;
@@ -6104,6 +7618,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
@@ -6131,6 +7661,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
@@ -6149,6 +7680,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;
 
@@ -6164,19 +7696,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                     emacsclient).  */
                  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
 
+                 if (! FRAME_LIVE_P (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 (XCONS (key)->cdr)
                  && ! localized_local_map)
                {
                  Lisp_Object map_here, start, pos;
 
                  localized_local_map = 1;
                  start = EVENT_START (key);
+                 
                  if (CONSP (start) && CONSP (XCONS (start)->cdr))
                    {
                      pos = POSN_BUFFER_POSN (start);
@@ -6205,22 +7742,33 @@ 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);
-                 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;
+
+                 /* 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;
                }
            }
@@ -6233,7 +7781,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              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, Qtoolbar))
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
@@ -6430,7 +7978,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  fkey_next
                    = get_keymap_1
                      (get_keyelt
-                      (access_keymap (fkey_map, meta_prefix_char, 1, 0)),
+                      (access_keymap (fkey_map, meta_prefix_char, 1, 0), 0),
                       0, 1);
                  XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
                }
@@ -6438,7 +7986,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));
+               = 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 (XCONS (XSYMBOL (fkey_next)->function)->car, 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.  */
@@ -6501,8 +8063,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;
@@ -6538,7 +8102,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                keytran_next
                  = get_keymap_1
                    (get_keyelt
-                    (access_keymap (keytran_map, meta_prefix_char, 1, 0)),
+                    (access_keymap (keytran_map, meta_prefix_char, 1, 0), 0),
                     0, 1);
                XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
              }
@@ -6546,10 +8110,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));
+             = 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 (XCONS (XSYMBOL (keytran_next)->function)->car, 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)
@@ -6604,7 +8182,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;
              }
@@ -6630,7 +8208,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)))
        {
@@ -6731,6 +8309,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       add_command_key (keybuf[t]);
     }
 
+  
+
   return t;
 }
 
@@ -6777,24 +8357,81 @@ 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, command_loop;
+{
+  Lisp_Object keybuf[30];
+  register int i;
+  struct gcpro gcpro1, gcpro2;
+  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;
+    }
+
+  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+                        prompt, ! NILP (dont_downcase_last),
+                        ! NILP (can_return_switch_frame), 0);
+
+  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;
+     Lisp_Object can_return_switch_frame, command_loop;
 {
   Lisp_Object keybuf[30];
   register int i;
   struct gcpro gcpro1, gcpro2;
+  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]));
@@ -6807,7 +8444,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
-                        ! NILP (can_return_switch_frame));
+                        ! NILP (can_return_switch_frame), 0);
 
   if (i == -1)
     {
@@ -6815,7 +8452,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
       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,
@@ -6881,13 +8518,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))
+               XCONS (tem)->cdr = Qnil;
+           }
+       }
 
       return Fexecute_kbd_macro (final, prefixarg);
     }
+
   if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
     {
       backtrace.next = backtrace_list;
@@ -6956,7 +8604,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);
+                              Qt, Qnil, Qextended_command_history, Qnil,
+                              Qnil);
 
   if (STRINGP (function) && XSTRING (function)->size == 0)
     error ("No command name given");
@@ -6967,7 +8616,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;
@@ -6978,20 +8626,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)
@@ -7007,32 +8652,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 ();
        }
     }
 
@@ -7082,6 +8743,7 @@ current_active_maps (maps_p)
 \f
 /* Return nonzero if input events are pending.  */
 
+int
 detect_input_pending ()
 {
   if (!input_pending)
@@ -7092,6 +8754,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;
 {
@@ -7101,7 +8764,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;
 }
@@ -7109,6 +8781,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;
@@ -7120,6 +8794,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);
@@ -7169,18 +8844,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,
@@ -7201,6 +8896,16 @@ 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.")
+  ()
+{
+  this_command_key_count = 0;
+  return Qnil;
 }
 
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
@@ -7247,10 +8952,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;
 
@@ -7277,7 +8979,6 @@ On such systems, Emacs starts a subshell instead of suspending.")
   int old_height, old_width;
   int width, height;
   struct gcpro gcpro1, gcpro2;
-  extern init_sys_modes ();
 
   if (!NILP (stuffstring))
     CHECK_STRING (stuffstring, 0);
@@ -7291,7 +8992,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 ();
@@ -7304,7 +9006,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))
@@ -7317,11 +9019,12 @@ 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;
 {
 /* stuff_char works only in BSD, versions 4.2 and up.  */
-#ifdef BSD
+#ifdef BSD_SYSTEM
 #ifndef BSD4_1
   register unsigned char *p;
 
@@ -7330,7 +9033,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');
@@ -7351,9 +9054,10 @@ stuff_buffered_input (stuffstring)
     }
   input_pending = 0;
 #endif
-#endif /* BSD and not BSD4_1 */
+#endif /* BSD_SYSTEM and not BSD4_1 */
 }
 \f
+void
 set_waiting_for_input (time_to_clear)
      EMACS_TIME *time_to_clear;
 {
@@ -7368,6 +9072,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,  */
@@ -7407,11 +9112,17 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
 
   cancel_echoing ();
 
-  if (!NILP (Vquit_flag) && FRAME_TERMCAP_P (selected_frame))
+  if (!NILP (Vquit_flag)
+      && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
     {
+      /* If SIGINT isn't blocked, don't let us be interrupted by
+        another SIGINT, it might be harmful due to non-reentrancy
+        in I/O functions.  */
+      sigblock (sigmask (SIGINT));
+
       fflush (stdout);
       reset_sys_modes ();
-      sigfree ();
+
 #ifdef SIGTSTP                 /* Support possible in later USG versions */
 /*
  * On systems which can suspend the current process and return to the original
@@ -7490,6 +9201,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
 #endif /* not MSDOS */
       fflush (stdout);
       init_sys_modes ();
+      sigfree ();
     }
   else
     {
@@ -7498,9 +9210,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 */
@@ -7515,9 +9235,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 ();
@@ -7565,7 +9285,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
@@ -7604,7 +9324,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
 
@@ -7651,7 +9371,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;
@@ -7695,6 +9417,7 @@ delete_kboard (kb)
 }
 #endif
 
+void
 init_keyboard ()
 {
   /* This is correct before outermost invocation of the editor loop */
@@ -7789,8 +9512,30 @@ struct event_head head_table[] = {
   &Qmake_frame_visible,        "make-frame-visible",   &Qmake_frame_visible,
 };
 
+void
 syms_of_keyboard ()
 {
+  /* Toolbars.  */
+  QCimage = intern (":image");
+  staticpro (&QCimage);
+
+  staticpro (&Qhelp_echo);
+  Qhelp_echo = intern ("help-echo");
+
+  staticpro (&item_properties);
+  item_properties = Qnil;
+
+  staticpro (&toolbar_item_properties);
+  toolbar_item_properties = Qnil;
+  staticpro (&toolbar_items_vector);
+  toolbar_items_vector = Qnil;
+
+  staticpro (&real_this_command);
+  real_this_command = Qnil;
+
+  Qtimer_event_handler = intern ("timer-event-handler");
+  staticpro (&Qtimer_event_handler);
+
   Qdisabled_command_hook = intern ("disabled-command-hook");
   staticpro (&Qdisabled_command_hook);
 
@@ -7828,11 +9573,42 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-  Qtimer_event = intern ("timer-event");
-  staticpro (&Qtimer_event);
+#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);
@@ -7853,6 +9629,12 @@ 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);
 
   Qevent_kind = intern ("event-kind");
   staticpro (&Qevent_kind);
@@ -7871,6 +9653,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;
 
@@ -7905,6 +9698,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);
@@ -7922,11 +9718,29 @@ 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);
 
+  internal_last_event_frame = Qnil;
+  staticpro (&internal_last_event_frame);
+
+  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);
@@ -7935,8 +9749,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);
@@ -7967,20 +9784,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\
@@ -7990,11 +9822,14 @@ 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\
@@ -8031,14 +9866,25 @@ by position only.");
   inhibit_local_menu_bar_menus = 0;
 
   DEFVAR_INT ("num-input-keys", &num_input_keys,
-    "Number of complete keys read from the keyboard so far.");
+    "Number of complete key sequences read as input so far.\n\
+This includes key sequences read from keyboard macros.\n\
+The number is effectively the number of interactive command invocations.");
   num_input_keys = 0;
 
+  DEFVAR_INT ("num-nonmacro-input-events", &num_nonmacro_input_events,
+    "Number of input events read from the keyboard so far.\n\
+This does not include events generated by keyboard macros.");
+  num_nonmacro_input_events = 0;
+
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
     "The frame in which the most recently read event occurred.\n\
 If the last event came from a keyboard macro, this is set to `macro'.");
   Vlast_event_frame = Qnil;
 
+  /* This variable is set up in sysdep.c.  */
+  DEFVAR_LISP ("tty-erase-char", &Vtty_erase_char,
+    "The ERASE character as set by the user with stty.");
+
   DEFVAR_LISP ("help-char", &Vhelp_char,
     "Character to recognize as meaning Help.\n\
 When it is read, do `(eval help-form)', and display result if it's a string.\n\
@@ -8077,8 +9923,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,
@@ -8122,12 +9968,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,
@@ -8141,6 +9991,13 @@ This feature is obsolete; use idle timers instead.  See `etc/NEWS'.");
 This is measured in microseconds.");
   post_command_idle_delay = 100000;
 
+#if 0
+  DEFVAR_LISP ("echo-area-clear-hook", ...,
+    "Normal hook run when clearing the echo area.");
+#endif
+  Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+  XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
     "t means menu bar, specified Lucid style, needs to be recomputed.");
   Vlucid_menu_bar_dirty_flag = Qnil;
@@ -8152,9 +10009,11 @@ The elements of the list are event types that may have menu bar bindings.");
 
   DEFVAR_KBOARD ("overriding-terminal-local-map",
                 Voverriding_terminal_local_map,
-    "Keymap that overrides all other local keymaps.\n\
+    "Per-terminal keymap that overrides all other local keymaps.\n\
 If this variable is non-nil, it is used as a keymap instead of the\n\
-buffer's local map, and the minor mode keymaps and text property keymaps.");
+buffer's local map, and the minor mode keymaps and text property keymaps.\n\
+This variable is intended to let commands such as `universal-argumemnt'\n\
+set up a different keymap for reading the next command.");
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
     "Keymap that overrides all other local keymaps.\n\
@@ -8193,7 +10052,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;
@@ -8205,8 +10064,42 @@ 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;
 }
 
+void
 keys_of_keyboard ()
 {
   initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");