(Fredirect_frame_focus): Don't call Ffocus_frame.
[bpt/emacs.git] / src / xdisp.c
index 6fb7a30..532d548 100644 (file)
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <config.h>
@@ -34,9 +35,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "disptab.h"
 #include "termhooks.h"
 #include "intervals.h"
+#include "keyboard.h"
 
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
 extern void set_frame_menubar ();
+extern int pending_menu_activation;
 #endif
 
 extern int interrupt_input;
@@ -44,6 +47,13 @@ extern int command_loop_level;
 
 extern Lisp_Object Qface;
 
+extern Lisp_Object Voverriding_local_map;
+extern Lisp_Object Voverriding_local_map_menu_flag;
+
+Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
+Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
+Lisp_Object Qredisplay_end_trigger_functions;
+
 /* Nonzero means print newline to stdout before next minibuffer message.  */
 
 int noninteractive_need_newline;
@@ -150,6 +160,7 @@ static int debug_end_pos;
 /* Nonzero means display mode line highlighted */
 int mode_line_inverse_video;
 
+static void redisplay_internal ();
 static int message_log_check_duplicate ();
 static void echo_area_display ();
 void mark_window_display_accurate ();
@@ -181,6 +192,11 @@ char *echo_area_glyphs;
 /* This is the length of the message in echo_area_glyphs.  */
 int echo_area_glyphs_length;
 
+/* This is the window where the echo area message was displayed.
+   It is always a minibuffer window, but it may not be the
+   same window currently active as a minibuffer.  */
+Lisp_Object echo_area_window;
+
 /* true iff we should redraw the mode lines on the next redisplay */
 int update_mode_lines;
 
@@ -199,10 +215,6 @@ int end_unchanged;
    contain no useful information */
 int unchanged_modified;
 
-/* Nonzero if head_clip or tail_clip of current buffer has changed
-   since last redisplay that finished */
-int clip_changed;
-
 /* Nonzero if window sizes or contents have changed
    since last redisplay that finished */
 int windows_or_buffers_changed;
@@ -218,6 +230,8 @@ static int line_number_display_limit;
    t means infinite.  nil means don't log at all.  */
 Lisp_Object Vmessage_log_max;
 \f
+/* Output a newline in the *Messages* buffer if "needs" one.  */
+
 void
 message_log_maybe_newline ()
 {
@@ -239,6 +253,7 @@ message_dolog (m, len, nlflag)
     {
       struct buffer *oldbuf;
       int oldpoint, oldbegv, oldzv;
+      int old_windows_or_buffers_changed = windows_or_buffers_changed;
 
       oldbuf = current_buffer;
       Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
@@ -307,11 +322,11 @@ message_dolog (m, len, nlflag)
       ZV = oldzv;
       TEMP_SET_PT (oldpoint);
       set_buffer_internal (oldbuf);
+      windows_or_buffers_changed = old_windows_or_buffers_changed;
       message_log_need_newline = !nlflag;
     }
 }
 
-
 /* We are at the end of the buffer after just having inserted a newline.
    (Note: We depend on the fact we won't be crossing the gap.)
    Check to see if the most recent message looks a lot like the previous one.
@@ -349,11 +364,16 @@ message_log_check_duplicate (prev_bol, this_bol)
     }
   return 0;
 }
-
+\f
 /* Display an echo area message M with a specified length of LEN chars.
-   The string may include null characters.  If m is 0, clear out any
+   The string may include null characters.  If M is 0, clear out any
    existing message, and let the minibuffer text show through.
-   Do not pass text that is stored in a Lisp string.  */
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message2 (m, len)
@@ -368,7 +388,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -390,16 +410,18 @@ message2_nolog (m, len)
      cmd_error, so this must be just an informative message; toss it.  */
   else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
     {
-#ifdef MULTI_FRAME
-      Lisp_Object minibuf_frame;
+      Lisp_Object mini_window;
+      FRAME_PTR f;
 
-      choose_minibuf_frame ();
-      minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
-      FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
+      /* Get the frame containing the minibuffer
+        that the selected frame is using.  */
+      mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
+      f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+
+      FRAME_SAMPLE_VISIBILITY (f);
       if (FRAME_VISIBLE_P (selected_frame)
-         && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
-       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
-#endif
+         && ! FRAME_VISIBLE_P (f))
+       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
 
       if (m)
        {
@@ -411,12 +433,21 @@ message2_nolog (m, len)
 
       do_pending_window_change ();
       echo_area_display ();
-      update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
+      update_frame (f, 1, 1);
       do_pending_window_change ();
       if (frame_up_to_date_hook != 0 && ! gc_in_progress)
-       (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
+       (*frame_up_to_date_hook) (f);
     }
 }
+\f
+/* Display a null-terminated echo area message M.  If M is 0, clear out any
+   existing message, and let the minibuffer text show through.
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message1 (m)
@@ -450,8 +481,9 @@ truncate_echo_area (len)
    zero if being used by message.  */
 int message_buf_print;
 
-/* Dump an informative message to the minibuf.  If m is 0, clear out
+/* Dump an informative message to the minibuf.  If M is 0, clear out
    any existing message, and let the minibuffer text show through.  */
+
 /* VARARGS 1 */
 void
 message (m, a1, a2, a3)
@@ -476,18 +508,18 @@ message (m, a1, a2, a3)
       /* The frame whose minibuffer we're going to display the message on.
         It may be larger than the selected frame, so we need
         to use its buffer, not the selected frame's buffer.  */
-      FRAME_PTR echo_frame;
-#ifdef MULTI_FRAME
-      choose_minibuf_frame ();
-      echo_frame = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
-#else
-      echo_frame = selected_frame;
-#endif
+      Lisp_Object mini_window;
+      FRAME_PTR f;
+
+      /* Get the frame containing the minibuffer
+        that the selected frame is using.  */
+      mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
+      f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
       /* A null message buffer means that the frame hasn't really been
         initialized yet.  Error messages get reported properly by
         cmd_error, so this must be just an informative message; toss it.  */
-      if (FRAME_MESSAGE_BUF (echo_frame))
+      if (FRAME_MESSAGE_BUF (f))
        {
          if (m)
            {
@@ -498,14 +530,14 @@ message (m, a1, a2, a3)
              a[1] = a2;
              a[2] = a3;
 
-             len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
-                           FRAME_WIDTH (echo_frame), m, (char *)0, 3, a);
+             len = doprnt (FRAME_MESSAGE_BUF (f),
+                           (int) FRAME_WIDTH (f), m, (char *)0, 3, a);
 #else
-             len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
-                           FRAME_WIDTH (echo_frame), m, (char *)0, 3, &a1);
+             len = doprnt (FRAME_MESSAGE_BUF (f),
+                           (int) FRAME_WIDTH (f), m, (char *)0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
 
-             message2 (FRAME_MESSAGE_BUF (echo_frame), len);
+             message2 (FRAME_MESSAGE_BUF (f), len);
            }
          else
            message1 (0);
@@ -517,7 +549,7 @@ message (m, a1, a2, a3)
     }
 }
 
