(Qforeground_color, Qbackground_color): Declare.
[bpt/emacs.git] / src / xdisp.c
index 65b4c2c..84a80d5 100644 (file)
@@ -1,5 +1,5 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 1997
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 1998
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -40,6 +40,11 @@ Boston, MA 02111-1307, USA.  */
 #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 ();
@@ -114,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;
 
@@ -125,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.  */
@@ -153,6 +160,10 @@ static int scroll_conservatively;
    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;
@@ -211,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;
 
@@ -247,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.  */
 
@@ -254,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];
@@ -316,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;
     }
 }
 
@@ -352,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++)
     {
@@ -394,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);
@@ -461,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.
@@ -474,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
@@ -546,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),
                            FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
 #else
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_MESSAGE_BUF_SIZE (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);
@@ -586,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
@@ -630,7 +779,8 @@ echo_area_display ()
                      echo_area_glyphs ? echo_area_glyphs_length : -1,
                      FRAME_LEFT_SCROLL_BAR_WIDTH (f),
                      0, 0, 0,
-                     FRAME_WIDTH (f) + FRAME_LEFT_SCROLL_BAR_WIDTH (f));
+                     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 */
@@ -654,7 +804,8 @@ echo_area_display ()
            display_string (XWINDOW (mini_window), i,
                            "", 0, 
                             0, 0, 0,
-                            0, FRAME_WIDTH (f) + FRAME_SCROLL_BAR_WIDTH (f));
+                            0, FRAME_WIDTH (f) + FRAME_SCROLL_BAR_WIDTH (f),
+                           0);
          }
       }
     }
@@ -731,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);
 }
@@ -783,7 +934,7 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
       int count = specpdl_ptr - specpdl;
 
-      record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
+      record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -869,7 +1020,7 @@ redisplay_internal (preserve_echo_area)
   int all_windows;
   register int tlbufpos, tlendpos;
   struct position pos;
-  int number_of_frames_redisplayed;
+  int number_of_visible_frames;
 
   if (noninteractive)
     return;
@@ -899,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));
@@ -947,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;
 
@@ -970,14 +1126,12 @@ redisplay_internal (preserve_echo_area)
                  Fmarker_position (XBUFFER (w->buffer)->mark))))
     this_line_bufpos = -1;
 
-  /* This is in case we goto update, below.  */
-  number_of_frames_redisplayed = 1;
-
   tlbufpos = this_line_bufpos;
   tlendpos = this_line_endpos;
   if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
       && !current_buffer->clip_changed
       && FRAME_VISIBLE_P (XFRAME (w->frame))
+      && !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)
@@ -1001,9 +1155,10 @@ redisplay_internal (preserve_echo_area)
              && end_unchanged >= tlendpos
              && Z - GPT >= tlendpos)))
     {
-      if (tlbufpos > BEGV && FETCH_BYTE (tlbufpos - 1) != '\n'
+      int tlbufpos_byte = CHAR_TO_BYTE (tlbufpos);
+      if (tlbufpos > BEGV && FETCH_BYTE (tlbufpos_byte - 1) != '\n'
          && (tlbufpos == ZV
-             || FETCH_BYTE (tlbufpos) == '\n'))
+             || FETCH_BYTE (tlbufpos_byte) == '\n'))
        /* Former continuation line has disappeared by becoming empty */
        goto cancel;
       else if (XFASTINT (w->last_modified) < MODIFF
@@ -1026,9 +1181,11 @@ redisplay_internal (preserve_echo_area)
 
          struct position val;
          int prevline;
+         int opoint = PT, opoint_byte = PT_BYTE;
+
+         scan_newline (tlbufpos, tlbufpos_byte, BEGV, BEGV_BYTE, -1, 1);
 
-         prevline = find_next_newline (tlbufpos, -1);
-         val = *compute_motion (prevline, 0,
+         val = *compute_motion (PT, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
                                 0,
                                 tlbufpos,
@@ -1036,14 +1193,16 @@ redisplay_internal (preserve_echo_area)
                                 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), 0);
+         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
@@ -1108,7 +1267,8 @@ 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;
@@ -1147,7 +1307,6 @@ redisplay_internal (preserve_echo_area)
       /* Recompute # windows showing selected buffer.
         This will be incremented each time such a window is displayed.  */
       buffer_shared = 0;
-      number_of_frames_redisplayed = 0;
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -1160,11 +1319,8 @@ redisplay_internal (preserve_echo_area)
              if (condemn_scroll_bars_hook)
                (*condemn_scroll_bars_hook) (f);
 
-             if (FRAME_VISIBLE_P (f))
-               {
-                 redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
-                 number_of_frames_redisplayed++;
-               }
+             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
                 should now go away.  */
@@ -1173,12 +1329,11 @@ 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 (!WINDOW_FULL_WIDTH_P (w))
        preserve_other_columns (w);
-      number_of_frames_redisplayed = 1;
     }
 
 update: 
