changeset 17017:667a3686a447

(display_text_line): Introduce new local variable rev_dir_bit to display right to left characters (not yet used). (message): Use FRAME_MESSAGE_BUF_SIZE(). (redisplay_internal): Add canceling code for continuation at wide-column. (display_text_line): Don't just decrement left_edge->bufpos, it may be multi-byte character, use DEC_POS instead. (try_window): Change the way of calculation of tab offset. We now use val.tab_offset to maintain tab offset. Removed local variable tab_offset. (try_window_id): Likewise. (pos_tab_offset): Return COL (Modulo is no longer valid). Add the line to set tab_offset member. Use pos.tab_offset. (redisplay_window): Specify big negative number for TOHPOS of compute_motion(). (try_window_id): Likewise. (tri_window_id): Specify "1 << (BITS_PER_SHORT - 1)" to express "Don't care". Include charset.h, coding.h, and process.h. (display_text_line): Handle multibyte characters. (display_mode_line): Pay attention to wide-column characters. (decode_mode_spec_coding): New function. (decode_mode_spec): Handle %-constructs `%z' and `%Z' to print coding system mnemonics. (display_string): Handle multibyte characters.
author Karl Heuer <kwzh@gnu.org>
date Thu, 20 Feb 1997 06:40:53 +0000
parents ded89d7e1575
children f13a67b3ec8d
files src/xdisp.c
diffstat 1 files changed, 400 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/src/xdisp.c	Thu Feb 20 06:39:27 1997 +0000
+++ b/src/xdisp.c	Thu Feb 20 06:40:53 1997 +0000
@@ -29,6 +29,7 @@
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "charset.h"
 #include "indent.h"
 #include "commands.h"
 #include "macros.h"
@@ -36,6 +37,8 @@
 #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 ();
@@ -548,10 +551,10 @@
 	      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);
@@ -987,15 +990,44 @@
 	      && 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;
@@ -1604,7 +1636,10 @@
 			       ? minibuf_prompt_width : 0)
 			      + (hscroll ? 1 - hscroll : 0)),
 			     0,
-			     PT, height, 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.  */
@@ -1711,8 +1746,12 @@
       int this_scroll_margin = scroll_margin;
 
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0), 0,
-			    PT, height, 0, width, hscroll,
-			    pos_tab_offset (w, startp), w);
+			     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)
@@ -1750,7 +1789,7 @@
      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;
     }
@@ -1957,7 +1996,7 @@
 
   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
@@ -2043,7 +2082,6 @@
   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;
@@ -2059,13 +2097,18 @@
   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;
       if (val.vpos) tab_offset = 0;
+#endif  /* 0 */
       vpos++;
       if (pos != val.bufpos)
 	{
@@ -2079,7 +2122,7 @@
 	  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;
     }
@@ -2133,7 +2176,7 @@
   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;
@@ -2145,7 +2188,10 @@
 
   /* 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)
     {
@@ -2156,7 +2202,10 @@
 	     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);
@@ -2188,12 +2237,14 @@
       --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;
@@ -2207,7 +2258,9 @@
   /* 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.  */
@@ -2223,7 +2276,7 @@
      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;
 
@@ -2236,17 +2289,20 @@
   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;
 	}
@@ -2263,14 +2319,17 @@
 	    {
 	      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;
@@ -2373,27 +2432,35 @@
 
   /* 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;
     }
 
@@ -2420,28 +2487,37 @@
       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;
       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.ovstring_chars_done);
+	  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;
 	}
 
@@ -2478,7 +2554,11 @@
   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)
@@ -2677,6 +2757,15 @@
   GLYPH continuer = (dp == 0 || !INTEGERP (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;
@@ -2760,7 +2849,8 @@
       if (left_edge->vpos > vpos
           || left_edge->hpos > 0)
         {
-          pos = left_edge->bufpos - 1;
+          pos = left_edge->bufpos;
+	  DEC_POS (pos);	/* MULE: It may be a multi-byte character */
           hpos = left_edge->prevhpos;
         }
       else
@@ -2820,13 +2910,32 @@
 		      ovstr += ovstr_done;
 		      ovlen -= ovstr_done;
 
