(Fredirect_frame_focus): Don't call Ffocus_frame.
[bpt/emacs.git] / src / xdisp.c
index cd5ec93..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;
@@ -54,6 +64,8 @@ static int message_log_need_newline;
 
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #define max(a, b) ((a) > (b) ? (a) : (b))
+#define minmax(floor, val, ceil) \
+       ((val) < (floor) ? (floor) : (val) > (ceil) ? (ceil) : (val))
 
 /* The buffer position of the first character appearing
  entirely or partially on the current frame line.
@@ -75,11 +87,6 @@ static int this_line_start_hpos;
 /* Buffer that this_line variables are describing. */
 static struct buffer *this_line_buffer;
 
-/* Set by try_window_id to the vpos of first of any lines
-   scrolled on to the bottom of the frame.  These lines should
-   not be included in any general scroll computation.  */
-static int scroll_bottom_vpos;
-
 /* Value of echo_area_glyphs when it was last acted on.
   If this is nonzero, there is a message on the frame
   in the minibuffer and it should be erased as soon
@@ -120,6 +127,11 @@ Lisp_Object Qmenu_bar_update_hook;
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 static int overlay_arrow_seen;
 
+/* Nonzero if visible end of buffer has already been displayed once
+   in this window.  (We need this variable in case there are overlay
+   strings that get displayed there.)  */
+static int zv_strings_seen;
+
 /* Nonzero means highlight the region even in nonselected windows.  */
 static int highlight_nonselected_windows;
 
@@ -148,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 ();
@@ -159,7 +172,6 @@ static int try_window_id ();
 static struct position *display_text_line ();
 static void display_mode_line ();
 static int display_mode_element ();
-static char *fmodetrunc ();
 static char *decode_mode_spec ();
 static int display_string ();
 static void display_menu_bar ();
@@ -180,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;
 
@@ -198,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;
@@ -217,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 ()
 {
@@ -238,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*")));
@@ -306,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.
@@ -348,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)
@@ -367,7 +388,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -389,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;
+
+      /* 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)));
 
-      choose_minibuf_frame ();
-      minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
-      FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
+      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)
        {
@@ -410,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)
@@ -449,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)
@@ -475,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)
            {
@@ -497,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, 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, 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);
@@ -516,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;
@@ -534,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;
@@ -558,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;
 
@@ -622,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?  */
@@ -633,7 +673,8 @@ x_consider_frame_title (frame)
       {
        FRAME_PTR tf = XFRAME (XCONS (tail)->car);
 
-       if (tf != f && tf->kboard == f->kboard && !FRAME_MINIBUF_ONLY_P (tf)
+       if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f)
+           && !FRAME_MINIBUF_ONLY_P (tf)
            && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
          break;
       }
@@ -674,7 +715,29 @@ 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
+     will show the up-to-date frame titles.
+
+     This used to be done after the menu bars, for a reason that
+     was stated as follows but which I do not understand:
+     "We do this after the menu bars so that the frame will first
+     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_WINDOW_SYSTEM
+  if (windows_or_buffers_changed || update_mode_lines)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+       if (FRAME_VISIBLE_P (XFRAME (frame))
+           || FRAME_ICONIFIED_P (XFRAME (frame)))
+         x_consider_frame_title (frame);
+    }
+#endif
 
   /* Update the menu bar item lists, if appropriate.
      This has to be done before any actual redisplay
@@ -714,20 +777,10 @@ prepare_menu_bars ()
   else
     update_menu_bar (selected_frame, 1);
 
-  /* Update all frame titles based on their buffer names, etc.
-     We do this after the menu bars so that the frame will first
-     create its menu bar using the name `emacs' if no other name
-     has yet been specified.  */
-#ifdef HAVE_X_WINDOWS
-  if (windows_or_buffers_changed)
-    {
-      Lisp_Object tail, frame;
-
-      FOR_EACH_FRAME (tail, frame)
-       if (FRAME_VISIBLE_P (XFRAME (frame))
-           || FRAME_ICONIFIED_P (XFRAME (frame)))
-         x_consider_frame_title (frame);
-    }
+  /* 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
@@ -755,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;
@@ -768,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.
@@ -796,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;
@@ -818,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
@@ -842,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
@@ -875,6 +967,7 @@ redisplay ()
        {
          cursor_vpos = -1;
          overlay_arrow_seen = 0;
+         zv_strings_seen = 0;
          display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
                             pos_tab_offset (w, tlbufpos));
          /* If line contains point, is not continued,
@@ -912,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)
            {
@@ -925,19 +1023,22 @@ 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,
-                                PT, 2, - (1 << (SHORTBITS - 1)),
+                                0,
+                                PT, 2, - (1 << (BITS_PER_SHORT - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
                                 pos_tab_offset (w, tlbufpos), w);
          if (pos.vpos < 1)
            {
+             int width = window_internal_width (w) - 1;
              FRAME_CURSOR_X (selected_frame)
-               = XFASTINT (w->left) + max (pos.hpos, 0);
+               = XFASTINT (w->left) + minmax (0, pos.hpos, width);
              FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
              goto update;
            }
@@ -975,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
@@ -984,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.  */
@@ -995,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);
     }
