]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Put doc strings in comments.
[gnu-emacs] / src / xdisp.c
index 91b2a5e8a6d4f34dc59213a74bb5ad0342c04a99..08a378e689d44bbf2d58a8e61ba8321f962c2cfa 100644 (file)
@@ -169,6 +169,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include <stdio.h>
+#define DOC_STRINGS_IN_COMMENTS
 #include "lisp.h"
 #include "keyboard.h"
 #include "frame.h"
@@ -198,9 +199,6 @@ Boston, MA 02111-1307, USA.  */
 #include "macterm.h"
 #endif
 
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#define max(a, b) ((a) > (b) ? (a) : (b))
-
 #define INFINITY 10000000
 
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
@@ -227,6 +225,7 @@ Lisp_Object QCeval, Qwhen, QCfile, QCdata;
 Lisp_Object Qfontified;
 Lisp_Object Qgrow_only;
 Lisp_Object Qinhibit_eval_during_redisplay;
+Lisp_Object Qbuffer_position, Qposition, Qobject;
 
 /* Functions called to fontify regions of text.  */
 
@@ -510,6 +509,11 @@ Lisp_Object Vmax_mini_window_height;
 int message_truncate_lines;
 Lisp_Object Qmessage_truncate_lines;
 
+/* Set to 1 in clear_message to make redisplay_internal aware
+   of an emptied echo area.   */
+
+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.  */
 
@@ -680,9 +684,6 @@ static void handle_stop P_ ((struct it *));
 static int tool_bar_lines_needed P_ ((struct frame *));
 static int single_display_prop_intangible_p P_ ((Lisp_Object));
 static void ensure_echo_area_buffers P_ ((void));
-static struct glyph_row *row_containing_pos P_ ((struct window *, int,
-                                                struct glyph_row *,
-                                                struct glyph_row *));
 static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object));
 static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *));
 static int with_echo_area_buffer P_ ((struct window *, int,
@@ -705,13 +706,11 @@ static void insert_left_trunc_glyphs P_ ((struct it *));
 static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
 static void extend_face_to_end_of_line P_ ((struct it *));
 static int append_space P_ ((struct it *, int));
-static void make_cursor_line_fully_visible P_ ((struct window *));
+static int make_cursor_line_fully_visible P_ ((struct window *));
 static int try_scrolling P_ ((Lisp_Object, int, int, int, int));
 static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
 static int message_log_check_duplicate P_ ((int, int, int, int));
-int invisible_p P_ ((Lisp_Object, Lisp_Object));
-int invisible_ellipsis_p P_ ((Lisp_Object, Lisp_Object));
 static void push_it P_ ((struct it *));
 static void pop_it P_ ((struct it *));
 static void sync_frame_with_window_matrix_rows P_ ((struct window *));
@@ -726,7 +725,7 @@ static int display_line P_ ((struct it *));
 static int display_mode_lines P_ ((struct window *));
 static int display_mode_line P_ ((struct window *, enum face_id, Lisp_Object));
 static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object));
-static char *decode_mode_spec P_ ((struct window *, int, int, int));
+static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
 static void display_menu_bar P_ ((struct window *));
 static int display_count_lines P_ ((int, int, int, int, int *));
 static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object,
@@ -748,8 +747,8 @@ static int next_element_from_composition P_ ((struct it *));
 static int next_element_from_image P_ ((struct it *));
 static int next_element_from_stretch P_ ((struct it *));
 static void load_overlay_strings P_ ((struct it *, int));
