]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
automatically generated from GPLed version
[gnu-emacs] / src / xdisp.c
index f56a16a7a829d598a226db1bf8a6c00a70f46114..d7c0bfe34bc3f9cb4da56167ea6afad7d11f3e40 100644 (file)
@@ -1,5 +1,6 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 1997
+     Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,6 +30,7 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "charset.h"
 #include "indent.h"
 #include "commands.h"
 #include "macros.h"
@@ -36,6 +38,8 @@ 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 ();
@@ -45,6 +49,8 @@ extern int pending_menu_activation;
 extern int interrupt_input;
 extern int command_loop_level;
 
+extern int minibuffer_auto_raise;
+
 extern Lisp_Object Qface;
 
 extern Lisp_Object Voverriding_local_map;
@@ -139,6 +145,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;
@@ -404,7 +418,8 @@ message2_nolog (m, len)
       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);
@@ -431,6 +446,9 @@ message2_nolog (m, len)
        {
          echo_area_glyphs = m;
          echo_area_glyphs_length = len;
+
+         if (minibuffer_auto_raise)
+           Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
        }
       else
        echo_area_glyphs = previous_echo_glyphs = 0;
@@ -535,10 +553,10 @@ message (m, a1, a2, a3)
              a[2] = a3;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           (int) FRAME_WIDTH (f), m, (char *)0, 3, a);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, a);
 #else
              len = doprnt (FRAME_MESSAGE_BUF (f),
-                           (int) FRAME_WIDTH (f), m, (char *)0, 3, &a1);
+                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
 
              message2 (FRAME_MESSAGE_BUF (f), len);
@@ -612,7 +630,8 @@ echo_area_display ()
                      echo_area_glyphs ? echo_area_glyphs : "",
                      echo_area_glyphs ? echo_area_glyphs_length : -1,
                      FRAME_LEFT_SCROLL_BAR_WIDTH (f),
-                     0, 0, 0, FRAME_WIDTH (f));
+                     0, 0, 0,
+                     FRAME_WIDTH (f) + FRAME_LEFT_SCROLL_BAR_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 */
@@ -630,10 +649,13 @@ echo_area_display ()
             i < vpos + XFASTINT (XWINDOW (mini_window)->height); i++)
          {
            get_display_line (f, i, 0);
-           display_string (XWINDOW (mini_window), vpos,
+           /* We don't use FRAME_SCROLL_BAR_WIDTH (f) as the starting
+              hpos, because it is good to clear whatever is behind the
+              scroll bar.  This does not affect the scroll bar itself.  */
+           display_string (XWINDOW (mini_window), i,
                            "", 0, 
-                            FRAME_LEFT_SCROLL_BAR_WIDTH (f),
-                           0, 0, 0, FRAME_WIDTH (f));
+                            0, 0, 0,
+                            0, FRAME_WIDTH (f) + FRAME_SCROLL_BAR_WIDTH (f));
          }
       }
     }