@@ -1008,7 +1109,6 @@ update:
     unrequest_sigio ();
   stop_polling ();
 
-#ifdef MULTI_FRAME
   if (all_windows)
     {
       Lisp_Object tail;
@@ -1024,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);
@@ -1038,7 +1138,6 @@ update:
        }
     }
   else
-#endif /* MULTI_FRAME */
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
@@ -1051,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);
       }
     }
@@ -1085,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);
@@ -1098,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;
@@ -1145,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
@@ -1168,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);
@@ -1179,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);
@@ -1220,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
@@ -1237,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);
        }
     }
 }
@@ -1265,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));
@@ -1291,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 */
 
@@ -1298,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))
@@ -1311,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++)
@@ -1340,12 +1477,21 @@ redisplay_window (window, just_this_one)
   /* Otherwise set up data on this window; select its buffer and point value */
 
   if (update_mode_line)
-    set_buffer_internal (XBUFFER (w->buffer));
+    set_buffer_internal_1 (XBUFFER (w->buffer));
   else
     set_buffer_temp (XBUFFER (w->buffer));
 
   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.  */
 
@@ -1389,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)))
@@ -1411,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 (XBUFFER (w->buffer));
+         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;
@@ -1430,13 +1591,14 @@ redisplay_window (window, just_this_one)
        {
          /* If point does not appear, move point so it does appear */
          pos = *compute_motion (startp, 0,
-                               ((EQ (window, minibuf_window) && startp == 1)
-                                ? minibuf_prompt_width : 0)
-                               +
-                               (hscroll ? 1 - hscroll : 0),
-                               ZV, height / 2,
-                               - (1 << (SHORTBITS - 1)),
-                               width, hscroll, pos_tab_offset (w, startp), w);
+                                (((EQ (window, minibuf_window)
+                                   && startp == BEG)
+                                  ? minibuf_prompt_width : 0)
+                                 + (hscroll ? 1 - hscroll : 0)),
+                                0,
+                                ZV, height / 2,
+                                - (1 << (BITS_PER_SHORT - 1)),
+                                width, hscroll, pos_tab_offset (w, startp), w);
          BUF_PT (current_buffer) = pos.bufpos;
          if (w != XWINDOW (selected_window))
            Fset_marker (w->pointm, make_number (PT), Qnil);
@@ -1444,7 +1606,8 @@ redisplay_window (window, just_this_one)
            {
              if (current_buffer == old)
                lpoint = PT;
-             FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
+             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+                                   + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
          /* If we are highlighting the region,
@@ -1460,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;
@@ -1470,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
@@ -1484,7 +1647,7 @@ redisplay_window (window, just_this_one)
       && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
       && !EQ (window, minibuf_window))
     {
-      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
+      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
                            PT, height, 0, width, hscroll,
                            pos_tab_offset (w, startp), w);
 
@@ -1494,7 +1657,8 @@ redisplay_window (window, just_this_one)
          if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
            {
              /* These variables are supposed to be origin 1 */
-             FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
+             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+                                   + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
          /* This doesn't do the trick, because if a window to the right of
@@ -1523,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)
@@ -1543,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 */
@@ -1552,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;
@@ -1566,33 +1742,39 @@ redisplay_window (window, just_this_one)
   if (!update_mode_line)
     {
       set_buffer_temp (old);
-      set_buffer_internal (XBUFFER (w->buffer));
+      set_buffer_internal_1 (XBUFFER (w->buffer));
       update_mode_line = 1;
       w->update_mode_line = Qt;
     }
 
   /* 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)
        {
-         pos = *vmotion (Z - XFASTINT (w->window_end_pos),
-                         scroll_step, width, hscroll, window);
+         pos = *vmotion (Z - XFASTINT (w->window_end_pos), scroll_step, w);
          if (pos.vpos >= height)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp,
-                     (PT < startp ? - scroll_step : scroll_step),
-                     width, hscroll, window);
+      pos = *vmotion (startp, (PT < startp ? - scroll_step : scroll_step), w);
 
       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;
@@ -1609,11 +1791,20 @@ recenter:
   /* Forget any previously recorded base line for line number display.  */
   w->base_line_number = Qnil;
 
-  pos = *vmotion (PT, - (height / 2), width, hscroll, window);
+  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);
-  w->start_at_line_beg 
+  w->start_at_line_beg
     = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
