]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(get_next_display_element):
[gnu-emacs] / src / xdisp.c
index d485dc59b57e8ef2c6794149b83a7f54c1de17ce..1bb2b4292c02f27b23e752c80068fe6386a7901b 100644 (file)
@@ -1,6 +1,6 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04
-   Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999,
+     2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -308,7 +308,7 @@ Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
 Lisp_Object Qslice;
 Lisp_Object Qcenter;
 Lisp_Object Qmargin, Qpointer;
-Lisp_Object Qline_height, Qtotal;
+Lisp_Object Qline_height;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
 extern Lisp_Object Qscroll_bar;
@@ -318,6 +318,10 @@ extern Lisp_Object Qcursor;
 
 Lisp_Object Vshow_trailing_whitespace;
 
+/* Non-nil means escape non-break space and hyphens.  */
+
+Lisp_Object Vnobreak_char_display;
+
 #ifdef HAVE_WINDOW_SYSTEM
 extern Lisp_Object Voverflow_newline_into_fringe;
 
@@ -345,7 +349,10 @@ Lisp_Object Qtrailing_whitespace;
 /* Name and number of the face used to highlight escape glyphs.  */
 
 Lisp_Object Qescape_glyph;
-int escape_glyph_face;
+
+/* Name and number of the face used to highlight non-breaking spaces.  */
+
+Lisp_Object Qnobreak_space;
 
 /* The symbol `image' which is the car of the lists used to represent
    images in Lisp.  */
@@ -459,7 +466,7 @@ static Lisp_Object Vwindow_size_change_functions;
 
 Lisp_Object Qmenu_bar_update_hook, Vmenu_bar_update_hook;
 
-/* Nonzero if overlay arrow has been displayed once in this window.  */
+/* Nonzero if an overlay arrow has been displayed in this window.  */
 
 static int overlay_arrow_seen;
 
@@ -564,12 +571,21 @@ Lisp_Object Vmessage_log_max;
 
 static Lisp_Object Vmessages_buffer_name;
 
-/* Current, index 0, and last displayed echo area message.  Either
-   buffers from echo_buffers, or nil to indicate no message.  */
+/* Index 0 is the buffer that holds the current (desired) echo area message,
+   or nil if none is desired right now.
+
+   Index 1 is the buffer that holds the previously displayed echo area message,
+   or nil to indicate no message.  This is normally what's on the screen now.
+
+   These two can point to the same buffer.  That happens when the last
+   message output by the user (or made by echoing) has been displayed.  */
 
 Lisp_Object echo_area_buffer[2];
 
-/* The buffers referenced from echo_area_buffer.  */
+/* Permanent pointers to the two buffers that are used for echo area
+   purposes.  Once the two buffers are made, and their pointers are
+   placed here, these two slots remain unchanged unless those buffers
+   need to be created afresh.  */
 
 static Lisp_Object echo_buffer[2];
 
@@ -609,12 +625,6 @@ Lisp_Object Qmessage_truncate_lines;
 
 static int message_cleared_p;
 
-/* Non-zero means we want a hollow cursor in windows that are not
-   selected.  Zero means there's no cursor in such windows.  */
-
-Lisp_Object Vcursor_in_non_selected_windows;
-Lisp_Object Qcursor_in_non_selected_windows;
-
 /* How to blink the default frame cursor off.  */
 Lisp_Object Vblink_cursor_alist;
 
@@ -778,6 +788,13 @@ enum move_it_result
 #define CLEAR_FACE_CACHE_COUNT 500
 static int clear_face_cache_count;
 
+/* Similarly for the image cache.  */
+
+#ifdef HAVE_WINDOW_SYSTEM
+#define CLEAR_IMAGE_CACHE_COUNT        101
+static int clear_image_cache_count;
+#endif
+
 /* Record the previous terminal frame we displayed.  */
 
 static struct frame *previous_terminal_frame;
@@ -824,15 +841,14 @@ static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
 static int invisible_text_between_p P_ ((struct it *, int, int));
 #endif
 
-static int next_element_from_ellipsis P_ ((struct it *));
 static void pint2str P_ ((char *, int, int));
 static void pint2hrstr P_ ((char *, int, int));
 static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
                                                        struct text_pos));
 static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
 static int text_outside_line_unchanged_p P_ ((struct window *, int, int));
-static void store_frame_title_char P_ ((char));
-static int store_frame_title P_ ((const unsigned char *, int, int));
+static void store_mode_line_noprop_char P_ ((char));
+static int store_mode_line_noprop P_ ((const unsigned char *, int, int));
 static void x_consider_frame_title P_ ((Lisp_Object));
 static void handle_stop P_ ((struct it *));
 static int tool_bar_lines_needed P_ ((struct frame *));
@@ -861,7 +877,7 @@ static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *,
                                                          Lisp_Object));
 static void extend_face_to_end_of_line P_ ((struct it *));
 static int append_space_for_newline P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *, int));
+static int cursor_row_fully_visible_p P_ ((struct window *, int, int));
 static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
 static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
@@ -899,6 +915,7 @@ static void reseat_1 P_ ((struct it *, struct text_pos, int));
 static void back_to_previous_visible_line_start P_ ((struct it *));
 void reseat_at_previous_visible_line_start P_ ((struct it *));
 static void reseat_at_next_visible_line_start P_ ((struct it *, int));
+static int next_element_from_ellipsis P_ ((struct it *));
 static int next_element_from_display_vector P_ ((struct it *));
 static int next_element_from_string P_ ((struct it *));
 static int next_element_from_c_string P_ ((struct it *));
@@ -1240,28 +1257,31 @@ line_bottom_y (it)
 }
 
 
-/* Return 1 if position CHARPOS is visible in window W.  Set *FULLY to
-   1 if POS is visible and the line containing POS is fully visible.
+/* Return 1 if position CHARPOS is visible in window W.
+   If visible, set *X and *Y to pixel coordinates of top left corner.
+   Set *RTOP and *RBOT to pixel height of an invisible area of glyph at POS.
    EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line
    and header-lines heights.  */
 
 int
-pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
      struct window *w;
-     int charpos, *fully, *x, *y, exact_mode_line_heights_p;
+     int charpos, *x, *y, *rtop, *rbot, exact_mode_line_heights_p;
 {
   struct it it;
   struct text_pos top;
-  int visible_p;
+  int visible_p = 0;
   struct buffer *old_buffer = NULL;
 
+  if (noninteractive)
+    return visible_p;
+
   if (XBUFFER (w->buffer) != current_buffer)
     {
       old_buffer = current_buffer;
       set_buffer_internal_1 (XBUFFER (w->buffer));
     }
 
-  *fully = visible_p = 0;
   SET_TEXT_POS_FROM_MARKER (top, w->start);
 
   /* Compute exact mode line heights, if requested.  */
@@ -1279,44 +1299,45 @@ pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
     }
 
   start_display (&it, w, top);
-  move_it_to (&it, charpos, 0, it.last_visible_y, -1,
-             MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+  move_it_to (&it, charpos, -1, it.last_visible_y, -1,
+             MOVE_TO_POS | MOVE_TO_Y);
 
   /* Note that we may overshoot because of invisible text.  */
   if (IT_CHARPOS (it) >= charpos)
     {
+      int top_x = it.current_x;
       int top_y = it.current_y;
-      int bottom_y = line_bottom_y (&it);
+      int bottom_y = (last_height = 0, line_bottom_y (&it));
       int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
 
       if (top_y < window_top_y)
        visible_p = bottom_y > window_top_y;
       else if (top_y < it.last_visible_y)
-       {
          visible_p = 1;
-         *fully = bottom_y <= it.last_visible_y;
-       }
-      if (visible_p && x)
+      if (visible_p)
        {
-         *x = it.current_x;
-         *y = max (top_y + it.max_ascent - it.ascent, window_top_y);
+         *x = top_x;
+         *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
+         *rtop = max (0, window_top_y - top_y);
+         *rbot = max (0, bottom_y - it.last_visible_y);
        }
     }
-  else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
+  else
     {
       struct it it2;
 
       it2 = it;
-      move_it_by_lines (&it, 1, 0);
+      if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
+       move_it_by_lines (&it, 1, 0);
       if (charpos < IT_CHARPOS (it))
        {
          visible_p = 1;
-         if (x)
-           {
-             move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
-             *x = it2.current_x;
-             *y = it2.current_y + it2.max_ascent - it2.ascent;
-           }
+         move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
+         *x = it2.current_x;
+         *y = it2.current_y + it2.max_ascent - it2.ascent;
+         *rtop = max (0, -it2.current_y);
+         *rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent)
+                          - it.last_visible_y));
        }
     }
 
@@ -1773,6 +1794,24 @@ get_glyph_string_clip_rect (s, nr)
       r.height = s->row->visible_height;
     }
 
+  if (s->clip_head)
+    if (r.x < s->clip_head->x)
+      {
+       if (r.width >= s->clip_head->x - r.x)
+         r.width -= s->clip_head->x - r.x;
+       else
+         r.width = 0;
+       r.x = s->clip_head->x;
+      }
+  if (s->clip_tail)
+    if (r.x + r.width > s->clip_tail->x + s->clip_tail->background_width)
+      {
+       if (s->clip_tail->x + s->clip_tail->background_width >= r.x)
+         r.width = s->clip_tail->x + s->clip_tail->background_width - r.x;
+       else
+         r.width = 0;
+      }
+
   /* If S draws overlapping rows, it's sufficient to use the top and
      bottom of the window for clipping because this glyph string
      intentionally draws over other lines.  */
@@ -1806,7 +1845,7 @@ get_glyph_string_clip_rect (s, nr)
   if (s->hl == DRAW_CURSOR)
     {
       struct glyph *glyph = s->first_glyph;
-      int height;
+      int height, max_y;
 
       if (s->x > r.x)
        {
@@ -1815,13 +1854,26 @@ get_glyph_string_clip_rect (s, nr)
        }
       r.width = min (r.width, glyph->pixel_width);
 
-      /* Don't draw cursor glyph taller than our actual glyph.  */
-      height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
-      if (height < r.height)
+      /* If r.y is below window bottom, ensure that we still see a cursor.  */
+      height = min (glyph->ascent + glyph->descent,
+                   min (FRAME_LINE_HEIGHT (s->f), s->row->visible_height));
+      max_y = window_text_bottom_y (s->w) - height;
+      max_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, max_y);
+      if (s->ybase - glyph->ascent > max_y)
+       {
+         r.y = max_y;
+         r.height = height;
+       }
+      else
        {
-         int max_y = r.y + r.height;
-         r.y = min (max_y, s->ybase + glyph->descent - height);
-         r.height = min (max_y - r.y, height);
+         /* Don't draw cursor glyph taller than our actual glyph.  */
+         height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
+         if (height < r.height)
+           {
+             max_y = r.y + r.height;
+             r.y = min (max_y, max (r.y, s->ybase + glyph->descent - height));
+             r.height = min (max_y - r.y, height);
+           }
        }
     }
 
@@ -1832,6 +1884,64 @@ get_glyph_string_clip_rect (s, nr)
 #endif
 }
 
+
+/* EXPORT:
+   Return the position and height of the phys cursor in window W.
+   Set w->phys_cursor_width to width of phys cursor.
+*/
+
+int
+get_phys_cursor_geometry (w, row, glyph, heightp)
+     struct window *w;
+     struct glyph_row *row;
+     struct glyph *glyph;
+     int *heightp;
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int y, wd, h, h0, y0;
+
+  /* Compute the width of the rectangle to draw.  If on a stretch
+     glyph, and `x-stretch-block-cursor' is nil, don't draw a
+     rectangle as wide as the glyph, but use a canonical character
+     width instead.  */
+  wd = glyph->pixel_width - 1;
+#ifdef HAVE_NTGUI
+  wd++; /* Why? */
+#endif
+  if (glyph->type == STRETCH_GLYPH
+      && !x_stretch_cursor_p)
+    wd = min (FRAME_COLUMN_WIDTH (f), wd);
+  w->phys_cursor_width = wd;
+
+  y = w->phys_cursor.y + row->ascent - glyph->ascent;
+
+  /* If y is below window bottom, ensure that we still see a cursor.  */
+  h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height);
+
+  h = max (h0, glyph->ascent + glyph->descent);
+  h0 = min (h0, glyph->ascent + glyph->descent);
+
+  y0 = WINDOW_HEADER_LINE_HEIGHT (w);
+  if (y < y0)
+    {
+      h = max (h - (y0 - y) + 1, h0);
+      y = y0 - 1;
+    }
+  else
+    {
+      y0 = window_text_bottom_y (w) - h0;
+      if (y > y0)
+       {
+         h += y - y0;
+         y = y0;
+       }
+    }
+
+  *heightp = h - 1;
+  return WINDOW_TO_FRAME_PIXEL_Y (w, y);
+}
+
+
 #endif /* HAVE_WINDOW_SYSTEM */
 
 \f
