(Qforeground_color, Qbackground_color): Declare.
[bpt/emacs.git] / src / xdisp.c
index 532d548..84a80d5 100644 (file)
@@ -1,5 +1,6 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 1998
+     Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,6 +30,7 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "charset.h"
 #include "indent.h"
 #include "commands.h"
 #include "macros.h"
@@ -36,6 +38,13 @@ Boston, MA 02111-1307, USA.  */
 #include "termhooks.h"
 #include "intervals.h"
 #include "keyboard.h"
+#include "coding.h"
+#include "process.h"
+#include "region-cache.h"
+
+#ifdef HAVE_WINDOW_SYSTEM
+#include "xterm.h"
+#endif
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
 extern void set_frame_menubar ();
@@ -45,6 +54,8 @@ extern int pending_menu_activation;
 extern int interrupt_input;
 extern int command_loop_level;
 
+extern int minibuffer_auto_raise;
+
 extern Lisp_Object Qface;
 
 extern Lisp_Object Voverriding_local_map;
@@ -108,6 +119,11 @@ Lisp_Object Voverlay_arrow_position;
 /* String to display for the arrow.  */
 Lisp_Object Voverlay_arrow_string;
 
+/* Values of those variables at last redisplay.
+   However, if Voverlay_arrow_position is a marker,
+   last_arrow_position is its numerical position.  */
+static Lisp_Object last_arrow_position, last_arrow_string;
+
 /* Like mode-line-format, but for the titlebar on a visible frame.  */
 Lisp_Object Vframe_title_format;
 
@@ -119,9 +135,6 @@ Lisp_Object Vicon_title_format;
    have changed.  */
 static Lisp_Object Vwindow_size_change_functions;
 
-/* Values of those variables at last redisplay.  */
-static Lisp_Object last_arrow_position, last_arrow_string;
-
 Lisp_Object Qmenu_bar_update_hook;
 
 /* Nonzero if overlay arrow has been displayed once in this window.  */
@@ -139,6 +152,18 @@ static int highlight_nonselected_windows;
    Try scrolling this many lines up or down if that will bring it back.  */
 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;
+
+/* Number of characters of overlap to show,
+   when scrolling a one-line window such as a minibuffer.  */
+static int minibuffer_scroll_overlap;
+
 /* Nonzero if try_window_id has made blank lines at window bottom
  since the last redisplay that paused */
 static int blank_end_of_window;
@@ -197,6 +222,10 @@ int echo_area_glyphs_length;
    same window currently active as a minibuffer.  */
 Lisp_Object echo_area_window;
 
+/* Nonzero means multibyte characters were enabled when the echo area
+   message was specified.  */
+int message_enable_multibyte;
+
 /* true iff we should redraw the mode lines on the next redisplay */
 int update_mode_lines;
 
@@ -211,10 +240,14 @@ 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;
 
+/* 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 */
 int windows_or_buffers_changed;
@@ -229,6 +262,11 @@ 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;
+
+#define COERCE_MARKER(X)       \
+  (MARKERP ((X)) ? Fmarker_position (X) : (X))
+
+static int pos_tab_offset P_ ((struct window *, int, int));
 \f
 /* Output a newline in the *Messages* buffer if "needs" one.  */
 
@@ -236,59 +274,105 @@ void
 message_log_maybe_newline ()
 {
   if (message_log_need_newline)
-    message_dolog ("", 0, 1);
+    message_dolog ("", 0, 1, 0);
 }
 
 
 /* Add a string to the message log, optionally terminated with a newline.
    This function calls low-level routines in order to bypass text property
-   hooks, etc. which might not be safe to run.  */
+   hooks, etc. which might not be safe to run.
+   MULTIBYTE, if nonzero, means interpret the contents of M as multibyte.  */
 
 void
-message_dolog (m, len, nlflag)
+message_dolog (m, len, nlflag, multibyte)
      char *m;
-     int len, nlflag;
+     int len, nlflag, multibyte;
 {
   if (!NILP (Vmessage_log_max))
     {
       struct buffer *oldbuf;
-      int oldpoint, oldbegv, oldzv;
+      Lisp_Object oldpoint, oldbegv, oldzv;
       int old_windows_or_buffers_changed = windows_or_buffers_changed;
+      int point_at_end = 0;
+      int zv_at_end = 0;
+      Lisp_Object old_deactivate_mark;
 
+      old_deactivate_mark = Vdeactivate_mark;
       oldbuf = current_buffer;
       Fset_buffer (Fget_buffer_create (build_string ("*Messages*")));
       current_buffer->undo_list = Qt;
-      oldpoint = PT;
-      oldbegv = BEGV;
-      oldzv = ZV;
+
+      oldpoint = Fpoint_marker ();
+      oldbegv = Fpoint_min_marker ();
+      oldzv = Fpoint_max_marker ();
+
+      if (PT == Z)
+       point_at_end = 1;
+      if (ZV == Z)
+       zv_at_end = 1;
+
       BEGV = BEG;
+      BEGV_BYTE = BEG_BYTE;
       ZV = Z;
-      if (oldpoint == Z)
-       oldpoint += len + nlflag;
-      if (oldzv == Z)
-       oldzv += len + nlflag;
-      TEMP_SET_PT (Z);
-      if (len)
-       insert_1 (m, len, 1, 0);
+      ZV_BYTE = Z_BYTE;
+      TEMP_SET_PT_BOTH (Z, Z_BYTE);
+
+      /* Insert the string--maybe converting multibyte to single byte
+        or vice versa, so that all the text fits the buffer.  */
+      if (multibyte
+         && NILP (current_buffer->enable_multibyte_characters))
+       {
+         int c, i = 0, nbytes;
+         /* Convert a multibyte string to single-byte
+            for the *Message* buffer.  */
+         while (i < len)
+           {
+             c = STRING_CHAR (m + i, len - i);
+             i += XFASTINT (Fchar_bytes (make_number (c)));
+             /* Truncate the character to its last byte--we can only hope
+                the user is happy with the character he gets,
+                since if it isn't right, there is no way to do it right.  */
+             c &= 0xff;
+             insert_char (c);
+           }
+       }
+      else if (! multibyte
+              && ! NILP (current_buffer->enable_multibyte_characters))
+       {
+         int i = 0;
+         unsigned char *msg = (unsigned char *) m;
+         /* Convert a single-byte string to multibyte
+            for the *Message* buffer.  */
+         while (i < len)
+           {
+             int c = unibyte_char_to_multibyte (msg[i++]);
+             insert_char (c);
+           }
+       }
+      else if (len)
+       insert_1 (m, len, 1, 0, 0);
+
       if (nlflag)
        {
-         int this_bol, prev_bol, dup;
-         insert_1 ("\n", 1, 1, 0);
+         int this_bol, this_bol_byte, prev_bol, prev_bol_byte, dup;
+         insert_1 ("\n", 1, 1, 0, 0);
+
+         scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
+         this_bol = PT;
+         this_bol_byte = PT_BYTE;
 
-         this_bol = scan_buffer ('\n', Z, 0, -2, 0, 0);
          if (this_bol > BEG)
            {
-             prev_bol = scan_buffer ('\n', this_bol, 0, -2, 0, 0);
-             dup = message_log_check_duplicate (prev_bol, this_bol);
+             scan_newline (PT, PT_BYTE, BEG, BEG_BYTE, -2, 0);
+             prev_bol = PT;
+             prev_bol_byte = PT_BYTE;
+
+             dup = message_log_check_duplicate (prev_bol, prev_bol_byte,
+                                                this_bol, this_bol_byte);
              if (dup)
                {
-                 if (oldpoint > prev_bol)
-                   oldpoint -= min (this_bol, oldpoint) - prev_bol;
-                 if (oldbegv > prev_bol)
-                   oldbegv -= min (this_bol, oldbegv) - prev_bol;
-                 if (oldzv > prev_bol)
-                   oldzv -= min (this_bol, oldzv) - prev_bol;
-                 del_range_1 (prev_bol, this_bol, 0);
+                 del_range_both (prev_bol, prev_bol_byte,
+                                 this_bol, this_bol_byte, 0);
                  if (dup > 1)
                    {
                      char dupstr[40];
@@ -298,32 +382,46 @@ message_dolog (m, len, nlflag)
                         change message_log_check_duplicate.  */
                      sprintf (dupstr, " [%d times]", dup);
                      duplen = strlen (dupstr);
-                     TEMP_SET_PT (Z-1);
-                     if (oldpoint == Z)
-                       oldpoint += duplen;
-                     if (oldzv == Z)
-                       oldzv += duplen;
-                     insert_1 (dupstr, duplen, 1, 0);
+                     TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
+                     insert_1 (dupstr, duplen, 1, 0, 1);
                    }
                }
            }
 
          if (NATNUMP (Vmessage_log_max))
            {
-             int pos = scan_buffer ('\n', Z, 0,
-                                    -XFASTINT (Vmessage_log_max) - 1, 0, 0);
-             oldpoint -= min (pos, oldpoint) - BEG;
-             oldbegv -= min (pos, oldbegv) - BEG;
-             oldzv -= min (pos, oldzv) - BEG;
-             del_range_1 (BEG, pos, 0);
+             scan_newline (Z, Z_BYTE, BEG, BEG_BYTE,
+                           -XFASTINT (Vmessage_log_max) - 1, 0);
+             del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
            }
        }
-      BEGV = oldbegv;
-      ZV = oldzv;
-      TEMP_SET_PT (oldpoint);
+      BEGV = XMARKER (oldbegv)->charpos;
+      BEGV_BYTE = marker_byte_position (oldbegv);
+
+      if (zv_at_end)
+       {
+         ZV = Z;
+         ZV_BYTE = Z_BYTE;
+       }
+      else
+       {
+         ZV = XMARKER (oldzv)->charpos;
+         ZV_BYTE = marker_byte_position (oldzv);
+       }
+
+      if (point_at_end)
+       TEMP_SET_PT_BOTH (Z, Z_BYTE);
+      else
+       Fgoto_char (oldpoint);
+
+      free_marker (oldpoint);
+      free_marker (oldbegv);
+      free_marker (oldzv);
+
       set_buffer_internal (oldbuf);
       windows_or_buffers_changed = old_windows_or_buffers_changed;
       message_log_need_newline = !nlflag;
+      Vdeactivate_mark = old_deactivate_mark;
     }
 }
 
@@ -334,14 +432,15 @@ message_dolog (m, len, nlflag)
    value N > 1 if we should also append " [N times]".  */
 
 static int
-message_log_check_duplicate (prev_bol, this_bol)
+message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte)
      int prev_bol, this_bol;