@@ -762,7 +784,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)
        {
@@ -848,6 +870,7 @@ redisplay_internal (preserve_echo_area)
   int all_windows;
   register int tlbufpos, tlendpos;
   struct position pos;
+  int number_of_frames_redisplayed;
 
   if (noninteractive)
     return;
@@ -857,6 +880,8 @@ redisplay_internal (preserve_echo_area)
     return;
 #endif
 
+ retry:
+
   if (! FRAME_WINDOW_P (selected_frame)
       && previous_terminal_frame != selected_frame)
     {
@@ -946,6 +971,9 @@ 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)
@@ -974,20 +1002,49 @@ redisplay_internal (preserve_echo_area)
              && 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
@@ -1041,7 +1098,8 @@ redisplay_internal (preserve_echo_area)
         then we can't just move the cursor.  */
       else if (! (!NILP (Vtransient_mark_mode)
                  && !NILP (current_buffer->mark_active))
-              && w == XWINDOW (current_buffer->last_selected_window)
+              && (w == XWINDOW (current_buffer->last_selected_window)
+                  || highlight_nonselected_windows)
               && NILP (w->region_showing)
               && !cursor_in_echo_area)
        {
@@ -1090,6 +1148,7 @@ 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)
        {
@@ -1103,7 +1162,10 @@ redisplay_internal (preserve_echo_area)
                (*condemn_scroll_bars_hook) (f);
 
              if (FRAME_VISIBLE_P (f))
-               redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
+               {
+                 redisplay_windows (FRAME_ROOT_WINDOW (f), preserve_echo_area);
+                 number_of_frames_redisplayed++;
+               }
 
              /* Any scroll bars which redisplay_windows should have nuked
                 should now go away.  */
@@ -1117,6 +1179,7 @@ redisplay_internal (preserve_echo_area)
       redisplay_window (selected_window, 1, preserve_echo_area);
       if (!WINDOW_FULL_WIDTH_P (w))
        preserve_other_columns (w);
+      number_of_frames_redisplayed = 1;
     }
 
 update: 
@@ -1225,6 +1288,16 @@ update:
          w->last_had_star
            = (BUF_MODIFF (XBUFFER (w->buffer)) > BUF_SAVE_MODIFF (XBUFFER (w->buffer))
               ? Qt : Qnil);
+
+         /* Record if we are showing a region, so can make sure to
+            update it fully at next redisplay.  */
+         w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && (w == XWINDOW (current_buffer->last_selected_window)
+                                  || highlight_nonselected_windows)
+                              && !NILP (XBUFFER (w->buffer)->mark_active)
+                              ? Fmarker_position (XBUFFER (w->buffer)->mark)
+                              : Qnil);
+
          w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
@@ -1248,13 +1321,37 @@ update:
     request_sigio ();
   start_polling ();
 
+  /* If something has become visible now which was not before,
+     redisplay again, so that we get them.  */
+  if (!pause)
+    {
+      Lisp_Object tail, frame;
+      int new_count = 0;
+
+      FOR_EACH_FRAME (tail, frame)
+       {
+         int this_is_visible = 0;
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+         FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+         if (XFRAME (frame)->visible)
+           this_is_visible = 1;
+
+         if (this_is_visible)
+           new_count++;
+       }
+
+      if (new_count != number_of_frames_redisplayed)
+       windows_or_buffers_changed++;
+    }
+
   /* Change frame size now if a change is pending.  */
   do_pending_window_change ();
 
-  /* If we just did a pending size change, redisplay again
-     for the new size.  */
+  /* If we just did a pending size change, or have additional
+     visible frames, redisplay again.  */
   if (windows_or_buffers_changed && !pause)
-    redisplay ();
+    goto retry;
 }
 
 /* Redisplay, but leave alone any recent echo area message
@@ -1302,7 +1399,8 @@ mark_window_display_accurate (window, flag)
          /* Record if we are showing a region, so can make sure to
             update it fully at next redisplay.  */
          w->region_showing = (!NILP (Vtransient_mark_mode)
-                              && w == XWINDOW (current_buffer->last_selected_window)
+                              && (w == XWINDOW (current_buffer->last_selected_window)
+                                  || highlight_nonselected_windows)
                               && !NILP (XBUFFER (w->buffer)->mark_active)
                               ? Fmarker_position (XBUFFER (w->buffer)->mark)
                               : Qnil);
@@ -1383,7 +1481,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);
@@ -1431,6 +1529,43 @@ redisplay_windows (window, preserve_echo_area)
     redisplay_window (window, 0, preserve_echo_area);
 }
 
+/* Return value in display table DP (Lisp_Char_Table *) for character
+   C.  Since a display table doesn't have any parent, we don't have to
+   follow parent.  Do not call this function directly but use the
+   macro DISP_CHAR_VECTOR.  */
+Lisp_Object
+disp_char_vector (dp, c)
+     struct Lisp_Char_Table *dp;
+     int c;
+{
+  int code[4], i;
+  Lisp_Object val;
+
+  if (SINGLE_BYTE_CHAR_P (c)) return (dp->contents[c]);
+  
+  SPLIT_NON_ASCII_CHAR (c, code[0], code[1], code[2]);
+  if (code[0] != CHARSET_COMPOSITION)
+    {
+      if (code[1] < 32) code[1] = -1;
+      else if (code[2] < 32) code[2] = -1;
+    }
+  /* Here, the possible range of CODE[0] (== charset ID) is
+     128..MAX_CHARSET.  Since the top level char table contains data
+     for multibyte characters after 256th element, we must increment
+     CODE[0] by 128 to get a correct index.  */
+  code[0] += 128;
+  code[3] = -1;                /* anchor */
+
+  for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
+    {
+      val = dp->contents[code[i]];
+      if (!SUB_CHAR_TABLE_P (val))
+       return (NILP (val) ? dp->defalt : val);
+    }
+  /* Here, VAL is a sub char table.  We return the default value of it.  */
+  return (dp->defalt);
+}
+
 /* Redisplay window WINDOW and its subwindows.  */
 
 static void
