]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Delete the code that was trying to define BSD "right"
[gnu-emacs] / src / xdisp.c
index e89e843d6a25e92fa7325653673302201820cd25..37cf8f1820812e6dd1ef581814cb8078e9aa791d 100644 (file)
@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "charset.h"
 #include "indent.h"
 #include "commands.h"
 #include "macros.h"
@@ -36,14 +37,19 @@ Boston, MA 02111-1307, USA.  */
 #include "termhooks.h"
 #include "intervals.h"
 #include "keyboard.h"
+#include "coding.h"
+#include "process.h"
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
 extern void set_frame_menubar ();
+extern int pending_menu_activation;
 #endif
 
 extern int interrupt_input;
 extern int command_loop_level;
 
+extern int minibuffer_auto_raise;
+
 extern Lisp_Object Qface;
 
 extern Lisp_Object Voverriding_local_map;
@@ -138,6 +144,14 @@ static int highlight_nonselected_windows;
    Try scrolling this many lines up or down if that will bring it back.  */
 static int scroll_step;
 
+/* Non-0 means scroll just far enough to bring point back on the screen,
+   when appropriate.  */
+static int scroll_conservatively;
+
+/* Recenter the window whenever point gets within this many lines
+   of the top or bottom of the window.  */
+int scroll_margin;
+
 /* Nonzero if try_window_id has made blank lines at window bottom
  since the last redisplay that paused */
 static int blank_end_of_window;
@@ -159,6 +173,7 @@ static int debug_end_pos;
 /* Nonzero means display mode line highlighted */
 int mode_line_inverse_video;
 
+static void redisplay_internal ();
 static int message_log_check_duplicate ();
 static void echo_area_display ();
 void mark_window_display_accurate ();
@@ -209,10 +224,14 @@ int beg_unchanged;
 int end_unchanged;
 
 /* MODIFF as of last redisplay that finished;
-   if it matches MODIFF, beg_unchanged and end_unchanged
+   if it matches MODIFF, and overlay_unchanged_modified
+   matches OVERLAY_MODIFF, that means beg_unchanged and end_unchanged
    contain no useful information */
 int unchanged_modified;
 
+/* OVERLAY_MODIFF as of last redisplay that finished.  */
+int overlay_unchanged_modified;
+
 /* Nonzero if window sizes or contents have changed
    since last redisplay that finished */
 int windows_or_buffers_changed;
@@ -228,6 +247,8 @@ static int line_number_display_limit;
    t means infinite.  nil means don't log at all.  */
 Lisp_Object Vmessage_log_max;
 \f
+/* Output a newline in the *Messages* buffer if "needs" one.  */
+
 void
 message_log_maybe_newline ()
 {
@@ -323,7 +344,6 @@ message_dolog (m, len, nlflag)
     }
 }
 
-
 /* We are at the end of the buffer after just having inserted a newline.
    (Note: We depend on the fact we won't be crossing the gap.)
    Check to see if the most recent message looks a lot like the previous one.
@@ -361,11 +381,16 @@ message_log_check_duplicate (prev_bol, this_bol)
     }
   return 0;
 }
-
+\f
 /* Display an echo area message M with a specified length of LEN chars.
-   The string may include null characters.  If m is 0, clear out any
+   The string may include null characters.  If M is 0, clear out any
    existing message, and let the minibuffer text show through.
-   Do not pass text that is stored in a Lisp string.  */
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message2 (m, len)
@@ -380,7 +405,7 @@ message2 (m, len)
 }
 
 
-/* The non-logging part of that function.  */
+/* The non-logging counterpart of message2.  */
 
 void
 message2_nolog (m, len)
@@ -410,17 +435,18 @@ message2_nolog (m, len)
       mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
-#ifdef MULTI_FRAME
       FRAME_SAMPLE_VISIBILITY (f);
       if (FRAME_VISIBLE_P (selected_frame)
          && ! FRAME_VISIBLE_P (f))
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
-#endif
 
       if (m)
        {
          echo_area_glyphs = m;
          echo_area_glyphs_length = len;
+
+         if (minibuffer_auto_raise)
+           Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
        }
       else
        echo_area_glyphs = previous_echo_glyphs = 0;
@@ -433,6 +459,15 @@ message2_nolog (m, len)
        (*frame_up_to_date_hook) (f);
     }
 }
+\f
+/* Display a null-terminated echo area message M.  If M is 0, clear out any
+   existing message, and let the minibuffer text show through.
+
+   The buffer M must continue to exist until after the echo area
+   gets cleared or some other message gets displayed there.
+
+   Do not pass text that is stored in a Lisp string.
+   Do not pass text in a buffer that was alloca'd.  */
 
 void
 message1 (m)
@@ -466,8 +501,9 @@ truncate_echo_area (len)
    zero if being used by message.  */
 int message_buf_print;
 
-/* Dump an informative message to the minibuf.  If m is 0, clear out
+/* Dump an informative message to the minibuf.  If M is 0, clear out
    any existing message, and let the minibuffer text show through.  */
+
 /* VARARGS 1 */
 void
 message (m, a1, a2, a3)
@@ -515,10 +551,10 @@ message (m, a1, a2, a3)
              a[2] = a3;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_WIDTH (f), m, (char *)0, 3, a);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
 #else
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_WIDTH (f), m, (char *)0, 3, &a1);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
 
              message2 (FRAME_MESSAGE_BUF (f), len);
@@ -533,7 +569,7 @@ message (m, a1, a2, a3)
     }
 }
 
-/* The non-logging version of that function.  */
+/* The non-logging version of message.  */
 void
 message_nolog (m, a1, a2, a3)
      char *m;
@@ -551,7 +587,7 @@ update_echo_area ()
 {
   message2 (echo_area_glyphs, echo_area_glyphs_length);
 }
-
+\f
 static void
 echo_area_display ()
 {
@@ -576,14 +612,23 @@ echo_area_display ()
 
   if (echo_area_glyphs || minibuf_level == 0)
     {
+      int i;
+
       echo_area_window = mini_window;
 
       vpos = XFASTINT (XWINDOW (mini_window)->top);
       get_display_line (f, vpos, 0);
+
+      /* Make sure the columns that overlap a left-hand scroll bar
+        are always clear.  */
+      for (i = 0; i < FRAME_LEFT_SCROLL_BAR_WIDTH (f); i++)
+       f->desired_glyphs->glyphs[vpos][i] = SPACEGLYPH;
+
       display_string (XWINDOW (mini_window), vpos,
                      echo_area_glyphs ? echo_area_glyphs : "",
                      echo_area_glyphs ? echo_area_glyphs_length : -1,
-                     0, 0, 0, 0, FRAME_WIDTH (f));
+                     FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                     0, 0, 0, FRAME_WIDTH (f));
 
 #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 */
@@ -602,7 +647,9 @@ echo_area_display ()
          {
            get_display_line (f, i, 0);
            display_string (XWINDOW (mini_window), vpos,
-                           "", 0, 0, 0, 0, 0, FRAME_WIDTH (f));
+                           "", 0, 
+                            FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                           0, 0, 0, FRAME_WIDTH (f));
          }
       }
     }
@@ -614,6 +661,8 @@ echo_area_display ()
 
   previous_echo_glyphs = echo_area_glyphs;
 }
+\f
+/* Update frame titles.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
 static char frame_title_buf[512];
@@ -729,7 +778,7 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
       int count = specpdl_ptr - specpdl;
 
-      record_unwind_protect (Fstore_match_data, Fmatch_data ());
+      record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -758,6 +807,12 @@ prepare_menu_bars ()
     }
   else
     update_menu_bar (selected_frame, 1);
+
+  /* Motif needs this.  See comment in xmenu.c.
+     Turn it off when pending_menu_activation is not defined.  */
+#ifdef USE_X_TOOLKIT
+  pending_menu_activation = 0;
+#endif
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -789,6 +844,19 @@ static FRAME_PTR previous_terminal_frame;
 
 void
 redisplay ()
