]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(Fnext_property_change): Properly offset interval
[gnu-emacs] / src / keyboard.c
index aa9138a4bad3fd63e6f58b50ef9cf0a86b11d2bd..a3dd95e0f7d72e22122478933aa053b35226339e 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>
 
@@ -143,6 +146,8 @@ static int before_command_restore_flag;
 
 extern int minbuf_level;
 
+extern int message_enable_multibyte;
+
 extern struct backtrace *backtrace_list;
 
 /* Nonzero means do menu prompting.  */
@@ -170,6 +175,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;
 
@@ -268,17 +276,17 @@ 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;
 
@@ -293,14 +301,12 @@ int last_point_position;
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
-#ifdef MULTI_FRAME
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
    like Fselect_frame, to make sure that a switch-frame event is
    generated by the next character.  */
 Lisp_Object internal_last_event_frame;
-#endif
 
 /* A user-visible version of the above, intended to allow users to
    figure out where the last event came from, if the event doesn't
@@ -315,6 +321,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.  */
@@ -341,6 +348,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;
@@ -439,14 +448,23 @@ Lisp_Object Qmake_frame_visible;
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-Lisp_Object Qtimer_event;
+#ifdef WINDOWSNT
+Lisp_Object Qmouse_wheel;
+#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);
@@ -467,15 +485,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.  */
@@ -521,9 +541,6 @@ int flow_control;
 #ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
-
-/* Non-nil enables Column Number mode.  */
-Lisp_Object Vcolumn_number_mode;
 \f
 /* Global variable declarations.  */
 
@@ -542,6 +559,8 @@ 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 ();
 
 /* > 0 if we are to echo keystrokes.  */
 static int echo_keystrokes;
