]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(get_next_display_element):
[gnu-emacs] / src / xdisp.c
index dd10551d5fae14f20e92cbc510a479bd25a84150..1bb2b4292c02f27b23e752c80068fe6386a7901b 100644 (file)
@@ -320,7 +320,7 @@ Lisp_Object Vshow_trailing_whitespace;
 
 /* Non-nil means escape non-break space and hyphens.  */
 
-Lisp_Object Vshow_nonbreak_escape;
+Lisp_Object Vnobreak_char_display;
 
 #ifdef HAVE_WINDOW_SYSTEM
 extern Lisp_Object Voverflow_newline_into_fringe;
@@ -350,6 +350,10 @@ Lisp_Object Qtrailing_whitespace;
 
 Lisp_Object Qescape_glyph;
 
+/* 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.  */
 
@@ -462,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;
 
@@ -567,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];
 
@@ -612,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;
 
@@ -781,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;
@@ -833,8 +847,8 @@ 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 *));
@@ -1291,6 +1305,7 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
   /* 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 = (last_height = 0, line_bottom_y (&it));
       int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
@@ -1299,15 +1314,12 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
        visible_p = bottom_y > window_top_y;
       else if (top_y < it.last_visible_y)
          visible_p = 1;
-      if (visible_p && x)
+      if (visible_p)
        {
-         *x = it.current_x;
+         *x = top_x;
          *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
-         if (rtop)
-           {
-             *rtop = max (0, window_top_y - top_y);
-             *rbot = max (0, bottom_y - it.last_visible_y);
-           }
+         *rtop = max (0, window_top_y - top_y);
+         *rbot = max (0, bottom_y - it.last_visible_y);
        }
     }
   else
@@ -1320,18 +1332,12 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
       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;
-             if (rtop)
-               {
-                 *rtop = max (0, -it2.current_y);
-                 *rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent)
-                                  - it.last_visible_y));
-               }
-           }
+         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));
        }
     }
 
@@ -1892,7 +1898,7 @@ get_phys_cursor_geometry (w, row, glyph, heightp)
      int *heightp;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  int x, y, wd, h, h0, y0;
+  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
@@ -2538,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]);
@@ -2695,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;
@@ -3372,8 +3385,11 @@ setup_for_ellipsis (it, len)
   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'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;
 }
@@ -3459,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;
     }
 
@@ -3503,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,
@@ -3724,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;
        }
@@ -3817,6 +3838,11 @@ 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;
@@ -5071,8 +5097,11 @@ get_next_display_element (it)
                       ? ((it->c >= 127
                           && it->len == 1)
                          || !CHAR_PRINTABLE_P (it->c)
-                         || (!NILP (Vshow_nonbreak_escape)
-                             && (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)))))
@@ -5084,11 +5113,14 @@ get_next_display_element (it)
                 display.  Then, set IT->dpvec to these glyphs.  */
              GLYPH g;
              int ctl_len;
-             int face_id, lface_id;
+             int face_id, lface_id = 0 ;
              GLYPH escape_glyph;
 
+             /* 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))
@@ -5096,19 +5128,18 @@ get_next_display_element (it)
                    {
                      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);
-                       }
+                   }
+                 if (lface_id)
+                   {
+                      g = FAST_GLYPH_CHAR (g);
+                      face_id = merge_faces (it->f, Qt, lface_id,
+                                             it->face_id);
                    }
                  else
                    {
                      /* Merge the escape-glyph face into the current face.  */
                      face_id = merge_faces (it->f, Qescape_glyph, 0,
                                             it->face_id);
-                     g = '^';
                    }
 
                  XSETINT (it->ctl_chars[0], g);
@@ -5118,31 +5149,73 @@ get_next_display_element (it)
                  goto display_control;
                }
 
+             /* 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))
+               {
+                 /* 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;
+               }
+
+             /* 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)
-                   {
-                     escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
-                     face_id = merge_faces (it->f, Qt, lface_id,
-                                            it->face_id);
-                   }
+               }
+             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
                {
                  /* Merge the escape-glyph face into the current face.  */
                  face_id = merge_faces (it->f, Qescape_glyph, 0,
                                         it->face_id);
-                 escape_glyph = '\\';
                }
 
-             if (it->c == 0x8a0 || it->c == 0x8ad)
+             /* Handle soft hyphens in the mode where they only get
+                highlighting.  */
+
+             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 == 0x8ad ? '-' : ' ';
+                 g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
                  XSETINT (it->ctl_chars[1], g);
                  ctl_len = 2;
                  goto display_control;
@@ -5409,6 +5482,8 @@ 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)))
     {
@@ -5845,15 +5920,25 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
   ((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)))