+{
+  redisplay_internal (0);
+}
+
+/* If PRESERVE_ECHO_AREA is nonzero, it means this redisplay
+   is not in response to any user action; therefore, we should
+   preserve the echo area.  (Actually, our caller does that job.)
+   Perhaps in the future avoid recentering windows
+   if it is not necessary; currently that causes some problems.  */
+
+static void
+redisplay_internal (preserve_echo_area)
+     int preserve_echo_area;
 {
   register struct window *w = XWINDOW (selected_window);
   register int pause;
@@ -800,8 +868,12 @@ redisplay ()
   if (noninteractive)
     return;
 
-#ifdef MULTI_FRAME
-  if (FRAME_TERMCAP_P (selected_frame)
+#ifdef USE_X_TOOLKIT
+  if (popup_activated ())
+    return;
+#endif
+
+  if (! FRAME_WINDOW_P (selected_frame)
       && previous_terminal_frame != selected_frame)
     {
       /* Since frames on an ASCII terminal share the same display area,
@@ -811,7 +883,6 @@ redisplay ()
       XSETFRAME (Vterminal_frame, selected_frame);
     }
   previous_terminal_frame = selected_frame;
-#endif
 
   /* Set the visible flags for all frames.
      Do this before checking for resized or garbaged frames; they want
@@ -844,9 +915,8 @@ redisplay ()
   if (windows_or_buffers_changed)
     update_mode_lines++;
 
-  /* Detect case that we need to write a star in the mode line.  */
-  if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= SAVE_MODIFF)
+  /* Detect case that we need to write or remove a star in the mode line.  */
+  if ((SAVE_MODIFF < MODIFF) != !NILP (w->last_had_star))
     {
       w->update_mode_line = Qt;
       if (buffer_shared > 1)
@@ -858,7 +928,8 @@ redisplay ()
       /* This alternative quickly identifies a common case
         where no change is needed.  */
       && !(PT == XFASTINT (w->last_point)
-          && XFASTINT (w->last_modified) >= MODIFF)
+          && XFASTINT (w->last_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
       && XFASTINT (w->column_number_displayed) != current_column ())
     w->update_mode_line = Qt; 
 
@@ -905,7 +976,8 @@ redisplay ()
       && PT <= Z - tlendpos
       /* All text outside that line, including its final newline,
         must be unchanged */
-      && (XFASTINT (w->last_modified) >= MODIFF
+      && ((XFASTINT (w->last_modified) >= MODIFF
+          && (XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF))
          || (beg_unchanged >= tlbufpos - 1
              && GPT >= tlbufpos
              /* If selective display, can't optimize
@@ -918,19 +990,49 @@ redisplay ()
              && end_unchanged >= tlendpos
              && Z - GPT >= tlendpos)))
     {
-      if (tlbufpos > BEGV && FETCH_CHAR (tlbufpos - 1) != '\n'
+      if (tlbufpos > BEGV && FETCH_BYTE (tlbufpos - 1) != '\n'
          && (tlbufpos == ZV
-             || FETCH_CHAR (tlbufpos) == '\n'))
+             || FETCH_BYTE (tlbufpos) == '\n'))
        /* Former continuation line has disappeared by becoming empty */
        goto cancel;
       else if (XFASTINT (w->last_modified) < MODIFF
+              || XFASTINT (w->last_overlay_modified) < OVERLAY_MODIFF
               || MINI_WINDOW_P (w))
        {
+         /* We have to handle the case of continuation around a
+            wide-column character (See the comment in indent.c around
+            line 885).
+
+            For instance, in the following case:
+
+            --------  Insert  --------
+            K_A_N_\\   `a'    K_A_N_a\         `X_' are wide-column chars.
+            J_I_       ==>    J_I_             `^^' are cursors.
+            ^^                ^^
+            --------          --------
+
+            As we have to redraw the line above, we should goto cancel.  */
+
+         struct position val;
+         int prevline;
+
+         prevline = find_next_newline (tlbufpos, -1);
+         val = *compute_motion (prevline, 0,
+                                XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
+                                0,
+                                tlbufpos,
+                                1 << (BITS_PER_SHORT - 1),
+                                1 << (BITS_PER_SHORT - 1),
+                                window_internal_width (w) - 1,
+                                XINT (w->hscroll), 0, w);
+         if (val.hpos != this_line_start_hpos)
+           goto cancel;
+
          cursor_vpos = -1;
          overlay_arrow_seen = 0;
          zv_strings_seen = 0;
          display_text_line (w, tlbufpos, this_line_vpos, this_line_start_hpos,
-                            pos_tab_offset (w, tlbufpos));
+                            pos_tab_offset (w, tlbufpos), 0);
          /* If line contains point, is not continued,
                 and ends at same distance from eob as before, we win */
          if (cursor_vpos >= 0 && this_line_bufpos
@@ -941,7 +1043,7 @@ redisplay ()
              if (this_line_vpos + 1
                  < XFASTINT (w->top) + window_internal_height (w))
                {
-                 int left = XFASTINT (w->left);
+                 int left = WINDOW_LEFT_MARGIN (w);
                  int *charstart_next_line
                    = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[this_line_vpos + 1];
                  int adjust;
@@ -959,7 +1061,7 @@ redisplay ()
                  adjust_window_charstarts (w, this_line_vpos, adjust);
                }
 
-             if (XFASTINT (w->width) != FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
+             if (!WINDOW_FULL_WIDTH_P (w))
                preserve_other_columns (w);
              goto update;
            }
@@ -984,6 +1086,7 @@ redisplay ()
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
+              && w == XWINDOW (current_buffer->last_selected_window)
               && NILP (w->region_showing)
               && !cursor_in_echo_area)
        {
@@ -998,7 +1101,7 @@ redisplay ()
            {
              int width = window_internal_width (w) - 1;
              FRAME_CURSOR_X (selected_frame)
-               = XFASTINT (w->left) + minmax (0, pos.hpos, width);
+               = WINDOW_LEFT_MARGIN (w) + minmax (0, pos.hpos, width);
              FRAME_CURSOR_Y (selected_frame) = this_line_vpos;
              goto update;
            }
@@ -1036,7 +1139,7 @@ redisplay ()
       FOR_EACH_FRAME (tail, frame)
        {
          FRAME_PTR f = XFRAME (frame);
-         if (! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if (FRAME_WINDOW_P (f) || f == selected_frame)
            {
 
              /* Mark all the scroll bars to be removed; we'll redeem the ones
@@ -1045,7 +1148,7 @@ redisplay ()
                (*condemn_scroll_bars_hook) (f);
 
              if (FRAME_VISIBLE_P (f))
-               redisplay_windows (FRAME_ROOT_WINDOW (f));
+               redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
 
              /* Any scroll bars which redisplay_windows should have nuked
                 should now go away.  */
@@ -1056,8 +1159,8 @@ redisplay ()
     }
   else if (FRAME_VISIBLE_P (selected_frame))
     {
-      redisplay_window (selected_window, 1);
-      if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
+      redisplay_window (selected_window, 1, preserve_echo_area);
+      if (!WINDOW_FULL_WIDTH_P (w))
        preserve_other_columns (w);
     }
 
@@ -1069,7 +1172,6 @@ update:
     unrequest_sigio ();
   stop_polling ();
 
-#ifdef MULTI_FRAME
   if (all_windows)
     {
       Lisp_Object tail;
@@ -1085,7 +1187,7 @@ update:
 
          f = XFRAME (XCONS (tail)->car);
 
-         if ((! FRAME_TERMCAP_P (f) || f == selected_frame)
+         if ((FRAME_WINDOW_P (f) || f == selected_frame)
              && FRAME_VISIBLE_P (f))
            {
              pause |= update_frame (f, 0, 0);
@@ -1099,7 +1201,6 @@ update:
        }
     }
   else
-#endif /* MULTI_FRAME */
     {
       if (FRAME_VISIBLE_P (selected_frame))
        pause = update_frame (selected_frame, 0, 0);
@@ -1118,8 +1219,7 @@ update:
        mini_window = FRAME_MINIBUF_WINDOW (selected_frame);
        mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
        
-       if (mini_frame != selected_frame
-           && ! FRAME_TERMCAP_P (mini_frame))
+       if (mini_frame != selected_frame && FRAME_WINDOW_P (mini_frame))
          pause |= update_frame (mini_frame, 0, 0);
       }
     }
@@ -1138,7 +1238,7 @@ update:
         may be null, so preserve_other_columns won't be able to
         preserve all the vertical-bar separators.  So, avoid using it
         in that case.  */
-      if (XFASTINT (w->width) != FRAME_WIDTH (selected_frame))
+      if (!WINDOW_FULL_WIDTH_P (w))
        update_mode_lines = 1;
     }
 
@@ -1151,6 +1251,7 @@ update:
 
       blank_end_of_window = 0;
       unchanged_modified = BUF_MODIFF (b);
+      overlay_unchanged_modified = BUF_OVERLAY_MODIFF (b);
       beg_unchanged = BUF_GPT (b) - BUF_BEG (b);
       end_unchanged = BUF_Z (b) - BUF_GPT (b);
 
@@ -1165,6 +1266,19 @@ update:
          b->clip_changed = 0;
          w->update_mode_line = Qnil;
          XSETFASTINT (w->last_modified, BUF_MODIFF (b));
+         XSETFASTINT (w->last_overlay_modified, BUF_OVERLAY_MODIFF (b));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
+
+         /* Record if we are showing a region, so can make sure to
+            update it fully at next redisplay.  */
+         w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && w == XWINDOW (current_buffer->last_selected_window)
+                              && !NILP (XBUFFER (w->buffer)->mark_active)
+                              ? Fmarker_position (XBUFFER (w->buffer)->mark)
+                              : Qnil);
+
          w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
@@ -1210,11 +1324,11 @@ redisplay_preserve_echo_area ()
   if (echo_area_glyphs == 0 && previous_echo_glyphs != 0)
     {
       echo_area_glyphs = previous_echo_glyphs;
-      redisplay ();
+      redisplay_internal (1);
       echo_area_glyphs = 0;
     }
   else
-    redisplay ();
+    redisplay_internal (1);
 }
 
 void
@@ -1233,10 +1347,16 @@ mark_window_display_accurate (window, flag)
        {
          XSETFASTINT (w->last_modified,
                       !flag ? 0 : BUF_MODIFF (XBUFFER (w->buffer)));
+         XSETFASTINT (w->last_overlay_modified,
+                      !flag ? 0 : BUF_OVERLAY_MODIFF (XBUFFER (w->buffer)));
+         w->last_had_star
+           = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              ? Qt : Qnil);
 
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
          w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && w == XWINDOW (current_buffer->last_selected_window)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
                               : Qnil);
@@ -1305,9 +1425,9 @@ update_menu_bar (f, save_match_data)
         windows_or_buffers_changed anyway.  */
       if (windows_or_buffers_changed
          || !NILP (w->update_mode_line)
-         || (XFASTINT (w->last_modified) < MODIFF
-             && (XFASTINT (w->last_modified)
-                 <= BUF_SAVE_MODIFF (XBUFFER (w->buffer))))
+         || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+              < BUF_MODIFF (XBUFFER (w->buffer)))
+             != !NILP (w->last_had_star))
          || ((!NILP (Vtransient_mark_mode)
               && !NILP (XBUFFER (w->buffer)->mark_active))
              != !NILP (w->region_showing)))
@@ -1317,7 +1437,7 @@ update_menu_bar (f, save_match_data)
 
          set_buffer_internal_1 (XBUFFER (w->buffer));
          if (save_match_data)
-           record_unwind_protect (Fstore_match_data, Fmatch_data ());
+           record_unwind_protect (Fstore_match_data, Fmatch_data (Qnil, Qnil));
          if (NILP (Voverriding_local_map_menu_flag))
            {
              specbind (Qoverriding_terminal_local_map, Qnil);
@@ -1330,12 +1450,21 @@ update_menu_bar (f, save_match_data)
             really recompute the menubar from the value.  */
          if (! NILP (Vlucid_menu_bar_dirty_flag))
            call0 (Qrecompute_lucid_menubar);
-         call1 (Vrun_hooks, Qmenu_bar_update_hook);
+         safe_run_hooks (Qmenu_bar_update_hook);
          FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
+         /* Redisplay the menu bar in case we changed it.  */
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
          if (FRAME_WINDOW_P (f))
            set_frame_menubar (f, 0, 0);
-#endif /* USE_X_TOOLKIT || HAVE_NTGUI */
+         else
+           /* On a terminal screen, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+           w->update_mode_line = Qt;
+#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
+         /* In the non-toolkit version, the menu bar is an ordinary screen
+            line, and this makes it get updated.  */
+         w->update_mode_line = Qt;
+#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
 
          unbind_to (count, Qnil);
          set_buffer_internal_1 (prev);
@@ -1348,19 +1477,57 @@ int do_id = 1;
 /* Redisplay WINDOW and its subwindows and siblings.  */
 
 static void
-redisplay_windows (window)
+redisplay_windows (window, preserve_echo_area)
      Lisp_Object window;
+     int preserve_echo_area;
 {
   for (; !NILP (window); window = XWINDOW (window)->next)
-    redisplay_window (window, 0);
+    redisplay_window (window, 0, preserve_echo_area);
+}
+
+/* Return value in display table DP (Lisp_Char_Table *) for character
+   C.  Since a display table doesn't have any parent, we don't have to
+   follow parent.  Do not call this function directly but use the
+   macro DISP_CHAR_VECTOR.  */
+Lisp_Object
+disp_char_vector (dp, c)
+     struct Lisp_Char_Table *dp;
+     int c;
+{
+  int code[4], i;
+  Lisp_Object val;
+
+  if (SINGLE_BYTE_CHAR_P (c)) return (dp->contents[c]);
+  
+  SPLIT_NON_ASCII_CHAR (c, code[0], code[1], code[2]);
+  if (code[0] != CHARSET_COMPOSITION)
+    {
+      if (code[1] < 32) code[1] = -1;
+      else if (code[2] < 32) code[2] = -1;
+    }
+  /* Here, the possible range of CODE[0] (== charset ID) is
+     128..MAX_CHARSET.  Since the top level char table contains data
+     for multibyte characters after 256th element, we must increment
+     CODE[0] by 128 to get a correct index.  */
+  code[0] += 128;
+  code[3] = -1;                /* anchor */
+
+  for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
+    {
+      val = dp->contents[code[i]];
+      if (!SUB_CHAR_TABLE_P (val))
+       return (NILP (val) ? dp->defalt : val);
+    }
+  /* Here, VAL is a sub char table.  We return the default value of it.  */
+  return (dp->defalt);
 }
 
 /* Redisplay window WINDOW and its subwindows.  */
 
 static void
-redisplay_window (window, just_this_one)
+redisplay_window (window, just_this_one, preserve_echo_area)
      Lisp_Object window;
-     int just_this_one;
+     int just_this_one, preserve_echo_area;
 {
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
@@ -1382,12 +1549,12 @@ redisplay_window (window, just_this_one)
 
   if (!NILP (w->vchild))
     {
-      redisplay_windows (w->vchild);
+      redisplay_windows (w->vchild, preserve_echo_area);
       return;
     }
   if (!NILP (w->hchild))
     {
-      redisplay_windows (w->hchild);
+      redisplay_windows (w->hchild, preserve_echo_area);
       return;
     }
   if (NILP (w->buffer))
@@ -1413,7 +1580,9 @@ redisplay_window (window, just_this_one)
          for (i = 0; i < height; i++)
            {
              get_display_line (f, vpos + i, 0);
-             display_string (w, vpos + i, "", 0, 0, 0, 1, 0, width);
+             display_string (w, vpos + i, "", 0, 
+                             FRAME_LEFT_SCROLL_BAR_WIDTH (f),
+                             0, 1, 0, width);
            }
          
          goto finish_scroll_bars;
@@ -1434,7 +1603,8 @@ redisplay_window (window, just_this_one)
       /* This alternative quickly identifies a common case
         where no change is needed.  */
       && !(PT == XFASTINT (w->last_point)
-          && XFASTINT (w->last_modified) >= MODIFF)
+          && XFASTINT (w->last_modified) >= MODIFF
+          && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)
       && XFASTINT (w->column_number_displayed) != current_column ())
     update_mode_line = 1; 
 
@@ -1499,6 +1669,30 @@ redisplay_window (window, just_this_one)
 
   startp = marker_position (w->start);
 
+  /* If someone specified a new starting point but did not insist,
+     check whether it can be used.  */
+  if (!NILP (w->optional_new_start))
+    {
+      w->optional_new_start = Qnil;
+      /* Check whether this start pos is usable given where point is.  */
+
+      pos = *compute_motion (startp, 0,
+                            (((EQ (window, minibuf_window)
+                               && startp == BEG)
+                              ? minibuf_prompt_width : 0)
+                             + (hscroll ? 1 - hscroll : 0)),
+                            0,
+                            PT, height, 
+                            /* BUG FIX: See the comment of
+                                Fpos_visible_in_window_p (window.c).  */
+                            - (1 << (BITS_PER_SHORT - 1)),
+                            width, hscroll, pos_tab_offset (w, startp), w);
+      /* If PT does fit on the screen, we will use this start pos,
+        so do so by setting force_start.  */
+      if (pos.bufpos == PT)
+       w->force_start = Qt;
+    }
+
   /* Handle case where place to start displaying has been specified,
      unless the specified location is outside the accessible range.  */
   if (!NILP (w->force_start))
@@ -1523,10 +1717,14 @@ redisplay_window (window, just_this_one)
          update_mode_line = 1;
          w->update_mode_line = Qt;
          if (! NILP (Vwindow_scroll_functions))
-           run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                                 make_number (startp));
+           {
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (startp));
+             startp = marker_position (w->start);
+           }
        }
       XSETFASTINT (w->last_modified, 0);