@@ -1205,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)
@@ -1219,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;
@@ -1298,7 +1453,7 @@ update:
                               : 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);
@@ -1330,6 +1485,7 @@ update:
       FOR_EACH_FRAME (tail, frame)
        {
          int this_is_visible = 0;
+
          if (XFRAME (frame)->visible)
            this_is_visible = 1;
          FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
@@ -1340,7 +1496,7 @@ update:
            new_count++;
        }
 
-      if (new_count != number_of_frames_redisplayed)
+      if (new_count != number_of_visible_frames)
        windows_or_buffers_changed++;
     }
 
@@ -1361,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)
@@ -1418,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
@@ -1480,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 (Qnil, Qnil));
+           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
          if (NILP (Voverriding_local_map_menu_flag))
            {
              specbind (Qoverriding_terminal_local_map, Qnil);
@@ -1575,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 */
 
@@ -1625,7 +1790,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
              get_display_line (f, vpos + i, 0);
              display_string (w, vpos + i, "", 0, 
                              FRAME_LEFT_SCROLL_BAR_WIDTH (f),
-                             0, 1, 0, width);
+                             0, 1, 0, width, 0);
            }
          
          goto finish_scroll_bars;
@@ -1635,11 +1800,21 @@ 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)
@@ -1672,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
@@ -1711,6 +1889,7 @@ 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.  */
@@ -1729,7 +1908,8 @@ redisplay_window (window, just_this_one, preserve_echo_area)
                             /* BUG FIX: See the comment of
                                 Fpos_visible_in_window_p (window.c).  */
                             - (1 << (BITS_PER_SHORT - 1)),
