]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(SET_RAW_SYNTAX_ENTRY, SYNTAX_ENTRY): Adjusted for the change of
[gnu-emacs] / src / xdisp.c
index fd08f443c0fead1f7db12d51accf069427ee5854..c9aa763edbb3c9c62cbe7a951ba64cfa42d4e44a 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>
@@ -28,22 +29,36 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "charset.h"
 #include "indent.h"
 #include "commands.h"
 #include "macros.h"
 #include "disptab.h"
 #include "termhooks.h"
 #include "intervals.h"
+#include "keyboard.h"
+#include "coding.h"
+#include "process.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;
 extern int command_loop_level;
 
+extern int minibuffer_auto_raise;
+
 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 +69,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 +92,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,12 +132,25 @@ 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;
 
 /* If cursor motion alone moves point off frame,
    Try scrolling this many lines up or down if that will bring it back.  */
-int scroll_step;
+static int scroll_step;
+
+/* Non-0 means scroll just far enough to bring point back on the screen,
+   when appropriate.  */
+static int scroll_conservatively;
+
+/* Recenter the window whenever point gets within this many lines
+   of the top or bottom of the window.  */
+int scroll_margin;
 
 /* Nonzero if try_window_id has made blank lines at window bottom
  since the last redisplay that paused */
@@ -143,24 +168,23 @@ int buffer_shared;
 static int cursor_vpos;
 static int cursor_hpos;
 
-int debug_end_pos;
+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 ();
 static void redisplay_windows ();
 static void redisplay_window ();
-static void update_menu_bars ();
 static void update_menu_bar ();
 static void try_window ();
 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 ();
@@ -181,6 +205,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;
 
@@ -195,13 +224,13 @@ int beg_unchanged;
 int end_unchanged;
 
 /* MODIFF as of last redisplay that finished;
-   if it matches MODIFF, beg_unchanged and end_unchanged
+   if it matches MODIFF, and overlay_unchanged_modified
+   matches OVERLAY_MODIFF, that means beg_unchanged and 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;
+/* OVERLAY_MODIFF as of last redisplay that finished.  */
+int overlay_unchanged_modified;
 
 /* Nonzero if window sizes or contents have changed
    since last redisplay that finished */
@@ -212,12 +241,14 @@ int windows_or_buffers_changed;
 int line_number_displayed;
 
 /* Maximum buffer size for which to display line numbers.  */
-int line_number_display_limit;
+static int line_number_display_limit;
 
 /* Number of lines to keep in the message log buffer.
    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,9 +270,11 @@ 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*")));
+      current_buffer->undo_list = Qt;
       oldpoint = PT;
       oldbegv = BEGV;
       oldzv = ZV;
@@ -306,16 +339,17 @@ 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.
    Return 0 if different, 1 if the new one should just replace it, or a
    value N > 1 if we should also append " [N times]".  */
+
 static int
 message_log_check_duplicate (prev_bol, this_bol)
      int prev_bol, this_bol;
@@ -323,8 +357,8 @@ message_log_check_duplicate (prev_bol, this_bol)
   int i;
   int len = Z - 1 - this_bol;
   int seen_dots = 0;
-  char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
-  char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
+  unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
+  unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
 
   for (i = 0; i < len; i++)
     {
@@ -347,11 +381,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)
@@ -366,7 +405,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -388,33 +427,47 @@ 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)
        {
          echo_area_glyphs = m;
          echo_area_glyphs_length = len;
+
+         if (minibuffer_auto_raise)
+           Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
        }
       else
        echo_area_glyphs = previous_echo_glyphs = 0;
 
       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)
@@ -448,8 +501,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)
@@ -474,18 +528,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)
            {
@@ -496,14 +550,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),
+                           FRAME_MESSAGE_BUF_SIZE (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),
+                           FRAME_MESSAGE_BUF_SIZE (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);
@@ -515,23 +569,37 @@ message (m, a1, a2, a3)
     }
 }
 
+/* The non-logging version of message.  */
+void
+message_nolog (m, a1, a2, a3)
+     char *m;
+     EMACS_INT a1, a2, a3;
+{
+  Lisp_Object old_log_max;
+  old_log_max = Vmessage_log_max;
+  Vmessage_log_max = Qnil;
+  message (m, a1, a2, a3);
+  Vmessage_log_max = old_log_max;
+}
+
 void
 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;
@@ -544,40 +612,59 @@ echo_area_display ()
 
   if (echo_area_glyphs || minibuf_level == 0)
     {
-      vpos = XFASTINT (XWINDOW (minibuf_window)->top);
+      int i;
+
+      echo_area_window = mini_window;
+
+      vpos = XFASTINT (XWINDOW (mini_window)->top);
       get_display_line (f, vpos, 0);
-      display_string (XWINDOW (minibuf_window), vpos,
+
+      /* Make sure the columns that overlap a left-hand scroll bar
+        are always clear.  */
+      for (i = 0; i < FRAME_LEFT_SCROLL_BAR_WIDTH (f); i++)
+       f->desired_glyphs->glyphs[vpos][i] = SPACEGLYPH;
+
+      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));
+                     FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                     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,
-                           "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
+           display_string (XWINDOW (mini_window), vpos,
+                           "", 0, 
+                            FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                           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;
 
@@ -606,9 +693,26 @@ 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;
-  multiple_frames = !EQ (Fnext_frame (frame, Qnil), frame);
+
+  /* Do we have more than one visible frame on this X display?  */
+  {
+    Lisp_Object tail;
+
+    for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
+      {
+       FRAME_PTR tf = XFRAME (XCONS (tail)->car);
+
+       if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f)
+           && !FRAME_MINIBUF_ONLY_P (tf)
+           && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
+         break;
+      }
+
+    multiple_frames = CONSP (tail);
+  }
+
   obuf = current_buffer;
   Fset_buffer (XWINDOW (f->selected_window)->buffer);
   fmt = (FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format);
@@ -632,7 +736,7 @@ x_consider_frame_title (frame)
 #endif
 \f
 /* Prepare for redisplay by updating menu-bar item lists when appropriate.
-   This can't be done in `redisplay' itself because it can call eval.  */
+   This can call eval.  */
 
 void
 prepare_menu_bars ()
@@ -641,34 +745,21 @@ prepare_menu_bars ()
   int all_windows;
   struct gcpro gcpro1, gcpro2;
 
-  if (noninteractive)
-    return;
-
-  /* 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.
-     See the comment in frame.h for FRAME_SAMPLE_VISIBILITY.  */
-  {
-    Lisp_Object tail, frame;
-
-    FOR_EACH_FRAME (tail, frame)
-      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
-  }
-
-  /* Notice any pending interrupt request to change frame size.  */
-  do_pending_window_change ();
-
-  if (frame_garbaged)
-    {
-      redraw_garbaged_frames ();
-      frame_garbaged = 0;
-    }
-
   all_windows = (update_mode_lines || buffer_shared > 1
-                || clip_changed || windows_or_buffers_changed);
-
-#ifdef HAVE_X_WINDOWS
-  if (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;
 
@@ -685,6 +776,9 @@ prepare_menu_bars ()
   if (all_windows)
     {
       Lisp_Object tail, frame;
+      int count = specpdl_ptr - specpdl;
+
+      record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -693,6 +787,8 @@ prepare_menu_bars ()
          if (FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)))
            {
              Lisp_Object functions;
+             /* Clear flag first in case we get error below.  */
+             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
              functions = Vwindow_size_change_functions;
              GCPRO2 (tail, functions);
              while (CONSP (functions))
@@ -701,15 +797,22 @@ prepare_menu_bars ()
                  functions = XCONS (functions)->cdr;
                }
              UNGCPRO;
-             FRAME_WINDOW_SIZES_CHANGED (XFRAME (frame)) = 0;
            }
          GCPRO1 (tail);
-         update_menu_bar (XFRAME (frame));
+         update_menu_bar (XFRAME (frame), 0);
          UNGCPRO;
        }
+
+      unbind_to (count, Qnil);
     }
   else