+      XSETFASTINT (w->last_overlay_modified, 0);
       if (startp < BEGV) startp = BEGV;
       if (startp > ZV)   startp = ZV;
       try_window (window, startp);
@@ -1549,7 +1747,7 @@ redisplay_window (window, just_this_one)
            {
              if (current_buffer == old)
                lpoint = PT;
-             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+             FRAME_CURSOR_X (f) = (WINDOW_LEFT_MARGIN (w)
                                    + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
@@ -1576,8 +1774,9 @@ redisplay_window (window, just_this_one)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
+      && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF
       && PT >= startp && !current_buffer->clip_changed
-      && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      && (just_this_one || WINDOW_FULL_WIDTH_P (w))
       /* If force-mode-line-update was called, really redisplay;
         that's how redisplay is forced after e.g. changing
         buffer-invisibility-spec.  */
@@ -1590,17 +1789,33 @@ redisplay_window (window, just_this_one)
       && XFASTINT (w->window_end_vpos) < XFASTINT (w->height)
       && !EQ (window, minibuf_window))
     {
-      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
-                           PT, height, 0, width, hscroll,
-                           pos_tab_offset (w, startp), w);
+      int this_scroll_margin = scroll_margin;
 
-      if (pos.vpos < height)
+      pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
+                            PT, height,
+                            /* BUG FIX: See the comment of
+                                Fpos_visible_in_window_p (window.c).  */
+                            - (1 << (BITS_PER_SHORT - 1)),
+                            width, hscroll,
+                            pos_tab_offset (w, startp), w);
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+
+      if (XINT (w->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      /* If point fits on the screen, and not within the scroll margin,
+        we are ok.  */
+      if (pos.vpos < height - this_scroll_margin
+         && (pos.vpos >= this_scroll_margin || startp == BEGV))
        {
          /* Ok, point is still on frame */
          if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
            {
              /* These variables are supposed to be origin 1 */
-             FRAME_CURSOR_X (f) = (XFASTINT (w->left)
+             FRAME_CURSOR_X (f) = (WINDOW_LEFT_MARGIN (w)
                                    + minmax (0, pos.hpos, width));
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
@@ -1608,7 +1823,7 @@ redisplay_window (window, just_this_one)
             this one must be redisplayed, this does nothing because there
             is nothing in DesiredFrame yet, and then the other window is
             redisplayed, making likes that are empty in this window's columns.
-            if (XFASTINT (w->width) != FRAME_WIDTH (f))
+            if (WINDOW_FULL_WIDTH_P (w))
             preserve_my_columns (w);
             */
          goto done;
@@ -1620,7 +1835,7 @@ redisplay_window (window, just_this_one)
      but no longer is, find a new starting point.  */
   else if (!NILP (w->start_at_line_beg)
           && !(startp <= BEGV
-               || FETCH_CHAR (startp - 1) == '\n'))
+               || FETCH_BYTE (startp - 1) == '\n'))
     {
       goto recenter;
     }
@@ -1632,7 +1847,7 @@ redisplay_window (window, just_this_one)
           && ! EQ (w->window_end_valid, Qnil)
           && do_id && !current_buffer->clip_changed
           && !blank_end_of_window
-          && XFASTINT (w->width) == FRAME_WIDTH (f)
+          && WINDOW_FULL_WIDTH_P (w)
           /* Can't use this case if highlighting a region.  */
           && !(!NILP (Vtransient_mark_mode)
                && !NILP (current_buffer->mark_active))
@@ -1653,9 +1868,18 @@ redisplay_window (window, just_this_one)
        goto done;
     }
   else if (startp >= BEGV && startp <= ZV
-          /* Avoid starting display at end of buffer! */
-          && (startp < ZV || startp == BEGV
-              || (XFASTINT (w->last_modified) >= MODIFF)))
+          && (startp < ZV
+              /* Avoid starting at end of buffer.  */
+#if 0 /* This change causes trouble for M-! finger & RET.
+        It will have to be considered later.  */
+              || ! EQ (window, selected_window)
+              /* Don't do the recentering if redisplay
+                 is not for no user action.  */
+              || preserve_echo_area
+#endif
+              || startp == BEGV
+              || (XFASTINT (w->last_modified) >= MODIFF
+                  && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
     {
       /* Try to redisplay starting at same place as before */
       /* If point has not moved off frame, accept the results */
@@ -1673,6 +1897,7 @@ redisplay_window (window, just_this_one)
     }
 
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   /* Redisplay the mode line.  Select the buffer properly for that.  */
   if (!update_mode_line)
     {
@@ -1684,6 +1909,83 @@ redisplay_window (window, just_this_one)
 
   /* Try to scroll by specified few lines */
 
+  if (scroll_conservatively && !current_buffer->clip_changed
+      && startp >= BEGV && startp <= ZV)
+    {
+      int this_scroll_margin = scroll_margin;
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+
+      if (XINT (w->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      if (PT >= Z - XFASTINT (w->window_end_pos))
+       {
+         struct position pos;
+         pos = *compute_motion (Z - XFASTINT (w->window_end_pos), 0, 0, 0,
+                                PT, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp), w);
+         if (pos.vpos > scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, pos.vpos + 1 + this_scroll_margin, w);
+
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (pos.bufpos));
+             pos.bufpos = marker_position (w->start);
+           }
+         try_window (window, pos.bufpos);
+         if (cursor_vpos >= 0)
+           {
+             if (!just_this_one || current_buffer->clip_changed
+                 || beg_unchanged < startp)
+               /* Forget any recorded base line for line number display.  */
+               w->base_line_number = Qnil;
+             goto done;
+           }
+         else
+           cancel_my_columns (w);
+       }
+      if (PT < startp)
+       {
+         struct position pos;
+         pos = *compute_motion (PT, 0, 0, 0,
+                                startp, XFASTINT (w->height), 0,
+                                XFASTINT (w->width), XFASTINT (w->hscroll),
+                                pos_tab_offset (w, startp), w);
+         if (pos.vpos >= scroll_conservatively)
+           goto scroll_fail_1;
+
+         pos = *vmotion (startp, - pos.vpos - this_scroll_margin, w);
+
+         if (! NILP (Vwindow_scroll_functions))
+           {
+             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (pos.bufpos));
+             pos.bufpos = marker_position (w->start);
+           }
+         try_window (window, pos.bufpos);
+         if (cursor_vpos >= 0)
+           {
+             if (!just_this_one || current_buffer->clip_changed
+                 || beg_unchanged < startp)
+               /* Forget any recorded base line for line number display.  */
+               w->base_line_number = Qnil;
+             goto done;
+           }
+         else
+           cancel_my_columns (w);
+       }
+    scroll_fail_1: ;
+    }
+
   if (scroll_step && !current_buffer->clip_changed
       && startp >= BEGV && startp <= ZV)
     {
@@ -1699,8 +2001,12 @@ redisplay_window (window, just_this_one)
       if (PT >= pos.bufpos)
        {
          if (! NILP (Vwindow_scroll_functions))
-           run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                                 make_number (pos.bufpos));
+           {
+             Fset_marker (w->start, make_number (pos.bufpos), Qnil);
+             run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                                   make_number (pos.bufpos));
+             pos.bufpos = marker_position (w->start);
+           }
          try_window (window, pos.bufpos);
          if (cursor_vpos >= 0)
            {
@@ -1727,19 +2033,22 @@ recenter:
      in case the window-scroll-functions functions get errors.  */
   Fset_marker (w->start, make_number (pos.bufpos), Qnil);
   if (! NILP (Vwindow_scroll_functions))
-    run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                         make_number (pos.bufpos));
+    {
+      run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                           make_number (pos.bufpos));
+      pos.bufpos = marker_position (w->start);
+    }
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
   w->start_at_line_beg
-    = (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil;
+    = (startp == BEGV || FETCH_BYTE (startp - 1) == '\n') ? Qt : Qnil;
 
 done:
   if ((update_mode_line
        /* If window not full width, must redo its mode line
          if the window to its side is being redone */
-       || (!just_this_one && width < FRAME_WIDTH (f) - 1)
+       || (!just_this_one && !WINDOW_FULL_WIDTH_P (w))
        || INTEGERP (w->base_line_pos)
        || (!NILP (w->column_number_displayed)
           && XFASTINT (w->column_number_displayed) != current_column ()))
@@ -1819,30 +2128,33 @@ try_window (window, pos)
   register int height = window_internal_height (w);
   register int vpos = XFASTINT (w->top);
   register int last_text_vpos = vpos;
-  int tab_offset = pos_tab_offset (w, pos);
   FRAME_PTR f = XFRAME (w->frame);
   int width = window_internal_width (w) - 1;
   struct position val;
 
+  /* POS should never be out of range!  */
+  if (pos < XBUFFER (w->buffer)->begv
+      || pos > XBUFFER (w->buffer)->zv)
+    abort ();
+
   Fset_marker (w->start, make_number (pos), Qnil);
   cursor_vpos = -1;
   overlay_arrow_seen = 0;
   zv_strings_seen = 0;
   val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
+  val.ovstring_chars_done = 0;
+  val.tab_offset = pos_tab_offset (w, pos);
 
   while (--height >= 0)
     {
-      val = *display_text_line (w, pos, vpos, val.hpos, tab_offset);
+      val = *display_text_line (w, pos, vpos, val.hpos, val.tab_offset,
+                               val.ovstring_chars_done);
+      /* The following code is omitted because we maintain tab_offset
+         in VAL.  */
+#if 0
       tab_offset += width;
-      /* For the first line displayed, display_text_line
-        subtracts the prompt width from the tab offset.
-        But it does not affect the value of our variable tab_offset.
-        So we do the subtraction again,
-        for the sake of continuation lines of that first line.  */
-      if (MINI_WINDOW_P (w) && vpos == XFASTINT (w->top))
-       tab_offset -= minibuf_prompt_width;
-
       if (val.vpos) tab_offset = 0;
+#endif  /* 0 */
       vpos++;
       if (pos != val.bufpos)
        {
@@ -1856,7 +2168,7 @@ try_window (window, pos)
          last_text_vpos
            /* Next line, unless prev line ended in end of buffer with no cr */
            = vpos - (val.vpos
-                     && (FETCH_CHAR (val.bufpos - 1) != '\n' || invis));
+                     && (FETCH_BYTE (val.bufpos - 1) != '\n' || invis));
        }
       pos = val.bufpos;
     }
@@ -1910,7 +2222,7 @@ try_window_id (window)
   struct position val, bp, ep, xp, pp;
   int scroll_amount = 0;
   int delta;
-  int tab_offset, epto, old_tick;
+  int epto, old_tick;
 
   if (GPT - BEG < beg_unchanged)
     beg_unchanged = GPT - BEG;
@@ -1922,7 +2234,10 @@ try_window_id (window)
 
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin, 0,
-                       min (ZV, beg_unchanged + BEG), height, 0,
+                       min (ZV, beg_unchanged + BEG), height,
+                       /* BUG FIX: See the comment of
+                           Fpos_visible_in_window_p() (window.c).  */
+                       - (1 << (BITS_PER_SHORT - 1)),
                        width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
@@ -1933,7 +2248,10 @@ try_window_id (window)
             But we need to update window_end_pos to account for
             any change in buffer size.  */
          bp = *compute_motion (start, 0, lmargin, 0,
-                               ZV, height, 0,
+                               ZV, height,
+                               /* BUG FIX: See the comment of
+                                   Fpos_visible_in_window_p() (window.c).  */
+                               - (1 << (BITS_PER_SHORT - 1)),
                                width, hscroll, pos_tab_offset (w, start), w);
          XSETFASTINT (w->window_end_vpos, height);
          XSETFASTINT (w->window_end_pos, Z - bp.bufpos);
@@ -1965,12 +2283,14 @@ try_window_id (window)
       --vpos;
       pos = bp.bufpos;
     }
+  val.tab_offset = bp.tab_offset; /* Update tab offset.  */
 
   if (bp.contin && bp.hpos != lmargin)
     {
       val.hpos = bp.prevhpos - width + lmargin;
+      val.tab_offset = bp.tab_offset + bp.prevhpos - width;
       did_motion = 1;
-      pos--;
+      DEC_POS (pos);
     }
 
   bp.vpos = vpos;
@@ -1984,7 +2304,9 @@ try_window_id (window)
   /* Compute the cursor position after that newline.  */
   ep = *compute_motion (pos, vpos, val.hpos, did_motion, tem,
                        height, - (1 << (BITS_PER_SHORT - 1)),
-                       width, hscroll, pos_tab_offset (w, bp.bufpos), w);
+                       width, hscroll,
+                       /* We have tab offset in VAL, use it.  */
+                       val.tab_offset, w); 
 
   /* If changes reach past the text available on the frame,
      just display rest of frame.  */
@@ -2000,7 +2322,7 @@ try_window_id (window)
      newline before it, so the following line must be redrawn. */
   if (stop_vpos == ep.vpos
       && (ep.bufpos == BEGV
-         || FETCH_CHAR (ep.bufpos - 1) != '\n'
+         || FETCH_BYTE (ep.bufpos - 1) != '\n'
          || ep.bufpos == Z - end_unchanged))
     stop_vpos = ep.vpos + 1;
 
@@ -2013,17 +2335,20 @@ try_window_id (window)
   if (stop_vpos < height)
     {
       /* Now determine how far up or down the rest of the window has moved */
-      epto = pos_tab_offset (w, ep.bufpos);
       xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
                            Z - XFASTINT (w->window_end_pos),
-                           10000, 0, width, hscroll, epto, w);
+                           /* Don't care for VPOS... */
+                           1 << (BITS_PER_SHORT - 1),
+                           /* ... nor HPOS.  */
+                           1 << (BITS_PER_SHORT - 1),
+                           width, hscroll, ep.tab_offset, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
 
       /* Is everything on frame below the changes whitespace?
         If so, no scrolling is really necessary.  */
       for (i = ep.bufpos; i < xp.bufpos; i++)
        {
-         tem = FETCH_CHAR (i);
+         tem = FETCH_BYTE (i);
          if (tem != ' ' && tem != '\n' && tem != '\t')
            break;
        }
@@ -2034,25 +2359,28 @@ try_window_id (window)
                   XFASTINT (w->window_end_vpos) + scroll_amount);
 
       /* Before doing any scrolling, verify that point will be on frame. */