-/* The non-logging version of that function.  */
+/* The non-logging version of message.  */
 void
 message_nolog (m, a1, a2, a3)
      char *m;
@@ -535,18 +567,19 @@ update_echo_area ()
 {
   message2 (echo_area_glyphs, echo_area_glyphs_length);
 }
-
+\f
 static void
 echo_area_display ()
 {
   register int vpos;
   FRAME_PTR f;
+  Lisp_Object mini_window;
 
-#ifdef MULTI_FRAME
-  choose_minibuf_frame ();
-#endif
-
-  f = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
+  /* Choose the minibuffer window for this display.
+     It is the minibuffer window used by the selected frame.  */
+  mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
+  /* This is the frame that window is in.  */
+  f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
   if (! FRAME_VISIBLE_P (f))
     return;
@@ -559,42 +592,48 @@ echo_area_display ()
 
   if (echo_area_glyphs || minibuf_level == 0)
     {
-      vpos = XFASTINT (XWINDOW (minibuf_window)->top);
+      echo_area_window = mini_window;
+
+      vpos = XFASTINT (XWINDOW (mini_window)->top);
       get_display_line (f, vpos, 0);
-      display_string (XWINDOW (minibuf_window), vpos,
+      display_string (XWINDOW (mini_window), vpos,
                      echo_area_glyphs ? echo_area_glyphs : "",
                      echo_area_glyphs ? echo_area_glyphs_length : -1,
                      0, 0, 0, 0, FRAME_WIDTH (f));
 
+#if 0 /* This just gets in the way.  update_frame does the job.  */
       /* If desired cursor location is on this line, put it at end of text */
       if (cursor_in_echo_area)
        FRAME_CURSOR_Y (f) = vpos;
       if (FRAME_CURSOR_Y (f) == vpos)
        FRAME_CURSOR_X (f) = FRAME_DESIRED_GLYPHS (f)->used[vpos];
+#endif
 
       /* Fill the rest of the minibuffer window with blank lines.  */
       {
        int i;
 
        for (i = vpos + 1;
-            i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
+            i < vpos + XFASTINT (XWINDOW (mini_window)->height); i++)
          {
            get_display_line (f, i, 0);
-           display_string (XWINDOW (minibuf_window), vpos,
+           display_string (XWINDOW (mini_window), vpos,
                            "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
          }
       }
     }
-  else if (!EQ (minibuf_window, selected_window))
+  else if (!EQ (mini_window, selected_window))
     windows_or_buffers_changed++;
 
-  if (EQ (minibuf_window, selected_window))
+  if (EQ (mini_window, selected_window))
     this_line_bufpos = 0;
 
   previous_echo_glyphs = echo_area_glyphs;
 }
+\f
+/* Update frame titles.  */
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 static char frame_title_buf[512];
 static char *frame_title_ptr;
 
@@ -623,7 +662,7 @@ x_consider_frame_title (frame)
   int len;
   FRAME_PTR f = XFRAME (frame);
 
-  if (!FRAME_X_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name)
+  if (!(FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name))
     return;
 
   /* Do we have more than one visible frame on this X display?  */
@@ -676,7 +715,7 @@ prepare_menu_bars ()
   struct gcpro gcpro1, gcpro2;
 
   all_windows = (update_mode_lines || buffer_shared > 1
-                || clip_changed || windows_or_buffers_changed);
+                || windows_or_buffers_changed);
 
   /* Update all frame titles based on their buffer names, etc.
      We do this before the menu bars so that the buffer-menu
@@ -688,8 +727,8 @@ prepare_menu_bars ()
      create its menu bar using the name `emacs' if no other name
      has yet been specified."
      I think that is no longer a concern.  */
-#ifdef HAVE_X_WINDOWS
-  if (windows_or_buffers_changed)
+#ifdef HAVE_WINDOW_SYSTEM
+  if (windows_or_buffers_changed || update_mode_lines)
     {
       Lisp_Object tail, frame;
 
@@ -737,6 +776,12 @@ prepare_menu_bars ()
     }
   else
     update_menu_bar (selected_frame, 1);
+
+  /* Motif needs this.  See comment in xmenu.c.
+     Turn it off when pending_menu_activation is not defined.  */
+#ifdef USE_X_TOOLKIT
+  pending_menu_activation = 0;
+#endif
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -763,8 +808,24 @@ static int do_verify_charstarts;
    no more than once ever 1000 redisplays.  */
 static int clear_face_cache_count;
 
+/* Record the previous terminal frame we displayed.  */
+static FRAME_PTR previous_terminal_frame;
+
 void
 redisplay ()
+{
+  redisplay_internal (0);
+}
+
+/* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay
+   is not in response to any user action; therefore, we should
+   preserve the echo area.  (Actually, our caller does that job.)
+   Perhaps in the future avoid recentering windows
+   if it is not necessary; currently that causes some problems.  */
+
+static void
+redisplay_internal (preserve_echo_area)
+     int preserve_echo_area;
 {
   register struct window *w = XWINDOW (selected_window);
   register int pause;
@@ -776,6 +837,22 @@ redisplay ()
   if (noninteractive)
     return;
 
+#ifdef USE_X_TOOLKIT
+  if (popup_activated ())
+    return;
+#endif
+
+  if (! FRAME_WINDOW_P (selected_frame)
+      && previous_terminal_frame != selected_frame)
+    {
+      /* Since frames on an ASCII terminal share the same display area,
+        displaying a different frame means redisplay the whole thing.  */
+      windows_or_buffers_changed++;
+      SET_FRAME_GARBAGED (selected_frame);
+      XSETFRAME (Vterminal_frame, selected_frame);
+    }
+  previous_terminal_frame = selected_frame;
+
   /* Set the visible flags for all frames.
      Do this before checking for resized or garbaged frames; they want
      to know if their frames are visible.
@@ -804,20 +881,26 @@ redisplay ()
 
   prepare_menu_bars ();
 
-  if (clip_changed || windows_or_buffers_changed
-      || (!NILP (w->column_number_displayed)
-         && XFASTINT (w->column_number_displayed) != current_column ()))
+  if (windows_or_buffers_changed)
     update_mode_lines++;
 
-  /* Detect case that we need to write a star in the mode line.  */
-  if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= SAVE_MODIFF)
+  /* Detect case that we need to write or remove a star in the mode line.  */
+  if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
     {
       w->update_mode_line = Qt;
       if (buffer_shared > 1)
        update_mode_lines++;
     }
 
+  /* If %c is in use, update it if needed.  */
+  if (!NILP (w->column_number_displayed)
+      /* This alternative quickly identifies a common case
+        where no change is needed.  */
+      && !(PT == XFASTINT (w->last_point)
+          && XFASTINT (w->last_modified) >= MODIFF)
+      && XFASTINT (w->column_number_displayed) != current_column ())
+    w->update_mode_line = Qt; 
+
   FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
 
   all_windows = update_mode_lines || buffer_shared > 1;
@@ -826,7 +909,7 @@ redisplay ()
      to ensure we remove any arrow that should no longer exist.  */
   if (! EQ (Voverlay_arrow_position, last_arrow_position)
       || ! EQ (Voverlay_arrow_string, last_arrow_string))
-    all_windows = 1, clip_changed = 1;
+    all_windows = 1;
 
   /* Normally the message* functions will have already displayed and
      updated the echo area, but the frame may have been trashed, or
@@ -850,6 +933,7 @@ redisplay ()
   tlbufpos = this_line_bufpos;
   tlendpos = this_line_endpos;
   if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
+      && !current_buffer->clip_changed
       && FRAME_VISIBLE_P (XFRAME (w->frame))
       /* Make sure recorded data applies to current buffer, etc */
       && this_line_buffer == current_buffer
@@ -921,7 +1005,12 @@ redisplay ()
          else
            goto cancel;
        }
-      else if (PT == XFASTINT (w->last_point))
+      else if (PT == XFASTINT (w->last_point)
+              /* Make sure the cursor was last displayed
+                 in this window.  Otherwise we have to reposition it.  */
+              && XINT (w->top) <= FRAME_CURSOR_Y (selected_frame)
+              && (XINT (w->top) + XINT (w->height)
+                  > FRAME_CURSOR_Y (selected_frame)))
        {
          if (!must_finish)
            {
@@ -934,13 +1023,14 @@ redisplay ()
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
+              && w == XWINDOW (current_buffer->last_selected_window)
               && NILP (w->region_showing)
               && !cursor_in_echo_area)
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
                                 0,
-                                PT, 2, - (1 << (SHORTBITS - 1)),
+                                PT, 2, - (1 << (BITS_PER_SHORT - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
                                 pos_tab_offset (w, tlbufpos), w);
@@ -986,7 +1076,7 @@ redisplay ()
       FOR_EACH_FRAME (tail, frame)
        {
          FRAME_PTR f = XFRAME (frame);
-         if (! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if (FRAME_WINDOW_P (f) || f == selected_frame)
            {
 
              /* Mark all the scroll bars to be removed; we'll redeem the ones
@@ -995,7 +1085,7 @@ redisplay ()
                (*condemn_scroll_bars_hook) (f);
 
              if (FRAME_VISIBLE_P (f))
-               redisplay_windows (FRAME_ROOT_WINDOW (f));
+               redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
 
              /* Any scroll bars which redisplay_windows should have nuked
                 should now go away.  */
@@ -1006,7 +1096,7 @@ redisplay ()
     }
   else if (FRAME_VISIBLE_P (selected_frame))
     {
-      redisplay_window (selected_window, 1);
+      redisplay_window (selected_window, 1, preserve_echo_area);
       if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
        preserve_other_columns (w);
     }
@@ -1019,7 +1109,6 @@ update:
     unrequest_sigio ();
   stop_polling ();
 
-#ifdef MULTI_FRAME
   if (all_windows)
     {
       Lisp_Object tail;
@@ -1035,7 +1124,7 @@ update:
 
          f = XFRAME (XCONS (tail)->car);
 
-         if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if ((FRAME_WINDOW_P (f) || f == selected_frame)
              && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
@@ -1049,7 +1138,6 @@ update:
        }
     }
   else
-#endif /* MULTI_FRAME */
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
@@ -1062,10 +1150,13 @@ update:
         above call to update_frame would not have caught it.  Catch
         it here.  */
       {
-       FRAME_PTR mini_frame
-         = XFRAME (WINDOW_FRAME (XWINDOW (minibuf_window)));
+       Lisp_Object mini_window;
+       FRAME_PTR mini_frame;
+
+       mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
+       mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
        
-       if (mini_frame != selected_frame)
+       if (mini_frame != selected_frame && FRAME_WINDOW_P (mini_frame))
          pause |= update_frame (mini_frame, 0, 0);
       }
     }
@@ -1096,7 +1187,6 @@ update:
       register struct buffer *b = XBUFFER (w->buffer);
 
       blank_end_of_window = 0;
-      clip_changed = 0;
       unchanged_modified = BUF_MODIFF (b);
       beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
       end_unchanged = BUF_Z (b) - BUF_GPT (b);
@@ -1109,8 +1199,12 @@ update:
        mark_window_display_accurate (FRAME_ROOT_WINDOW (selected_frame), 1);
       else
        {
+         b->clip_changed = 0;
          w->update_mode_line = Qnil;
          XSETFASTINT (w->last_modified, BUF_MODIFF (b));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
          w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
@@ -1156,11 +1250,11 @@ redisplay_preserve_echo_area ()
   if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
     {
       echo_area_glyphs = previous_echo_glyphs;
-      redisplay ();
+      redisplay_internal (1);
       echo_area_glyphs = 0;
     }
   else
-    redisplay ();
+    redisplay_internal (1);
 }
 
 void
@@ -1179,10 +1273,14 @@ mark_window_display_accurate (window, flag)
        {
          XSETFASTINT (w->last_modified,
                       !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
 
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
          w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && w == XWINDOW (current_buffer->last_selected_window)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
                               : Qnil);
@@ -1190,6 +1288,8 @@ mark_window_display_accurate (window, flag)
 
       w->window_end_valid = w->buffer;
       w->update_mode_line = Qnil;
+      if (!NILP (w->buffer) && flag)
+       XBUFFER (w->buffer)->clip_changed = 0;
 
       if (!NILP (w->vchild))
        mark_window_display_accurate (w->vchild, flag);
@@ -1231,13 +1331,14 @@ update_menu_bar (f, save_match_data)
   if (update_mode_lines)
     w->update_mode_line = Qt;
 
-  if (
-#ifdef USE_X_TOOLKIT
+  if (FRAME_WINDOW_P (f)
+      ?
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
       FRAME_EXTERNAL_MENU_BAR (f) 
 #else
       FRAME_MENU_BAR_LINES (f) > 0
 #endif
-      )
+      : FRAME_MENU_BAR_LINES (f) > 0)
     {
       /* If the user has switched buffers or windows, we need to
         recompute to reflect the new bindings.  But we'll
@@ -1248,25 +1349,49 @@ update_menu_bar (f, save_match_data)
         windows_or_buffers_changed anyway.  */
       if (windows_or_buffers_changed
          || !NILP (w->update_mode_line)
-         || (XFASTINT (w->last_modified) < MODIFF
-             && (XFASTINT (w->last_modified)
-                 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer)))))
+         || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              < BUF_MODIFF (XBUFFER (w->buffer)))
+             != !NILP (w->last_had_star))
+         || ((!NILP (Vtransient_mark_mode)
+              && !NILP (XBUFFER (w->buffer)->mark_active))
+             != !NILP (w->region_showing)))
        {
          struct buffer *prev = current_buffer;
          int count = specpdl_ptr - specpdl;
 
-         if (!save_match_data)
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+         if (save_match_data)
            record_unwind_protect (Fstore_match_data, Fmatch_data ());
+         if (NILP (Voverriding_local_map_menu_flag))
+           {
+             specbind (Qoverriding_terminal_local_map, Qnil);
+             specbind (Qoverriding_local_map, Qnil);
+           }
 
-         call1 (Vrun_hooks, Qmenu_bar_update_hook);
-         current_buffer = XBUFFER (w->buffer);
+         /* Run the Lucid hook.  */
+         call1 (Vrun_hooks, Qactivate_menubar_hook);
+         /* If it has changed current-menubar from previous value,
+            really recompute the menubar from the value.  */
+         if (! NILP (Vlucid_menu_bar_dirty_flag))
+           call0 (Qrecompute_lucid_menubar);
+         safe_run_hooks (Qmenu_bar_update_hook);
          FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
-         current_buffer = prev;
-#ifdef USE_X_TOOLKIT
-         set_frame_menubar (f, 0);
-#endif /* USE_X_TOOLKIT */
+         /* Redisplay the menu bar in case we changed it.  */
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+         if (FRAME_WINDOW_P (f))
+           set_frame_menubar (f, 0, 0);
+         else
+           /* On a terminal screen, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+           w->update_mode_line = Qt;
+#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
+         /* In the non-toolkit version, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+         w->update_mode_line = Qt;
+#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
 
          unbind_to (count, Qnil);
+         set_buffer_internal_1 (prev);
        }
     }
 }
@@ -1276,19 +1401,20 @@ int do_id = 1;
 /* Redisplay WINDOW and its subwindows and siblings.  */
 
 static void
-redisplay_windows (window)
+redisplay_windows (window, preserve_echo_area)
      Lisp_Object window;
+     int preserve_echo_area;
 {
   for (; !NILP (window); window = XWINDOW (window)->next)
-    redisplay_window (window, 0);
+    redisplay_window (window, 0, preserve_echo_area);
 }
 
 /* Redisplay window WINDOW and its subwindows.  */
 
 static void
-redisplay_window (window, just_this_one)
+redisplay_window (window, just_this_one, preserve_echo_area)
      Lisp_Object window;
-     int just_this_one;
+     int just_this_one, preserve_echo_area;
 {
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
@@ -1302,6 +1428,7 @@ redisplay_window (window, just_this_one)
   int opoint = PT;
   int tem;
   int update_mode_line;
+  struct Lisp_Char_Table *dp = window_display_table (w);
 
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
@@ -1309,12 +1436,12 @@ redisplay_window (window, just_this_one)
 
   if (!NILP (w->vchild))
     {
-      redisplay_windows (w->vchild);
+      redisplay_windows (w->vchild, preserve_echo_area);
       return;
     }
   if (!NILP (w->hchild))
     {
-      redisplay_windows (w->hchild);
+      redisplay_windows (w->hchild, preserve_echo_area);
       return;
     }
   if (NILP (w->buffer))
@@ -1322,20 +1449,19 @@ redisplay_window (window, just_this_one)
   
   height = window_internal_height (w);
   update_mode_line = (!NILP (w->update_mode_line) || update_mode_lines);
+  if (XBUFFER (w->buffer)->clip_changed)
+    update_mode_line = 1;
 
   if (MINI_WINDOW_P (w))
     {
-      if (w == XWINDOW (minibuf_window))
-       {
-         if (echo_area_glyphs)
-           /* We've already displayed the echo area glyphs, if any.  */
-           goto finish_scroll_bars;
-       }
-      else
+      if (w == XWINDOW (echo_area_window) && echo_area_glyphs)
+       /* We've already displayed the echo area glyphs in this window.  */
+       goto finish_scroll_bars;
+      else if (w != XWINDOW (minibuf_window))
        {
-         /* This is a minibuffer, but it's not the currently active one, so
-            clear it.  */
-         int vpos = XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (f))->top);
+         /* This is a minibuffer, but it's not the currently active one,
+            so clear it.  */
+         int vpos = XFASTINT (w->top);
          int i;
 
          for (i = 0; i < height; i++)
@@ -1357,6 +1483,15 @@ redisplay_window (window, just_this_one)
 
   opoint = PT;
 
+  /* If %c is in mode line, update it if needed.  */
+  if (!NILP (w->column_number_displayed)
+      /* This alternative quickly identifies a common case
+        where no change is needed.  */
+      && !(PT == XFASTINT (w->last_point)
+          && XFASTINT (w->last_modified) >= MODIFF)
+      && XFASTINT (w->column_number_displayed) != current_column ())
+    update_mode_line = 1; 
+
   /* Count number of windows showing the selected buffer.
      An indirect buffer counts as its base buffer.  */
 
@@ -1400,7 +1535,7 @@ redisplay_window (window, just_this_one)
      changed, so why should we worry about doing any better?  */
   if (current_buffer->width_run_cache)
     {
-      struct Lisp_Vector *disptab = buffer_display_table ();
+      struct Lisp_Char_Table *disptab = buffer_display_table ();
 
       if (! disptab_matches_widthtab (disptab,
                                       XVECTOR (current_buffer->width_table)))
@@ -1422,17 +1557,32 @@ redisplay_window (window, just_this_one)
      unless the specified location is outside the accessible range.  */
   if (!NILP (w->force_start))
     {
+      w->force_start = Qnil;
       /* Forget any recorded base line for line number display.  */
       w->base_line_number = Qnil;
-      /* Redisplay the mode line.  Select the buffer properly for that.  */
-      if (!update_mode_line)
+      /* Redisplay the mode line.  Select the buffer properly for that.
+        Also, run the hook window-scroll-functions
+        because we have scrolled.  */
+      /* Note, we do this after clearing force_start because
+        if there's an error, it is better to forget about force_start
+        than to get into an infinite loop calling the hook functions
+        and having them get more errors.  */
+      if (!update_mode_line
+         || ! NILP (Vwindow_scroll_functions))
        {
+         Lisp_Object temp[3];
+
          set_buffer_temp (old);
          set_buffer_internal_1 (XBUFFER (w->buffer));
          update_mode_line = 1;
          w->update_mode_line = Qt;
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (startp));
+             startp = marker_position (w->start);
+           }
        }
-      w->force_start = Qnil;
       XSETFASTINT (w->last_modified, 0);
       if (startp < BEGV) startp = BEGV;
       if (startp > ZV)   startp = ZV;
@@ -1447,7 +1597,7 @@ redisplay_window (window, just_this_one)
                                  + (hscroll ? 1 - hscroll : 0)),
                                 0,
                                 ZV, height / 2,
-                                - (1 << (SHORTBITS - 1)),
+                                - (1 << (BITS_PER_SHORT - 1)),
                                 width, hscroll, pos_tab_offset (w, startp), w);
          BUF_PT (current_buffer) = pos.bufpos;
          if (w != XWINDOW (selected_window))
@@ -1473,7 +1623,7 @@ redisplay_window (window, just_this_one)
     }
 
   /* Handle case where text has not changed, only point,
-     and it has not moved off the frame */
+     and it has not moved off the frame */
 
   /* This code is not used for minibuffer for the sake of
      the case of redisplaying to replace an echo area message;
@@ -1483,7 +1633,7 @@ redisplay_window (window, just_this_one)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
-      && PT >= startp && !clip_changed
+      && PT >= startp && !current_buffer->clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
       /* If force-mode-line-update was called, really redisplay;
         that's how redisplay is forced after e.g. changing
@@ -1537,12 +1687,15 @@ redisplay_window (window, just_this_one)
           /* or else vmotion on first line won't work.  */
           && ! NILP (w->start_at_line_beg)
           && ! EQ (w->window_end_valid, Qnil)