-    update_menu_bar (selected_frame);
+    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.
@@ -736,8 +839,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;
@@ -749,6 +868,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.
@@ -757,7 +892,13 @@ redisplay ()
     Lisp_Object tail, frame;
 
     FOR_EACH_FRAME (tail, frame)
-      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+      {
+       FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+
+       /* Clear out all the display lines in which we will generate the
+          glyphs to display.  */
+       init_desired_glyphs (XFRAME (frame));
+      }
   }
 
   /* Notice any pending interrupt request to change frame size.  */
@@ -769,20 +910,29 @@ redisplay ()
       frame_garbaged = 0;
     }
 
-  if (clip_changed || windows_or_buffers_changed
-      || (!NILP (w->column_number_displayed)
-         && XFASTINT (w->column_number_displayed) != current_column ()))
+  prepare_menu_bars ();
+
+  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->last_overlay_modified) >= OVERLAY_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;
@@ -791,7 +941,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
@@ -815,6 +965,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
@@ -825,7 +976,8 @@ redisplay ()
       && PT <= Z - tlendpos
       /* All text outside that line, including its final newline,
         must be unchanged */
-      && (XFASTINT (w->last_modified) >= MODIFF
+      && ((XFASTINT (w->last_modified) >= MODIFF
+          && (XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF))
          || (beg_unchanged >= tlbufpos - 1
              && GPT >= tlbufpos
              /* If selective display, can't optimize
@@ -838,18 +990,49 @@ redisplay ()
              && end_unchanged >= tlendpos
              && Z - GPT >= tlendpos)))
     {
-      if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
+      if (tlbufpos > BEGV && FETCH_BYTE (tlbufpos - 1) != '\n'
          && (tlbufpos == ZV
-             || FETCH_CHAR (tlbufpos) == '\n'))
+             || FETCH_BYTE (tlbufpos) == '\n'))
        /* Former continuation line has disappeared by becoming empty */
        goto cancel;
       else if (XFASTINT (w->last_modified) < MODIFF
+              || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF
               || MINI_WINDOW_P (w))
        {
+         /* We have to handle the case of continuation around a
+            wide-column character (See the comment in indent.c around
+            line 885).
+
+            For instance, in the following case:
+
+            --------  Insert  --------
+            K_A_N_\\   `a'    K_A_N_a\         `X_' are wide-column chars.
+            J_I_       ==>    J_I_             `^^' are cursors.
+            ^^                ^^
+            --------          --------
+
+            As we have to redraw the line above, we should goto cancel.  */
+
+         struct position val;
+         int prevline;
+
+         prevline = find_next_newline (tlbufpos, -1);
+         val = *compute_motion (prevline, 0,
+                                XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
+                                0,
+                                tlbufpos,
+                                1 << (BITS_PER_SHORT - 1),
+                                1 << (BITS_PER_SHORT - 1),
+                                window_internal_width (w) - 1,
+                                XINT (w->hscroll), 0, w);
+         if (val.hpos != this_line_start_hpos)
+           goto cancel;
+
          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));
+                            pos_tab_offset (w, tlbufpos), 0);
          /* If line contains point, is not continued,
                 and ends at same distance from eob as before, we win */
          if (cursor_vpos >= 0 && this_line_bufpos
@@ -860,7 +1043,7 @@ redisplay ()
              if (this_line_vpos + 1
                  < XFASTINT (w->top) + window_internal_height (w))
                {
-                 int left = XFASTINT (w->left);
+                 int left = WINDOW_LEFT_MARGIN (w);
                  int *charstart_next_line
                    = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
                  int adjust;
@@ -878,14 +1061,19 @@ redisplay ()
                  adjust_window_charstarts (w, this_line_vpos, adjust);
                }
 
-             if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
+             if (!WINDOW_FULL_WIDTH_P (w))
                preserve_other_columns (w);
              goto update;
            }
          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)
            {
@@ -894,21 +1082,26 @@ redisplay ()
            }
          goto update;
        }
-      /* If highlighting the region, we can't just move the cursor.  */
+      /* If highlighting the region, or if the cursor is in the echo area,
+        then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && NILP (w->region_showing))
+              && 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);
+               = WINDOW_LEFT_MARGIN (w) + minmax (0, pos.hpos, width);
              FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
              goto update;
            }
@@ -946,7 +1139,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
@@ -955,7 +1148,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.  */
@@ -966,8 +1159,8 @@ redisplay ()
     }
   else if (FRAME_VISIBLE_P (selected_frame))
     {
-      redisplay_window (selected_window, 1);
-      if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
+      redisplay_window (selected_window, 1, preserve_echo_area);
+      if (!WINDOW_FULL_WIDTH_P (w))
        preserve_other_columns (w);
     }
 
@@ -979,7 +1172,6 @@ update:
     unrequest_sigio ();
   stop_polling ();
 
-#ifdef MULTI_FRAME
   if (all_windows)
     {
       Lisp_Object tail;
@@ -994,7 +1186,9 @@ update:
            continue;
 
          f = XFRAME (XCONS (tail)->car);
-         if (FRAME_VISIBLE_P (f))
+
+         if ((FRAME_WINDOW_P (f) || f == selected_frame)
+             && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
              if (!pause)
@@ -1007,7 +1201,6 @@ update:
        }
     }
   else
-#endif /* MULTI_FRAME */
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
@@ -1020,10 +1213,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);
       }
     }
@@ -1042,7 +1238,7 @@ update:
         may be null, so preserve_other_columns won't be able to
         preserve all the vertical-bar separators.  So, avoid using it
         in that case.  */
-      if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
+      if (!WINDOW_FULL_WIDTH_P (w))
        update_mode_lines = 1;
     }
 
@@ -1054,8 +1250,8 @@ update:
       register struct buffer *b = XBUFFER (w->buffer);
 
       blank_end_of_window = 0;
-      clip_changed = 0;
       unchanged_modified = BUF_MODIFF (b);
+      overlay_unchanged_modified = BUF_OVERLAY_MODIFF (b);
       beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
       end_unchanged = BUF_Z (b) - BUF_GPT (b);
 
@@ -1067,8 +1263,13 @@ 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));
+         XSETFASTINT (w->last_overlay_modified, BUF_OVERLAY_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;
@@ -1114,11 +1315,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
@@ -1137,10 +1338,16 @@ mark_window_display_accurate (window, flag)
        {
          XSETFASTINT (w->last_modified,
                       !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
+         XSETFASTINT (w->last_overlay_modified,
+                      !flag ? 0 : BUF_OVERLAY_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);
@@ -1148,6 +1355,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);
@@ -1170,28 +1379,33 @@ mark_window_display_accurate (window, flag)
 \f
 /* Update the menu bar item list for frame F.
    This has to be done before we start to fill in any display lines,
-   because it can call eval.  */
+   because it can call eval.
+
+   If SAVE_MATCH_DATA is 1, we must save and restore it here.  */
 
 static void
-update_menu_bar (f)
+update_menu_bar (f, save_match_data)
      FRAME_PTR f;
+     int save_match_data;
 {
   struct buffer *old = current_buffer;
   Lisp_Object window;
   register struct window *w;
+
   window = FRAME_SELECTED_WINDOW (f);
   w = XWINDOW (window);
   
   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
@@ -1202,18 +1416,49 @@ update_menu_bar (f)
         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;
-         call1 (Vrun_hooks, Qmenu_bar_update_hook);
-         current_buffer = XBUFFER (w->buffer);
+         int count = specpdl_ptr - specpdl;
+
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+         if (save_match_data)
+           record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
+         if (NILP (Voverriding_local_map_menu_flag))
+           {
+             specbind (Qoverriding_terminal_local_map, Qnil);
+             specbind (Qoverriding_local_map, Qnil);
+           }
+
+         /* 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);
        }
     }
 }
@@ -1223,19 +1468,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));
@@ -1249,6 +1495,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 */
 
@@ -1256,12 +1503,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))
@@ -1269,26 +1516,27 @@ 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++)
            {
              get_display_line (f, vpos + i, 0);
-             display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
+             display_string (w, vpos + i, "", 0, 
+                             FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                             0, 1, 0, width);
            }
          
          goto finish_scroll_bars;
