Add support for large files, 64-bit Solaris, system locale codings.
[bpt/emacs.git] / src / keyboard.c
index 2afeca3..ab331ca 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,10 +18,8 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* Allow config.h to undefine symbols found here.  */
-#include <signal.h>
-
 #include <config.h>
+#include <signal.h>
 #include <stdio.h>
 #include "termchar.h"
 #include "termopts.h"
@@ -55,6 +53,11 @@ Boston, MA 02111-1307, USA.  */
 #include "syssignal.h"
 #include "systty.h"
 
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 /* This is to get the definitions of the XK_ symbols.  */
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -84,7 +87,12 @@ extern int input_fd;
 
 #ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
+#ifdef macintosh
+/* But not too big (local data > 32K error) if on macintosh */
+#define KBD_BUFFER_SIZE 512
+#else
 #define KBD_BUFFER_SIZE 4096
+#endif
 #else  /* No X-windows, character input */
 #define KBD_BUFFER_SIZE 256
 #endif /* No X-windows */
@@ -166,6 +174,11 @@ extern int message_enable_multibyte;
 
 extern struct backtrace *backtrace_list;
 
+/* If non-nil, the function that implements the display of help.
+   It's called with one argument, the help string to display.  */
+
+Lisp_Object Vshow_help_function;
+
 /* Nonzero means do menu prompting.  */
 static int menu_prompting;
 
@@ -179,11 +192,20 @@ static jmp_buf getcjmp;
 int waiting_for_input;
 
 /* True while displaying for echoing.   Delays C-g throwing.  */
+
 static int echoing;
 
-/* True means we can start echoing at the next input pause
-   even though there is something in the echo area.  */
-static char *ok_to_echo_at_next_pause;
+/* Non-null means we can start echoing at the next input pause even
+   though there is something in the echo area.  */
+
+static struct kboard *ok_to_echo_at_next_pause;
+
+/* The kboard currently echoing, or null for none.  Set in echo_now to
+   the kboard echoing.  Reset to 0 in cancel_echoing.  If non-null,
+   and a current echo area message exists, we know that it comes from
+   echoing.  */
+
+static struct kboard *echo_kboard;
 
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
@@ -459,7 +481,7 @@ static struct input_event *kbd_fetch_ptr;
 /* Pointer to next place to store character in kbd_buffer.  This
    may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
    character should go in kbd_buffer[0].  */
-static volatile struct input_event *kbd_store_ptr;
+static struct input_event * volatile kbd_store_ptr;
 
 /* The above pair of variables forms a "queue empty" flag.  When we
    enqueue a non-hook event, we increment kbd_store_ptr.  When we
@@ -482,12 +504,14 @@ Lisp_Object Qswitch_frame;
 Lisp_Object Qdelete_frame;
 Lisp_Object Qiconify_frame;
 Lisp_Object Qmake_frame_visible;
+Lisp_Object Qhelp_echo;
 
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
 #ifdef WINDOWSNT
 Lisp_Object Qmouse_wheel;
+Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
 /* Lisp_Object Qmouse_movement; - also an event header */
@@ -599,6 +623,7 @@ static Lisp_Object make_lispy_switch_frame ();
 static int parse_solitary_modifier ();
 static void save_getcjmp ();
 static void restore_getcjmp ();
+static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
 
 /* > 0 if we are to echo keystrokes.  */
 static int echo_keystrokes;
@@ -730,9 +755,9 @@ echo_now ()
     }
 
   echoing = 1;
+  echo_kboard = current_kboard;
   message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
                  ! NILP (current_buffer->enable_multibyte_characters));
-
   echoing = 0;
 
   if (waiting_for_input && !NILP (Vquit_flag))
@@ -748,6 +773,7 @@ cancel_echoing ()
   current_kboard->echoptr = current_kboard->echobuf;
   current_kboard->echo_after_prompt = -1;
   ok_to_echo_at_next_pause = 0;
+  echo_kboard = 0;
 }
 
 /* Return the length of the current echo string.  */