-static void init_from_display_pos P_ ((struct it *, struct window *,
-                                      struct display_pos *));
+static int init_from_display_pos P_ ((struct it *, struct window *,
+                                     struct display_pos *));
 static void reseat_to_string P_ ((struct it *, unsigned char *,
                                  Lisp_Object, int, int, int, int));
 static enum move_it_result move_it_in_display_line_to P_ ((struct it *,
@@ -757,8 +756,8 @@ static enum move_it_result move_it_in_display_line_to P_ ((struct it *,
 void move_it_vertically_backward P_ ((struct it *, int));
 static void init_to_row_start P_ ((struct it *, struct window *,
                                   struct glyph_row *));
-static void init_to_row_end P_ ((struct it *, struct window *,
-                                struct glyph_row *));
+static int init_to_row_end P_ ((struct it *, struct window *,
+                               struct glyph_row *));
 static void back_to_previous_line_start P_ ((struct it *));
 static int forward_to_next_line_start P_ ((struct it *, int *));
 static struct text_pos string_pos_nchars_ahead P_ ((struct text_pos,
@@ -1429,7 +1428,7 @@ check_window_end (w)
    at character position CHARPOS.  CHARPOS < 0 means that no buffer
    position is specified which is useful when the iterator is assigned
    a position later.  BYTEPOS is the byte position corresponding to
-   CHARPOS.  BYTEPOS <= 0 means compute it from CHARPOS.
+   CHARPOS.  BYTEPOS < 0 means compute it from CHARPOS.
 
    If ROW is not null, calls to produce_glyphs with IT as parameter
    will produce glyphs in that row.
@@ -1455,7 +1454,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
 
   /* Some precondition checks.  */
   xassert (w != NULL && it != NULL);
-  xassert (charpos < 0 || (charpos > 0 && charpos <= ZV));
+  xassert (charpos < 0 || (charpos >= BUF_BEG (current_buffer)
+                          && charpos <= ZV));
 
   /* If face attributes have been changed since the last redisplay,
      free realized faces now because they depend on face definitions
@@ -1535,7 +1535,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
 
   /* Non-zero if we should highlight the region.  */
   highlight_region_p
-    = (!NILP (Vtransient_mark_mode) 
+    = (!NILP (Vtransient_mark_mode)
        && !NILP (current_buffer->mark_active)
        && XMARKER (current_buffer->mark)->buffer != 0);
 
@@ -1672,14 +1672,14 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
 
   /* If a buffer position was specified, set the iterator there,
      getting overlays and face properties from that position.  */
-  if (charpos > 0)
+  if (charpos >= BUF_BEG (current_buffer))
     {
       it->end_charpos = ZV;
       it->face_id = -1;
       IT_CHARPOS (*it) = charpos;
       
       /* Compute byte position if not specified.  */
-      if (bytepos <= 0)
+      if (bytepos < charpos)
        IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
       else
        IT_BYTEPOS (*it) = bytepos;
@@ -1700,36 +1700,32 @@ start_display (it, w, pos)
      struct window *w;
      struct text_pos pos;
 {
-  int start_at_line_beg_p;
   struct glyph_row *row;
   int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
-  int first_y;
 
   row = w->desired_matrix->rows + first_vpos;
   init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
-  first_y = it->current_y;
-  
-  /* If window start is not at a line start, move back to the line
-     start.  This makes sure that we take continuation lines into
-     account.  */
-  start_at_line_beg_p = (CHARPOS (pos) == BEGV
-                        || FETCH_BYTE (BYTEPOS (pos) - 1) == '\n');
-  if (!start_at_line_beg_p)
-    reseat_at_previous_visible_line_start (it);
-
-  /* If window start is not at a line start, skip forward to POS to
-     get the correct continuation_lines_width and current_x.  */
-  if (!start_at_line_beg_p)
-    {
-      move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
-
-      /* If lines are continued, this line may end in the middle of a
-        multi-glyph character (e.g. a control character displayed as
-        \003, or in the middle of an overlay string).  In this case
-        move_it_to above will not have taken us to the start of
-        the continuation line but to the end of the continued line.  */
-      if (!it->truncate_lines_p)
+
+  if (!it->truncate_lines_p)
+    {
+      int start_at_line_beg_p;
+      int first_y = it->current_y;
+  
+      /* If window start is not at a line start, skip forward to POS to
+        get the correct continuation lines width.  */
+      start_at_line_beg_p = (CHARPOS (pos) == BEGV
+                            || FETCH_BYTE (BYTEPOS (pos) - 1) == '\n');
+      if (!start_at_line_beg_p)
        {
+         reseat_at_previous_visible_line_start (it);
+         move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
+
+         /* If lines are continued, this line may end in the middle
+            of a multi-glyph character (e.g. a control character
+            displayed as \003, or in the middle of an overlay
+            string).  In this case move_it_to above will not have
+            taken us to the start of the continuation line but to the
+            end of the continued line.  */
          if (it->current_x > 0)
            {
              if (it->current.dpvec_index >= 0
@@ -1738,7 +1734,7 @@ start_display (it, w, pos)
                  set_iterator_to_next (it, 1);
                  move_it_in_display_line_to (it, -1, -1, 0);
                }
-         
+             
              it->continuation_lines_width += it->current_x;
            }
 
@@ -1747,11 +1743,11 @@ start_display (it, w, pos)
             fields in the iterator structure.  */
          it->max_ascent = it->max_descent = 0;
          it->max_phys_ascent = it->max_phys_descent = 0;
-       }
       
-      it->current_y = first_y;
-      it->vpos = 0;
-      it->current_x = it->hpos = 0;
+         it->current_y = first_y;
+         it->vpos = 0;
+         it->current_x = it->hpos = 0;
+       }
     }
 
 #if 0 /* Don't assert the following because start_display is sometimes
@@ -1793,9 +1789,7 @@ in_ellipses_for_invisible_text_p (pos, w)
     {
       prop = Fget_char_property (make_number (charpos - 1), Qinvisible,
                                 window);
-      if (TEXT_PROP_MEANS_INVISIBLE (prop)
-         && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop))
-       ellipses_p = 1;
+      ellipses_p = 2 == TEXT_PROP_MEANS_INVISIBLE (prop);
     }
 
   return ellipses_p;
@@ -1804,15 +1798,17 @@ in_ellipses_for_invisible_text_p (pos, w)
 
 /* Initialize IT for stepping through current_buffer in window W,
    starting at position POS that includes overlay string and display
-   vector/ control character translation position information.  */
+   vector/ control character translation position information.  Value
+   is zero if there are overlay strings with newlines at POS.  */
 
-static void
+static int
 init_from_display_pos (it, w, pos)
      struct it *it;
      struct window *w;
      struct display_pos *pos;
 {
   int charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
+  int i, overlay_strings_with_newlines = 0;
   
   /* If POS specifies a position in a display vector, this might
      be for an ellipsis displayed for invisible text.  We won't
@@ -1835,6 +1831,21 @@ 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)
+    {
+      char *s = XSTRING (it->overlay_strings[i])->data;
+      char *e = s + STRING_BYTES (XSTRING (it->overlay_strings[i]));
+      
+      while (s < e && *s != '\n')
+       ++s;
+
+      if (s < e)
+       {
+         overlay_strings_with_newlines = 1;
+         break;
+       }
+    }
+
   /* If position is within an overlay string, set up IT to the right
      overlay string.  */
   if (pos->overlay_string_index >= 0)
@@ -1870,6 +1881,11 @@ init_from_display_pos (it, w, pos)
       it->current.string_pos = pos->string_pos;
       it->method = next_element_from_string;
     }
+  
+#if 0 /* This is bogus because POS not having an overlay string
+        position does not mean it's after the string.  Example: A
+        line starting with a before-string and initialization of IT
+        to the previous row's end position.  */
   else if (it->current.overlay_string_index >= 0)
     {
       /* If POS says we're already after an overlay string ending at
@@ -1883,6 +1899,7 @@ init_from_display_pos (it, w, pos)
       if (CHARPOS (pos->pos) == ZV)
        it->overlay_strings_at_end_processed_p = 1;
     }
+#endif /* 0 */
   
   if (CHARPOS (pos->string_pos) >= 0)
     {
@@ -1904,6 +1921,7 @@ init_from_display_pos (it, w, pos)
     }
   
   CHECK_IT (it);
+  return !overlay_strings_with_newlines;
 }
 
 
@@ -1923,20 +1941,28 @@ init_to_row_start (it, w, row)
 
      
 /* Initialize IT for stepping through current_buffer in window W
-   starting in the line following ROW, i.e. starting at ROW->end.  */
+   starting in the line following ROW, i.e. starting at ROW->end.
+   Value is zero if there are overlay strings with newlines at ROW's
+   end position.  */
 
-static void
+static int
 init_to_row_end (it, w, row)
      struct it *it;
      struct window *w;
      struct glyph_row *row;
 {
-  init_from_display_pos (it, w, &row->end);
-
-  if (row->continued_p)
-    it->continuation_lines_width = (row->continuation_lines_width
-                                   + row->pixel_width);
-  CHECK_IT (it);
+  int success = 0;
+  
+  if (init_from_display_pos (it, w, &row->end))
+    {
+      if (row->continued_p)
+       it->continuation_lines_width
+         = row->continuation_lines_width + row->pixel_width;
+      CHECK_IT (it);
+      success = 1;
+    }
+  
+  return success;
 }
 
 
@@ -2175,7 +2201,6 @@ handle_fontified_prop (it)
 
       val = Vfontification_functions;
       specbind (Qfontification_functions, Qnil);
-      specbind (Qafter_change_functions, Qnil);
   
       if (!CONSP (val) || EQ (XCAR (val), Qlambda))
        safe_call1 (val, pos);
@@ -2540,7 +2565,7 @@ handle_invisible_prop (it)
     }
   else
     {
-      int visible_p, newpos, next_stop, start_charpos;
+      int invis_p, newpos, next_stop, start_charpos;
       Lisp_Object pos, prop, overlay;
 
       /* First of all, is there invisible text at this position?  */
@@ -2548,15 +2573,14 @@ handle_invisible_prop (it)
       pos = make_number (IT_CHARPOS (*it));
       prop = get_char_property_and_overlay (pos, Qinvisible, it->window,
                                            &overlay);
-      
+      invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
+
       /* If we are on invisible text, skip over it.  */
-      if (TEXT_PROP_MEANS_INVISIBLE (prop)
-         && IT_CHARPOS (*it) < it->end_charpos)
+      if (invis_p && IT_CHARPOS (*it) < it->end_charpos)
        {
          /* Record whether we have to display an ellipsis for the
             invisible text.  */
-         int display_ellipsis_p
-           = TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop);
+         int display_ellipsis_p = invis_p == 2;
 
          handled = HANDLED_RECOMPUTE_PROPS;
          
@@ -2576,26 +2600,26 @@ handle_invisible_prop (it)
                 text in the first place.  If everything to the end of
                 the buffer was skipped, end the loop.  */
              if (newpos == IT_CHARPOS (*it) || newpos >= ZV)
-               visible_p = 1;
+               invis_p = 0;
              else
                {
                  /* We skipped some characters but not necessarily
                     all there are.  Check if we ended up on visible
                     text.  Fget_char_property returns the property of
                     the char before the given position, i.e. if we
-                    get visible_p = 1, this means that the char at
+                    get invis_p = 0, this means that the char at
                     newpos is visible.  */
                  pos = make_number (newpos);
                  prop = Fget_char_property (pos, Qinvisible, it->window);
-                 visible_p = !TEXT_PROP_MEANS_INVISIBLE (prop);
+                 invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
                }
              
              /* If we ended up on invisible text, proceed to
                 skip starting with next_stop.  */
-             if (!visible_p)
+             if (invis_p)
                IT_CHARPOS (*it) = next_stop;
            }
-         while (!visible_p);
+         while (invis_p);
 
          /* The position newpos is now either ZV or on visible text.  */
          IT_CHARPOS (*it) = newpos;
@@ -2796,26 +2820,22 @@ handle_single_display_prop (it, prop, object, position,
 
   if (!NILP (form) && !EQ (form, Qt))
     {
+      int count = BINDING_STACK_SIZE ();
       struct gcpro gcpro1;
-      struct text_pos end_pos, pt;
-      
-      GCPRO1 (form);
-      end_pos = display_prop_end (it, object, *position);
 
-      /* Temporarily set point to the end position, and then evaluate
-        the form.  This makes `(eolp)' work as FORM.  */
-      if (BUFFERP (object))
-       {
-         CHARPOS (pt) = PT;
-         BYTEPOS (pt) = PT_BYTE;
-         TEMP_SET_PT_BOTH (CHARPOS (end_pos), BYTEPOS (end_pos));
-       }
-      
+      /* Bind `object' to the object having the `display' property, a
+        buffer or string.  Bind `position' to the position in the
+        object where the property was found, and `buffer-position'
+        to the current position in the buffer.  */
+      specbind (Qobject, object);
+      specbind (Qposition, make_number (CHARPOS (*position)));
+      specbind (Qbuffer_position,
+               make_number (STRINGP (object)
+                            ? IT_CHARPOS (*it) : CHARPOS (*position)));
+      GCPRO1 (form);
       form = safe_eval (form);
-      
-      if (BUFFERP (object))
-       TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
-      UNGCPRO;  
+      UNGCPRO;
+      unbind_to (count, Qnil);
     }
   
   if (NILP (form))
@@ -3211,7 +3231,7 @@ string_buffer_position (w, string, around_charpos)
       if (!NILP (prop) && display_prop_string_p (prop, string))
        found = 1;
       else
-       pos = Fnext_single_property_change (pos, Qdisplay, Qnil, limit);
+       pos = Fnext_single_char_property_change (pos, Qdisplay, Qnil, limit);
     }
 
   if (!found)
@@ -3224,8 +3244,8 @@ string_buffer_position (w, string, around_charpos)
          if (!NILP (prop) && display_prop_string_p (prop, string))
            found = 1;
          else
-           pos = Fprevious_single_property_change (pos, Qdisplay, Qnil,
-                                                   limit);
+           pos = Fprevious_single_char_property_change (pos, Qdisplay, Qnil,
+                                                        limit);
        }
     }
 
@@ -4009,6 +4029,7 @@ reseat_1 (it, pos, set_stop_p)
   IT_STRING_BYTEPOS (*it) = -1;
   it->string = Qnil;
   it->method = next_element_from_buffer;
+  it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
   it->sp = 0;
   it->face_before_selective_p = 0;
 
@@ -5476,6 +5497,10 @@ move_it_by_lines (it, dvpos, need_y_p)
       struct it it2;
       int start_charpos, i;
       
+      /* Start at the beginning of the screen line containing IT's
+        position.  */
+      move_it_vertically_backward (it, 0);
+      
       /* Go back -DVPOS visible lines and reseat the iterator there.  */
       start_charpos = IT_CHARPOS (*it);
       for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
@@ -5538,7 +5563,7 @@ add_to_log (format, arg1, arg2)
 
   len = STRING_BYTES (XSTRING (msg)) + 1;
   buffer = (char *) alloca (len);
-  strcpy (buffer, XSTRING (msg)->data);
+  bcopy (XSTRING (msg)->data, buffer, len);
   
   message_dolog (buffer, len - 1, 1, 0);
   UNGCPRO;
@@ -6205,7 +6230,7 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
 
   /* Don't get confused by reusing the buffer used for echoing
      for a different purpose.  */
-  if (!echoing && EQ (buffer, echo_message_buffer))
+  if (echo_kboard == NULL && EQ (buffer, echo_message_buffer))
     cancel_echoing ();
 
   record_unwind_protect (unwind_with_echo_area_buffer,
@@ -6228,6 +6253,7 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
   current_buffer->undo_list = Qt;
   current_buffer->read_only = Qnil;
   specbind (Qinhibit_read_only, Qt);
+  specbind (Qinhibit_modification_hooks, Qt);
 
   if (clear_buffer_p && Z > BEG)
     del_range (BEG, Z);
@@ -6455,7 +6481,8 @@ display_echo_area_1 (a1, a2, a3, a4)
 
 
 /* Resize the echo area window to exactly the size needed for the
-   currently displayed message, if there is one.  */
+   currently displayed message, if there is one.  If a mini-buffer
+   is active, don't shrink it.  */
 
 void
 resize_echo_area_exactly ()
@@ -6465,9 +6492,15 @@ resize_echo_area_exactly ()
     {
       struct window *w = XWINDOW (echo_area_window);
       int resized_p;
+      Lisp_Object resize_exactly;
+
+      if (minibuf_level == 0)
+       resize_exactly = Qt;
+      else
+       resize_exactly = Qnil;
       
       resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
-                                        (EMACS_INT) w, Qnil, 0, 0);
+                                        (EMACS_INT) w, resize_exactly, 0, 0);
       if (resized_p)
        {
          ++windows_or_buffers_changed;
@@ -6480,16 +6513,17 @@ resize_echo_area_exactly ()
 
 /* Callback function for with_echo_area_buffer, when used from
    resize_echo_area_exactly.  A1 contains a pointer to the window to
-   resize, A2 to A4 are not used.  Value is what resize_mini_window
-   returns.  */
+   resize, EXACTLY non-nil means resize the mini-window exactly to the
+   size of the text displayed.  A3 and A4 are not used.  Value is what
+   resize_mini_window returns.  */
 
 static int
-resize_mini_window_1 (a1, a2, a3, a4)
+resize_mini_window_1 (a1, exactly, a3, a4)
      EMACS_INT a1;
-     Lisp_Object a2;
+     Lisp_Object exactly;
      EMACS_INT a3, a4;
 {
-  return resize_mini_window ((struct window *) a1, 1);
+  return resize_mini_window ((struct window *) a1, !NILP (exactly));
 }
 
 
@@ -6542,7 +6576,7 @@ resize_mini_window (w, exact_p)
 
       /* Compute the max. number of lines specified by the user.  */
       if (FLOATP (Vmax_mini_window_height))
-       max_height = XFLOATINT (Vmax_mini_window_height) * total_height;
+       max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_HEIGHT (f);
       else if (INTEGERP (Vmax_mini_window_height))
        max_height = XINT (Vmax_mini_window_height);
       else
@@ -6895,7 +6929,10 @@ clear_message (current_p, last_displayed_p)
      int current_p, last_displayed_p;
 {
   if (current_p)
-    echo_area_buffer[0] = Qnil;
+    {
+      echo_area_buffer[0] = Qnil;
+      message_cleared_p = 1;
+    }
   
   if (last_displayed_p)
     echo_area_buffer[1] = Qnil;
@@ -7755,8 +7792,8 @@ tool_bar_lines_needed (f)
 
 DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
        0, 1, 0,
-  "Return the number of lines occupied by the tool bar of FRAME.")
-  (frame)
+       /* Return the number of lines occupied by the tool bar of FRAME.  */
+       (frame))
      Lisp_Object frame;
 {
   struct frame *f;
@@ -7951,6 +7988,7 @@ hscroll_window_tree (window)
                      &text_area_width, &text_area_height);
 
          /* Scroll when cursor is inside this scroll margin.  */
+         /* Shouldn't we export this `5' for customization ?  -stef  */
          hscroll_margin = 5 * CANON_X_UNIT (XFRAME (w->frame));
          
          if ((XFASTINT (w->hscroll)
@@ -8151,6 +8189,23 @@ text_outside_line_unchanged_p (w, start, end)
          && XINT (current_buffer->selective_display) > 0
          && (BEG_UNCHANGED < start || GPT <= start))
        unchanged_p = 0;
+
+      /* If there are overlays at the start or end of the line, these
+        may have overlay strings with newlines in them.  A change at
+        START, for instance, may actually concern the display of such
+        overlay strings as well, and they are displayed on different
+        lines.  So, quickly rule out this case.  (For the future, it
+        might be desirable to implement something more telling than
+        just BEG/END_UNCHANGED.)  */
+      if (unchanged_p)
+       {
+         if (BEG + BEG_UNCHANGED == start
+             && overlay_touches_p (start))
+           unchanged_p = 0;
+         if (END_UNCHANGED == end
+             && overlay_touches_p (Z - end))
+           unchanged_p = 0;
+       }
     }
 
   return unchanged_p;
@@ -8170,6 +8225,7 @@ redisplay ()
   redisplay_internal (0);
 }
 
+
 /* Return 1 if point moved out of or into a composition.  Otherwise
    return 0.  PREV_BUF and PREV_PT are the last point buffer and
    position.  BUF and PT are the current point buffer and position.  */
@@ -8208,6 +8264,7 @@ check_point_in_composition (prev_buf, prev_pt, buf, pt)
          && start < pt && end > pt);
 }
 
+
 /* Reconsider the setting of B->clip_changed which is displayed
    in window W.  */
 
@@ -8406,12 +8463,21 @@ redisplay_internal (preserve_echo_area)
   /* Normally the message* functions will have already displayed and
      updated the echo area, but the frame may have been trashed, or
      the update may have been preempted, so display the echo area
-     again here.  Checking both message buffers captures the case that
+     again here.  Checking message_cleared_p captures the case that
      the echo area should be cleared.  */
-  if (!NILP (echo_area_buffer[0]) || !NILP (echo_area_buffer[1]))
+  if ((!NILP (echo_area_buffer[0]) && !display_last_displayed_message_p)
+      || (!NILP (echo_area_buffer[1]) && display_last_displayed_message_p)
+      || (message_cleared_p && minibuf_level == 0))
     {
       int window_height_changed_p = echo_area_display (0);
       must_finish = 1;
+
+      /* If we don't display the current message, don't clear the
+        message_cleared_p flag, because, if we did, we wouldn't clear
+        the echo area in the next redisplay which doesn't preserve
+        the echo area.  */
+      if (!display_last_displayed_message_p)
+       message_cleared_p = 0;
       
       if (fonts_changed_p)
        goto retry;
@@ -8992,9 +9058,11 @@ mark_window_display_accurate_1 (w, accurate_p)
   if (accurate_p)
     {
       w->window_end_valid = w->buffer;
+#if 0 /* This is incorrect with variable-height lines.  */
       xassert (XINT (w->window_end_vpos)
               < (XINT (w->height)
                  - (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)));
+#endif
       w->update_mode_line = Qnil;
     }
 }
@@ -9210,9 +9278,11 @@ run_window_scroll_functions (window, startp)
 
 
 /* Modify the desired matrix of window W and W->vscroll so that the
-   line containing the cursor is fully visible.  */
+   line containing the cursor is fully visible.  If this requires
+   larger matrices than are allocated, set fonts_changed_p and return
+   0.  */
 
-static void
+static int
 make_cursor_line_fully_visible (w)
      struct window *w;
 {
@@ -9223,7 +9293,7 @@ make_cursor_line_fully_visible (w)
   /* It's not always possible to find the cursor, e.g, when a window
      is full of overlay strings.  Don't do anything in that case.  */
   if (w->cursor.vpos < 0)
-    return;
+    return 1;
   
   matrix = w->desired_matrix;
   row = MATRIX_ROW (matrix, w->cursor.vpos);
@@ -9231,13 +9301,13 @@ make_cursor_line_fully_visible (w)
   /* If the cursor row is not partially visible, there's nothing
      to do.  */
   if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
-    return;
+    return 1;
 
   /* If the row the cursor is in is taller than the window's height,
      it's not clear what to do, so do nothing.  */
   window_height = window_box_height (w);
   if (row->height >= window_height)
-    return;
+    return 1;
 
   if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
     {
@@ -9260,6 +9330,16 @@ make_cursor_line_fully_visible (w)
      the correct y-position.  */
   if (w == XWINDOW (selected_window))
     this_line_y = w->cursor.y;
+
+  /* If vscrolling requires a larger glyph matrix, arrange for a fresh
+     redisplay with larger matrices.  */
+  if (matrix->nrows < required_matrix_height (w))
+    {
+      fonts_changed_p = 1;
+      return 0;
+    }
+
+  return 1;
 }
 
 
@@ -9278,6 +9358,13 @@ make_cursor_line_fully_visible (w)
    -1  if new fonts have been loaded so that we must interrupt
    redisplay, adjust glyph matrices, and try again.  */
 
+enum
+{
+  SCROLLING_SUCCESS,
+  SCROLLING_FAILED,
+  SCROLLING_NEED_LARGER_MATRICES
+};
+
 static int
 try_scrolling (window, just_this_one_p, scroll_conservatively,
               scroll_step, temp_scroll_step)
@@ -9367,7 +9454,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
       dy = 1 + it.current_y - y0;
       
       if (dy > scroll_max)
-       return 0;
+       return SCROLLING_FAILED;
       
       /* Move the window start down.  If scrolling conservatively,
         move it just enough down to make point visible.  If
@@ -9390,7 +9477,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
        }
 
       if (amount_to_scroll <= 0)
-       return 0;
+       return SCROLLING_FAILED;
 
       move_it_vertically (&it, amount_to_scroll);
       startp = it.current.pos;
@@ -9424,7 +9511,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
          dy = it.current_y - y0;
          if (dy > scroll_max)
-           return 0;
+           return SCROLLING_FAILED;
          
          /* Compute new window start.  */
          start_display (&it, w, startp);
@@ -9444,7 +9531,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
            }
 
          if (amount_to_scroll <= 0)
-           return 0;
+           return SCROLLING_FAILED;
          
          move_it_vertically (&it, - amount_to_scroll);
          startp = it.current.pos;
@@ -9457,11 +9544,11 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   /* Display the window.  Give up if new fonts are loaded, or if point
      doesn't appear.  */
   if (!try_window (window, startp))
-    rc = -1;
+    rc = SCROLLING_NEED_LARGER_MATRICES;
   else if (w->cursor.vpos < 0)
     {
       clear_glyph_matrix (w->desired_matrix);
-      rc = 0;
+      rc = SCROLLING_FAILED;
     }
   else
     {
@@ -9472,9 +9559,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
        w->base_line_number = Qnil;
       
       /* If cursor ends up on a partially visible line, shift display
-        lines up or down.  */
-      make_cursor_line_fully_visible (w);
-      rc = 1;
+        lines up or down.  If that fails because we need larger
+        matrices, give up.  */
+      if (!make_cursor_line_fully_visible (w))
+       rc = SCROLLING_NEED_LARGER_MATRICES;
+      else
+       rc = SCROLLING_SUCCESS;
     }
 
   return rc;
@@ -9556,13 +9646,25 @@ compute_window_start_on_continuation_line (w)
 /* Try cursor movement in case text has not changes in window WINDOW,
    with window start STARTP.  Value is
 
-   1   if successful
+   CURSOR_MOVEMENT_SUCCESS if successful
    
-   0   if this method cannot be used
-   
-   -1  if we know we have to scroll the display.  *SCROLL_STEP is
-   set to 1, under certain circumstances, if we want to scroll as
-   if scroll-step were set to 1.  See the code.  */
+   CURSOR_MOVEMENT_CANNOT_BE_USED if this method cannot be used
+
+   CURSOR_MOVEMENT_MUST_SCROLL if we know we have to scroll the
+   display.  *SCROLL_STEP is set to 1, under certain circumstances, if
+   we want to scroll as if scroll-step were set to 1.  See the code.
+
+   CURSOR_MOVEMENT_NEED_LARGER_MATRICES if we need larger matrices, in
+   which case we have to abort this redisplay, and adjust matrices
+   first.  */
+
+enum 
+{
+  CURSOR_MOVEMENT_SUCCESS,
+  CURSOR_MOVEMENT_CANNOT_BE_USED,
+  CURSOR_MOVEMENT_MUST_SCROLL,
+  CURSOR_MOVEMENT_NEED_LARGER_MATRICES
+};
 
 static int
 try_cursor_movement (window, startp, scroll_step)
@@ -9572,7 +9674,7 @@ try_cursor_movement (window, startp, scroll_step)
 {
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
-  int rc = 0;
+  int rc = CURSOR_MOVEMENT_CANNOT_BE_USED;
   
   /* Handle case where text has not changed, only point, and it has
      not moved off the frame.  */
@@ -9630,17 +9732,17 @@ try_cursor_movement (window, startp, scroll_step)
         not paused redisplay.  Give up if that row is not valid.  */
       if (w->last_cursor.vpos < 0
          || w->last_cursor.vpos >= w->current_matrix->nrows)
-       rc = -1;
+       rc = CURSOR_MOVEMENT_MUST_SCROLL;
       else
        {
          row = MATRIX_ROW (w->current_matrix, w->last_cursor.vpos);
          if (row->mode_line_p)
            ++row;
          if (!row->enabled_p)
-           rc = -1;
+           rc = CURSOR_MOVEMENT_MUST_SCROLL;
        }
 
-      if (rc == 0)
+      if (rc == CURSOR_MOVEMENT_CANNOT_BE_USED)
        {
          int scroll_p = 0;
          int last_y = window_text_bottom_y (w) - this_scroll_margin;
@@ -9723,14 +9825,14 @@ try_cursor_movement (window, startp, scroll_step)
              || PT > MATRIX_ROW_END_CHARPOS (row))
            {
              /* if PT is not in the glyph row, give up.  */
-             rc = -1;
+             rc = CURSOR_MOVEMENT_MUST_SCROLL;
            }
          else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
            {
              if (PT == MATRIX_ROW_END_CHARPOS (row)
                  && !row->ends_at_zv_p
                  && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
-               rc = -1;
+               rc = CURSOR_MOVEMENT_MUST_SCROLL;
              else if (row->height > window_box_height (w))
                {
                  /* If we end up in a partially visible line, let's
@@ -9738,22 +9840,24 @@ try_cursor_movement (window, startp, scroll_step)
                     than the window, in which case we can't do much
                     about it.  */
                  *scroll_step = 1;
-                 rc = -1;
+                 rc = CURSOR_MOVEMENT_MUST_SCROLL;
                }
              else
                {
                  set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
                  try_window (window, startp);
-                 make_cursor_line_fully_visible (w);
-                 rc = 1;
+                 if (!make_cursor_line_fully_visible (w))
+                   rc = CURSOR_MOVEMENT_NEED_LARGER_MATRICES;
+                 else
+                   rc = CURSOR_MOVEMENT_SUCCESS;
                }
            }
          else if (scroll_p)
-           rc = -1;
+           rc = CURSOR_MOVEMENT_MUST_SCROLL;
          else
            {
              set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-             rc = 1;
+             rc = CURSOR_MOVEMENT_SUCCESS;
            }
        }
     }
@@ -10027,11 +10131,12 @@ redisplay_window (window, just_this_one_p)
            {
              clear_glyph_matrix (w->desired_matrix);
              if (!try_window (window, startp))
-               goto finish_scroll_bars;
+               goto need_larger_matrices;
            }
        }
 
-      make_cursor_line_fully_visible (w);
+      if (!make_cursor_line_fully_visible (w))
+       goto need_larger_matrices;
 #if GLYPH_DEBUG
       debug_method_add (w, "forced window start");
 #endif
@@ -10042,12 +10147,22 @@ redisplay_window (window, just_this_one_p)
      not moved off the frame.  */
   if (current_matrix_up_to_date_p
       && (rc = try_cursor_movement (window, startp, &temp_scroll_step),
-         rc != 0))
+         rc != CURSOR_MOVEMENT_CANNOT_BE_USED))
     {
-      if (rc == -1)
-       goto try_to_scroll;
-      else
-       goto done;
+      switch (rc)
+       {
+       case CURSOR_MOVEMENT_SUCCESS:
+         goto done;
+         
+       case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
+         goto need_larger_matrices;
+         
+       case CURSOR_MOVEMENT_MUST_SCROLL:
+         goto try_to_scroll;
+         
+       default:
+         abort ();
+       }
     }
   /* If current starting point was originally the beginning of a line
      but no longer is, find a new starting point.  */