@@ -1298,12 +1546,22 @@ 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->last_overlay_modified) >= OVERLAY_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.  */
 
@@ -1347,7 +1605,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)))
@@ -1365,22 +1623,62 @@ redisplay_window (window, just_this_one)
 
   startp = marker_position (w->start);
 
+  /* If someone specified a new starting point but did not insist,
+     check whether it can be used.  */
+  if (!NILP (w->optional_new_start))
+    {
+      w->optional_new_start = Qnil;
+      /* Check whether this start pos is usable given where point is.  */
+
+      pos = *compute_motion (startp, 0,
+                            (((EQ (window, minibuf_window)
+                               && startp == BEG)
+                              ? minibuf_prompt_width : 0)
+                             + (hscroll ? 1 - hscroll : 0)),
+                            0,
+                            PT, height, 
+                            /* BUG FIX: See the comment of
+                                Fpos_visible_in_window_p (window.c).  */
+                            - (1 << (BITS_PER_SHORT - 1)),
+                            width, hscroll, pos_tab_offset (w, startp), w);
+      /* If PT does fit on the screen, we will use this start pos,
+        so do so by setting force_start.  */
+      if (pos.bufpos == PT)
+       w->force_start = Qt;
+    }
+
   /* Handle case where place to start displaying has been specified,
      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);
+      XSETFASTINT (w->last_overlay_modified, 0);
       if (startp < BEGV) startp = BEGV;
       if (startp > ZV)   startp = ZV;
       try_window (window, startp);
@@ -1388,13 +1686,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);
@@ -1402,7 +1701,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) = (WINDOW_LEFT_MARGIN (w)
+                                   + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
          /* If we are highlighting the region,
@@ -1418,7 +1718,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;
@@ -1428,8 +1728,9 @@ redisplay_window (window, just_this_one)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
-      && PT >= startp && !clip_changed
-      && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF
+      && PT >= startp && !current_buffer->clip_changed
+      && (just_this_one || WINDOW_FULL_WIDTH_P (w))
       /* If force-mode-line-update was called, really redisplay;
         that's how redisplay is forced after e.g. changing
         buffer-invisibility-spec.  */
@@ -1442,24 +1743,41 @@ 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),
-                           PT, height, 0, width, hscroll,
-                           pos_tab_offset (w, startp), w);
-
-      if (pos.vpos < height)
+      int this_scroll_margin = scroll_margin;
+
+      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
+                            PT, height,
+                            /* BUG FIX: See the comment of
+                                Fpos_visible_in_window_p (window.c).  */
+                            - (1 << (BITS_PER_SHORT - 1)),
+                            width, hscroll,
+                            pos_tab_offset (w, startp), w);
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+
+      if (XINT (w->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      /* If point fits on the screen, and not within the scroll margin,
+        we are ok.  */
+      if (pos.vpos < height - this_scroll_margin
+         && (pos.vpos >= this_scroll_margin || startp == BEGV))
        {
          /* Ok, point is still on frame */
          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) = (WINDOW_LEFT_MARGIN (w)
+                                   + 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
             this one must be redisplayed, this does nothing because there
             is nothing in DesiredFrame yet, and then the other window is
             redisplayed, making likes that are empty in this window's columns.
-            if (XFASTINT (w->width) != FRAME_WIDTH (f))
+            if (WINDOW_FULL_WIDTH_P (w))
             preserve_my_columns (w);
             */
          goto done;
@@ -1471,7 +1789,7 @@ redisplay_window (window, just_this_one)
      but no longer is, find a new starting point.  */
   else if (!NILP (w->start_at_line_beg)
           && !(startp <= BEGV
-               || FETCH_CHAR (startp - 1) == '\n'))
+               || FETCH_BYTE (startp - 1) == '\n'))
     {
       goto recenter;
     }
@@ -1481,12 +1799,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)
+          && WINDOW_FULL_WIDTH_P (w)
           /* 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)
@@ -1501,16 +1822,26 @@ 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
-              || (XFASTINT (w->last_modified) >= MODIFF)))
+          && (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
+                  && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
     {
       /* Try to redisplay starting at same place as before */
       /* If point has not moved off frame, accept the results */
       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;
@@ -1520,36 +1851,121 @@ redisplay_window (window, just_this_one)
     }
 
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   /* Redisplay the mode line.  Select the buffer properly for that.  */
   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_conservatively && !current_buffer->clip_changed
+      && startp >= BEGV && startp <= ZV)
+    {
+      int this_scroll_margin = scroll_margin;
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+
+      if (XINT (w->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      if (PT >= Z - XFASTINT (w->window_end_pos))
+       {
+         struct position pos;
+         pos = *compute_motion (Z - XFASTINT (w->window_end_pos), 0, 0, 0,
+                                PT, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp), w);
+         if (pos.vpos > scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, pos.vpos + 1 + this_scroll_margin, w);
+
+         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 || current_buffer->clip_changed
+                 || beg_unchanged < startp)
+               /* Forget any recorded base line for line number display.  */
+               w->base_line_number = Qnil;
+             goto done;
+           }
+         else
+           cancel_my_columns (w);
+       }
+      if (PT < startp)
+       {
+         struct position pos;
+         pos = *compute_motion (PT, 0, 0, 0,
+                                startp, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp), w);
+         if (pos.vpos >= scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, - pos.vpos - this_scroll_margin, w);
+
+         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 || current_buffer->clip_changed
+                 || beg_unchanged < startp)
+               /* Forget any recorded base line for line number display.  */
+               w->base_line_number = Qnil;
+             goto done;
+           }
+         else
+           cancel_my_columns (w);
+       }
+    scroll_fail_1: ;
+    }
+
+  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;
@@ -1566,18 +1982,27 @@ 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 
-    = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
+  w->start_at_line_beg
+    = (startp == BEGV || FETCH_BYTE (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
   if ((update_mode_line
        /* If window not full width, must redo its mode line
          if the window to its side is being redone */
-       || (!just_this_one && width < FRAME_WIDTH (f) - 1)
+       || (!just_this_one && !WINDOW_FULL_WIDTH_P (w))
        || INTEGERP (w->base_line_pos)
        || (!NILP (w->column_number_displayed)
           && XFASTINT (w->column_number_displayed) != current_column ()))
@@ -1592,11 +2017,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);
 
@@ -1637,7 +2065,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;
@@ -1654,29 +2082,33 @@ try_window (window, pos)
   register int height = window_internal_height (w);
   register int vpos = XFASTINT (w->top);
   register int last_text_vpos = vpos;
-  int tab_offset = pos_tab_offset (w, pos);
   FRAME_PTR f = XFRAME (w->frame);
   int width = window_internal_width (w) - 1;
   struct position val;
 
+  /* POS should never be out of range!  */
+  if (pos < XBUFFER (w->buffer)->begv
+      || pos > XBUFFER (w->buffer)->zv)
+    abort ();
+
   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;
+  val.ovstring_chars_done = 0;
+  val.tab_offset = pos_tab_offset (w, pos);
 
   while (--height >= 0)
     {
-      val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
+      val = *display_text_line (w, pos, vpos, val.hpos, val.tab_offset,
+                               val.ovstring_chars_done);
+      /* The following code is omitted because we maintain tab_offset
+         in VAL.  */
+#if 0
       tab_offset += width;
-      /* For the first line displayed, display_text_line
-        subtracts the prompt width from the tab offset.
-        But it does not affect the value of our variable tab_offset.
-        So we do the subtraction again,
-        for the sake of continuation lines of that first line.  */
-      if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
-       tab_offset -= minibuf_prompt_width;
-
       if (val.vpos) tab_offset = 0;
+#endif  /* 0 */
       vpos++;
       if (pos != val.bufpos)
        {
@@ -1690,7 +2122,7 @@ try_window (window, pos)
          last_text_vpos
            /* Next line, unless prev line ended in end of buffer with no cr */
            = vpos - (val.vpos
-                     && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
+                     && (FETCH_BYTE (val.bufpos - 1) != '\n' || invis));
        }
       pos = val.bufpos;
     }
@@ -1732,6 +2164,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;
@@ -1743,7 +2176,7 @@ try_window_id (window)
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
   int delta;
-  int tab_offset, epto;
+  int epto, old_tick;
 
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
@@ -1754,19 +2187,25 @@ 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,
-                       min (ZV, beg_unchanged + BEG), height, 0,
+  bp = *compute_motion (start, 0, lmargin, 0,
+                       min (ZV, beg_unchanged + BEG), height,
+                       /* BUG FIX: See the comment of
+                           Fpos_visible_in_window_p() (window.c).  */
+                       - (1 << (BITS_PER_SHORT - 1)),
                        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,
+                               /* BUG FIX: See the comment of
+                                   Fpos_visible_in_window_p() (window.c).  */
+                               - (1 << (BITS_PER_SHORT - 1)),
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
@@ -1778,13 +2217,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 */
@@ -1793,15 +2233,18 @@ 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;
     }
+  val.tab_offset = bp.tab_offset; /* Update tab offset.  */
 
   if (bp.contin && bp.hpos != lmargin)
     {
       val.hpos = bp.prevhpos - width + lmargin;
-      pos--;
+      val.tab_offset = bp.tab_offset + bp.prevhpos - width;
+      did_motion = 1;
+      DEC_POS (pos);
     }
 
   bp.vpos = vpos;
@@ -1813,9 +2256,11 @@ 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)),
-                       width, hscroll, pos_tab_offset (w, bp.bufpos), w);
+  ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
+                       height, - (1 << (BITS_PER_SHORT - 1)),
+                       width, hscroll,
+                       /* We have tab offset in VAL, use it.  */
+                       val.tab_offset, w); 
 
   /* If changes reach past the text available on the frame,
      just display rest of frame.  */