-      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
+      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.vpos < height))
        {
          if (PT <= xp.bufpos)
            {
              pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos, 1,
                                    PT, height, - (1 << (BITS_PER_SHORT - 1)),
-                                   width, hscroll, epto, w);
+                                   width, hscroll,
+                                   /* We have tab offset in EP, use it.  */
+                                   ep.tab_offset, w);
            }
          else
            {
              pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos, 1,
                                    PT, height, - (1 << (BITS_PER_SHORT - 1)),
                                    width, hscroll,
-                                   pos_tab_offset (w, xp.bufpos), w);
+                                   /* We have tab offset in XP, use it. */
+                                   xp.tab_offset, w);
            }
          if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
-         cursor_hpos = XFASTINT (w->left) + minmax (0, pp.hpos, width);
+         cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, pp.hpos, width);
        }
 
       if (stop_vpos - scroll_amount >= height
@@ -2150,26 +2478,35 @@ try_window_id (window)
 
   /* Redisplay the lines where the text was changed */
   last_text_vpos = vpos;
+  /* The following code is omitted because we maintain tab offset in
+     val.tab_offset.  */
+#if 0
   tab_offset = pos_tab_offset (w, pos);
   /* If we are starting display in mid-character, correct tab_offset
      to account for passing the line that that character really starts in.  */
   if (val.hpos < lmargin)
     tab_offset += width;
+#endif /* 0 */
   old_tick = MODIFF;
   while (vpos < stop_vpos)
     {
-      val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+      val = *display_text_line (w, pos, top + vpos++, val.hpos, val.tab_offset,
+                               val.ovstring_chars_done);
       /* If display_text_line ran a hook and changed some text,
         redisplay all the way to bottom of buffer
         So that we show the changes.  */
       if (old_tick != MODIFF)
        stop_vpos = height;
+      /* The following code is omitted because we maintain tab offset
+        in val.tab_offset.  */
+#if 0
       tab_offset += width;
       if (val.vpos) tab_offset = 0;
+#endif
       if (pos != val.bufpos)
        last_text_vpos
          /* Next line, unless prev line ended in end of buffer with no cr */
-           = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
+           = vpos - (val.vpos && FETCH_BYTE (val.bufpos - 1) != '\n');
       pos = val.bufpos;
     }
 
@@ -2196,27 +2533,41 @@ try_window_id (window)
       FRAME_SCROLL_BOTTOM_VPOS (f) = xp.vpos;
       vpos = xp.vpos;
       pos = xp.bufpos;
-      val.hpos = lmargin;
+      val.hpos = xp.hpos;
+      val.tab_offset = xp.tab_offset;
       if (pos == ZV)
-       vpos = height + scroll_amount;
+       { /* Display from next line */
+         vpos = height + scroll_amount;
+         val.hpos = lmargin;
+         val.tab_offset = 0;
+       }
       else if (xp.contin && xp.hpos != lmargin)
        {
          val.hpos = xp.prevhpos - width + lmargin;
-         pos--;
+         val.tab_offset = xp.tab_offset + bp.prevhpos - width;
+         DEC_POS (pos);
        }
 
       blank_end_of_window = 1;
+      /* The following code is omitted because we maintain tab offset
+        in val.tab_offset.  */
+#if 0
       tab_offset = pos_tab_offset (w, pos);
       /* If we are starting display in mid-character, correct tab_offset
         to account for passing the line that that character starts in.  */
       if (val.hpos < lmargin)
        tab_offset += width;
-
+#endif
       while (vpos < height)
        {
-         val = *display_text_line (w, pos, top + vpos++, val.hpos, tab_offset);
+         val = *display_text_line (w, pos, top + vpos++, val.hpos,
+                                   val.tab_offset, val.ovstring_chars_done);
+         /* The following code is omitted because we maintain tab
+            offset in val.tab_offset.  */
+#if 0
          tab_offset += width;
          if (val.vpos) tab_offset = 0;
+#endif /* 0 */
          pos = val.bufpos;
        }
 
@@ -2253,7 +2604,11 @@ try_window_id (window)
   if (cursor_vpos < 0)
     {
     findpoint:
-      val = *compute_motion (start, 0, lmargin, 0, PT, 10000, 10000,
+      val = *compute_motion (start, 0, lmargin, 0, PT, 
+                            /* Don't care for VPOS...  */
+                            1 << (BITS_PER_SHORT - 1),
+                            /* ... nor HPOS.  */
+                            1 << (BITS_PER_SHORT - 1),
                             width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
@@ -2263,7 +2618,7 @@ try_window_id (window)
          return 0;
        }
       cursor_vpos = val.vpos + top;
-      cursor_hpos = XFASTINT (w->left) + minmax (0, val.hpos, width);
+      cursor_hpos = WINDOW_LEFT_MARGIN (w) + minmax (0, val.hpos, width);
     }
 
   FRAME_CURSOR_X (f) = cursor_hpos;
@@ -2283,76 +2638,6 @@ try_window_id (window)
 
   return 1;
 }
-\f
-/* Mark a section of BUF as modified, but only for the sake of redisplay.
-   This is useful for recording changes to overlays.
-
-   We increment the buffer's modification timestamp and set the
-   redisplay caches (windows_or_buffers_changed, beg_unchanged, etc)
-   as if the region of text between START and END had been modified;
-   the redisplay code will check this against the windows' timestamps,
-   and redraw the appropriate area of the buffer.
-
-   However, if the buffer is unmodified, we bump the last-save
-   timestamp as well, so that incrementing the timestamp doesn't fool
-   Emacs into thinking that the buffer's text has been modified. 
-
-   Tweaking the timestamps shouldn't hurt the first-modification
-   timestamps recorded in the undo records; those values aren't
-   written until just before a real text modification is made, so they
-   will never catch the timestamp value just before this function gets
-   called.  */
-
-void
-redisplay_region (buf, start, end)
-     struct buffer *buf;
-     int start, end;
-{
-  if (start == end)
-    return;
-
-  if (start > end)
-    {
-      int temp = start;
-      start = end; end = temp;
-    }
-
-  /* If this is a buffer not in the selected window,
-     we must do other windows.  */
-  if (buf != XBUFFER (XWINDOW (selected_window)->buffer))
-    windows_or_buffers_changed = 1;
-  /* If it's not current, we can't use beg_unchanged, end_unchanged for it.  */
-  else if (buf != current_buffer)
-    windows_or_buffers_changed = 1;
-  /* If multiple windows show this buffer, we must do other windows.  */
-  else if (buffer_shared > 1)
-    windows_or_buffers_changed = 1;
-  else
-    {
-      if (unchanged_modified == MODIFF)
-       {
-         beg_unchanged = start - BEG;
-         end_unchanged = Z - end;
-       }
-      else
-       {
-         if (Z - end < end_unchanged)
-           end_unchanged = Z - end;
-         if (start - BEG < beg_unchanged)
-           beg_unchanged = start - BEG;
-       }
-    }
-
-  /* Increment the buffer's time stamp, but also increment the save
-     and autosave timestamps, so as not to screw up that timekeeping.  */
-  if (BUF_MODIFF (buf) == BUF_SAVE_MODIFF (buf))
-    BUF_SAVE_MODIFF (buf)++;
-  if (BUF_MODIFF (buf) == buf->auto_save_modified)
-    buf->auto_save_modified++;
-
-  BUF_MODIFF (buf) ++;
-}
-
 \f
 /* Copy LEN glyphs starting address FROM to the rope TO.
    But don't actually copy the parts that would come in before S.
@@ -2378,8 +2663,13 @@ copy_part_of_rope (f, to, s, from, len, face)
   if (! FRAME_TERMCAP_P (f))
     while (n--)
       {
-       int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
+       GLYPH glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        int facecode;
+       unsigned int c = FAST_GLYPH_CHAR (glyph);
+
+       if (c > MAX_CHAR)
+         /* For an invalid character code, use space.  */
+         c = ' ';
 
        if (FAST_GLYPH_FACE (glyph) == 0)
          /* If GLYPH has no face code, use FACE.  */
@@ -2395,7 +2685,7 @@ copy_part_of_rope (f, to, s, from, len, face)
          }
 
        if (to >= s)