@@ -10071,7 +10186,7 @@ redisplay_window (window, just_this_one_p)
 #endif
 
       if (fonts_changed_p)
-       goto finish_scroll_bars;
+       goto need_larger_matrices;
       if (tem > 0)
        goto done;
 
@@ -10106,7 +10221,7 @@ redisplay_window (window, just_this_one_p)
        }
 
       if (fonts_changed_p)
-       goto finish_scroll_bars;
+       goto need_larger_matrices;
       
       if (w->cursor.vpos >= 0)
        {
@@ -10116,7 +10231,8 @@ redisplay_window (window, just_this_one_p)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
          
-         make_cursor_line_fully_visible (w);
+         if (!make_cursor_line_fully_visible (w))
+           goto need_larger_matrices;
          goto done;
        }
       else
@@ -10151,10 +10267,20 @@ redisplay_window (window, just_this_one_p)
                              scroll_conservatively,
                              scroll_step,
                              temp_scroll_step);
-      if (rc > 0)
-       goto done;
-      else if (rc < 0)
-       goto finish_scroll_bars;
+      switch (rc)
+       {
+       case SCROLLING_SUCCESS:
+         goto done;
+         
+       case SCROLLING_NEED_LARGER_MATRICES:
+         goto need_larger_matrices;
+         
+       case SCROLLING_FAILED:
+         break;
+         
+       default:
+         abort ();
+       }
     }
 
   /* Finally, just choose place to start which centers point */