@@ -1831,29 +2276,33 @@ try_window_id (window)
      newline before it, so the following line must be redrawn. */
   if (stop_vpos == ep.vpos
       && (ep.bufpos == BEGV
-         || FETCH_CHAR (ep.bufpos - 1) != '\n'
+         || FETCH_BYTE (ep.bufpos - 1) != '\n'
          || ep.bufpos == Z - end_unchanged))
     stop_vpos = ep.vpos + 1;
 
   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 */
   if (stop_vpos < height)
     {
       /* 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);
+                           /* Don't care for VPOS... */
+                           1 << (BITS_PER_SHORT - 1),
+                           /* ... nor HPOS.  */
+                           1 << (BITS_PER_SHORT - 1),
+                           width, hscroll, ep.tab_offset, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
 
       /* Is everything on frame below the changes whitespace?
         If so, no scrolling is really necessary.  */
       for (i = ep.bufpos; i < xp.bufpos; i++)
        {
-         tem = FETCH_CHAR (i);
+         tem = FETCH_BYTE (i);
          if (tem != ' ' && tem != '\n' && tem != '\t')
            break;
        }
@@ -1864,25 +2313,28 @@ try_window_id (window)
                   XFASTINT (w->window_end_vpos) + scroll_amount);
 
       /* Before doing any scrolling, verify that point will be on frame. */
-      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
+      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.vpos < height))
        {
          if (PT <= xp.bufpos)
            {
-             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
-                                   PT, height, - (1 << (SHORTBITS - 1)),
-                                   width, hscroll, epto, w);
+             pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
+                                   PT, height, - (1 << (BITS_PER_SHORT - 1)),
+                                   width, hscroll,
+                                   /* We have tab offset in EP, use it.  */
+                                   ep.tab_offset, 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);
+                                   /* We have tab offset in XP, use it. */
+                                   xp.tab_offset, w);
            }
          if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
-         cursor_hpos = pp.hpos + XFASTINT (w->left);
+         cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, pp.hpos, width);
        }
 
       if (stop_vpos - scroll_amount >= height
@@ -1934,8 +2386,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.  */
@@ -1980,20 +2432,35 @@ try_window_id (window)
 
   /* Redisplay the lines where the text was changed */
   last_text_vpos = vpos;
+  /* The following code is omitted because we maintain tab offset in
+     val.tab_offset.  */
+#if 0
   tab_offset = pos_tab_offset (w, pos);
   /* If we are starting display in mid-character, correct tab_offset
      to account for passing the line that that character really starts in.  */
   if (val.hpos < lmargin)
     tab_offset += width;
+#endif /* 0 */
+  old_tick = MODIFF;
   while (vpos < stop_vpos)
     {
-      val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+      val = *display_text_line (w, pos, top + vpos++, val.hpos, val.tab_offset,
+                               val.ovstring_chars_done);
+      /* 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;
+      /* The following code is omitted because we maintain tab offset
+        in val.tab_offset.  */
+#if 0
       tab_offset += width;
       if (val.vpos) tab_offset = 0;
+#endif
       if (pos != val.bufpos)
        last_text_vpos
          /* Next line, unless prev line ended in end of buffer with no cr */
-           = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
+           = vpos - (val.vpos && FETCH_BYTE (val.bufpos - 1) != '\n');
       pos = val.bufpos;
     }
 
@@ -2020,27 +2487,41 @@ try_window_id (window)
       FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
       vpos = xp.vpos;
       pos = xp.bufpos;
-      val.hpos = lmargin;
+      val.hpos = xp.hpos;
+      val.tab_offset = xp.tab_offset;
       if (pos == ZV)
-       vpos = height + scroll_amount;
+       { /* Display from next line */
+         vpos = height + scroll_amount;
+         val.hpos = lmargin;
+         val.tab_offset = 0;
+       }
       else if (xp.contin && xp.hpos != lmargin)
        {
          val.hpos = xp.prevhpos - width + lmargin;
-         pos--;
+         val.tab_offset = xp.tab_offset + bp.prevhpos - width;
+         DEC_POS (pos);
        }
 
       blank_end_of_window = 1;
+      /* The following code is omitted because we maintain tab offset
+        in val.tab_offset.  */
+#if 0
       tab_offset = pos_tab_offset (w, pos);
       /* If we are starting display in mid-character, correct tab_offset
         to account for passing the line that that character starts in.  */
       if (val.hpos < lmargin)
        tab_offset += width;
-
+#endif
       while (vpos < height)
        {
-         val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+         val = *display_text_line (w, pos, top + vpos++, val.hpos,
+                                   val.tab_offset, val.ovstring_chars_done);
+         /* The following code is omitted because we maintain tab
+            offset in val.tab_offset.  */
+#if 0
          tab_offset += width;
          if (val.vpos) tab_offset = 0;
+#endif /* 0 */
          pos = val.bufpos;
        }
 
@@ -2064,8 +2545,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);
@@ -2078,7 +2558,11 @@ 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, 
+                            /* Don't care for VPOS...  */
+                            1 << (BITS_PER_SHORT - 1),
+                            /* ... nor HPOS.  */
+                            1 << (BITS_PER_SHORT - 1),
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
@@ -2088,16 +2572,16 @@ try_window_id (window)
          return 0;
        }
       cursor_vpos = val.vpos + top;
-      cursor_hpos = val.hpos + XFASTINT (w->left);
+      cursor_hpos = WINDOW_LEFT_MARGIN (w) + 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 ();
@@ -2108,76 +2592,6 @@ try_window_id (window)
 
   return 1;
 }