-         *to = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), facecode);
+         *to = FAST_MAKE_GLYPH (c, facecode);
        ++to;
        ++fp;
       }
@@ -2442,6 +2732,9 @@ fix_glyph (f, glyph, cface)
 
    TABOFFSET is an offset for ostensible hpos, used in tab stop calculations.
 
+   OVSTR_DONE is the number of chars of overlay before/after strings
+   at this position which have already been processed.
+
    Display on position VPOS on the frame.  It is origin 0, relative to
    the top of the frame, not W.
 
@@ -2452,12 +2745,13 @@ fix_glyph (f, glyph, cface)
 struct position val_display_text_line;
 
 static struct position *
-display_text_line (w, start, vpos, hpos, taboffset)
+display_text_line (w, start, vpos, hpos, taboffset, ovstr_done)
      struct window *w;
      int start;
      int vpos;
      int hpos;
      int taboffset;
+     int ovstr_done;
 {
   register int pos = start;
   register int c;
@@ -2482,12 +2776,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
   int hscroll = XINT (w->hscroll);
   int truncate = (hscroll
                  || (truncate_partial_width_windows
-                     && XFASTINT (w->width) < FRAME_WIDTH (f))
+                     && !WINDOW_FULL_WIDTH_P (w))
                  || !NILP (current_buffer->truncate_lines));
 
   /* 1 if we should highlight the region.  */
   int highlight_region