@@ -1941,7 +2051,7 @@ static void
 check_it (it)
      struct it *it;
 {
-  if (it->method == next_element_from_string)
+  if (it->method == GET_FROM_STRING)
     {
       xassert (STRINGP (it->string));
       xassert (IT_STRING_CHARPOS (*it) >= 0);
@@ -1949,7 +2059,7 @@ check_it (it)
   else
     {
       xassert (IT_STRING_CHARPOS (*it) < 0);
-      if (it->method == next_element_from_buffer)
+      if (it->method == GET_FROM_BUFFER)
        {
          /* Check that character and byte positions agree.  */
          xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
@@ -2434,7 +2544,10 @@ init_from_display_pos (it, w, pos)
      after-string.  */
   init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
 
-  for (i = 0; i < it->n_overlay_strings; ++i)
+  /* This only scans the current chunk -- it should scan all chunks.
+     However, OVERLAY_STRING_CHUNK_SIZE has been increased from 3 in 21.1
+     to 16 in 22.1 to make this a lesser problem.  */
+  for (i = 0; i < it->n_overlay_strings && i < OVERLAY_STRING_CHUNK_SIZE; ++i)
     {
       const char *s = SDATA (it->overlay_strings[i]);
       const char *e = s + SBYTES (it->overlay_strings[i]);
@@ -2459,7 +2572,7 @@ init_from_display_pos (it, w, pos)
         property for an image, the iterator will be set up for that
         image, and we have to undo that setup first before we can
         correct the overlay string index.  */
-      if (it->method == next_element_from_image)
+      if (it->method == GET_FROM_IMAGE)
        pop_it (it);
 
       /* We already have the first chunk of overlay strings in
@@ -2482,7 +2595,7 @@ init_from_display_pos (it, w, pos)
       it->string = it->overlay_strings[relative_index];
       xassert (STRINGP (it->string));
       it->current.string_pos = pos->string_pos;
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
     }
 
 #if 0 /* This is bogus because POS not having an overlay string
@@ -2498,7 +2611,7 @@ init_from_display_pos (it, w, pos)
       while (it->sp)
        pop_it (it);
       it->current.overlay_string_index = -1;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
       if (CHARPOS (pos->pos) == ZV)
        it->overlay_strings_at_end_processed_p = 1;
     }
@@ -2591,6 +2704,10 @@ handle_stop (it)
   it->dpvec = NULL;
   it->current.dpvec_index = -1;
 
+  /* Use face of preceding text for ellipsis (if invisible) */
+  if (it->selective_display_ellipsis_p)
+    it->saved_face_id = it->face_id;
+
   do
     {
       handled = HANDLED_NORMALLY;
@@ -2612,7 +2729,7 @@ handle_stop (it)
        {
          /* Don't check for overlay strings below when set to deliver
             characters from a display vector.  */
-         if (it->method == next_element_from_display_vector)
+         if (it->method == GET_FROM_DISPLAY_VECTOR)
            handle_overlay_change_p = 0;
 
          /* Handle overlay changes.  */
@@ -3265,11 +3382,16 @@ setup_for_ellipsis (it, len)
 
   it->dpvec_char_len = len;
   it->current.dpvec_index = 0;
+  it->dpvec_face_id = -1;
 
   /* Remember the current face id in case glyphs specify faces.
-     IT's face is restored in set_iterator_to_next.  */
-  it->saved_face_id = it->face_id;
-  it->method = next_element_from_display_vector;
+     IT's face is restored in set_iterator_to_next.
+     saved_face_id was set to preceding char's face in handle_stop.  */
+  if (it->saved_face_id < 0 || it->saved_face_id != it->face_id)
+    it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
+
+  it->method = GET_FROM_DISPLAY_VECTOR;
+  it->ellipsis_p = 1;
 }
 
 
@@ -3290,7 +3412,7 @@ handle_display_prop (it)
 {
   Lisp_Object prop, object;
   struct text_pos *position;
-  /* Nonzero if some property replaces the display of the text itself.  */ 
+  /* Nonzero if some property replaces the display of the text itself.  */
   int display_replaced_p = 0;
 
   if (STRINGP (it->string))
@@ -3353,7 +3475,10 @@ handle_display_prop (it)
     }
   else
     {
-      if (handle_single_display_spec (it, prop, object, position, 0))
+      int ret = handle_single_display_spec (it, prop, object, position, 0);
+      if (ret < 0)  /* Replaced by "", i.e. nothing. */
+       return HANDLED_RECOMPUTE_PROPS;
+      if (ret)
        display_replaced_p = 1;
     }
 
@@ -3397,7 +3522,8 @@ display_prop_end (it, object, start_pos)
    property ends.
 
    Value is non-zero if something was found which replaces the display
-   of buffer or string text.  */
+   of buffer or string text.  Specifically, the value is -1 if that
+   "something" is "nothing". */
 
 static int
 handle_single_display_spec (it, spec, object, position,
@@ -3455,7 +3581,7 @@ handle_single_display_spec (it, spec, object, position,
     {
       if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
        return 0;
-      
+
       it->font_height = XCAR (XCDR (spec));
       if (!NILP (it->font_height))
        {
@@ -3618,7 +3744,8 @@ handle_single_display_spec (it, spec, object, position,
       if (CONSP (XCDR (XCDR (spec))))
        {
          Lisp_Object face_name = XCAR (XCDR (XCDR (spec)));
-         int face_id2 = lookup_named_face (it->f, face_name, 'A', 0);
+         int face_id2 = lookup_derived_face (it->f, face_name,
+                                             'A', FRINGE_FACE_ID, 0);
          if (face_id2 >= 0)
            face_id = face_id2;
        }
@@ -3633,7 +3760,7 @@ handle_single_display_spec (it, spec, object, position,
       it->image_id = -1; /* no image */
       it->position = start_pos;
       it->object = NILP (object) ? it->w->buffer : object;
-      it->method = next_element_from_image;
+      it->method = GET_FROM_IMAGE;
       it->face_id = face_id;
 
       /* Say that we haven't consumed the characters with
@@ -3711,12 +3838,17 @@ handle_single_display_spec (it, spec, object, position,
 
       if (STRINGP (value))
        {
+         if (SCHARS (value) == 0)
+           {
+             pop_it (it);
+             return -1;  /* Replaced by "", i.e. nothing.  */
+           }
          it->string = value;
          it->multibyte_p = STRING_MULTIBYTE (it->string);
          it->current.overlay_string_index = -1;
          IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
          it->end_charpos = it->string_nchars = SCHARS (it->string);
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          it->stop_charpos = 0;
          it->string_from_display_prop_p = 1;
          /* Say that we haven't consumed the characters with
@@ -3726,7 +3858,7 @@ handle_single_display_spec (it, spec, object, position,
        }
       else if (CONSP (value) && EQ (XCAR (value), Qspace))
        {
-         it->method = next_element_from_stretch;
+         it->method = GET_FROM_STRETCH;
          it->object = value;
          it->current.pos = it->position = start_pos;
        }
@@ -3737,7 +3869,7 @@ handle_single_display_spec (it, spec, object, position,
          it->image_id = lookup_image (it->f, value);
          it->position = start_pos;
          it->object = NILP (object) ? it->w->buffer : object;
-         it->method = next_element_from_image;
+         it->method = GET_FROM_IMAGE;
 
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
@@ -3993,7 +4125,7 @@ handle_composition_prop (it)
 
       if (id >= 0)
        {
-         it->method = next_element_from_composition;
+         it->method = GET_FROM_COMPOSITION;
          it->cmp_id = id;
          it->cmp_len = COMPOSITION_LENGTH (prop);
          /* For a terminal, draw only the first character of the
@@ -4068,7 +4200,7 @@ next_overlay_string (it)
       it->current.overlay_string_index = -1;
       SET_TEXT_POS (it->current.string_pos, -1, -1);
       it->n_overlay_strings = 0;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
 
       /* If we're at the end of the buffer, record that we have
         processed the overlay strings there already, so that
@@ -4097,7 +4229,7 @@ next_overlay_string (it)
       it->string = it->overlay_strings[i];
       it->multibyte_p = STRING_MULTIBYTE (it->string);
       SET_TEXT_POS (it->current.string_pos, 0, 0);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
       it->stop_charpos = 0;
     }
 
@@ -4362,13 +4494,13 @@ get_overlay_strings (it, charpos)
       xassert (STRINGP (it->string));
       it->end_charpos = SCHARS (it->string);
       it->multibyte_p = STRING_MULTIBYTE (it->string);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
     }
   else
     {
       it->string = Qnil;
       it->current.overlay_string_index = -1;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
     }
 
   CHECK_IT (it);
@@ -4568,47 +4700,57 @@ static void
 back_to_previous_visible_line_start (it)
      struct it *it;
 {
-  int visible_p = 0;
-
-  /* Go back one newline if not on BEGV already.  */
-  if (IT_CHARPOS (*it) > BEGV)
-    back_to_previous_line_start (it);
-
-  /* Move over lines that are invisible because of selective display
-     or text properties.  */
-  while (IT_CHARPOS (*it) > BEGV
-        && !visible_p)
+  while (IT_CHARPOS (*it) > BEGV)
     {
-      visible_p = 1;
+      back_to_previous_line_start (it);
+      if (IT_CHARPOS (*it) <= BEGV)
+       break;
 
       /* If selective > 0, then lines indented more than that values
         are invisible.  */
       if (it->selective > 0
          && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
                                (double) it->selective)) /* iftc */
-       visible_p = 0;
-      else
-       {
-         Lisp_Object prop;
+       continue;
 
-         /* Check the newline before point for invisibility.  */
-         prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
+      /* Check the newline before point for invisibility.  */
+      {
+       Lisp_Object prop;
+       prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
                                     Qinvisible, it->window);
-         if (TEXT_PROP_MEANS_INVISIBLE (prop))
-           visible_p = 0;
-       }
+       if (TEXT_PROP_MEANS_INVISIBLE (prop))
+         continue;
+      }
 
-      if (visible_p)
+      /* If newline has a display property that replaces the newline with something
+        else (image or text), find start of overlay or interval and continue search
+        from that point.  */
+      if (IT_CHARPOS (*it) > BEGV)
        {
          struct it it2 = *it;
-
-         if (handle_display_prop (&it2) == HANDLED_RETURN)
-           visible_p = 0;
+         int pos;
+         int beg, end;
+         Lisp_Object val, overlay;
+
+         pos = --IT_CHARPOS (it2);
+         --IT_BYTEPOS (it2);
+         it2.sp = 0;
+         if (handle_display_prop (&it2) == HANDLED_RETURN
+             && !NILP (val = get_char_property_and_overlay
+                       (make_number (pos), Qdisplay, Qnil, &overlay))
+             && (OVERLAYP (overlay)
+                 ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
+                 : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
+           {
+             if (beg < BEGV)
+               beg = BEGV;
+             IT_CHARPOS (*it) = beg;
+             IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
+             continue;
+           }
        }
 
-      /* Back one more newline if the current one is invisible.  */
-      if (!visible_p)
-       back_to_previous_line_start (it);
+      break;
     }
 
   xassert (IT_CHARPOS (*it) >= BEGV);
@@ -4740,7 +4882,7 @@ reseat_1 (it, pos, set_stop_p)
   IT_STRING_CHARPOS (*it) = -1;
   IT_STRING_BYTEPOS (*it) = -1;
   it->string = Qnil;
-  it->method = next_element_from_buffer;
+  it->method = GET_FROM_BUFFER;
   /* RMS: I added this to fix a bug in move_it_vertically_backward
      where it->area continued to relate to the starting point
      for the backward motion.  Bug report from
@@ -4806,7 +4948,7 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
       it->string = string;
       it->s = NULL;
       it->end_charpos = it->string_nchars = SCHARS (string);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
       it->current.string_pos = string_pos (charpos, string);
     }
   else
@@ -4828,7 +4970,7 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
          it->end_charpos = it->string_nchars = strlen (s);
        }
 
-      it->method = next_element_from_c_string;
+      it->method = GET_FROM_C_STRING;
     }
 
   /* PRECISION > 0 means don't return more than PRECISION characters
@@ -4859,6 +5001,20 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
                              Iteration
  ***********************************************************************/
 
+/* Map enum it_method value to corresponding next_element_from_* function.  */
+
+static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) =
+{
+  next_element_from_buffer,
+  next_element_from_display_vector,
+  next_element_from_composition,
+  next_element_from_string,
+  next_element_from_c_string,
+  next_element_from_image,
+  next_element_from_stretch
+};
+
+
 /* Load IT's display element fields with information about the next
    display element from the current position of IT.  Value is zero if
    end of buffer (or C string) is reached.  */
@@ -4874,7 +5030,7 @@ get_next_display_element (it)
   int success_p;
 
  get_next:
-  success_p = (*it->method) (it);
+  success_p = (*get_next_element[it->method]) (it);
 
   if (it->what == IT_CHARACTER)
     {
@@ -4906,8 +5062,10 @@ get_next_display_element (it)
                  it->dpvec = v->contents;
                  it->dpend = v->contents + v->size;
                  it->current.dpvec_index = 0;
+                 it->dpvec_face_id = -1;
                  it->saved_face_id = it->face_id;
-                 it->method = next_element_from_display_vector;
+                 it->method = GET_FROM_DISPLAY_VECTOR;
+                 it->ellipsis_p = 0;
                }
              else
                {
@@ -4932,15 +5090,18 @@ get_next_display_element (it)
          else if ((it->c < ' '
                    && (it->area != TEXT_AREA
                        /* In mode line, treat \n like other crl chars.  */
-                       || (it->c != '\n'
+                       || (it->c != '\t'
                            && it->glyph_row && it->glyph_row->mode_line_p)
                        || (it->c != '\n' && it->c != '\t')))
                   || (it->multibyte_p
                       ? ((it->c >= 127
                           && it->len == 1)
                          || !CHAR_PRINTABLE_P (it->c)
-                         || it->c == 0x8ad
-                         || it->c == 0x8a0)
+                         || (!NILP (Vnobreak_char_display)
+                             && (it->c == 0x8a0 || it->c == 0x8ad
+                                 || it->c == 0x920 || it->c == 0x92d
+                                 || it->c == 0xe20 || it->c == 0xe2d
+                                 || it->c == 0xf20 || it->c == 0xf2d)))
                       : (it->c >= 127
                          && (!unibyte_display_via_language_environment
                              || it->c == unibyte_char_to_multibyte (it->c)))))
@@ -4952,79 +5113,131 @@ get_next_display_element (it)
                 display.  Then, set IT->dpvec to these glyphs.  */
              GLYPH g;
              int ctl_len;
-             int face_id = escape_glyph_face;
+             int face_id, lface_id = 0 ;
+             GLYPH escape_glyph;
 
-             /* Find the face id if `escape-glyph' unless we recently did.  */
-             if (face_id < 0)
-               {
-                 Lisp_Object tem = Fget (Qescape_glyph, Qface);
-                 if (INTEGERP (tem))
-                   face_id = XINT (tem);
-                 else
-                   face_id = 0;
-                 /* If there's overflow, use 0 instead.  */
-                 if (FAST_GLYPH_FACE (FAST_MAKE_GLYPH (0, face_id)) != face_id)
-                   face_id = 0;
-                 escape_glyph_face = face_id;
-               }
+             /* Handle control characters with ^.  */
 
              if (it->c < 128 && it->ctl_arrow_p)
                {
+                 g = '^';           /* default glyph for Control */
                  /* Set IT->ctl_chars[0] to the glyph for `^'.  */
                  if (it->dp
                      && INTEGERP (DISP_CTRL_GLYPH (it->dp))
                      && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (it->dp))))
-                   g = XINT (DISP_CTRL_GLYPH (it->dp));
+                   {
+                     g = XINT (DISP_CTRL_GLYPH (it->dp));
+                     lface_id = FAST_GLYPH_FACE (g);
+                   }
+                 if (lface_id)
+                   {
+                      g = FAST_GLYPH_CHAR (g);
+                      face_id = merge_faces (it->f, Qt, lface_id,
+                                             it->face_id);
+                   }
                  else
-                   g = FAST_MAKE_GLYPH ('^', face_id);
-                 XSETINT (it->ctl_chars[0], g);
+                   {
+                     /* Merge the escape-glyph face into the current face.  */
+                     face_id = merge_faces (it->f, Qescape_glyph, 0,
+                                            it->face_id);
+                   }
 
-                 g = FAST_MAKE_GLYPH (it->c ^ 0100, face_id);
+                 XSETINT (it->ctl_chars[0], g);
+                 g = it->c ^ 0100;
                  XSETINT (it->ctl_chars[1], g);
                  ctl_len = 2;
+                 goto display_control;
                }
-             else if (it->c == 0x8a0 || it->c == 0x8ad)
+
+             /* Handle non-break space in the mode where it only gets
+                highlighting.  */
+
+             if (EQ (Vnobreak_char_display, Qt)
+                 && (it->c == 0x8a0 || it->c == 0x920
+                     || it->c == 0xe20 || it->c == 0xf20))
                {
-                 /* Set IT->ctl_chars[0] to the glyph for `\\'.  */
-                 if (it->dp
-                     && INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
-                     && GLYPH_CHAR_VALID_P (XINT (DISP_ESCAPE_GLYPH (it->dp))))
-                   g = XINT (DISP_ESCAPE_GLYPH (it->dp));
-                 else
-                   g = FAST_MAKE_GLYPH ('\\', face_id);
+                 /* Merge the no-break-space face into the current face.  */
+                 face_id = merge_faces (it->f, Qnobreak_space, 0,
+                                        it->face_id);
+
+                 g = it->c = ' ';
                  XSETINT (it->ctl_chars[0], g);
+                 ctl_len = 1;
+                 goto display_control;
+               }
 
-                 g = FAST_MAKE_GLYPH (it->c == 0x8ad ? '-' : ' ', face_id);
-                 XSETINT (it->ctl_chars[1], g);
-                 ctl_len = 2;
+             /* Handle sequences that start with the "escape glyph".  */
+
+             /* the default escape glyph is \.  */
+             escape_glyph = '\\';
+
+             if (it->dp
+                 && INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
+                 && GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
+               {
+                 escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
+                 lface_id = FAST_GLYPH_FACE (escape_glyph);
+               }
+             if (lface_id)
+               {
+                 /* The display table specified a face.
+                    Merge it into face_id and also into escape_glyph.  */
+                 escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
+                 face_id = merge_faces (it->f, Qt, lface_id,
+                                        it->face_id);
                }
              else
                {
-                 unsigned char str[MAX_MULTIBYTE_LENGTH];
-                 int len;
-                 int i;
-                 GLYPH escape_glyph;
+                 /* Merge the escape-glyph face into the current face.  */
+                 face_id = merge_faces (it->f, Qescape_glyph, 0,
+                                        it->face_id);
+               }
 
-                 /* Set IT->ctl_chars[0] to the glyph for `\\'.  */
-                 if (it->dp
-                     && INTEGERP (DISP_ESCAPE_GLYPH (it->dp))
-                     && GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp))))
-                   escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp));
-                 else
-                   escape_glyph = FAST_MAKE_GLYPH ('\\', face_id);
+             /* Handle soft hyphens in the mode where they only get
+                highlighting.  */
 
-                 if (SINGLE_BYTE_CHAR_P (it->c))
-                   str[0] = it->c, len = 1;
-                 else
-                   {
-                     len = CHAR_STRING_NO_SIGNAL (it->c, str);
-                     if (len < 0)
-                       {
-                         /* It's an invalid character, which
-                            shouldn't happen actually, but due to
-                            bugs it may happen.  Let's print the char
-                            as is, there's not much meaningful we can
-                            do with it.  */
+             if (EQ (Vnobreak_char_display, Qt)
+                 && (it->c == 0x8ad || it->c == 0x92d
+                     || it->c == 0xe2d || it->c == 0xf2d))
+               {
+                 g = it->c = '-';
+                 XSETINT (it->ctl_chars[0], g);
+                 ctl_len = 1;
+                 goto display_control;
+               }
+
+             /* Handle non-break space and soft hyphen
+                with the escape glyph.  */
+
+             if (it->c == 0x8a0 || it->c == 0x8ad
+                 || it->c == 0x920 || it->c == 0x92d
+                 || it->c == 0xe20 || it->c == 0xe2d
+                 || it->c == 0xf20 || it->c == 0xf2d)
+               {
+                 XSETINT (it->ctl_chars[0], escape_glyph);
+                 g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
+                 XSETINT (it->ctl_chars[1], g);
+                 ctl_len = 2;
+                 goto display_control;
+               }
+
+             {
+               unsigned char str[MAX_MULTIBYTE_LENGTH];
+               int len;
+               int i;
+
+               /* Set IT->ctl_chars[0] to the glyph for `\\'.  */
+               if (SINGLE_BYTE_CHAR_P (it->c))
+                 str[0] = it->c, len = 1;
+               else
+                 {
+                   len = CHAR_STRING_NO_SIGNAL (it->c, str);
+                   if (len < 0)
+                     {
+                       /* It's an invalid character, which shouldn't
+                          happen actually, but due to bugs it may
+                          happen.  Let's print the char as is, there's
+                          not much meaningful we can do with it.  */
                          str[0] = it->c;
                          str[1] = it->c >> 8;
                          str[2] = it->c >> 16;
@@ -5033,31 +5246,31 @@ get_next_display_element (it)
                        }
                    }
 
-                 for (i = 0; i < len; i++)
-                   {
-                     XSETINT (it->ctl_chars[i * 4], escape_glyph);
-                     /* Insert three more glyphs into IT->ctl_chars for
-                        the octal display of the character.  */
-                     g = FAST_MAKE_GLYPH (((str[i] >> 6) & 7) + '0',
-                                          face_id);
-                     XSETINT (it->ctl_chars[i * 4 + 1], g);
-                     g = FAST_MAKE_GLYPH (((str[i] >> 3) & 7) + '0',
-                                          face_id);
-                     XSETINT (it->ctl_chars[i * 4 + 2], g);
-                     g = FAST_MAKE_GLYPH ((str[i] & 7) + '0',
-                                          face_id);
-                     XSETINT (it->ctl_chars[i * 4 + 3], g);
-                   }
-                 ctl_len = len * 4;
-               }
+               for (i = 0; i < len; i++)
+                 {
+                   XSETINT (it->ctl_chars[i * 4], escape_glyph);
+                   /* Insert three more glyphs into IT->ctl_chars for
+                      the octal display of the character.  */
+                   g = ((str[i] >> 6) & 7) + '0';
+                   XSETINT (it->ctl_chars[i * 4 + 1], g);
+                   g = ((str[i] >> 3) & 7) + '0';
+                   XSETINT (it->ctl_chars[i * 4 + 2], g);
+                   g = (str[i] & 7) + '0';
+                   XSETINT (it->ctl_chars[i * 4 + 3], g);
+                 }
+               ctl_len = len * 4;
+             }
 
+           display_control:
              /* Set up IT->dpvec and return first character from it.  */
              it->dpvec_char_len = it->len;
              it->dpvec = it->ctl_chars;
              it->dpend = it->dpvec + ctl_len;
              it->current.dpvec_index = 0;
+             it->dpvec_face_id = face_id;
              it->saved_face_id = it->face_id;
-             it->method = next_element_from_display_vector;
+             it->method = GET_FROM_DISPLAY_VECTOR;
+             it->ellipsis_p = 0;
              goto get_next;
            }
        }
@@ -5118,8 +5331,9 @@ set_iterator_to_next (it, reseat_p)
      moving the iterator to a new position might set them.  */
   it->start_of_box_run_p = it->end_of_box_run_p = 0;
 
-  if (it->method == next_element_from_buffer)
+  switch (it->method)
     {
+    case GET_FROM_BUFFER:
       /* The current display element of IT is a character from
         current_buffer.  Advance in the buffer, and maybe skip over
         invisible lines that are so because of selective display.  */
@@ -5132,32 +5346,32 @@ set_iterator_to_next (it, reseat_p)
          IT_CHARPOS (*it) += 1;
          xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
        }
-    }
-  else if (it->method == next_element_from_composition)
-    {
-      xassert (it->cmp_id >= 0 && it ->cmp_id < n_compositions);
+      break;
+
+    case GET_FROM_COMPOSITION:
+      xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
       if (STRINGP (it->string))
        {
          IT_STRING_BYTEPOS (*it) += it->len;
          IT_STRING_CHARPOS (*it) += it->cmp_len;
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          goto consider_string_end;
        }
       else
        {
          IT_BYTEPOS (*it) += it->len;
          IT_CHARPOS (*it) += it->cmp_len;
-         it->method = next_element_from_buffer;
+         it->method = GET_FROM_BUFFER;
        }
-    }
-  else if (it->method == next_element_from_c_string)
-    {
+      break;
+
+    case GET_FROM_C_STRING:
       /* Current display element of IT is from a C string.  */
       IT_BYTEPOS (*it) += it->len;
       IT_CHARPOS (*it) += 1;
-    }
-  else if (it->method == next_element_from_display_vector)
-    {
+      break;
+
+    case GET_FROM_DISPLAY_VECTOR:
       /* Current display element of IT is from a display table entry.
         Advance in the display table definition.  Reset it to null if
         end reached, and continue with characters from buffers/
@@ -5171,18 +5385,15 @@ set_iterator_to_next (it, reseat_p)
       if (it->dpvec + it->current.dpvec_index == it->dpend)
        {
          if (it->s)
-           it->method = next_element_from_c_string;
+           it->method = GET_FROM_C_STRING;
          else if (STRINGP (it->string))
-           it->method = next_element_from_string;
+           it->method = GET_FROM_STRING;
          else
-           it->method = next_element_from_buffer;
+           it->method = GET_FROM_BUFFER;
 
          it->dpvec = NULL;
          it->current.dpvec_index = -1;
 
-         /* Recheck faces after display vector */
-         it->stop_charpos = 0;
-
          /* Skip over characters which were displayed via IT->dpvec.  */
          if (it->dpvec_char_len < 0)
            reseat_at_next_visible_line_start (it, 1);
@@ -5191,10 +5402,13 @@ set_iterator_to_next (it, reseat_p)
              it->len = it->dpvec_char_len;
              set_iterator_to_next (it, reseat_p);
            }
+
+         /* Recheck faces after display vector */
+         it->stop_charpos = IT_CHARPOS (*it);
        }
-    }
-  else if (it->method == next_element_from_string)
-    {
+      break;
+
+    case GET_FROM_STRING:
       /* Current display element is a character from a Lisp string.  */
       xassert (it->s == NULL && STRINGP (it->string));
       IT_STRING_BYTEPOS (*it) += it->len;
@@ -5219,34 +5433,35 @@ set_iterator_to_next (it, reseat_p)
              && it->sp > 0)
            {
              pop_it (it);
-             if (!STRINGP (it->string))
-               it->method = next_element_from_buffer;
-             else
+             if (STRINGP (it->string))
                goto consider_string_end;
+             it->method = GET_FROM_BUFFER;
            }
        }