@@ -557,6 +576,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;
 {
@@ -577,6 +597,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;
 {
@@ -602,10 +623,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
@@ -625,6 +647,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
@@ -649,6 +672,7 @@ echo_dash ()
 /* Display the current echo string, and begin echoing if not already
    doing so.  */
 
+void
 echo_now ()
 {
   if (!current_kboard->immediate_echo)
@@ -668,7 +692,9 @@ echo_now ()
     }
 
   echoing = 1;
-  message1_nolog (current_kboard->echobuf);
+  message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
+                 ! NILP (current_buffer->enable_multibyte_characters));
+
   echoing = 0;
 
   if (waiting_for_input && !NILP (Vquit_flag))
@@ -677,6 +703,7 @@ echo_now ()
 
 /* Turn off echoing, for the start of a new command.  */
 
+void
 cancel_echoing ()
 {
   current_kboard->immediate_echo = 0;
@@ -755,19 +782,25 @@ recursive_edit_1 ()
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
+  /* Handle throw from read_minibuf when using minibuffer
+     while it's active but we're in another window.  */
+  if (STRINGP (val))
+    Fsignal (Qerror, Fcons (val, Qnil));
 
   return unbind_to (count, Qnil);
 }
 
 /* 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;
@@ -888,10 +921,23 @@ cmd_error (data)
      Lisp_Object data;
 {
   Lisp_Object old_level, old_length;
+  char macroerror[50];
+
+  if (!NILP (executing_macro))
+    {
+      if (executing_macro_iterations == 1)
+       sprintf (macroerror, "After 1 kbd macro iteration: ");
+      else
+       sprintf (macroerror, "After %d kbd macro iterations: ",
+                executing_macro_iterations);
+    }
+  else
+    *macroerror = 0;
 
   Vstandard_output = Qt;
   Vstandard_input = Qt;
   Vexecuting_macro = Qnil;
+  executing_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
   cancel_echoing ();
 
@@ -900,7 +946,7 @@ cmd_error (data)
   old_length = Vprint_length;
   XSETFASTINT (Vprint_level, 10);
   XSETFASTINT (Vprint_length, 10);
-  cmd_error_internal (data, NULL);
+  cmd_error_internal (data, macroerror);
   Vprint_level = old_level;
   Vprint_length = old_length;
 
@@ -914,6 +960,15 @@ 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;
@@ -1054,7 +1109,7 @@ Lisp_Object
 command_loop_1 ()
 {
   Lisp_Object cmd, tem;
-  int lose;
+  int lose, lose2;
   int nonundocount;
   Lisp_Object keybuf[30];
   int i;
@@ -1090,7 +1145,7 @@ command_loop_1 ()
     {
       if (NILP (Vunread_command_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);
     }
 
@@ -1126,7 +1181,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);
 
@@ -1144,7 +1200,6 @@ command_loop_1 ()
 #endif /* C_ALLOCA */
 
 #if 0
-#ifdef MULTI_FRAME
       /* Select the frame that the last event came from.  Usually,
         switch-frame events will take care of this, but if some lisp
         code swallows a switch-frame event, we'll fix things up here.
@@ -1152,7 +1207,6 @@ command_loop_1 ()
       if (FRAMEP (internal_last_event_frame)
          && XFRAME (internal_last_event_frame) != selected_frame)
        Fselect_frame (internal_last_event_frame, Qnil);
-#endif
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
@@ -1167,7 +1221,11 @@ command_loop_1 ()
 
       /* 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 (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+       set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
 
       ++num_input_keys;
 
@@ -1248,7 +1306,7 @@ command_loop_1 ()
                {
                   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))
@@ -1256,14 +1314,19 @@ 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)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT - 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
@@ -1273,7 +1336,7 @@ command_loop_1 ()
                   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
@@ -1282,12 +1345,14 @@ command_loop_1 ()
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
+                     && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT + 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (-1);
                  goto directly_done;
@@ -1296,7 +1361,7 @@ command_loop_1 ()
                       /* 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)
@@ -1311,13 +1376,15 @@ command_loop_1 ()
                    }
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
+                         || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                             < OVERLAY_MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_point)
                              != PT)
                          || MODIFF <= SAVE_MODIFF
                          || windows_or_buffers_changed
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
-                         || !NILP (Vcolumn_number_mode)
+                         || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_macro));
                  value = internal_self_insert (c, 0);
                  if (value)
@@ -1326,12 +1393,18 @@ command_loop_1 ()
                    nonundocount = 0;
 
                  if (!lose
-                     && (PT == ZV || FETCH_CHAR (PT) == '\n'))
+                     && (PT == ZV || FETCH_BYTE (PT_BYTE) == '\n'))
                    {
                      struct Lisp_Char_Table *dp
                        = window_display_table (XWINDOW (selected_window));
                      int lose = c;
 
+                     /* Add the offset to the character, for Finsert_char.
+                        We pass internal_self_insert the unmodified character
+                        because it itself does this offsetting.  */
+                     if (! NILP (current_buffer->enable_multibyte_characters))
+                       lose = unibyte_char_to_multibyte (lose);
+
                      if (dp)
                        {
                          Lisp_Object obj;
@@ -1385,7 +1458,7 @@ command_loop_1 ()
        {
          if (NILP (Vunread_command_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);
        }
 
@@ -1504,6 +1577,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
@@ -1534,6 +1608,7 @@ input_polling_used ()
 
 /* Turn off polling.  */
 
+void
 stop_polling ()
 {
 #ifdef POLL_FOR_INPUT
@@ -1573,6 +1648,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,17 +1740,22 @@ 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 also_record;
+  struct gcpro gcpro1;
+
   also_record = Qnil;
 
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
+  c = Qnil;
+
+  GCPRO1 (c);
 
  retry:
 
@@ -1713,7 +1794,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (!NILP (Vexecuting_macro))
     {
-#ifdef MULTI_FRAME
       /* We set this to Qmacro; since that's not a frame, nobody will
         try to switch frames on us, and the selected window will
         remain unchanged.
@@ -1725,7 +1805,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         events read from a macro should never cause a new frame to be
         selected. */
       Vlast_event_frame = internal_last_event_frame = Qmacro;
-#endif
 
       /* Exit the macro if we are at the end.
         Also, some things replace the macro with t
@@ -1734,7 +1813,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));
@@ -1757,9 +1836,30 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       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
@@ -1800,10 +1900,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (_setjmp (local_getcjmp))
     {
       XSETINT (c, quit_char);
-#ifdef MULTI_FRAME
       XSETFRAME (internal_last_event_frame, selected_frame);
       Vlast_event_frame = internal_last_event_frame;
-#endif
       /* If we report the quit char as an event,
         don't do so more than once.  */
       if (!NILP (Vinhibit_quit))
@@ -1825,6 +1923,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);
          }
       }
@@ -1855,9 +1956,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 ();
        }
     }