-    = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
+    = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
+       && XWINDOW (current_buffer->last_selected_window) == w);
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
@@ -2513,10 +2808,21 @@ display_text_line (w, start, vpos, hpos, taboffset)
        : default_invis_vector);
 
   GLYPH truncator = (dp == 0 || !INTEGERP (DISP_TRUNC_GLYPH (dp))
+                    || !GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (dp)))
                     ? '$' : XINT (DISP_TRUNC_GLYPH (dp)));
   GLYPH continuer = (dp == 0 || !INTEGERP (DISP_CONTINUE_GLYPH (dp))
+                    || !GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (dp)))
                     ? '\\' : XINT (DISP_CONTINUE_GLYPH (dp)));
 
+  /* If 1, we must handle multibyte characters.  */
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  /* Length of multibyte form of each character.  */
+  int len;
+  /* Glyphs generated should be set this bit mask if text must be
+     displayed from right to left.  */
+  GLYPH rev_dir_bit = (NILP (current_buffer->direction_reversed)
+                      ? 0 : GLYPH_MASK_REV_DIR);
+
   /* The next buffer location at which the face should change, due
      to overlays or text property changes.  */
   int next_face_change;
@@ -2532,8 +2838,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   XSETFASTINT (default_invis_vector[2], '.');
   default_invis_vector[0] = default_invis_vector[1] = default_invis_vector[2];
 
-  hpos += XFASTINT (w->left);
-  get_display_line (f, vpos, XFASTINT (w->left));
+  hpos += WINDOW_LEFT_MARGIN (w);
+  get_display_line (f, vpos, WINDOW_LEFT_MARGIN (w));
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
   /* Show where to highlight the region.  */
@@ -2553,7 +2859,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
       w->region_showing = Qt;
     }
   else
-    region_beg = region_end = -1;
+    {
+      region_beg = region_end = -1;
+      w->region_showing = Qnil;
+    }
 
   if (MINI_WINDOW_P (w)
       && start == BEG
@@ -2570,7 +2879,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
                               /* Truncate the prompt a little before the
                                  margin, so user input can at least start
                                  on the first line.  */
-                              w->width > 10 ? w->width - 4 : -1)
+                              (XFASTINT (w->width) > 10
+                               ? XFASTINT (w->width) - 4 : -1))
               - hpos);
          hpos += minibuf_prompt_width;
          taboffset -= minibuf_prompt_width;
@@ -2600,7 +2910,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
       if (left_edge->vpos > vpos
           || left_edge->hpos > 0)
         {
-          pos = left_edge->bufpos - 1;
+          pos = left_edge->bufpos;
+         /* Since this should not be a valid multibyte character, we
+             can decrease POS by 1.  */
+         pos--;
           hpos = left_edge->prevhpos;
         }
       else
@@ -2615,8 +2928,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   p1start = p1;
   charstart = desired_glyphs->charstarts[vpos] + hpos;
   /* In case we don't ever write anything into it...  */
-  desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
-  leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+  desired_glyphs->charstarts[vpos][WINDOW_LEFT_MARGIN (w)] = -1;
+  leftmargin = desired_glyphs->glyphs[vpos] + WINDOW_LEFT_MARGIN (w);
   endp = leftmargin + width;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
@@ -2651,13 +2964,47 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (pos < ZV || !zv_strings_seen++)
                {
                  int ovlen;
-                 char *ovstr;
+                 unsigned char *ovstr;
                  ovlen = overlay_strings (pos, w, &ovstr);
-                 for (; ovlen; ovlen--, ovstr++)
+
+                 if (ovlen > 0)
                    {
-                     if (p1 >= leftmargin && p1 < endp)
-                       *p1 = MAKE_GLYPH (f, *ovstr, current_face);
-                     p1++;
+                     /* Skip the ones we did in a previous line.  */
+                     ovstr += ovstr_done;
+                     ovlen -= ovstr_done;
+
+                     while (ovlen > 0)
+                       {
+                         int charset, cols;
+                         GLYPH g;
+
+                         if (multibyte)
+                           {
+                             c = STRING_CHAR_AND_LENGTH (ovstr, ovlen, len);
+                             ovstr += len, ovlen -= len, ovstr_done += len;
+                             charset = CHAR_CHARSET (c);
+                             cols = (charset == CHARSET_COMPOSITION
+                                     ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                                     : CHARSET_WIDTH (charset));
+                           }
+                         else
+                           {
+                             c = *ovstr++, ovlen--, ovstr_done++;
+                             cols = 1;
+                           }
+                         g = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
+                         while (cols-- > 0)
+                           {
+                             if (p1 >= leftmargin && p1 < endp)
+                               *p1 = g, g |= GLYPH_MASK_PADDING;
+                             p1++;
+                           }
+                       }
+                     /* If we did all the overlay strings
+                        and we have room for text, clear ovstr_done
+                        just for neatness' sake.  */
+                     if (ovlen == 0 && p1 < endp)
+                       ovstr_done = 0;
                    }
                }
 
@@ -2677,7 +3024,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
              /* This is just an estimate to give reasonable
                 performance; nothing should go wrong if it is too small.  */
              if (XFASTINT (limit) > pos + 50)
-               XSETFASTINT (limit, pos + 50);
+               {
+                 int limitpos = pos + 50;
+                 if (limitpos < Z)
+                   INC_POS (limitpos); /* Adjust to character boundary.  */
+                 XSETFASTINT (limit, limitpos);
+               }
              limit = Fnext_single_property_change (position, Qinvisible,
                                                    Fcurrent_buffer (), limit);
 #endif
@@ -2756,10 +3108,17 @@ display_text_line (w, start, vpos, hpos, taboffset)
          /* Did we hit a face change?  Figure out what face we should
             use now.  We also hit this the first time through the
             loop, to see what face we should start with.  */
-         if (pos >= next_face_change && (FRAME_WINDOW_P (f)))
-           current_face = compute_char_face (f, w, pos,
-                                             region_beg, region_end,
-                                             &next_face_change, pos + 50, 0);
+         if (pos >= next_face_change
+             && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
+           {
+             int limit = pos + 50;
+
+             if (limit < Z && !CHAR_HEAD_P (POS_ADDR (limit)))
+               INC_POS (limit); /* Adjust to character boundary.  */
+             current_face = compute_char_face (f, w, pos,
+                                               region_beg, region_end,
+                                               &next_face_change, limit, 0);
+           }
 #endif
 
          /* Compute the next place we need to stop
@@ -2782,7 +3141,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
-         p = &FETCH_CHAR (pos);
+         p = POS_ADDR (pos);
        }
 
       if (p1 >= endp)
@@ -2790,19 +3149,23 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
       p1prev = p1;
 
-      c = *p++;
+      if (multibyte)
+       /* PAUSE is surely at character boundary.  */
+       c = STRING_CHAR_AND_LENGTH (p, pause - pos, len), p += len;
+      else
+       c = *p++, len = 1;
       /* Let a display table override all standard display methods.  */
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
        {
          p1 = copy_part_of_rope (f, p1, leftmargin,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
-                                 current_face);
+                                 current_face, rev_dir_bit);
        }
       else if (c >= 040 && c < 0177)
        {
          if (p1 >= leftmargin)
-           *p1 = MAKE_GLYPH (f, c, current_face);
+           *p1 = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
          p1++;
        }
       else if (c == '\n')
@@ -2817,7 +3180,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
            {
              invis = 1;
              pos = find_next_newline (pos + 1, 1);
-             if (FETCH_CHAR (pos - 1) == '\n')
+             if (FETCH_BYTE (pos - 1) == '\n')
                pos--;
            }
          if (invis && selective_rlen > 0 && p1 >= leftmargin)
@@ -2826,7 +3189,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
+                                (p1 - p1prev), current_face, rev_dir_bit);
            }
 #ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
@@ -2836,7 +3199,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 < leftmargin)
                p1 = leftmargin;
              while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
            }
 #endif
 
@@ -2865,7 +3228,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          do
            {
              if (p1 >= leftmargin && p1 < endp)
-               *p1 = MAKE_GLYPH (f, ' ', current_face);
+               *p1 = MAKE_GLYPH (f, ' ', current_face) | rev_dir_bit;
              p1++;
            }
          while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