-\f
-/* Mark a section of BUF as modified, but only for the sake of redisplay.
-   This is useful for recording changes to overlays.
-
-   We increment the buffer's modification timestamp and set the
-   redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
-   as if the region of text between START and END had been modified;
-   the redisplay code will check this against the windows' timestamps,
-   and redraw the appropriate area of the buffer.
-
-   However, if the buffer is unmodified, we bump the last-save
-   timestamp as well, so that incrementing the timestamp doesn't fool
-   Emacs into thinking that the buffer's text has been modified. 
-
-   Tweaking the timestamps shouldn't hurt the first-modification
-   timestamps recorded in the undo records; those values aren't
-   written until just before a real text modification is made, so they
-   will never catch the timestamp value just before this function gets
-   called.  */
-
-void
-redisplay_region (buf, start, end)
-     struct buffer *buf;
-     int start, end;
-{
-  if (start == end)
-    return;
-
-  if (start > end)
-    {
-      int temp = start;
-      start = end; end = temp;
-    }
-
-  /* If this is a buffer not in the selected window,
-     we must do other windows.  */
-  if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
-    windows_or_buffers_changed = 1;
-  /* If it's not current, we can't use beg_unchanged, end_unchanged for it.  */
-  else if (buf != current_buffer)
-    windows_or_buffers_changed = 1;
-  /* If multiple windows show this buffer, we must do other windows.  */
-  else if (buffer_shared > 1)
-    windows_or_buffers_changed = 1;
-  else
-    {
-      if (unchanged_modified == MODIFF)
-       {
-         beg_unchanged = start - BEG;
-         end_unchanged = Z - end;
-       }
-      else
-       {
-         if (Z - end < end_unchanged)
-           end_unchanged = Z - end;
-         if (start - BEG < beg_unchanged)
-           beg_unchanged = start - BEG;
-       }
-    }
-
-  /* Increment the buffer's time stamp, but also increment the save
-     and autosave timestamps, so as not to screw up that timekeeping.  */
-  if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
-    BUF_SAVE_MODIFF (buf)++;
-  if (BUF_MODIFF (buf) == buf->auto_save_modified)
-    buf->auto_save_modified++;
-
-  BUF_MODIFF (buf) ++;
-}
-
 \f
 /* Copy LEN glyphs starting address FROM to the rope TO.
    But don't actually copy the parts that would come in before S.
@@ -2203,8 +2617,13 @@ copy_part_of_rope (f, to, s, from, len, face)
   if (! FRAME_TERMCAP_P (f))
     while (n--)
       {
-       int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
+       GLYPH glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        int facecode;
+       unsigned int c = FAST_GLYPH_CHAR (glyph);
+
+       if (c > MAX_CHAR)
+         /* For an invalid character code, use space.  */
+         c = ' ';
 
        if (FAST_GLYPH_FACE (glyph) == 0)
          /* If GLYPH has no face code, use FACE.  */
@@ -2220,7 +2639,7 @@ copy_part_of_rope (f, to, s, from, len, face)
          }
 
        if (to >= s)
-         *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
+         *to = FAST_MAKE_GLYPH (c, facecode);
        ++to;
        ++fp;
       }
@@ -2267,6 +2686,9 @@ fix_glyph (f, glyph, cface)
 
    TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
 
+   OVSTR_DONE is the number of chars of overlay before/after strings
+   at this position which have already been processed.
+
    Display on position VPOS on the frame.  It is origin 0, relative to
    the top of the frame, not W.
 
@@ -2277,23 +2699,24 @@ fix_glyph (f, glyph, cface)
 struct position val_display_text_line;
 
 static struct position *
-display_text_line (w, start, vpos, hpos, taboffset)
+display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
      struct window *w;
      int start;
      int vpos;
      int hpos;
      int taboffset;
+     int ovstr_done;
 {
   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);
@@ -2307,19 +2730,20 @@ display_text_line (w, start, vpos, hpos, taboffset)
   int hscroll = XINT (w->hscroll);
   int truncate = (hscroll
                  || (truncate_partial_width_windows
-                     && XFASTINT (w->width) < FRAME_WIDTH (f))
+                     && !WINDOW_FULL_WIDTH_P (w))
                  || !NILP (current_buffer->truncate_lines));
 
   /* 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
@@ -2338,19 +2762,29 @@ display_text_line (w, start, vpos, hpos, taboffset)
        : default_invis_vector);
 
   GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
+                    || !GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (dp)))
                     ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
   GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
+                    || !GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (dp)))
                     ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
 
+  /* If 1, we must handle multibyte characters.  */
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  /* Length of multibyte form of each character.  */
+  int len;
+  /* Glyphs generated should be set this bit mask if text must be
+     displayed from right to left.  */
+  GLYPH rev_dir_bit = (NILP (current_buffer->direction_reversed)
+                      ? 0 : GLYPH_MASK_REV_DIR);
+
   /* The next buffer location at which the face should change, due
      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;
@@ -2358,8 +2792,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   XSETFASTINT (default_invis_vector[2], '.');
   default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
 
-  hpos += XFASTINT (w->left);
-  get_display_line (f, vpos, XFASTINT (w->left));
+  hpos += WINDOW_LEFT_MARGIN (w);
+  get_display_line (f, vpos, WINDOW_LEFT_MARGIN (w));
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
   /* Show where to highlight the region.  */
@@ -2382,7 +2816,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))
@@ -2405,16 +2839,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
@@ -2428,7 +2860,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
       if (left_edge->vpos > vpos
           || left_edge->hpos > 0)
         {
-          pos = left_edge->bufpos - 1;
+          pos = left_edge->bufpos;
+         /* Since this should not be a valid multibyte character, we
+             can decrease POS by 1.  */
+         pos--;
           hpos = left_edge->prevhpos;
         }
       else
@@ -2443,8 +2878,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   p1start = p1;
   charstart = desired_glyphs->charstarts[vpos] + hpos;
   /* In case we don't ever write anything into it...  */
-  desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
-  leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+  desired_glyphs->charstarts[vpos][WINDOW_LEFT_MARGIN (w)] = -1;
+  leftmargin = desired_glyphs->glyphs[vpos] + WINDOW_LEFT_MARGIN (w);
   endp = leftmargin + width;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
@@ -2460,90 +2895,195 @@ 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;
 
-#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);
-             /* This is just an estimate to give reasonable
-                performance; nothing should go wrong if it is too small.  */
+             /* 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;
+                 unsigned char *ovstr;
+                 ovlen = overlay_strings (pos, w, &ovstr);
+
+                 if (ovlen > 0)
+                   {
+                     /* Skip the ones we did in a previous line.  */
+                     ovstr += ovstr_done;
+                     ovlen -= ovstr_done;
+
+                     while (ovlen > 0)
+                       {
+                         int charset, cols;
+                         GLYPH g;
+
+                         if (multibyte)
+                           {
+                             c = STRING_CHAR_AND_LENGTH (ovstr, ovlen, len);
+                             ovstr += len, ovlen -= len, ovstr_done += len;
+                             charset = CHAR_CHARSET (c);
+                             cols = (charset == CHARSET_COMPOSITION
+                                     ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                                     : CHARSET_WIDTH (charset));
+                           }
+                         else
+                           {
+                             c = *ovstr++, ovlen--, ovstr_done++;
+                             cols = 1;
+                           }
+                         g = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
+                         while (cols-- > 0)
+                           {
+                             if (p1 >= leftmargin && p1 < endp)
+                               *p1 = g, g |= GLYPH_MASK_PADDING;
+                             p1++;
+                           }
+                       }
+                     /* If we did all the overlay strings
+                        and we have room for text, clear ovstr_done
+                        just for neatness' sake.  */
+                     if (ovlen == 0 && p1 < endp)
+                       ovstr_done = 0;
+                   }
+               }
+
+             /* 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;
+
+             XSETFASTINT (position, pos);
              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.  */
              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;
+               {
+                 int limitpos = pos + 50;
+                 if (limitpos < Z)
+                   INC_POS (limitpos); /* Adjust to character boundary.  */
+                 XSETFASTINT (limit, limitpos);
+               }
+             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))
-           current_face = compute_char_face (f, w, pos,
-                                             region_beg, region_end,
-                                             &next_face_change, pos + 50, 0);
+         if (pos >= next_face_change
+             && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
+           {
+             int limit = pos + 50;
+
+             if (limit < Z && !CHAR_HEAD_P (POS_ADDR (limit)))
+               INC_POS (limit); /* Adjust to character boundary.  */
+             current_face = compute_char_face (f, w, pos,
+                                               region_beg, region_end,
+                                               &next_face_change, limit, 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)
@@ -2551,21 +3091,31 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
-         p = &FETCH_CHAR (pos);
+         p = POS_ADDR (pos);
        }
-      c = *p++;
+
+      if (p1 >= endp)
+       break;
+
+      p1prev = p1;
+
+      if (multibyte)
+       /* PAUSE is surely at character boundary.  */
+       c = STRING_CHAR_AND_LENGTH (p, pause - pos, len), p += len;
+      else
+       c = *p++, len = 1;
       /* Let a display table override all standard display methods.  */
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          p1 = copy_part_of_rope (f, p1, leftmargin,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 current_face);
+                                 current_face, rev_dir_bit);
        }
       else if (c >= 040 && c < 0177)
        {
          if (p1 >= leftmargin)
-           *p1 = MAKE_GLYPH (f, c, current_face);
+           *p1 = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
          p1++;
        }
       else if (c == '\n')