+     int prev_bol_byte, this_bol_byte;
 {
   int i;
   int len = Z - 1 - this_bol;
   int seen_dots = 0;
-  unsigned char *p1 = BUF_CHAR_ADDRESS (current_buffer, prev_bol);
-  unsigned char *p2 = BUF_CHAR_ADDRESS (current_buffer, this_bol);
+  unsigned char *p1 = BUF_BYTE_ADDRESS (current_buffer, prev_bol_byte);
+  unsigned char *p2 = BUF_BYTE_ADDRESS (current_buffer, this_bol_byte);
 
   for (i = 0; i < len; i++)
     {
@@ -376,31 +475,35 @@ message_log_check_duplicate (prev_bol, this_bol)
    Do not pass text in a buffer that was alloca'd.  */
 
 void
-message2 (m, len)
+message2 (m, len, multibyte)
      char *m;
      int len;
+     int multibyte;
 {
   /* First flush out any partial line written with print.  */
   message_log_maybe_newline ();
   if (m)
-    message_dolog (m, len, 1);
-  message2_nolog (m, len);
+    message_dolog (m, len, 1, multibyte);
+  message2_nolog (m, len, multibyte);
 }
 
 
 /* The non-logging counterpart of message2.  */
 
 void
-message2_nolog (m, len)
+message2_nolog (m, len, multibyte)
      char *m;
      int len;
 {
+  message_enable_multibyte = multibyte;
+
   if (noninteractive)
     {
       if (noninteractive_need_newline)
        putc ('\n', stderr);
       noninteractive_need_newline = 0;
-      fwrite (m, len, 1, stderr);
+      if (m)
+       fwrite (m, len, 1, stderr);
       if (cursor_in_echo_area == 0)
        fprintf (stderr, "\n");
       fflush (stderr);
@@ -427,6 +530,9 @@ message2_nolog (m, len)
        {
          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;
@@ -440,10 +546,11 @@ message2_nolog (m, len)
     }
 }
 \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.
+/* Display in echo area the null-terminated ASCII-only string 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
+   The string 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.
@@ -453,14 +560,75 @@ void
 message1 (m)
      char *m;
 {
-  message2 (m, (m ? strlen (m) : 0));
+  message2 (m, (m ? strlen (m) : 0), 0);
 }
 
 void
 message1_nolog (m)
      char *m;
 {
-  message2_nolog (m, (m ? strlen (m) : 0));
+  message2_nolog (m, (m ? strlen (m) : 0), 0);
+}
+
+/* Display a message M which contains a single %s
+   which gets replaced with STRING.  */
+
+void
+message_with_string (m, string, log)
+     char *m;
+     Lisp_Object string;
+     int log;
+{
+  if (noninteractive)
+    {
+      if (m)
+       {
+         if (noninteractive_need_newline)
+           putc ('\n', stderr);
+         noninteractive_need_newline = 0;
+         fprintf (stderr, m, XSTRING (string)->data);
+         if (cursor_in_echo_area == 0)
+           fprintf (stderr, "\n");
+         fflush (stderr);
+       }
+    }
+  else if (INTERACTIVE)
+    {
+      /* 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.  */
+      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 (f))
+       {
+         int len;
+         char *a[1];
+         a[0] = (char *) XSTRING (string)->data;
+
+         len = doprnt (FRAME_MESSAGE_BUF (f),
+                       FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
+
+         if (log)
+           message2 (FRAME_MESSAGE_BUF (f), len,
+                     STRING_MULTIBYTE (string));
+         else
+           message2_nolog (FRAME_MESSAGE_BUF (f), len,
+                           STRING_MULTIBYTE (string));
+
+         /* Print should start at the beginning of the message
+            buffer next time.  */
+         message_buf_print = 0;
+       }
+    }
 }
 
 /* Truncate what will be displayed in the echo area
@@ -525,19 +693,20 @@ message (m, a1, a2, a3)
            {
              int len;
 #ifdef NO_ARG_ARRAY
-             EMACS_INT a[3];
-             a[0] = a1;
-             a[1] = a2;
-             a[2] = a3;
+             char *a[3];
+             a[0] = (char *) a1;
+             a[1] = (char *) a2;
+             a[2] = (char *) a3;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           (int) FRAME_WIDTH (f), m, (char *)0, 3, a);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
 #else
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           (int) FRAME_WIDTH (f), m, (char *)0, 3, &a1);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3,
+                           (char **) &a1);
 #endif /* NO_ARG_ARRAY */
 
-             message2 (FRAME_MESSAGE_BUF (f), len);
+             message2 (FRAME_MESSAGE_BUF (f), len, 0);
            }
          else
            message1 (0);
@@ -565,7 +734,8 @@ message_nolog (m, a1, a2, a3)
 void
 update_echo_area ()
 {
-  message2 (echo_area_glyphs, echo_area_glyphs_length);
+  message2 (echo_area_glyphs, echo_area_glyphs_length,
+           ! NILP (current_buffer->enable_multibyte_characters));
 }
 \f
 static void
@@ -592,14 +762,25 @@ echo_area_display ()
 
   if (echo_area_glyphs || minibuf_level == 0)
     {
+      int i;
+
       echo_area_window = mini_window;
 
       vpos = XFASTINT (XWINDOW (mini_window)->top);
       get_display_line (f, vpos, 0);
+
+      /* 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) + FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                     message_enable_multibyte);
 
 #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 */
@@ -617,8 +798,14 @@ echo_area_display ()
             i < vpos + XFASTINT (XWINDOW (mini_window)->height); i++)
          {
            get_display_line (f, i, 0);
-           display_string (XWINDOW (mini_window), vpos,
-                           "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
+           /* We don't use FRAME_SCROLL_BAR_WIDTH (f) as the starting
+              hpos, because it is good to clear whatever is behind the
+              scroll bar.  This does not affect the scroll bar itself.  */
+           display_string (XWINDOW (mini_window), i,
+                           "", 0, 
+                            0, 0, 0,
+                            0, FRAME_WIDTH (f) + FRAME_SCROLL_BAR_WIDTH (f),
+                           0);
          }
       }
     }
@@ -695,7 +882,7 @@ x_consider_frame_title (frame)
      already wasted too much time by walking through the list with
      display_mode_element, then we might need to optimize at a higher
      level than this.)  */
-  if (! STRINGP (f->name) || XSTRING (f->name)->size != len
+  if (! STRINGP (f->name) || STRING_BYTES (XSTRING (f->name)) != len
       || bcmp (frame_title_buf, XSTRING (f->name)->data, len) != 0)
     x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
 }
@@ -747,7 +934,7 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
       int count = specpdl_ptr - specpdl;
 
-      record_unwind_protect (Fstore_match_data, Fmatch_data ());
+      record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -833,6 +1020,7 @@ redisplay_internal (preserve_echo_area)
   int all_windows;
   register int tlbufpos, tlendpos;
   struct position pos;
+  int number_of_visible_frames;
 
   if (noninteractive)
     return;
@@ -842,6 +1030,8 @@ redisplay_internal (preserve_echo_area)
     return;
 #endif
 
+ retry:
+
   if (! FRAME_WINDOW_P (selected_frame)
       && previous_terminal_frame != selected_frame)
     {
@@ -860,10 +1050,15 @@ redisplay_internal (preserve_echo_area)
   {
     Lisp_Object tail, frame;
 
+    number_of_visible_frames = 0;
+
     FOR_EACH_FRAME (tail, frame)
       {
        FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
 
+       if (FRAME_VISIBLE_P (XFRAME (frame)))
+         number_of_visible_frames++;
+
        /* Clear out all the display lines in which we will generate the
           glyphs to display.  */
        init_desired_glyphs (XFRAME (frame));
@@ -897,7 +1092,8 @@ redisplay_internal (preserve_echo_area)
       /* 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_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
       && XFASTINT (w->column_number_displayed) != current_column ())
     w->update_mode_line = Qt; 
 
@@ -907,7 +1103,7 @@ redisplay_internal (preserve_echo_area)
 
   /* If specs for an arrow have changed, do thorough redisplay
      to ensure we remove any arrow that should no longer exist.  */
-  if (! EQ (Voverlay_arrow_position, last_arrow_position)
+  if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position)
       || ! EQ (Voverlay_arrow_string, last_arrow_string))
     all_windows = 1;
 
@@ -935,6 +1131,7 @@ redisplay_internal (preserve_echo_area)
   if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
       && !current_buffer->clip_changed
       && FRAME_VISIBLE_P (XFRAME (w->frame))
+      && !FRAME_OBSCURED_P (XFRAME (w->frame))
       /* Make sure recorded data applies to current buffer, etc */
       && this_line_buffer == current_buffer
       && current_buffer == XBUFFER (w->buffer)
@@ -944,7 +1141,8 @@ redisplay_internal (preserve_echo_area)
       && 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
@@ -957,19 +1155,54 @@ redisplay_internal (preserve_echo_area)
              && end_unchanged >= tlendpos
              && Z - GPT >= tlendpos)))
     {
-      if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
+      int tlbufpos_byte = CHAR_TO_BYTE (tlbufpos);
+      if (tlbufpos > BEGV && FETCH_BYTE (tlbufpos_byte - 1) != '\n'
          && (tlbufpos == ZV
-             || FETCH_CHAR (tlbufpos) == '\n'))
+             || FETCH_BYTE (tlbufpos_byte) == '\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;
+         int opoint = PT, opoint_byte = PT_BYTE;
+
+         scan_newline (tlbufpos, tlbufpos_byte, BEGV, BEGV_BYTE, -1, 1);
+
+         val = *compute_motion (PT, 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);
+         SET_PT_BOTH (opoint, opoint_byte);
+         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));
+         display_text_line (w, tlbufpos, tlbufpos_byte,
+                            this_line_vpos, this_line_start_hpos,
+                            pos_tab_offset (w, tlbufpos, tlbufpos_byte), 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
@@ -980,7 +1213,7 @@ redisplay_internal (preserve_echo_area)
              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;
@@ -998,7 +1231,7 @@ redisplay_internal (preserve_echo_area)
                  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;
            }