@@ -10215,7 +10341,7 @@ redisplay_window (window, just_this_one_p)
      have to start a new redisplay since we need to re-adjust glyph
      matrices.  */
   if (fonts_changed_p)
-    goto finish_scroll_bars;
+    goto need_larger_matrices;
 
   /* If cursor did not appear assume that the middle of the window is
      in the first line of the window.  Do it again with the next line.
@@ -10255,7 +10381,8 @@ redisplay_window (window, just_this_one_p)
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
   
-  make_cursor_line_fully_visible (w);
+  if (!make_cursor_line_fully_visible (w))
+    goto need_larger_matrices;
 
  done:
 
@@ -10282,13 +10409,7 @@ redisplay_window (window, just_this_one_p)
        && (WINDOW_WANTS_MODELINE_P (w)
           || WINDOW_WANTS_HEADER_LINE_P (w)))
     {
-      Lisp_Object old_selected_frame;
-      
-      old_selected_frame = selected_frame;
-      
-      XSETFRAME (selected_frame, f);
       display_mode_lines (w);
-      selected_frame = old_selected_frame;
 
       /* If mode line height has changed, arrange for a thorough
         immediate redisplay using the correct mode line height.  */
@@ -10311,7 +10432,7 @@ redisplay_window (window, just_this_one_p)
        }
 
       if (fonts_changed_p)