@@ -1866,7 +1968,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);
@@ -1886,7 +1988,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* 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.  */
 
@@ -1908,7 +2017,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)
        {
@@ -1917,10 +2026,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);
 
@@ -1936,6 +2046,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))
@@ -1950,12 +2068,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          if (NILP (current_kboard->kbd_queue))
            current_kboard->kbd_queue_has_data = 0;
          input_pending = readable_events (0);
-#ifdef MULTI_FRAME
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
            internal_last_event_frame = XCONS (XCONS (c)->cdr)->car;
          Vlast_event_frame = internal_last_event_frame;
-#endif
        }
     }
 
@@ -1975,6 +2091,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);
          }
     }
@@ -2012,6 +2131,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
@@ -2037,10 +2159,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 ();
 
@@ -2056,12 +2175,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.  */
@@ -2086,6 +2203,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Wipe the echo area.  */
+  if (echo_area_glyphs)
+    safe_run_hooks (Qecho_area_clear_hook);
   echo_area_glyphs = 0;
 
   /* Handle things that only apply to characters.  */
@@ -2093,14 +2212,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       /* 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 > XFASTINT (c))
-       XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
-      else if ((VECTORP (Vkeyboard_translate_table)
-               && XVECTOR (Vkeyboard_translate_table)->size > XFASTINT (c))
-              || CHAR_TABLE_P (Vkeyboard_translate_table))
+       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);
@@ -2140,6 +2259,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  from_macro:
  reread_first:
+
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
 
@@ -2164,7 +2284,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* 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))
@@ -2196,7 +2316,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.  */
+  echo_area_glyphs = 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".  */
@@ -2249,7 +2402,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);
            }
@@ -2260,7 +2413,7 @@ record_char (c)
 
   store_kbd_macro_char (c);
 
-  num_nonmacro_input_chars++;
+  num_nonmacro_input_events++;
 }
 
 Lisp_Object
@@ -2280,12 +2433,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;
 {
@@ -2464,7 +2619,6 @@ kbd_buffer_store_event (event)
            }
 #endif
 
-#ifdef MULTI_FRAME
          /* If this results in a quit_char being returned to Emacs as
             input, set Vlast_event_frame properly.  If this doesn't
             get returned to Emacs as an event, the next event read
@@ -2478,7 +2632,6 @@ kbd_buffer_store_event (event)
            internal_last_event_frame = focus;
            Vlast_event_frame = focus;
          }
-#endif
 
          last_event_timestamp = event->timestamp;
          interrupt_signal ();
@@ -2534,6 +2687,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,
@@ -2601,6 +2776,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.  */
@@ -2691,12 +2875,13 @@ 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;
          input_pending = readable_events (0);
-         x_activate_menubar (XFRAME (event->frame_or_window));
+         if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
+           x_activate_menubar (XFRAME (event->frame_or_window));
        }
 #endif
       /* Just discard these, by returning nil.
@@ -2705,6 +2890,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
         (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;
 
@@ -2712,7 +2899,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
         time, and leave the event in the queue for next time.  */
       else
        {
-#ifdef MULTI_FRAME
          Lisp_Object frame;
          Lisp_Object focus;
 
@@ -2730,7 +2916,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && XFRAME (frame) != selected_frame)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
-#endif /* MULTI_FRAME */
 
          /* If we didn't decide to make a switch-frame event, go ahead
             and build a real event from the queue entry.  */
@@ -2777,7 +2962,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
       obj = Qnil;
 
-#ifdef MULTI_FRAME
       /* Decide if we should generate a switch-frame event.  Don't
         generate switch-frame events for motion outside of all Emacs
         frames.  */
@@ -2794,7 +2978,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
-#endif
 
       /* If we didn't decide to make a switch-frame event, go ahead and
         return a mouse-motion event.  */
@@ -2809,9 +2992,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
   input_pending = readable_events (0);
 
-#ifdef MULTI_FRAME
   Vlast_event_frame = internal_last_event_frame;
-#endif
 
   return (obj);
 }
@@ -2873,29 +3054,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;
     }