@@ -1023,7 +1256,8 @@ redisplay_internal (preserve_echo_area)
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && w == XWINDOW (current_buffer->last_selected_window)
+              && (w == XWINDOW (current_buffer->last_selected_window)
+                  || highlight_nonselected_windows)
               && NILP (w->region_showing)
               && !cursor_in_echo_area)
        {
@@ -1033,12 +1267,13 @@ redisplay_internal (preserve_echo_area)
                                 PT, 2, - (1 << (BITS_PER_SHORT - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
-                                pos_tab_offset (w, tlbufpos), w);
+                                pos_tab_offset (w, tlbufpos, tlbufpos_byte),
+                                w);
          if (pos.vpos < 1)
            {
              int width = window_internal_width (w) - 1;
              FRAME_CURSOR_X (selected_frame)
-               = XFASTINT (w->left) + minmax (0, pos.hpos, width);
+               = WINDOW_LEFT_MARGIN (w) + minmax (0, pos.hpos, width);
              FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
              goto update;
            }
@@ -1084,7 +1319,7 @@ redisplay_internal (preserve_echo_area)
              if (condemn_scroll_bars_hook)
                (*condemn_scroll_bars_hook) (f);
 
-             if (FRAME_VISIBLE_P (f))
+             if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
                redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
 
              /* Any scroll bars which redisplay_windows should have nuked
@@ -1094,10 +1329,10 @@ redisplay_internal (preserve_echo_area)
            }
        }
     }
-  else if (FRAME_VISIBLE_P (selected_frame))
+  else if (FRAME_VISIBLE_P (selected_frame) && !FRAME_OBSCURED_P (selected_frame))
     {
       redisplay_window (selected_window, 1, preserve_echo_area);
-      if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
+      if (!WINDOW_FULL_WIDTH_P (w))
        preserve_other_columns (w);
     }
 
@@ -1125,7 +1360,7 @@ update:
          f = XFRAME (XCONS (tail)->car);
 
          if ((FRAME_WINDOW_P (f) || f == selected_frame)
-             && FRAME_VISIBLE_P (f))
+             && FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
            {
              pause |= update_frame (f, 0, 0);
              if (!pause)
@@ -1139,7 +1374,7 @@ update:
     }
   else
     {
-      if (FRAME_VISIBLE_P (selected_frame))
+      if (FRAME_VISIBLE_P (selected_frame) && !FRAME_OBSCURED_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
       else
        pause = 0;
@@ -1175,7 +1410,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;
     }
 
@@ -1188,6 +1423,7 @@ update:
 
       blank_end_of_window = 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);
 
@@ -1202,11 +1438,22 @@ update:
          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);
+
+         /* 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)
+                                  || highlight_nonselected_windows)
+                              && !NILP (XBUFFER (w->buffer)->mark_active)
+                              ? Fmarker_position (XBUFFER (w->buffer)->mark)
+                              : Qnil);
+
          w->window_end_valid = w->buffer;
-         last_arrow_position = Voverlay_arrow_position;
+         last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
          last_arrow_string = Voverlay_arrow_string;
          if (do_verify_charstarts)
            verify_charstarts (w);
@@ -1228,13 +1475,38 @@ update:
     request_sigio ();
   start_polling ();
 
+  /* If something has become visible now which was not before,
+     redisplay again, so that we get them.  */
+  if (!pause)
+    {
+      Lisp_Object tail, frame;
+      int new_count = 0;
+
+      FOR_EACH_FRAME (tail, frame)
+       {
+         int this_is_visible = 0;
+
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+         FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+
+         if (this_is_visible)
+           new_count++;
+       }
+
+      if (new_count != number_of_visible_frames)
+       windows_or_buffers_changed++;
+    }
+
   /* Change frame size now if a change is pending.  */
   do_pending_window_change ();
 
-  /* If we just did a pending size change, redisplay again
-     for the new size.  */
+  /* If we just did a pending size change, or have additional
+     visible frames, redisplay again.  */
   if (windows_or_buffers_changed && !pause)
-    redisplay ();
+    goto retry;
 }
 
 /* Redisplay, but leave alone any recent echo area message
@@ -1245,6 +1517,7 @@ update:
    area to be cleared.  See tracking_off and
    wait_reading_process_input for examples of these situations.  */
 
+void
 redisplay_preserve_echo_area ()
 {
   if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
@@ -1273,6 +1546,8 @@ 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);
@@ -1280,7 +1555,8 @@ mark_window_display_accurate (window, flag)
          /* 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)
+                              && (w == XWINDOW (current_buffer->last_selected_window)
+                                  || highlight_nonselected_windows)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
                               : Qnil);
@@ -1299,7 +1575,7 @@ mark_window_display_accurate (window, flag)
 
   if (flag)
     {
-      last_arrow_position = Voverlay_arrow_position;
+      last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
       last_arrow_string = Voverlay_arrow_string;
     }
   else
@@ -1361,7 +1637,7 @@ update_menu_bar (f, save_match_data)
 
          set_buffer_internal_1 (XBUFFER (w->buffer));
          if (save_match_data)
-           record_unwind_protect (Fstore_match_data, Fmatch_data ());
+           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
          if (NILP (Voverriding_local_map_menu_flag))
            {
              specbind (Qoverriding_terminal_local_map, Qnil);
@@ -1409,6 +1685,43 @@ redisplay_windows (window, preserve_echo_area)
     redisplay_window (window, 0, preserve_echo_area);
 }
 
+/* Return value in display table DP (Lisp_Char_Table *) for character
+   C.  Since a display table doesn't have any parent, we don't have to
+   follow parent.  Do not call this function directly but use the
+   macro DISP_CHAR_VECTOR.  */
+Lisp_Object
+disp_char_vector (dp, c)
+     struct Lisp_Char_Table *dp;
+     int c;
+{
+  int code[4], i;
+  Lisp_Object val;
+
+  if (SINGLE_BYTE_CHAR_P (c)) return (dp->contents[c]);
+  
+  SPLIT_NON_ASCII_CHAR (c, code[0], code[1], code[2]);
+  if (code[0] != CHARSET_COMPOSITION)
+    {
+      if (code[1] < 32) code[1] = -1;
+      else if (code[2] < 32) code[2] = -1;
+    }
+  /* Here, the possible range of CODE[0] (== charset ID) is
+     128..MAX_CHARSET.  Since the top level char table contains data
+     for multibyte characters after 256th element, we must increment
+     CODE[0] by 128 to get a correct index.  */
+  code[0] += 128;
+  code[3] = -1;                /* anchor */
+
+  for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
+    {
+      val = dp->contents[code[i]];
+      if (!SUB_CHAR_TABLE_P (val))
+       return (NILP (val) ? dp->defalt : val);
+    }
+  /* Here, VAL is a sub char table.  We return the default value of it.  */
+  return (dp->defalt);
+}
+
 /* Redisplay window WINDOW and its subwindows.  */
 
 static void
@@ -1419,16 +1732,24 @@ redisplay_window (window, just_this_one, preserve_echo_area)
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
   int height;
-  register int lpoint = PT;
+  int lpoint = PT;
+  int lpoint_byte = PT_BYTE;
   struct buffer *old = current_buffer;
   register int width = window_internal_width (w) - 1;
-  register int startp;
+  register int startp, startp_byte;
   register int hscroll = XINT (w->hscroll);
   struct position pos;
   int opoint = PT;
+  int opoint_byte = PT_BYTE;
   int tem;
   int update_mode_line;
   struct Lisp_Char_Table *dp = window_display_table (w);
+  int really_switched_buffer = 0;
+
+  if (Z == Z_BYTE && lpoint != lpoint_byte)
+    abort ();
+  if (lpoint_byte < lpoint)
+    abort ();
 
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
@@ -1467,7 +1788,9 @@ redisplay_window (window, just_this_one, preserve_echo_area)
          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, 0);
            }
          
          goto finish_scroll_bars;
@@ -1477,18 +1800,29 @@ redisplay_window (window, just_this_one, preserve_echo_area)
   /* Otherwise set up data on this window; select its buffer and point value */
 
   if (update_mode_line)
-    set_buffer_internal_1 (XBUFFER (w->buffer));
+    /* Really select the buffer, for the sake of buffer-local variables.  */
+    {
+      set_buffer_internal_1 (XBUFFER (w->buffer));
+      really_switched_buffer = 1;
+    }
   else
     set_buffer_temp (XBUFFER (w->buffer));
 
   opoint = PT;
+  opoint_byte = PT_BYTE;
+
+  if (Z == Z_BYTE && opoint != opoint_byte)
+    abort ();
+  if (opoint_byte < opoint)
+    abort ();
 
   /* 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_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
       && XFASTINT (w->column_number_displayed) != current_column ())
     update_mode_line = 1; 
 
@@ -1513,19 +1847,22 @@ redisplay_window (window, just_this_one, preserve_echo_area)
 
   if (!EQ (window, selected_window))
     {
-      int new_pt = marker_position (w->pointm);
+      int new_pt = XMARKER (w->pointm)->charpos;
+      int new_pt_byte = marker_byte_position (w->pointm);
       if (new_pt < BEGV)
        {
          new_pt = BEGV;
-         Fset_marker (w->pointm, make_number (new_pt), Qnil);
+         new_pt_byte = BEGV_BYTE;
+         set_marker_both (w->pointm, Qnil, BEGV, BEGV_BYTE);
        }
       else if (new_pt > (ZV - 1))
        {
          new_pt = ZV;
-         Fset_marker (w->pointm, make_number (new_pt), Qnil);
+         new_pt_byte = ZV_BYTE;
+         set_marker_both (w->pointm, Qnil, ZV, ZV_BYTE);
        }
       /* We don't use SET_PT so that the point-motion hooks don't run.  */
-      BUF_PT (current_buffer) = new_pt;
+      TEMP_SET_PT_BOTH (new_pt, new_pt_byte);
     }
 
   /* If any of the character widths specified in the display table
@@ -1552,6 +1889,32 @@ redisplay_window (window, just_this_one, preserve_echo_area)
     goto recenter;
 
   startp = marker_position (w->start);
+  startp_byte = marker_byte_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, startp_byte), 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.  */
@@ -1572,8 +1935,12 @@ redisplay_window (window, just_this_one, preserve_echo_area)
        {
          Lisp_Object temp[3];
 
-         set_buffer_temp (old);
-         set_buffer_internal_1 (XBUFFER (w->buffer));
+         if (!really_switched_buffer)
+           {
+             set_buffer_temp (old);
+             set_buffer_internal_1 (XBUFFER (w->buffer));
+           }
+         really_switched_buffer = 1;
          update_mode_line = 1;
          w->update_mode_line = Qt;
          if (! NILP (Vwindow_scroll_functions))
@@ -1584,8 +1951,9 @@ redisplay_window (window, just_this_one, preserve_echo_area)
            }
        }
       XSETFASTINT (w->last_modified, 0);
-      if (startp < BEGV) startp = BEGV;
-      if (startp > ZV)   startp = ZV;
+      XSETFASTINT (w->last_overlay_modified, 0);
+      if (startp < BEGV) startp = BEGV, startp_byte = BEGV_BYTE;
+      if (startp > ZV)   startp = ZV, startp = ZV_BYTE;
       try_window (window, startp);
       if (cursor_vpos < 0)
        {
@@ -1598,15 +1966,20 @@ redisplay_window (window, just_this_one, preserve_echo_area)
                                 0,
                                 ZV, height / 2,
                                 - (1 << (BITS_PER_SHORT - 1)),
-                                width, hscroll, pos_tab_offset (w, startp), w);
-         BUF_PT (current_buffer) = pos.bufpos;
+                                width, hscroll,
+                                pos_tab_offset (w, startp, startp_byte),
+                                w);
+         TEMP_SET_PT_BOTH (pos.bufpos, pos.bytepos);
          if (w != XWINDOW (selected_window))