@@ -855,7 +881,6 @@ This function is called by the editor initialization to begin editing.")
   ()
 {
   int count = specpdl_ptr - specpdl;
-  Lisp_Object val;
 
   command_loop_level++;
   update_mode_lines = 1;
@@ -1013,17 +1038,27 @@ cmd_error_internal (data, context)
      char *context;
 {
   Lisp_Object stream;
+  int kill_emacs_p = 0;
+  struct frame *sf = SELECTED_FRAME ();
 
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
-  echo_area_glyphs = 0;
+  clear_message (1, 0);
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're not interactive, it's best to dump this message out
      to stderr and exit.  */
-  if (! FRAME_MESSAGE_BUF (selected_frame)
+  if (!sf->glyphs_initialized_p
+      /* This is the case of the frame dumped with Emacs, when we're
+        running under a window system.  */
+      || (!NILP (Vwindow_system)
+         && !inhibit_window_system
+         && FRAME_TERMCAP_P (sf))
       || noninteractive)
-    stream = Qexternal_debugging_output;
+    {
+      stream = Qexternal_debugging_output;
+      kill_emacs_p = 1;
+    }
   else
     {
       Fdiscard_input ();
@@ -1038,8 +1073,7 @@ cmd_error_internal (data, context)
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're in -batch mode, this error should cause Emacs to exit.  */
-  if (! FRAME_MESSAGE_BUF (selected_frame)
-      || noninteractive)
+  if (kill_emacs_p)
     {
       Fterpri (stream);
       Fkill_emacs (make_number (-1));
@@ -1059,7 +1093,8 @@ command_loop ()
 {
   if (command_loop_level > 0 || minibuf_level > 0)
     {
-      Lisp_Object val = internal_catch (Qexit, command_loop_2, Qnil);
+      Lisp_Object val;
+      val = internal_catch (Qexit, command_loop_2, Qnil);
       executing_macro = Qnil;
       return val;
     }
@@ -1150,8 +1185,8 @@ void safe_run_hooks ();
 Lisp_Object
 command_loop_1 ()
 {
-  Lisp_Object cmd, tem;
-  int lose, lose2;
+  Lisp_Object cmd;
+  int lose;
   int nonundocount;
   Lisp_Object keybuf[30];
   int i;
@@ -1181,6 +1216,11 @@ command_loop_1 ()
   if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
     safe_run_hooks (Qpost_command_hook);
 
+  /* If displaying a message, resize the echo area window to fit
+     that message's size exactly.  */
+  if (!NILP (echo_area_buffer[0]))
+    resize_echo_area_axactly ();
+
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
 
@@ -1200,6 +1240,9 @@ command_loop_1 ()
 
   while (1)
     {
+      if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+       Fkill_emacs (Qnil);
+
       /* Make sure the current window's buffer is selected.  */
       if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
        set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
@@ -1217,7 +1260,8 @@ command_loop_1 ()
       /* If minibuffer on and echo area in use,
         wait 2 sec and redraw minibuffer.  */
 
-      if (minibuf_level && echo_area_glyphs
+      if (minibuf_level
+         && !NILP (echo_area_buffer[0])
          && EQ (minibuf_window, echo_area_window))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
@@ -1251,7 +1295,7 @@ command_loop_1 ()
         code swallows a switch-frame event, we'll fix things up here.
         Is this a good idea?  */
       if (FRAMEP (internal_last_event_frame)
-         && XFRAME (internal_last_event_frame) != selected_frame)
+         && !EQ (internal_last_event_frame, selected_frame))
        Fselect_frame (internal_last_event_frame, Qnil);
 #endif
       /* If it has changed current-menubar from previous value,
@@ -1271,6 +1315,8 @@ command_loop_1 ()
                             Qnil, 0, 1, 1);
 
       /* A filter may have run while we were reading the input.  */
+      if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+       Fkill_emacs (Qnil);
       if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
        set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
 
@@ -1300,8 +1346,10 @@ command_loop_1 ()
         update the whole window properly.  */
       if (!NILP (XWINDOW (selected_window)->force_start))
        {
+         struct buffer *b;
          XWINDOW (selected_window)->force_start = Qnil;
-         beg_unchanged = end_unchanged = 0;
+         b = XBUFFER (XWINDOW (selected_window)->buffer);
+         BUF_BEG_UNCHANGED (b) = BUF_END_UNCHANGED (b) = 0;
        }
 
       cmd = read_key_sequence_cmd;
@@ -1414,7 +1462,6 @@ command_loop_1 ()
                {
                  unsigned int c = XINT (last_command_char);
                  int value;
-
                  if (NILP (Vexecuting_macro)
                      && !EQ (minibuf_window, selected_window))
                    {
@@ -1425,6 +1472,7 @@ command_loop_1 ()
                        }
                      nonundocount++;
                    }
+                 
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
@@ -1437,58 +1485,33 @@ command_loop_1 ()
                          || detect_input_pending ()
                          || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_macro));
+                 
                  value = internal_self_insert (c, 0);
-                 if (value)
-                   lose = 1;
+
                  if (value == 2)
                    nonundocount = 0;
 
-                 if (!lose
-                     && (PT == ZV || FETCH_BYTE (PT_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;
-
-                         obj = DISP_CHAR_VECTOR (dp, lose);
-                         if (NILP (obj))
-                           {
-                             /* Do it only for char codes
-                                that by default display as themselves.  */
-                             if (lose >= 0x20 && lose <= 0x7e)
-                               no_redisplay = direct_output_for_insert (lose);
-                           }
-                         else if (VECTORP (obj)
-                                  && XVECTOR (obj)->size == 1
-                                  && (obj = XVECTOR (obj)->contents[0],
-                                      INTEGERP (obj))
-                                  /* Insist face not specified in glyph.  */
-                                  && (XINT (obj) & ((-1) << 8)) == 0)
-                           no_redisplay
-                             = direct_output_for_insert (XINT (obj));
-                       }
-                     else
-                       {
-                         if (lose >= 0x20 && lose <= 0x7e)
-                           no_redisplay = direct_output_for_insert (lose);
-                       }
-                   }
+                 /* VALUE == 1 when AFTER-CHANGE functions are
+                    installed which is the case most of the time
+                    because FONT-LOCK installs one.  */
+                 if (!lose && !value)
+                   no_redisplay = direct_output_for_insert (c);
                  goto directly_done;
                }
            }
 
          /* Here for a command that isn't executed directly */
 
+#ifdef HAVE_X_WINDOWS
+         if (display_busy_cursor_p)
+           {
+             if (inhibit_busy_cursor != 2)
+               inhibit_busy_cursor = 0;
+             if (!inhibit_busy_cursor)
+               Fx_show_busy_cursor ();
+           }
+#endif
+
          nonundocount = 0;
          if (NILP (current_kboard->Vprefix_arg))
            Fundo_boundary ();
@@ -1502,6 +1525,11 @@ command_loop_1 ()
       if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpost_command_hook);
 
+      /* If displaying a message, resize the echo area window to fit
+        that message's size exactly.  */
+      if (!NILP (echo_area_buffer[0]))
+       resize_echo_area_axactly ();
+
       if (!NILP (Vdeferred_action_list))
        safe_run_hooks (Qdeferred_action_function);
 
@@ -1588,7 +1616,6 @@ void
 safe_run_hooks (hook)
      Lisp_Object hook;
 {
-  Lisp_Object value;
   int count = specpdl_ptr - specpdl;
   specbind (Qinhibit_quit, hook);
 
@@ -1778,7 +1805,10 @@ static jmp_buf wrong_kboard_jmpbuf;
    MAPS is an array of keymaps;  NMAPS is the length of MAPS.
 
    PREV_EVENT is the previous input event, or nil if we are reading
-   the first event of a key sequence.
+   the first event of a key sequence (or not reading a key sequence).
+   If PREV_EVENT is t, that is a "magic" value that says
+   not to run input methods, but in other respects to act as if
+   not reading a key sequence.
 
    If USED_MOUSE_MENU is non-null, then we set *USED_MOUSE_MENU to 1
    if we used a mouse menu to read the input, or zero otherwise.  If
@@ -1800,7 +1830,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   jmp_buf save_jump;
   int key_already_recorded = 0;
   Lisp_Object tem, save;
-  Lisp_Object echo_area_message;
+  Lisp_Object previous_echo_area_message;
   Lisp_Object also_record;
   int reread;
   struct gcpro gcpro1, gcpro2;
@@ -1810,9 +1840,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
   c = Qnil;
-  echo_area_message = Qnil;
+  previous_echo_area_message = Qnil;
 
-  GCPRO2 (c, echo_area_message);
+  GCPRO2 (c, previous_echo_area_message);
 
  retry:
 
@@ -1948,9 +1978,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
-  if (echo_area_glyphs && *echo_area_glyphs
-      && echo_area_glyphs != current_kboard->echobuf
-      && ok_to_echo_at_next_pause != echo_area_glyphs)
+  if (/* There is a current message.  */
+      !NILP (echo_area_buffer[0])
+      /* And we're not echoing from this kboard.  */
+      && echo_kboard != current_kboard
+      /* And it's either not ok to echo (ok_to_echo == NULL), or the
+        last char echoed was from a different kboard.  */
+      && ok_to_echo_at_next_pause != echo_kboard)
     cancel_echoing ();
   else
     /* If already echoing, continue.  */
@@ -1986,7 +2020,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (_setjmp (local_getcjmp))
     {
       XSETINT (c, quit_char);
-      XSETFRAME (internal_last_event_frame, selected_frame);
+      internal_last_event_frame = selected_frame;
       Vlast_event_frame = internal_last_event_frame;
       /* If we report the quit char as an event,
         don't do so more than once.  */
@@ -1995,7 +2029,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
 #ifdef MULTI_KBOARD
       {
-       KBOARD *kb = FRAME_KBOARD (selected_frame);
+       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
        if (kb != current_kboard)
          {
            Lisp_Object *tailp = &kb->kbd_queue;
@@ -2024,15 +2058,23 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
-  if (minibuf_level == 0 && !current_kboard->immediate_echo
+  if (minibuf_level == 0 
+      && !current_kboard->immediate_echo
       && this_command_key_count > 0
       && ! noninteractive
       && echo_keystrokes > 0
-      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
-         || ok_to_echo_at_next_pause == echo_area_glyphs))
+      && (/* No message.  */
+         NILP (echo_area_buffer[0])
+         /* Or empty message.  */
+         || (BUF_BEG (XBUFFER (echo_area_buffer[0]))
+             == BUF_Z (XBUFFER (echo_area_buffer[0])))
+         /* Or already echoing from same kboard.  */
+         || (echo_kboard && ok_to_echo_at_next_pause == echo_kboard)
+         /* Or not echoing before and echoing allowed.  */
+         || (!echo_kboard && ok_to_echo_at_next_pause)))
     {
       Lisp_Object tem0;
-
+      
       /* After a mouse event, start echoing right away.
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
@@ -2071,6 +2113,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && !NILP (prev_event)
       && EVENT_HAS_PARAMETERS (prev_event)
       && !EQ (XCONS (prev_event)->car, Qmenu_bar)
+      && !EQ (XCONS (prev_event)->car, Qtool_bar)
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events)
       && unread_command_char < 0)
@@ -2323,7 +2366,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       posn = POSN_BUFFER_POSN (EVENT_START (c));
       /* Handle menu-bar events:
         insert the dummy prefix event `menu-bar'.  */
-      if (EQ (posn, Qmenu_bar))
+      if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
        {
          /* Change menu-bar to (menu-bar) as the event "position".  */
          POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
@@ -2347,40 +2390,96 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && ! NILP (Vinput_method_function)
       && (unsigned) XINT (c) >= ' '
       && (unsigned) XINT (c) < 127)
-    Vinput_method_previous_message = echo_area_message = Fcurrent_message ();
+    {
+      previous_echo_area_message = Fcurrent_message ();
+      Vinput_method_previous_message = previous_echo_area_message;
+    }
 
   /* Now wipe the echo area.  */
-  if (echo_area_glyphs)
+  if (!NILP (echo_area_buffer[0]))
     safe_run_hooks (Qecho_area_clear_hook);
-  echo_area_glyphs = 0;
+  clear_message (1, 0);
 
  reread_for_input_method:
  from_macro:
   /* Pass this to the input method, if appropriate.  */
   if (INTEGERP (c)
       && ! NILP (Vinput_method_function)
+      /* Don't run the input method within a key sequence,
+        after the first event of the key sequence.  */
+      && NILP (prev_event)
       && (unsigned) XINT (c) >= ' '
       && (unsigned) XINT (c) < 127)
     {
       Lisp_Object keys; 
-      int key_count = this_command_key_count;
-      int saved = current_kboard->immediate_echo;
+      int key_count;
       struct gcpro gcpro1;
+      int count = specpdl_ptr - specpdl;
 
-      keys = Fcopy_sequence (this_command_keys);
+      /* Save the echo status.  */
+      int saved_immediate_echo = current_kboard->immediate_echo;
+      struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+      int saved_echo_after_prompt = current_kboard->echo_after_prompt;
+
+      if (before_command_restore_flag)
+       {
+         this_command_key_count = before_command_key_count_1;
+         if (this_command_key_count < this_single_command_key_start)
+           this_single_command_key_start = this_command_key_count;
+         echo_truncate (before_command_echo_length_1);
+         before_command_restore_flag = 0;
+       }
+
+      /* Save the this_command_keys status.  */
+      key_count = this_command_key_count;
+
+      if (key_count > 0)
+       keys = Fcopy_sequence (this_command_keys);
+      else
+       keys = Qnil;
       GCPRO1 (keys);
+
+      /* Clear out this_command_keys.  */
+      this_command_key_count = 0;
+
+      /* Now wipe the echo area.  */
+      if (!NILP (echo_area_buffer[0]))
+       safe_run_hooks (Qecho_area_clear_hook);
+      clear_message (1, 0);
+      echo_truncate (0);
+
+      /* If we are not reading a key sequence,
+        never use the echo area.  */
+      if (maps == 0)
+       {
+         specbind (Qinput_method_use_echo_area, Qt);
+       }
+
+      /* Call the input method.  */
       tem = call1 (Vinput_method_function, c);
+
+      tem = unbind_to (count, tem);
+
+      /* Restore the saved echoing state
+        and this_command_keys state.  */
+      this_command_key_count = key_count;
+      if (key_count > 0)
+       this_command_keys = keys;
+
+      cancel_echoing ();
+      ok_to_echo_at_next_pause = saved_ok_to_echo;
+      current_kboard->echo_after_prompt = saved_echo_after_prompt;
+      if (saved_immediate_echo)
+       echo_now ();
+
       UNGCPRO;
-      current_kboard->immediate_echo = saved;
+
       /* The input method can return no events.  */
       if (! CONSP (tem))
        {
          /* Bring back the previous message, if any.  */
-         if (! NILP (Vinput_method_previous_message))
-           message_with_string ("%s", echo_area_message, 0);
-         this_command_keys = keys;
-         this_command_key_count = key_count;
-         cancel_echoing ();
+         if (! NILP (previous_echo_area_message))
+           message_with_string ("%s", previous_echo_area_message, 0);
          goto retry;
        }
       /* It returned one event or more.  */
@@ -2391,6 +2490,25 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  reread_first:
 
+  /* Display help if not echoing.  */
+  if (CONSP (c)
+      && EQ (XCAR (c), Qhelp_echo))
+    {
+      Lisp_Object msg = XCDR (XCDR (c));
+
+      if (!NILP (Vshow_help_function))
+       call1 (Vshow_help_function, msg);
+      else if (!echoing && !MINI_WINDOW_P (XWINDOW (selected_window)))
+       {
+         if (STRINGP (msg))
+           message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg));
+         else
+           message (0);
+       }
+      
+      goto retry;
+    }
+  
   if (this_command_key_count == 0 || ! reread)
     {
       before_command_key_count = this_command_key_count;
@@ -2406,7 +2524,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            echo_char (also_record);
          /* Once we reread a character, echoing can happen
             the next time we pause to read a new one.  */
-         ok_to_echo_at_next_pause = echo_area_glyphs;
+         ok_to_echo_at_next_pause = current_kboard;
        }
 
       /* Record this character as part of the current key.  */
@@ -2459,7 +2577,7 @@ record_menu_key (c)
      Lisp_Object c;
 {
   /* Wipe the echo area.  */
-  echo_area_glyphs = 0;
+  clear_message (1, 0);
 
   record_char (c);
 
@@ -2792,7 +2910,7 @@ kbd_buffer_store_event (event)
      Discard the event if it would fill the last slot.  */
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
-      volatile struct input_event *sp = kbd_store_ptr;
+      struct input_event *sp = kbd_store_ptr;
       sp->kind = event->kind;
       if (event->kind == selection_request_event)
        {
@@ -2854,7 +2972,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 {
   register int c;
   Lisp_Object obj;
-  EMACS_TIME next_timer_delay;
 
   if (noninteractive)
     {
@@ -3015,6 +3132,17 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
            x_activate_menubar (XFRAME (event->frame_or_window));
        }
+#endif
+#ifdef WINDOWSNT
+      else if (event->kind == language_change_event)
+       {
+         /* Make an event (language-change (FRAME CHARSET LCID)).  */
+         obj = Fcons (event->modifiers, Qnil);
+         obj = Fcons (event->code, Qnil);
+         obj = Fcons (event->frame_or_window, obj);
+         obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
+         kbd_fetch_ptr = event + 1;
+       }
 #endif
       /* Just discard these, by returning nil.
         With MULTI_KBOARD, these events are used as placeholders
@@ -3026,7 +3154,13 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          mouse events during a popup-menu call.  */
       else if (event->kind == no_event)
        kbd_fetch_ptr = event + 1;
-
+      else if (event->kind == HELP_EVENT)
+       {
+         /* The car of event->frame_or_window is a frame,
+            the cdr is the help to display.  */
+         obj = Fcons (Qhelp_echo, event->frame_or_window);
+         kbd_fetch_ptr = event + 1;
+       }
       /* If this event is on a different frame, return a switch-frame this
         time, and leave the event in the queue for next time.  */
       else
@@ -3045,7 +3179,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            frame = focus;
 
          if (! EQ (frame, internal_last_event_frame)
-             && XFRAME (frame) != selected_frame)
+             && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
 
@@ -3061,8 +3195,10 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
                 we're returning is (menu-bar), though; that indicates the
                 beginning of the menu sequence, and we might as well leave
                 that as the `event with parameters' for this selection.  */
-             if (event->kind == menu_bar_event
+             if ((event->kind == menu_bar_event
+                  || event->kind == TOOL_BAR_EVENT)
                  && !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar))
+                 && !(CONSP (obj) && EQ (XCONS (obj)->car, Qtool_bar))
                  && used_mouse_menu)
                *used_mouse_menu = 1;
 #endif
@@ -3106,7 +3242,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            XSETFRAME (frame, f);
 
          if (! EQ (frame, internal_last_event_frame)
-             && XFRAME (frame) != selected_frame)
+             && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
@@ -3282,7 +3418,6 @@ timer_check (do_it_now)
 
   while (CONSP (timers) || CONSP (idle_timers))
     {
-      int triggertime = EMACS_SECS (now);
       Lisp_Object *vector;
       Lisp_Object timer, idle_timer;
       EMACS_TIME timer_time, idle_timer_time;
@@ -3394,9 +3529,11 @@ timer_check (do_it_now)
        {
          if (NILP (vector[0]))
            {
-             Lisp_Object tem;
              int was_locked = single_kboard;
              int count = specpdl_ptr - specpdl;
+#ifdef HAVE_WINDOW_SYSTEM
+             int old_inhibit_busy_cursor = inhibit_busy_cursor;
+#endif
 
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
@@ -3404,9 +3541,17 @@ timer_check (do_it_now)
 
              specbind (Qinhibit_quit, Qt);
 
+#ifdef HAVE_WINDOW_SYSTEM
+             inhibit_busy_cursor = 2;
+#endif
+             
              call1 (Qtimer_event_handler, chosen_timer);
              timers_run++;
 
+#ifdef HAVE_WINDOW_SYSTEM
+             inhibit_busy_cursor = old_inhibit_busy_cursor;
+#endif
+
              unbind_to (count, Qnil);
 
              /* Resume allowing input from any kboard, if that was true before.  */
@@ -3557,15 +3702,15 @@ char *lispy_function_keys[] =
     
     0, 0,             /*    0x0E .. 0x0F        */
   
-    "shift",          /* VK_SHIFT          0x10 */
-    "control",        /* VK_CONTROL        0x11 */
-    "menu",           /* VK_MENU           0x12 */
+    0,                /* VK_SHIFT          0x10 */
+    0,                /* VK_CONTROL        0x11 */
+    0,                /* VK_MENU           0x12 */
     "pause",          /* VK_PAUSE          0x13 */
-    "capital",        /* VK_CAPITAL        0x14 */
+    "capslock",       /* VK_CAPITAL        0x14 */
     
     0, 0, 0, 0, 0, 0, /*    0x15 .. 0x1A        */
     
-    0,                /* VK_ESCAPE         0x1B */
+    "escape",         /* VK_ESCAPE         0x1B */
     
     0, 0, 0, 0,       /*    0x1C .. 0x1F        */
     
@@ -3692,6 +3837,7 @@ char *lispy_function_keys[] =
     "noname",        /* VK_NONAME         0xFC */
     "pa1",           /* VK_PA1            0xFD */
     "oem_clear",     /* VK_OEM_CLEAR      0xFE */
+    0 /* 0xFF */
   };
 
 #else /* not HAVE_NTGUI */
@@ -3871,12 +4017,21 @@ static char *lispy_drag_n_drop_names[] =
 
 /* Scroll bar parts.  */
 Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
-Lisp_Object Qup, Qdown;
+Lisp_Object Qup, Qdown, Qbottom, Qend_scroll;
+Lisp_Object Qtop;
 
 /* An array of scroll bar parts, indexed by an enum scroll_bar_part value.  */
 Lisp_Object *scroll_bar_parts[] = {
   &Qabove_handle, &Qhandle, &Qbelow_handle,
-  &Qup, &Qdown,
+  &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll
+};
+
+/* User signal events.  */
+Lisp_Object Qusr1_signal, Qusr2_signal;
+
+Lisp_Object *lispy_user_signals[] =
+{
+  &Qusr1_signal, &Qusr2_signal
 };
 
 
@@ -4012,7 +4167,9 @@ make_lispy_event (event)
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
     case mouse_click:
+#ifndef USE_TOOLKIT_SCROLL_BARS
     case scroll_bar_click:
+#endif
       {
        int button = event->code;
        int is_double;
@@ -4030,6 +4187,7 @@ make_lispy_event (event)
            FRAME_PTR f = XFRAME (event->frame_or_window);
            Lisp_Object window;
            Lisp_Object posn;
+           Lisp_Object string_info = Qnil;
            int row, column;
 
            /* Ignore mouse events that were made on frame that
@@ -4037,8 +4195,13 @@ make_lispy_event (event)
            if (! FRAME_LIVE_P (f))
              return Qnil;
 
-           pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                                  &column, &row, NULL, 1);
+           /* EVENT->x and EVENT->y are frame-relative pixel
+              coordinates at this place.  Under old redisplay, COLUMN
+              and ROW are set to frame relative glyph coordinates
+              which are then used to determine whether this click is
+              in a menu (non-toolkit version).  */
+           pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                                  &column, &row, NULL, 1);
 
 #ifndef USE_X_TOOLKIT
            /* In the non-toolkit version, clicks on the menu bar
@@ -4063,6 +4226,7 @@ make_lispy_event (event)
                  return Qnil;
 #endif
 
+               /* Find the menu bar item under `column'.  */
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
                for (i = 0; i < XVECTOR (items)->size; i += 4)
@@ -4080,6 +4244,8 @@ make_lispy_event (event)
                      }
                  }
 
+               /* ELisp manual 2.4b says (x y) are window relative but
+                  code says they are frame-relative.  */
                position
                  = Fcons (event->frame_or_window,
                           Fcons (Qmenu_bar,
@@ -4091,7 +4257,10 @@ make_lispy_event (event)
              }
 #endif /* not USE_X_TOOLKIT */
 
-           window = window_from_coordinates (f, column, row, &part);
+           /* Set `window' to the window under frame pixel coordinates
+              event->x/event->y.  */
+           window = window_from_coordinates (f, XINT (event->x),
+                                             XINT (event->y), &part, 0);
 
            if (!WINDOWP (window))
              {
@@ -4100,21 +4269,36 @@ make_lispy_event (event)
              }
            else
              {
-               int pixcolumn, pixrow;
-               column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
-               row -= XINT (XWINDOW (window)->top);
-               glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
-               XSETINT (event->x, pixcolumn);
-               XSETINT (event->y, pixrow);
-
-               if (part == 1)
-                 posn = Qmode_line;
+               /* It's a click in window window at frame coordinates
+                  event->x/ event->y.  */
+               struct window *w = XWINDOW (window);
+
+               /* Get window relative coordinates.  Original code
+                  `rounded' this to glyph boundaries.  */
+               int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+               int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+               /* Set event coordinates to window-relative coordinates
+                  for constructing the Lisp event below.  */
+               XSETINT (event->x, wx);
+               XSETINT (event->y, wy);
+
+               if (part == 1 || part == 3)
+                 {
+                   /* Mode line or top line.  Look for a string under
+                      the mouse that may have a `local-map' property.  */
+                   Lisp_Object string;
+                   int charpos;
+                   
+                   posn = part == 1 ? Qmode_line : Qheader_line;
+                   string = mode_line_string (w, wx, wy, part == 1, &charpos);
+                   if (STRINGP (string))
+                     string_info = Fcons (string, make_number (charpos));
+                 }
                else if (part == 2)
                  posn = Qvertical_line;
                else
-                 XSETINT (posn,
-                          buffer_posn_from_coords (XWINDOW (window),
-                                                   column, row));
+                 XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
              }
 
            position
@@ -4122,10 +4306,14 @@ make_lispy_event (event)
                       Fcons (posn,
                              Fcons (Fcons (event->x, event->y),
                                     Fcons (make_number (event->timestamp),
-                                           Qnil))));
+                                           (NILP (string_info)
+                                            ? Qnil
+                                            : Fcons (string_info, Qnil))))));
          }
+#ifndef USE_TOOLKIT_SCROLL_BARS
        else
          {
+           /* It's a scrollbar click.  */
            Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
@@ -4141,6 +4329,7 @@ make_lispy_event (event)
                                     Fcons (make_number (event->timestamp),
                                            Fcons (part, Qnil)))));
          }
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 
        start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
 