@@ -2912,6 +3070,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;
@@ -2937,6 +3096,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);
@@ -2966,8 +3126,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);
@@ -3104,64 +3262,27 @@ timer_check (do_it_now)
        {
          if (NILP (vector[0]))
            {
+             Lisp_Object tem;
+             int was_locked = single_kboard;
+             int count = specpdl_ptr - specpdl;
+
              /* 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);
 
-                 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++;
+             call1 (Qtimer_event_handler, chosen_timer);
+             timers_run++;
 
-                 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
@@ -3169,10 +3290,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;
        }
     }
@@ -3187,6 +3304,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.  */
@@ -3415,7 +3536,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 */
@@ -3441,7 +3562,42 @@ char *lispy_function_keys[] =
     "oem_clear",     /* VK_OEM_CLEAR      0xFE */
   };
 
-#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
 
@@ -3464,7 +3620,8 @@ static char *lispy_function_keys[] =
     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, "kanji", "muhenkan", 
+             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff20...2f */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff30...3f */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff40...4f */
 
@@ -3539,15 +3696,59 @@ 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;
@@ -3621,6 +3822,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;
@@ -3655,17 +3860,33 @@ 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
@@ -3760,7 +3981,7 @@ make_lispy_event (event)
            else
              {
                int pixcolumn, pixrow;
-               column -= XINT (XWINDOW (window)->left);
+               column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
                row -= XINT (XWINDOW (window)->top);
                glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
                XSETINT (event->x, pixcolumn);
@@ -3912,7 +4133,7 @@ make_lispy_event (event)
       }
 
 #ifdef WINDOWSNT
-    case win32_scroll_bar_click:
+    case w32_scroll_bar_click:
       {
        int button = event->code;
        int is_double;
@@ -3932,15 +4153,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;
 
        {
@@ -3958,8 +4179,140 @@ 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);
+
+       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
+             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);
+
+       if (!WINDOWP (window))
+         {
+           window = XCONS (event->frame_or_window)->car;
+           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
+             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,
+                                     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)
@@ -3986,7 +4339,6 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
      Lisp_Object x, y;
      unsigned long time;
 {
-#ifdef MULTI_FRAME
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
@@ -4005,18 +4357,13 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 
   /* Or is it an ordinary mouse movement?  */
   else
-#endif /* MULTI_FRAME */
     {
       int area;
       Lisp_Object window;
       Lisp_Object posn;
       int column, row;
 
-#ifdef MULTI_FRAME
       if (frame)
-#else
-      if (1)
-#endif
        {
          /* It's in a frame; which window on that frame?  */
          pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
@@ -4029,7 +4376,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
       if (WINDOWP (window))
        {
          int pixcolumn, pixrow;
-         column -= XINT (XWINDOW (window)->left);
+         column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
          row -= XINT (XWINDOW (window)->top);
          glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
          XSETINT (x, pixcolumn);
@@ -4043,13 +4390,11 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
            XSETINT (posn,
                     buffer_posn_from_coords (XWINDOW (window), column, row));
        }
-#ifdef MULTI_FRAME
       else if (frame != 0)
        {
          XSETFRAME (window, frame);
          posn = Qnil;
        }
-#endif
       else
        {
          window = Qnil;
@@ -4102,7 +4447,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;
@@ -4149,7 +4494,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.  */
@@ -4160,7 +4506,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;
@@ -4175,16 +4521,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;
 
   {
@@ -4215,9 +4561,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);
   }
@@ -4276,7 +4623,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))
@@ -4330,7 +4677,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);
@@ -4463,7 +4811,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
@@ -4483,7 +4831,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
        }
 
       if (CONSP (*symbol_table))
-       *symbol_table = Fcons (value, *symbol_table);
+        *symbol_table = Fcons (Fcons (symbol_int, value), *symbol_table);
       else
        XVECTOR (*symbol_table)->contents[symbol_num] = value;
 
@@ -4578,11 +4926,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;
 
@@ -4696,7 +5044,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;
 {
@@ -4705,7 +5053,7 @@ gobble_input (expected)
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4714,7 +5062,7 @@ gobble_input (expected)
   if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGALRM);
+      mask = sigblock (sigmask (SIGALRM));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4728,6 +5076,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;
@@ -4754,7 +5103,7 @@ record_asynch_buffer_change ()
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       kbd_buffer_store_event (&event);
       sigsetmask (mask);
     }
@@ -4791,8 +5140,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
@@ -4846,6 +5194,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
@@ -4889,11 +5244,7 @@ read_avail_input (expected)
            cbuf[i] &= ~0x80;
 
          buf[i].code = cbuf[i];