@@ -1635,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);
 
@@ -1680,7 +1874,7 @@ done:
 
   BUF_PT (current_buffer) = opoint;
   if (update_mode_line)
-    set_buffer_internal (old);
+    set_buffer_internal_1 (old);
   else
     set_buffer_temp (old);
   BUF_PT (current_buffer) = lpoint;
@@ -1705,6 +1899,7 @@ try_window (window, pos)
   Fset_marker (w->start, make_number (pos), Qnil);
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
+  zv_strings_seen = 0;
   val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
 
   while (--height >= 0)
@@ -1775,6 +1970,7 @@ try_window_id (window)
   int width = window_internal_width (w) - 1;
   int hscroll = XINT (w->hscroll);
   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
+  int did_motion;
   register int vpos;
   register int i, tem;
   int last_text_vpos = 0;
@@ -1786,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;
@@ -1797,19 +1993,19 @@ try_window_id (window)
     return 0;                  /* Give up if changes go above top of window */
 
   /* Find position before which nothing is changed.  */
-  bp = *compute_motion (start, 0, lmargin,
+  bp = *compute_motion (start, 0, lmargin, 0,
                        min (ZV, beg_unchanged + BEG), height, 0,
                        width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
       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,
-                               Z, height, 0,
+         bp = *compute_motion (start, 0, lmargin, 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);
@@ -1821,13 +2017,14 @@ try_window_id (window)
   vpos = bp.vpos;
 
   /* Find beginning of that frame line.  Must display from there.  */
-  bp = *vmotion (bp.bufpos, 0, width, hscroll, window);
+  bp = *vmotion (bp.bufpos, 0, w);
 
   pos = bp.bufpos;
   val.hpos = lmargin;
   if (pos < start)
     return -1;
 
+  did_motion = 0;
   /* If about to start displaying at the beginning of a continuation line,
      really start with previous frame line, in case it was not
      continued when last redisplayed */
@@ -1836,7 +2033,7 @@ try_window_id (window)
       /* Likewise if we have to worry about selective display.  */
       (selective > 0 && bp.bufpos - 1 == beg_unchanged && vpos > 0))
     {
-      bp = *vmotion (bp.bufpos, -1, width, hscroll, window);
+      bp = *vmotion (bp.bufpos, -1, w);
       --vpos;
       pos = bp.bufpos;
     }
@@ -1844,6 +2041,7 @@ try_window_id (window)
   if (bp.contin && bp.hpos != lmargin)
     {
       val.hpos = bp.prevhpos - width + lmargin;
+      did_motion = 1;
       pos--;
     }
 
@@ -1856,8 +2054,8 @@ try_window_id (window)
       tem = find_next_newline (tem, 1);
 
   /* Compute the cursor position after that newline.  */
-  ep = *compute_motion (pos, vpos, val.hpos, tem,
-                       height, - (1 << (SHORTBITS - 1)),
+  ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
+                       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,
@@ -1880,6 +2078,7 @@ try_window_id (window)
 
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
+  zv_strings_seen = 0;
 
   /* If changes do not reach to bottom of window,
      figure out how much to scroll the rest of the window */
@@ -1887,7 +2086,7 @@ try_window_id (window)
     {
       /* Now determine how far up or down the rest of the window has moved */
       epto = pos_tab_offset (w, ep.bufpos);
-      xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
+      xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
                            Z - XFASTINT (w->window_end_pos),
                            10000, 0, width, hscroll, epto, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
@@ -1911,21 +2110,21 @@ try_window_id (window)
        {
          if (PT <= xp.bufpos)
            {
-             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
-                                   PT, height, - (1 << (SHORTBITS - 1)),
+             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
+                                   PT, height, - (1 << (BITS_PER_SHORT - 1)),
                                    width, hscroll, epto, w);
            }
          else
            {
-             pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
-                                   PT, height, - (1 << (SHORTBITS - 1)),
+             pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
+                                   PT, height, - (1 << (BITS_PER_SHORT - 1)),
                                    width, hscroll,
                                    pos_tab_offset (w, xp.bufpos), w);
            }
          if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
-         cursor_hpos = pp.hpos + XFASTINT (w->left);
+         cursor_hpos = XFASTINT (w->left) + minmax (0, pp.hpos, width);
        }
 
       if (stop_vpos - scroll_amount >= height
@@ -1977,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.  */
@@ -2028,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)
@@ -2107,8 +2312,7 @@ try_window_id (window)
          || (delta > 0 && xp.bufpos <= ZV)
          || (delta == 0 && xp.hpos))
        {
-         val = *vmotion (Z - XFASTINT (w->window_end_pos),
-                         delta, width, hscroll, window);
+         val = *vmotion (Z - XFASTINT (w->window_end_pos), delta, w);
          XSETFASTINT (w->window_end_pos, Z - val.bufpos);
          XSETFASTINT (w->window_end_vpos,
                       XFASTINT (w->window_end_vpos) + val.vpos);
@@ -2121,7 +2325,7 @@ try_window_id (window)
   if (cursor_vpos < 0)
     {
     findpoint:
-      val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
+      val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
@@ -2131,16 +2335,16 @@ try_window_id (window)
          return 0;
        }
       cursor_vpos = val.vpos + top;
-      cursor_hpos = val.hpos + XFASTINT (w->left);
+      cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
     }
 