-    }
-  else if (it->method == next_element_from_image
-          || it->method == next_element_from_stretch)
-    {
+      break;
+
+    case GET_FROM_IMAGE:
+    case GET_FROM_STRETCH:
       /* The position etc with which we have to proceed are on
         the stack.  The position may be at the end of a string,
          if the `display' property takes up the whole string.  */
+      xassert (it->sp > 0);
       pop_it (it);
       it->image_id = 0;
       if (STRINGP (it->string))
        {
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          goto consider_string_end;
        }
-      else
-       it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
+      break;
+
+    default:
+      /* There are no other methods defined, so this should be a bug.  */
+      abort ();
     }
-  else
-    /* There are no other methods defined, so this should be a bug.  */
-    abort ();
 
-  xassert (it->method != next_element_from_string
+  xassert (it->method != GET_FROM_STRING
           || (STRINGP (it->string)
               && IT_STRING_CHARPOS (*it) >= 0));
 }
@@ -5267,10 +5482,11 @@ next_element_from_display_vector (it)
   /* Precondition.  */
   xassert (it->dpvec && it->current.dpvec_index >= 0);
 
+  it->face_id = it->saved_face_id;
+
   if (INTEGERP (*it->dpvec)
       && GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec)))
     {
-      int lface_id;
       GLYPH g;
 
       g = XFASTINT (it->dpvec[it->current.dpvec_index]);
@@ -5280,13 +5496,14 @@ next_element_from_display_vector (it)
       /* The entry may contain a face id to use.  Such a face id is
         the id of a Lisp face, not a realized face.  A face id of
         zero means no face is specified.  */
-      lface_id = FAST_GLYPH_FACE (g);
-      if (lface_id)
+      if (it->dpvec_face_id >= 0)
+       it->face_id = it->dpvec_face_id;
+      else
        {
-         /* The function returns -1 if lface_id is invalid.  */
-         int face_id = ascii_face_of_lisp_face (it->f, lface_id);
-         if (face_id >= 0)
-           it->face_id = face_id;
+         int lface_id = FAST_GLYPH_FACE (g);
+         if (lface_id > 0)
+           it->face_id = merge_faces (it->f, Qt, lface_id,
+                                      it->saved_face_id);
        }
     }
   else
@@ -5458,7 +5675,7 @@ next_element_from_ellipsis (it)
         was in IT->saved_face_id, and signal that it's there by
         setting face_before_selective_p.  */
       it->saved_face_id = it->face_id;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
       reseat_at_next_visible_line_start (it, 1);
       it->face_before_selective_p = 1;
     }
@@ -5699,15 +5916,29 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
   saved_glyph_row = it->glyph_row;
   it->glyph_row = NULL;
 
-#define BUFFER_POS_REACHED_P()                     \
-  ((op & MOVE_TO_POS) != 0                         \
-   && BUFFERP (it->object)                         \
-   && IT_CHARPOS (*it) >= to_charpos)
+#define BUFFER_POS_REACHED_P()                                 \
+  ((op & MOVE_TO_POS) != 0                                     \
+   && BUFFERP (it->object)                                     \
+   && IT_CHARPOS (*it) >= to_charpos                           \
+   && (it->method == GET_FROM_BUFFER                           \
+       || (it->method == GET_FROM_DISPLAY_VECTOR               \
+          && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
+
 
   while (1)
     {
       int x, i, ascent = 0, descent = 0;
 
+      /* Stop if we move beyond TO_CHARPOS (after an image or stretch glyph).  */
+      if ((op & MOVE_TO_POS) != 0
+         && BUFFERP (it->object)
+         && it->method == GET_FROM_BUFFER
+         && IT_CHARPOS (*it) > to_charpos)
+       {
+         result = MOVE_POS_MATCH_OR_ZV;
+         break;
+       }
+
       /* Stop when ZV reached.
          We used to stop here when TO_CHARPOS reached as well, but that is
          too soon if this glyph does not fit on this line.  So we handle it
@@ -6172,7 +6403,11 @@ move_it_vertically_backward (it, dy)
         value of nlines is > 0 if continuation lines were involved.  */
       if (nlines > 0)
        move_it_by_lines (it, nlines, 1);
+#if 0
+      /* I think this assert is bogus if buffer contains
+        invisible text or images.  KFS.  */
       xassert (IT_CHARPOS (*it) <= start_pos);
+#endif
     }
   else
     {
@@ -6190,7 +6425,8 @@ move_it_vertically_backward (it, dy)
             a line height of 13 pixels each, recentering with point
             on the bottom line will try to move -39/2 = 19 pixels
             backward.  Try to avoid moving into the first line.  */
-         && it->current_y - target_y > line_height * 2 / 3
+         && (it->current_y - target_y
+             > min (window_box_height (it->w), line_height * 2 / 3))
          && IT_CHARPOS (*it) > BEGV)
        {
          TRACE_MOVE ((stderr, "  not far enough -> move_vert %d\n",
@@ -6220,7 +6456,11 @@ move_it_vertically_backward (it, dy)
              while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
            }
 
+#if 0
+         /* I think this assert is bogus if buffer contains
+            invisible text or images.  KFS.  */
          xassert (IT_CHARPOS (*it) >= BEGV);
+#endif
        }
     }
 }
@@ -6364,11 +6604,15 @@ move_it_by_lines (it, dvpos, need_y_p)
       it->current_y -= it2.current_y;
       it->current_x = it->hpos = 0;
 
-      /* If we moved too far, move IT some lines forward.  */
+      /* If we moved too far back, move IT some lines forward.  */
       if (it2.vpos > -dvpos)
        {
          int delta = it2.vpos + dvpos;
+         it2 = *it;
          move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
+         /* Move back again if we got too far ahead.  */
+         if (IT_CHARPOS (*it) >= start_charpos)
+           *it = it2;
        }
     }
 }