-           Fset_marker (w->pointm, make_number (PT), Qnil);
+           set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
          else
            {
              if (current_buffer == old)
-               lpoint = PT;
-             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+               {
+                 lpoint = PT;
+                 lpoint_byte = PT_BYTE;
+               }
+             FRAME_CURSOR_X (f) = (WINDOW_LEFT_MARGIN (w)
                                    + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
@@ -1633,8 +2006,9 @@ redisplay_window (window, just_this_one, preserve_echo_area)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
+      && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF
       && PT >= startp && !current_buffer->clip_changed
-      && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      && (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.  */
@@ -1645,19 +2019,75 @@ redisplay_window (window, just_this_one, preserve_echo_area)
       /* If end pos is out of date, scroll bar and percentage will be wrong */
       && INTEGERP (w->window_end_vpos)
       && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
-      && !EQ (window, minibuf_window))
+      && !EQ (window, minibuf_window)
+      && (!MARKERP (Voverlay_arrow_position)
+         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
     {
-      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
-                           PT, height, 0, width, hscroll,
-                           pos_tab_offset (w, startp), w);
+      /* All positions in this clause are relative to the window edge.  */
+
+      int this_scroll_margin = scroll_margin;
+      int last_point_y = XFASTINT (w->last_point_y) - XINT (w->top);
+      int last_point_x = (XFASTINT (w->last_point_x) - WINDOW_LEFT_MARGIN (w));
+
+      /* Find where PT is located now on the frame.  */
+      /* Check just_this_one as a way of verifying that the 
+        window edges have not changed.  */
+      if (PT == XFASTINT (w->last_point) && just_this_one)
+       {
+         pos.hpos = last_point_x;
+         pos.vpos = last_point_y;
+         pos.bufpos = PT;
+       }
+      else if (PT > XFASTINT (w->last_point)
+              && XFASTINT (w->last_point) > startp && just_this_one
+              /* We can't use this if point is in the left margin of a
+                 hscrolled window, because w->last_point_x has been
+                 clipped to the window edges.  */
+              && !(last_point_x <= 0 && hscroll))
+       {
+         int last_point = XFASTINT (w->last_point);
+         int last_point_byte = CHAR_TO_BYTE (last_point);
+         int tab_offset = (pos_tab_offset (w, last_point, last_point_byte)
+                           - (last_point_x + hscroll - !! hscroll));
+
+         pos = *compute_motion (last_point, last_point_y, last_point_x, 0,
+                                PT, height,
+                                /* BUG FIX: See the comment of 
+                                   Fpos_visible_in_window_p (window.c).  */
+                                - (1 << (BITS_PER_SHORT - 1)),
+                                width, hscroll,
+                                tab_offset,
+                                w);
+       }
+      else
+       {
+         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, startp_byte),
+                                w);
+       }
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
 
-      if (pos.vpos < height)
+      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) = (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);
            }
@@ -1665,9 +2095,14 @@ redisplay_window (window, just_this_one, preserve_echo_area)
             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);
             */
+         if (current_buffer->clip_changed
+             && ! NILP (Vwindow_scroll_functions))
+           run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                 make_number (marker_position (w->start)));
+
          goto done;
        }
       /* Don't bother trying redisplay with same start;
@@ -1677,7 +2112,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
      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_byte - 1) == '\n'))
     {
       goto recenter;
     }
@@ -1689,7 +2124,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
           && ! EQ (w->window_end_valid, Qnil)
           && 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))
@@ -1697,7 +2132,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
              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_position, COERCE_MARKER (Voverlay_arrow_position))
           && EQ (last_arrow_string, Voverlay_arrow_string)
           && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
           && tem != -2)
@@ -1720,7 +2155,8 @@ redisplay_window (window, just_this_one, preserve_echo_area)
               || preserve_echo_area
 #endif
               || startp == BEGV
-              || (XFASTINT (w->last_modified) >= MODIFF)))
+              || (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 */
@@ -1731,6 +2167,12 @@ redisplay_window (window, just_this_one, preserve_echo_area)
              || beg_unchanged < startp)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
+
+         if (current_buffer->clip_changed
+             && ! NILP (Vwindow_scroll_functions))
+           run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                 make_number (marker_position (w->start)));
+
          goto done;
        }
       else
@@ -1738,17 +2180,114 @@ redisplay_window (window, just_this_one, preserve_echo_area)
     }
 
   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_1 (XBUFFER (w->buffer));
+      if (!really_switched_buffer)
+       {
+         set_buffer_temp (old);
+         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_conservatively && !current_buffer->clip_changed
+      && startp >= BEGV && startp <= ZV)
+    {
+      int this_scroll_margin = scroll_margin;
+      int scroll_margin_pos;
+
+      /* 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 * this_scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      scroll_margin_pos = Z - XFASTINT (w->window_end_pos);
+      if (this_scroll_margin)
+       {
+         pos = *vmotion (scroll_margin_pos, -this_scroll_margin, w);
+         scroll_margin_pos = pos.bufpos;
+       }
+      if (PT >= scroll_margin_pos)
+       {
+         struct position pos;
+         pos = *compute_motion (scroll_margin_pos, 0, 0, 0,
+                                PT, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp, startp_byte),
+                                w);
+         if (pos.vpos > scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, pos.vpos + 1, w);
+
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             set_marker_both (w->start, Qnil, pos.bufpos, pos.bytepos);
+             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_margin_pos = startp;
+      if (this_scroll_margin)
+       {
+         pos = *vmotion (scroll_margin_pos, this_scroll_margin, w);
+         scroll_margin_pos = pos.bufpos;
+       }
+      if (PT < scroll_margin_pos)
+       {
+         struct position pos;
+         pos = *compute_motion (PT, 0, 0, 0,
+                                scroll_margin_pos, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp, startp_byte),
+                                w);
+         if (pos.vpos > scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, -pos.vpos, w);
+
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             set_marker_both (w->start, Qnil, pos.bufpos, pos.bytepos);
+             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)
     {
@@ -1765,7 +2304,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
        {
          if (! NILP (Vwindow_scroll_functions))
            {
-             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             set_marker_both (w->start, Qnil, pos.bufpos, pos.bytepos);
              run_hook_with_args_2 (Qwindow_scroll_functions, window,
                                    make_number (pos.bufpos));
              pos.bufpos = marker_position (w->start);
@@ -1792,31 +2331,61 @@ recenter:
   w->base_line_number = Qnil;
 
   pos = *vmotion (PT, - (height / 2), w);
+
+  /* The minibuffer is often just one line.  Ordinary scrolling
+     gives little overlap and looks bad.  So show 20 chars before point.  */
+  if (height == 1
+      && (pos.bufpos >= PT - minibuffer_scroll_overlap
+         /* If we scrolled less than 1/2 line forward, we will
+            get too much overlap, so change to the usual amount.  */
+         || pos.bufpos < startp + width / 2)
+      && PT > BEGV + minibuffer_scroll_overlap
+      /* If we scrolled to an actual line boundary,
+        that's different; don't ignore line boundaries.  */
+      && FETCH_BYTE (pos.bytepos - 1) != '\n')
+    {
+      pos.bufpos = PT - minibuffer_scroll_overlap;
+      pos.bytepos = CHAR_TO_BYTE (pos.bufpos);
+    }
+    
   /* 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);
+  set_marker_both (w->start, Qnil, pos.bufpos, pos.bytepos);
   if (! NILP (Vwindow_scroll_functions))
     {
       run_hook_with_args_2 (Qwindow_scroll_functions, window,
                            make_number (pos.bufpos));
       pos.bufpos = marker_position (w->start);
+      pos.bytepos = marker_byte_position (w->start);
     }
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
+  startp_byte = marker_byte_position (w->start);
   w->start_at_line_beg
-    = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
+    = (startp == BEGV || FETCH_BYTE (startp_byte - 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 ()))
       && height != XFASTINT (w->height))
-    display_mode_line (w);
+    {
+      FRAME_PTR oframe = selected_frame;
+      if (!really_switched_buffer)
+       {
+         set_buffer_temp (old);
+         set_buffer_internal_1 (XBUFFER (w->buffer));
+         really_switched_buffer = 1;
+       }
+      selected_frame = f;
+      display_mode_line (w);
+      selected_frame = oframe;
+    }
   if (! line_number_displayed
       && ! BUFFERP (w->base_line_pos))
     {
@@ -1872,12 +2441,12 @@ done:
       (*redeem_scroll_bar_hook) (w);
     }
 
-  BUF_PT (current_buffer) = opoint;
-  if (update_mode_line)
+  TEMP_SET_PT_BOTH (opoint, opoint_byte);
+  if (really_switched_buffer)
     set_buffer_internal_1 (old);
   else
     set_buffer_temp (old);
-  BUF_PT (current_buffer) = lpoint;
+  TEMP_SET_PT_BOTH (lpoint, lpoint_byte);
 }
 \f
 /* Do full redisplay on one window, starting at position `pos'. */
@@ -1891,44 +2460,52 @@ 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;
 
-  Fset_marker (w->start, make_number (pos), Qnil);
+  /* POS should never be out of range!  */
+  if (pos < XBUFFER (w->buffer)->begv
+      || pos > XBUFFER (w->buffer)->zv)
+    abort ();
+
+  if (XMARKER (w->start)->charpos != pos)
+    Fset_marker (w->start, make_number (pos), Qnil);
+
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
   zv_strings_seen = 0;
   val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
+  val.ovstring_chars_done = 0;
+  val.bytepos = marker_byte_position (w->start);
+  val.tab_offset = pos_tab_offset (w, pos, val.bytepos);
 
   while (--height >= 0)
     {
-      val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
+      val = *display_text_line (w, pos, val.bytepos, 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)
        {
          int invis = 0;
 #ifdef USE_TEXT_PROPERTIES
          Lisp_Object invis_prop;
-         invis_prop = Fget_char_property (val.bufpos-1, Qinvisible, window);
+         invis_prop = Fget_char_property (make_number (val.bufpos - 1),
+                                          Qinvisible, window);
          invis = TEXT_PROP_MEANS_INVISIBLE (invis_prop);
 #endif
 
          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.bytepos - 1) != '\n' || invis));
        }
       pos = val.bufpos;
     }
@@ -1961,7 +2538,8 @@ static int
 try_window_id (window)
      Lisp_Object window;
 {
-  int pos;
+  int pos, pos_byte;
+  int opoint, opoint_byte;
   register struct window *w = XWINDOW (window);
   register int height = window_internal_height (w);
   FRAME_PTR f = XFRAME (w->frame);
@@ -1978,11 +2556,12 @@ try_window_id (window)
   int selective = (INTEGERP (current_buffer->selective_display)
                   ? XINT (current_buffer->selective_display)
                   : !NILP (current_buffer->selective_display) ? -1 : 0);
-
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
   int delta;
-  int tab_offset, epto, old_tick;
+  int epto, old_tick;
+
+  int start_byte = marker_byte_position (w->start);
 
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
@@ -1994,8 +2573,13 @@ try_window_id (window)
 
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin, 0,
-                       min (ZV, beg_unchanged + BEG), height, 0,
-                       width, hscroll, pos_tab_offset (w, start), w);
+                       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, start_byte),
+                       w);
   if (bp.vpos >= height)
     {
       if (PT < bp.bufpos)
@@ -2005,8 +2589,12 @@ try_window_id (window)
             But we need to update window_end_pos to account for
             any change in buffer size.  */
          bp = *compute_motion (start, 0, lmargin, 0,
-                               ZV, height, 0,
-                               width, hscroll, pos_tab_offset (w, start), w);
+                               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, start_byte), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
          goto findpoint;
@@ -2020,6 +2608,7 @@ try_window_id (window)
   bp = *vmotion (bp.bufpos, 0, w);
 
   pos = bp.bufpos;
+  pos_byte = bp.bytepos;
   val.hpos = lmargin;
   if (pos < start)
     return -1;