@@ -4252,6 +4441,55 @@ make_lispy_event (event)
        }
       }
 
+#if USE_TOOLKIT_SCROLL_BARS
+
+      /* We don't have down and up events if using toolkit scroll bars,
+        so make this always a click event.  Store in the `part' of
+        the Lisp event a symbol which maps to the following actions:
+
+        `above_handle'         page up
+        `below_handle'         page down
+        `up'                   line up
+        `down'                 line down
+        `top'                  top of buffer
+        `bottom'               bottom of buffer
+        `handle'               thumb has been dragged.
+        `end-scroll'           end of interaction with scroll bar
+
+        The incoming input_event contains in its `part' member an
+        index of type `enum scroll_bar_part' which we can use as an
+        index in scroll_bar_parts to get the appropriate symbol.  */
+        
+    case scroll_bar_click:
+      {
+       Lisp_Object position, head, window, portion_whole, part;
+
+       window = event->frame_or_window;
+       portion_whole = Fcons (event->x, event->y);
+       part = *scroll_bar_parts[(int) event->part];
+
+       position
+         = Fcons (window,
+                  Fcons (Qvertical_scroll_bar,
+                         Fcons (portion_whole,
+                                Fcons (make_number (event->timestamp),
+                                       Fcons (part, Qnil)))));
+
+       /* Always treat scroll bar events as clicks. */
+       event->modifiers |= click_modifier;
+
+       /* Get the symbol we should use for the mouse click.  */
+       head = modify_event_symbol (event->code,
+                                   event->modifiers,
+                                   Qmouse_click, Qnil,
+                                   lispy_mouse_names, &mouse_syms,
+                                   (sizeof (lispy_mouse_names)
+                                    / sizeof (lispy_mouse_names[0])));
+       return Fcons (head, Fcons (position, Qnil));
+      }
+      
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
 #ifdef WINDOWSNT
     case w32_scroll_bar_click:
       {
@@ -4314,7 +4552,7 @@ make_lispy_event (event)
          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);