@@ -2574,13 +3124,13 @@ 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))
            {
              invis = 1;
              pos = find_next_newline (pos + 1, 1);
-             if (FETCH_CHAR (pos - 1) == '\n')
+             if (FETCH_BYTE (pos - 1) == '\n')
                pos--;
            }
          if (invis && selective_rlen > 0 && p1 >= leftmargin)
@@ -2589,7 +3139,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
+                                (p1 - p1prev), current_face, rev_dir_bit);
            }
 #ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
@@ -2599,9 +3149,28 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 < leftmargin)
                p1 = leftmargin;
              while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
            }
 #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')
@@ -2609,7 +3178,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          do
            {
              if (p1 >= leftmargin && p1 < endp)
-               *p1 = MAKE_GLYPH (f, ' ', current_face);
+               *p1 = MAKE_GLYPH (f, ' ', current_face) | rev_dir_bit;
              p1++;
            }
          while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
@@ -2618,7 +3187,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c == Ctl ('M') && selective == -1)
        {
          pos = find_next_newline (pos, 1);
-         if (FETCH_CHAR (pos - 1) == '\n')
+         if (FETCH_BYTE (pos - 1) == '\n')
            pos--;
          if (selective_rlen > 0)
            {
@@ -2626,7 +3195,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
+                                (p1 - p1prev), current_face, rev_dir_bit);
            }
 #ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
@@ -2636,66 +3205,106 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 < leftmargin)
                p1 = leftmargin;
              while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
            }
 #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)
        {
          if (p1 >= leftmargin)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
-                                ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
-                            current_face);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (dp)))
+                       ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+                   current_face)
+                  | rev_dir_bit);
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
+           *p1 = MAKE_GLYPH (f, c ^ 0100, current_face) | rev_dir_bit;
          p1++;
        }
-      else
+      else if (len == 1)
        {
+         /* C is not a multibyte character.  */
          if (p1 >= leftmargin)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-                                ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-                            current_face);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (DISP_ESCAPE_GLYPH (dp))
+                       ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
+                   current_face)
+                  | rev_dir_bit);
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
+           *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face) | rev_dir_bit;
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
+           *p1 = (MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face)
+                  | rev_dir_bit);
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
+           *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face) | rev_dir_bit;
          p1++;
        }
+      else
+       {
+         /* C is a multibyte character.  */
+         int charset = CHAR_CHARSET (c);
+         int columns = (charset == CHARSET_COMPOSITION
+                        ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                        : CHARSET_WIDTH (charset));
+         GLYPH g = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
+
+         while (columns--)
+           {
+             if (p1 >= leftmargin && p1 < endp)
+               *p1 = g, g |= GLYPH_MASK_PADDING;
+             p1++;
+           }
+       }
+
+      prevpos = pos;
+      pos += len;
+
+      /* 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);
@@ -2726,10 +3335,37 @@ display_text_line (w, start, vpos, hpos, taboffset)
         This occurs when the minibuffer prompt takes up the whole line.  */
       if (p1prev)
        {
-         /* Start the next line with that same character */
-         pos--;
-         /* but at negative hpos, to skip the columns output on this line.  */
-         val.hpos += p1prev - endp;
+         /* Start the next line with that same character whose
+             character code is C and the length of multi-byte form is
+             LEN.  */
+         pos = prevpos;
+
+         if (len == 1)
+           /* C is not a multi-byte character.  We can break it and
+              start from the middle column in the next line.  So,
+              adjust VAL.HPOS to skip the columns output on this
+              line.  */
+           val.hpos += p1prev - endp;
+         else
+           {
+             /* C is a multibyte character.  Since we can't broke it
+                in the middle, the whole character should be driven
+                into the next line.  */
+             /* As the result, the actual columns occupied by the
+                text on this line is less than WIDTH.  VAL.TAB_OFFSET
+                must be adjusted.  */
+             taboffset = taboffset + (p1prev - endp);
+             /* Let's fill unused columns with TRUNCATOR or CONTINUER.  */
+             {
+               GLYPH g = fix_glyph (f, truncate ? truncator : continuer, 0);
+               while (p1prev < endp)
+                 *p1prev++ = g;
+             }
+             /* If POINT is at POS, cursor should not on this line.  */
+             lastpos = pos;
+             if (PT == pos)
+               cursor_vpos = -1;
+           }
        }
 
       /* Keep in this line everything up to the continuation column.  */
@@ -2743,10 +3379,11 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   if (pos < ZV)
     {
-      if (FETCH_CHAR (pos) == '\n')
+      if (FETCH_BYTE (pos) == '\n')
        {
          /* If stopped due to a newline, start next line after it */
          pos++;
+         val.tab_offset = 0;
          /* Check again for hidden lines, in case the newline occurred exactly
             at the right margin.  */
          while (pos < ZV && selective > 0
@@ -2768,16 +3405,20 @@ display_text_line (w, start, vpos, hpos, taboffset)
                     && indented_beyond_p (pos, selective));
              val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
 
-             lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
+             lastpos = pos - (FETCH_BYTE (pos - 1) == '\n');
+             val.tab_offset = 0;
            }
          else
            {
              *p1++ = fix_glyph (f, continuer, 0);
              val.vpos = 0;
              lastpos--;
+             val.tab_offset = taboffset + width;
            }
        }
     }
+  else
+    val.tab_offset = 0;
 
   /* If point is at eol or in invisible text at eol,
      record its frame location now.  */