-          && do_id && !clip_changed
+          && do_id && !current_buffer->clip_changed
           && !blank_end_of_window
           && XFASTINT (w->width) == FRAME_WIDTH (f)
           /* Can't use this case if highlighting a region.  */
           && !(!NILP (Vtransient_mark_mode)
                && !NILP (current_buffer->mark_active))
+          /* Don't use try_window_id if newline
+             doesn't display as the end of a line.  */
+          && !(dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, '\n')))
           && NILP (w->region_showing)
           && EQ (last_arrow_position, Voverlay_arrow_position)
           && EQ (last_arrow_string, Voverlay_arrow_string)
@@ -1557,8 +1710,16 @@ redisplay_window (window, just_this_one)
        goto done;
     }
   else if (startp >= BEGV && startp <= ZV
-          /* Avoid starting display at end of buffer! */
-          && (startp < ZV || startp == BEGV
+          && (startp < ZV
+              /* Avoid starting at end of buffer.  */
+#if 0 /* This change causes trouble for M-! finger & RET.
+        It will have to be considered later.  */
+              || ! EQ (window, selected_window)
+              /* Don't do the recentering if redisplay
+                 is not for no user action.  */
+              || preserve_echo_area
+#endif
+              || startp == BEGV
               || (XFASTINT (w->last_modified) >= MODIFF)))
     {
       /* Try to redisplay starting at same place as before */
@@ -1566,7 +1727,8 @@ redisplay_window (window, just_this_one)
       try_window (window, startp);
       if (cursor_vpos >= 0)
        {
-         if (!just_this_one || clip_changed || beg_unchanged < startp)
+         if (!just_this_one || current_buffer->clip_changed
+             || beg_unchanged < startp)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
          goto done;
@@ -1587,7 +1749,8 @@ redisplay_window (window, just_this_one)
 
   /* Try to scroll by specified few lines */
 
-  if (scroll_step && !clip_changed)
+  if (scroll_step && !current_buffer->clip_changed
+      && startp >= BEGV && startp <= ZV)
     {
       if (PT > startp)
        {
@@ -1600,10 +1763,18 @@ redisplay_window (window, just_this_one)
 
       if (PT >= pos.bufpos)
        {
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (pos.bufpos));
+             pos.bufpos = marker_position (w->start);
+           }
          try_window (window, pos.bufpos);
          if (cursor_vpos >= 0)
            {
-             if (!just_this_one || clip_changed || beg_unchanged < startp)
+             if (!just_this_one || current_buffer->clip_changed
+                 || beg_unchanged < startp)
                /* Forget any recorded base line for line number display.  */
                w->base_line_number = Qnil;
              goto done;
@@ -1621,6 +1792,15 @@ recenter:
   w->base_line_number = Qnil;
 
   pos = *vmotion (PT, - (height / 2), w);
+  /* Set startp here explicitly in case that helps avoid an infinite loop
+     in case the window-scroll-functions functions get errors.  */
+  Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+  if (! NILP (Vwindow_scroll_functions))
+    {
+      run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                           make_number (pos.bufpos));
+      pos.bufpos = marker_position (w->start);
+    }
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
@@ -1646,11 +1826,14 @@ done:
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
   if (update_mode_line
-#ifdef USE_X_TOOLKIT
-      && FRAME_EXTERNAL_MENU_BAR (f) 
+      && (FRAME_WINDOW_P (f)
+         ?
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+         FRAME_EXTERNAL_MENU_BAR (f) 
 #else
-      && FRAME_MENU_BAR_LINES (f) > 0
+         FRAME_MENU_BAR_LINES (f) > 0
 #endif
+         : FRAME_MENU_BAR_LINES (f) > 0)
       && EQ (FRAME_SELECTED_WINDOW (f), window))
     display_menu_bar (w);
 
@@ -1799,7 +1982,7 @@ try_window_id (window)
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
   int delta;
-  int tab_offset, epto;
+  int tab_offset, epto, old_tick;
 
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
@@ -1817,12 +2000,12 @@ try_window_id (window)
     {
       if (PT < bp.bufpos)
        {
-         /* All changes are below the frame, and point is on the frame.
-            We don't need to change the frame at all.
+         /* All changes are beyond the window end, and point is on the screen.
+            We don't need to change the text at all.
             But we need to update window_end_pos to account for
             any change in buffer size.  */
          bp = *compute_motion (start, 0, lmargin, 0,
-                               Z, height, 0,
+                               ZV, height, 0,
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
@@ -1872,7 +2055,7 @@ try_window_id (window)
 
   /* Compute the cursor position after that newline.  */
   ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
-                       height, - (1 << (SHORTBITS - 1)),
+                       height, - (1 << (BITS_PER_SHORT - 1)),
                        width, hscroll, pos_tab_offset (w, bp.bufpos), w);
 
   /* If changes reach past the text available on the frame,
@@ -1928,13 +2111,13 @@ try_window_id (window)
          if (PT <= xp.bufpos)
            {
              pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
-                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   PT, height, - (1 << (BITS_PER_SHORT - 1)),
                                    width, hscroll, epto, w);
            }
          else
            {
              pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
-                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   PT, height, - (1 << (BITS_PER_SHORT - 1)),
                                    width, hscroll,
                                    pos_tab_offset (w, xp.bufpos), w);
            }
@@ -1993,8 +2176,8 @@ try_window_id (window)
                 lines' charstarts in the case where the text of the
                 screen line at bp.vpos has changed.
                 (This can happen in a deletion that ends in mid-line.)
-                To adjust properly, we need to make things constent at
-                the position ep.
+                To adjust properly, we need to make things consistent
+                at the position ep.
                 So do a second adjust to make that happen.
                 Note that stop_vpos >= ep.vpos, so it is sufficient
                 to update the charstarts for lines at ep.vpos and below.  */
@@ -2044,9 +2227,15 @@ try_window_id (window)
      to account for passing the line that that character really starts in.  */
   if (val.hpos < lmargin)
     tab_offset += width;
+  old_tick = MODIFF;
   while (vpos < stop_vpos)
     {
       val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+      /* If display_text_line ran a hook and changed some text,
+        redisplay all the way to bottom of buffer
+        So that we show the changes.  */
+      if (old_tick != MODIFF)
+       stop_vpos = height;
       tab_offset += width;
       if (val.vpos) tab_offset = 0;
       if (pos != val.bufpos)
@@ -2155,7 +2344,7 @@ try_window_id (window)
   if (debug_end_pos)
     {
       val = *compute_motion (start, 0, lmargin, 0, ZV,
-                            height, - (1 << (SHORTBITS - 1)),
+                            height, - (1 << (BITS_PER_SHORT - 1)),
                             width, hscroll, pos_tab_offset (w, start), w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
        abort ();
@@ -2370,14 +2559,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   /* 1 if we should highlight the region.  */
   int highlight_region
-    = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
+    = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
+       && XWINDOW (current_buffer->last_selected_window) == w);
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
                   ? XINT (current_buffer->selective_display)
                   : !NILP (current_buffer->selective_display) ? -1 : 0);
   register struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
-  register struct Lisp_Vector *dp = window_display_table (w);
+  register struct Lisp_Char_Table *dp = window_display_table (w);
 
   Lisp_Object default_invis_vector[3];
   /* Number of characters of ellipsis to display after an invisible line
@@ -2522,6 +2712,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
     {
       if (pos >= pause)
        {
+         int e_t_h;
+
          while (pos == next_boundary)
            {
              Lisp_Object position, limit, prop, ww;
@@ -2590,18 +2782,63 @@ display_text_line (w, start, vpos, hpos, taboffset)
          /* Did we hit the end of the visible region of the buffer?
             Stop here.  */
          if (pos >= ZV)
-           break;
+           {
+             /* Update charstarts for the end of this line.  */
+             /* Do nothing if off the left edge or at the right edge.  */
+             if (p1 >= leftmargin && p1 + 1 != endp)
+               {
+                 int *p2x = &charstart[(p1 < leftmargin
+                                        ? leftmargin : p1)
+                                       - p1start];
+                 *p2x++ = pos;
+               }
+             break;
+           }
+
+         /* Figure out where (if at all) the
+            redisplay_end_trigger-hook should run.  */
+         if (MARKERP (w->redisplay_end_trigger)
+             && XMARKER (w->redisplay_end_trigger)->buffer != 0)
+           e_t_h = marker_position (w->redisplay_end_trigger);
+         else if (INTEGERP (w->redisplay_end_trigger))
+           e_t_h = XINT (w->redisplay_end_trigger);
+         else
+           e_t_h = ZV;
+
+         /* If we've gone past the place to run a hook,
+            run the hook.  */
+         if (pos >= e_t_h && e_t_h != ZV)
+           {
+             Lisp_Object args[3];
+
+             args[0] = Qredisplay_end_trigger_functions;
+             XSETWINDOW (args[1], w);
+             XSETINT (args[2], e_t_h);
+
+             /* Since we are *trying* to run these functions,
+                don't try to run them again, even if they get an error.  */
+             w->redisplay_end_trigger = Qnil;
+             Frun_hook_with_args (3, args);
+
+             e_t_h = ZV;
+             /* Notice if it changed the face of this character.  */
+             next_face_change = pos;
+           }
 
 #ifdef HAVE_FACES
          /* Did we hit a face change?  Figure out what face we should
             use now.  We also hit this the first time through the
             loop, to see what face we should start with.  */
-         if (pos >= next_face_change && FRAME_X_P (f))
+         if (pos >= next_face_change
+             && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
            current_face = compute_char_face (f, w, pos,
                                              region_beg, region_end,
                                              &next_face_change, pos + 50, 0);
 #endif
 
+         /* Compute the next place we need to stop
+            and do something special; set PAUSE.  */
+
          pause = ZV;
 
          if (pos < next_boundary && next_boundary < pause)
@@ -2609,6 +2846,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (pos < next_face_change && next_face_change < pause)
            pause = next_face_change;
 
+         if (e_t_h < pause)
+           pause = e_t_h;
+
          /* Wouldn't you hate to read the next line to someone over
              the phone?  */
          if (pos < PT && PT < pause)
@@ -2946,11 +3186,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
          covered up by the scroll bars, and it's distracting to see
          them when the scroll bar windows are flickering around to be
          reconfigured.  */
-      *p1++ = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
-              ? ' '
-              : (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
-                 ? DISP_BORDER_GLYPH (dp)
-                 : '|'));
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+       {
+         int i;
+         for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
+           *p1++ = SPACEGLYPH;
+       }
+      else
+       *p1++ = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
+                ? DISP_BORDER_GLYPH (dp)
+                : '|');
     }
   desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
                                   p1 - desired_glyphs->glyphs[vpos]);
@@ -3021,21 +3266,27 @@ display_menu_bar (w)
   int hpos = 0;
   int i;
 
-#ifndef USE_X_TOOLKIT
-  if (FRAME_MENU_BAR_LINES (f) <= 0)
+#ifdef HAVE_NTGUI
+  if (!NILP (Vwindow_system))
     return;
+#endif
+
+#ifdef USE_X_TOOLKIT
+  if (FRAME_X_P (f))
+    return;
+#endif /* USE_X_TOOLKIT */
 
   get_display_line (f, vpos, 0);
 
   items = FRAME_MENU_BAR_ITEMS (f);
-  for (i = 0; i < XVECTOR (items)->size; i += 3)
+  for (i = 0; i < XVECTOR (items)->size; i += 4)
     {
       Lisp_Object pos, string;
       string = XVECTOR (items)->contents[i + 1];
       if (NILP (string))
        break;
 
-      XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
+      XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
 
       if (hpos < maxendcol)
        hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
@@ -3062,7 +3313,6 @@ display_menu_bar (w)
   vpos++;
   while (vpos < FRAME_MENU_BAR_LINES (f))
     get_display_line (f, vpos++, 0);
-#endif /* not USE_X_TOOLKIT */
 }
 \f
 /* Display the mode line for window w */
@@ -3177,6 +3427,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
              }
            else /* c == '%' */
              {
+               register int minendcol;
                register int spec_width = 0;
 
                /* We can't allow -ve args due to the "%-" construct */
@@ -3189,9 +3440,12 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                    spec_width = spec_width * 10 + (c - '0');
                  }
 
-               spec_width += hpos;
-               if (spec_width > maxendcol)
-                 spec_width = maxendcol;
+               minendcol = hpos + spec_width;
+               if (minendcol > maxendcol)
+                 {
+                   spec_width = maxendcol - hpos;
+                   minendcol = maxendcol;
+                 }
 
                if (c == 'M')
                  hpos = display_mode_element (w, vpos, hpos, depth,
@@ -3199,13 +3453,14 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                                               Vglobal_mode_string);
                else if (c != 0)
                  {
-                   char *spec = decode_mode_spec (w, c, maxendcol - hpos);
+                   char *spec = decode_mode_spec (w, c, spec_width,
+                                                  maxendcol - hpos);
                    if (frame_title_ptr)
-                     hpos = store_frame_title (spec, spec_width, maxendcol);
+                     hpos = store_frame_title (spec, minendcol, maxendcol);
                    else
                      hpos = display_string (w, vpos, spec, -1,
                                             hpos, 0, 1,
-                                            spec_width, maxendcol);
+                                            minendcol, maxendcol);
                  }
              }
          }