@@ -2874,7 +3237,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c == Ctl ('M') && selective == -1)
        {
          pos = find_next_newline (pos, 1);
-         if (FETCH_CHAR (pos - 1) == '\n')
+         if (FETCH_BYTE (pos - 1) == '\n')
            pos--;
          if (selective_rlen > 0)
            {
@@ -2882,7 +3245,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
+                                (p1 - p1prev), current_face, rev_dir_bit);
            }
 #ifdef HAVE_FACES
          /* Draw the face of the newline character as extending all the 
@@ -2892,7 +3255,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (p1 < leftmargin)
                p1 = leftmargin;
              while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
            }
 #endif
 
@@ -2918,34 +3281,58 @@ display_text_line (w, start, vpos, hpos, taboffset)
       else if (c < 0200 && ctl_arrow)
        {
          if (p1 >= leftmargin)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
-                                ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
-                            current_face);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (dp)))
+                       ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+                   current_face)
+                  | rev_dir_bit);
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
+           *p1 = MAKE_GLYPH (f, c ^ 0100, current_face) | rev_dir_bit;
          p1++;
        }
-      else
+      else if (len == 1)
        {
+         /* C is not a multibyte character.  */
          if (p1 >= leftmargin)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-                                ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-                            current_face);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (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);
+           *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face) | rev_dir_bit;
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
+           *p1 = (MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face)
+                  | rev_dir_bit);
          p1++;
          if (p1 >= leftmargin && p1 < endp)
-           *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
+           *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face) | rev_dir_bit;
          p1++;
        }
+      else
+       {
+         /* C is a multibyte character.  */
+         int charset = CHAR_CHARSET (c);
+         int columns = (charset == CHARSET_COMPOSITION
+                        ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                        : CHARSET_WIDTH (charset));
+         GLYPH g = MAKE_GLYPH (f, c, current_face) | rev_dir_bit;
+
+         while (columns--)
+           {
+             if (p1 >= leftmargin && p1 < endp)
+               *p1 = g, g |= GLYPH_MASK_PADDING;
+             p1++;
+           }
+       }
 
       prevpos = pos;
-      pos++;
+      pos += len;
 
       /* Update charstarts for the character just output.  */
 
@@ -2998,10 +3385,37 @@ display_text_line (w, start, vpos, hpos, taboffset)
         This occurs when the minibuffer prompt takes up the whole line.  */
       if (p1prev)
        {
-         /* Start the next line with that same character */
-         pos--;
-         /* but at negative hpos, to skip the columns output on this line.  */
-         val.hpos += p1prev - endp;
+         /* Start the next line with that same character whose
+             character code is C and the length of multi-byte form is
+             LEN.  */
+         pos = prevpos;
+
+         if (len == 1)
+           /* C is not a multi-byte character.  We can break it and
+              start from the middle column in the next line.  So,
+              adjust VAL.HPOS to skip the columns output on this
+              line.  */
+           val.hpos += p1prev - endp;
+         else
+           {
+             /* C is a multibyte character.  Since we can't broke it
+                in the middle, the whole character should be driven
+                into the next line.  */
+             /* As the result, the actual columns occupied by the
+                text on this line is less than WIDTH.  VAL.TAB_OFFSET
+                must be adjusted.  */
+             taboffset = taboffset + (p1prev - endp);
+             /* Let's fill unused columns with TRUNCATOR or CONTINUER.  */
+             {
+               GLYPH g = fix_glyph (f, truncate ? truncator : continuer, 0);
+               while (p1prev < endp)
+                 *p1prev++ = g;
+             }
+             /* If POINT is at POS, cursor should not on this line.  */
+             lastpos = pos;
+             if (PT == pos)
+               cursor_vpos = -1;
+           }
        }
 
       /* Keep in this line everything up to the continuation column.  */
@@ -3015,10 +3429,11 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
   if (pos < ZV)
     {
-      if (FETCH_CHAR (pos) == '\n')
+      if (FETCH_BYTE (pos) == '\n')
        {
          /* If stopped due to a newline, start next line after it */
          pos++;
+         val.tab_offset = 0;
          /* Check again for hidden lines, in case the newline occurred exactly
             at the right margin.  */
          while (pos < ZV && selective > 0
@@ -3040,16 +3455,20 @@ display_text_line (w, start, vpos, hpos, taboffset)
                     && indented_beyond_p (pos, selective));
              val.hpos = XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0;
 
-             lastpos = pos - (FETCH_CHAR (pos - 1) == '\n');
+             lastpos = pos - (FETCH_BYTE (pos - 1) == '\n');
+             val.tab_offset = 0;
            }
          else
            {
              *p1++ = fix_glyph (f, continuer, 0);
              val.vpos = 0;
              lastpos--;
+             val.tab_offset = taboffset + width;
            }
        }
     }
+  else
+    val.tab_offset = 0;
 
   /* If point is at eol or in invisible text at eol,
      record its frame location now.  */