@@ -2792,17 +3433,21 @@ display_text_line (w, start, vpos, hpos, taboffset)
     {
       if (cursor_hpos < 0) cursor_hpos = 0;
       if (cursor_hpos > width) cursor_hpos = width;
-      cursor_hpos += XFASTINT (w->left);
+      cursor_hpos += WINDOW_LEFT_MARGIN (w);
       if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
        {
-         FRAME_CURSOR_Y (f) = cursor_vpos;
-         FRAME_CURSOR_X (f) = cursor_hpos;
+         if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
+               && EQ (FRAME_MINIBUF_WINDOW (f), minibuf_window)))
+           {
+             FRAME_CURSOR_Y (f) = cursor_vpos;
+             FRAME_CURSOR_X (f) = cursor_hpos;
+           }
 
          if (w == XWINDOW (selected_window))
            {
              /* Line is not continued and did not start
                 in middle of character */
-             if ((hpos - XFASTINT (w->left)
+             if ((hpos - WINDOW_LEFT_MARGIN (w)
                   == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
                  && val.vpos)
                {
@@ -2821,12 +3466,19 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If hscroll and line not empty, insert truncation-at-left marker */
   if (hscroll && lastpos != start)
     {
-      *leftmargin = fix_glyph (f, truncator, 0);
+      GLYPH g = fix_glyph (f, truncator, 0);
+      *leftmargin = g;
       if (p1 <= leftmargin)
        p1 = leftmargin + 1;
+      else                     /* MULE: it may be a wide-column character */
+       {
+         p1prev = leftmargin + 1;
+         while (p1prev < p1 && *p1prev & GLYPH_MASK_PADDING)
+           *p1prev++ = g;
+       }
     }
 
-  if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
+  if (!WINDOW_RIGHTMOST_P (w))
     {
       endp++;
       if (p1 < leftmargin) p1 = leftmargin;
@@ -2836,11 +3488,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_ON_RIGHT (f))
+       {
+         int i;
+         for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
+           *p1++ = SPACEGLYPH;
+       }
+      else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+       *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]);
@@ -2894,6 +3551,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
     }
 
   val.bufpos = pos;
+  val.ovstring_chars_done = ovstr_done;
   val_display_text_line = val;
   return &val_display_text_line;
 }
@@ -2911,21 +3569,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,
@@ -2952,7 +3616,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 */
@@ -2962,49 +3625,55 @@ display_mode_line (w)
      struct window *w;
 {
   register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
-  register int left = XFASTINT (w->left);
-  register int right = XFASTINT (w->width) + left;
+  register int left = WINDOW_LEFT_MARGIN (w);
+  register int right = WINDOW_RIGHT_MARGIN (w);
   register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
 
   line_number_displayed = 0;
   w->column_number_displayed = Qnil;
 
   get_display_line (f, vpos, left);
-#ifdef MULTI_KBOARD
-  {
-    /* Sigh, mode-line-format can reference kboard-local variables like
-       defining-kbd-macro.  Use the one associated with the frame we're
-       updating.  */
-    KBOARD *orig_kboard = current_kboard;
-    current_kboard = FRAME_KBOARD (f);
-#endif
-    display_mode_element (w, vpos, left, 0, right, right,
-                         current_buffer->mode_line_format);
-#ifdef MULTI_KBOARD
-    current_kboard = orig_kboard;
-  }
-#endif
+
+  /* Temporarily make frame F's kboard the current kboard
+     so that kboard-local variables in the mode_line_format
+     will get the right values.  */
+  push_frame_kboard (f);
+
+  display_mode_element (w, vpos, left, 0, right, right,
+                       current_buffer->mode_line_format);
+
+  pop_frame_kboard ();
+
   FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
 
-  /* Make the mode line inverse video if the entire line
-     is made of mode lines.
-     I.e. if this window is full width,
-     or if it is the child of a full width window
-     (which implies that that window is split side-by-side
-     and the rest of this line is mode lines of the sibling windows).  */
-  if (XFASTINT (w->width) == FRAME_WIDTH (f)
-      || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
-    FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
+  /* Put the mode line in inverse video.
+     Use faces if possible, since that lets us handle
+     partial-width windows and avoid inverting the scroll bar columns.  */
 #ifdef HAVE_FACES
-  else if (! FRAME_TERMCAP_P (f))
+  if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
     {
       /* For a partial width window, explicitly set face of each glyph. */
       int i;
+      unsigned int padding;
       GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
       for (i = left; i < right; ++i)
-       ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
+       {
+         padding = ptr[i] & GLYPH_MASK_PADDING;
+         ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1) | padding;
+       }
     }
+  else
 #endif
+
+  /* Make the mode line inverse video if the entire line
+     is made of mode lines.
+     I.e. if this window is full width,
+     or if it is the child of a full width window
+     (which implies that that window is split side-by-side
+     and the rest of this line is mode lines of the sibling windows).  */
+  if (WINDOW_FULL_WIDTH_P (w)
+      || WINDOW_FULL_WIDTH_P (XWINDOW (w->parent)))
+    FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
 }
 
 /* Contribute ELT to the mode line for window W.
@@ -3070,6 +3739,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 */
@@ -3082,9 +3752,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,
@@ -3092,13 +3765,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);
                  }
              }
          }
@@ -3232,15 +3906,87 @@ 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;
+  }
+}
+
+/* Set a mnemonic character for CODING_SYSTEM (Lisp symbol) in BUF.
+   If EOL_FLAG is 1, set also a mnemonic character for end-of-line
+   type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+
+static char *
+decode_mode_spec_coding (coding_system, buf, eol_flag)
+     Lisp_Object coding_system;
+     register char *buf;
+     int eol_flag;
+{
+  register Lisp_Object val = coding_system;
+
+  if (NILP (val))              /* Not yet decided.  */
+    {
+      *buf++ = '-';
+      if (eol_flag) *buf++ = eol_mnemonic_undecided;
+    }
+  else
+    {
+      while (!NILP (val) && SYMBOLP (val))
+       val = Fget (val, Qcoding_system);
+      *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+      if (eol_flag)
+       {
+         val = Fget (coding_system, Qeol_type);
+
+         if (NILP (val))       /* Not yet decided.  */
+           *buf++ = eol_mnemonic_undecided;
+         else if (VECTORP (val)) /* Not yet decided.  */
+           *buf++ = eol_mnemonic_undecided;
+         else                  /* INTEGERP (val) -- 1:LF, 2:CRLF, 3:CR */
+           *buf++ = (XFASTINT (val) == 1
+                     ? eol_mnemonic_unix
+                     : (XFASTINT (val) == 2
+                        ? eol_mnemonic_dos : eol_mnemonic_mac));
+       }
+    }
+  return buf;
+}
+
 /* 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;
@@ -3254,6 +4000,74 @@ decode_mode_spec (w, c, maxwidth)
 
   switch (c)
     {
+    case '*':
+      if (!NILP (b->read_only))
+       return "%";
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '+':
+      /* This differs from %* only for a modified read-only buffer.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      if (!NILP (b->read_only))
+       return "%";
+      return "-";
+
+    case '&':
+      /* This differs from %* in ignoring read-only-ness.  */
+      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
+       return "*";
+      return "-";
+
+    case '%':
+      return "%";
+
+    case '[': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return "[[[... ";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = '[';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case ']': 
+      {
+       int i;
+       char *p;
+
+       if (command_loop_level > 5)
+         return " ...]]]";
+       p = decode_mode_spec_buf;
+       for (i = 0; i < command_loop_level; i++)
+         *p++ = ']';
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
+
+    case '-':
+      {
+       register char *p;
+       register int i;
+       
+       if (maxwidth < sizeof (lots_of_dashes))
+         return lots_of_dashes;
+       else
+         {
+           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
+             *p++ = '-';
+           *p = '\0';
+         }
+       return decode_mode_spec_buf;
+      }
+
     case 'b': 
       obj = b->name;
 #if 0
@@ -3267,6 +4081,22 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
+    case 'c':
+      {
+       int col = current_column ();
+       XSETFASTINT (w->column_number_displayed, col);
+       pint2str (decode_mode_spec_buf, spec_width, col);
+       return decode_mode_spec_buf;
+      }
+
+    case 'F':
+      /* %F displays the frame name.  */
+      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;
 #if 0
@@ -3282,14 +4112,6 @@ decode_mode_spec (w, c, maxwidth)
 #endif
       break;
 
-    case 'c':
-      {
-       int col = current_column ();
-       XSETFASTINT (w->column_number_displayed, col);
-       sprintf (decode_mode_spec_buf, "%d", col);
-       return decode_mode_spec_buf;
-      }
-
     case 'l':
       {
        int startpos = marker_position (w->start);
@@ -3301,14 +4123,17 @@ 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;
+       /* But do forget it, if the window shows a different buffer now.  */
+       else if (BUFFERP (w->base_line_pos))
+         w->base_line_pos = Qnil;
 
        /* 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)
@@ -3358,7 +4183,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);
@@ -3372,8 +4197,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;
 
@@ -3386,44 +4218,6 @@ decode_mode_spec (w, c, maxwidth)
        return " Narrow";
       break;
 
-    case '*':
-      if (!NILP (b->read_only))
-       return "%";
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      return "-";
-
-    case '+':
-      /* This differs from %* only for a modified read-only buffer.  */
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      if (!NILP (b->read_only))
-       return "%";
-      return "-";
-
-    case '&':
-      /* This differs from %* in ignoring read-only-ness.  */
-      if (BUF_MODIFF (b) > BUF_SAVE_MODIFF (b))
-       return "*";
-      return "-";
-
-    case 's':
-      /* status of process */
-      obj = Fget_buffer_process (w->buffer);
-      if (NILP (obj))
-       return "no process";
-#ifdef subprocesses
-      obj = Fsymbol_name (Fprocess_status (obj));
-#endif
-      break;
-
-    case 't':                  /* indicate TEXT or BINARY */
-#ifdef MODE_LINE_BINARY_TEXT
-      return MODE_LINE_BINARY_TEXT (b);
-#else
-      return "T";
-#endif
-
     case 'p':
       {
        int pos = marker_position (w->start);
@@ -3440,7 +4234,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)
@@ -3466,7 +4264,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)
@@ -3479,50 +4281,50 @@ decode_mode_spec (w, c, maxwidth)
          }
       }
 