-       goto finish_scroll_bars;
+       goto need_larger_matrices;
     }
 
   if (!line_number_displayed
@@ -10351,6 +10472,8 @@ redisplay_window (window, just_this_one_p)
 #endif
     }
 
+ need_larger_matrices:
+  ;
  finish_scroll_bars:
 
   if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
@@ -11059,7 +11182,7 @@ sync_frame_with_window_matrix_rows (w)
    all rows to the end of the display area of W.  Value is the row
    containing CHARPOS or null.  */
 
-static struct glyph_row *
+struct glyph_row *
 row_containing_pos (w, charpos, start, end)
      struct window *w;
      int charpos;
@@ -11366,14 +11489,16 @@ try_window_id (w)
         for instance.  This is easier than to set up the iterator
         exactly, and it's not a frequent case, so the additional
         effort wouldn't really pay off.  */
-      while (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row)
+      while ((MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row)
+             || last_unchanged_at_beg_row->ends_in_newline_from_string_p)
             && last_unchanged_at_beg_row > w->current_matrix->rows)
        --last_unchanged_at_beg_row;
 
       if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (last_unchanged_at_beg_row))
        GIVE_UP (17);
-      
-      init_to_row_end (&it, w, last_unchanged_at_beg_row);
+
+      if (init_to_row_end (&it, w, last_unchanged_at_beg_row) == 0)
+       GIVE_UP (18);
       start_pos = it.current.pos;
       
       /* Start displaying new lines in the desired matrix at the same
@@ -11413,8 +11538,23 @@ try_window_id (w)
   stop_pos = 0;
   if (first_unchanged_at_end_row)
     {
+#if GLYPH_DEBUG
       xassert (last_unchanged_at_beg_row == NULL
               || first_unchanged_at_end_row >= last_unchanged_at_beg_row);
+#else
+      /* This is for the release of 21.1 only, and should be removed
+        after the release.
+
+        This case means that unchanged information is probably bogus,
+        which leads to being unable to compute a correct
+        first_unchanged_at_end_row.  At least that was the case in
+        one debugging session.  I've fixed a bug that can lead to
+        wrong unchanged info, but didn't find a way to reproduce this
+        case.  2001-09-18 gerd.  */
+      if (last_unchanged_at_beg_row 
+         && first_unchanged_at_end_row < last_unchanged_at_beg_row)
+       GIVE_UP (20);
+#endif
       
       /* If this is a continuation line, move forward to the next one
         that isn't.  Changes in lines above affect this line.
@@ -11827,7 +11967,7 @@ try_window_id (w)
 
 #if GLYPH_DEBUG
 
-void dump_glyph_row P_ ((struct glyph_matrix *, int, int));
+void dump_glyph_row P_ ((struct glyph_row *, int, int));
 void dump_glyph_matrix P_ ((struct glyph_matrix *, int));
 void dump_glyph P_ ((struct glyph_row *, struct glyph *, int));
 
@@ -11845,7 +11985,7 @@ dump_glyph_matrix (matrix, glyphs)
 {
   int i;
   for (i = 0; i < matrix->nrows; ++i)
-    dump_glyph_row (matrix, i, glyphs);
+    dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
 }
 
 
@@ -11926,17 +12066,10 @@ dump_glyph (row, glyph, area)
    GLYPHS > 1 means show glyphs in long form.  */
 
 void
-dump_glyph_row (matrix, vpos, glyphs)
-     struct glyph_matrix *matrix;
+dump_glyph_row (row, vpos, glyphs)
+     struct glyph_row *row;
      int vpos, glyphs;
 {
-  struct glyph_row *row;
-  
-  if (vpos < 0 || vpos >= matrix->nrows)
-    return;
-
-  row = MATRIX_ROW (matrix, vpos);
-
   if (glyphs != 1)
     {
       fprintf (stderr, "Row Start   End Used oEI><O\\CTZFesm     X    Y    W    H    V    A    P\n");
@@ -11944,7 +12077,7 @@ dump_glyph_row (matrix, vpos, glyphs)
   
       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%1.1d%1.1d  %4d %4d %4d %4d %4d %4d %4d\n",
-              row - matrix->rows,
+              vpos,
               MATRIX_ROW_START_CHARPOS (row),
               MATRIX_ROW_END_CHARPOS (row),
               row->used[TEXT_AREA],
@@ -12028,11 +12161,11 @@ dump_glyph_row (matrix, vpos, glyphs)
 
 DEFUN ("dump-glyph-matrix", Fdump_glyph_matrix,
        Sdump_glyph_matrix, 0, 1, "p",
-  "Dump the current matrix of the selected window to stderr.\n\
-Shows contents of glyph row structures.  With non-nil\n\
-parameter GLYPHS, dump glyphs as well.  If GLYPHS is 1 show\n\
-glyphs in short form, otherwise show glyphs in long form.")
-  (glyphs)
+       /* Dump the current matrix of the selected window to stderr.
+Shows contents of glyph row structures.  With non-nil
+parameter GLYPHS, dump glyphs as well.  If GLYPHS is 1 show
+glyphs in short form, otherwise show glyphs in long form.  */
+       (glyphs))
      Lisp_Object glyphs;
 {
   struct window *w = XWINDOW (selected_window);
@@ -12050,40 +12183,52 @@ glyphs in short form, otherwise show glyphs in long form.")
 
 
 DEFUN ("dump-glyph-row", Fdump_glyph_row, Sdump_glyph_row, 1, 2, "",
-  "Dump glyph row ROW to stderr.\n\
-GLYPH 0 means don't dump glyphs.\n\
-GLYPH 1 means dump glyphs in short form.\n\
-GLYPH > 1 or omitted means dump glyphs in long form.")
-  (row, glyphs)
+       /* Dump glyph row ROW to stderr.
+GLYPH 0 means don't dump glyphs.
+GLYPH 1 means dump glyphs in short form.
+GLYPH > 1 or omitted means dump glyphs in long form.  */
+       (row, glyphs))
      Lisp_Object row, glyphs;
 {
+  struct glyph_matrix *matrix;
+  int vpos;
+  
   CHECK_NUMBER (row, 0);
-  dump_glyph_row (XWINDOW (selected_window)->current_matrix,
-                 XINT (row),
-                 INTEGERP (glyphs) ? XINT (glyphs) : 2);
+  matrix = XWINDOW (selected_window)->current_matrix;
+  vpos = XINT (row);
+  if (vpos >= 0 && vpos < matrix->nrows)
+    dump_glyph_row (MATRIX_ROW (matrix, vpos),
+                   vpos,
+                   INTEGERP (glyphs) ? XINT (glyphs) : 2);
   return Qnil;
 }
 
 
 DEFUN ("dump-tool-bar-row", Fdump_tool_bar_row, Sdump_tool_bar_row, 1, 2, "",
-  "Dump glyph row ROW of the tool-bar of the current frame to stderr.\n\
-GLYPH 0 means don't dump glyphs.\n\
-GLYPH 1 means dump glyphs in short form.\n\
-GLYPH > 1 or omitted means dump glyphs in long form.")
-  (row, glyphs)
+  /* Dump glyph row ROW of the tool-bar of the current frame to stderr.
+GLYPH 0 means don't dump glyphs.
+GLYPH 1 means dump glyphs in short form.
+GLYPH > 1 or omitted means dump glyphs in long form.  */
+       (row, glyphs))
      Lisp_Object row, glyphs;
 {
   struct frame *sf = SELECTED_FRAME ();
-  struct glyph_matrix *m = (XWINDOW (sf->tool_bar_window)->current_matrix);
-  dump_glyph_row (m, XINT (row), INTEGERP (glyphs) ? XINT (glyphs) : 2);
+  struct glyph_matrix *m = XWINDOW (sf->tool_bar_window)->current_matrix;
+  int vpos;
+  
+  CHECK_NUMBER (row, 0);
+  vpos = XINT (row);
+  if (vpos >= 0 && vpos < m->nrows)
+    dump_glyph_row (MATRIX_ROW (m, vpos), vpos,
+                   INTEGERP (glyphs) ? XINT (glyphs) : 2);
   return Qnil;
 }
 
 
 DEFUN ("trace-redisplay", Ftrace_redisplay, Strace_redisplay, 0, 1, "P",
-  "Toggle tracing of redisplay.\n\
-With ARG, turn tracing on if and only if ARG is positive.")
-  (arg)
+       /* Toggle tracing of redisplay.
+With ARG, turn tracing on if and only if ARG is positive.  */
+       (arg))
      Lisp_Object arg;
 {
   if (NILP (arg))
@@ -12098,13 +12243,14 @@ With ARG, turn tracing on if and only if ARG is positive.")
 }
 
 
-DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, 1, "",
-   "Print STRING to stderr.")
-   (string)
-     Lisp_Object string;
+DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
+       /* Like `format', but print result to stderr.  */
+       (nargs, args))
+     int nargs;
+     Lisp_Object *args;
 {
-  CHECK_STRING (string, 0);
-  fprintf (stderr, "%s", XSTRING (string)->data);
+  Lisp_Object s = Fformat (nargs, args);
+  fprintf (stderr, "%s", XSTRING (s)->data);
   return Qnil;
 }
        
@@ -12853,6 +12999,8 @@ display_line (it)
        {
          int used_before = row->used[TEXT_AREA];
 
+         row->ends_in_newline_from_string_p = STRINGP (it->object);
+
          /* Add a space at the end of the line that is used to
             display the cursor there.  */
          append_space (it, 0);
@@ -13125,7 +13273,6 @@ redisplay_mode_lines (window, force)
               || FRAME_GARBAGED_P (XFRAME (w->frame))
               || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
        {
-         Lisp_Object old_selected_frame;
          struct text_pos lpoint;
          struct buffer *old = current_buffer;
 
@@ -13148,10 +13295,6 @@ redisplay_mode_lines (window, force)
                TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
            }
 
-         /* Temporarily set up the selected frame.  */
-         old_selected_frame = selected_frame;
-         selected_frame = w->frame;
-
          /* Display mode lines.  */
          clear_glyph_matrix (w->desired_matrix);
          if (display_mode_lines (w))
@@ -13161,7 +13304,6 @@ redisplay_mode_lines (window, force)
            }
 
          /* Restore old settings.  */
-         selected_frame = old_selected_frame;
          set_buffer_internal_1 (old);
          TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
        }
@@ -13180,7 +13322,13 @@ static int
 display_mode_lines (w)
      struct window *w;
 {
+  Lisp_Object old_selected_window, old_selected_frame;
   int n = 0;
+
+  old_selected_frame = selected_frame;
+  selected_frame = w->frame;
+  old_selected_window = selected_window;
+  XSETWINDOW (selected_window, w);
   
   /* These will be set while the mode line specs are processed.  */
   line_number_displayed = 0;
@@ -13200,6 +13348,8 @@ display_mode_lines (w)
       ++n;
     }
 
+  selected_frame = old_selected_frame;
+  selected_window = old_selected_window;
   return n;
 }
 
@@ -13313,15 +13463,21 @@ display_mode_element (it, depth, field_width, precision, elt)
                   is length of string.  Don't output more than
                   PRECISION allows us.  */
                --this;
-               prec = strwidth (last, this - last);
+
+               prec = chars_in_text (last, this - last);
                if (precision > 0 && prec > precision - n)
                  prec = precision - n;
                
                if (frame_title_ptr)
                  n += store_frame_title (last, 0, prec);
                else
-                 n += display_string (NULL, elt, Qnil, 0, last - lisp_string,
-                                      it, 0, prec, 0, -1);
+                 {
+                   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));
+                 }
              }
            else /* c == '%' */
              {
@@ -13345,20 +13501,25 @@ display_mode_element (it, depth, field_width, precision, elt)
                                             Vglobal_mode_string);
                else if (c != 0)
                  {
+                   int multibyte;
                    unsigned char *spec
-                     = decode_mode_spec (it->w, c, field, prec);
-                   
+                     = decode_mode_spec (it->w, c, field, prec, &multibyte);
+
                    if (frame_title_ptr)
                      n += store_frame_title (spec, field, prec);
                    else
                      {
-                       int nglyphs_before
-                         = it->glyph_row->used[TEXT_AREA];
-                       int charpos
-                         = percent_position - XSTRING (elt)->data;
-                       int nwritten
-                         = display_string (spec, Qnil, elt, charpos, 0, it,
-                                           field, prec, 0, -1);
+                       int nglyphs_before, bytepos, charpos, nwritten;
+                       
+                       nglyphs_before = it->glyph_row->used[TEXT_AREA];
+                       bytepos = percent_position - XSTRING (elt)->data;
+                       charpos = (multibyte
+                                  ? string_byte_to_char (elt, bytepos)
+                                  : bytepos);
+                       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
@@ -13405,7 +13566,7 @@ display_mode_element (it, depth, field_width, precision, elt)
                  n += store_frame_title (XSTRING (tem)->data, -1, prec);
                else
                  n += display_string (NULL, tem, Qnil, 0, 0, it,
-                                      0, prec, 0, -1);
+                                      0, prec, 0, STRING_MULTIBYTE (tem));
              }
            else if (!EQ (tem, elt))
              {
@@ -13654,15 +13815,17 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
 /* Return a string for the output of a mode line %-spec for window W,
    generated by character C.  PRECISION >= 0 means don't return a
    string longer than that value.  FIELD_WIDTH > 0 means pad the
-   string returned with spaces to that value.  */
+   string returned with spaces to that value.  Return 1 in *MULTIBYTE
+   if the result is multibyte text.  */
 
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
 static char *
-decode_mode_spec (w, c, field_width, precision)
+decode_mode_spec (w, c, field_width, precision, multibyte)
      struct window *w;
      register int c;
      int field_width, precision;
+     int *multibyte;
 {
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
@@ -13670,6 +13833,7 @@ decode_mode_spec (w, c, field_width, precision)
   struct buffer *b = XBUFFER (w->buffer);
 
   obj = Qnil;
+  *multibyte = 0;
 
   switch (c)
     {
@@ -14003,7 +14167,10 @@ decode_mode_spec (w, c, field_width, precision)
     }
 
   if (STRINGP (obj))
-    return (char *) XSTRING (obj)->data;
+    {
+      *multibyte = STRING_MULTIBYTE (obj);
+      return (char *) XSTRING (obj)->data;
+    }
   else
     return "";
 }
@@ -14332,11 +14499,13 @@ display_string (string, lisp_string, face_string, face_string_pos,
 
 
 \f
-/* This is like a combination of memq and assq.  Return 1 if PROPVAL
+/* This is like a combination of memq and assq.  Return 1/2 if PROPVAL
    appears as an element of LIST or as the car of an element of LIST.
    If PROPVAL is a list, compare each element against LIST in that
-   way, and return 1 if any element of PROPVAL is found in LIST.
-   Otherwise return 0.  This function cannot quit.  */
+   way, and return 1/2 if any element of PROPVAL is found in LIST.
+   Otherwise return 0.  This function cannot quit.
+   The return value is 2 if the text is invisible but with an ellipsis
+   and 1 if it's invisible and without an ellipsis.  */
 
 int
 invisible_p (propval, list)
@@ -14352,7 +14521,7 @@ invisible_p (propval, list)
       if (EQ (propval, tem))
        return 1;
       if (CONSP (tem) && EQ (propval, XCAR (tem)))
-       return 1;
+       return NILP (XCDR (tem)) ? 1 : 2;
     }
   
   if (CONSP (propval))
@@ -14368,7 +14537,7 @@ invisible_p (propval, list)
              if (EQ (propelt, tem))
                return 1;
              if (CONSP (tem) && EQ (propelt, XCAR (tem)))
-               return 1;
+               return NILP (XCDR (tem)) ? 1 : 2;
            }
        }
     }
@@ -14376,46 +14545,6 @@ invisible_p (propval, list)
   return 0;
 }
 