-                            width, hscroll, pos_tab_offset (w, startp), w);
+                            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)
@@ -1755,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))
@@ -1768,8 +1952,8 @@ redisplay_window (window, just_this_one, preserve_echo_area)
        }
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
-      if (startp < BEGV) startp = BEGV;
-      if (startp > ZV)   startp = ZV;
+      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)
        {
@@ -1782,14 +1966,19 @@ 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;
+               {
+                 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);
@@ -1830,17 +2019,57 @@ 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))
     {
+      /* 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));
 
-      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
-                            PT, height,
-                            /* BUG FIX: See the comment of
-                                Fpos_visible_in_window_p (window.c).  */
-                            - (1 << (BITS_PER_SHORT - 1)),
-                            width, hscroll,
-                            pos_tab_offset (w, startp), w);
+      /* 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)
@@ -1869,6 +2098,11 @@ redisplay_window (window, just_this_one, preserve_echo_area)
             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;
@@ -1878,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_BYTE (startp - 1) == '\n'))
+               || FETCH_BYTE (startp_byte - 1) == '\n'))
     {
       goto recenter;
     }
@@ -1898,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)
@@ -1933,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
@@ -1944,8 +2184,11 @@ redisplay_window (window, just_this_one, preserve_echo_area)
   /* 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;
     }
@@ -1956,29 +2199,37 @@ redisplay_window (window, just_this_one, preserve_echo_area)
       && 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 * scroll_margin)
+      if (XINT (w->height) < 4 * this_scroll_margin)
        this_scroll_margin = XINT (w->height) / 4;
 
-      if (PT >= Z - XFASTINT (w->window_end_pos))
+      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 (Z - XFASTINT (w->window_end_pos), 0, 0, 0,
+         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), w);
+                                pos_tab_offset (w, startp, startp_byte),
+                                w);
          if (pos.vpos > scroll_conservatively)
            goto scroll_fail_1;
 
-         pos = *vmotion (startp, pos.vpos + 1 + this_scroll_margin, w);
+         pos = *vmotion (startp, pos.vpos + 1, w);
 
          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);
@@ -1995,21 +2246,29 @@ redisplay_window (window, just_this_one, preserve_echo_area)
          else
            cancel_my_columns (w);
        }
-      if (PT < startp)
+
+      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,
-                                startp, XFASTINT (w->height), 0,
+                                scroll_margin_pos, XFASTINT (w->height), 0,
                                 XFASTINT (w->width), XFASTINT (w->hscroll),
-                                pos_tab_offset (w, startp), w);
-         if (pos.vpos >= scroll_conservatively)
+                                pos_tab_offset (w, startp, startp_byte),
+                                w);
+         if (pos.vpos > scroll_conservatively)
            goto scroll_fail_1;
 
-         pos = *vmotion (startp, - pos.vpos - this_scroll_margin, w);
+         pos = *vmotion (startp, -pos.vpos, w);
 
          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);
@@ -2045,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);
@@ -2072,20 +2331,39 @@ 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_BYTE (startp - 1) == '\n') ? Qt : Qnil;
+    = (startp == BEGV || FETCH_BYTE (startp_byte - 1) == '\n') ? Qt : Qnil;
 
 done:
   if ((update_mode_line
@@ -2096,7 +2374,18 @@ done:
        || (!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))
     {
@@ -2152,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'. */
@@ -2180,17 +2469,21 @@ try_window (window, pos)
       || pos > XBUFFER (w->buffer)->zv)
     abort ();
 
-  Fset_marker (w->start, make_number (pos), Qnil);
+  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.tab_offset = pos_tab_offset (w, pos);
+  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, val.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.  */
@@ -2204,14 +2497,15 @@ try_window (window, pos)
          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_BYTE (val.bufpos - 1) != '\n' || invis));
+                     && (FETCH_BYTE (val.bytepos - 1) != '\n' || invis));
        }
       pos = val.bufpos;
     }
@@ -2244,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);
@@ -2261,12 +2556,13 @@ 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 epto, old_tick;
 
+  int start_byte = marker_byte_position (w->start);
+
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
   if (Z - GPT < end_unchanged)
@@ -2279,9 +2575,11 @@ try_window_id (window)
   bp = *compute_motion (start, 0, lmargin, 0,
                        min (ZV, beg_unchanged + BEG), height,
                        /* BUG FIX: See the comment of
-                           Fpos_visible_in_window_p() (window.c).  */
+                           Fpos_visible_in_window_p (window.c).  */
                        - (1 << (BITS_PER_SHORT - 1)),
-                       width, hscroll, pos_tab_offset (w, start), w);
+                       width, hscroll,
+                       pos_tab_offset (w, start, start_byte),
+                       w);
   if (bp.vpos >= height)
     {
       if (PT < bp.bufpos)
@@ -2295,7 +2593,8 @@ try_window_id (window)
                                /* BUG FIX: See the comment of
                                    Fpos_visible_in_window_p() (window.c).  */
                                - (1 << (BITS_PER_SHORT - 1)),
-                               width, hscroll, pos_tab_offset (w, start), w);
+                               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;
@@ -2309,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;
@@ -2325,6 +2625,7 @@ 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.  */
 
@@ -2333,16 +2634,20 @@ try_window_id (window)
       val.hpos = bp.prevhpos - width + lmargin;
       val.tab_offset = bp.tab_offset + bp.prevhpos - width;
       did_motion = 1;