+       window = window_from_coordinates (f, column, row, &part, 0);
 
        if (!WINDOWP (window))
          {
@@ -4334,6 +4572,8 @@ make_lispy_event (event)
              posn = Qmode_line;
            else if (part == 2)
              posn = Qvertical_line;
+           else if (part == 3)
+             posn = Qheader_line;
            else
              XSETINT (posn,
                       buffer_posn_from_coords (XWINDOW (window),
@@ -4368,7 +4608,6 @@ make_lispy_event (event)
        FRAME_PTR f;
        Lisp_Object window;
        Lisp_Object posn;
-       Lisp_Object head, position;
        Lisp_Object files;
        int row, column;
 
@@ -4387,7 +4626,7 @@ make_lispy_event (event)
          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);
+       window = window_from_coordinates (f, column, row, &part, 0);
 
        if (!WINDOWP (window))
          {
@@ -4396,21 +4635,27 @@ make_lispy_event (event)
          }
        else
          {
-           int pixcolumn, pixrow;
-           column -= XINT (XWINDOW (window)->left);
-           row -= XINT (XWINDOW (window)->top);
-           glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
-           XSETINT (event->x, pixcolumn);
-           XSETINT (event->y, pixrow);
+           /* It's an event in window `window' at frame coordinates
+              event->x/ event->y.  */
+           struct window *w = XWINDOW (window);
+
+           /* Get window relative coordinates.  */
+           int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+           int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+           /* Set event coordinates to window-relative coordinates
+              for constructing the Lisp event below.  */
+           XSETINT (event->x, wx);
+           XSETINT (event->y, wy);
 
            if (part == 1)
              posn = Qmode_line;
            else if (part == 2)
              posn = Qvertical_line;
+           else if (part == 3)
+             posn = Qheader_line;
            else
-             XSETINT (posn,
-                      buffer_posn_from_coords (XWINDOW (window),
-                                               column, row));
+             XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
          }
 
        {
@@ -4443,6 +4688,21 @@ make_lispy_event (event)
       return XCONS (event->frame_or_window)->cdr;
 #endif
 
+    case TOOL_BAR_EVENT:
+      {
+       Lisp_Object key;
+       if (!CONSP (event->frame_or_window))
+         abort ();
+       key = XCDR (event->frame_or_window);
+       if (SYMBOLP (key))
+         key = apply_modifiers (event->modifiers, key);
+       return key;
+      }
+
+    case user_signal:
+      /* A user signal.  */
+      return *lispy_user_signals[event->code];
+      
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -4481,34 +4741,32 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
       int area;
       Lisp_Object window;
       Lisp_Object posn;
-      int column, row;
 
       if (frame)
-       {
-         /* It's in a frame; which window on that frame?  */
-         pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
-                                NULL, 1);
-         window = window_from_coordinates (frame, column, row, &area);
-       }
+       /* It's in a frame; which window on that frame?  */
+       window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
       else
        window = Qnil;
 
       if (WINDOWP (window))
        {
-         int pixcolumn, pixrow;
-         column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
-         row -= XINT (XWINDOW (window)->top);
-         glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
-         XSETINT (x, pixcolumn);
-         XSETINT (y, pixrow);
-
+         struct window *w = XWINDOW (window);
+         int wx, wy;
+         
+         /* Get window relative coordinates.  */
+         wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
+         wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
+         XSETINT (x, wx);
+         XSETINT (y, wy);
+         
          if (area == 1)
            posn = Qmode_line;
          else if (area == 2)
            posn = Qvertical_line;
+         else if (area == 3)
+           posn = Qheader_line;
          else
-           XSETINT (posn,
-                    buffer_posn_from_coords (XWINDOW (window), column, row));
+           XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
        }
       else if (frame != 0)
        {
@@ -4726,7 +4984,7 @@ lispy_modifier_list (modifiers)
    SYMBOL's Qevent_symbol_element_mask property, and maintains the
    Qevent_symbol_elements property.  */
 
-static Lisp_Object
+Lisp_Object
 parse_modifiers (symbol)
      Lisp_Object symbol;
 {
@@ -5312,7 +5570,7 @@ read_avail_input (expected)
          cbuf[0] = dos_keyread ();
          nread = 1;
 #else
-         nread = read (input_fd, cbuf, n_to_read);
+         nread = emacs_read (input_fd, cbuf, n_to_read);
 #endif
          /* POSIX infers that processes which are not in the session leader's
             process group won't get SIGHUP's at logout time.  BSDI adheres to
@@ -5364,7 +5622,7 @@ read_avail_input (expected)
            cbuf[i] &= ~0x80;
 
          buf[i].code = cbuf[i];
-         XSETFRAME (buf[i].frame_or_window, selected_frame);
+         buf[i].frame_or_window = selected_frame;
        }
     }
 
@@ -5605,7 +5863,6 @@ menu_bar_items (old)
   if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
     {
       Lisp_Object tem;
-      int newsize = 2 * i;
       tem = Fmake_vector (make_number (2 * i), Qnil);
       bcopy (XVECTOR (menu_bar_items_vector)->contents,
             XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
@@ -5626,11 +5883,15 @@ menu_bar_items (old)
 /* Scan one map KEYMAP, accumulating any menu items it defines
    in menu_bar_items_vector.  */
 
+static Lisp_Object menu_bar_one_keymap_changed_items;
+
 static void
 menu_bar_one_keymap (keymap)
      Lisp_Object keymap;
 {
-  Lisp_Object tail, item, table;
+  Lisp_Object tail, item;
+
+  menu_bar_one_keymap_changed_items = Qnil;
 
   /* Loop over all keymap entries that have menu strings.  */
   for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
@@ -5664,6 +5925,7 @@ menu_bar_item (key, item)
 {
   struct gcpro gcpro1;
   int i;
+  Lisp_Object tem;
 
   if (EQ (item, Qundefined))
     {
@@ -5692,6 +5954,15 @@ menu_bar_item (key, item)
   if (!i)
     return;
 
+  /* If this keymap has already contributed to this KEY,
+     don't contribute to it a second time.  */
+  tem = Fmemq (key, menu_bar_one_keymap_changed_items);
+  if (!NILP (tem))
+    return;
+
+  menu_bar_one_keymap_changed_items
+    = Fcons (key, menu_bar_one_keymap_changed_items);
+
   item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
 
   /* Find any existing item for this KEY.  */
@@ -5706,7 +5977,6 @@ menu_bar_item (key, item)
       if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
        {
          Lisp_Object tem;
-         int newsize = 2 * i;
          tem = Fmake_vector (make_number (2 * i), Qnil);
          bcopy (XVECTOR (menu_bar_items_vector)->contents,
                 XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
@@ -5745,7 +6015,7 @@ menu_item_eval_property_1 (arg)
 
 /* Evaluate an expression and return the result (or nil if something 
    went wrong).  Used to evaluate dynamic parts of menu items.  */
-static Lisp_Object
+Lisp_Object
 menu_item_eval_property (sexpr)
      Lisp_Object sexpr;
 {
@@ -5774,12 +6044,16 @@ parse_menu_item (item, notreal, inmenubar)
      int notreal, inmenubar;
 {
   Lisp_Object def, tem, item_string, start;
-  Lisp_Object cachelist = Qnil;
-  Lisp_Object filter = Qnil;
-  Lisp_Object keyhint = Qnil;
+  Lisp_Object cachelist;
+  Lisp_Object filter;
+  Lisp_Object keyhint;
   int i;
   int newcache = 0;
 
+  cachelist = Qnil;
+  filter = Qnil;
+  keyhint = Qnil;
+
   if (!CONSP (item))
     return 0;
 
@@ -5887,7 +6161,7 @@ parse_menu_item (item, notreal, inmenubar)
              else if (EQ (tem, QCkeys))
                {
                  tem = XCONS (item)->car;
-                 if (CONSP (tem) || STRINGP (tem) && NILP (cachelist))
+                 if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
                    XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
                      = tem;
                }
@@ -5955,14 +6229,18 @@ parse_menu_item (item, notreal, inmenubar)
   /* See if this is a separate pane or a submenu.  */
   def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
   tem = get_keymap_1 (def, 0, 1);
+  /* For a subkeymap, just record its details and exit.  */
   if (!NILP (tem))
     {
       XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
       XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
       return 1;
     }
-  else if (inmenubar > 0)
-    return 0;                  /* Entries in menu bar must be submenus.  */
+  /* At the top level in the menu bar, do likewise for commands also.
+     The menu bar does not display equivalent key bindings anyway.
+     ITEM_PROPERTY_DEF is already set up properly.  */
+  if (inmenubar > 0)
+    return 1;
 
   /* This is a command.  See if there is an equivalent key binding. */
   if (NILP (cachelist))
@@ -6018,11 +6296,11 @@ parse_menu_item (item, notreal, inmenubar)
        }
       /* 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)))
+              || (!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)
@@ -6097,6 +6375,392 @@ parse_menu_item (item, notreal, inmenubar)
 
   return 1;
 }
+
+
+\f
+/***********************************************************************
+                              Tool-bars
+ ***********************************************************************/
+
+/* A vector holding tool bar items while they are parsed in function
+   tool_bar_items runs Each item occupies TOOL_BAR_ITEM_NSCLOTS elements
+   in the vector.  */
+
+static Lisp_Object tool_bar_items_vector;
+
+/* A vector holding the result of parse_tool_bar_item.  Layout is like
+   the one for a single item in tool_bar_items_vector.  */
+
+static Lisp_Object tool_bar_item_properties;
+
+/* Next free index in tool_bar_items_vector.  */
+
+static int ntool_bar_items;
+
+/* The symbols `tool-bar', and `:image'.  */
+
+extern Lisp_Object Qtool_bar;
+Lisp_Object QCimage;
+
+/* Function prototypes.  */
+
+static void init_tool_bar_items P_ ((Lisp_Object));
+static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void append_tool_bar_item P_ ((void));
+
+
+/* Return a vector of tool bar items for keymaps currently in effect.
+   Reuse vector REUSE if non-nil.  Return in *NITEMS the number of
+   tool bar items found.  */
+
+Lisp_Object
+tool_bar_items (reuse, nitems)
+     Lisp_Object reuse;
+     int *nitems;
+{
+  Lisp_Object *maps;
+  int nmaps, i;
+  Lisp_Object oquit;
+  Lisp_Object *tmaps;
+  extern Lisp_Object Voverriding_local_map_menu_flag;
+  extern Lisp_Object Voverriding_local_map;
+
+  *nitems = 0;
+
+  /* In order to build the menus, we need to call the keymap
+     accessors.  They all call QUIT.  But this function is called
+     during redisplay, during which a quit is fatal.  So inhibit
+     quitting while building the menus.  We do this instead of
+     specbind because (1) errors will clear it anyway and (2) this
+     avoids risk of specpdl overflow.  */
+  oquit = Vinhibit_quit;
+  Vinhibit_quit = Qt;
+  
+  /* Initialize tool_bar_items_vector and protect it from GC.  */
+  init_tool_bar_items (reuse);
+
+  /* Build list of keymaps in maps.  Set nmaps to the number of maps
+     to process.  */
+  
+  /* Should overriding-terminal-local-map and overriding-local-map apply?  */
+  if (!NILP (Voverriding_local_map_menu_flag))
+    {
+      /* Yes, use them (if non-nil) as well as the global map.  */
+      maps = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+      nmaps = 0;
+      if (!NILP (current_kboard->Voverriding_terminal_local_map))
+       maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+      if (!NILP (Voverriding_local_map))
+       maps[nmaps++] = Voverriding_local_map;
+    }
+  else
+    {
+      /* No, so use major and minor mode keymaps.  */
+      nmaps = current_minor_maps (NULL, &tmaps);
+      maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+#ifdef USE_TEXT_PROPERTIES
+      maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+      maps[nmaps++] = current_buffer->keymap;
+#endif
+    }
+
+  /* Add global keymap at the end.  */
+  maps[nmaps++] = current_global_map;
+
+  /* Process maps in reverse order and look up in each map the prefix
+     key `tool-bar'.  */
+  for (i = nmaps - 1; i >= 0; --i)
+    if (!NILP (maps[i]))
+      {
+       Lisp_Object keymap;
+      
+       keymap = get_keyelt (access_keymap (maps[i], Qtool_bar, 1, 1), 0);
+       if (!NILP (Fkeymapp (keymap)))
+         {
+           Lisp_Object tail;
+           
+           /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'.  */
+           for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+             {
+               Lisp_Object keydef = XCAR (tail);
+               if (CONSP (keydef))
+                 process_tool_bar_item (XCAR (keydef), XCDR (keydef));
+             }
+         }
+      }
+
+  Vinhibit_quit = oquit;
+  *nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+  return tool_bar_items_vector;
+}
+
+
+/* Process the definition of KEY which is DEF.  */
+
+static void
+process_tool_bar_item (key, def)
+     Lisp_Object key, def;
+{
+  int i;
+  extern Lisp_Object Qundefined;
+  struct gcpro gcpro1, gcpro2;
+
+  /* Protect KEY and DEF from GC because parse_tool_bar_item may call
+     eval.  */
+  GCPRO2 (key, def);
+
+  if (EQ (def, Qundefined))
+    {
+      /* If a map has an explicit `undefined' as definition,
+        discard any previously made item.  */
+      for (i = 0; i < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS)
+       {
+         Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i;
+         
+         if (EQ (key, v[TOOL_BAR_ITEM_KEY]))
+           {
+             if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS)
+               bcopy (v + TOOL_BAR_ITEM_NSLOTS, v,
+                      ((ntool_bar_items - i - TOOL_BAR_ITEM_NSLOTS)
+                       * sizeof (Lisp_Object)));
+             ntool_bar_items -= TOOL_BAR_ITEM_NSLOTS;
+             break;
+           }
+       }
+    }
+  else if (parse_tool_bar_item (key, def))
+    /* Append a new tool bar item to tool_bar_items_vector.  Accept
+       more than one definition for the same key.  */
+    append_tool_bar_item ();
+
+  UNGCPRO;
+}
+
+
+/* Parse a tool bar item specification ITEM for key KEY and return the
+   result in tool_bar_item_properties.  Value is zero if ITEM is
+   invalid.
+
+   ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
+   
+   CAPTION is the caption of the item,  If it's not a string, it is
+   evaluated to get a string.
+   
+   BINDING is the tool bar item's binding.  Tool-bar items with keymaps
+   as binding are currently ignored.
+
+   The following properties are recognized:
+
+   - `:enable FORM'.
+   
+   FORM is evaluated and specifies whether the tool bar item is
+   enabled or disabled.
+   
+   - `:visible FORM'
+   
+   FORM is evaluated and specifies whether the tool bar item is visible.
+   
+   - `:filter FUNCTION'
+
+   FUNCTION is invoked with one parameter `(quote BINDING)'.  Its
+   result is stored as the new binding.
+   
+   - `:button (TYPE SELECTED)'
+
+   TYPE must be one of `:radio' or `:toggle'.  SELECTED is evaluated
+   and specifies whether the button is selected (pressed) or not.
+   
+   - `:image IMAGES'
+
+   IMAGES is either a single image specification or a vector of four
+   image specifications.  See enum tool_bar_item_images.
+   
+   - `:help HELP-STRING'.
+   
+   Gives a help string to display for the tool bar item.  */
+
+static int
+parse_tool_bar_item (key, item)
+     Lisp_Object key, item;
+{
+  /* Access slot with index IDX of vector tool_bar_item_properties.  */
+#define PROP(IDX) XVECTOR (tool_bar_item_properties)->contents[IDX]
+
+  Lisp_Object filter = Qnil;
+  Lisp_Object caption;
+  extern Lisp_Object QCenable, QCvisible, QChelp, QCfilter;
+  extern Lisp_Object QCbutton, QCtoggle, QCradio;
+  int i;
+
+  /* Defininition looks like `(tool-bar-item CAPTION BINDING
+     PROPS...)'.  Rule out items that aren't lists, don't start with
+     `tool-bar-item' or whose rest following `tool-bar-item' is not a
+     list.  */
+  if (!CONSP (item)
+      || !EQ (XCAR (item), Qmenu_item)
+      || (item = XCDR (item),
+         !CONSP (item)))
+    return 0;
+
+  /* Create tool_bar_item_properties vector if necessary.  Reset it to
+     defaults.  */
+  if (VECTORP (tool_bar_item_properties))
+    {
+      for (i = 0; i < TOOL_BAR_ITEM_NSLOTS; ++i)
+       PROP (i) = Qnil;
+    }
+  else
+    tool_bar_item_properties
+      = Fmake_vector (make_number (TOOL_BAR_ITEM_NSLOTS), Qnil);
+  
+  /* Set defaults.  */
+  PROP (TOOL_BAR_ITEM_KEY) = key;
+  PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt;
+        
+  /* Get the caption of the item.  If the caption is not a string,
+     evaluate it to get a string.  If we don't get a string, skip this
+     item.  */
+  caption = XCAR (item);
+  if (!STRINGP (caption))
+    {
+      caption = menu_item_eval_property (caption);
+      if (!STRINGP (caption))
+       return 0;
+    }
+  PROP (TOOL_BAR_ITEM_CAPTION) = caption;
+
+  /* Give up if rest following the caption is not a list.  */
+  item = XCDR (item);
+  if (!CONSP (item))
+    return 0;
+
+  /* Store the binding.  */
+  PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
+  item = XCDR (item);
+
+  /* Process the rest of the properties.  */
+  for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
+    {
+      Lisp_Object key, value;
+
+      key = XCAR (item);
+      value = XCAR (XCDR (item));
+
+      if (EQ (key, QCenable))
+       /* `:enable FORM'.  */
+       PROP (TOOL_BAR_ITEM_ENABLED_P) = value;
+      else if (EQ (key, QCvisible))
+       {
+         /* `:visible FORM'.  If got a visible property and that
+            evaluates to nil then ignore this item.  */
+         if (NILP (menu_item_eval_property (value)))
+           return 0;
+       }
+      else if (EQ (key, QChelp))
+       /* `:help HELP-STRING'.  */
+       PROP (TOOL_BAR_ITEM_HELP) = value;
+      else if (EQ (key, QCfilter))
+       /* ':filter FORM'.  */
+       filter = value;
+      else if (EQ (key, QCbutton) && CONSP (value))
+       {
+         /* `:button (TYPE . SELECTED)'.  */
+         Lisp_Object type, selected;
+
+         type = XCAR (value);
+         selected = XCDR (value);
+         if (EQ (type, QCtoggle) || EQ (type, QCradio))
+           {
+             PROP (TOOL_BAR_ITEM_SELECTED_P) = selected;
+             PROP (TOOL_BAR_ITEM_TYPE) = type;
+           }
+       }
+      else if (EQ (key, QCimage)
+              && (CONSP (value)
+                  || (VECTORP (value) && XVECTOR (value)->size == 4)))
+       /* Value is either a single image specification or a vector
+          of 4 such specifications for the different buttion states.  */
+       PROP (TOOL_BAR_ITEM_IMAGES) = value;
+    }
+
+  /* If got a filter apply it on binding.  */
+  if (!NILP (filter))
+    PROP (TOOL_BAR_ITEM_BINDING)
+      = menu_item_eval_property (list2 (filter,
+                                       list2 (Qquote,
+                                              PROP (TOOL_BAR_ITEM_BINDING))));
+
+  /* See if the binding is a keymap.  Give up if it is.  */
+  if (!NILP (get_keymap_1 (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
+    return 0;
+
+  /* Enable or disable selection of item.  */
+  if (!EQ (PROP (TOOL_BAR_ITEM_ENABLED_P), Qt))
+    PROP (TOOL_BAR_ITEM_ENABLED_P)
+      = menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P));
+
+  /* Handle radio buttons or toggle boxes.  */ 
+  if (!NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)))
+    PROP (TOOL_BAR_ITEM_SELECTED_P)
+      = menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P));
+
+  return 1;
+  
+#undef PROP
+}
+
+
+/* Initialize tool_bar_items_vector.  REUSE, if non-nil, is a vector
+   that can be reused.  */
+
+static void
+init_tool_bar_items (reuse)
+     Lisp_Object reuse;
+{
+  if (VECTORP (reuse))
+    tool_bar_items_vector = reuse;
+  else
+    tool_bar_items_vector = Fmake_vector (make_number (64), Qnil);
+  ntool_bar_items = 0;
+}
+
+
+/* Append parsed tool bar item properties from
+   tool_bar_item_properties */
+
+static void
+append_tool_bar_item ()
+{
+  Lisp_Object *to, *from;
+  
+  /* Enlarge tool_bar_items_vector if necessary.  */
+  if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS
+      >= XVECTOR (tool_bar_items_vector)->size)
+    {
+      Lisp_Object new_vector;
+      int old_size = XVECTOR (tool_bar_items_vector)->size;
+
+      new_vector = Fmake_vector (make_number (2 * old_size), Qnil);
+      bcopy (XVECTOR (tool_bar_items_vector)->contents,
+            XVECTOR (new_vector)->contents,
+            old_size * sizeof (Lisp_Object));
+      tool_bar_items_vector = new_vector;
+    }
+
+  /* Append entries from tool_bar_item_properties to the end of
+     tool_bar_items_vector.  */
+  to = XVECTOR (tool_bar_items_vector)->contents + ntool_bar_items;
+  from = XVECTOR (tool_bar_item_properties)->contents;
+  bcopy (from, to, TOOL_BAR_ITEM_NSLOTS * sizeof *to);
+  ntool_bar_items += TOOL_BAR_ITEM_NSLOTS;
+}
+
+
+
+
 \f
 /* Read a character using menus based on maps in the array MAPS.
    NMAPS is the length of MAPS.  Return nil if there are no menus in the maps.
@@ -6127,7 +6791,6 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
 {
   int mapno;
   register Lisp_Object name;
-  Lisp_Object rest, vector;
 
   if (used_mouse_menu)
     *used_mouse_menu = 0;
@@ -6160,7 +6823,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
   if (EVENT_HAS_PARAMETERS (prev_event)
-      && !EQ (XCONS (prev_event)->car, Qmenu_bar))
+      && !EQ (XCONS (prev_event)->car, Qmenu_bar)
+      && !EQ (XCONS (prev_event)->car, Qtool_bar))
     {
       /* Display the menu and get the selection.  */
       Lisp_Object *realmaps
@@ -6230,7 +6894,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   int mapno;
   register Lisp_Object name;
   int nlength;
-  int width = FRAME_WIDTH (selected_frame) - 4;
+  int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
@@ -6685,7 +7349,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int prev_keytran_start;
   int prev_keytran_end;
 
+#if defined (GOBBLE_FIRST_EVENT)
   int junk;
+#endif
 
   raw_keybuf_count = 0;
 
@@ -6733,10 +7399,6 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
   orig_local_map = get_local_map (PT, current_buffer);
 
-  /* Bind input-method-function so that we can set it to nil
-     temporarily after the first input event.  */
-  specbind (Qinput_method_function, Vinput_method_function);
-
   /* We jump here when the key sequence has been thoroughly changed, and
      we need to rescan it starting from the beginning.  When we jump here,
      keybuf[0..mock_input] holds the sequence we should reread.  */
@@ -6868,12 +7530,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       /* If not, we should actually read a character.  */
       else
        {
-         struct buffer *buf = current_buffer;
-
          {
 #ifdef MULTI_KBOARD
            KBOARD *interrupted_kboard = current_kboard;
-           struct frame *interrupted_frame = selected_frame;
+           struct frame *interrupted_frame = SELECTED_FRAME ();
            if (setjmp (wrong_kboard_jmpbuf))
              {
                if (!NILP (delayed_switch_frame))
@@ -6908,9 +7568,6 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 #endif
            key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
                             &used_mouse_menu);
-
-           /* Turn off input methods after a prefix character.  */
-           Vinput_method_function = Qnil;
          }
 
          /* read_char returns t when it shows a menu and the user rejects it.
@@ -6943,8 +7600,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                 This is to be more consistent with the behavior
                 of the command_loop_1.  */
              if (fix_current_buffer)
-               if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
-                 Fset_buffer (XWINDOW (selected_window)->buffer);
+               {
+                 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+                   Fkill_emacs (Qnil);
+                 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+                   Fset_buffer (XWINDOW (selected_window)->buffer);
+               }
 
              orig_local_map = get_local_map (PT, current_buffer);
              goto replay_sequence;
@@ -7008,6 +7669,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              window = POSN_WINDOW      (EVENT_START (key));
              posn   = POSN_BUFFER_POSN (EVENT_START (key));
+
              if (CONSP (posn))
                {
                  /* We're looking at the second event of a
@@ -7042,19 +7704,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                     emacsclient).  */
                  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
 
+                 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+                   Fkill_emacs (Qnil);
                  set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
                  orig_local_map = get_local_map (PT, current_buffer);
                  goto replay_sequence;
                }
+             
              /* For a mouse click, get the local text-property keymap
                 of the place clicked on, rather than point.  */
-             if (last_real_key_start == 0 && CONSP (XCONS (key)->cdr)
+             if (last_real_key_start == 0
+                 && CONSP (XCONS (key)->cdr)
                  && ! localized_local_map)
                {
                  Lisp_Object map_here, start, pos;
 
                  localized_local_map = 1;
                  start = EVENT_START (key);
+                 
                  if (CONSP (start) && CONSP (XCONS (start)->cdr))
                    {
                      pos = POSN_BUFFER_POSN (start);
@@ -7083,11 +7750,33 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
                  mock_input = t + 2;
-
+                 
                  /* Zap the position in key, so we know that we've
                     expanded it, and don't try to do so again.  */
                  POSN_BUFFER_POSN (EVENT_START (key))
                    = Fcons (posn, Qnil);
+
+                 /* If on a mode line string with a local keymap,
+                    reconsider the key sequence with that keymap.  */
+                 if (CONSP (POSN_STRING (EVENT_START (key))))
+                   {
+                     Lisp_Object string, pos, map;
+
+                     string = POSN_STRING (EVENT_START (key));
+                     pos = XCDR (string);
+                     string = XCAR (string);
+                     
+                     if (pos >= 0
+                         && pos < XSTRING (string)->size
+                         && (map = Fget_text_property (pos, Qlocal_map,
+                                                       string),
+                             !NILP (map)))
+                       {
+                         orig_local_map = map;
+                         goto replay_sequence;
+                       }
+                   }
+
                  goto replay_key;
                }
            }
@@ -7100,7 +7789,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              posn = POSN_BUFFER_POSN (EVENT_START (key));
              /* Handle menu-bar events:
                 insert the dummy prefix event `menu-bar'.  */
-             if (EQ (posn, Qmenu_bar))
+             if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
                {
                  if (t + 1 >= bufsize)
                    error ("Key sequence too long");
@@ -7305,7 +7994,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                fkey_next = fkey_map;
 
              fkey_next
-               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 0);
+               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 1);
+
+             /* Handle symbol with autoload definition.  */
+             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+                 && CONSP (XSYMBOL (fkey_next)->function)
+                 && EQ (XCONS (XSYMBOL (fkey_next)->function)->car, Qautoload))
+               do_autoload (XSYMBOL (fkey_next)->function,
+                            fkey_next);
+
+             /* Handle a symbol whose function definition is a keymap
+                or an array.  */
+             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+                 && (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
+                     || !NILP (Fkeymapp (XSYMBOL (fkey_next)->function))))
+               fkey_next = XSYMBOL (fkey_next)->function;
 
 #if 0 /* I didn't turn this on, because it might cause trouble
         for the mapping of return into C-m and tab into C-i.  */
@@ -7368,8 +8071,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  fkey_start = fkey_end = t;
                  fkey_map = Vfunction_key_map;
 
-                 /* Do pass the results through key-translation-map.  */
-                 keytran_start = keytran_end = 0;
+                 /* Do pass the results through key-translation-map.
+                    But don't retranslate what key-translation-map
+                    has already translated.  */
+                 keytran_end = keytran_start;
                  keytran_map = Vkey_translation_map;
 
                  goto replay_sequence;
@@ -7413,10 +8118,24 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              keytran_next = keytran_map;
 
            keytran_next
-             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 0);
+             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 1);
 
+           /* Handle symbol with autoload definition.  */
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+               && CONSP (XSYMBOL (keytran_next)->function)
+               && EQ (XCONS (XSYMBOL (keytran_next)->function)->car, Qautoload))
+             do_autoload (XSYMBOL (keytran_next)->function,
+                          keytran_next);
+
+           /* Handle a symbol whose function definition is a keymap
+              or an array.  */
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+               && (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
+                   || !NILP (Fkeymapp (XSYMBOL (keytran_next)->function))))
+             keytran_next = XSYMBOL (keytran_next)->function;
+           
            /* If the key translation map gives a function, not an
-              array, then call the function with no args and use
+              array, then call the function with one arg and use
               its value instead.  */
            if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
                && keytran_end == t)