@@ -1578,6 +1713,30 @@ redisplay_window (window, just_this_one, preserve_echo_area)
 
   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))
@@ -1674,11 +1833,27 @@ redisplay_window (window, just_this_one, preserve_echo_area)
       && 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)))
@@ -1704,7 +1879,7 @@ redisplay_window (window, just_this_one, preserve_echo_area)
      but no longer is, find a new starting point.  */
   else if (!NILP (w->start_at_line_beg)
           && !(startp <= BEGV
-               || FETCH_CHAR (startp - 1) == '\n'))
+               || FETCH_BYTE (startp - 1) == '\n'))
     {
       goto recenter;
     }
@@ -1778,6 +1953,83 @@ redisplay_window (window, just_this_one, preserve_echo_area)
 
   /* 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)
     {
@@ -1834,7 +2086,7 @@ recenter:
 
   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
@@ -1920,30 +2172,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)
        {
@@ -1957,7 +2212,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;
     }
@@ -2011,7 +2266,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;
@@ -2023,7 +2278,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)
     {
@@ -2034,7 +2292,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);
@@ -2066,12 +2327,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;
@@ -2085,7 +2348,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.  */
@@ -2101,7 +2366,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;
 
@@ -2114,17 +2379,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;
        }
@@ -2135,20 +2403,23 @@ 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;
@@ -2251,26 +2522,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;
     }
 
@@ -2297,27 +2577,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;
        }
 
@@ -2354,7 +2648,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)
@@ -2409,8 +2707,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.  */
@@ -2426,7 +2729,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;
       }
@@ -2473,6 +2776,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.
 
@@ -2483,12 +2789,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;
@@ -2519,7 +2826,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* 1 if we should highlight the region.  */
   int highlight_region
     = (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active)
-       && XWINDOW (current_buffer->last_selected_window) == w);
+       && (XWINDOW (current_buffer->last_selected_window) == w
+          || highlight_nonselected_windows));
   int region_beg, region_end;
 
   int selective = (INTEGERP (current_buffer->selective_display)
@@ -2545,10 +2853,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;
@@ -2585,7 +2904,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
@@ -2602,7 +2924,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;
@@ -2632,7 +2955,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
@@ -2667,7 +2993,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
   next_boundary = pos;
   p1prev = p1;
   prevpos = pos;
-  while (1)
+  while (p1 < endp)
     {
       if (pos >= pause)
        {
@@ -2685,11 +3011,45 @@ display_text_line (w, start, vpos, hpos, taboffset)
                  int ovlen;
                  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;
                    }
                }
 
@@ -2709,7 +3069,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
@@ -2790,9 +3155,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
             loop, to see what face we should start with.  */
          if (pos >= next_face_change
              && (FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f)))