-      DEC_POS (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,
@@ -2365,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_BYTE (ep.bufpos - 1) != '\n'
+         || FETCH_BYTE (ep.bytepos - 1) != '\n'
          || ep.bufpos == Z - end_unchanged))
     stop_vpos = ep.vpos + 1;
 
@@ -2389,13 +2694,13 @@ try_window_id (window)
 
       /* 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_BYTE (i);
          if (tem != ' ' && tem != '\n' && tem != '\t')
            break;
        }
-      if (i == xp.bufpos)
+      if (i == xp.bytepos)
        return -2;
 
       XSETFASTINT (w->window_end_vpos,
@@ -2519,12 +2824,14 @@ 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;
   /* The following code is omitted because we maintain tab offset in
      val.tab_offset.  */
 #if 0
-  tab_offset = pos_tab_offset (w, pos);
+  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)
@@ -2533,7 +2840,8 @@ try_window_id (window)
   old_tick = MODIFF;
   while (vpos < stop_vpos)
     {
-      val = *display_text_line (w, pos, top + vpos++, val.hpos, val.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
@@ -2549,7 +2857,7 @@ try_window_id (window)
       if (pos != val.bufpos)
        last_text_vpos
          /* Next line, unless prev line ended in end of buffer with no cr */
-           = vpos - (val.vpos && FETCH_BYTE (val.bufpos - 1) != '\n');
+           = vpos - (val.vpos && FETCH_BYTE (val.bytepos - 1) != '\n');
       pos = val.bufpos;
     }
 
@@ -2576,6 +2884,7 @@ try_window_id (window)
       FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
       vpos = xp.vpos;
       pos = xp.bufpos;
+      pos_byte = xp.bytepos;
       val.hpos = xp.hpos;
       val.tab_offset = xp.tab_offset;
       if (pos == ZV)
@@ -2588,22 +2897,24 @@ try_window_id (window)
        {
          val.hpos = xp.prevhpos - width + lmargin;
          val.tab_offset = xp.tab_offset + bp.prevhpos - width;
-         DEC_POS (pos);
+         DEC_BOTH (pos, pos_byte);
        }
 
       blank_end_of_window = 1;
       /* The following code is omitted because we maintain tab offset
         in val.tab_offset.  */
 #if 0
-      tab_offset = pos_tab_offset (w, pos);
+      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,
+         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.  */
@@ -2652,7 +2963,9 @@ try_window_id (window)
                             1 << (BITS_PER_SHORT - 1),
                             /* ... nor HPOS.  */
                             1 << (BITS_PER_SHORT - 1),
-                            width, hscroll, pos_tab_offset (w, start), w);
+                            width, hscroll,
+                            pos_tab_offset (w, start, start_byte),
+                            w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
        {
@@ -2671,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)
@@ -2763,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
@@ -2788,7 +3133,7 @@ fix_glyph (f, glyph, cface)
 struct position val_display_text_line;
 
 static struct position *
-display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
+display_text_line (w, start, start_byte, vpos, hpos, taboffset, ovstr_done)
      struct window *w;
      int start;
      int vpos;
@@ -2797,22 +3142,24 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
      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;
@@ -2822,11 +3169,10 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
                      && !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
-          || highlight_nonselected_windows));
+       && XMARKER (current_buffer->mark)->buffer != 0);
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
@@ -2882,15 +3228,16 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
   XSETFASTINT (default_invis_vector[2], '.');
   default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
 
-  hpos += WINDOW_LEFT_MARGIN (w);
   get_display_line (f, vpos, WINDOW_LEFT_MARGIN (w));
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
   /* Show where to highlight the region.  */