+   && (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
@@ -6895,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)
@@ -6907,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 ();
@@ -6918,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)
@@ -7212,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
@@ -7240,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.  */
@@ -7870,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;
@@ -7891,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))
@@ -7902,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))
     {
@@ -8118,10 +8193,8 @@ 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];
-  /* Inform read_char that we're not echoing.  */
-  echo_message_buffer = Qnil;
 
   /* Prevent redisplay optimization in redisplay_internal by resetting
      this_line_start_pos.  This is done because the mini-buffer now
@@ -8135,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
@@ -8188,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;
 {
@@ -8199,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
@@ -8231,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))
        {
@@ -8252,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
@@ -8272,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);
     }
 }
 
@@ -8332,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)
        {
@@ -8455,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);
@@ -8646,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))
@@ -9645,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;
 }
 
@@ -9710,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;
     }
@@ -9740,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)))
@@ -9753,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;
 
@@ -9780,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;
 }
 
@@ -10362,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
@@ -10375,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;
@@ -10397,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)
@@ -10606,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;
@@ -12283,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;
     }
 
@@ -14137,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),
@@ -14150,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,
@@ -14832,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.  */
@@ -15240,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.  */
@@ -15273,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;
     }
@@ -15560,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);
@@ -15570,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.  */
@@ -15577,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);
 
@@ -15599,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.
 
@@ -15631,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)
@@ -15721,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;
@@ -15756,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))
+               switch (mode_line_target)
                  {
-                   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
-                 {
-                   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 == '%' */
@@ -15816,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))
-                     {
-                       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
+                   switch (mode_line_target)
                      {
-                       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 */
@@ -16001,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);
@@ -16019,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;
@@ -16072,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;
@@ -16097,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
@@ -16157,6 +16350,9 @@ are the selected window and the window's buffer).  */)
   struct buffer *old_buffer = NULL;
   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;
@@ -16184,64 +16380,50 @@ are the selected window and the window's buffer).  */)
     face_id = DEFAULT_FACE_ID;
 
   if (XBUFFER (buffer) != current_buffer)
-    {
-      old_buffer = current_buffer;
-      set_buffer_internal_1 (XBUFFER (buffer));
-    }
+    old_buffer = current_buffer;
+
+  record_unwind_protect (unwind_format_mode_line,
+                        format_mode_line_unwind_data (old_buffer));
+
+  if (old_buffer)
+    set_buffer_internal_1 (XBUFFER (buffer));
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
 
-  if (!no_props)
+  if (no_props)
     {
-      mode_line_string_face = face;
-      mode_line_string_face_prop
-       = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
-
-      /* 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;
+      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 (!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
@@ -16559,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))
@@ -18900,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.
@@ -18931,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)
@@ -18951,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
@@ -18969,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)
@@ -19017,7 +19200,7 @@ get_line_height_property (it, prop)
      struct it *it;
      Lisp_Object prop;
 {
-  Lisp_Object position, val;
+  Lisp_Object position;
 
   if (STRINGP (it->object))
     position = make_number (IT_STRING_CHARPOS (*it));
@@ -19368,7 +19551,6 @@ x_produce_glyphs (it)
          else
            {
              Lisp_Object spacing;
-             int total = 0;
 
              it->phys_ascent = it->ascent;
              it->phys_descent = it->descent;
@@ -20110,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);
     }
 
@@ -20194,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)
@@ -20771,8 +20955,10 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
 
   /* 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.  Backtrack if we
-     have a STOP object and previous row's end glyph came from STOP.  */
+     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;
@@ -20780,11 +20966,11 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
             && MATRIX_ROW_END_CHARPOS (prev) == charpos
             && prev->used[TEXT_AREA] > 0)
        {
-         end = prev->glyphs[TEXT_AREA];
-         glyph = end + prev->used[TEXT_AREA];
-         while (--glyph >= end
+         struct glyph *beg = prev->glyphs[TEXT_AREA];
+         glyph = beg + prev->used[TEXT_AREA];
+         while (--glyph >= beg
                 && INTEGERP (glyph->object));
-         if (glyph < end
+         if (glyph < beg
              || !EQ (stop, glyph->object))
            break;
          row = prev;
@@ -21195,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;
@@ -21208,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);
@@ -21223,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))
@@ -21239,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;
@@ -21254,7 +21470,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
            }
        }
       if (NILP (pointer))
-       pointer = Fsafe_plist_get (XCDR (object), QCpointer);
+       pointer = Fplist_get (XCDR (object), QCpointer);
     }
 
   if (STRINGP (string))
@@ -21288,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);
 }
 
@@ -21342,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.  */
@@ -21368,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;
     }
 
@@ -21407,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,
@@ -21425,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;
@@ -21438,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);
            }
        }
 
@@ -21628,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,
@@ -22456,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");
@@ -22470,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");
@@ -22531,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);
@@ -22558,9 +22883,14 @@ wide as that tab on the display.  */);
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
-  DEFVAR_LISP ("show-nonbreak-escape", &Vshow_nonbreak_escape,
-    doc: /* *Non-nil means display escape character before non-break space and hyphen.  */);
-  Vshow_nonbreak_escape = Qt;
+  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.
@@ -22586,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.
@@ -22765,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
@@ -22812,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,
@@ -22887,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;