-           current_face = compute_char_face (f, w, pos,
-                                             region_beg, region_end,
-                                             &next_face_change, pos + 50, 0);
+           {
+             int limit = pos + 50;
+
+             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
@@ -2815,7 +3186,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)
@@ -2823,23 +3194,33 @@ 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')
        {
+#if 0
+         /* Same as p1prev, but after the invis_vector_contents text
+            (if we have that on this line).  */
+         GLYPH *p1prev_modified;
+#endif
+
          invis = 0;
          if (last_invis_skip == pos
              && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (last_invis_prop))
@@ -2850,28 +3231,35 @@ 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)
            {
+#if 0
+             GLYPH *cs, *csend;
+
+             cs = charstart + (p1 - p1start);
+#endif
+
              p1 += selective_rlen;
              if (p1 - leftmargin > width)
                p1 = endp;
+
+#if 0 /* This needs more work; charstarts needs to record
+        both whether a position ho;ds an ellipsis character
+        and what buffer position it corresponds to.  */
+             csend = charstart + (p1 - p1start);
+             while (cs != csend)
+               *cs++ = -2;
+             /* The idea is to use p1prev_modified instead of p1prev
+                in the loop below over p2x.  */
+             p1prev_modified = p1;
+#endif
+
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
-                                (p1 - p1prev), current_face);
-           }
-#ifdef HAVE_FACES
-         /* Draw the face of the newline character as extending all the 
-            way to the end of the frame line.  */
-         if (current_face)
-           {
-             if (p1 < leftmargin)
-               p1 = leftmargin;
-             while (p1 < endp)
-               *p1++ = FAST_MAKE_GLYPH (' ', current_face);
+                                (p1 - p1prev), current_face, rev_dir_bit);
            }
-#endif
 
          /* Update charstarts for the newline that ended this line.  */
          /* Do nothing here for a char that's entirely off the left edge
@@ -2890,6 +3278,17 @@ display_text_line (w, start, vpos, hpos, taboffset)
              while (p2x < p2)
                *p2x++ = -1;
            }
+#ifdef HAVE_FACES
+         /* Draw the face of the newline character as extending all the 
+            way to the end of the frame line.  */
+         if (current_face)
+           {
+             if (p1 < leftmargin)
+               p1 = leftmargin;
+             while (p1 < endp)
+               *p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
+           }
+#endif
 
          break;
        }
@@ -2898,7 +3297,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))
@@ -2907,7 +3306,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)
            {
@@ -2915,7 +3314,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 
@@ -2925,7 +3324,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
 
@@ -2951,34 +3350,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.  */
 
@@ -3031,10 +3454,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.  */
@@ -3048,10 +3498,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
@@ -3073,16 +3524,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.  */
@@ -3130,9 +3585,16 @@ 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 (!WINDOW_RIGHTMOST_P (w))
@@ -3153,7 +3615,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
        }
       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],
@@ -3208,6 +3670,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;
 }
@@ -3248,7 +3711,7 @@ display_menu_bar (w)
       XSETFASTINT (XVECTOR (items)->contents[i + 3], hpos);
 
       if (hpos < maxendcol)
-       hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
+       hpos = display_string (w, vpos,
                               XSTRING (string)->data,
                               XSTRING (string)->size,
                               hpos, 0, 0, hpos, maxendcol);
@@ -3310,10 +3773,15 @@ display_mode_line (w)
     {
       /* 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
@@ -3322,8 +3790,8 @@ display_mode_line (w)
      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).  */
-  else if (WINDOW_FULL_WIDTH_P (w)
-          || WINDOW_FULL_WIDTH_P (XWINDOW (w->parent)))
+  if (WINDOW_FULL_WIDTH_P (w)
+      || WINDOW_FULL_WIDTH_P (XWINDOW (w->parent)))
     FRAME_DESIRED_GLYPHS (f)->highlight[vpos] = mode_line_inverse_video;
 }
 
@@ -3586,6 +4054,64 @@ pint2str (buf, width, d)
   }
 }
 