-
-/* Return 1 if PROPVAL appears as the car of an element of LIST and
-   the cdr of that element is non-nil.  If PROPVAL is a list, check
-   each element of PROPVAL in that way, and the first time some
-   element is found, return 1 if the cdr of that element is non-nil.
-   Otherwise return 0.  This function cannot quit.  */
-
-int
-invisible_ellipsis_p (propval, list)
-     register Lisp_Object propval;
-     Lisp_Object list;
-{
-  register Lisp_Object tail, proptail;
-  
-  for (tail = list; CONSP (tail); tail = XCDR (tail))
-    {
-      register Lisp_Object tem;
-      tem = XCAR (tail);
-      if (CONSP (tem) && EQ (propval, XCAR (tem)))
-       return ! NILP (XCDR (tem));
-    }
-  
-  if (CONSP (propval))
-    for (proptail = propval; CONSP (proptail); proptail = XCDR (proptail))
-      {
-       Lisp_Object propelt;
-       propelt = XCAR (proptail);
-       for (tail = list; CONSP (tail); tail = XCDR (tail))
-         {
-           register Lisp_Object tem;
-           tem = XCAR (tail);
-           if (CONSP (tem) && EQ (propelt, XCAR (tem)))
-             return ! NILP (XCDR (tem));
-         }
-      }
-  
-  return 0;
-}
-
-
 \f
 /***********************************************************************
                            Initialization
@@ -14510,6 +14639,12 @@ syms_of_xdisp ()
   staticpro (&Qinhibit_menubar_update);
   Qinhibit_eval_during_redisplay = intern ("inhibit-eval-during-redisplay");
   staticpro (&Qinhibit_eval_during_redisplay);
+  Qposition = intern ("position");
+  staticpro (&Qposition);
+  Qbuffer_position = intern ("buffer-position");
+  staticpro (&Qbuffer_position);
+  Qobject = intern ("object");
+  staticpro (&Qobject);
 
   last_arrow_position = Qnil;
   last_arrow_string = Qnil;
@@ -14527,220 +14662,219 @@ syms_of_xdisp ()
   Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
   
-  DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
-    "Non-nil means highlight trailing whitespace.\n\
-The face used for trailing whitespace is `trailing-whitespace'.");
+  DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace
+    /* Non-nil means highlight trailing whitespace.
+The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
-  DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
-    "Non-nil means don't actually do any redisplay.\n\
-This is used for internal purposes.");
+  DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay
+    /* Non-nil means don't actually do any redisplay.
+This is used for internal purposes.  */);
   Vinhibit_redisplay = Qnil;
 
-  DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
-    "String (or mode line construct) included (normally) in `mode-line-format'.");
+  DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string
+    /* String (or mode line construct) included (normally) in `mode-line-format'.  */);
   Vglobal_mode_string = Qnil;
 
-  DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position,
-    "Marker for where to display an arrow on top of the buffer text.\n\
-This must be the beginning of a line in order to work.\n\
-See also `overlay-arrow-string'.");
+  DEFVAR_LISP ("overlay-arrow-position", &Voverlay_arrow_position
+    /* Marker for where to display an arrow on top of the buffer text.
+This must be the beginning of a line in order to work.
+See also `overlay-arrow-string'.  */);
   Voverlay_arrow_position = Qnil;
 
-  DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
-    "String to display as an arrow.  See also `overlay-arrow-position'.");
+  DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string
+    /* String to display as an arrow.  See also `overlay-arrow-position'.  */);
   Voverlay_arrow_string = Qnil;
 
-  DEFVAR_INT ("scroll-step", &scroll_step,
-    "*The number of lines to try scrolling a window by when point moves out.\n\
-If that fails to bring point back on frame, point is centered instead.\n\
-If this is zero, point is always centered after it moves off frame.\n\
-If you want scrolling to always be a line at a time, you should set\n\
-  `scroll-conservatively' to a large value rather than set this to 1.");
-
-  DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
-    "*Scroll up to this many lines, to bring point back on screen.\n\
-A value of zero means to scroll the text to center point vertically\n\
-in the window.");
+  DEFVAR_INT ("scroll-step", &scroll_step
+    /* *The number of lines to try scrolling a window by when point moves out.
+If that fails to bring point back on frame, point is centered instead.
+If this is zero, point is always centered after it moves off frame.
+If you want scrolling to always be a line at a time, you should set
+`scroll-conservatively' to a large value rather than set this to 1.  */);
+
+  DEFVAR_INT ("scroll-conservatively", &scroll_conservatively
+    /* *Scroll up to this many lines, to bring point back on screen.
+A value of zero means to scroll the text to center point vertically
+in the window.  */);
   scroll_conservatively = 0;
 
-  DEFVAR_INT ("scroll-margin", &scroll_margin,
-    "*Number of lines of margin at the top and bottom of a window.\n\
-Recenter the window whenever point gets within this many lines\n\
-of the top or bottom of the window.");
+  DEFVAR_INT ("scroll-margin", &scroll_margin
+    /* *Number of lines of margin at the top and bottom of a window.
+Recenter the window whenever point gets within this many lines
+of the top or bottom of the window.  */);
   scroll_margin = 0;
 
 #if GLYPH_DEBUG
-  DEFVAR_INT ("debug-end-pos", &debug_end_pos, "Don't ask");
+  DEFVAR_INT ("debug-end-pos", &debug_end_pos /* Don't ask.  */);
 #endif
 
   DEFVAR_BOOL ("truncate-partial-width-windows",
-              &truncate_partial_width_windows,
-    "*Non-nil means truncate lines in all windows less than full frame wide.");
+              &truncate_partial_width_windows
+    /* *Non-nil means truncate lines in all windows less than full frame wide.  */);
   truncate_partial_width_windows = 1;
 
-  DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
-    "nil means display the mode-line/header-line/menu-bar in the default face.\n\
-Any other value means to use the appropriate face, `mode-line',\n\
-`header-line', or `menu' respectively.\n\
-\n\
-This variable is deprecated; please change the above faces instead.");
+  DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video
+    /* nil means display the mode-line/header-line/menu-bar in the default face.
+Any other value means to use the appropriate face, `mode-line',
+`header-line', or `menu' respectively.
+
+This variable is deprecated; please change the above faces instead.  */);
   mode_line_inverse_video = 1;
 
-  DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit,
-    "*Maximum buffer size for which line number should be displayed.\n\
-If the buffer is bigger than this, the line number does not appear\n\
-in the mode line.  A value of nil means no limit.");
+  DEFVAR_LISP ("line-number-display-limit", &Vline_number_display_limit
+    /* *Maximum buffer size for which line number should be displayed.
+If the buffer is bigger than this, the line number does not appear
+in the mode line.  A value of nil means no limit.  */);
   Vline_number_display_limit = Qnil;
 
   DEFVAR_INT ("line-number-display-limit-width",
-             &line_number_display_limit_width,
-    "*Maximum line width (in characters) for line number display.\n\
-If the average length of the lines near point is bigger than this, then the\n\
-line number may be omitted from the mode line.");
+             &line_number_display_limit_width
+    /* *Maximum line width (in characters) for line number display.
+If the average length of the lines near point is bigger than this, then the
+line number may be omitted from the mode line.  */);
   line_number_display_limit_width = 200;
 
-  DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
-    "*Non-nil means highlight region even in nonselected windows.");
+  DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows
+    /* *Non-nil means highlight region even in nonselected windows.  */);
   highlight_nonselected_windows = 0;
 
-  DEFVAR_BOOL ("multiple-frames", &multiple_frames,
-    "Non-nil if more than one frame is visible on this display.\n\
-Minibuffer-only frames don't count, but iconified frames do.\n\
-This variable is not guaranteed to be accurate except while processing\n\
-`frame-title-format' and `icon-title-format'.");
-
-  DEFVAR_LISP ("frame-title-format", &Vframe_title_format,
-    "Template for displaying the title bar of visible frames.\n\
-\(Assuming the window manager supports this feature.)\n\
-This variable has the same structure as `mode-line-format' (which see),\n\
-and is used only on frames for which no explicit name has been set\n\
-\(see `modify-frame-parameters').");
-  DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
-    "Template for displaying the title bar of an iconified frame.\n\
-\(Assuming the window manager supports this feature.)\n\
-This variable has the same structure as `mode-line-format' (which see),\n\
-and is used only on frames for which no explicit name has been set\n\
-\(see `modify-frame-parameters').");
+  DEFVAR_BOOL ("multiple-frames", &multiple_frames
+    /* Non-nil if more than one frame is visible on this display.
+Minibuffer-only frames don't count, but iconified frames do.
+This variable is not guaranteed to be accurate except while processing
+`frame-title-format' and `icon-title-format'.  */);
+
+  DEFVAR_LISP ("frame-title-format", &Vframe_title_format
+    /* Template for displaying the title bar of visible frames.
+\(Assuming the window manager supports this feature.)
+This variable has the same structure as `mode-line-format' (which see),
+and is used only on frames for which no explicit name has been set
+\(see `modify-frame-parameters').  */);
+  DEFVAR_LISP ("icon-title-format", &Vicon_title_format
+    /* Template for displaying the title bar of an iconified frame.
+\(Assuming the window manager supports this feature.)
+This variable has the same structure as `mode-line-format' (which see),
+and is used only on frames for which no explicit name has been set
+\(see `modify-frame-parameters').  */);
   Vicon_title_format
     = Vframe_title_format
     = Fcons (intern ("multiple-frames"),
             Fcons (build_string ("%b"),
-                   Fcons (Fcons (build_string (""),
+                   Fcons (Fcons (empty_string,
                                  Fcons (intern ("invocation-name"),
                                         Fcons (build_string ("@"),
                                                Fcons (intern ("system-name"),
                                                               Qnil)))),
                           Qnil)));
 
-  DEFVAR_LISP ("message-log-max", &Vmessage_log_max,
-    "Maximum number of lines to keep in the message log buffer.\n\
-If nil, disable message logging.  If t, log messages but don't truncate\n\
-the buffer when it becomes large.");
+  DEFVAR_LISP ("message-log-max", &Vmessage_log_max
+    /* Maximum number of lines to keep in the message log buffer.
+If nil, disable message logging.  If t, log messages but don't truncate
+the buffer when it becomes large.  */);
   Vmessage_log_max = make_number (50);
 
-  DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions,
-    "Functions called before redisplay, if window sizes have changed.\n\
-The value should be a list of functions that take one argument.\n\
-Just before redisplay, for each frame, if any of its windows have changed\n\
-size since the last redisplay, or have been split or deleted,\n\
-all the functions in the list are called, with the frame as argument.");
+  DEFVAR_LISP ("window-size-change-functions", &Vwindow_size_change_functions
+    /* Functions called before redisplay, if window sizes have changed.
+The value should be a list of functions that take one argument.
+Just before redisplay, for each frame, if any of its windows have changed
+size since the last redisplay, or have been split or deleted,
+all the functions in the list are called, with the frame as argument.  */);
   Vwindow_size_change_functions = Qnil;
 
-  DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
-    "List of Functions to call before redisplaying a window with scrolling.\n\
-Each function is called with two arguments, the window\n\
-and its new display-start position.  Note that the value of `window-end'\n\
-is not valid when these functions are called.");
+  DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions
+    /* List of Functions to call before redisplaying a window with scrolling.
+Each function is called with two arguments, the window
+and its new display-start position.  Note that the value of `window-end'
+is not valid when these functions are called.  */);
   Vwindow_scroll_functions = Qnil;
   