-#ifdef MULTI_FRAME
          XSETFRAME (buf[i].frame_or_window, selected_frame);
-#else
-         buf[i].frame_or_window = Qnil;
-#endif
        }
     }
 
@@ -4925,7 +5276,7 @@ input_available_signal (signo)
   extern int select_alarmed;
 #endif
 
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
   signal (signo, input_available_signal);
@@ -5091,7 +5442,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;
 
@@ -5159,25 +5510,14 @@ static void
 menu_bar_one_keymap (keymap)
      Lisp_Object keymap;
 {
-  Lisp_Object tail, item, key, binding, item_string, table;
+  Lisp_Object tail, item, table;
 
   /* 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.  */
@@ -5187,41 +5527,25 @@ menu_bar_one_keymap (keymap)
            {
              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);
+             menu_bar_item (character, XVECTOR (item)->contents[c]);
            }
        }
     }
 }
 
-/* This is used as the handler when calling internal_condition_case_1.  */
-
-static Lisp_Object
-menu_bar_item_1 (arg)
-     Lisp_Object arg;
-{
-  return Qnil;
-}
-
 /* 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_string, def)
-     Lisp_Object key, item_string, def;
+menu_bar_item (key, item)
+     Lisp_Object key, item;
 {
-  Lisp_Object tem;
-  Lisp_Object enabled;
+  struct gcpro gcpro1;
   int i;
 
-  if (EQ (def, Qundefined))
+  if (EQ (item, Qundefined))
     {
       /* If a map has an explicit `undefined' as definition,
         discard any previously made menu bar item.  */
@@ -5242,25 +5566,14 @@ menu_bar_item (key, item_string, def)
       return;
     }
 
-  /* See if this entry is enabled.  */
-  enabled = Qt;
-
-  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))
+  GCPRO1 (key);                        /* Is this necessary? */
+  i = parse_menu_item (item, 0, 1);
+  UNGCPRO;
+  if (!i)
     return;
 
+  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]))
@@ -5279,20 +5592,387 @@ menu_bar_item (key, item_string, def)
                 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++]
+       = 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 DEF to its list of maps.  */
+  /* 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 (def, old);
+      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.  */
+static Lisp_Object
+menu_item_eval_property (sexpr)
+     Lisp_Object sexpr;
+{
+  Lisp_Object val;
+  val = internal_condition_case_1 (Feval, sexpr, Qerror,
+                                  menu_item_eval_property_1);
+  return 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 = Qnil;
+  Lisp_Object filter = Qnil;
+  Lisp_Object keyhint = Qnil;
+  int i;
+  int newcache = 0;
+
+  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 (Fcons (XCONS (filter)->car,
+                                           Fcons (def, Qnil)));
+      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);
+  if (!NILP (tem))
+    {
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
+      XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
+      return 1;
+    }
+  else if (inmenubar > 0)
+    return 0;                  /* Entries in menu bar must be submenus.  */
+
+  /* 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
 /* Read a character using menus based on maps in the array MAPS.
@@ -5375,6 +6055,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
@@ -5385,10 +6067,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.
@@ -5459,7 +6144,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;
@@ -5480,7 +6165,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))
@@ -5513,26 +6198,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);
@@ -5541,6 +6227,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
@@ -5602,7 +6309,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
@@ -5669,7 +6377,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
@@ -5694,7 +6402,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;
        }
@@ -5742,16 +6450,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;
 
@@ -5843,12 +6555,12 @@ 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;
 
@@ -6091,6 +6803,14 @@ 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 (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;
            }
@@ -6434,7 +7154,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);
                }
@@ -6442,7 +7162,7 @@ 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), 0);
 
 #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.  */
@@ -6542,7 +7262,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);
              }