@@ -3064,7 +3483,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
     {
       if (cursor_hpos < 0) cursor_hpos = 0;
       if (cursor_hpos > width) cursor_hpos = width;
-      cursor_hpos += XFASTINT (w->left);
+      cursor_hpos += WINDOW_LEFT_MARGIN (w);
       if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
        {
          if (!(cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f)
@@ -3078,7 +3497,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
            {
              /* Line is not continued and did not start
                 in middle of character */
-             if ((hpos - XFASTINT (w->left)
+             if ((hpos - WINDOW_LEFT_MARGIN (w)
                   == (XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0))
                  && val.vpos)
                {
@@ -3097,12 +3516,19 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If hscroll and line not empty, insert truncation-at-left marker */
   if (hscroll && lastpos != start)
     {
-      *leftmargin = fix_glyph (f, truncator, 0);
+      GLYPH g = fix_glyph (f, truncator, 0);
+      *leftmargin = g;
       if (p1 <= leftmargin)
        p1 = leftmargin + 1;
+      else                     /* MULE: it may be a wide-column character */
+       {
+         p1prev = leftmargin + 1;
+         while (p1prev < p1 && *p1prev & GLYPH_MASK_PADDING)
+           *p1prev++ = g;
+       }
     }
 
-  if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
+  if (!WINDOW_RIGHTMOST_P (w))
     {
       endp++;
       if (p1 < leftmargin) p1 = leftmargin;
@@ -3112,15 +3538,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
          covered up by the scroll bars, and it's distracting to see
          them when the scroll bar windows are flickering around to be
          reconfigured.  */
-      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
        {
          int i;
          for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
            *p1++ = SPACEGLYPH;
        }
-      else
+      else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
        *p1++ = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
-                ? DISP_BORDER_GLYPH (dp)
+                ? XINT (DISP_BORDER_GLYPH (dp))
                 : '|');
     }
   desired_glyphs->used[vpos] = max (desired_glyphs->used[vpos],
@@ -3175,6 +3601,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
     }
 
   val.bufpos = pos;
+  val.ovstring_chars_done = ovstr_done;
   val_display_text_line = val;
   return &val_display_text_line;
 }
@@ -3193,7 +3620,8 @@ display_menu_bar (w)
   int i;
 
 #ifdef HAVE_NTGUI
-  return;
+  if (!NILP (Vwindow_system))
+    return;
 #endif
 
 #ifdef USE_X_TOOLKIT
@@ -3204,14 +3632,14 @@ display_menu_bar (w)
   get_display_line (f, vpos, 0);
 
   items = FRAME_MENU_BAR_ITEMS (f);
-  for (i = 0; i < XVECTOR (items)->size; i += 3)
+  for (i = 0; i < XVECTOR (items)->size; i += 4)
     {
       Lisp_Object pos, string;
       string = XVECTOR (items)->contents[i + 1];
       if (NILP (string))
        break;
 
-      XSETFASTINT (XVECTOR (items)->contents[i + 2], hpos);
+      XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
 
       if (hpos < maxendcol)
        hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
@@ -3247,8 +3675,8 @@ display_mode_line (w)
      struct window *w;
 {
   register int vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
-  register int left = XFASTINT (w->left);
-  register int right = XFASTINT (w->width) + left;
+  register int left = WINDOW_LEFT_MARGIN (w);
+  register int right = WINDOW_RIGHT_MARGIN (w);
   register FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
 
   line_number_displayed = 0;
@@ -3268,25 +3696,34 @@ display_mode_line (w)
 
   FRAME_DESIRED_GLYPHS (f)->bufp[vpos] = 0;
 
-  /* Make the mode line inverse video if the entire line
-     is made of mode lines.
-     I.e. if this window is full width,
-     or if it is the child of a full width window
-     (which implies that that window is split side-by-side
-     and the rest of this line is mode lines of the sibling windows).  */
-  if (XFASTINT (w->width) == FRAME_WIDTH (f)
-      || XFASTINT (XWINDOW (w->parent)->width) == FRAME_WIDTH (f))
-    FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
+  /* Put the mode line in inverse video.
+     Use faces if possible, since that lets us handle
+     partial-width windows and avoid inverting the scroll bar columns.  */
 #ifdef HAVE_FACES
-  else if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
+  if (! FRAME_TERMCAP_P (f) && mode_line_inverse_video)
     {
       /* For a partial width window, explicitly set face of each glyph. */
       int i;
+      unsigned int padding;
       GLYPH *ptr = FRAME_DESIRED_GLYPHS (f)->glyphs[vpos];
       for (i = left; i < right; ++i)
-       ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1);
+       {
+         padding = ptr[i] & GLYPH_MASK_PADDING;
+         ptr[i] = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (ptr[i]), 1) | padding;
+       }
     }
+  else
 #endif
+
+  /* Make the mode line inverse video if the entire line
+     is made of mode lines.
+     I.e. if this window is full width,
+     or if it is the child of a full width window
+     (which implies that that window is split side-by-side
+     and the rest of this line is mode lines of the sibling windows).  */
+  if (WINDOW_FULL_WIDTH_P (w)
+      || WINDOW_FULL_WIDTH_P (XWINDOW (w->parent)))
+    FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
 }
 
 /* Contribute ELT to the mode line for window W.
@@ -3548,6 +3985,46 @@ pint2str (buf, width, d)
   }
 }
 
+/* Set a mnemonic character for CODING_SYSTEM (Lisp symbol) in BUF.
+   If EOL_FLAG is 1, set also a mnemonic character for end-of-line
+   type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+
+static char *
+decode_mode_spec_coding (coding_system, buf, eol_flag)
+     Lisp_Object coding_system;
+     register char *buf;
+     int eol_flag;
+{
+  register Lisp_Object val = coding_system;
+
+  if (NILP (val))              /* Not yet decided.  */
+    {
+      *buf++ = '-';
+      if (eol_flag) *buf++ = eol_mnemonic_undecided;
+    }
+  else
+    {
+      while (!NILP (val) && SYMBOLP (val))
+       val = Fget (val, Qcoding_system);
+      *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+      if (eol_flag)
+       {
+         val = Fget (coding_system, Qeol_type);
+
+         if (NILP (val))       /* Not yet decided.  */
+           *buf++ = eol_mnemonic_undecided;
+         else if (VECTORP (val)) /* Not yet decided.  */
+           *buf++ = eol_mnemonic_undecided;
+         else                  /* INTEGERP (val) -- 1:LF, 2:CRLF, 3:CR */
+           *buf++ = (XFASTINT (val) == 1
+                     ? eol_mnemonic_unix
+                     : (XFASTINT (val) == 2
+                        ? eol_mnemonic_dos : eol_mnemonic_mac));
+       }
+    }
+  return buf;
+}
+
 /* Return a string for the output of a mode line %-spec for window W,
    generated by character C.  SPEC_WIDTH is the field width when
    padding to the left (%c, %l).  The value returned from this
@@ -3664,13 +4141,11 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 
     case 'F':
       /* %F displays the frame name.  */
-#ifdef MULTI_FRAME
-      if (!NILP (selected_frame->title))
-       return (char *) XSTRING (selected_frame->title)->data;
-      return (char *) XSTRING (selected_frame->name)->data;
-#else
+      if (!NILP (f->title))
+       return (char *) XSTRING (f->title)->data;
+      if (f->explicit_name || ! FRAME_WINDOW_P (f))
+       return (char *) XSTRING (f->name)->data;
       return "Emacs";
-#endif
 
     case 'f': 
       obj = b->filename;
@@ -3699,6 +4174,9 @@ decode_mode_spec (w, c, spec_width, maxwidth)
           don't forget that too fast.  */
        if (EQ (w->base_line_pos, w->buffer))
          goto no_value;
+       /* But do forget it, if the window shows a different buffer now.  */
+       else if (BUFFERP (w->base_line_pos))
+         w->base_line_pos = Qnil;
 
        /* If the buffer is very big, don't waste time.  */
        if (BUF_ZV (b) - BUF_BEGV (b) > line_number_display_limit)
@@ -3869,6 +4347,36 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 #else
       return "T";
 #endif
+
+    case 'z':
+      /* coding-system (not including end-of-line format) */
+    case 'Z':
+      /* coding-system (including end-of-line type) */
+      {
+       int eol_flag = (c == 'Z');
+       char *p;
+
+       p = decode_mode_spec_coding
+         (find_symbol_value (Qbuffer_file_coding_system),
+          decode_mode_spec_buf, eol_flag);
+       if (FRAME_TERMCAP_P (f))
+         {
+           p = decode_mode_spec_coding (keyboard_coding.symbol, p, eol_flag);
+           p = decode_mode_spec_coding (terminal_coding.symbol, p, eol_flag);
+         }
+#ifdef subprocesses
+       obj = Fget_buffer_process (Fcurrent_buffer ());
+       if (PROCESSP (obj))
+         {
+           p = decode_mode_spec_coding (XPROCESS (obj)->decode_coding_system,
+                                        p, eol_flag);
+           p = decode_mode_spec_coding (XPROCESS (obj)->encode_coding_system,
+                                        p, eol_flag);
+         }
+#endif /* subprocesses */
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
     }
 
   if (STRINGP (obj))
@@ -3921,8 +4429,8 @@ display_scan_buffer (start, count, shortage)
       {
        ceiling =  BUFFER_CEILING_OF (start);
        ceiling = min (limit, ceiling);
-       ceiling_addr = &FETCH_CHAR (ceiling) + 1;
-       base = (cursor = &FETCH_CHAR (start));
+       ceiling_addr = POS_ADDR (ceiling) + 1;
+       base = (cursor = POS_ADDR (start));
        while (1)
          {
            while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
@@ -3950,8 +4458,8 @@ display_scan_buffer (start, count, shortage)
        {                       /* we WILL scan under start */
          ceiling =  BUFFER_FLOOR_OF (start);
          ceiling = max (limit, ceiling);
-         ceiling_addr = &FETCH_CHAR (ceiling) - 1;
-         base = (cursor = &FETCH_CHAR (start));
+         ceiling_addr = POS_ADDR (ceiling) - 1;
+         base = (cursor = POS_ADDR (start));
          cursor++;
          while (1)
            {
@@ -4052,6 +4560,8 @@ 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.  */
@@ -4070,16 +4580,16 @@ display_string (w, vpos, string, length, hpos, truncate,
     {
       end = start + window_width - (truncate != 0);
 
-      if ((window_width + XFASTINT (w->left)) != FRAME_WIDTH (f))
+      if (!WINDOW_RIGHTMOST_P (w))
        {
-         if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+         if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
            {
              int i;
 
              for (i = 0; i < FRAME_SCROLL_BAR_COLS (f); i++)
                *end-- = ' ';
            }
-         else
+         else if (!FRAME_HAS_VERTICAL_SCROLL_BARS (f))
            *end-- = '|';
        }
     }
@@ -4095,20 +4605,25 @@ display_string (w, vpos, string, length, hpos, truncate,
   if (maxcol >= 0 && mincol > maxcol)
     mincol = maxcol;
 
+  if (length < 0)
+    /* We need this value for multibyte characters.  */
+    length = strlen (string);
+
   /* We set truncated to 1 if we get stopped by trying to pass END
      (that is, trying to pass MAXCOL.)  */
   truncated = 0;
   while (1)
     {
-      if (length == 0)
-       break;
-      c = *string++;
-      /* Specified length.  */
-      if (length >= 0)
-       length--;
-      /* Unspecified length (null-terminated string).  */
-      else if (c == 0)
+      int len;
+
+      if (length <= 0)
        break;
+      if (multibyte)
+       c = STRING_CHAR_AND_LENGTH (string, length, len);
+      else
+       c = *string, len = 1;
+
+      string += len, length -= len;
 
       if (p1 >= end)
        {
@@ -4142,20 +4657,25 @@ display_string (w, vpos, string, length, hpos, truncate,
       else if (c < 0200 && ! NILP (buffer_defaults.ctl_arrow))
        {
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
-                                ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
-                            0);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_CTRL_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (dp)))
+                       ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+                   0));
          p1++;
          if (p1 >= start && p1 < end)
            *p1 = c ^ 0100;
          p1++;
        }
-      else
+      else if (len == 1)
        {
+         /* C is a control character or a binary byte data.  */
          if (p1 >= start)
-           *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-                                ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-                            0);
+           *p1 = (fix_glyph
+                  (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
+                       && GLYPH_CHAR_VALID_P (XINT (DISP_ESCAPE_GLYPH (dp)))
+                       ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
+                   0));
          p1++;
          if (p1 >= start && p1 < end)
            *p1 = (c >> 6) + '0';
@@ -4167,6 +4687,48 @@ display_string (w, vpos, string, length, hpos, truncate,
            *p1 = (7 & c) + '0';
          p1++;
        }
+      else
+       {
+         /* C is a multibyte character.  */      
+         int charset = CHAR_CHARSET (c);
+         int columns = (charset == CHARSET_COMPOSITION
+                        ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
+                        : CHARSET_WIDTH (charset));
+
+         if (p1 < start)
+           {
+             /* Since we can't show the left part of C, fill all
+                 columns with spaces.  */
+             columns -= start - p1;
+             p1 = start;
+             while (columns--)
+               {
+                 if (p1 < end)
+                   *p1 = SPACEGLYPH;
+                 p1++;
+               }
+           }
+         else if (p1 + columns > end)
+           {
+             /* Since we can't show the right part of C, fill all
+                 columns with TRUNCATE if TRUNCATE is specified.  */
+             if (truncate)
+               {
+                 while (p1 < end)
+                   *p1++ = fix_glyph (f, truncate, 0);
+                 /* And tell the line is truncated.  */
+                 truncated = 1;
+               }
+             break;
+           }
+         else
+           {
+             /* We can show the whole glyph of C.  */
+             *p1++ = c;
+             while (--columns)
+               *p1++ = c | GLYPH_MASK_PADDING;
+           }
+       }
     }
 
   if (truncated)
@@ -4314,6 +4876,16 @@ See also `overlay-arrow-string'.");
 If that fails to bring point back on frame, point is centered instead.\n\
 If this is zero, point is always centered after it moves off frame.");
 
+  DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
+    "*Scroll up to this many lines, to bring point back on screen.");
+  scroll_conservatively = 0;
+
+  DEFVAR_INT ("scroll-margin", &scroll_margin,
+    "*Number of lines of margin at the top and bottom of a window.\n\
+Recenter the window whenever point gets within this many lines\n\
+of the top or bottom of the window.");
+  scroll_margin = 0;
+
   DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
 
   DEFVAR_BOOL ("truncate-partial-width-windows",