-    case '%':
-      return "%";
-
-    case '[': 
-      {
-       int i;
-       char *p;
+    case 's':
+      /* status of process */
+      obj = Fget_buffer_process (w->buffer);
+      if (NILP (obj))
+       return "no process";
+#ifdef subprocesses
+      obj = Fsymbol_name (Fprocess_status (obj));
+#endif
+      break;
 
-       if (command_loop_level > 5)
-         return "[[[... ";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = '[';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
+    case 't':                  /* indicate TEXT or BINARY */
+#ifdef MODE_LINE_BINARY_TEXT
+      return MODE_LINE_BINARY_TEXT (b);
+#else
+      return "T";
+#endif
 
-    case ']': 
+    case 'z':
+      /* coding-system (not including end-of-line format) */
+    case 'Z':
+      /* coding-system (including end-of-line type) */
       {
-       int i;
+       int eol_flag = (c == 'Z');
        char *p;
 
-       if (command_loop_level > 5)
-         return " ...]]]";
-       p = decode_mode_spec_buf;
-       for (i = 0; i < command_loop_level; i++)
-         *p++ = ']';
-       *p = 0;
-       return decode_mode_spec_buf;
-      }
-
-    case '-':
-      {
-       register char *p;
-       register int i;
-       
-       if (maxwidth < sizeof (lots_of_dashes))
-         return lots_of_dashes;
-       else
+       p = decode_mode_spec_coding
+         (find_symbol_value (Qbuffer_file_coding_system),
+          decode_mode_spec_buf, eol_flag);
+       if (FRAME_TERMCAP_P (f))
          {
-           for (p = decode_mode_spec_buf, i = maxwidth; i > 0; i--)
-             *p++ = '-';
-           *p = '\0';
+           p = decode_mode_spec_coding (keyboard_coding.symbol, p, eol_flag);
+           p = decode_mode_spec_coding (terminal_coding.symbol, p, eol_flag);
+         }
+#ifdef subprocesses
+       obj = Fget_buffer_process (Fcurrent_buffer ());
+       if (PROCESSP (obj))
+         {
+           p = decode_mode_spec_coding (XPROCESS (obj)->decode_coding_system,
+                                        p, eol_flag);
+           p = decode_mode_spec_coding (XPROCESS (obj)->encode_coding_system,
+                                        p, eol_flag);
          }
+#endif /* subprocesses */
+       *p = 0;
        return decode_mode_spec_buf;
       }
     }
@@ -3577,8 +4379,8 @@ display_scan_buffer (start, count, shortage)
       {
        ceiling =  BUFFER_CEILING_OF (start);
        ceiling = min (limit, ceiling);
-       ceiling_addr = &FETCH_CHAR (ceiling) + 1;
-       base = (cursor = &FETCH_CHAR (start));
+       ceiling_addr = POS_ADDR (ceiling) + 1;
+       base = (cursor = POS_ADDR (start));
        while (1)
          {
            while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
@@ -3606,8 +4408,8 @@ display_scan_buffer (start, count, shortage)
        {                       /* we WILL scan under start */
          ceiling =  BUFFER_FLOOR_OF (start);
          ceiling = max (limit, ceiling);
-         ceiling_addr = &FETCH_CHAR (ceiling) - 1;
-         base = (cursor = &FETCH_CHAR (start));
+         ceiling_addr = POS_ADDR (ceiling) - 1;
+         base = (cursor = POS_ADDR (start));
          cursor++;
          while (1)
            {
@@ -3698,6 +4500,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);
@@ -3707,15 +4510,16 @@ display_string (w, vpos, string, length, hpos, truncate,
   struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
   GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
   int window_width = XFASTINT (w->width);
+  /* If 1, we must display multibyte characters.  */
+  int multibyte = !NILP (XBUFFER (w->buffer)->enable_multibyte_characters);
 
   /* 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;
 
@@ -3726,16 +4530,16 @@ display_string (w, vpos, string, length, hpos, truncate,
     {
       end = start + window_width - (truncate != 0);
 
-      if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
+      if (!WINDOW_RIGHTMOST_P (w))
        {
-         if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+         if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
            {
              int i;
 
              for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
                *end-- = ' ';
            }
-         else
+         else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
            *end-- = '|';
        }
     }
@@ -3751,17 +4555,31 @@ display_string (w, vpos, string, length, hpos, truncate,
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
-  while (p1 < end)
+  if (length < 0)
+    /* We need this value for multibyte characters.  */
+    length = strlen (string);
+
+  /* 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;
-      c = *string++;
-      /* Specified length.  */
-      if (length >= 0)
-       length--;
-      /* Unspecified length (null-terminated string).  */
-      else if (c == 0)
+      int len;
+
+      if (length <= 0)
        break;
+      if (multibyte)
+       c = STRING_CHAR_AND_LENGTH (string, length, len);
+      else
+       c = *string, len = 1;
+
+      string += len, length -= len;
+
+      if (p1 >= end)
+       {
+         truncated = 1;
+         break;
+       }
 
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
@@ -3789,20 +4607,25 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
        {
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
-                                ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
-                            0);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (dp)))
+                       ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+                   0));
          p1++;
          if (p1 >= start && p1 < end)
            *p1 = c ^ 0100;
          p1++;
        }
-      else
+      else if (len == 1)
        {
+         /* C is a control character or a binary byte data.  */
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-                                ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-                            0);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_ESCAPE_GLYPH (dp)))
+                       ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
+                   0));
          p1++;
          if (p1 >= start && p1 < end)
            *p1 = (c >> 6) + '0';
@@ -3814,9 +4637,51 @@ display_string (w, vpos, string, length, hpos, truncate,
            *p1 = (7 & c) + '0';
          p1++;
        }
+      else
+       {
+         /* C is a multibyte character.  */      
+         int charset = CHAR_CHARSET (c);
+         int columns = (charset == CHARSET_COMPOSITION
+                        ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                        : CHARSET_WIDTH (charset));
+
+         if (p1 < start)
+           {
+             /* Since we can't show the left part of C, fill all
+                 columns with spaces.  */
+             columns -= start - p1;
+             p1 = start;
+             while (columns--)
+               {
+                 if (p1 < end)
+                   *p1 = SPACEGLYPH;
+                 p1++;
+               }
+           }
+         else if (p1 + columns > end)
+           {
+             /* Since we can't show the right part of C, fill all
+                 columns with TRUNCATE if TRUNCATE is specified.  */
+             if (truncate)
+               {
+                 while (p1 < end)
+                   *p1++ = fix_glyph (f, truncate, 0);
+                 /* And tell the line is truncated.  */
+                 truncated = 1;
+               }
+             break;
+           }
+         else
+           {
+             /* We can show the whole glyph of C.  */
+             *p1++ = c;
+             while (--columns)
+               *p1++ = c | GLYPH_MASK_PADDING;
+           }
+       }
     }
 
-  if (c && length > 0)
+  if (truncated)
     {
       p1 = end;
       if (truncate) *p1++ = fix_glyph (f, truncate, 0);
@@ -3925,6 +4790,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;
@@ -3949,6 +4826,16 @@ See also `overlay-arrow-string'.");
 If that fails to bring point back on frame, point is centered instead.\n\
 If this is zero, point is always centered after it moves off frame.");
 
+  DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
+    "*Scroll up to this many lines, to bring point back on screen.");
+  scroll_conservatively = 0;
+
+  DEFVAR_INT ("scroll-margin", &scroll_margin,
+    "*Number of lines of margin at the top and bottom of a window.\n\
+Recenter the window whenever point gets within this many lines\n\
+of the top or bottom of the window.");
+  scroll_margin = 0;
+
   DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
 
   DEFVAR_BOOL ("truncate-partial-width-windows",
@@ -3969,8 +4856,10 @@ If this is zero, point is always centered after it moves off frame.");
   highlight_nonselected_windows = 1;
 
   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
-    "Non-nil means more than one frame is in use, not counting minibuffer frames.\n\
-Not guaranteed to be accurate except while parsing frame-title-format.");
+    "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 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\
@@ -4008,6 +4897,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 */