@@ -6550,7 +7270,7 @@ 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), 0);
 
            /* If the key translation map gives a function, not an
               array, then call the function with no args and use
@@ -6634,7 +7354,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)))
        {
@@ -6811,7 +7531,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)
     {
@@ -6821,6 +7541,44 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
   UNGCPRO;
   return make_event_array (i, keybuf);
 }
+
+DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
+       Sread_key_sequence_vector, 1, 4, 0,
+  "Like `read-key-sequence' but always return a vector.")
+  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+     Lisp_Object prompt, continue_echo, dont_downcase_last;
+     Lisp_Object can_return_switch_frame;
+{
+  Lisp_Object keybuf[30];
+  register int i;
+  struct gcpro gcpro1, gcpro2;
+
+  if (!NILP (prompt))
+    CHECK_STRING (prompt, 0);
+  QUIT;
+
+  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 Fvector (i, keybuf);
+}
 \f
 DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
  "Execute CMD as an editor command.\n\
@@ -6868,7 +7626,13 @@ a special event, so ignore the prefix argument and don't clear it.")
       final = Findirect_function (cmd);
 
       if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
-       do_autoload (final, cmd);
+       {
+         struct gcpro gcpro1, gcpro2;
+
+         GCPRO2 (cmd, prefixarg);
+         do_autoload (final, cmd);
+         UNGCPRO;
+       }
       else
        break;
     }
@@ -6879,13 +7643,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;
@@ -6912,12 +7687,13 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object function;
   char buf[40];
   Lisp_Object saved_keys;
-  struct gcpro gcpro1;
+  Lisp_Object bindings, value;
+  struct gcpro gcpro1, gcpro2;
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
   buf[0] = 0;
-  GCPRO1 (saved_keys);
+  GCPRO2 (saved_keys, prefixarg);
 
   if (EQ (prefixarg, Qminus))
     strcpy (buf, "- ");
@@ -6953,7 +7729,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");
@@ -6964,7 +7741,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;
@@ -6975,13 +7751,9 @@ 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;
@@ -6994,24 +7766,52 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   if (!NILP (Vsuggest_key_bindings)
       && NILP (Vexecuting_macro)
       && SYMBOLP (function))
-    {
-      Lisp_Object bindings;
+    bindings = Fwhere_is_internal (function, Voverriding_local_map,
+                                  Qt, Qnil);
+  else
+    bindings = Qnil;
 
-      bindings = Fwhere_is_internal (function, Voverriding_local_map,
-                                    Qt, Qnil);
+  value = Qnil;
+  GCPRO2 (bindings, value);
+  value = Fcommand_execute (function, Qt, Qnil, Qnil);
 
-      if (!NILP (bindings))
+  /* If the command has a key binding, print it now.  */
+  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))
+         && ! CONSP (Vunread_command_events))
        {
-         message ("You can run the command `%s' by typing %s",
+         Lisp_Object binding;
+         char *newmessage;
+         char *oldmessage = echo_area_glyphs;
+         int oldmessage_len = echo_area_glyphs_length;
+         int oldmultibyte = message_enable_multibyte;
+
+         binding = Fkey_description (bindings);
+
+         newmessage
+           = (char *) alloca (XSYMBOL (function)->name->size
+                              + STRING_BYTES (XSTRING (binding))
+                              + 100);
+         sprintf (newmessage, "You can run the command `%s' with %s",
                   XSYMBOL (function)->name->data,
-                  XSTRING (Fkey_description (bindings))->data);
-         Fsit_for ((NUMBERP (Vsuggest_key_bindings)
-                    ? Vsuggest_key_bindings : make_number (2)),
-                   Qnil, Qnil);
+                  XSTRING (binding)->data);
+         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, oldmultibyte);
        }
     }
 
-  return Fcommand_execute (function, Qt, Qnil, Qnil);
+  RETURN_UNGCPRO (value);
 }
 
 /* Find the set of keymaps now active.
@@ -7057,6 +7857,7 @@ current_active_maps (maps_p)
 \f
 /* Return nonzero if input events are pending.  */
 
+int
 detect_input_pending ()
 {
   if (!input_pending)
@@ -7065,9 +7866,9 @@ detect_input_pending ()
   return input_pending;
 }
 
-/* Return nonzero if input events are pending.
-   Execute timers immediately; don't make events for them.  */
+/* Return nonzero if input events are pending, and run any pending timers.  */
 
+int
 detect_input_pending_run_timers (do_display)
      int do_display;
 {
@@ -7085,11 +7886,26 @@ 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;
 }
 
+/* Return nonzero if there are pending requeued events.
+   This isn't used yet.  The hope is to make wait_reading_process_input
+   call it, and return return if it runs Lisp code that unreads something.
+   The problem is, kbd_buffer_get_event needs to be fixed to know what
+   to do in that case.  It isn't trivial.  */
+
+int
+requeued_events_pending_p ()
+{
+  return (!NILP (Vunread_command_events) || unread_command_char != -1);
+}
+
+
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
   "T if command input is currently available with no waiting.\n\
 Actually, the value is nil only if we can be sure that no input is available.")