@@ -6379,7 +6623,7 @@ int
 in_display_vector_p (it)
      struct it *it;
 {
-  return (it->method == next_element_from_display_vector
+  return (it->method == GET_FROM_DISPLAY_VECTOR
          && it->current.dpvec_index > 0
          && it->dpvec + it->current.dpvec_index != it->dpend);
 }
@@ -6736,7 +6980,9 @@ message2_nolog (m, nbytes, multibyte)
 /* Display an echo area message M with a specified length of NBYTES
    bytes.  The string may include null characters.  If M is not a
    string, clear out any existing message, and let the mini-buffer
-   text show through.  */
+   text show through.
+
+   This function cancels echoing.  */
 
 void
 message3 (m, nbytes, multibyte)
@@ -6748,6 +6994,7 @@ message3 (m, nbytes, multibyte)
 
   GCPRO1 (m);
   clear_message (1,1);
+  cancel_echoing ();
 
   /* First flush out any partial line written with print.  */
   message_log_maybe_newline ();
@@ -6759,7 +7006,10 @@ message3 (m, nbytes, multibyte)
 }
 
 
-/* The non-logging version of message3.  */
+/* The non-logging version of message3.
+   This does not cancel echoing, because it is used for echoing.
+   Perhaps we need to make a separate function for echoing
+   and make this cancel echoing.  */
 
 void
 message3_nolog (m, nbytes, multibyte)
@@ -7053,10 +7303,6 @@ ensure_echo_area_buffers ()
    WHICH > 0 means use echo_area_buffer[1].  If that is nil, choose a
    suitable buffer from echo_buffer[] and clear it.
 
-   If WHICH < 0, set echo_area_buffer[1] to echo_area_buffer[0], so
-   that the current message becomes the last displayed one, make
-   choose a suitable buffer for echo_area_buffer[0], and clear it.
-
    Value is what FN returns.  */
 
 static int
@@ -7081,17 +7327,6 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
     this_one = 0, the_other = 1;
   else if (which > 0)
     this_one = 1, the_other = 0;
-  else
-    {
-      this_one = 0, the_other = 1;
-      clear_buffer_p = 1;
-
-      /* We need a fresh one in case the current echo buffer equals
-        the one containing the last displayed echo area message.  */
-      if (!NILP (echo_area_buffer[this_one])
-         && EQ (echo_area_buffer[this_one], echo_area_buffer[the_other]))
-       echo_area_buffer[this_one] = Qnil;
-    }
 
   /* Choose a suitable buffer from echo_buffer[] is we don't
      have one.  */
@@ -7711,7 +7946,7 @@ set_message (s, string, nbytes, multibyte_p)
     = ((s && multibyte_p)
        || (STRINGP (string) && STRING_MULTIBYTE (string)));
 
-  with_echo_area_buffer (0, -1, set_message_1,
+  with_echo_area_buffer (0, 0, set_message_1,
                         (EMACS_INT) s, string, nbytes, multibyte_p);
   message_buf_print = 0;
   help_echo_showing_p = 0;
@@ -7732,8 +7967,6 @@ set_message_1 (a1, a2, nbytes, multibyte_p)
   const char *s = (const char *) a1;
   Lisp_Object string = a2;
 
-  xassert (BEG == Z);
-
   /* Change multibyteness of the echo buffer appropriately.  */
   if (message_enable_multibyte
       != !NILP (current_buffer->enable_multibyte_characters))
@@ -7743,6 +7976,7 @@ set_message_1 (a1, a2, nbytes, multibyte_p)
 
   /* Insert new message at BEG.  */
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+  Ferase_buffer ();
 
   if (STRINGP (string))
     {
@@ -7959,7 +8193,7 @@ echo_area_display (update_frame_p)
   else if (!EQ (mini_window, selected_window))
     windows_or_buffers_changed++;
 
-  /* Last displayed message is now the current message.  */
+  /* The current message is now also the last one displayed.  */
   echo_area_buffer[1] = echo_area_buffer[0];
 
   /* Prevent redisplay optimization in redisplay_internal by resetting
@@ -7974,52 +8208,125 @@ echo_area_display (update_frame_p)
 
 \f
 /***********************************************************************
-                            Frame Titles
+                    Mode Lines and Frame Titles
  ***********************************************************************/
 
+/* A buffer for constructing non-propertized mode-line strings and
+   frame titles in it; allocated from the heap in init_xdisp and
+   resized as needed in store_mode_line_noprop_char.  */
 
-/* The frame title buffering code is also used by Fformat_mode_line.
-   So it is not conditioned by HAVE_WINDOW_SYSTEM.  */
+static char *mode_line_noprop_buf;
 
-/* A buffer for constructing frame titles in it; allocated from the
-   heap in init_xdisp and resized as needed in store_frame_title_char.  */
+/* The buffer's end, and a current output position in it.  */
 
-static char *frame_title_buf;
+static char *mode_line_noprop_buf_end;
+static char *mode_line_noprop_ptr;
 
-/* The buffer's end, and a current output position in it.  */
+#define MODE_LINE_NOPROP_LEN(start) \
+  ((mode_line_noprop_ptr - mode_line_noprop_buf) - start)
 
-static char *frame_title_buf_end;
-static char *frame_title_ptr;
+static enum {
+  MODE_LINE_DISPLAY = 0,
+  MODE_LINE_TITLE,
+  MODE_LINE_NOPROP,
+  MODE_LINE_STRING
+} mode_line_target;
 
+/* Alist that caches the results of :propertize.
+   Each element is (PROPERTIZED-STRING . PROPERTY-LIST).  */
+static Lisp_Object mode_line_proptrans_alist;
 
-/* Store a single character C for the frame title in frame_title_buf.
-   Re-allocate frame_title_buf if necessary.  */
+/* List of strings making up the mode-line.  */
+static Lisp_Object mode_line_string_list;
+
+/* Base face property when building propertized mode line string.  */
+static Lisp_Object mode_line_string_face;
+static Lisp_Object mode_line_string_face_prop;
+
+
+/* Unwind data for mode line strings */
+
+static Lisp_Object Vmode_line_unwind_vector;
+
+static Lisp_Object
+format_mode_line_unwind_data (obuf)
+     struct buffer *obuf;
+{
+  Lisp_Object vector;
+
+  /* Reduce consing by keeping one vector in
+     Vwith_echo_area_save_vector.  */
+  vector = Vmode_line_unwind_vector;
+  Vmode_line_unwind_vector = Qnil;
+
+  if (NILP (vector))
+    vector = Fmake_vector (make_number (7), Qnil);
+
+  AREF (vector, 0) = make_number (mode_line_target);
+  AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0));
+  AREF (vector, 2) = mode_line_string_list;
+  AREF (vector, 3) = mode_line_proptrans_alist;
+  AREF (vector, 4) = mode_line_string_face;
+  AREF (vector, 5) = mode_line_string_face_prop;
+
+  if (obuf)
+    XSETBUFFER (AREF (vector, 6), obuf);
+  else
+    AREF (vector, 6) = Qnil;
+
+  return vector;
+}
+
+static Lisp_Object
+unwind_format_mode_line (vector)
+     Lisp_Object vector;
+{
+  mode_line_target = XINT (AREF (vector, 0));
+  mode_line_noprop_ptr = mode_line_noprop_buf + XINT (AREF (vector, 1));
+  mode_line_string_list = AREF (vector, 2);
+  mode_line_proptrans_alist = AREF (vector, 3);
+  mode_line_string_face = AREF (vector, 4);
+  mode_line_string_face_prop = AREF (vector, 5);
+
+  if (!NILP (AREF (vector, 6)))
+    {
+      set_buffer_internal_1 (XBUFFER (AREF (vector, 6)));
+      AREF (vector, 6) = Qnil;
+    }
+
+  Vmode_line_unwind_vector = vector;
+  return Qnil;
+}
+
+
+/* Store a single character C for the frame title in mode_line_noprop_buf.
+   Re-allocate mode_line_noprop_buf if necessary.  */
 
 static void
 #ifdef PROTOTYPES
-store_frame_title_char (char c)
+store_mode_line_noprop_char (char c)
 #else
-store_frame_title_char (c)
+store_mode_line_noprop_char (c)
     char c;
 #endif
 {
   /* If output position has reached the end of the allocated buffer,
      double the buffer's size.  */
-  if (frame_title_ptr == frame_title_buf_end)
+  if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
     {
-      int len = frame_title_ptr - frame_title_buf;
-      int new_size = 2 * len * sizeof *frame_title_buf;
-      frame_title_buf = (char *) xrealloc (frame_title_buf, new_size);
-      frame_title_buf_end = frame_title_buf + new_size;
-      frame_title_ptr = frame_title_buf + len;
+      int len = MODE_LINE_NOPROP_LEN (0);
+      int new_size = 2 * len * sizeof *mode_line_noprop_buf;
+      mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
+      mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
+      mode_line_noprop_ptr = mode_line_noprop_buf + len;
     }
 
-  *frame_title_ptr++ = c;
+  *mode_line_noprop_ptr++ = c;
 }
 
 
-/* Store part of a frame title in frame_title_buf, beginning at
-   frame_title_ptr.  STR is the string to store.  Do not copy
+/* Store part of a frame title in mode_line_noprop_buf, beginning at
+   mode_line_noprop_ptr.  STR is the string to store.  Do not copy
    characters that yield more columns than PRECISION; PRECISION <= 0
    means copy the whole string.  Pad with spaces until FIELD_WIDTH
    number of characters have been copied; FIELD_WIDTH <= 0 means don't
@@ -8027,7 +8334,7 @@ store_frame_title_char (c)
    frame title.  */
 
 static int
-store_frame_title (str, field_width, precision)
+store_mode_line_noprop (str, field_width, precision)
      const unsigned char *str;
      int field_width, precision;
 {
@@ -8038,19 +8345,23 @@ store_frame_title (str, field_width, precision)
   nbytes = strlen (str);
   n += c_string_width (str, nbytes, precision, &dummy, &nbytes);
   while (nbytes--)
-    store_frame_title_char (*str++);
+    store_mode_line_noprop_char (*str++);
 
   /* Fill up with spaces until FIELD_WIDTH reached.  */
   while (field_width > 0
         && n < field_width)
     {
-      store_frame_title_char (' ');
+      store_mode_line_noprop_char (' ');
       ++n;
     }
 
   return n;
 }
 
+/***********************************************************************
+                            Frame Titles
+ ***********************************************************************/
+
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Set the title of FRAME, if it has changed.  The title format is
@@ -8070,9 +8381,11 @@ x_consider_frame_title (frame)
       /* Do we have more than one visible frame on this X display?  */
       Lisp_Object tail;
       Lisp_Object fmt;
-      struct buffer *obuf;
+      int title_start;
+      char *title;
       int len;
       struct it it;
+      int count = SPECPDL_INDEX ();
 
       for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
        {
@@ -8091,18 +8404,22 @@ x_consider_frame_title (frame)
       multiple_frames = CONSP (tail);
 
       /* Switch to the buffer of selected window of the frame.  Set up
-        frame_title_ptr so that display_mode_element will output into it;
-        then display the title.  */
-      obuf = current_buffer;
+        mode_line_target so that display_mode_element will output into
+        mode_line_noprop_buf; then display the title.  */
+      record_unwind_protect (unwind_format_mode_line,
+                            format_mode_line_unwind_data (current_buffer));
+
       set_buffer_internal_1 (XBUFFER (XWINDOW (f->selected_window)->buffer));
       fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
-      frame_title_ptr = frame_title_buf;
+
+      mode_line_target = MODE_LINE_TITLE;
+      title_start = MODE_LINE_NOPROP_LEN (0);
       init_iterator (&it, XWINDOW (f->selected_window), -1, -1,
                     NULL, DEFAULT_FACE_ID);
       display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
-      len = frame_title_ptr - frame_title_buf;
-      frame_title_ptr = NULL;
-      set_buffer_internal_1 (obuf);
+      len = MODE_LINE_NOPROP_LEN (title_start);
+      title = mode_line_noprop_buf + title_start;
+      unbind_to (count, Qnil);
 
       /* Set the title only if it's changed.  This avoids consing in
         the common case where it hasn't.  (If it turns out that we've
@@ -8111,8 +8428,8 @@ x_consider_frame_title (frame)
         higher level than this.)  */
       if (! STRINGP (f->name)
          || SBYTES (f->name) != len
-         || bcmp (frame_title_buf, SDATA (f->name), len) != 0)
-       x_implicitly_set_name (f, make_string (frame_title_buf, len), Qnil);
+         || bcmp (title, SDATA (f->name), len) != 0)
+       x_implicitly_set_name (f, make_string (title, len), Qnil);
     }
 }
 
@@ -8171,7 +8488,7 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
       int count = SPECPDL_INDEX ();
 
-      record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+      record_unwind_save_match_data ();
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -8294,7 +8611,7 @@ update_menu_bar (f, save_match_data)
 
          set_buffer_internal_1 (XBUFFER (w->buffer));
          if (save_match_data)