@@ -2036,27 +2625,36 @@ try_window_id (window)
       bp = *vmotion (bp.bufpos, -1, w);
       --vpos;
       pos = bp.bufpos;
+      pos_byte = bp.bytepos;
     }
+  val.tab_offset = bp.tab_offset; /* Update tab offset.  */
 
   if (bp.contin && bp.hpos != lmargin)
     {
       val.hpos = bp.prevhpos - width + lmargin;
+      val.tab_offset = bp.tab_offset + bp.prevhpos - width;
       did_motion = 1;
-      pos--;
+      DEC_BOTH (pos, pos_byte);
     }
 
   bp.vpos = vpos;
 
   /* Find first visible newline after which no more is changed.  */
-  tem = find_next_newline (Z - max (end_unchanged, Z - ZV), 1);
+  opoint = PT, opoint_byte = PT_BYTE;
+  SET_PT (Z - max (end_unchanged, Z - ZV));
+  scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 1);
   if (selective > 0)
-    while (tem < ZV - 1 && (indented_beyond_p (tem, selective)))
-      tem = find_next_newline (tem, 1);
+    while (PT < ZV - 1 && indented_beyond_p (PT, PT_BYTE, selective))
+      scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 1);
+  tem = PT;
+  SET_PT_BOTH (opoint, opoint_byte);
 
   /* Compute the cursor position after that newline.  */
   ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
                        height, - (1 << (BITS_PER_SHORT - 1)),
-                       width, hscroll, pos_tab_offset (w, bp.bufpos), w);
+                       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.  */
@@ -2072,7 +2670,7 @@ 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.bytepos - 1) != '\n'
          || ep.bufpos == Z - end_unchanged))
     stop_vpos = ep.vpos + 1;
 
@@ -2085,46 +2683,52 @@ try_window_id (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, 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++)
+      for (i = ep.bytepos; i < xp.bytepos; i++)
        {
-         tem = FETCH_CHAR (i);
+         tem = FETCH_BYTE (i);
          if (tem != ' ' && tem != '\n' && tem != '\t')
            break;
        }
-      if (i == xp.bufpos)
+      if (i == xp.bytepos)
        return -2;
 
       XSETFASTINT (w->window_end_vpos,
                   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, 1,
                                    PT, height, - (1 << (BITS_PER_SHORT - 1)),
-                                   width, hscroll, epto, w);
+                                   width, hscroll,
+                                   /* We have tab offset in EP, use it.  */
+                                   ep.tab_offset, w);
            }
          else
            {
              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 = XFASTINT (w->left) + minmax (0, pp.hpos, width);
+         cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, pp.hpos, width);
        }
 
       if (stop_vpos - scroll_amount >= height
@@ -2220,28 +2824,40 @@ try_window_id (window)
   if (vpos == 0 && pos < marker_position (w->start))
     Fset_marker (w->start, make_number (pos), Qnil);
 
+  val.bytepos = pos_byte;
+
   /* Redisplay the lines where the text was changed */
   last_text_vpos = vpos;
-  tab_offset = pos_tab_offset (w, pos);
+  /* The following code is omitted because we maintain tab offset in
+     val.tab_offset.  */
+#if 0
+  tab_offset = pos_tab_offset (w, pos, pos_byte);
   /* 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, val.bytepos, 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.bytepos - 1) != '\n');
       pos = val.bufpos;
     }
 
@@ -2268,27 +2884,44 @@ try_window_id (window)
       FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
       vpos = xp.vpos;
       pos = xp.bufpos;
-      val.hpos = lmargin;
+      pos_byte = xp.bytepos;
+      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_BOTH (pos, pos_byte);
        }
 
       blank_end_of_window = 1;
-      tab_offset = pos_tab_offset (w, pos);
+      /* The following code is omitted because we maintain tab offset
+        in val.tab_offset.  */
+#if 0
+      tab_offset = pos_tab_offset (w, pos, pos_byte);
       /* 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
+      val.bytepos = pos_byte;
       while (vpos < height)
        {
-         val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+         val = *display_text_line (w, pos, val.bytepos,
+                                   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;
        }
 
@@ -2325,8 +2958,14 @@ try_window_id (window)
   if (cursor_vpos < 0)
     {
     findpoint:
-      val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
-                            width, hscroll, pos_tab_offset (w, start), w);
+      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, start_byte),
+                            w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
        {
@@ -2335,7 +2974,7 @@ try_window_id (window)
          return 0;
        }
       cursor_vpos = val.vpos + top;
-      cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
+      cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, val.hpos, width);
     }
 
   FRAME_CURSOR_X (f) = cursor_hpos;
@@ -2345,7 +2984,9 @@ try_window_id (window)
     {
       val = *compute_motion (start, 0, lmargin, 0, ZV,
                             height, - (1 << (BITS_PER_SHORT - 1)),
-                            width, hscroll, pos_tab_offset (w, start), w);
+                            width, hscroll,
+                            pos_tab_offset (w, start, start_byte),
+                            w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
        abort ();
       if (XFASTINT (w->window_end_pos)
@@ -2356,76 +2997,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.
    Value is TO, advanced past the copied data.
@@ -2450,8 +3021,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.  */
@@ -2467,7 +3043,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;
       }
@@ -2502,7 +3078,37 @@ fix_glyph (f, glyph, cface)
   return glyph;
 }
 \f
-/* Display one line of window W, starting at position START in W's buffer.
+/* Return the column of position POS / POS_BYTE in window W's buffer.
+   When used on the character at the beginning of a line,
+   starting at column 0, this says how much to subtract from
+   the column position of any character in the line
+   to get its horizontal position on the screen.  */
+
+static int
+pos_tab_offset (w, pos, pos_byte)
+     struct window *w;
+     register int pos, pos_byte;
+{
+  int opoint = PT;
+  int opoint_byte = PT_BYTE;
+  int col;
+  int width = window_internal_width (w) - 1;
+
+  if (pos == BEGV)
+    return MINI_WINDOW_P (w) ? -minibuf_prompt_width : 0;
+
+  if (FETCH_BYTE (pos_byte - 1) == '\n')
+    return 0;
+
+  TEMP_SET_PT_BOTH (pos, pos_byte);
+  col = current_column ();
+  TEMP_SET_PT_BOTH (opoint, opoint_byte);
+
+  return col;
+}
+\f\f
+/* Display one line of window W, starting at char position START in W's buffer.
+   START_BYTE is the corresponding byte position.
 
    Display starting at horizontal position HPOS, expressed relative to
    W's left edge.  In situations where the text at START shouldn't
@@ -2514,6 +3120,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.
 
@@ -2524,43 +3133,46 @@ 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, start_byte, vpos, hpos, taboffset, ovstr_done)
      struct window *w;
      int start;
      int vpos;
      int hpos;
      int taboffset;
+     int ovstr_done;
 {
   register int pos = start;
+  int pos_byte = start_byte;
   register int c;
   register GLYPH *p1;
-  register int pause;
+  int pause, limit_byte;
   register unsigned char *p;
   GLYPH *endp;
   register GLYPH *leftmargin;
   register GLYPH *p1prev;
   register GLYPH *p1start;
-  int prevpos;
+  GLYPH *p1_wide_column_end = (GLYPH *) 0;
+  int prevpos, prevpos_byte;
   int *charstart;
   FRAME_PTR f = XFRAME (w->frame);
   int tab_width = XINT (current_buffer->tab_width);
   int ctl_arrow = !NILP (current_buffer->ctl_arrow);
   int width = window_internal_width (w) - 1;
   struct position val;
-  int lastpos;
+  int lastpos, lastpos_byte;
   int invis;
   int last_invis_skip = 0;
   Lisp_Object last_invis_prop;
   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.  */
+  /* 1 if this buffer has a region to highlight.  */
   int highlight_region
     = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
-       && XWINDOW (current_buffer->last_selected_window) == w);
+       && XMARKER (current_buffer->mark)->buffer != 0);
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
@@ -2586,10 +3198,21 @@ 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;
@@ -2605,15 +3228,16 @@ 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));
+  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.  */
-  if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
+  if (highlight_region
       /* Maybe highlight only in selected window.  */
       && (highlight_nonselected_windows
-         || w == XWINDOW (selected_window)))
+         || w == XWINDOW (selected_window)
+         || (MINI_WINDOW_P (XWINDOW (selected_window))
+             && w == XWINDOW (Vminibuf_scroll_window))))
     {
       region_beg = marker_position (current_buffer->mark);
       if (PT < region_beg)
@@ -2626,7 +3250,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
       w->region_showing = Qt;
     }
   else
-    region_beg = region_end = -1;
+    {
+      region_beg = region_end = -1;
+      w->region_showing = Qnil;
+    }
 
   if (MINI_WINDOW_P (w)
       && start == BEG
@@ -2634,19 +3261,24 @@ display_text_line (w, start, vpos, hpos, taboffset)
     {
       if (! NILP (minibuf_prompt))
        {
+         int old_width = minibuf_prompt_width;
+
          minibuf_prompt_width
            = (display_string (w, vpos, XSTRING (minibuf_prompt)->data,
-                              XSTRING (minibuf_prompt)->size, hpos,
+                              STRING_BYTES (XSTRING (minibuf_prompt)),
+                              hpos + WINDOW_LEFT_MARGIN (w),
                               /* Display a space if we truncate.  */
                               ' ',
                               1, -1,
                               /* Truncate the prompt a little before the
                                  margin, so user input can at least start
                                  on the first line.  */
-                              w->width > 10 ? w->width - 4 : -1)
-              - hpos);
+                              (XFASTINT (w->width) > 10
+                               ? XFASTINT (w->width) - 4 : -1),
+                              STRING_MULTIBYTE (minibuf_prompt))
+              - hpos - WINDOW_LEFT_MARGIN (w));
          hpos += minibuf_prompt_width;
-         taboffset -= minibuf_prompt_width;
+         taboffset -= minibuf_prompt_width - old_width;
        }
       else
        minibuf_prompt_width = 0;
@@ -2673,23 +3305,28 @@ 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;
+         pos_byte = left_edge->bytepos;
+         DEC_BOTH (pos, pos_byte);
           hpos = left_edge->prevhpos;
         }
       else
         {
           pos = left_edge->bufpos;
+         pos_byte = left_edge->bytepos;
           hpos = left_edge->hpos;
         }
     }
 
+  hpos += WINDOW_LEFT_MARGIN (w);
+
   desired_glyphs->bufp[vpos] = start;
   p1 = desired_glyphs->glyphs[vpos] + hpos;
   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
@@ -2704,11 +3341,23 @@ display_text_line (w, start, vpos, hpos, taboffset)
      if reach or pass continuation column,
      or at face change.  */
   pause = pos;
+  limit_byte = pos_byte;
   next_face_change = pos;
   next_boundary = pos;
   p1prev = p1;
   prevpos = pos;