@@ -7471,7 +8190,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                /* Don't pass the results of key-translation-map
                   through function-key-map.  */
                fkey_start = fkey_end = t;
-               fkey_map = Vkey_translation_map;
+               fkey_map = Vfunction_key_map;
 
                goto replay_sequence;
              }
@@ -7652,7 +8371,7 @@ The optional fifth argument COMMAND-LOOP, if non-nil, means\n\
 that this key sequence is being read by something that will\n\
 read commands one after another.  It should be nil if the caller\n\
 will read just one key sequence.")
-  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+  (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
 #endif
 
 DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
@@ -7664,7 +8383,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
 {
   Lisp_Object keybuf[30];
   register int i;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
   int count = specpdl_ptr - specpdl;
 
   if (!NILP (prompt))
@@ -7709,7 +8428,7 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
 {
   Lisp_Object keybuf[30];
   register int i;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
   int count = specpdl_ptr - specpdl;
 
   if (!NILP (prompt))
@@ -7868,7 +8587,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
       if (sizeof (int) == sizeof (EMACS_INT))
        sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car));
       else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", XINT (XCONS (prefixarg)->car));
+       sprintf (buf, "%ld ", (long) XINT (XCONS (prefixarg)->car));
       else
        abort ();
     }
@@ -7877,7 +8596,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
       if (sizeof (int) == sizeof (EMACS_INT))
        sprintf (buf, "%d ", XINT (prefixarg));
       else if (sizeof (long) == sizeof (EMACS_INT))