-  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)
@@ -2914,9 +3261,12 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
     {
       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,
@@ -2924,10 +3274,11 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
                                  margin, so user input can at least start
                                  on the first line.  */
                               (XFASTINT (w->width) > 10
-                               ? XFASTINT (w->width) - 4 : -1))
-              - hpos);
+                               ? 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;
@@ -2955,18 +3306,20 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
           || left_edge->hpos > 0)
         {
           pos = left_edge->bufpos;
-         /* Since this should not be a valid multibyte character, we
-             can decrease POS by 1.  */
-         pos--;
+         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;
@@ -2988,10 +3341,22 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
      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;
+  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)
@@ -3070,8 +3435,6 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
              if (XFASTINT (limit) > pos + 50)
                {
                  int limitpos = pos + 50;
-                 if (limitpos < Z)
-                   INC_POS (limitpos); /* Adjust to character boundary.  */
                  XSETFASTINT (limit, limitpos);
                }
              limit = Fnext_single_property_change (position, Qinvisible,
@@ -3090,6 +3453,7 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
                      cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_boundary;
+                 pos_byte = CHAR_TO_BYTE (pos);
                  last_invis_skip = pos;
                  last_invis_prop = prop;
                }
@@ -3157,8 +3521,6 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
            {
              int limit = pos + 50;
 
-             if (limit < Z && !CHAR_HEAD_P (POS_ADDR (limit)))
-               INC_POS (limit); /* Adjust to character boundary.  */
              current_face = compute_char_face (f, w, pos,
                                                region_beg, region_end,
                                                &next_face_change, limit, 0);
@@ -3185,17 +3547,27 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
-         p = POS_ADDR (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;
 
       if (multibyte)
-       /* PAUSE is surely at character boundary.  */
-       c = STRING_CHAR_AND_LENGTH (p, pause - pos, len), p += len;
+       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.  */
@@ -3226,12 +3598,20 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
            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_BYTE (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)
            {
@@ -3304,9 +3684,13 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
        }
       else if (c == Ctl ('M') && selective == -1)
        {
-         pos = find_next_newline (pos, 1);
-         if (FETCH_BYTE (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;
@@ -3360,47 +3744,63 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
            *p1 = MAKE_GLYPH (f, c ^ 0100, current_face) | rev_dir_bit;
          p1++;
        }
-      else if (len == 1)
-       {
-         /* C is not a multibyte character.  */
-         if (p1 >= leftmargin)
-           *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++;
-       }
       else
        {
-         /* C is a multibyte character.  */
-         int charset = CHAR_CHARSET (c);
-         int columns = (charset == CHARSET_COMPOSITION
-                        ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
-                        : CHARSET_WIDTH (charset));
-         GLYPH g = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
+         /* 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 (columns--)
+         while (remaining_bytes > 0)
            {
+             c = *(p - remaining_bytes--);
+
              if (p1 >= leftmargin && p1 < endp)
-               *p1 = g, g |= GLYPH_MASK_PADDING;
+               *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;
-      pos += len;
+      prevpos_byte = pos_byte;
+      pos++;
+      pos_byte += len;
 
       /* Update charstarts for the character just output.  */
 
@@ -3432,6 +3832,7 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
   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
@@ -3457,18 +3858,19 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
              character code is C and the length of multi-byte form is
              LEN.  */
          pos = prevpos;
+         pos_byte = prevpos_byte;
 
-         if (len == 1)
-           /* C is not a multi-byte character.  We can break it and
-              start from the middle column in the next line.  So,
-              adjust VAL.HPOS to skip the columns output on this
-              line.  */
+         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
            {
-             /* C is a multibyte character.  Since we can't broke it
-                in the middle, the whole character should be driven
-                into the next line.  */
+             /* 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.  */
@@ -3481,6 +3883,7 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
              }
              /* If POINT is at POS, cursor should not on this line.  */
              lastpos = pos;
+             lastpos_byte = pos_byte;
              if (PT == pos)
                cursor_vpos = -1;
            }
@@ -3497,40 +3900,52 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
 
   if (pos < ZV)
     {
-      if (FETCH_BYTE (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_BYTE (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;
            }
        }
@@ -3572,7 +3987,7 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
                  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
@@ -3630,34 +4045,36 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
       && 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;
 
-             XSETFASTINT (ilisp, 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);
+#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.  */
@@ -3669,6 +4086,7 @@ display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
     }
 
   val.bufpos = pos;
+  val.bytepos = pos_byte;
   val.ovstring_chars_done = ovstr_done;
   val_display_text_line = val;
   return &val_display_text_line;
@@ -3712,14 +4130,15 @@ display_menu_bar (w)
       if (hpos < maxendcol)
        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);
        }
     }
 
@@ -3728,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++;
@@ -3853,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 == '%' */
              {
@@ -3890,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);
                  }
              }
          }