@@ -7133,18 +7949,26 @@ 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 make_event_array (this_command_key_count
-                          - this_single_command_key_start,
-                          (XVECTOR (this_command_keys)->contents
-                           + this_single_command_key_start));
+  return Fvector (this_command_key_count
+                 - this_single_command_key_start,
+                 (XVECTOR (this_command_keys)->contents
+                  + this_single_command_key_start));
 }
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
@@ -7241,7 +8065,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);
@@ -7255,7 +8078,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 ();
@@ -7281,11 +8105,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;
 
@@ -7294,7 +8119,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');
@@ -7315,9 +8140,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;
 {
@@ -7332,6 +8158,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,  */
@@ -7359,7 +8186,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
 
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
   if (!read_socket_hook && NILP (Vwindow_system))
     {
       /* USG systems forget handlers when they are used;
@@ -7371,11 +8198,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
@@ -7454,6 +8287,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
 #endif /* not MSDOS */
       fflush (stdout);
       init_sys_modes ();
+      sigfree ();
     }
   else
     {
@@ -7462,9 +8296,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 */
@@ -7479,6 +8321,7 @@ 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 ();
@@ -7499,12 +8342,10 @@ quit_throw_to_read_char ()
     abort ();
 #endif
 #endif
-#ifdef MULTI_FRAME
   if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     Qnil, 0);
-#endif
 
   _longjmp (getcjmp, 1);
 }
@@ -7531,7 +8372,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
@@ -7570,7 +8411,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
 
@@ -7661,6 +8502,7 @@ delete_kboard (kb)
 }
 #endif
 
+void
 init_keyboard ()
 {
   /* This is correct before outermost invocation of the editor loop */
@@ -7681,12 +8523,10 @@ init_keyboard ()
 #endif
   input_pending = 0;
 
-#ifdef MULTI_FRAME
   /* This means that command_loop_1 won't try to select anything the first
      time through.  */
   internal_last_event_frame = Qnil;
   Vlast_event_frame = internal_last_event_frame;
-#endif
 
 #ifdef MULTI_KBOARD
   current_kboard = initial_kboard;
@@ -7757,8 +8597,15 @@ struct event_head head_table[] = {
   &Qmake_frame_visible,        "make-frame-visible",   &Qmake_frame_visible,
 };
 
+void
 syms_of_keyboard ()
 {
+  staticpro (&item_properties);
+  item_properties = Qnil;
+
+  Qtimer_event_handler = intern ("timer-event-handler");
+  staticpro (&Qtimer_event_handler);
+
   Qdisabled_command_hook = intern ("disabled-command-hook");
   staticpro (&Qdisabled_command_hook);
 
@@ -7796,11 +8643,33 @@ 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);
+#endif
+  Qdrag_n_drop = intern ("drag-n-drop");
+  staticpro (&Qdrag_n_drop);
 
   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);
+  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);
@@ -7890,11 +8759,26 @@ 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);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
+  defsubr (&Sread_key_sequence_vector);
   defsubr (&Srecursive_edit);
 #ifdef HAVE_MOUSE
   defsubr (&Strack_mouse);
@@ -7903,6 +8787,7 @@ syms_of_keyboard ()
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
+  defsubr (&Sthis_command_keys_vector);
   defsubr (&Sthis_single_command_keys);
   defsubr (&Sreset_this_command_lengths);
   defsubr (&Ssuspend_emacs);
@@ -7999,14 +8884,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\
@@ -8109,6 +9005,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;
@@ -8120,9 +9023,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\
@@ -8166,10 +9071,6 @@ 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;
 
-  DEFVAR_LISP ("column-number-mode", &Vcolumn_number_mode,
-    "Non-nil enables display of the current column number in the mode line.");
-  Vcolumn_number_mode = Qnil;
-
   DEFVAR_LISP ("timer-list", &Vtimer_list,
     "List of active absolute time timers in order of increasing time");
   Vtimer_list = Qnil;
@@ -8179,6 +9080,7 @@ If the value is non-nil and not a number, we wait 2 seconds.");
   Vtimer_idle_list = Qnil;
 }
 
+void
 keys_of_keyboard ()
 {
   initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");