-  while (1)
+  prevpos_byte = pos_byte;
+
+  /* If the window is hscrolled and point is in the invisible part of the
+     current line beyond the left margin we can record the cursor location
+     right away.  */
+  if (hscroll && start <= PT && PT < pos && cursor_vpos < 0)
+    {
+      cursor_vpos = vpos;
+      cursor_hpos = p1 - leftmargin;
+    }
+
+  while (p1 < endp)
     {
       if (pos >= pause)
        {
@@ -2724,13 +3373,47 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (pos < ZV || !zv_strings_seen++)
                {
                  int ovlen;
-                 char *ovstr;
+                 unsigned char *ovstr;
                  ovlen = overlay_strings (pos, w, &ovstr);
-                 for (; ovlen; ovlen--, ovstr++)
+
+                 if (ovlen > 0)
                    {
-                     if (p1 >= leftmargin && p1 < endp)
-                       *p1 = MAKE_GLYPH (f, *ovstr, current_face);
-                     p1++;
+                     /* 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;
                    }
                }
 
@@ -2750,7 +3433,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
              /* 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);
+               {
+                 int limitpos = pos + 50;
+                 XSETFASTINT (limit, limitpos);
+               }
              limit = Fnext_single_property_change (position, Qinvisible,
                                                    Fcurrent_buffer (), limit);
 #endif
@@ -2767,6 +3453,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
                      cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_boundary;
+                 pos_byte = CHAR_TO_BYTE (pos);
                  last_invis_skip = pos;
                  last_invis_prop = prop;
                }
@@ -2831,9 +3518,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
             loop, to see what face we should start with.  */
          if (pos >= next_face_change
              && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
-           current_face = compute_char_face (f, w, pos,
-                                             region_beg, region_end,
-                                             &next_face_change, pos + 50, 0);
+           {
+             int limit = pos + 50;
+
+             current_face = compute_char_face (f, w, pos,
+                                               region_beg, region_end,
+                                               &next_face_change, limit, 0);
+           }
 #endif
 
          /* Compute the next place we need to stop
@@ -2856,63 +3547,98 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
-         p = &FETCH_CHAR (pos);
+         /* LIMIT_BYTE is not the same place in the buffer as PAUSE.
+            It is a limit on valid characters.
+            We use it to bound STRING_CHAR_AND_LENGTH.  */
+         limit_byte = ZV_BYTE;
+         if (pos < GPT && GPT_BYTE < limit_byte)
+           limit_byte = GPT_BYTE;
+
+         {
+           int temp = CHAR_TO_BYTE (pos);
+           p = BYTE_POS_ADDR (temp);
+         }
        }
 
       if (p1 >= endp)
        break;
 
       p1prev = p1;
+      p1_wide_column_end = (GLYPH *) 0;
 
-      c = *p++;
+      if (multibyte)
+       c = STRING_CHAR_AND_LENGTH (p, limit_byte - pos_byte, 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')
        {
+#if 0
+         /* Same as p1prev, but after the invis_vector_contents text
+            (if we have that on this line).  */
+         GLYPH *p1prev_modified;
+#endif
+
          invis = 0;
          if (last_invis_skip == pos
              && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
            invis = 1;
          while (pos + 1 < ZV
                 && selective > 0
-                && indented_beyond_p (pos + 1, selective))
+                && indented_beyond_p (pos + 1, pos_byte + 1, selective))
            {
+             int opoint = PT, opoint_byte = PT_BYTE;
+
              invis = 1;
-             pos = find_next_newline (pos + 1, 1);
-             if (FETCH_CHAR (pos - 1) == '\n')
-               pos--;
+             INC_BOTH (pos, pos_byte);
+             scan_newline (pos, pos_byte, ZV, ZV_BYTE, 1, 1);
+             pos = PT, pos_byte = PT_BYTE;
+             if (FETCH_BYTE (pos_byte - 1) == '\n')
+               {
+                 pos--;
+                 pos_byte--;
+               }
+             SET_PT_BOTH (opoint, opoint_byte);
            }
          if (invis && selective_rlen > 0 && p1 >= leftmargin)
            {
+#if 0
+             GLYPH *cs, *csend;
+
+             cs = charstart + (p1 - p1start);
+#endif
+
              p1 += selective_rlen;
              if (p1 - leftmargin > width)
                p1 = endp;
+
+#if 0 /* This needs more work; charstarts needs to record
+        both whether a position ho;ds an ellipsis character
+        and what buffer position it corresponds to.  */
+             csend = charstart + (p1 - p1start);
+             while (cs != csend)
+               *cs++ = -2;
+             /* The idea is to use p1prev_modified instead of p1prev
+                in the loop below over p2x.  */
+             p1prev_modified = p1;
+#endif
+
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
-           }
-#ifdef HAVE_FACES
-         /* Draw the face of the newline character as extending all the 
-            way to the end of the frame line.  */
-         if (current_face)
-           {
-             if (p1 < leftmargin)
-               p1 = leftmargin;
-             while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+                                (p1 - p1prev), 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
@@ -2931,6 +3657,17 @@ display_text_line (w, start, vpos, hpos, taboffset)
              while (p2x < p2)
                *p2x++ = -1;
            }
+#ifdef HAVE_FACES
+         /* Draw the face of the newline character as extending all the 
+            way to the end of the frame line.  */
+         if (current_face)
+           {
+             if (p1 < leftmargin)
+               p1 = leftmargin;
+             while (p1 < endp)
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
+           }
+#endif
 
          break;
        }
@@ -2939,7 +3676,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))
@@ -2947,16 +3684,20 @@ 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')
-           pos--;
+         int opoint = PT, opoint_byte = PT_BYTE;
+         scan_newline (pos, pos_byte, ZV, ZV_BYTE, 1, 1);
+         pos = PT, pos_byte = PT_BYTE;
+         SET_PT_BOTH (opoint, opoint_byte);
+
+         if (FETCH_BYTE (pos_byte - 1) == '\n')
+           pos--, pos_byte--;
          if (selective_rlen > 0)
            {
              p1 += selective_rlen;
              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 
@@ -2966,7 +3707,7 @@ 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
 
@@ -2992,34 +3733,74 @@ display_text_line (w, start, vpos, hpos, taboffset)
       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
        {
-         if (p1 >= leftmargin)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-                                ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-                            current_face);
-         p1++;
-         if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
-         p1++;
-         if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
-         p1++;
-         if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
-         p1++;
+         /* C is a multibyte character or a character to be displayed
+             by octral form.  */
+         int remaining_bytes = len;
+
+         if (c >= 0400)
+           {
+             /* 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++;
+               }
+             p1_wide_column_end = p1;
+             remaining_bytes -= CHARSET_BYTES (charset);
+           }
+
+         while (remaining_bytes > 0)
+           {
+             c = *(p - remaining_bytes--);
+
+             if (p1 >= leftmargin && p1 < endp)
+               *p1 = (fix_glyph
+                      (f,
+                       (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+                        && GLYPH_CHAR_VALID_P (XINT (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)
+                      | rev_dir_bit);
+             p1++;
+             if (p1 >= leftmargin && p1 < endp)
+               *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)
+                      | rev_dir_bit);
+             p1++;
+           }
        }
 
       prevpos = pos;
+      prevpos_byte = pos_byte;
       pos++;
+      pos_byte += len;
 
       /* Update charstarts for the character just output.  */
 
@@ -3051,6 +3832,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
   val.vpos = 1;
 
   lastpos = pos;
+  lastpos_byte = pos_byte;
 
   /* Store 0 in this charstart line for the positions where
      there is no character.  But do leave what was recorded
@@ -3072,10 +3854,39 @@ 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;
+         pos_byte = prevpos_byte;
+
+         if (p1_wide_column_end < endp)
+           /* As ENDP is not in the middle of wide-column character,
+              we can break the line at ENDP 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
+           {
+             /* We displayed a wide-column character at around ENDP.
+                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;
+             lastpos_byte = pos_byte;
+             if (PT == pos)
+               cursor_vpos = -1;
+           }
        }
 
       /* Keep in this line everything up to the continuation column.  */
@@ -3089,41 +3900,58 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   if (pos < ZV)
     {
-      if (FETCH_CHAR (pos) == '\n')
+      if (FETCH_BYTE (pos_byte) == '\n')
        {
+         int opoint = PT, opoint_byte = PT_BYTE;
+
          /* If stopped due to a newline, start next line after it */
-         pos++;
+         SET_PT_BOTH (pos + 1, pos_byte + 1);
+
+         val.tab_offset = 0;
          /* Check again for hidden lines, in case the newline occurred exactly
             at the right margin.  */
-         while (pos < ZV && selective > 0
-                && indented_beyond_p (pos, selective))
-           pos = find_next_newline (pos, 1);
+         while (PT < ZV && selective > 0
+                && indented_beyond_p (PT, PT_BYTE, selective))
+           scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 1);
+
+         pos = PT, pos_byte = PT_BYTE;
+         SET_PT_BOTH (opoint, opoint_byte);
        }
       else
        /* Stopped due to right margin of window */
        {
          if (truncate)
            {
+             int opoint = PT, opoint_byte = PT_BYTE;
+
+             SET_PT_BOTH (pos, pos_byte);
              *p1++ = fix_glyph (f, truncator, 0);
              /* Truncating => start next line after next newline,
                 and point is on this line if it is before the newline,
                 and skip none of first char of next line */
              do
-               pos = find_next_newline (pos, 1);
-             while (pos < ZV && selective > 0
-                    && indented_beyond_p (pos, selective));
+               scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 1);
+             while (PT < ZV && selective > 0
+                    && indented_beyond_p (PT, PT_BYTE, selective));
+             pos = PT, pos_byte = PT_BYTE;
              val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
+             SET_PT_BOTH (opoint, opoint_byte);
 
-             lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
+             lastpos = pos - (FETCH_BYTE (pos_byte - 1) == '\n');
+             lastpos_byte = CHAR_TO_BYTE (lastpos);
+             val.tab_offset = 0;
            }
          else
            {
              *p1++ = fix_glyph (f, continuer, 0);
              val.vpos = 0;
-             lastpos--;
+             DEC_BOTH (lastpos, lastpos_byte);
+             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.  */
@@ -3138,7 +3966,7 @@ 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)))
        {
          if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
@@ -3152,14 +3980,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
            {
              /* 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)
                {
                  this_line_bufpos = start;
                  this_line_buffer = current_buffer;
                  this_line_vpos = cursor_vpos;
-                 this_line_start_hpos = hpos;
+                 this_line_start_hpos = hpos - WINDOW_LEFT_MARGIN (w);
                  this_line_endpos = Z - lastpos;
                }
              else
@@ -3171,12 +3999,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;
@@ -3186,15 +4021,15 @@ 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.  */
-      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++)
            *p1++ = SPACEGLYPH;
        }
-      else
+      else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
        *p1++ = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
-                ? DISP_BORDER_GLYPH (dp)
+                ? XINT (DISP_BORDER_GLYPH (dp))
                 : '|');
     }
   desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
@@ -3210,34 +4045,36 @@ display_text_line (w, start, vpos, hpos, taboffset)
       && STRINGP (Voverlay_arrow_string)
       && ! overlay_arrow_seen)
     {
-      unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
-      int i;
+      int i, i_byte;
       int len = XSTRING (Voverlay_arrow_string)->size;
       int arrow_end;
 
       if (len > width)
        len = width;
-#ifdef HAVE_FACES
-      if (!NULL_INTERVAL_P (XSTRING (Voverlay_arrow_string)->intervals))
+
+      /* If the arrow string has text props, obey them when displaying.  */
+      for (i = 0, i_byte = 0; i < len; )
        {
-         /* If the arrow string has text props, obey them when displaying.  */
-         for (i = 0; i < len; i++)
-           {
-             int c = p[i];
-             Lisp_Object face, ilisp;
-             int newface;
+         int c;
+         Lisp_Object face, ilisp;
+         int newface;
+         int idx = i;
+
+         if (STRING_MULTIBYTE (Voverlay_arrow_string))
+           FETCH_STRING_CHAR_ADVANCE (c, Voverlay_arrow_string, i, i_byte);
+         else
+           c = XSTRING (Voverlay_arrow_string)->data[i++];
 
-             XSETFASTINT (ilisp, i);
+         XSETFASTINT (ilisp, i);
+#ifdef HAVE_FACES
+         if (FRAME_WINDOW_P (f))
+           {
              face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
              newface = compute_glyph_face_1 (f, face, 0);
-             leftmargin[i] = FAST_MAKE_GLYPH (c, newface);
+             c = FAST_MAKE_GLYPH (c, newface);
            }
-       }
-      else
 #endif /* HAVE_FACES */
-       {
-         for (i = 0; i < len; i++)
-           leftmargin[i] = p[i];
+         leftmargin[idx] = c;
        }
 
       /* Bug in SunOS 4.1.1 compiler requires this intermediate variable.  */
@@ -3249,6 +4086,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
     }
 
   val.bufpos = pos;
+  val.bytepos = pos_byte;
+  val.ovstring_chars_done = ovstr_done;
   val_display_text_line = val;
   return &val_display_text_line;
 }