@@ -3917,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))
@@ -4012,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;
     }
 
@@ -4020,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
@@ -4064,12 +4486,14 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
      int eol_flag;
 {
   Lisp_Object val;
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
 
   val = coding_system;
 
   if (NILP (val))              /* Not yet decided.  */
     {
-      *buf++ = '-';
+      if (multibyte)
+       *buf++ = '-';
       if (eol_flag)
        *buf++ = eol_mnemonic_undecided;
       /* Don't mention EOL conversion if it isn't decided.  */
@@ -4084,10 +4508,12 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
        {
          val = Fget (val, Qcoding_system);
          if (NILP (eolvalue))
-           eolvalue = Fget (coding_system, Qeol_type);
+           eolvalue = Fget (val, Qeol_type);
        }
 
-      *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+      if (multibyte)
+       *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+
       if (eol_flag)
        {
          /* The EOL conversion we are using.  */
@@ -4207,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] = '\\';
@@ -4227,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;
@@ -4238,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;
        }
@@ -4250,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);
@@ -4274,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;
 
@@ -4303,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;
@@ -4323,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;
@@ -4440,9 +4880,9 @@ decode_mode_spec (w, c, spec_width, maxwidth)
       /* coding-system (including end-of-line type) */
       {
        int eol_flag = (c == 'Z');
-       char *p;
+       char *p = decode_mode_spec_buf;
 
-       if (FRAME_TERMCAP_P (f))
+       if (! FRAME_WINDOW_P (f))
          {
            /* No need to mention EOL here--the terminal never needs
               to do EOL conversion.  */
@@ -4450,7 +4890,7 @@ decode_mode_spec (w, c, spec_width, maxwidth)
            p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
          }
        p = decode_mode_spec_coding (b->buffer_file_coding_system,
-                                    decode_mode_spec_buf, eol_flag);
+                                    p, eol_flag);
 
 #if 0 /* This proves to be annoying; I think we can do without.  -- rms.  */
 #ifdef subprocesses
@@ -4475,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.
+/* 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 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.
-
-   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 = POS_ADDR (ceiling) + 1;
-       base = (cursor = POS_ADDR (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 = POS_ADDR (ceiling) - 1;
-         base = (cursor = POS_ADDR (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)));
-}
-
-/* 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.  */
-
-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);
+  *byte_pos_ptr = limit_byte;
 
-  ZV = oldzv;
-  BEGV = oldbegv;
+  if (count < 0)
+    return - orig_count + count;
+  return orig_count - count;
 
-  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.
@@ -4626,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;
@@ -4638,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;
@@ -4650,24 +5067,27 @@ display_string (w, vpos, string, length, hpos, truncate,
   struct frame_glyphs *desired_glyphs = FRAME_DESIRED_GLYPHS (f);
   GLYPH *p1start = desired_glyphs->glyphs[vpos] + hpos;
   int window_width = XFASTINT (w->width);
-  /* If 1, we must display multibyte characters.  */
-  int multibyte = !NILP (XBUFFER (w->buffer)->enable_multibyte_characters);
 
   /* Use the standard display table, not the window's display table.
      We don't want the mode line in rot13.  */
   register struct Lisp_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_RIGHTMOST_P (w))
@@ -4988,7 +5408,9 @@ of the top or bottom of the window.");
   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,
@@ -5039,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;