-           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+           record_unwind_save_match_data ();
          if (NILP (Voverriding_local_map_menu_flag))
            {
              specbind (Qoverriding_terminal_local_map, Qnil);
@@ -8485,7 +8802,7 @@ update_tool_bar (f, save_match_data)
 
          /* Save match data, if we must.  */
          if (save_match_data)
-           record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+           record_unwind_save_match_data ();
 
          /* Make sure that we don't accidentally use bogus keymaps.  */
          if (NILP (Voverriding_local_map_menu_flag))
@@ -9484,22 +9801,14 @@ redisplay ()
 
 
 static Lisp_Object
-overlay_arrow_string_or_property (var, pbitmap)
+overlay_arrow_string_or_property (var)
      Lisp_Object var;
-     int *pbitmap;
 {
-  Lisp_Object pstr = Fget (var, Qoverlay_arrow_string);
-  Lisp_Object bitmap;
+  Lisp_Object val;
 
-  if (pbitmap)
-    {
-      *pbitmap = 0;
-      if (bitmap  = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap))
-       *pbitmap = XINT (bitmap);
-    }
+  if (val = Fget (var, Qoverlay_arrow_string), STRINGP (val))
+    return val;
 
-  if (!NILP (pstr))
-    return pstr;
   return Voverlay_arrow_string;
 }
 
@@ -9549,7 +9858,7 @@ overlay_arrows_changed_p ()
        continue;
       if (! EQ (COERCE_MARKER (val),
                Fget (var, Qlast_arrow_position))
-         || ! (pstr = overlay_arrow_string_or_property (var, 0),
+         || ! (pstr = overlay_arrow_string_or_property (var),
                EQ (pstr, Fget (var, Qlast_arrow_string))))
        return 1;
     }
@@ -9579,7 +9888,7 @@ update_overlay_arrows (up_to_date)
          Fput (var, Qlast_arrow_position,
                COERCE_MARKER (val));
          Fput (var, Qlast_arrow_string,
-               overlay_arrow_string_or_property (var, 0));
+               overlay_arrow_string_or_property (var));
        }
       else if (up_to_date < 0
               || !NILP (Fget (var, Qlast_arrow_position)))
@@ -9592,14 +9901,13 @@ update_overlay_arrows (up_to_date)
 
 
 /* Return overlay arrow string to display at row.
-   Return t if display as bitmap in left fringe.
+   Return integer (bitmap number) for arrow bitmap in left fringe.
    Return nil if no overlay arrow.  */
 
 static Lisp_Object
-overlay_arrow_at_row (it, row, pbitmap)
+overlay_arrow_at_row (it, row)
      struct it *it;
      struct glyph_row *row;
-     int *pbitmap;
 {
   Lisp_Object vlist;
 
@@ -9619,17 +9927,21 @@ overlay_arrow_at_row (it, row, pbitmap)
          && current_buffer == XMARKER (val)->buffer
          && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
        {
-         val = overlay_arrow_string_or_property (var, pbitmap);
          if (FRAME_WINDOW_P (it->f)
              && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
-           return Qt;
-         if (STRINGP (val))
-           return val;
-         break;
+           {
+             if (val = Fget (var, Qoverlay_arrow_bitmap), SYMBOLP (val))
+               {
+                 int fringe_bitmap;
+                 if ((fringe_bitmap = lookup_fringe_bitmap (val)) != 0)
+                   return make_number (fringe_bitmap);
+               }
+             return make_number (-1); /* Use default arrow bitmap */
+           }
+         return overlay_arrow_string_or_property (var);
        }
     }
 
-  *pbitmap = 0;
   return Qnil;
 }
 
@@ -10201,7 +10513,9 @@ redisplay_internal (preserve_echo_area)
   CHARPOS (this_line_start_pos) = 0;
   consider_all_windows_p |= buffer_shared > 1;
   ++clear_face_cache_count;
-
+#ifdef HAVE_WINDOW_SYSTEM
+  ++clear_image_cache_count;
+#endif
 
   /* Build desired matrices, and update the display.  If
      consider_all_windows_p is non-zero, do it for all windows on all
@@ -10214,13 +10528,6 @@ redisplay_internal (preserve_echo_area)
       struct frame **updated
        = (struct frame **) alloca (size * sizeof *updated);
 
-      /* Clear the face cache eventually.  */
-      if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
-       {
-         clear_face_cache (0);
-         clear_face_cache_count = 0;
-       }
-
       /* Recompute # windows showing selected buffer.  This will be
         incremented each time such a window is displayed.  */
       buffer_shared = 0;
@@ -10236,12 +10543,6 @@ redisplay_internal (preserve_echo_area)
                   variables.  */
                select_frame_for_redisplay (frame);
 
-#ifdef HAVE_WINDOW_SYSTEM
-             if (clear_face_cache_count % 50 == 0
-                 && FRAME_WINDOW_P (f))
-               clear_image_cache (f, 0);
-#endif /* HAVE_WINDOW_SYSTEM */
-
              /* Mark all the scroll bars to be removed; we'll redeem
                 the ones we want when we redisplay their windows.  */
              if (condemn_scroll_bars_hook)
@@ -10445,6 +10746,29 @@ redisplay_internal (preserve_echo_area)
   if (windows_or_buffers_changed && !pause)
     goto retry;
 
+  /* Clear the face cache eventually.  */
+  if (consider_all_windows_p)
+    {
+      if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
+       {
+         clear_face_cache (0);
+         clear_face_cache_count = 0;
+       }
+#ifdef HAVE_WINDOW_SYSTEM
+      if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT)
+       {
+         Lisp_Object tail, frame;
+         FOR_EACH_FRAME (tail, frame)
+           {
+             struct frame *f = XFRAME (frame);
+             if (FRAME_WINDOW_P (f))
+               clear_image_cache (f, 0);
+           }
+         clear_image_cache_count = 0;
+       }
+#endif /* HAVE_WINDOW_SYSTEM */
+    }
+
  end_of_redisplay:
   unbind_to (count, Qnil);
   RESUME_POLLING;
@@ -10808,6 +11132,18 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
       glyph = cursor;
       x = cursor_x;
     }