-  DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p,
-    "*Non-nil means automatically resize tool-bars.\n\
-This increases a tool-bar's height if not all tool-bar items are visible.\n\
-It decreases a tool-bar's height when it would display blank lines\n\
-otherwise.");
+  DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p
+    /* *Non-nil means automatically resize tool-bars.
+This increases a tool-bar's height if not all tool-bar items are visible.
+It decreases a tool-bar's height when it would display blank lines
+otherwise.  */);
   auto_resize_tool_bars_p = 1;
   
-  DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,
-    "*Non-nil means raise tool-bar buttons when the mouse moves over them.");
+  DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p
+    /* *Non-nil means raise tool-bar buttons when the mouse moves over them.  */);
   auto_raise_tool_bar_buttons_p = 1;
 
-  DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin,
-    "*Margin around tool-bar buttons in pixels.\n\
-If an integer, use that for both horizontal and vertical margins.\n\
-Otherwise, value should be a pair of integers `(HORZ : VERT)' with\n\
-HORZ specifying the horizontal margin, and VERT specifying the\n\
-vertical margin.");
+  DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin
+    /* *Margin around tool-bar buttons in pixels.
+If an integer, use that for both horizontal and vertical margins.
+Otherwise, value should be a pair of integers `(HORZ : VERT)' with
+HORZ specifying the horizontal margin, and VERT specifying the
+vertical margin.  */);
   Vtool_bar_button_margin = make_number (DEFAULT_TOOL_BAR_BUTTON_MARGIN);
 
-  DEFVAR_INT ("tool-bar-button-relief", &tool_bar_button_relief,
-    "Relief thickness of tool-bar buttons.");
+  DEFVAR_INT ("tool-bar-button-relief", &tool_bar_button_relief
+    /* Relief thickness of tool-bar buttons.  */);
   tool_bar_button_relief = DEFAULT_TOOL_BAR_BUTTON_RELIEF;
 
-  DEFVAR_LISP ("fontification-functions", &Vfontification_functions,
-    "List of functions to call to fontify regions of text.\n\
-Each function is called with one argument POS.  Functions must\n\
-fontify a region starting at POS in the current buffer, and give\n\
-fontified regions the property `fontified'.\n\
-This variable automatically becomes buffer-local when set.");
+  DEFVAR_LISP ("fontification-functions", &Vfontification_functions
+    /* List of functions to call to fontify regions of text.
+Each function is called with one argument POS.  Functions must
+fontify a region starting at POS in the current buffer, and give
+fontified regions the property `fontified'.  */);
   Vfontification_functions = Qnil;
   Fmake_variable_buffer_local (Qfontification_functions);
 
   DEFVAR_BOOL ("unibyte-display-via-language-environment",
-               &unibyte_display_via_language_environment,
-    "*Non-nil means display unibyte text according to language environment.\n\
-Specifically this means that unibyte non-ASCII characters\n\
-are displayed by converting them to the equivalent multibyte characters\n\
-according to the current language environment.  As a result, they are\n\
-displayed according to the current fontset.");
+               &unibyte_display_via_language_environment
+    /* *Non-nil means display unibyte text according to language environment.
+Specifically this means that unibyte non-ASCII characters
+are displayed by converting them to the equivalent multibyte characters
+according to the current language environment.  As a result, they are
+displayed according to the current fontset.  */);
   unibyte_display_via_language_environment = 0;
 
-  DEFVAR_LISP ("max-mini-window-height", &Vmax_mini_window_height,
-    "*Maximum height for resizing mini-windows.\n\
-If a float, it specifies a fraction of the mini-window frame's height.\n\
-If an integer, it specifies a number of lines.");
+  DEFVAR_LISP ("max-mini-window-height", &Vmax_mini_window_height
+    /* *Maximum height for resizing mini-windows.
+If a float, it specifies a fraction of the mini-window frame's height.
+If an integer, it specifies a number of lines.  */);
   Vmax_mini_window_height = make_float (0.25);
 
-  DEFVAR_LISP ("resize-mini-windows", &Vresize_mini_windows,
-    "*How to resize mini-windows.\n\
-A value of nil means don't automatically resize mini-windows.\n\
-A value of t means resize them to fit the text displayed in them.\n\
-A value of `grow-only', the default, means let mini-windows grow\n\
-only, until their display becomes empty, at which point the windows\n\
-go back to their normal size.");
+  DEFVAR_LISP ("resize-mini-windows", &Vresize_mini_windows
+    /* *How to resize mini-windows.
+A value of nil means don't automatically resize mini-windows.
+A value of t means resize them to fit the text displayed in them.
+A value of `grow-only', the default, means let mini-windows grow
+only, until their display becomes empty, at which point the windows
+go back to their normal size.  */);
   Vresize_mini_windows = Qgrow_only;
 
   DEFVAR_BOOL ("cursor-in-non-selected-windows",
-              &cursor_in_non_selected_windows,
-    "*Non-nil means display a hollow cursor in non-selected windows.\n\
-Nil means don't display a cursor there.");
+              &cursor_in_non_selected_windows
+    /* *Non-nil means display a hollow cursor in non-selected windows.
+Nil means don't display a cursor there.  */);
   cursor_in_non_selected_windows = 1;
   
-  DEFVAR_BOOL ("automatic-hscrolling", &automatic_hscrolling_p,
-    "*Non-nil means scroll the display automatically to make point visible.");
+  DEFVAR_BOOL ("automatic-hscrolling", &automatic_hscrolling_p
+    /* *Non-nil means scroll the display automatically to make point visible.  */);
   automatic_hscrolling_p = 1;
   
-  DEFVAR_LISP ("image-types", &Vimage_types,
-    "List of supported image types.\n\
-Each element of the list is a symbol for a supported image type.");
+  DEFVAR_LISP ("image-types", &Vimage_types
+    /* List of supported image types.
+Each element of the list is a symbol for a supported image type.  */);
   Vimage_types = Qnil;
   
-  DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
-    "If non-nil, messages are truncated instead of resizing the echo area.\n\
-Bind this around calls to `message' to let it take effect.");
+  DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines
+    /* If non-nil, messages are truncated instead of resizing the echo area.
+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,
-    "Normal hook run for clicks on menu bar, before displaying a submenu.\n\
-Can be used to update submenus whose contents should vary.");
+  DEFVAR_LISP ("menu-bar-update-hook",  &Vmenu_bar_update_hook
+    /* Normal hook run for clicks on menu bar, before displaying a submenu.
+Can be used to update submenus whose contents should vary.  */);
   Vmenu_bar_update_hook = Qnil;
   
-  DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update,
-    "Non-nil means don't update menu bars.  Internal use only.");
+  DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update
+    /* Non-nil means don't update menu bars.  Internal use only.  */);
   inhibit_menubar_update = 0;
 
-  DEFVAR_BOOL ("inhibit-eval-during-redisplay", &inhibit_eval_during_redisplay,
-    "Non-nil means don't eval Lisp during redisplay.");
+  DEFVAR_BOOL ("inhibit-eval-during-redisplay", &inhibit_eval_during_redisplay
+    /* Non-nil means don't eval Lisp during redisplay.  */);
   inhibit_eval_during_redisplay = 0;
 }