@@ -3289,16 +4128,17 @@ display_menu_bar (w)
       XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
 
       if (hpos < maxendcol)
-       hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
+       hpos = display_string (w, vpos,
                               XSTRING (string)->data,
-                              XSTRING (string)->size,
-                              hpos, 0, 0, hpos, maxendcol);
+                              STRING_BYTES (XSTRING (string)),
+                              hpos, 0, 0, hpos, maxendcol,
+                              STRING_MULTIBYTE (string));
       /* Put a space between items.  */
       if (hpos < maxendcol)
        {
          int hpos1 = hpos + 1;
          hpos = display_string (w, vpos, "", 0, hpos, 0, 0,
-                                min (hpos1, maxendcol), maxendcol);
+                                min (hpos1, maxendcol), maxendcol, 0);
        }
     }
 
@@ -3307,7 +4147,7 @@ display_menu_bar (w)
 
   /* Fill out the line with spaces.  */
   if (maxendcol > hpos)
-    hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol);
+    hpos = display_string (w, vpos, "", 0, hpos, 0, 0, maxendcol, maxendcol, 0);
 
   /* Clear the rest of the lines allocated to the menu bar.  */
   vpos++;
@@ -3322,8 +4162,8 @@ 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;
@@ -3343,25 +4183,34 @@ display_mode_line (w)
 
   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) && mode_line_inverse_video)
+  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.
@@ -3423,7 +4272,8 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                  hpos = store_frame_title (last, hpos, min (lim, maxendcol));
                else
                  hpos = display_string (w, vpos, last, -1, hpos, 0, 1,
-                                        hpos, min (lim, maxendcol));
+                                        hpos, min (lim, maxendcol),
+                                        STRING_MULTIBYTE (elt));
              }
            else /* c == '%' */
              {
@@ -3460,7 +4310,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                    else
                      hpos = display_string (w, vpos, spec, -1,
                                             hpos, 0, 1,
-                                            minendcol, maxendcol);
+                                            minendcol, maxendcol, -1);
                  }
              }
          }
@@ -3487,8 +4337,9 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                                            minendcol, maxendcol);
                else
                  hpos = display_string (w, vpos, XSTRING (tem)->data,
-                                        XSTRING (tem)->size,
-                                        hpos, 0, 1, minendcol, maxendcol);
+                                        STRING_BYTES (XSTRING (tem)),
+                                        hpos, 0, 1, minendcol, maxendcol,
+                                        STRING_MULTIBYTE (tem));
              }
            /* Give up right away for nil or t.  */
            else if (!EQ (tem, elt))
@@ -3582,7 +4433,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
        hpos = store_frame_title ("*invalid*", minendcol, maxendcol);
       else
        hpos = display_string (w, vpos, "*invalid*", -1, hpos, 0, 1,
-                              minendcol, maxendcol);
+                              minendcol, maxendcol, 0);
       return hpos;
     }
 
@@ -3590,7 +4441,8 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
     if (frame_title_ptr)
       hpos = store_frame_title ("", minendcol, maxendcol);
     else
-      hpos = display_string (w, vpos, "", 0, hpos, 0, 1, minendcol, maxendcol);
+      hpos = display_string (w, vpos, "", 0, hpos,
+                            0, 1, minendcol, maxendcol, 0);
   return hpos;
 }
 \f
@@ -3623,6 +4475,68 @@ pint2str (buf, width, 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;
+{
+  Lisp_Object val;
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+
+  val = coding_system;
+
+  if (NILP (val))              /* Not yet decided.  */
+    {
+      if (multibyte)
+       *buf++ = '-';
+      if (eol_flag)
+       *buf++ = eol_mnemonic_undecided;
+      /* Don't mention EOL conversion if it isn't decided.  */
+    }
+  else
+    {
+      Lisp_Object eolvalue;
+
+      eolvalue = Fget (coding_system, Qeol_type);
+
+      while (!NILP (val) && SYMBOLP (val))
+       {
+         val = Fget (val, Qcoding_system);
+         if (NILP (eolvalue))
+           eolvalue = Fget (val, Qeol_type);
+       }
+
+      if (multibyte)
+       *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+
+      if (eol_flag)
+       {
+         /* The EOL conversion we are using.  */
+         int eoltype;
+         /* The EOL conversion that is normal on this system.  */
+
+         if (NILP (eolvalue))  /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else if (VECTORP (eolvalue)) /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else                  /* INTEGERP (eolvalue) -- 0:LF, 1:CRLF, 2:CR */
+           eoltype = (XFASTINT (eolvalue) == 0
+                      ? eol_mnemonic_unix
+                      : (XFASTINT (eolvalue) == 1
+                         ? eol_mnemonic_dos : eol_mnemonic_mac));
+
+         /* Mention the EOL conversion if it is not the usual one.  */
+         *buf++ = eoltype;
+       }
+    }
+  return buf;
+}
+
 /* Return a string for the output of a mode line %-spec for window W,
    generated by character C.  SPEC_WIDTH is the field width when
    padding to the left (%c, %l).  The value returned from this
@@ -3719,7 +4633,7 @@ decode_mode_spec (w, c, spec_width, maxwidth)
     case 'b': 
       obj = b->name;
 #if 0
-      if (maxwidth >= 3 && XSTRING (obj)->size > maxwidth)
+      if (maxwidth >= 3 && STRING_BYTES (XSTRING (obj)) > maxwidth)
        {
          bcopy (XSTRING (obj)->data, decode_mode_spec_buf, maxwidth - 1);
          decode_mode_spec_buf[maxwidth - 1] = '\\';
@@ -3739,7 +4653,10 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 
     case 'F':
       /* %F displays the frame name.  */
-      if (!NILP (f->title))
+      /* Systems that can only display a single frame at a time should
+        NOT replace the frame name with the (constant) frame title,
+        since then they won't be able to tell which frame is that.  */
+      if (FRAME_WINDOW_P (f) && !NILP (f->title))
        return (char *) XSTRING (f->title)->data;
       if (f->explicit_name || ! FRAME_WINDOW_P (f))
        return (char *) XSTRING (f->name)->data;
@@ -3750,10 +4667,10 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 #if 0
       if (NILP (obj))
        return "[none]";
-      else if (STRINGP (obj) && XSTRING (obj)->size > maxwidth)
+      else if (STRINGP (obj) && STRING_BYTES (XSTRING (obj)) > maxwidth)
        {
          bcopy ("...", decode_mode_spec_buf, 3);
-         bcopy (XSTRING (obj)->data + XSTRING (obj)->size - maxwidth + 3,
+         bcopy (XSTRING (obj)->data + STRING_BYTES (XSTRING (obj)) - maxwidth + 3,
                 decode_mode_spec_buf + 3, maxwidth - 3);
          return decode_mode_spec_buf;
        }
@@ -3762,8 +4679,9 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 
     case 'l':
       {
-       int startpos = marker_position (w->start);
-       int line, linepos, topline;
+       int startpos = XMARKER (w->start)->charpos;
+       int startpos_byte = marker_byte_position (w->start);
+       int line, linepos, linepos_byte, topline;
        int nlines, junk;
        Lisp_Object tem;
        int height = XFASTINT (w->height);
@@ -3772,6 +4690,9 @@ decode_mode_spec (w, c, spec_width, maxwidth)
           don't forget that too fast.  */
        if (EQ (w->base_line_pos, w->buffer))
          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)
@@ -3783,19 +4704,23 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 
        if (!NILP (w->base_line_number)
            && !NILP (w->base_line_pos)
-           && XFASTINT (w->base_line_pos) <= marker_position (w->start))
+           && XFASTINT (w->base_line_pos) <= startpos)
          {
            line = XFASTINT (w->base_line_number);
            linepos = XFASTINT (w->base_line_pos);
+           linepos_byte = buf_charpos_to_bytepos (b, linepos);
          }
        else
          {
            line = 1;
            linepos = BUF_BEGV (b);
+           linepos_byte = BUF_BEGV_BYTE (b);
          }
 
        /* Count lines from base line to window start position.  */
-       nlines = display_count_lines (linepos, startpos, startpos, &junk);
+       nlines = display_count_lines (linepos, linepos_byte,
+                                     startpos_byte,
+                                     startpos, &junk);
 
        topline = nlines + line;
 
@@ -3812,19 +4737,24 @@ decode_mode_spec (w, c, spec_width, maxwidth)
                 || linepos == BUF_BEGV (b))
          {
            int limit = BUF_BEGV (b);
+           int limit_byte = BUF_BEGV_BYTE (b);
            int position;
            int distance = (height * 2 + 30) * 200;
 
            if (startpos - distance > limit)
-             limit = startpos - distance;
+             {
+               limit = startpos - distance;
+               limit_byte = CHAR_TO_BYTE (limit);
+             }
 
-           nlines = display_count_lines (startpos, limit,
-                                         -(height * 2 + 30),
+           nlines = display_count_lines (startpos, startpos_byte,
+                                         limit_byte,
+                                         - (height * 2 + 30),
                                          &position);
            /* If we couldn't find the lines we wanted within 
               200 chars per line,
               give up on line numbers for this window.  */
-           if (position == startpos - distance)
+           if (position == limit_byte && limit == startpos - distance)
              {
                w->base_line_pos = w->buffer;
                w->base_line_number = Qnil;
@@ -3832,11 +4762,12 @@ decode_mode_spec (w, c, spec_width, maxwidth)
              }
 
            XSETFASTINT (w->base_line_number, topline - nlines);
-           XSETFASTINT (w->base_line_pos, position);
+           XSETFASTINT (w->base_line_pos, BYTE_TO_CHAR (position));
          }
 
        /* Now count lines from the start pos to point.  */
-       nlines = display_count_lines (startpos, PT, PT, &junk);
+       nlines = display_count_lines (startpos, startpos_byte,
+                                     PT_BYTE, PT, &junk);
 
        /* Record that we did display the line number.  */
        line_number_displayed = 1;
@@ -3942,6 +4873,40 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 #else
       return "T";
 #endif
+
+    case 'z':
+      /* coding-system (not including end-of-line format) */
+    case 'Z':
+      /* coding-system (including end-of-line type) */
+      {
+       int eol_flag = (c == 'Z');
+       char *p = decode_mode_spec_buf;
+
+       if (! FRAME_WINDOW_P (f))
+         {
+           /* No need to mention EOL here--the terminal never needs
+              to do EOL conversion.  */
+           p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
+           p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+         }
+       p = decode_mode_spec_coding (b->buffer_file_coding_system,
+                                    p, eol_flag);
+
+#if 0 /* This proves to be annoying; I think we can do without.  -- rms.  */
+#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 */
+#endif /* 0 */
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
     }
 
   if (STRINGP (obj))
@@ -3950,137 +4915,109 @@ decode_mode_spec (w, c, spec_width, maxwidth)
     return "";
 }
 \f