+  else if (row->ends_in_ellipsis_p && glyph == end)
+    {
+      /* Scan back over the ellipsis glyphs, decrementing positions.  */
+      while (glyph > row->glyphs[TEXT_AREA]
+            && (glyph - 1)->charpos == last_pos)
+       glyph--, x -= glyph->pixel_width;
+      /* That loop always goes one position too far,
+        including the glyph before the ellipsis.
+        So scan forward over that one.  */
+      x += glyph->pixel_width;
+      glyph++;
+    }
   else if (string_start
           && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
     {
@@ -10930,7 +11266,7 @@ run_window_scroll_functions (window, startp)
    as if point had gone off the screen.  */
 
 static int
-make_cursor_line_fully_visible (w, force_p)
+cursor_row_fully_visible_p (w, force_p, current_matrix_p)
      struct window *w;
      int force_p;
 {
@@ -10946,7 +11282,7 @@ make_cursor_line_fully_visible (w, force_p)
   if (w->cursor.vpos < 0)
     return 1;
 
-  matrix = w->desired_matrix;
+  matrix = current_matrix_p ? w->current_matrix : w->desired_matrix;
   row = MATRIX_ROW (matrix, w->cursor.vpos);
 
   /* If the cursor row is not partially visible, there's nothing to do.  */
@@ -11251,7 +11587,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
-      if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
+      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
        {
          clear_glyph_matrix (w->desired_matrix);
          ++extra_scroll_margin_lines;
@@ -11521,6 +11857,12 @@ try_cursor_movement (window, startp, scroll_step)
                  && CHARPOS (startp) != BEGV)
                scroll_p = 1;
            }
+         else
+           {
+             /* Cursor did not move.  So don't scroll even if cursor line
+                is partially visible, as it was so before.  */
+                rc = CURSOR_MOVEMENT_SUCCESS;
+           }
 
          if (PT < MATRIX_ROW_START_CHARPOS (row)
              || PT > MATRIX_ROW_END_CHARPOS (row))
@@ -11528,7 +11870,8 @@ try_cursor_movement (window, startp, scroll_step)
              /* if PT is not in the glyph row, give up.  */
              rc = CURSOR_MOVEMENT_MUST_SCROLL;
            }
-         else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
+         else if (rc != CURSOR_MOVEMENT_SUCCESS
+                  && MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
                   && make_cursor_line_fully_visible_p)
            {
              if (PT == MATRIX_ROW_END_CHARPOS (row)
@@ -11547,7 +11890,7 @@ try_cursor_movement (window, startp, scroll_step)
              else
                {
                  set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-                 if (!make_cursor_line_fully_visible (w, 0))
+                 if (!cursor_row_fully_visible_p (w, 0, 1))
                    rc = CURSOR_MOVEMENT_MUST_SCROLL;
                  else
                    rc = CURSOR_MOVEMENT_SUCCESS;
@@ -11632,7 +11975,7 @@ redisplay_window (window, just_this_one_p)
   int temp_scroll_step = 0;
   int count = SPECPDL_INDEX ();
   int rc;
-  int centering_position;
+  int centering_position = -1;
   int last_line_misfit = 0;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
@@ -11644,9 +11987,6 @@ redisplay_window (window, just_this_one_p)
   *w->desired_matrix->method = 0;
 #endif
 
-  /* Force this to be looked up again for each redisp of each window.  */
-  escape_glyph_face = -1;
-
   specbind (Qinhibit_point_motion_hooks, Qt);
 
   reconsider_clip_changes (w, buffer);
@@ -11881,7 +12221,7 @@ redisplay_window (window, just_this_one_p)
          new_vpos = window_box_height (w) / 2;
        }
 
-      if (!make_cursor_line_fully_visible (w, 0))
+      if (!cursor_row_fully_visible_p (w, 0, 0))
        {
          /* Point does appear, but on a line partly visible at end of window.
             Move it back to a fully-visible line.  */
@@ -12018,7 +12358,7 @@ redisplay_window (window, just_this_one_p)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
 
-         if (!make_cursor_line_fully_visible (w, 1))
+         if (!cursor_row_fully_visible_p (w, 1, 0))
            {
              clear_glyph_matrix (w->desired_matrix);
              last_line_misfit = 1;
@@ -12078,10 +12418,8 @@ redisplay_window (window, just_this_one_p)
   /* Finally, just choose place to start which centers point */
 
  recenter:
-  centering_position = window_box_height (w) / 2;
-
- point_at_top:
-  /* Jump here with centering_position already set to 0.  */
+  if (centering_position < 0)
+    centering_position = window_box_height (w) / 2;
 
 #if GLYPH_DEBUG
   debug_method_add (w, "recenter");
@@ -12108,7 +12446,11 @@ redisplay_window (window, just_this_one_p)
     {
       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
       move_it_vertically_backward (&it, 0);
+#if 0
+      /* I think this assert is bogus if buffer contains
+        invisible text or images.  KFS.  */
       xassert (IT_CHARPOS (it) <= PT);
+#endif
       it.current_y = 0;
     }
 
@@ -12178,7 +12520,7 @@ redisplay_window (window, just_this_one_p)
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
-  if (!make_cursor_line_fully_visible (w, centering_position > 0))
+  if (!cursor_row_fully_visible_p (w, 0, 0))
     {
       /* If vscroll is enabled, disable it and try again.  */
       if (w->vscroll)
@@ -12191,9 +12533,12 @@ redisplay_window (window, just_this_one_p)
       /* If centering point failed to make the whole line visible,
         put point at the top instead.  That has to make the whole line
         visible, if it can be done.  */
+      if (centering_position == 0)
+       goto done;
+
       clear_glyph_matrix (w->desired_matrix);
       centering_position = 0;
-      goto point_at_top;
+      goto recenter;
     }
 
  done:
@@ -12978,8 +13323,10 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes)
         starts at a minimum position >= last_unchanged_pos_old.  */
       for (; row > first_text_row; --row)
        {
+         /* This used to abort, but it can happen.
+            It is ok to just stop the search instead here.  KFS.  */
          if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-           abort ();
+           break;
 
          if (MATRIX_ROW_START_CHARPOS (row) >= last_unchanged_pos_old)
            row_found = row;
@@ -13686,7 +14033,12 @@ try_window_id (w)
                        bottom_vpos, dy);
 
   if (first_unchanged_at_end_row)
-    first_unchanged_at_end_row += dvpos;
+    {
+      first_unchanged_at_end_row += dvpos;
+      if (first_unchanged_at_end_row->y >= it.last_visible_y
+         || !MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row))
+       first_unchanged_at_end_row = NULL;
+    }
 
   /* If scrolling up, there may be some lines to display at the end of
      the window.  */
@@ -13743,7 +14095,6 @@ try_window_id (w)
 
   /* Update window_end_pos and window_end_vpos.  */
   if (first_unchanged_at_end_row
-      && first_unchanged_at_end_row->y < it.last_visible_y
       && !last_text_row_at_end)
     {
       /* Window end line if one of the preserved rows from the current
@@ -13953,10 +14304,10 @@ dump_glyph_row (row, vpos, glyphs)
 {
   if (glyphs != 1)
     {
-      fprintf (stderr, "Row Start   End Used oEI><O\\CTZFesm     X    Y    W    H    V    A    P\n");
-      fprintf (stderr, "=======================================================================\n");
+      fprintf (stderr, "Row Start   End Used oEI><\\CTZFesm     X    Y    W    H    V    A    P\n");
+      fprintf (stderr, "======================================================================\n");
 
-      fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d%1.1d\
+      fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
 %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d  %4d %4d %4d %4d %4d %4d %4d\n",
               vpos,
               MATRIX_ROW_START_CHARPOS (row),
@@ -13966,7 +14317,6 @@ dump_glyph_row (row, vpos, glyphs)
               row->enabled_p,
               row->truncated_on_left_p,
               row->truncated_on_right_p,
-              row->overlay_arrow_p,
               row->continued_p,
               MATRIX_ROW_CONTINUATION_LINE_P (row),
               row->displays_text_p,
@@ -14609,10 +14959,22 @@ cursor_row_p (w, row)
       /* If the row ends with a newline from a string, we don't want
         the cursor there (if the row is continued it doesn't end in a
         newline).  */
-      if (CHARPOS (row->end.string_pos) >= 0
-         || MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
+      if (CHARPOS (row->end.string_pos) >= 0)
        cursor_row_p = row->continued_p;
-
+      else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
+       {
+         /* If the row ends in middle of a real character,
+            and the line is continued, we want the cursor here.
+            That's because MATRIX_ROW_END_CHARPOS would equal
+            PT if PT is before the character.  */
+         if (!row->ends_in_ellipsis_p)
+           cursor_row_p = row->continued_p;
+         else
+         /* If the row ends in an ellipsis, then
+            MATRIX_ROW_END_CHARPOS will equal point after the invisible text.
+            We want that position to be displayed after the ellipsis.  */
+           cursor_row_p = 0;
+       }
       /* If the row ends at ZV, display the cursor at the end of that
         row instead of at the start of the row below.  */
       else if (row->ends_at_zv_p)
@@ -14636,7 +14998,6 @@ display_line (it)
      struct it *it;
 {
   struct glyph_row *row = it->glyph_row;
-  int overlay_arrow_bitmap;
   Lisp_Object overlay_arrow_string;
 
   /* We always start displaying at hpos zero even if hscrolled.  */
@@ -15044,9 +15405,8 @@ display_line (it)
      mark this glyph row as the one containing the overlay arrow.
      This is clearly a mess with variable size fonts.  It would be
      better to let it be displayed like cursors under X.  */
-  if (! overlay_arrow_seen
-      && (overlay_arrow_string
-           = overlay_arrow_at_row (it, row, &overlay_arrow_bitmap),
+  if ((row->displays_text_p || !overlay_arrow_seen)
+      && (overlay_arrow_string = overlay_arrow_at_row (it, row),
          !NILP (overlay_arrow_string)))
     {
       /* Overlay arrow in window redisplay is a fringe bitmap.  */
@@ -15077,8 +15437,8 @@ display_line (it)
        }
       else
        {
-         it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
-         row->overlay_arrow_p = 1;
+         xassert (INTEGERP (overlay_arrow_string));
+         row->overlay_arrow_bitmap = XINT (overlay_arrow_string);
        }
       overlay_arrow_seen = 1;
     }
@@ -15089,6 +15449,11 @@ display_line (it)
   /* Remember the position at which this line ends.  */
   row->end = it->current;
 
+  /* Record whether this row ends inside an ellipsis.  */
+  row->ends_in_ellipsis_p
+    = (it->method == GET_FROM_DISPLAY_VECTOR
+       && it->ellipsis_p);
+
   /* Save fringe bitmaps in this row.  */
   row->left_user_fringe_bitmap = it->left_user_fringe_bitmap;
   row->left_user_fringe_face_id = it->left_user_fringe_face_id;
@@ -15359,6 +15724,7 @@ display_mode_line (w, face_id, format)
 {
   struct it it;
   struct face *face;
+  int count = SPECPDL_INDEX ();
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
   prepare_desired_row (it.glyph_row);
@@ -15369,6 +15735,11 @@ display_mode_line (w, face_id, format)
     /* Force the mode-line to be displayed in the default face.  */
     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
 
+  record_unwind_protect (unwind_format_mode_line,
+                        format_mode_line_unwind_data (NULL));
+
+  mode_line_target = MODE_LINE_DISPLAY;
+
   /* Temporarily make frame's keyboard the current kboard so that
      kboard-local variables in the mode_line_format will get the right
      values.  */
@@ -15376,6 +15747,8 @@ display_mode_line (w, face_id, format)
   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
   pop_frame_kboard ();
 
+  unbind_to (count, Qnil);
+
   /* Fill up with spaces.  */
   display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
 
@@ -15398,18 +15771,6 @@ display_mode_line (w, face_id, format)
   return it.glyph_row->height;
 }
 
-/* Alist that caches the results of :propertize.
-   Each element is (PROPERTIZED-STRING . PROPERTY-LIST).  */
-Lisp_Object mode_line_proptrans_alist;
-
-/* List of strings making up the mode-line.  */
-Lisp_Object mode_line_string_list;
-
-/* Base face property when building propertized mode line string.  */
-static Lisp_Object mode_line_string_face;
-static Lisp_Object mode_line_string_face_prop;
-
-
 /* Contribute ELT to the mode line for window IT->w.  How it
    translates into text depends on its data type.
 
@@ -15430,8 +15791,9 @@ static Lisp_Object mode_line_string_face_prop;
    If RISKY is nonzero, remove (disregard) any properties in any string
    we encounter, and ignore :eval and :propertize.
 
-   If the global variable `frame_title_ptr' is non-NULL, then the output
-   is passed to `store_frame_title' instead of `display_string'.  */
+   The global variable `mode_line_target' determines whether the
+   output is passed to `store_mode_line_noprop',
+   `store_mode_line_string', or `display_string'.  */
 
 static int
 display_mode_element (it, depth, field_width, precision, elt, props, risky)
@@ -15520,21 +15882,27 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
        if (literal)
          {
            prec = precision - n;
-           if (frame_title_ptr)
-             n += store_frame_title (SDATA (elt), -1, prec);
-           else if (!NILP (mode_line_string_list))
-             n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil);
-           else
-             n += display_string (NULL, elt, Qnil, 0, 0, it,
-                                  0, prec, 0, STRING_MULTIBYTE (elt));
+           switch (mode_line_target)
+             {
+             case MODE_LINE_NOPROP:
+             case MODE_LINE_TITLE:
+               n += store_mode_line_noprop (SDATA (elt), -1, prec);
+               break;
+             case MODE_LINE_STRING:
+               n += store_mode_line_string (NULL, elt, 1, 0, prec, Qnil);
+               break;
+             case MODE_LINE_DISPLAY:
+               n += display_string (NULL, elt, Qnil, 0, 0, it,
+                                    0, prec, 0, STRING_MULTIBYTE (elt));
+               break;
+             }
 
            break;
          }
 
        while ((precision <= 0 || n < precision)
               && *this
-              && (frame_title_ptr
-                  || !NILP (mode_line_string_list)
+              && (mode_line_target != MODE_LINE_DISPLAY
                   || it->current_x < it->last_visible_x))
          {
            const unsigned char *last = this;
@@ -15555,29 +15923,36 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                prec = c_string_width (last, this - last, precision - n,
                                       &nchars, &nbytes);
 
-               if (frame_title_ptr)
-                 n += store_frame_title (last, 0, prec);
-               else if (!NILP (mode_line_string_list))
-                 {
-                   int bytepos = last - lisp_string;
-                   int charpos = string_byte_to_char (elt, bytepos);
-                   int endpos = (precision <= 0
-                                 ? string_byte_to_char (elt,
-                                                        this - lisp_string)
-                                 : charpos + nchars);
-
-                   n += store_mode_line_string (NULL,
-                                                Fsubstring (elt, make_number (charpos),
-                                                            make_number (endpos)),
-                                                0, 0, 0, Qnil);
-                 }
-               else
+               switch (mode_line_target)
                  {
-                   int bytepos = last - lisp_string;
-                   int charpos = string_byte_to_char (elt, bytepos);
-                   n += display_string (NULL, elt, Qnil, 0, charpos,
-                                        it, 0, prec, 0,
-                                        STRING_MULTIBYTE (elt));
+                 case MODE_LINE_NOPROP:
+                 case MODE_LINE_TITLE:
+                   n += store_mode_line_noprop (last, 0, prec);
+                   break;
+                 case MODE_LINE_STRING:
+                   {
+                     int bytepos = last - lisp_string;
+                     int charpos = string_byte_to_char (elt, bytepos);
+                     int endpos = (precision <= 0
+                                   ? string_byte_to_char (elt,
+                                                          this - lisp_string)
+                                   : charpos + nchars);
+
+                     n += store_mode_line_string (NULL,
+                                                  Fsubstring (elt, make_number (charpos),
+                                                              make_number (endpos)),
+                                                  0, 0, 0, Qnil);
+                   }
+                   break;
+                 case MODE_LINE_DISPLAY:
+                   {
+                     int bytepos = last - lisp_string;
+                     int charpos = string_byte_to_char (elt, bytepos);
+                     n += display_string (NULL, elt, Qnil, 0, charpos,
+                                          it, 0, prec, 0,
+                                          STRING_MULTIBYTE (elt));
+                   }
+                   break;
                  }
              }
            else /* c == '%' */
@@ -15615,44 +15990,51 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                    spec
                      = decode_mode_spec (it->w, c, field, prec, &multibyte);
 
-                   if (frame_title_ptr)
-                     n += store_frame_title (spec, field, prec);
-                   else if (!NILP (mode_line_string_list))
+                   switch (mode_line_target)
                      {
-                       int len = strlen (spec);
-                       Lisp_Object tem = make_string (spec, len);
-                       props = Ftext_properties_at (make_number (charpos), elt);
-                       /* Should only keep face property in props */
-                       n += store_mode_line_string (NULL, tem, 0, field, prec, props);
-                     }
-                   else
-                     {
-                       int nglyphs_before, nwritten;
-
-                       nglyphs_before = it->glyph_row->used[TEXT_AREA];
-                       nwritten = display_string (spec, Qnil, elt,
-                                                  charpos, 0, it,
-                                                  field, prec, 0,
-                                                  multibyte);
-
-                       /* Assign to the glyphs written above the
-                          string where the `%x' came from, position
-                          of the `%'.  */
-                       if (nwritten > 0)
-                         {
-                           struct glyph *glyph
-                             = (it->glyph_row->glyphs[TEXT_AREA]
-                                + nglyphs_before);
-                           int i;
-
-                           for (i = 0; i < nwritten; ++i)
-                             {
-                               glyph[i].object = elt;
-                               glyph[i].charpos = charpos;
-                             }
-
-                           n += nwritten;
-                         }
+                     case MODE_LINE_NOPROP:
+                     case MODE_LINE_TITLE:
+                       n += store_mode_line_noprop (spec, field, prec);
+                       break;
+                     case MODE_LINE_STRING:
+                       {
+                         int len = strlen (spec);
+                         Lisp_Object tem = make_string (spec, len);
+                         props = Ftext_properties_at (make_number (charpos), elt);
+                         /* Should only keep face property in props */
+                         n += store_mode_line_string (NULL, tem, 0, field, prec, props);
+                       }
+                       break;
+                     case MODE_LINE_DISPLAY:
+                       {
+                         int nglyphs_before, nwritten;
+
+                         nglyphs_before = it->glyph_row->used[TEXT_AREA];
+                         nwritten = display_string (spec, Qnil, elt,
+                                                    charpos, 0, it,
+                                                    field, prec, 0,
+                                                    multibyte);
+
+                         /* Assign to the glyphs written above the
+                            string where the `%x' came from, position
+                            of the `%'.  */
+                         if (nwritten > 0)
+                           {
+                             struct glyph *glyph
+                               = (it->glyph_row->glyphs[TEXT_AREA]
+                                  + nglyphs_before);
+                             int i;
+
+                             for (i = 0; i < nwritten; ++i)
+                               {
+                                 glyph[i].object = elt;
+                                 glyph[i].charpos = charpos;
+                               }
+
+                             n += nwritten;
+                           }
+                       }
+                       break;
                      }
                  }
                else /* c == 0 */
@@ -15800,7 +16182,12 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                   && --limit > 0
                   && (precision <= 0 || n < precision))
              {
-               n += display_mode_element (it, depth, field_width - n,
+               n += display_mode_element (it, depth,
+                                          /* Do padding only after the last
+                                             element in the list.  */
+                                          (! CONSP (XCDR (elt))
+                                           ? field_width - n
+                                           : 0),
                                           precision - n, XCAR (elt),
                                           props, risky);
                elt = XCDR (elt);
@@ -15818,13 +16205,20 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
   /* Pad to FIELD_WIDTH.  */
   if (field_width > 0 && n < field_width)
     {
-      if (frame_title_ptr)
-       n += store_frame_title ("", field_width - n, 0);
-      else if (!NILP (mode_line_string_list))
-       n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil);
-      else
-       n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
-                            0, 0, 0);
+      switch (mode_line_target)
+       {
+       case MODE_LINE_NOPROP:
+       case MODE_LINE_TITLE:
+         n += store_mode_line_noprop ("", field_width - n, 0);
+         break;
+       case MODE_LINE_STRING:
+         n += store_mode_line_string ("", Qnil, 0, field_width - n, 0, Qnil);
+         break;
+       case MODE_LINE_DISPLAY:
+         n += display_string ("", Qnil, Qnil, 0, 0, it, field_width - n,
+                              0, 0, 0);
+         break;
+       }
     }
 
   return n;
@@ -15871,7 +16265,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
        props = mode_line_string_face_prop;
       else if (!NILP (mode_line_string_face))
        {
-         Lisp_Object face = Fsafe_plist_get (props, Qface);
+         Lisp_Object face = Fplist_get (props, Qface);
          props = Fcopy_sequence (props);
          if (NILP (face))
            face = mode_line_string_face;
@@ -15896,7 +16290,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
          Lisp_Object face;
          if (NILP (props))
            props = Ftext_properties_at (make_number (0), lisp_string);
-         face = Fsafe_plist_get (props, Qface);
+         face = Fplist_get (props, Qface);
          if (NILP (face))
            face = mode_line_string_face;
          else
@@ -15932,22 +16326,33 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
 
 
 DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
-       0, 4, 0,
-       doc: /* Return the mode-line of selected window as a string.
-First optional arg FORMAT specifies a different format string (see
-`mode-line-format' for details) to use.  If FORMAT is t, return
-the buffer's header-line.  Second optional arg WINDOW specifies a
-different window to use as the context for the formatting.
-If third optional arg NO-PROPS is non-nil, string is not propertized.
-Fourth optional arg BUFFER specifies which buffer to use.  */)
-  (format, window, no_props, buffer)
-     Lisp_Object format, window, no_props, buffer;
+       1, 4, 0,
+       doc: /* Format a string out of a mode line format specification.
+First arg FORMAT specifies the mode line format (see `mode-line-format'
+for details) to use.
+
+Optional second arg FACE specifies the face property to put
+on all characters for which no face is specified.
+t means whatever face the window's mode line currently uses
+\(either `mode-line' or `mode-line-inactive', depending).
+nil means the default is no face property.
+If FACE is an integer, the value string has no text properties.
+
+Optional third and fourth args WINDOW and BUFFER specify the window
+and buffer to use as the context for the formatting (defaults
+are the selected window and the window's buffer).  */)
+  (format, face, window, buffer)
+     Lisp_Object format, face, window, buffer;
 {
   struct it it;
   int len;
   struct window *w;
   struct buffer *old_buffer = NULL;
-  enum face_id face_id = DEFAULT_FACE_ID;
+  int face_id = -1;
+  int no_props = INTEGERP (face);
+  int count = SPECPDL_INDEX ();
+  Lisp_Object str;
+  int string_start = 0;
 
   if (NILP (window))
     window = selected_window;
@@ -15956,83 +16361,69 @@ Fourth optional arg BUFFER specifies which buffer to use.  */)
 
   if (NILP (buffer))
     buffer = w->buffer;
-
   CHECK_BUFFER (buffer);
 
-  if (XBUFFER (buffer) != current_buffer)
-    {
-      old_buffer = current_buffer;
-      set_buffer_internal_1 (XBUFFER (buffer));
-    }
+  if (NILP (format))
+    return build_string ("");
 
-  if (NILP (format) || EQ (format, Qt))
+  if (no_props)
+    face = Qnil;
+
+  if (!NILP (face))
     {
-      face_id = (NILP (format)
-                ? CURRENT_MODE_LINE_FACE_ID (w)
-                : HEADER_LINE_FACE_ID);
-      format = (NILP (format)
-               ? current_buffer->mode_line_format
-               : current_buffer->header_line_format);
+      if (EQ (face, Qt))
+       face = (EQ (window, selected_window) ? Qmode_line : Qmode_line_inactive);
+      face_id = lookup_named_face (XFRAME (WINDOW_FRAME (w)), face, 0, 0);
     }
 
-  init_iterator (&it, w, -1, -1, NULL, face_id);
+  if (face_id < 0)
+    face_id = DEFAULT_FACE_ID;
 
-  if (NILP (no_props))
-    {
-      mode_line_string_face
-       = (face_id == MODE_LINE_FACE_ID ? Qmode_line
-          : face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive
-          : face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
+  if (XBUFFER (buffer) != current_buffer)
+    old_buffer = current_buffer;
 
-      mode_line_string_face_prop
-       = (NILP (mode_line_string_face) ? Qnil
-          : Fcons (Qface, Fcons (mode_line_string_face, Qnil)));
+  record_unwind_protect (unwind_format_mode_line,
+                        format_mode_line_unwind_data (old_buffer));
+
+  if (old_buffer)
+    set_buffer_internal_1 (XBUFFER (buffer));
 
-      /* We need a dummy last element in mode_line_string_list to
-        indicate we are building the propertized mode-line string.
-        Using mode_line_string_face_prop here GC protects it.  */
-      mode_line_string_list
-       = Fcons (mode_line_string_face_prop, Qnil);
-      frame_title_ptr = NULL;
+  init_iterator (&it, w, -1, -1, NULL, face_id);
+
+  if (no_props)
+    {
+      mode_line_target = MODE_LINE_NOPROP;
+      mode_line_string_face_prop = Qnil;
+      mode_line_string_list = Qnil;
+      string_start = MODE_LINE_NOPROP_LEN (0);
     }
   else
     {
-      mode_line_string_face_prop = Qnil;
+      mode_line_target = MODE_LINE_STRING;
       mode_line_string_list = Qnil;
-      frame_title_ptr = frame_title_buf;
+      mode_line_string_face = face;
+      mode_line_string_face_prop
+       = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
     }
 
   push_frame_kboard (it.f);
   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
   pop_frame_kboard ();
 
-  if (old_buffer)
-    set_buffer_internal_1 (old_buffer);
-
-  if (NILP (no_props))
+  if (no_props)
     {
-      Lisp_Object str;
-      mode_line_string_list = Fnreverse (mode_line_string_list);
-      str = Fmapconcat (intern ("identity"), XCDR (mode_line_string_list),
-                       make_string ("", 0));
-      mode_line_string_face_prop = Qnil;
-      mode_line_string_list = Qnil;
-      return str;
+      len = MODE_LINE_NOPROP_LEN (string_start);
+      str = make_string (mode_line_noprop_buf + string_start, len);
     }
-
-  len = frame_title_ptr - frame_title_buf;
-  if (len > 0 && frame_title_ptr[-1] == '-')
+  else
     {
-      /* Mode lines typically ends with numerous dashes; reduce to two dashes.  */
-      while (frame_title_ptr > frame_title_buf && *--frame_title_ptr == '-')
-       ;
-      frame_title_ptr += 3;  /* restore last non-dash + two dashes */
-      if (len > frame_title_ptr - frame_title_buf)
-       len = frame_title_ptr - frame_title_buf;
+      mode_line_string_list = Fnreverse (mode_line_string_list);
+      str = Fmapconcat (intern ("identity"), mode_line_string_list,
+                       make_string ("", 0));
     }
 
-  frame_title_ptr = NULL;
-  return make_string (frame_title_buf, len);
+  unbind_to (count, Qnil);
+  return str;
 }
 
 /* Write a null-terminated, right justified decimal representation of
@@ -16350,7 +16741,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
        register int i;
 
        /* Let lots_of_dashes be a string of infinite length.  */
-       if (!NILP (mode_line_string_list))
+       if (mode_line_target == MODE_LINE_NOPROP ||
+           mode_line_target == MODE_LINE_STRING)
          return "--";
        if (field_width <= 0
            || field_width > sizeof (lots_of_dashes))
@@ -18166,6 +18558,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
 {
   struct glyph_string *head, *tail;
   struct glyph_string *s;
+  struct glyph_string *clip_head = NULL, *clip_tail = NULL;
   int last_x, area_width;
   int x_reached;
   int i, j;
@@ -18234,6 +18627,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
          start = i;
          compute_overhangs_and_x (t, head->x, 1);
          prepend_glyph_string_lists (&head, &tail, h, t);
+         clip_head = head;
        }
 
       /* Prepend glyph strings for glyphs in front of the first glyph
@@ -18246,6 +18640,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
       i = left_overwriting (head);
       if (i >= 0)
        {
+         clip_head = head;
          BUILD_GLYPH_STRINGS (i, start, h, t,
                               DRAW_NORMAL_TEXT, dummy_x, last_x);
          for (s = h; s; s = s->next)
@@ -18265,6 +18660,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
                               DRAW_NORMAL_TEXT, x, last_x);
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
+         clip_tail = tail;
        }
 
       /* Append glyph strings for glyphs following the last glyph
@@ -18275,6 +18671,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
       i = right_overwriting (tail);
       if (i >= 0)
        {
+         clip_tail = tail;
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               DRAW_NORMAL_TEXT, x, last_x);
          for (s = h; s; s = s->next)
@@ -18282,6 +18679,12 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
        }
+      if (clip_head || clip_tail)
+       for (s = head; s; s = s->next)
+         {
+           s->clip_head = clip_head;
+           s->clip_tail = clip_tail;
+         }
     }
 
   /* Draw all strings.  */
@@ -18295,8 +18698,9 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
         completely. */
       && !overlaps_p)
     {
-      int x0 = head ? head->x : x;
-      int x1 = tail ? tail->x + tail->background_width : x;
+      int x0 = clip_head ? clip_head->x : (head ? head->x : x);
+      int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
+               : (tail ? tail->x + tail->background_width : x));
 
       int text_left = window_box_left (w, TEXT_AREA);
       x0 -= text_left;
@@ -18679,14 +19083,14 @@ produce_stretch_glyph (it)
   plist = XCDR (it->object);
 
   /* Compute the width of the stretch.  */
-  if ((prop = Fsafe_plist_get (plist, QCwidth), !NILP (prop))
+  if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
       && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
     {
       /* Absolute width `:width WIDTH' specified and valid.  */
       zero_width_ok_p = 1;
       width = (int)tem;
     }
-  else if (prop = Fsafe_plist_get (plist, QCrelative_width),
+  else if (prop = Fplist_get (plist, QCrelative_width),
           NUMVAL (prop) > 0)
     {
       /* Relative width `:relative-width FACTOR' specified and valid.
@@ -18710,7 +19114,7 @@ produce_stretch_glyph (it)
       x_produce_glyphs (&it2);
       width = NUMVAL (prop) * it2.pixel_width;
     }
-  else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop))
+  else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
           && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
     {
       if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
@@ -18730,13 +19134,13 @@ produce_stretch_glyph (it)
     width = 1;
 
   /* Compute height.  */
-  if ((prop = Fsafe_plist_get (plist, QCheight), !NILP (prop))
+  if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
       && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
     {
       height = (int)tem;
       zero_height_ok_p = 1;
     }
-  else if (prop = Fsafe_plist_get (plist, QCrelative_height),
+  else if (prop = Fplist_get (plist, QCrelative_height),
           NUMVAL (prop) > 0)
     height = FONT_HEIGHT (font) * NUMVAL (prop);
   else
@@ -18748,7 +19152,7 @@ produce_stretch_glyph (it)
   /* Compute percentage of height used for ascent.  If
      `:ascent ASCENT' is present and valid, use that.  Otherwise,
      derive the ascent from the font in use.  */
-  if (prop = Fsafe_plist_get (plist, QCascent),
+  if (prop = Fplist_get (plist, QCascent),
       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
     ascent = height * NUMVAL (prop) / 100.0;
   else if (!NILP (prop)
@@ -18787,24 +19191,16 @@ produce_stretch_glyph (it)
   take_vertical_position_into_account (it);
 }
 
-/* Calculate line-height and line-spacing properties.
-   An integer value specifies explicit pixel value.
-   A float value specifies relative value to current face height.
-   A cons (float . face-name) specifies relative value to
-   height of specified face font.
-
-   Returns height in pixels, or nil.  */
+/* Get line-height and line-spacing property at point.
+   If line-height has format (HEIGHT TOTAL), return TOTAL
+   in TOTAL_HEIGHT.  */
 
 static Lisp_Object
-calc_line_height_property (it, prop, font, boff, total)
+get_line_height_property (it, prop)
      struct it *it;
      Lisp_Object prop;
-     XFontStruct *font;
-     int boff, *total;
 {
-  Lisp_Object position, val;
-  Lisp_Object face_name = Qnil;
-  int ascent, descent, height, override;
+  Lisp_Object position;
 
   if (STRINGP (it->object))
     position = make_number (IT_STRING_CHARPOS (*it));
@@ -18813,33 +19209,44 @@ calc_line_height_property (it, prop, font, boff, total)
   else
     return Qnil;
 
-  val = Fget_char_property (position, prop, it->object);
+  return Fget_char_property (position, prop, it->object);
+}
 
-  if (NILP (val))
-    return val;
+/* Calculate line-height and line-spacing properties.
+   An integer value specifies explicit pixel value.
+   A float value specifies relative value to current face height.
+   A cons (float . face-name) specifies relative value to
+   height of specified face font.
 
-  if (total && CONSP (val) && EQ (XCAR (val), Qtotal))
-    {
-      *total = 1;
-      val = XCDR (val);
-    }
+   Returns height in pixels, or nil.  */
+
+
+static Lisp_Object
+calc_line_height_property (it, val, font, boff, override)
+     struct it *it;
+     Lisp_Object val;
+     XFontStruct *font;
+     int boff, override;
+{
+  Lisp_Object face_name = Qnil;
+  int ascent, descent, height;
 
-  if (INTEGERP (val))
+  if (NILP (val) || INTEGERP (val) || (override && EQ (val, Qt)))
     return val;
 
   if (CONSP (val))
     {
-      face_name = XCDR (val);
-      val = XCAR (val);
-    }
-  else if (SYMBOLP (val))
-    {
-      face_name = val;
-      val = Qnil;
+      face_name = XCAR (val);
+      val = XCDR (val);
+      if (!NUMBERP (val))
+       val = make_number (1);
+      if (NILP (face_name))
+       {
+         height = it->ascent + it->descent;
+         goto scale;
+       }
     }
 
-  override = EQ (prop, Qline_height);
-
   if (NILP (face_name))
     {
       font = FRAME_FONT (it->f);
@@ -18881,6 +19288,8 @@ calc_line_height_property (it, prop, font, boff, total)
     }
 
   height = ascent + descent;
+
+ scale:
   if (FLOATP (val))
     height = (int)(XFLOAT_DATA (val) * height);
   else if (INTEGERP (val))
@@ -19093,12 +19502,22 @@ x_produce_glyphs (it)
             increase that height */
 
          Lisp_Object height;
+         Lisp_Object total_height = Qnil;
 
          it->override_ascent = -1;
          it->pixel_width = 0;
          it->nglyphs = 0;
 
-         height = calc_line_height_property(it, Qline_height, font, boff, 0);
+         height = get_line_height_property(it, Qline_height);
+         /* Split (line-height total-height) list */
+         if (CONSP (height)
+             && CONSP (XCDR (height))
+             && NILP (XCDR (XCDR (height))))
+           {
+             total_height = XCAR (XCDR (height));
+             height = XCAR (height);
+           }
+         height = calc_line_height_property(it, height, font, boff, 1);
 
          if (it->override_ascent >= 0)
            {
@@ -19112,7 +19531,7 @@ x_produce_glyphs (it)
              it->descent = FONT_DESCENT (font) - boff;
            }
 
-         if (EQ (height, make_number(0)))
+         if (EQ (height, Qt))
            {
              if (it->descent > it->max_descent)
                {
@@ -19132,7 +19551,6 @@ x_produce_glyphs (it)
          else
            {
              Lisp_Object spacing;
-             int total = 0;
 
              it->phys_ascent = it->ascent;
              it->phys_descent = it->descent;
@@ -19148,25 +19566,31 @@ x_produce_glyphs (it)
                  && XINT (height) > it->ascent + it->descent)
                it->ascent = XINT (height) - it->descent;
 
-             spacing = calc_line_height_property(it, Qline_spacing, font, boff, &total);
+             if (!NILP (total_height))
+               spacing = calc_line_height_property(it, total_height, font, boff, 0);
+             else
+               {
+                 spacing = get_line_height_property(it, Qline_spacing);
+                 spacing = calc_line_height_property(it, spacing, font, boff, 0);
+               }
              if (INTEGERP (spacing))
                {
                  extra_line_spacing = XINT (spacing);
-                 if (total)
+                 if (!NILP (total_height))
                    extra_line_spacing -= (it->phys_ascent + it->phys_descent);
                }
            }
        }
       else if (it->char_to_display == '\t')
        {
-         int tab_width = it->tab_width * FRAME_COLUMN_WIDTH (it->f);
+         int tab_width = it->tab_width * FRAME_SPACE_WIDTH (it->f);
          int x = it->current_x + it->continuation_lines_width;
          int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
 
          /* If the distance from the current position to the next tab
-            stop is less than a canonical character width, use the
+            stop is less than a space character width, use the
             tab stop after that.  */
-         if (next_tab_x - x < FRAME_COLUMN_WIDTH (it->f))
+         if (next_tab_x - x < FRAME_SPACE_WIDTH (it->f))
            next_tab_x += tab_width;
 
          it->pixel_width = next_tab_x - x;
@@ -19868,7 +20292,7 @@ get_window_cursor_type (w, glyph, width, active_cursor)
   /* Use cursor-in-non-selected-windows for non-selected window or frame.  */
   if (non_selected)
     {
-      alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, w->buffer);
+      alt_cursor = XBUFFER (w->buffer)->cursor_in_non_selected_windows;
       return get_specified_cursor_type (alt_cursor, width);
     }
 
@@ -19952,8 +20376,10 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1)
   if (area != TEXT_AREA)
     return;
 
-  row = w->current_matrix->rows + w->phys_cursor.vpos;
-  if (!row->displays_text_p)
+  if (w->phys_cursor.vpos < 0
+      || w->phys_cursor.vpos >= w->current_matrix->nrows
+      || (row = w->current_matrix->rows + w->phys_cursor.vpos,
+         !(row->enabled_p && row->displays_text_p)))
     return;
 
   if (row->cursor_in_fringe_p)
@@ -20527,6 +20953,30 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
       past_end = 1;
     }
 
+  /* If whole rows or last part of a row came from a display overlay,
+     row_containing_pos will skip over such rows because their end pos
+     equals the start pos of the overlay or interval.
+
+     Move back if we have a STOP object and previous row's
+     end glyph came from STOP.  */
+  if (!NILP (stop))
+    {
+      struct glyph_row *prev;
+      while ((prev = row - 1, prev >= first)
+            && MATRIX_ROW_END_CHARPOS (prev) == charpos
+            && prev->used[TEXT_AREA] > 0)
+       {
+         struct glyph *beg = prev->glyphs[TEXT_AREA];
+         glyph = beg + prev->used[TEXT_AREA];
+         while (--glyph >= beg
+                && INTEGERP (glyph->object));
+         if (glyph < beg
+             || !EQ (stop, glyph->object))
+           break;
+         row = prev;
+       }
+    }
+
   *x = row->x;
   *y = row->y;
   *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
@@ -20931,11 +21381,12 @@ define_frame_cursor1 (f, cursor, pointer)
    position relative to the start of the mode line.  */
 
 static void
-note_mode_line_or_margin_highlight (w, x, y, area)
-     struct window *w;
+note_mode_line_or_margin_highlight (window, x, y, area)
+     Lisp_Object window;
      int x, y;
      enum window_part area;
 {
+  struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
   Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
@@ -20944,9 +21395,38 @@ note_mode_line_or_margin_highlight (w, x, y, area)
   Lisp_Object string, object = Qnil;
   Lisp_Object pos, help;
 
+  Lisp_Object mouse_face;
+  int original_x_pixel = x;
+  struct glyph * glyph = NULL;
+  struct glyph_row *row;
+
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
-    string = mode_line_string (w, area, &x, &y, &charpos,
-                              &object, &dx, &dy, &width, &height);
+    {
+      int x0;
+      struct glyph *end;
+
+      string = mode_line_string (w, area, &x, &y, &charpos,
+                                &object, &dx, &dy, &width, &height);
+
+      row = (area == ON_MODE_LINE
+            ? MATRIX_MODE_LINE_ROW (w->current_matrix)
+            : MATRIX_HEADER_LINE_ROW (w->current_matrix));
+
+      /* Find glyph */
+      if (row->mode_line_p && row->enabled_p)
+       {
+         glyph = row->glyphs[TEXT_AREA];
+         end = glyph + row->used[TEXT_AREA];
+
+         for (x0 = original_x_pixel;
+              glyph < end && x0 >= glyph->pixel_width;
+              ++glyph)
+           x0 -= glyph->pixel_width;
+
+         if (glyph >= end)
+           glyph = NULL;
+       }
+    }
   else
     {
       x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
@@ -20959,7 +21439,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
   if (IMAGEP (object))
     {
       Lisp_Object image_map, hotspot;
-      if ((image_map = Fsafe_plist_get (XCDR (object), QCmap),
+      if ((image_map = Fplist_get (XCDR (object), QCmap),
           !NILP (image_map))
          && (hotspot = find_hot_spot (image_map, dx, dy),
              CONSP (hotspot))
@@ -20975,10 +21455,10 @@ note_mode_line_or_margin_highlight (w, x, y, area)
          if (CONSP (hotspot)
              && (plist = XCAR (hotspot), CONSP (plist)))
            {
-             pointer = Fsafe_plist_get (plist, Qpointer);
+             pointer = Fplist_get (plist, Qpointer);
              if (NILP (pointer))
                pointer = Qhand;
-             help = Fsafe_plist_get (plist, Qhelp_echo);
+             help = Fplist_get (plist, Qhelp_echo);
              if (!NILP (help))
                {
                  help_echo_string = help;
@@ -20988,9 +21468,9 @@ note_mode_line_or_margin_highlight (w, x, y, area)
                  help_echo_pos = charpos;
                }
            }
-         if (NILP (pointer))
-           pointer = Fsafe_plist_get (XCDR (object), QCpointer);
        }
+      if (NILP (pointer))
+       pointer = Fplist_get (XCDR (object), QCpointer);
     }
 
   if (STRINGP (string))
@@ -21024,8 +21504,110 @@ note_mode_line_or_margin_highlight (w, x, y, area)
          if (!KEYMAPP (map))
            cursor = dpyinfo->vertical_scroll_bar_cursor;
        }
-    }
 
+     /* Change the mouse face according to what is under X/Y.  */
+      mouse_face = Fget_text_property (pos, Qmouse_face, string);
+      if (!NILP (mouse_face)
+         && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
+         && glyph)
+       {
+         Lisp_Object b, e;
+
+         struct glyph * tmp_glyph;
+
+         int gpos;
+         int gseq_length;
+         int total_pixel_width;
+         int ignore;
+
+         int vpos, hpos;
+
+         b = Fprevious_single_property_change (make_number (charpos + 1),
+                                               Qmouse_face, string, Qnil);
+         if (NILP (b))
+           b = make_number (0);
+
+         e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil);
+         if (NILP (e))
+           e = make_number (SCHARS (string));
+
+         /* Calculate the position(glyph position: GPOS) of GLYPH in
+            displayed string. GPOS is different from CHARPOS.
+
+            CHARPOS is the position of glyph in internal string
+            object. A mode line string format has structures which
+            is converted to a flatten by emacs lisp interpreter.
+            The internal string is an element of the structures.
+            The displayed string is the flatten string. */
+         for (tmp_glyph = glyph - 1, gpos = 0;
+              tmp_glyph->charpos >= XINT (b);
+              tmp_glyph--, gpos++)
+           {
+             if (!EQ (tmp_glyph->object, glyph->object))
+               break;
+           }
+
+         /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of
+            displayed string holding GLYPH.
+
+            GSEQ_LENGTH is different from SCHARS (STRING).
+            SCHARS (STRING) returns the length of the internal string. */
+         for (tmp_glyph = glyph, gseq_length = gpos;
+              tmp_glyph->charpos < XINT (e);
+              tmp_glyph++, gseq_length++)
+             {
+               if (!EQ (tmp_glyph->object, glyph->object))
+                 break;
+             }
+
+         total_pixel_width = 0;
+         for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++)
+           total_pixel_width += tmp_glyph->pixel_width;
+
+         /* Pre calculation of re-rendering position */
+         vpos = (x - gpos);
+         hpos = (area == ON_MODE_LINE
+                 ? (w->current_matrix)->nrows - 1
+                 : 0);
+
+         /* If the re-rendering position is included in the last
+            re-rendering area, we should do nothing. */
+         if ( EQ (window, dpyinfo->mouse_face_window)
+              && dpyinfo->mouse_face_beg_col <= vpos
+              && vpos < dpyinfo->mouse_face_end_col
+              && dpyinfo->mouse_face_beg_row == hpos )
+           return;
+
+         if (clear_mouse_face (dpyinfo))
+           cursor = No_Cursor;
+
+         dpyinfo->mouse_face_beg_col = vpos;
+         dpyinfo->mouse_face_beg_row = hpos;
+
+         dpyinfo->mouse_face_beg_x   = original_x_pixel - (total_pixel_width + dx);
+         dpyinfo->mouse_face_beg_y   = 0;
+
+         dpyinfo->mouse_face_end_col = vpos + gseq_length;
+         dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row;
+
+         dpyinfo->mouse_face_end_x   = 0;
+         dpyinfo->mouse_face_end_y   = 0;
+
+         dpyinfo->mouse_face_past_end = 0;
+         dpyinfo->mouse_face_window  = window;
+
+         dpyinfo->mouse_face_face_id = face_at_string_position (w, string,
+                                                                charpos,
+                                                                0, 0, 0, &ignore,
+                                                                glyph->face_id, 1);
+         show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+
+         if (NILP (pointer))
+           pointer = Qhand;
+       }
+      else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
+       clear_mouse_face (dpyinfo);
+    }
   define_frame_cursor1 (f, cursor, pointer);
 }
 
@@ -21078,7 +21660,8 @@ note_mouse_highlight (f, x, y)
   /* If we were displaying active text in another window, clear that.
      Also clear if we move out of text area in same window.  */
   if (! EQ (window, dpyinfo->mouse_face_window)
-      || (part != ON_TEXT && !NILP (dpyinfo->mouse_face_window)))
+      || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE 
+         && !NILP (dpyinfo->mouse_face_window)))
     clear_mouse_face (dpyinfo);
 
   /* Not on a window -> return.  */
@@ -21104,7 +21687,7 @@ note_mouse_highlight (f, x, y)
   if (part == ON_MODE_LINE || part == ON_HEADER_LINE
       || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
     {
-      note_mode_line_or_margin_highlight (w, x, y, part);
+      note_mode_line_or_margin_highlight (window, x, y, part);
       return;
     }
 
@@ -21143,7 +21726,7 @@ note_mouse_highlight (f, x, y)
          if (img != NULL && IMAGEP (img->spec))
            {
              Lisp_Object image_map, hotspot;
-             if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap),
+             if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
                   !NILP (image_map))
                  && (hotspot = find_hot_spot (image_map,
                                               glyph->slice.x + dx,
@@ -21161,10 +21744,10 @@ note_mouse_highlight (f, x, y)
                  if (CONSP (hotspot)
                      && (plist = XCAR (hotspot), CONSP (plist)))
                    {
-                     pointer = Fsafe_plist_get (plist, Qpointer);
+                     pointer = Fplist_get (plist, Qpointer);
                      if (NILP (pointer))
                        pointer = Qhand;
-                     help_echo_string = Fsafe_plist_get (plist, Qhelp_echo);
+                     help_echo_string = Fplist_get (plist, Qhelp_echo);
                      if (!NILP (help_echo_string))
                        {
                          help_echo_window = window;
@@ -21174,7 +21757,7 @@ note_mouse_highlight (f, x, y)
                    }
                }
              if (NILP (pointer))
-               pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer);
+               pointer = Fplist_get (XCDR (img->spec), QCpointer);
            }
        }
 
@@ -21364,6 +21947,7 @@ note_mouse_highlight (f, x, y)
                b = make_number (0);
              if (NILP (e))
                e = make_number (SCHARS (object) - 1);
+
              fast_find_string_pos (w, XINT (b), object,
                                    &dpyinfo->mouse_face_beg_col,
                                    &dpyinfo->mouse_face_beg_row,
@@ -21868,7 +22452,9 @@ expose_window (w, fr)
              || (r.y >= y0 && r.y < y1)
              || (r.y + r.height > y0 && r.y + r.height < y1))
            {
-             if (row->overlapping_p)
+             /* A header line may be overlapping, but there is no need
+                to fix overlapping areas for them.  KFS 2005-02-12 */
+             if (row->overlapping_p && !row->mode_line_p)
                {
                  if (first_overlapping_row == NULL)
                    first_overlapping_row = row;
@@ -22170,8 +22756,6 @@ syms_of_xdisp ()
   staticpro (&Qcenter);
   Qline_height = intern ("line-height");
   staticpro (&Qline_height);
-  Qtotal = intern ("total");
-  staticpro (&Qtotal);
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
   QCrelative_width = intern (":relative-width");
@@ -22192,6 +22776,8 @@ syms_of_xdisp ()
   staticpro (&Qtrailing_whitespace);
   Qescape_glyph = intern ("escape-glyph");
   staticpro (&Qescape_glyph);
+  Qnobreak_space = intern ("nobreak-space");
+  staticpro (&Qnobreak_space);
   Qimage = intern ("image");
   staticpro (&Qimage);
   QCmap = intern (":map");
@@ -22206,8 +22792,6 @@ syms_of_xdisp ()
   staticpro (&Qpoly);
   Qmessage_truncate_lines = intern ("message-truncate-lines");
   staticpro (&Qmessage_truncate_lines);
-  Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows");
-  staticpro (&Qcursor_in_non_selected_windows);
   Qgrow_only = intern ("grow-only");
   staticpro (&Qgrow_only);
   Qinhibit_menubar_update = intern ("inhibit-menubar-update");
@@ -22267,9 +22851,14 @@ syms_of_xdisp ()
 
   mode_line_proptrans_alist = Qnil;
   staticpro (&mode_line_proptrans_alist);
-
   mode_line_string_list = Qnil;
   staticpro (&mode_line_string_list);
+  mode_line_string_face = Qnil;
+  staticpro (&mode_line_string_face);
+  mode_line_string_face_prop = Qnil;
+  staticpro (&mode_line_string_face_prop);
+  Vmode_line_unwind_vector = Qnil;
+  staticpro (&Vmode_line_unwind_vector);
 
   help_echo_string = Qnil;
   staticpro (&help_echo_string);
@@ -22294,6 +22883,15 @@ wide as that tab on the display.  */);
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
+  DEFVAR_LISP ("nobreak-char-display", &Vnobreak_char_display,
+    doc: /* *Control highlighting of nobreak space and soft hyphen.
+t means highlight the character itself (for nobreak space,
+use face `nobreak-space'.
+nil means no highlighting.
+other values mean display the escape glyph followed by an ordinary
+space or ordinary hyphen.  */);
+  Vnobreak_char_display = Qt;
+
   DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
     doc: /* *The pointer shape to show in void text areas.
 Nil means to show the text pointer.  Other options are `arrow', `text',
@@ -22318,7 +22916,7 @@ See also `overlay-arrow-string'.  */);
   DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = Qnil;
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -22497,12 +23095,6 @@ only, until their display becomes empty, at which point the windows
 go back to their normal size.  */);
   Vresize_mini_windows = Qgrow_only;
 
-  DEFVAR_LISP ("cursor-in-non-selected-windows",
-              &Vcursor_in_non_selected_windows,
-    doc: /* *Cursor type to display in non-selected windows.
-t means to use hollow box cursor.  See `cursor-type' for other values.  */);
-  Vcursor_in_non_selected_windows = Qt;
-
   DEFVAR_LISP ("blink-cursor-alist", &Vblink_cursor_alist,
     doc: /* Alist specifying how to blink the cursor off.
 Each element has the form (ON-STATE . OFF-STATE).  Whenever the
@@ -22544,8 +23136,10 @@ Bind this around calls to `message' to let it take effect.  */);
   message_truncate_lines = 0;
 
   DEFVAR_LISP ("menu-bar-update-hook",  &Vmenu_bar_update_hook,
-    doc: /* Normal hook run for clicks on menu bar, before displaying a submenu.
-Can be used to update submenus whose contents should vary.  */);
+    doc: /* Normal hook run to update the menu bar definitions.
+Redisplay runs this hook before it redisplays the menu bar.
+This is used to update submenus such as Buffers,
+whose contents depend on various data.  */);
   Vmenu_bar_update_hook = Qnil;
 
   DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
@@ -22619,9 +23213,10 @@ init_xdisp ()
     /* Allocate the buffer for frame titles.
        Also used for `format-mode-line'.  */
     int size = 100;
-    frame_title_buf = (char *) xmalloc (size);
-    frame_title_buf_end = frame_title_buf + size;
-    frame_title_ptr = NULL;
+    mode_line_noprop_buf = (char *) xmalloc (size);
+    mode_line_noprop_buf_end = mode_line_noprop_buf + size;
+    mode_line_noprop_ptr = mode_line_noprop_buf;
+    mode_line_target = MODE_LINE_DISPLAY;
   }
 
   help_echo_showing_p = 0;