-       sprintf (buf, "%ld ", XINT (prefixarg));
+       sprintf (buf, "%ld ", (long) XINT (prefixarg));
       else
        abort ();
     }
@@ -7947,7 +8666,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     {
       /* But first wait, and skip the message if there is input.  */
       int delay_time;
-      if (echo_area_glyphs != 0)
+      if (!NILP (echo_area_buffer[0]))
        /* This command displayed something in the echo area;
           so wait a few seconds, then display our suggestion message.  */
        delay_time = (NUMBERP (Vsuggest_key_bindings)
@@ -7962,9 +8681,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
        {
          Lisp_Object binding;
          char *newmessage;
-         char *oldmessage = echo_area_glyphs;
-         int oldmessage_len = echo_area_glyphs_length;
-         int oldmultibyte = message_enable_multibyte;
+         int message_p = push_message ();
 
          binding = Fkey_description (bindings);
 
@@ -7980,8 +8697,11 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                          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);
+                              Qnil, Qnil))
+             && message_p)
+           restore_message ();
+
+         pop_message ();
        }
     }
 
@@ -8052,7 +8772,16 @@ detect_input_pending_run_timers (do_display)
     get_input_pending (&input_pending, 1);
 
   if (old_timers_run != timers_run && do_display)
-    redisplay_preserve_echo_area ();
+    {
+      redisplay_preserve_echo_area ();
+      /* The following fixes a bug when using lazy-lock with
+        lazy-lock-defer-on-the-fly set to t, i.e.  when fontifying
+        from an idle timer function.  The symptom of the bug is that
+        the cursor sometimes doesn't become visible until the next X
+        event is processed.  --gerd.  */
+      if (rif)
+       rif->flush_display (NULL);
+    }
 
   return input_pending;
 }