-/* Search for COUNT instances of a line boundary, which means either a
-   newline or (if selective display enabled) a carriage return.
-   Start at START.  If COUNT is negative, search backwards.
-
-   If we find COUNT instances, set *SHORTAGE to zero, and return the
-   position after the COUNTth match.  Note that for reverse motion
-   this is not the same as the usual convention for Emacs motion commands.
+/* Count up to COUNT lines starting from START / START_BYTE.
+   But don't go beyond LIMIT_BYTE.
+   Return the number of lines thus found (always nonnegative).
 
-   If we don't find COUNT instances before reaching the end of the
-   buffer (or the beginning, if scanning backwards), set *SHORTAGE to
-   the number of line boundaries left unfound, and return the end of the
-   buffer we bumped up against.  */
+   Set *BYTE_POS_PTR to 1 if we found COUNT lines, 0 if we hit LIMIT.  */
 
 static int
-display_scan_buffer (start, count, shortage)
-     int *shortage, start;
-     register int count;
+display_count_lines (start, start_byte, limit_byte, count, byte_pos_ptr)
+     int start, start_byte, limit_byte, count;
+     int *byte_pos_ptr;
 {
-  int limit = ((count > 0) ? ZV - 1 : BEGV);
-  int direction = ((count > 0) ? 1 : -1);
-
   register unsigned char *cursor;
   unsigned char *base;
 
   register int ceiling;
   register unsigned char *ceiling_addr;
+  int orig_count = count;
 
   /* If we are not in selective display mode,
      check only for newlines.  */
-  if (! (!NILP (current_buffer->selective_display)
-        && !INTEGERP (current_buffer->selective_display)))
-    return scan_buffer ('\n', start, 0, count, shortage, 0);
-
-  /* The code that follows is like scan_buffer
-     but checks for either newline or carriage return.  */
-
-  if (shortage != 0)
-    *shortage = 0;
+  int selective_display = (!NILP (current_buffer->selective_display)
+                          && !INTEGERP (current_buffer->selective_display));
 
   if (count > 0)
-    while (start != limit + 1)
-      {
-       ceiling =  BUFFER_CEILING_OF (start);
-       ceiling = min (limit, ceiling);
-       ceiling_addr = &FETCH_CHAR (ceiling) + 1;
-       base = (cursor = &FETCH_CHAR (start));
-       while (1)
-         {
-           while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
-             ;
-           if (cursor != ceiling_addr)
-             {
-               if (--count == 0)
-                 {
-                   immediate_quit = 0;
-                   return (start + cursor - base + 1);
-                 }
-               else
-                 if (++cursor == ceiling_addr)
-                   break;
-             }
-           else
-             break;
-         }
-       start += cursor - base;
-      }
+    {
+      while (start_byte < limit_byte)
+       {
+         ceiling =  BUFFER_CEILING_OF (start_byte);
+         ceiling = min (limit_byte - 1, ceiling);
+         ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
+         base = (cursor = BYTE_POS_ADDR (start_byte));
+         while (1)
+           {
+             if (selective_display)
+               while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
+                 ;
+             else
+               while (*cursor != '\n' && ++cursor != ceiling_addr)
+                 ;
+
+             if (cursor != ceiling_addr)
+               {
+                 if (--count == 0)
+                   {
+                     start_byte += cursor - base + 1;
+                     *byte_pos_ptr = start_byte;
+                     return orig_count;
+                   }
+                 else
+                   if (++cursor == ceiling_addr)
+                     break;
+               }
+             else
+               break;
+           }
+         start_byte += cursor - base;
+       }
+    }
   else
     {
-      start--;                 /* first character we scan */
-      while (start > limit - 1)
-       {                       /* 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));
-         cursor++;
+      while (start_byte > limit_byte)
+       {
+         ceiling = BUFFER_FLOOR_OF (start_byte - 1);
+         ceiling = max (limit_byte, ceiling);
+         ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
+         base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
          while (1)
            {
-             while (--cursor != ceiling_addr
-                    && *cursor != '\n' && *cursor != 015)
-               ;
+             if (selective_display)
+               while (--cursor != ceiling_addr
+                      && *cursor != '\n' && *cursor != 015)
+                 ;
+             else
+               while (--cursor != ceiling_addr && *cursor != '\n')
+                 ;
+
              if (cursor != ceiling_addr)
                {
                  if (++count == 0)
                    {
-                     immediate_quit = 0;
-                     return (start + cursor - base + 1);
+                     start_byte += cursor - base + 1;
+                     *byte_pos_ptr = start_byte;
+                     /* When scanning backwards, we should
+                        not count the newline posterior to which we stop.  */
+                     return - orig_count - 1;
                    }
                }
              else
                break;
            }
-         start += cursor - base;
+         /* Here we add 1 to compensate for the last decrement
+            of CURSOR, which took it past the valid range.  */
+         start_byte += cursor - base + 1;
        }
     }
 
-  if (shortage != 0)
-    *shortage = count * direction;
-  return (start + ((direction == 1 ? 0 : 1)));
-}
+  *byte_pos_ptr = limit_byte;
 
-/* Count up to N lines starting from FROM.
-   But don't go beyond LIMIT.
-   Return the number of lines thus found (always positive).
-   Store the position after what was found into *POS_PTR.  */
+  if (count < 0)
+    return - orig_count + count;
+  return orig_count - count;
 
-static int
-display_count_lines (from, limit, n, pos_ptr)
-     int from, limit, n;
-     int *pos_ptr;
-{
-  int oldbegv = BEGV;
-  int oldzv = ZV;
-  int shortage = 0;
-  
-  if (limit < from)
-    BEGV = limit;
-  else
-    ZV = limit;
-
-  *pos_ptr = display_scan_buffer (from, n, &shortage);
-
-  ZV = oldzv;
-  BEGV = oldbegv;
-
-  if (n < 0)
-    /* When scanning backwards, scan_buffer stops *after* the last newline
-       it finds, but does count it.  Compensate for that.  */
-    return - n - shortage - (*pos_ptr != limit);
-  return n - shortage;
-}  
+}
 \f
 /* Display STRING on one line of window W, starting at HPOS.
    Display at position VPOS.  Caller should have done get_display_line.
@@ -4101,11 +5038,15 @@ display_count_lines (from, limit, n, pos_ptr)
   and not display anything beyond there.  Otherwise, only MAXCOL
   controls where to stop output.
 
+  MULTIBYTE can be 0 meaning do not display multibyte chars,
+  1 meaning do display them, or -1 meaning obey the current buffer's
+  value of enable_multibyte_characters.
+
   Returns ending hpos.  */
 
 static int
 display_string (w, vpos, string, length, hpos, truncate,
-               obey_window_width, mincol, maxcol)
+               obey_window_width, mincol, maxcol, multibyte)
      struct window *w;
      unsigned char *string;
      int length;
@@ -4113,6 +5054,7 @@ display_string (w, vpos, string, length, hpos, truncate,
      GLYPH truncate;
      int obey_window_width;
      int mincol, maxcol;
+     int multibyte;
 {
   register int c;
   int truncated;
@@ -4131,28 +5073,33 @@ display_string (w, vpos, string, length, hpos, truncate,
   register struct Lisp_Char_Table *dp = 0;
   int i;
 
+  if (multibyte == -1)
+    multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  /* Now multibyte is 1 if we should display multibyte characters.  */
+
   if (DISP_TABLE_P (Vstandard_display_table))
     dp = XCHAR_TABLE (Vstandard_display_table);
 
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
   p1 = p1start;
-  start = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+  start = desired_glyphs->glyphs[vpos];
 
   if (obey_window_width)
     {
+      start += XFASTINT (w->left);
       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-- = '|';
        }
     }
@@ -4168,20 +5115,25 @@ display_string (w, vpos, string, length, hpos, truncate,
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
+  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)
        {
@@ -4215,20 +5167,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';
@@ -4240,6 +5197,48 @@ 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 (truncated)
@@ -4387,6 +5386,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",
@@ -4399,12 +5408,14 @@ If this is zero, point is always centered after it moves off frame.");
   mode_line_inverse_video = 1;
 
   DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
-    "*Maximum buffer size for which line number should be displayed.");
+    "*Maximum buffer size (in characters) for line number display\n\
+If the buffer is bigger than this, the line number does not appear\n\
+in the mode line..");
   line_number_display_limit = 1000000;
 
   DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
     "*Non-nil means highlight region even in nonselected windows.");
-  highlight_nonselected_windows = 1;
+  highlight_nonselected_windows = 0;
 
   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
     "Non-nil if more than one frame is visible on this display.\n\
@@ -4450,14 +5461,20 @@ 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\
+    "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;
+
+  DEFVAR_INT ("minibuffer-scroll-overlap", &minibuffer_scroll_overlap,
+    "*Number of characters of overlap when scrolling a one-line window.\n\
+This commonly affects the minibuffer window, hence the name of the variable.");
+  minibuffer_scroll_overlap = 20;
 }
 
 /* initialize the window system */
+void
 init_xdisp ()
 {
   Lisp_Object root_window;
@@ -4477,8 +5494,10 @@ init_xdisp ()
   if (!noninteractive)
     {
       FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
-      XSETFASTINT (XWINDOW (root_window)->top, 0);
-      set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
+      XSETFASTINT (XWINDOW (root_window)->top, FRAME_MENU_BAR_LINES (f));
+      set_window_height (root_window,
+                        FRAME_HEIGHT (f) - 1 - FRAME_MENU_BAR_LINES (f),
+                        0);
       XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
       set_window_height (minibuf_window, 1, 0);