-		      /* Start outputting.  */
-		      for (; ovlen; ovlen--, ovstr++)
+		      while (ovlen > 0)
 			{
-			  if (p1 >= leftmargin && p1 < endp)
-			    *p1 = MAKE_GLYPH (f, *ovstr, current_face);
-			  p1++;
-			  ovstr_done++;
+			  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
@@ -2852,7 +2961,12 @@
 	      /* 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
@@ -2933,9 +3047,15 @@
 	     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
@@ -2958,7 +3078,7 @@
 	  if (pos < GPT && GPT < pause)
 	    pause = GPT;
 
-	  p = &FETCH_CHAR (pos);
+	  p = POS_ADDR (pos);
 	}
 
       if (p1 >= endp)
@@ -2966,19 +3086,23 @@
 
       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')
@@ -2993,7 +3117,7 @@
 	    {
 	      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)
@@ -3002,7 +3126,7 @@
 	      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 
@@ -3012,7 +3136,7 @@
 	      if (p1 < leftmargin)
 		p1 = leftmargin;
 	      while (p1 < endp)
-		*p1++ = FAST_MAKE_GLYPH (' ', current_face);
+		*p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
 	    }
 #endif
 
@@ -3041,7 +3165,7 @@
 	  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))
@@ -3050,7 +3174,7 @@
       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)
 	    {
@@ -3058,7 +3182,7 @@
 	      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 
@@ -3068,7 +3192,7 @@
 	      if (p1 < leftmargin)
 		p1 = leftmargin;
 	      while (p1 < endp)
-		*p1++ = FAST_MAKE_GLYPH (' ', current_face);
+		*p1++ = FAST_MAKE_GLYPH (' ', current_face) | rev_dir_bit;
 	    }
 #endif
 
@@ -3094,34 +3218,54 @@
       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))
+				  ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
+			      current_face)
+		   | rev_dir_bit);
 	  p1++;
 	  if (p1 >= leftmargin && p1 < endp)
-	    *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
+	    *p1 = MAKE_GLYPH (f, c ^ 0100, current_face) | rev_dir_bit;
+	  p1++;
+	}
+      else if (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)
+		   | rev_dir_bit);
+	  p1++;
+	  if (p1 >= leftmargin && p1 < endp)
+	    *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face) | rev_dir_bit;
+	  p1++;
+	  if (p1 >= leftmargin && p1 < endp)
+	    *p1 = (MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face)
+		   | rev_dir_bit);
+	  p1++;
+	  if (p1 >= leftmargin && p1 < endp)
+	    *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face) | rev_dir_bit;
 	  p1++;
 	}
       else
 	{
-	  if (p1 >= leftmargin)
-	    *p1 = fix_glyph (f, (dp && INTEGERP (DISP_ESCAPE_GLYPH (dp))
-				 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
-			     current_face);
-	  p1++;
-	  if (p1 >= leftmargin && p1 < endp)
-	    *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
-	  p1++;
-	  if (p1 >= leftmargin && p1 < endp)
-	    *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
-	  p1++;
-	  if (p1 >= leftmargin && p1 < endp)
-	    *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
-	  p1++;
+	  /* C is a multibyte character.  */
+	  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.  */
 
@@ -3174,10 +3318,37 @@
 	 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.  */
@@ -3191,10 +3362,11 @@
 
   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
@@ -3216,16 +3388,20 @@
 		     && 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.  */
@@ -3273,9 +3449,16 @@
   /* 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))
@@ -3454,9 +3637,13 @@
     {
       /* 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;
+	}
     }
 #endif
 
@@ -3730,6 +3917,46 @@
   }
 }
 
+/* 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
@@ -4052,6 +4279,36 @@
 #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))
@@ -4104,8 +4361,8 @@
       {
 	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)
@@ -4133,8 +4390,8 @@
 	{			/* 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)
 	    {
@@ -4235,6 +4492,8 @@
   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.  */
@@ -4278,20 +4537,25 @@
   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)
+      int len;
+
+      if (length <= 0)
 	break;
-      c = *string++;
-      /* Specified length.  */
-      if (length >= 0)
-	length--;
-      /* Unspecified length (null-terminated string).  */
-      else if (c == 0)
-	break;
+      if (multibyte)
+	c = STRING_CHAR_AND_LENGTH (string, length, len);
+      else
+	c = *string, len = 1;
+
+      string += len, length -= len;
 
       if (p1 >= end)
 	{
@@ -4333,8 +4597,9 @@
 	    *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)) : '\\'),
@@ -4350,6 +4615,48 @@
 	    *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)