@@ -8175,6 +8904,16 @@ appears in the echo area and in the value of `this-command-keys.'.")
   before_command_restore_flag = 1;
   before_command_key_count_1 = before_command_key_count;
   before_command_echo_length_1 = before_command_echo_length;
+  return Qnil;
+}
+
+DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
+  Sclear_this_command_keys, 0, 0, 0,
+  "Clear out the vector that `this-command-keys' returns.")
+  ()
+{
+  this_command_key_count = 0;
+  return Qnil;
 }
 
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
@@ -8221,10 +8960,7 @@ Also cancel any kbd macro being defined.")
 
   discard_tty_input ();
 
-  /* Without the cast, GCC complains that this assignment loses the
-     volatile qualifier of kbd_store_ptr.  Is there anything wrong
-     with that?  */
-  kbd_fetch_ptr = (struct input_event *) kbd_store_ptr;
+  kbd_fetch_ptr =  kbd_store_ptr;
   Ffillarray (kbd_buffer_frame_or_window, Qnil);
   input_pending = 0;
 
@@ -8246,11 +8982,10 @@ On such systems, Emacs starts a subshell instead of suspending.")
   (stuffstring)
      Lisp_Object stuffstring;
 {
-  Lisp_Object tem;
   int count = specpdl_ptr - specpdl;
   int old_height, old_width;
   int width, height;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1;
 
   if (!NILP (stuffstring))
     CHECK_STRING (stuffstring, 0);
@@ -8278,7 +9013,7 @@ On such systems, Emacs starts a subshell instead of suspending.")
      with a window system; but suspend should be disabled in that case.  */
   get_frame_size (&width, &height);
   if (width != old_width || height != old_height)
-    change_frame_size (selected_frame, height, width, 0, 0);
+    change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);
 
   /* Run suspend-resume-hook.  */
   if (!NILP (Vrun_hooks))