@@ -3339,15 +3594,47 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
   return hpos;
 }
 \f
+/* Write a null-terminated, right justified decimal representation of
+   the positive integer D to BUF using a minimal field width WIDTH.  */
+
+static void
+pint2str (buf, width, d)
+     register char *buf;
+     register int width;
+     register int d;
+{
+  register char *p = buf;
+  
+  if (d <= 0)
+      *p++ = '0';
+  else
+      while (d > 0)
+      {
+         *p++ = d % 10 + '0';
+         d /= 10;
+      }
+  for (width -= (int) (p - buf); width > 0; --width) *p++ = ' ';
+  *p-- = '\0';
+  while (p > buf)
+  {
+      d = *buf;
+      *buf++ = *p;
+      *p-- = d;
+  }
+}
+
 /* Return a string for the output of a mode line %-spec for window W,
-   generated by character C and width MAXWIDTH.  */
+   generated by character C.  SPEC_WIDTH is the field width when
+   padding to the left (%c, %l).  The value returned from this
+   function will later be truncated to width MAXWIDTH. */
 
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
 static char *
-decode_mode_spec (w, c, maxwidth)
+decode_mode_spec (w, c, spec_width, maxwidth)
      struct window *w;
      register char c;
+     register int spec_width;
      register int maxwidth;
 {
   Lisp_Object obj;
@@ -3446,13 +3733,17 @@ decode_mode_spec (w, c, maxwidth)
       {
        int col = current_column ();
        XSETFASTINT (w->column_number_displayed, col);
-       sprintf (decode_mode_spec_buf, "%d", col);
+       pint2str (decode_mode_spec_buf, spec_width, col);
        return decode_mode_spec_buf;
       }
 
     case 'F':
       /* %F displays the frame name.  */
-      return (char *) XSTRING (selected_frame->name)->data;
+      if (!NILP (f->title))
+       return (char *) XSTRING (f->title)->data;
+      if (f->explicit_name || ! FRAME_WINDOW_P (f))
+       return (char *) XSTRING (f->name)->data;
+      return "Emacs";
 
     case 'f': 
       obj = b->filename;
@@ -3480,14 +3771,14 @@ decode_mode_spec (w, c, maxwidth)
        /* If we decided that this buffer isn't suitable for line numbers, 
           don't forget that too fast.  */
        if (EQ (w->base_line_pos, w->buffer))
-         return "??";
+         goto no_value;
 
        /* If the buffer is very big, don't waste time.  */
        if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
          {
            w->base_line_pos = Qnil;
            w->base_line_number = Qnil;
-           return "??";
+           goto no_value;
          }
 
        if (!NILP (w->base_line_number)
@@ -3537,7 +3828,7 @@ decode_mode_spec (w, c, maxwidth)
              {
                w->base_line_pos = w->buffer;
                w->base_line_number = Qnil;
-               return "??";
+               goto no_value;
              }
 
            XSETFASTINT (w->base_line_number, topline - nlines);
@@ -3551,8 +3842,15 @@ decode_mode_spec (w, c, maxwidth)
        line_number_displayed = 1;
 
        /* Make the string to show.  */
-       sprintf (decode_mode_spec_buf, "%d", topline + nlines);
+       pint2str (decode_mode_spec_buf, spec_width, topline + nlines);
        return decode_mode_spec_buf;
+    no_value:
+        {
+         char* p = decode_mode_spec_buf;
+         for (spec_width -= 2; spec_width > 0; --spec_width) *p++ = ' ';
+         strcpy (p, "??");
+         return decode_mode_spec_buf;
+       }
       }
       break;
 
@@ -3581,7 +3879,11 @@ decode_mode_spec (w, c, maxwidth)
          return "Top";
        else
          {
-           total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
+           else
+             total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
@@ -3607,7 +3909,11 @@ decode_mode_spec (w, c, maxwidth)
          }
        else
          {
-           total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
+           if (total > 1000000)
+             /* Do it differently for a large value, to avoid overflow.  */
+             total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
+           else
+             total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
            /* We can't normally display a 3-digit number,
               so get us a 2-digit number that is close.  */
            if (total == 100)
@@ -3809,6 +4115,7 @@ display_string (w, vpos, string, length, hpos, truncate,
      int mincol, maxcol;
 {
   register int c;
+  int truncated;
   register GLYPH *p1;
   int hscroll = XINT (w->hscroll);
   int tab_width = XINT (XBUFFER (w->buffer)->tab_width);
@@ -3821,12 +4128,11 @@ display_string (w, vpos, string, length, hpos, truncate,
 
   /* Use the standard display table, not the window's display table.
      We don't want the mode line in rot13.  */
-  register struct Lisp_Vector *dp = 0;
+  register struct Lisp_Char_Table *dp = 0;
   int i;
 
-  if (VECTORP (Vstandard_display_table)
-      && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
-    dp = XVECTOR (Vstandard_display_table);
+  if (DISP_TABLE_P (Vstandard_display_table))
+    dp = XCHAR_TABLE (Vstandard_display_table);
 
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
@@ -3862,7 +4168,10 @@ display_string (w, vpos, string, length, hpos, truncate,
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
-  while (p1 < end)
+  /* We set truncated to 1 if we get stopped by trying to pass END
+     (that is, trying to pass MAXCOL.)  */
+  truncated = 0;
+  while (1)
     {
       if (length == 0)
        break;
@@ -3874,6 +4183,12 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c == 0)
        break;
 
+      if (p1 >= end)
+       {
+         truncated = 1;
+         break;
+       }
+
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          p1 = copy_part_of_rope (f, p1, start,
@@ -3927,7 +4242,7 @@ display_string (w, vpos, string, length, hpos, truncate,
        }
     }
 
-  if (c && length > 0)
+  if (truncated)
     {
       p1 = end;
       if (truncate) *p1++ = fix_glyph (f, truncate, 0);
@@ -4036,6 +4351,18 @@ syms_of_xdisp ()
   staticpro (&Qmenu_bar_update_hook);
   Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
 
+  staticpro (&Qoverriding_terminal_local_map);
+  Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
+
+  staticpro (&Qoverriding_local_map);
+  Qoverriding_local_map = intern ("overriding-local-map");
+
+  staticpro (&Qwindow_scroll_functions);
+  Qwindow_scroll_functions = intern ("window-scroll-functions");
+
+  staticpro (&Qredisplay_end_trigger_functions);
+  Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
+
   staticpro (&last_arrow_position);
   staticpro (&last_arrow_string);
   last_arrow_position = Qnil;
@@ -4082,8 +4409,8 @@ If this is zero, point is always centered after it moves off frame.");
   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
     "Non-nil if more than one frame is visible on this display.\n\
 Minibuffer-only frames don't count, but iconified frames do.\n\
-This variable is not guaranteed to be accurate except while parsing\n\
-frame-title-format.");
+This variable is not guaranteed to be accurate except while processing\n\
+`frame-title-format' and `icon-title-format'.");
 
   DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
     "Template for displaying the titlebar of visible frames.\n\
@@ -4121,6 +4448,13 @@ Just before redisplay, for each frame, if any of its windows have changed\n\
 size since the last redisplay, or have been split or deleted,\n\
 all the functions in the list are called, with the frame as argument.");
   Vwindow_size_change_functions = Qnil;
+
+  DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
+    "List of Functions to call before redisplaying a window with scrolling.\n\
+Each function is called with two arguments, the window\n\
+and its new display-start position.  Note that the value of `window-end'\n\
+is not valid when these functions are called.");
+  Vwindow_scroll_functions = Qnil;
 }
 
 /* initialize the window system */