]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(get_next_display_element):
[gnu-emacs] / src / xdisp.c
index 56c686aed478a61fa565e5b6df350fc0cb72560c..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.  */
 
@@ -843,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 *));
@@ -1894,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
@@ -3471,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;
     }
 
@@ -3515,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,
@@ -3830,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;
@@ -5084,9 +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
-                                 || it->c == 0xf2d || it->c == 0xf20)))
+                         || (!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)))))
@@ -5101,6 +5116,8 @@ get_next_display_element (it)
              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 */
@@ -5132,7 +5149,28 @@ get_next_display_element (it)
                  goto display_control;
                }
 
-             escape_glyph = '\\';    /* default for Octal display */
+             /* 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))))
@@ -5142,6 +5180,8 @@ get_next_display_element (it)
                }
              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);
@@ -5153,11 +5193,29 @@ get_next_display_element (it)
                                         it->face_id);
                }
 
+             /* 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;
+                 g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
                  XSETINT (it->ctl_chars[1], g);
                  ctl_len = 2;
                  goto display_control;
@@ -6922,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)
@@ -6934,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 ();
@@ -6945,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)
@@ -8144,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.  */
+
+static char *mode_line_noprop_buf;
 
-/* The frame title buffering code is also used by Fformat_mode_line.
-   So it is not conditioned by HAVE_WINDOW_SYSTEM.  */
+/* The buffer's end, and a current output position in it.  */
 
-/* A buffer for constructing frame titles in it; allocated from the
-   heap in init_xdisp and resized as needed in store_frame_title_char.  */
+static char *mode_line_noprop_buf_end;
+static char *mode_line_noprop_ptr;
 
-static char *frame_title_buf;
+#define MODE_LINE_NOPROP_LEN(start) \
+  ((mode_line_noprop_ptr - mode_line_noprop_buf) - start)
 
-/* The buffer's end, and a current output position in it.  */
+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;
+
+/* 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 char *frame_title_buf_end;
-static char *frame_title_ptr;
+static Lisp_Object Vmode_line_unwind_vector;
 
+static Lisp_Object
+format_mode_line_unwind_data (obuf)
+     struct buffer *obuf;
+{
+  Lisp_Object vector;
 
-/* Store a single character C for the frame title in frame_title_buf.
-   Re-allocate frame_title_buf if necessary.  */
+  /* 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
@@ -8197,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;
 {
@@ -8208,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
@@ -8240,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))
        {
@@ -8261,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
@@ -8281,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);
     }
 }
 
@@ -8341,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)
        {
@@ -8464,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);
@@ -8655,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))
@@ -15577,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);
@@ -15587,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.  */
@@ -15594,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);
 
@@ -15616,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.
 
@@ -15648,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)
@@ -15738,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;
@@ -15773,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 == '%' */
@@ -15833,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 */
@@ -16018,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);
@@ -16036,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;
@@ -16174,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;
@@ -16201,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
@@ -16576,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))
@@ -19034,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));
@@ -19385,7 +19551,6 @@ x_produce_glyphs (it)
          else
            {
              Lisp_Object spacing;
-             int total = 0;
 
              it->phys_ascent = it->ascent;
              it->phys_descent = it->descent;
@@ -21216,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;
@@ -21229,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);
@@ -21309,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);
 }
 
@@ -21363,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.  */
@@ -21389,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;
     }
 
@@ -21649,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,
@@ -22477,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");
@@ -22550,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);
@@ -22577,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.
@@ -22902,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;