+/* Set a mnemonic character for CODING_SYSTEM (Lisp symbol) in BUF.
+   If EOL_FLAG is 1, set also a mnemonic character for end-of-line
+   type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+
+static char *
+decode_mode_spec_coding (coding_system, buf, eol_flag)
+     Lisp_Object coding_system;
+     register char *buf;
+     int eol_flag;
+{
+  Lisp_Object val;
+
+  val = coding_system;
+
+  if (NILP (val))              /* Not yet decided.  */
+    {
+      *buf++ = '-';
+      if (eol_flag)
+       *buf++ = eol_mnemonic_undecided;
+      /* Don't mention EOL conversion if it isn't decided.  */
+    }
+  else
+    {
+      Lisp_Object eolvalue;
+
+      eolvalue = Fget (coding_system, Qeol_type);
+
+      while (!NILP (val) && SYMBOLP (val))
+       {
+         val = Fget (val, Qcoding_system);
+         if (NILP (eolvalue))
+           eolvalue = Fget (coding_system, Qeol_type);
+       }
+
+      *buf++ = XFASTINT (XVECTOR (val)->contents[1]);
+      if (eol_flag)
+       {
+         /* The EOL conversion we are using.  */
+         int eoltype;
+         /* The EOL conversion that is normal on this system.  */
+
+         if (NILP (eolvalue))  /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else if (VECTORP (eolvalue)) /* Not yet decided.  */
+           eoltype = eol_mnemonic_undecided;
+         else                  /* INTEGERP (eolvalue) -- 0:LF, 1:CRLF, 2:CR */
+           eoltype = (XFASTINT (eolvalue) == 0
+                      ? eol_mnemonic_unix
+                      : (XFASTINT (eolvalue) == 1
+                         ? eol_mnemonic_dos : eol_mnemonic_mac));
+
+         /* Mention the EOL conversion if it is not the usual one.  */
+         *buf++ = eoltype;
+       }
+    }
+  return buf;
+}
+
 /* Return a string for the output of a mode line %-spec for window W,
    generated by character C.  SPEC_WIDTH is the field width when
    padding to the left (%c, %l).  The value returned from this
@@ -3735,6 +4261,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)
@@ -3905,6 +4434,40 @@ decode_mode_spec (w, c, spec_width, maxwidth)
 #else
       return "T";
 #endif
+
+    case 'z':
+      /* coding-system (not including end-of-line format) */
+    case 'Z':
+      /* coding-system (including end-of-line type) */
+      {
+       int eol_flag = (c == 'Z');
+       char *p = decode_mode_spec_buf;
+
+       if (FRAME_TERMCAP_P (f))
+         {
+           /* No need to mention EOL here--the terminal never needs
+              to do EOL conversion.  */
+           p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
+           p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+         }
+       p = decode_mode_spec_coding (b->buffer_file_coding_system,
+                                    p, eol_flag);
+
+#if 0 /* This proves to be annoying; I think we can do without.  -- rms.  */
+#ifdef subprocesses
+       obj = Fget_buffer_process (Fcurrent_buffer ());
+       if (PROCESSP (obj))
+         {
+           p = decode_mode_spec_coding (XPROCESS (obj)->decode_coding_system,
+                                        p, eol_flag);
+           p = decode_mode_spec_coding (XPROCESS (obj)->encode_coding_system,
+                                        p, eol_flag);
+         }
+#endif /* subprocesses */
+#endif /* 0 */
+       *p = 0;
+       return decode_mode_spec_buf;
+      }
     }
 
   if (STRINGP (obj))
@@ -3957,8 +4520,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)
@@ -3986,8 +4549,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)
            {
@@ -4088,6 +4651,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.  */
@@ -4131,20 +4696,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)
        {
@@ -4178,20 +4748,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';
@@ -4203,6 +4778,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)
@@ -4350,6 +4967,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",
@@ -4367,7 +4994,7 @@ If this is zero, point is always centered after it moves off frame.");
 
   DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
     "*Non-nil means highlight region even in nonselected windows.");
-  highlight_nonselected_windows = 1;
+  highlight_nonselected_windows = 0;
 
   DEFVAR_BOOL ("multiple-frames", &multiple_frames,
     "Non-nil if more than one frame is visible on this display.\n\
@@ -4440,8 +5067,10 @@ init_xdisp ()
   if (!noninteractive)
     {
       FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
-      XSETFASTINT (XWINDOW (root_window)->top, 0);
-      set_window_height (root_window, FRAME_HEIGHT (f) - 1, 0);
+      XSETFASTINT (XWINDOW (root_window)->top, FRAME_MENU_BAR_LINES (f));
+      set_window_height (root_window,
+                        FRAME_HEIGHT (f) - 1 - FRAME_MENU_BAR_LINES (f),
+                        0);
       XSETFASTINT (mini_w->top, FRAME_HEIGHT (f) - 1);
       set_window_height (minibuf_window, 1, 0);