-  FRAME_CURSOR_X (f) = max (0, cursor_hpos);
+  FRAME_CURSOR_X (f) = cursor_hpos;
   FRAME_CURSOR_Y (f) = cursor_vpos;
 
   if (debug_end_pos)
     {
-      val = *compute_motion (start, 0, lmargin, ZV,
-                            height, - (1 << (SHORTBITS - 1)),
+      val = *compute_motion (start, 0, lmargin, 0, ZV,
+                            height, - (1 << (BITS_PER_SHORT - 1)),
                             width, hscroll, pos_tab_offset (w, start), w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
        abort ();
@@ -2330,13 +2534,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register int pos = start;
   register int c;
   register GLYPH *p1;
-  int end;
   register int pause;
   register unsigned char *p;
   GLYPH *endp;
   register GLYPH *leftmargin;
-  register GLYPH *p1prev = 0;
+  register GLYPH *p1prev;
   register GLYPH *p1start;
+  int prevpos;
   int *charstart;
   FRAME_PTR f = XFRAME (w->frame);
   int tab_width = XINT (current_buffer->tab_width);
@@ -2355,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
@@ -2389,11 +2594,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
      to overlays or text property changes.  */
   int next_face_change;
 
-#ifdef USE_TEXT_PROPERTIES
-  /* The next location where the `invisible' property changes */
-  int next_invisible;
-#endif
-  
+  /* The next location where the `invisible' property changes, or an
+     overlay starts or ends.  */
+  int next_boundary;
+
   /* The face we're currently using.  */
   int current_face = 0;
   int i;
@@ -2425,7 +2629,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
     region_beg = region_end = -1;
 
   if (MINI_WINDOW_P (w)
-      && start == 1
+      && start == BEG
       && vpos == XFASTINT (w->top))
     {
       if (! NILP (minibuf_prompt))
@@ -2448,16 +2652,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
        minibuf_prompt_width = 0;
     }
 
-  end = ZV;
-
   /* If we're hscrolled at all, use compute_motion to skip over any
      text off the left edge of the window.  compute_motion may know
      tricks to do this faster than we can.  */
   if (hpos < 0)
     {
       struct position *left_edge
-        = compute_motion (pos, vpos, hpos,
-                          end, vpos, 0,
+        = compute_motion (pos, vpos, hpos, 0,
+                          ZV, vpos, 0,
                           width, hscroll, taboffset, w);
 
       /* Retrieve the buffer position and column provided by
@@ -2503,90 +2705,150 @@ display_text_line (w, start, vpos, hpos, taboffset)
      or at face change.  */
   pause = pos;
   next_face_change = pos;
-#ifdef USE_TEXT_PROPERTIES
-  next_invisible = pos;
-#endif
+  next_boundary = pos;
+  p1prev = p1;
+  prevpos = pos;
   while (1)
     {
-      /* Record which glyph starts a character,
-        and the character position of that character.  */
-      if (p1 >= leftmargin)
-       charstart[p1 - p1start] = pos;
-
-      if (p1 >= endp)
-       break;
-
-      p1prev = p1;
       if (pos >= pause)
        {
-         /* Did we hit the end of the visible region of the buffer?
-            Stop here.  */
-         if (pos >= end)
-           break;
+         int e_t_h;
 
-         /* Did we reach point?  Record the cursor location.  */
-         if (pos == PT && cursor_vpos < 0)
+         while (pos == next_boundary)
            {
-             cursor_vpos = vpos;
-             cursor_hpos = p1 - leftmargin;
-           }
+             Lisp_Object position, limit, prop, ww;
+
+             /* Display the overlay strings here, unless we're at ZV
+                and have already displayed the appropriate strings
+                on an earlier line.  */
+             if (pos < ZV || !zv_strings_seen++)
+               {
+                 int ovlen;
+                 char *ovstr;
+                 ovlen = overlay_strings (pos, w, &ovstr);
+                 for (; ovlen; ovlen--, ovstr++)
+                   {
+                     if (p1 >= leftmargin && p1 < endp)
+                       *p1 = MAKE_GLYPH (f, *ovstr, current_face);
+                     p1++;
+                   }
+               }
+
+             /* Did we reach point?  Record the cursor location.  */
+             if (pos == PT && cursor_vpos < 0)
+               {
+                 cursor_vpos = vpos;
+                 cursor_hpos = p1 - leftmargin;
+               }
+
+             if (pos >= ZV)
+               break;
 
-#ifdef USE_TEXT_PROPERTIES
-         /* if the `invisible' property is set to t, we can skip to
-            the next property change */
-         while (pos == next_invisible && pos < end)
-           {
-             Lisp_Object position, limit, endpos, prop, ww;
              XSETFASTINT (position, pos);
-             XSETWINDOW (ww, w);
-             prop = Fget_char_property (position, Qinvisible, ww);
+             limit = Fnext_overlay_change (position);
+#ifdef USE_TEXT_PROPERTIES
              /* This is just an estimate to give reasonable
                 performance; nothing should go wrong if it is too small.  */
-             limit = Fnext_overlay_change (position);
              if (XFASTINT (limit) > pos + 50)
                XSETFASTINT (limit, pos + 50);
-             endpos = Fnext_single_property_change (position, Qinvisible,
-                                                    Fcurrent_buffer (),
-                                                    limit);
-             if (INTEGERP (endpos))
-               next_invisible = XINT (endpos);
-             else
-               next_invisible = end;
+             limit = Fnext_single_property_change (position, Qinvisible,
+                                                   Fcurrent_buffer (), limit);
+#endif
+             next_boundary = XFASTINT (limit);
+             /* if the `invisible' property is set, we can skip to
+                the next property change.  */
+             XSETWINDOW (ww, w);
+             prop = Fget_char_property (position, Qinvisible, ww);
              if (TEXT_PROP_MEANS_INVISIBLE (prop))
                {
-                 if (pos < PT && next_invisible >= PT)
+                 if (pos < PT && next_boundary >= PT)
                    {
                      cursor_vpos = vpos;
                      cursor_hpos = p1 - leftmargin;
                    }
-                 pos = next_invisible;
+                 pos = next_boundary;
                  last_invis_skip = pos;
                  last_invis_prop = prop;
                }
            }
-         if (pos >= end)
-           break;
-#endif
+
+         /* Did we reach point?  Record the cursor location.  */
+         if (pos == PT && cursor_vpos < 0)
+           {
+             cursor_vpos = vpos;
+             cursor_hpos = p1 - leftmargin;
+           }
+
+         /* Did we hit the end of the visible region of the buffer?
+            Stop here.  */
+         if (pos >= ZV)
+           {
+             /* 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
 
-         pause = end;
+         /* Compute the next place we need to stop
+            and do something special; set PAUSE.  */
 
-#ifdef USE_TEXT_PROPERTIES       
-         if (pos < next_invisible && next_invisible < pause)
-           pause = next_invisible;
-#endif
+         pause = ZV;
+
+         if (pos < next_boundary && next_boundary < pause)
+           pause = next_boundary;
          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)
@@ -2596,6 +2858,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
          p = &FETCH_CHAR (pos);
        }
+
+      if (p1 >= endp)
+       break;
+
+      p1prev = p1;
+
       c = *p++;
       /* Let a display table override all standard display methods.  */
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
@@ -2617,7 +2885,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (last_invis_skip == pos
              && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
            invis = 1;
-         while (pos + 1 < end
+         while (pos + 1 < ZV
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
            {
@@ -2645,6 +2913,25 @@ display_text_line (w, start, vpos, hpos, taboffset)
                *p1++ = FAST_MAKE_GLYPH (' ', current_face);
            }
 #endif
+
+         /* Update charstarts for the newline that ended this line.  */
+         /* Do nothing here for a char that's entirely off the left edge
+            or if it starts at the right edge.  */
+         if (p1 >= leftmargin && p1prev != endp)
+           {
+             /* Store the newline's position into charstarts
+                for the column where the newline starts.
+                Store -1 for the rest of the glyphs it occupies.  */
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
+             int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
+
+             *p2x++ = pos;
+             while (p2x < p2)
+               *p2x++ = -1;
+           }
+
          break;
        }
       else if (c == '\t')
@@ -2682,6 +2969,24 @@ display_text_line (w, start, vpos, hpos, taboffset)
                *p1++ = FAST_MAKE_GLYPH (' ', current_face);
            }
 #endif
+
+         /* Update charstarts for the ^M that ended this line.  */
+         /* Do nothing here for a char that's entirely off the left edge
+            or if it starts at the right edge.  */
+         if (p1 >= leftmargin && p1prev != endp)
+           {
+             /* Store the newline's position into charstarts
+                for the column where the newline starts.
+                Store -1 for the rest of the glyphs it occupies.  */
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
+             int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
+
+             *p2x++ = pos;
+             while (p2x < p2)
+               *p2x++ = -1;
+           }
          break;
        }
       else if (c < 0200 && ctl_arrow)
@@ -2713,32 +3018,30 @@ display_text_line (w, start, vpos, hpos, taboffset)
          p1++;
        }
 
+      prevpos = pos;
+      pos++;
+
+      /* Update charstarts for the character just output.  */
+
       /* Do nothing here for a char that's entirely off the left edge.  */
       if (p1 >= leftmargin)
        {
-         /* For all the glyphs occupied by this character, except for the
-            first, store -1 in charstarts.  */
+         /* Store the char's position into charstarts
+            for the first glyph occupied by this char.
+            Store -1 for the rest of the glyphs it occupies.  */
          if (p1 != p1prev)
            {
-             int *p2x = &charstart[p1prev - p1start];
+             int *p2x = &charstart[(p1prev < leftmargin
+                                    ? leftmargin : p1prev)
+                                   - p1start];
              int *p2 = &charstart[(p1 < endp ? p1 : endp) - p1start];
 
-             /* The window's left column should always
-                contain a character position.
-                And don't clobber anything to the left of that.  */
-             if (p1prev < leftmargin)
-               {
-                 p2x = charstart + (leftmargin - p1start);
-                 *p2x = pos;
-               }
-
-             /* This loop skips over the char p2x initially points to.  */
-             while (++p2x < p2)
-               *p2x = -1;
+             if (p2x < p2)
+               *p2x++ = prevpos;
+             while (p2x < p2)
+               *p2x++ = -1;
            }
        }
-
-      pos++;
     }
 
   val.hpos = - XINT (w->hscroll);
@@ -2883,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]);
@@ -2958,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,
@@ -2999,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 */
@@ -3114,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 */
@@ -3126,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,
@@ -3136,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);
                  }
              }
          }
@@ -3276,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;
@@ -3383,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;
@@ -3417,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)
@@ -3474,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);
@@ -3488,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;
 
@@ -3518,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)
@@ -3544,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)
@@ -3746,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);
@@ -3758,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;
 
@@ -3799,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;
@@ -3811,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,
@@ -3864,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);
@@ -3973,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;
@@ -4019,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\
@@ -4058,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 */