@@ -8371,6 +9106,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   char c;
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
+  struct frame *sf = SELECTED_FRAME ();
 
 #if defined (USG) && !defined (POSIX_SIGNALS)
   if (!read_socket_hook && NILP (Vwindow_system))
@@ -8385,7 +9121,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   cancel_echoing ();
 
   if (!NILP (Vquit_flag)
-      && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
+      && (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)))
     {
       /* If SIGINT isn't blocked, don't let us be interrupted by
         another SIGINT, it might be harmful due to non-reentrancy
@@ -8510,7 +9246,6 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
 void
 quit_throw_to_read_char ()
 {
-  quit_error_check ();
   sigfree ();
   /* Prevent another signal from doing this before we finish.  */
   clear_waiting_for_input ();
@@ -8529,7 +9264,7 @@ quit_throw_to_read_char ()
 #endif
 #endif
   if (FRAMEP (internal_last_event_frame)
-      && XFRAME (internal_last_event_frame) != selected_frame)
+      && !EQ (internal_last_event_frame, selected_frame))
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     Qnil, 0);
 
@@ -8788,9 +9523,21 @@ struct event_head head_table[] = {
 void
 syms_of_keyboard ()
 {
+  /* Tool-bars.  */
+  QCimage = intern (":image");
+  staticpro (&QCimage);
+
+  staticpro (&Qhelp_echo);
+  Qhelp_echo = intern ("help-echo");
+
   staticpro (&item_properties);
   item_properties = Qnil;
 
+  staticpro (&tool_bar_item_properties);
+  tool_bar_item_properties = Qnil;
+  staticpro (&tool_bar_items_vector);
+  tool_bar_items_vector = Qnil;
+
   staticpro (&real_this_command);
   real_this_command = Qnil;
 
@@ -8837,10 +9584,17 @@ syms_of_keyboard ()
 #ifdef WINDOWSNT
   Qmouse_wheel = intern ("mouse-wheel");
   staticpro (&Qmouse_wheel);
+  Qlanguage_change = intern ("language-change");
+  staticpro (&Qlanguage_change);
 #endif
   Qdrag_n_drop = intern ("drag-n-drop");
   staticpro (&Qdrag_n_drop);
 
+  Qusr1_signal = intern ("usr1-signal");
+  staticpro (&Qusr1_signal);
+  Qusr2_signal = intern ("usr2-signal");
+  staticpro (&Qusr2_signal);
+
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
   Qmenu_alias = intern ("menu-alias");
@@ -8849,6 +9603,8 @@ syms_of_keyboard ()
   staticpro (&QCenable);
   QCvisible = intern (":visible");
   staticpro (&QCvisible);
+  QChelp = intern (":help");
+  staticpro (&QChelp);
   QCfilter = intern (":filter");
   staticpro (&QCfilter);
   QCbutton = intern (":button");
@@ -8881,6 +9637,12 @@ syms_of_keyboard ()
   staticpro (&Qup);
   Qdown = intern ("down");
   staticpro (&Qdown);
+  Qtop = intern ("top");
+  staticpro (&Qtop);
+  Qbottom = intern ("bottom");
+  staticpro (&Qbottom);
+  Qend_scroll = intern ("end-scroll");
+  staticpro (&Qend_scroll);
 
   Qevent_kind = intern ("event-kind");
   staticpro (&Qevent_kind);
@@ -8981,6 +9743,9 @@ syms_of_keyboard ()
   read_key_sequence_cmd = Qnil;
   staticpro (&read_key_sequence_cmd);
 
+  menu_bar_one_keymap_changed_items = Qnil;
+  staticpro (&menu_bar_one_keymap_changed_items);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
@@ -8996,6 +9761,7 @@ syms_of_keyboard ()
   defsubr (&Sthis_single_command_keys);
   defsubr (&Sthis_single_command_raw_keys);
   defsubr (&Sreset_this_command_lengths);
+  defsubr (&Sclear_this_command_keys);
   defsubr (&Ssuspend_emacs);
   defsubr (&Sabort_recursive_edit);
   defsubr (&Sexit_recursive_edit);
@@ -9046,14 +9812,15 @@ before actual keyboard input.");
   Vunread_input_method_events = Qnil;
 
   DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
-    "Meta-prefix character code.  Meta-foo as command input\n\
-turns into this character followed by foo.");
+    "Meta-prefix character code.\n\
+Meta-foo as command input turns into this character followed by foo.");
   XSETINT (meta_prefix_char, 033);
 
   DEFVAR_KBOARD ("last-command", Vlast_command,
-    "The last command executed.  Normally a symbol with a function definition,\n\
-but can be whatever was found in the keymap, or whatever the variable\n\
-`this-command' was set to by that command.\n\
+    "The last command executed.\n\
+Normally a symbol with a function definition, but can be whatever was found\n\
+in the keymap, or whatever the variable `this-command' was set to by that\n\
+command.\n\
 \n\
 The value `mode-exit' is special; it means that the previous command\n\
 read an event that told it to exit, and it did so and unread that event.\n\
@@ -9073,7 +9840,7 @@ will be in `last-command' during the following command.");
   Vthis_command = Qnil;
 
   DEFVAR_INT ("auto-save-interval", &auto_save_interval,
-    "*Number of keyboard input characters between auto-saves.\n\
+    "*Number of input events between auto-saves.\n\
 Zero means disable autosaving due to number of characters typed.");
   auto_save_interval = 300;
 
@@ -9164,8 +9931,8 @@ In a vector or a char-table, an element which is nil means \"no translation\".")
   Vkeyboard_translate_table = Qnil;
 
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
-    "Non-nil means to always spawn a subshell instead of suspending,\n\
-even if the operating system has support for stopping a process.");
+    "Non-nil means to always spawn a subshell instead of suspending.\n\
+\(Even if the operating system has support for stopping a process.\)");
   cannot_suspend = 0;
 
   DEFVAR_BOOL ("menu-prompting", &menu_prompting,
@@ -9209,12 +9976,16 @@ Buffer modification stores t in this variable.");
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
     "Normal hook run before each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
     "Normal hook run after each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
   Vpost_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
@@ -9325,10 +10096,15 @@ for guidance on what to do.");
 
   DEFVAR_LISP ("input-method-previous-message",
               &Vinput_method_previous_message,
-              "When `input-mehod-function' is called, hold the previous echo area message.\n\
+    "When `input-method-function' is called, hold the previous echo area message.\n\
 This variable exists because `read-event' clears the echo area\n\
 before running the input method.  It is nil if there was no message.");
   Vinput_method_previous_message = Qnil;
+
+  DEFVAR_LISP ("show-help-function", &Vshow_help_function,
+    "If non-nil, the function that implements the display of help.\n\
+It's called with one argument, the help string to display.");
+  Vshow_help_function = Qnil;
 }
 
 void