]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Put doc strings in comments.
[gnu-emacs] / src / xdisp.c
index b40d944b30fa76881b689020090234a7584ca087..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)
@@ -226,6 +224,8 @@ Lisp_Object Qinhibit_point_motion_hooks;
 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.  */
 
@@ -254,6 +254,10 @@ int auto_resize_tool_bars_p;
 
 Lisp_Object Vinhibit_redisplay, Qinhibit_redisplay;
 
+/* Non-zero means Lisp evaluation during redisplay is inhibited.  */
+
+int inhibit_eval_during_redisplay;
+
 /* Names of text properties relevant for redisplay.  */
 
 Lisp_Object Qdisplay, Qrelative_width, Qalign_to;
@@ -505,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.  */
 
@@ -654,6 +663,7 @@ enum move_it_result
 \f
 /* Function prototypes.  */
 
+static void setup_for_ellipsis P_ ((struct it *));
 static void mark_window_display_accurate_1 P_ ((struct window *, int));
 static int single_display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
 static int display_prop_string_p P_ ((Lisp_Object, Lisp_Object));
@@ -674,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,
@@ -699,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 *));
@@ -720,14 +725,14 @@ 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,
                               int, int, struct it *, int, int, int, int));
 static void compute_line_metrics P_ ((struct it *));
 static void run_redisplay_end_trigger_hook P_ ((struct it *));
-static int get_overlay_strings P_ ((struct it *));
+static int get_overlay_strings P_ ((struct it *, int));
 static void next_overlay_string P_ ((struct it *));
 static void reseat P_ ((struct it *, struct text_pos, int));
 static void reseat_1 P_ ((struct it *, struct text_pos, int));
@@ -741,9 +746,9 @@ static int next_element_from_buffer P_ ((struct it *));
 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 *));
-static void init_from_display_pos P_ ((struct it *, struct window *,
-                                      struct display_pos *));
+static void load_overlay_strings P_ ((struct it *, int));
+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 *,
@@ -751,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,
@@ -769,6 +774,8 @@ static int handle_single_display_prop P_ ((struct it *, Lisp_Object,
                                           Lisp_Object, struct text_pos *,
                                           int));
 static int underlying_face_id P_ ((struct it *));
+static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *,
+                                                struct window *));
 
 #define face_before_it_pos(IT) face_before_or_after_it_pos ((IT), 1)
 #define face_after_it_pos(IT)  face_before_or_after_it_pos ((IT), 0)
@@ -1270,43 +1277,61 @@ safe_eval_handler (arg)
 
 
 /* Evaluate SEXPR and return the result, or nil if something went
-   wrong.  */
+   wrong.  Prevent redisplay during the evaluation.  */
 
 Lisp_Object
 safe_eval (sexpr)
      Lisp_Object sexpr;
 {
-  int count = BINDING_STACK_SIZE ();
-  struct gcpro gcpro1;
   Lisp_Object val;
+  
+  if (inhibit_eval_during_redisplay)
+    val = Qnil;
+  else
+    {
+      int count = BINDING_STACK_SIZE ();
+      struct gcpro gcpro1;
 
-  GCPRO1 (sexpr);
-  specbind (Qinhibit_redisplay, Qt);
-  val = internal_condition_case_1 (Feval, sexpr, Qerror, safe_eval_handler);
-  UNGCPRO;
-  return unbind_to (count, val);
+      GCPRO1 (sexpr);
+      specbind (Qinhibit_redisplay, Qt);
+      val = internal_condition_case_1 (Feval, sexpr, Qerror,
+                                      safe_eval_handler);
+      UNGCPRO;
+      val = unbind_to (count, val);
+    }
+  
+  return val;
 }
 
 
 /* Call function ARGS[0] with arguments ARGS[1] to ARGS[NARGS - 1].
-   Return the result, or nil if something went wrong.  */
+   Return the result, or nil if something went wrong.  Prevent
+   redisplay during the evaluation.  */
 
 Lisp_Object
 safe_call (nargs, args)
      int nargs;
      Lisp_Object *args;
 {
-  int count = BINDING_STACK_SIZE ();
   Lisp_Object val;
-  struct gcpro gcpro1;
+  
+  if (inhibit_eval_during_redisplay)
+    val = Qnil;
+  else
+    {
+      int count = BINDING_STACK_SIZE ();
+      struct gcpro gcpro1;
 
-  GCPRO1 (args[0]);
-  gcpro1.nvars = nargs;
-  specbind (Qinhibit_redisplay, Qt);
-  val = internal_condition_case_2 (Ffuncall, nargs, args, Qerror,
-                                  safe_eval_handler);
-  UNGCPRO;
-  return unbind_to (count, val);
+      GCPRO1 (args[0]);
+      gcpro1.nvars = nargs;
+      specbind (Qinhibit_redisplay, Qt);
+      val = internal_condition_case_2 (Ffuncall, nargs, args, Qerror,
+                                      safe_eval_handler);
+      UNGCPRO;
+      val = unbind_to (count, val);
+    }
+
+  return val;
 }
 
 
@@ -1403,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.
@@ -1429,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
@@ -1509,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);
 
@@ -1646,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;
@@ -1674,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
@@ -1712,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;
            }
 
@@ -1721,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
@@ -1740,18 +1762,17 @@ start_display (it, w, pos)
 }
 
 
-/* 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.  */
+/* Return 1 if POS is a position in ellipses displayed for invisible
+   text.  W is the window we display, for text property lookup.  */
 
-static void
-init_from_display_pos (it, w, pos)
-     struct it *it;
-     struct window *w;
+static int
+in_ellipses_for_invisible_text_p (pos, w)
      struct display_pos *pos;
+     struct window *w;
 {
-  int charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
   Lisp_Object prop, window;
+  int ellipses_p = 0;
+  int charpos = CHARPOS (pos->pos);
   
   /* If POS specifies a position in a display vector, this might
      be for an ellipsis displayed for invisible text.  We won't
@@ -1764,16 +1785,39 @@ init_from_display_pos (it, w, pos)
       && (XSETWINDOW (window, w),
          prop = Fget_char_property (make_number (charpos),
                                     Qinvisible, window),
-         NILP (prop)))
+         !TEXT_PROP_MEANS_INVISIBLE (prop)))
     {
       prop = Fget_char_property (make_number (charpos - 1), Qinvisible,
                                 window);
-      if (TEXT_PROP_MEANS_INVISIBLE (prop)
-         && TEXT_PROP_MEANS_INVISIBLE_WITH_ELLIPSIS (prop))
-       {
-         --charpos;
-         bytepos = 0;
-       }
+      ellipses_p = 2 == TEXT_PROP_MEANS_INVISIBLE (prop);
+    }
+
+  return ellipses_p;
+}
+
+
+/* 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.  Value
+   is zero if there are overlay strings with newlines at POS.  */
+
+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
+     get the iterator set up for delivering that ellipsis unless
+     we make sure that it gets aware of the invisible text.  */
+  if (in_ellipses_for_invisible_text_p (pos, w))
+    {
+      --charpos;
+      bytepos = 0;
     }
     
   /* Keep in mind: the call to reseat in init_iterator skips invisible
@@ -1786,13 +1830,34 @@ init_from_display_pos (it, w, pos)
      but the call to init_iterator below will move us to the
      after-string.  */
   init_iterator (it, w, charpos, bytepos, NULL, DEFAULT_FACE_ID);
-  xassert (IT_CHARPOS (*it) == CHARPOS (pos->pos));
 
-  /* If position is within an overlay string, set up IT to
-     the right overlay string.  */
+  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)
     {
       int relative_index;
+
+      /* If the first overlay string happens to have a `display'
+        property for an image, the iterator will be set up for that
+        image, and we have to undo that setup first before we can
+        correct the overlay string index.  */
+      if (it->method == next_element_from_image)
+       pop_it (it);
       
       /* We already have the first chunk of overlay strings in
         IT->overlay_strings.  Load more until the one for
@@ -1803,7 +1868,7 @@ init_from_display_pos (it, w, pos)
          it->current.overlay_string_index = 0;
          while (n--)
            {
-             load_overlay_strings (it);
+             load_overlay_strings (it, 0);
              it->current.overlay_string_index += OVERLAY_STRING_CHUNK_SIZE;
            }
        }
@@ -1816,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
@@ -1829,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)
     {
@@ -1848,20 +1919,9 @@ init_from_display_pos (it, w, pos)
       xassert (it->dpvec && it->current.dpvec_index == 0);
       it->current.dpvec_index = pos->dpvec_index;
     }
-  else if (it->current.dpvec_index >= 0)
-    {
-      /* I don't think this can happen, just being paranoid...  */
-      it->dpvec = NULL;
-      it->current.dpvec_index = -1;
-      if (it->s)
-       it->method = next_element_from_c_string;
-      else if (STRINGP (it->string))
-       it->method = next_element_from_string;
-      else
-       it->method = next_element_from_buffer;
-    }
   
   CHECK_IT (it);
+  return !overlay_strings_with_newlines;
 }
 
 
@@ -1881,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;
 }
 
 
@@ -2133,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);
@@ -2498,21 +2565,22 @@ handle_invisible_prop (it)
     }
   else
     {
-      int visible_p, newpos, next_stop;
-      Lisp_Object pos, prop;
+      int invis_p, newpos, next_stop, start_charpos;
+      Lisp_Object pos, prop, overlay;
 
       /* First of all, is there invisible text at this position?  */
+      start_charpos = IT_CHARPOS (*it);
       pos = make_number (IT_CHARPOS (*it));
-      prop = Fget_char_property (pos, Qinvisible, it->window);
-      
+      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;
          
@@ -2532,56 +2600,45 @@ 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;
          IT_BYTEPOS (*it) = CHAR_TO_BYTE (newpos);
          
-         /* Maybe return `...' next for the end of the invisible text.  */
-         if (display_ellipsis_p)
+         /* If there are before-strings at the start of invisible
+            text, and the text is invisible because of a text
+            property, arrange to show before-strings because 20.x did
+            it that way.  (If the text is invisible because of an
+            overlay property instead of a text property, this is
+            already handled in the overlay code.)  */
+         if (NILP (overlay)
+             && get_overlay_strings (it, start_charpos))
            {
-             if (it->dp 
-                 && VECTORP (DISP_INVIS_VECTOR (it->dp)))
-               {
-                 struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
-                 it->dpvec = v->contents;
-                 it->dpend = v->contents + v->size;
-               }
-             else 
-               {
-                 /* Default `...'.  */
-                 it->dpvec = default_invis_vector;
-                 it->dpend = default_invis_vector + 3;
-               }
-
-             /* The ellipsis display does not replace the display of
-                the character at the new position.  Indicate this by
-                setting IT->dpvec_char_len to zero.  */
-             it->dpvec_char_len = 0;
-             
-             it->current.dpvec_index = 0;
-             it->method = next_element_from_display_vector;
+             handled = HANDLED_RECOMPUTE_PROPS;
+             it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p;
            }
+         else if (display_ellipsis_p)
+           setup_for_ellipsis (it);
        }
     }
 
@@ -2589,6 +2646,36 @@ handle_invisible_prop (it)
 }
 
 
+/* Make iterator IT return `...' next.  */
+
+static void
+setup_for_ellipsis (it)
+     struct it *it;
+{
+  if (it->dp 
+      && VECTORP (DISP_INVIS_VECTOR (it->dp)))
+    {
+      struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
+      it->dpvec = v->contents;
+      it->dpend = v->contents + v->size;
+    }
+  else 
+    {
+      /* Default `...'.  */
+      it->dpvec = default_invis_vector;
+      it->dpend = default_invis_vector + 3;
+    }
+  
+  /* The ellipsis display does not replace the display of the
+     character at the new position.  Indicate this by setting
+     IT->dpvec_char_len to zero.  */
+  it->dpvec_char_len = 0;
+  
+  it->current.dpvec_index = 0;
+  it->method = next_element_from_display_vector;
+}
+
+
 \f
 /***********************************************************************
                            'display' property
@@ -2633,10 +2720,17 @@ handle_display_prop (it)
     return HANDLED_NORMALLY;
 
   if (CONSP (prop)
-      && CONSP (XCAR (prop))
-      && !EQ (Qmargin, XCAR (XCAR (prop))))
+      /* Simple properties.  */
+      && !EQ (XCAR (prop), Qimage)
+      && !EQ (XCAR (prop), Qspace)
+      && !EQ (XCAR (prop), Qwhen)
+      && !EQ (XCAR (prop), Qspace_width)
+      && !EQ (XCAR (prop), Qheight)
+      && !EQ (XCAR (prop), Qraise)
+      /* Marginal area specifications.  */
+      && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
+      && !NILP (XCAR (prop)))
     {
-      /* A list of sub-properties.  */
       for (; CONSP (prop); prop = XCDR (prop))
        {
          if (handle_single_display_prop (it, XCAR (prop), object,
@@ -2726,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))
@@ -3141,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)
@@ -3154,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);
        }
     }
 
@@ -3245,7 +3335,7 @@ static enum prop_handled
 handle_overlay_change (it)
      struct it *it;
 {
-  if (!STRINGP (it->string) && get_overlay_strings (it))
+  if (!STRINGP (it->string) && get_overlay_strings (it, 0))
     return HANDLED_RECOMPUTE_PROPS;
   else
     return HANDLED_NORMALLY;
@@ -3269,6 +3359,8 @@ next_overlay_string (it)
       /* No more overlay strings.  Restore IT's settings to what
         they were before overlay strings were processed, and
         continue to deliver from current_buffer.  */
+      int display_ellipsis_p = it->stack[it->sp - 1].display_ellipsis_p;
+      
       pop_it (it);
       xassert (it->stop_charpos >= BEGV
               && it->stop_charpos <= it->end_charpos);
@@ -3283,6 +3375,11 @@ next_overlay_string (it)
         next_element_from_buffer doesn't try it again.  */
       if (IT_CHARPOS (*it) >= it->end_charpos)
        it->overlay_strings_at_end_processed_p = 1;
+
+      /* If we have to display `...' for invisible text, set
+        the iterator up for that.  */
+      if (display_ellipsis_p)
+       setup_for_ellipsis (it);
     }
   else
     {
@@ -3293,7 +3390,7 @@ next_overlay_string (it)
       int i = it->current.overlay_string_index % OVERLAY_STRING_CHUNK_SIZE;
   
       if (it->current.overlay_string_index && i == 0)
-       load_overlay_strings (it);
+       load_overlay_strings (it, 0);
 
       /* Initialize IT to deliver display elements from the overlay
          string.  */
@@ -3353,8 +3450,8 @@ compare_overlay_entries (e1, e2)
 
 
 /* Load the vector IT->overlay_strings with overlay strings from IT's
-   current buffer position.  Set IT->n_overlays to the total number of
-   overlay strings found.  
+   current buffer position, or from CHARPOS if that is > 0.  Set
+   IT->n_overlays to the total number of overlay strings found.
 
    Overlay strings are processed OVERLAY_STRING_CHUNK_SIZE strings at
    a time.  On entry into load_overlay_strings,
@@ -3377,8 +3474,9 @@ compare_overlay_entries (e1, e2)
    compare_overlay_entries.  */
    
 static void
-load_overlay_strings (it)
+load_overlay_strings (it, charpos)
      struct it *it;
+     int charpos;
 {
   extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority;
   Lisp_Object ov, overlay, window, str, invisible;
@@ -3387,7 +3485,9 @@ load_overlay_strings (it)
   int n = 0, i, j, invis_p;
   struct overlay_entry *entries
     = (struct overlay_entry *) alloca (size * sizeof *entries);
-  int charpos = IT_CHARPOS (*it);
+
+  if (charpos <= 0)
+    charpos = IT_CHARPOS (*it);
 
   /* Append the overlay string STRING of overlay OVERLAY to vector
      `entries' which has size `size' and currently contains `n'
@@ -3519,12 +3619,13 @@ load_overlay_strings (it)
 
 
 /* Get the first chunk of overlay strings at IT's current buffer
-   position.  Value is non-zero if at least one overlay string was
-   found.   */
+   position, or at CHARPOS if that is > 0.  Value is non-zero if at
+   least one overlay string was found.  */
 
 static int
-get_overlay_strings (it)
+get_overlay_strings (it, charpos)
      struct it *it;
+     int charpos;
 {
   /* Get the first OVERLAY_STRING_CHUNK_SIZE overlay strings to
      process.  This fills IT->overlay_strings with strings, and sets
@@ -3534,7 +3635,7 @@ get_overlay_strings (it)
      when no overlay strings are found because a zero value would
      indicate a position in the first overlay string.  */
   it->current.overlay_string_index = 0;
-  load_overlay_strings (it);
+  load_overlay_strings (it, charpos);
 
   /* If we found overlay strings, set up IT to deliver display
      elements from the first one.  Otherwise set up IT to deliver
@@ -3555,8 +3656,9 @@ get_overlay_strings (it)
       /* Set up IT to deliver display elements from the first overlay
         string.  */
       IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
-      it->stop_charpos = 0;
       it->string = it->overlay_strings[0];
+      it->stop_charpos = 0;
+      it->end_charpos = XSTRING (it->string)->size;
       it->multibyte_p = STRING_MULTIBYTE (it->string);
       xassert (STRINGP (it->string));
       it->method = next_element_from_string;
@@ -3607,6 +3709,7 @@ push_it (it)
   p->font_height = it->font_height;
   p->voffset = it->voffset;
   p->string_from_display_prop_p = it->string_from_display_prop_p;
+  p->display_ellipsis_p = 0;
   ++it->sp;
 }
 
@@ -3926,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;
 
@@ -3972,7 +4076,8 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
   it->current.dpvec_index = -1;
   xassert (charpos >= 0);
   
-  /* Use the setting of MULTIBYTE if specified.  */
+  /* If STRING is specified, use its multibyteness, otherwise use the
+     setting of MULTIBYTE, if specified.  */
   if (multibyte >= 0)
     it->multibyte_p = multibyte > 0;
   
@@ -4151,7 +4256,22 @@ get_next_display_element (it)
                  if (SINGLE_BYTE_CHAR_P (it->c))
                    str[0] = it->c, len = 1;
                  else
-                   len = CHAR_STRING (it->c, str);
+                   {
+                     len = CHAR_STRING_NO_SIGNAL (it->c, str);
+                     if (len < 0)
+                       {
+                         /* It's an invalid character, which
+                            shouldn't happen actually, but due to
+                            bugs it may happen.  Let's print the char
+                            as is, there's not much meaningful we can
+                            do with it.  */
+                         str[0] = it->c;
+                         str[1] = it->c >> 8;
+                         str[2] = it->c >> 16;
+                         str[3] = it->c >> 24;
+                         len = 4;
+                       }
+                   }
 
                  for (i = 0; i < len; i++)
                    {
@@ -4334,6 +4454,8 @@ set_iterator_to_next (it, reseat_p)
              pop_it (it);
              if (!STRINGP (it->string))
                it->method = next_element_from_buffer;
+             else
+               goto consider_string_end;
            }
        }
     }
@@ -4658,7 +4780,7 @@ next_element_from_buffer (it)
          else
            {
              it->overlay_strings_at_end_processed_p = 1;
-             overlay_strings_follow_p = get_overlay_strings (it);
+             overlay_strings_follow_p = get_overlay_strings (it, 0);
            }
 
          if (overlay_strings_follow_p)
@@ -5375,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)
@@ -5421,6 +5547,12 @@ add_to_log (format, arg1, arg2)
   int len;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
+  /* Do nothing if called asynchronously.  Inserting text into
+     a buffer may call after-change-functions and alike and
+     that would means running Lisp asynchronously.  */
+  if (handling_signal)
+    return;
+
   fmt = msg = Qnil;
   GCPRO4 (fmt, msg, arg1, arg2);
   
@@ -5431,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;
@@ -6096,6 +6228,11 @@ with_echo_area_buffer (w, which, fn, a1, a2, a3, a4)
 
   buffer = echo_area_buffer[this_one];
 
+  /* Don't get confused by reusing the buffer used for echoing
+     for a different purpose.  */
+  if (echo_kboard == NULL && EQ (buffer, echo_message_buffer))
+    cancel_echoing ();
+
   record_unwind_protect (unwind_with_echo_area_buffer,
                         with_echo_area_buffer_unwind_data (w));
 
@@ -6116,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);
@@ -6343,19 +6481,26 @@ 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_axactly ()
+resize_echo_area_exactly ()
 {
   if (BUFFERP (echo_area_buffer[0])
       && WINDOWP (echo_area_window))
     {
       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;
@@ -6367,17 +6512,18 @@ resize_echo_area_axactly ()
 
 
 /* Callback function for with_echo_area_buffer, when used from
-   resize_echo_area_axactly.  A1 contains a pointer to the window to
-   resize, A2 to A4 are not used.  Value is what resize_mini_window
-   returns.  */
+   resize_echo_area_exactly.  A1 contains a pointer to the window to
+   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));
 }
 
 
@@ -6396,6 +6542,15 @@ resize_mini_window (w, exact_p)
 
   xassert (MINI_WINDOW_P (w));
 
+  /* Don't resize windows while redisplaying a window; it would
+     confuse redisplay functions when the size of the window they are
+     displaying changes from under them.  Such a resizing can happen,
+     for instance, when which-func prints a long message while
+     we are running fontification-functions.  We're running these
+     functions with safe_call which binds inhibit-redisplay to t.  */
+  if (!NILP (Vinhibit_redisplay))
+    return 0;
+  
   /* Nil means don't try to resize.  */
   if (NILP (Vresize_mini_windows)
       || (FRAME_X_P (f) && f->output_data.x == NULL))
@@ -6421,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
@@ -6774,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;
@@ -7634,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;
@@ -7830,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)
@@ -8030,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;
@@ -8049,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.  */
@@ -8087,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.  */
 
@@ -8285,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;
@@ -8871,6 +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;
     }
 }
@@ -9086,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;
 {
@@ -9099,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);
@@ -9107,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))
     {
@@ -9136,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;
 }
 
 
@@ -9154,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)
@@ -9243,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
@@ -9266,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;
@@ -9300,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);
@@ -9320,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;
@@ -9333,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
     {
@@ -9348,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;
@@ -9432,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)
@@ -9448,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.  */
@@ -9490,7 +9716,7 @@ try_cursor_movement (window, startp, scroll_step)
          || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
     {
       int this_scroll_margin;
-      struct glyph_row *row;
+      struct glyph_row *row = NULL;
 
 #if GLYPH_DEBUG
       debug_method_add (w, "cursor movement");
@@ -9506,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;
@@ -9599,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
@@ -9614,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;
            }
        }
     }
@@ -9705,6 +9933,8 @@ redisplay_window (window, just_this_one_p)
            blank_row (w, row, y);
          goto finish_scroll_bars;
        }
+
+      clear_glyph_matrix (w->desired_matrix);
     }
 
   /* Otherwise set up data on this window; select its buffer and point
@@ -9901,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
@@ -9916,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.  */
@@ -9935,43 +10176,17 @@ redisplay_window (window, just_this_one_p)
       goto recenter;
     }
   
-  /* Try scrolling with try_window_id.  */
-  else if (/* Windows and buffers haven't changed.  */
-          !windows_or_buffers_changed
-          /* Window must be either use window-based redisplay or
-             be full width.  */
-          && (FRAME_WINDOW_P (f)
-              || (line_ins_del_ok && WINDOW_FULL_WIDTH_P (w)))
-          && !MINI_WINDOW_P (w)
-          /* Point is not known NOT to appear in window.  */
-          && PT >= CHARPOS (startp)
-          && XFASTINT (w->last_modified)
-          /* Window is not hscrolled.  */
-          && XFASTINT (w->hscroll) == 0
-          /* Selective display has not changed.  */
-          && !current_buffer->clip_changed
-          /* Current matrix is up to date.  */
-          && !NILP (w->window_end_valid)
-          /* Can't use this case if highlighting a region because
-             a cursor movement will do more than just set the cursor.  */
-          && !(!NILP (Vtransient_mark_mode)
-               && !NILP (current_buffer->mark_active))
-          && NILP (w->region_showing)
-          && NILP (Vshow_trailing_whitespace)
-          /* Overlay arrow position and string not changed.  */
-          && EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
-          && EQ (last_arrow_string, Voverlay_arrow_string)
-          /* Value is > 0 if update has been done, it is -1 if we
-             know that the same window start will not work.  It is 0
-             if unsuccessful for some other reason.  */
-          && (tem = try_window_id (w)) != 0)
+  /* Try scrolling with try_window_id.  Value is > 0 if update has
+     been done, it is -1 if we know that the same window start will
+     not work.  It is 0 if unsuccessful for some other reason.  */
+  else if ((tem = try_window_id (w)) != 0)
     {
 #if GLYPH_DEBUG
       debug_method_add (w, "try_window_id %d", tem);
 #endif
 
       if (fonts_changed_p)
-       goto finish_scroll_bars;
+       goto need_larger_matrices;
       if (tem > 0)
        goto done;
 
@@ -10006,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)
        {
@@ -10016,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
@@ -10051,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 */
@@ -10075,7 +10301,7 @@ redisplay_window (window, just_this_one_p)
   /* Move backward half the height of the window.  */
   init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
   it.current_y = it.last_visible_y;
-  move_it_vertically_backward (&it, it.last_visible_y / 2);
+  move_it_vertically_backward (&it, window_box_height (w) / 2);
   xassert (IT_CHARPOS (it) >= BEGV);
 
   /* The function move_it_vertically_backward may move over more
@@ -10115,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.
@@ -10155,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:
 
@@ -10182,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.  */
@@ -10211,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
@@ -10251,6 +10472,8 @@ redisplay_window (window, just_this_one_p)
 #endif
     }
 
+ need_larger_matrices:
+  ;
  finish_scroll_bars:
 
   if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
@@ -10388,7 +10611,7 @@ try_window_reusing_current_matrix (w)
   struct glyph_row *last_reused_text_row;
   struct glyph_row *start_row;
   int start_vpos, min_y, max_y;
-  
+
   if (/* This function doesn't handle terminal frames.  */
       !FRAME_WINDOW_P (f)
       /* Don't try to reuse the display if windows have been split
@@ -10427,6 +10650,13 @@ try_window_reusing_current_matrix (w)
     {
       int first_row_y;
       
+      /* Don't use this method if the display starts with an ellipsis
+        displayed for invisible text.  It's not easy to handle that case
+        below, and it's certainly not worth the effort since this is
+        not a frequent case.  */
+      if (in_ellipses_for_invisible_text_p (&start_row->start, w))
+       return 0;
+
       IF_DEBUG (debug_method_add (w, "twu1"));
       
       /* Display up to a row that can be reused.  The variable
@@ -10460,7 +10690,8 @@ try_window_reusing_current_matrix (w)
              row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
              while (MATRIX_ROW_DISPLAYS_TEXT_P (row))
                {
-                 if (cursor_row_p (w, row))
+                 if (PT >= MATRIX_ROW_START_CHARPOS (row)
+                     && PT < MATRIX_ROW_END_CHARPOS (row))
                    {
                      set_cursor_from_row (w, row, w->current_matrix, 0, 0,
                                           dy, nrows_scrolled);
@@ -10522,14 +10753,12 @@ try_window_reusing_current_matrix (w)
               ++row)
            {
              row->y = it.current_y;
+             row->visible_height = row->height;
 
              if (row->y < min_y)
-               row->visible_height = row->height - (min_y - row->y);
-             else if (row->y + row->height > max_y)
-               row->visible_height
-                 = row->height - (row->y + row->height - max_y);
-             else
-               row->visible_height = row->height;
+               row->visible_height -= min_y - row->y;
+             if (row->y + row->height > max_y)
+               row->visible_height -= row->y + row->height - max_y;
              
              it.current_y += row->height;
 
@@ -10617,13 +10846,15 @@ try_window_reusing_current_matrix (w)
           MATRIX_ROW_BOTTOM_Y (first_row_to_display) < yb;
           ++first_row_to_display)
        {
-         if (cursor_row_p (w, first_row_to_display))
+         if (PT >= MATRIX_ROW_START_CHARPOS (first_row_to_display)
+             && PT < MATRIX_ROW_END_CHARPOS (first_row_to_display))
            pt_row = first_row_to_display;
        }
 
       /* Start displaying at the start of first_row_to_display.  */
       xassert (first_row_to_display->y < yb);
       init_to_row_start (&it, w, first_row_to_display);
+
       nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix)
                        - start_vpos);
       it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
@@ -10682,13 +10913,11 @@ try_window_reusing_current_matrix (w)
       for (row = first_reusable_row; row < first_row_to_display; ++row)
        {
          row->y -= dy;
+         row->visible_height = row->height;
          if (row->y < min_y)
-           row->visible_height = row->height - (min_y - row->y);
-         else if (row->y + row->height > max_y)
-           row->visible_height
-             = row->height - (row->y + row->height - max_y);
-         else
-           row->visible_height = row->height;
+           row->visible_height -= min_y - row->y;
+         if (row->y + row->height > max_y)
+           row->visible_height -= row->y + row->height - max_y;
        }
 
       /* Scroll the current matrix.  */
@@ -10778,15 +11007,14 @@ find_last_row_displaying_text (matrix, it, start)
 
 
 /* Return the last row in the current matrix of W that is not affected
-   by changes at the start of current_buffer that occurred since the
-   last time W was redisplayed.  Value is null if no such row exists.
+   by changes at the start of current_buffer that occurred since W's
+   current matrix was built.  Value is null if no such row exists.
 
-   The global variable beg_unchanged has to contain the number of
-   bytes unchanged at the start of current_buffer.  BEG +
-   beg_unchanged is the buffer position of the first changed byte in
-   current_buffer.  Characters at positions < BEG + beg_unchanged are
-   at the same buffer positions as they were when the current matrix
-   was built.  */
+   BEG_UNCHANGED us the number of characters unchanged at the start of
+   current_buffer.  BEG + BEG_UNCHANGED is the buffer position of the
+   first changed character in current_buffer.  Characters at positions <
+   BEG + BEG_UNCHANGED are at the same buffer positions as they were
+   when the current matrix was built.  */
 
 static struct glyph_row *
 find_last_unchanged_at_beg_row (w)
@@ -10827,12 +11055,16 @@ find_last_unchanged_at_beg_row (w)
 
 
 /* Find the first glyph row in the current matrix of W that is not
-   affected by changes at the end of current_buffer since the last
-   time the window was redisplayed.  Return in *DELTA the number of
-   chars by which buffer positions in unchanged text at the end of
-   current_buffer must be adjusted.  Return in *DELTA_BYTES the
-   corresponding number of bytes.  Value is null if no such row
-   exists, i.e. all rows are affected by changes.  */
+   affected by changes at the end of current_buffer since the 
+   time W's current matrix was built.
+
+   Return in *DELTA the number of chars by which buffer positions in
+   unchanged text at the end of current_buffer must be adjusted.
+   
+   Return in *DELTA_BYTES the corresponding number of bytes.
+
+   Value is null if no such row exists, i.e. all rows are affected by
+   changes.  */
    
 static struct glyph_row *
 find_first_unchanged_at_end_row (w, delta, delta_bytes)
@@ -10877,8 +11109,8 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes)
 
       /* Set last_unchanged_pos to the buffer position of the last
         character in the buffer that has not been changed.  Z is the
-        index + 1 of the last byte in current_buffer, i.e. by
-        subtracting end_unchanged we get the index of the last
+        index + 1 of the last character in current_buffer, i.e. by
+        subtracting END_UNCHANGED we get the index of the last
         unchanged character, and we have to add BEG to get its buffer
         position.  */
       last_unchanged_pos = Z - END_UNCHANGED + BEG;
@@ -10950,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;
@@ -11025,8 +11257,6 @@ row_containing_pos (w, charpos, start, end)
 
    7. Update W's window end information.  */
 
-  /* Check that window end is what we expect it to be.  */
-
 static int
 try_window_id (w)
      struct window *w;
@@ -11046,15 +11276,78 @@ try_window_id (w)
   int first_unchanged_at_end_vpos = 0;
   struct glyph_row *last_text_row, *last_text_row_at_end;
   struct text_pos start;
+  int first_changed_charpos, last_changed_charpos;
 
+  /* This is handy for debugging.  */
+#if 0
+#define GIVE_UP(X)                                             \
+  do {                                                         \
+    fprintf (stderr, "try_window_id give up %d\n", (X));       \
+    return 0;                                                  \
+  } while (0)
+#else
+#define GIVE_UP(X) return 0
+#endif
+  
   SET_TEXT_POS_FROM_MARKER (start, w->start);
 
-  /* Check pre-conditions.  Window end must be valid, otherwise
-     the current matrix would not be up to date.  */
-  xassert (!NILP (w->window_end_valid));
-  xassert (FRAME_WINDOW_P (XFRAME (w->frame))
-          || (line_ins_del_ok && WINDOW_FULL_WIDTH_P (w)));
+  /* Don't use this for mini-windows because these can show
+     messages and mini-buffers, and we don't handle that here.  */
+  if (MINI_WINDOW_P (w))
+    GIVE_UP (1);
+  
+  /* This flag is used to prevent redisplay optimizations.  */
+  if (windows_or_buffers_changed)
+    GIVE_UP (2);
+  
+  /* Verify that narrowing has not changed.  This flag is also set to prevent
+     redisplay optimizations.  It would be nice to further
+     reduce the number of cases where this prevents try_window_id.  */
+  if (current_buffer->clip_changed)
+    GIVE_UP (3);
+
+  /* Window must either use window-based redisplay or be full width.  */
+  if (!FRAME_WINDOW_P (f)
+      && (!line_ins_del_ok
+         || !WINDOW_FULL_WIDTH_P (w)))
+    GIVE_UP (4);
+
+  /* Give up if point is not known NOT to appear in W.  */
+  if (PT < CHARPOS (start))
+    GIVE_UP (5);
+
+  /* Another way to prevent redisplay optimizations.  */
+  if (XFASTINT (w->last_modified) == 0)
+    GIVE_UP (6);
+  
+  /* Verify that window is not hscrolled.  */
+  if (XFASTINT (w->hscroll) != 0)
+    GIVE_UP (7);
+  
+  /* Verify that display wasn't paused.  */
+  if (NILP (w->window_end_valid))
+    GIVE_UP (8);
+  
+  /* Can't use this if highlighting a region because a cursor movement
+     will do more than just set the cursor.  */
+  if (!NILP (Vtransient_mark_mode)
+      && !NILP (current_buffer->mark_active))
+    GIVE_UP (9);
+
+  /* Likewise if highlighting trailing whitespace.  */
+  if (!NILP (Vshow_trailing_whitespace))
+    GIVE_UP (11);
+  
+  /* Likewise if showing a region.  */
+  if (!NILP (w->region_showing))
+    GIVE_UP (10);
+  
+  /* Can use this if overlay arrow position and or string have changed.  */
+  if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
+      || !EQ (last_arrow_string, Voverlay_arrow_string))
+    GIVE_UP (12);
 
+  
   /* Make sure beg_unchanged and end_unchanged are up to date.  Do it
      only if buffer has really changed.  The reason is that the gap is
      initially at Z for freshly visited files.  The code below would
@@ -11069,73 +11362,119 @@ try_window_id (w)
        END_UNCHANGED = Z - GPT;
     }
 
+  /* The position of the first and last character that has been changed.  */
+  first_changed_charpos = BEG + BEG_UNCHANGED;
+  last_changed_charpos  = Z - END_UNCHANGED;
+
   /* If window starts after a line end, and the last change is in
      front of that newline, then changes don't affect the display.
      This case happens with stealth-fontification.  Note that although
      the display is unchanged, glyph positions in the matrix have to
      be adjusted, of course.  */
   row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
-  if (CHARPOS (start) > BEGV
-      && Z - END_UNCHANGED < CHARPOS (start) - 1
-      && FETCH_BYTE (BYTEPOS (start) - 1) == '\n'
-      && PT < MATRIX_ROW_END_CHARPOS (row))
+  if (MATRIX_ROW_DISPLAYS_TEXT_P (row)
+      && ((last_changed_charpos < CHARPOS (start)
+          && CHARPOS (start) == BEGV)
+         || (last_changed_charpos < CHARPOS (start) - 1
+             && FETCH_BYTE (BYTEPOS (start) - 1) == '\n')))
+    {
+      int Z_old, delta, Z_BYTE_old, delta_bytes;
+      struct glyph_row *r0;
+
+      /* Compute how many chars/bytes have been added to or removed
+        from the buffer.  */
+      Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
+      Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
+      delta = Z - Z_old;
+      delta_bytes = Z_BYTE - Z_BYTE_old;
+         
+      /* Give up if PT is not in the window.  Note that it already has
+        been checked at the start of try_window_id that PT is not in
+        front of the window start.  */
+      if (PT >= MATRIX_ROW_END_CHARPOS (row) + delta)
+       GIVE_UP (13);
+
+      /* If window start is unchanged, we can reuse the whole matrix
+        as is, after adjusting glyph positions.  No need to compute
+        the window end again, since its offset from Z hasn't changed.  */
+      r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
+      if (CHARPOS (start) == MATRIX_ROW_START_CHARPOS (r0) + delta
+         && BYTEPOS (start) == MATRIX_ROW_START_BYTEPOS (r0) + delta_bytes)
+       {
+         /* Adjust positions in the glyph matrix.  */
+         if (delta || delta_bytes)
+           {
+             struct glyph_row *r1
+               = MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
+             increment_matrix_positions (w->current_matrix,
+                                         MATRIX_ROW_VPOS (r0, current_matrix),
+                                         MATRIX_ROW_VPOS (r1, current_matrix),
+                                         delta, delta_bytes);
+           }
+      
+         /* Set the cursor.  */
+         row = row_containing_pos (w, PT, r0, NULL);
+         set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
+         return 1;
+       }
+    }
+
+  /* Handle the case that changes are all below what is displayed in
+     the window, and that PT is in the window.  This shortcut cannot
+     be taken if ZV is visible in the window, and text has been added
+     there that is visible in the window.  */
+  if (first_changed_charpos >= MATRIX_ROW_END_CHARPOS (row)
+      /* ZV is not visible in the window, or there are no
+        changes at ZV, actually.  */
+      && (current_matrix->zv > MATRIX_ROW_END_CHARPOS (row)
+         || first_changed_charpos == last_changed_charpos))
     {
-      struct glyph_row *r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
-      int delta = CHARPOS (start) - MATRIX_ROW_START_CHARPOS (r0);
+      struct glyph_row *r0;
+
+      /* Give up if PT is not in the window.  Note that it already has
+        been checked at the start of try_window_id that PT is not in
+        front of the window start.  */
+      if (PT >= MATRIX_ROW_END_CHARPOS (row))
+       GIVE_UP (14);
 
-      if (delta)
+      /* If window start is unchanged, we can reuse the whole matrix
+        as is, without changing glyph positions since no text has
+        been added/removed in front of the window end.  */
+      r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
+      if (TEXT_POS_EQUAL_P (start, r0->start.pos))
        {
-         struct glyph_row *r1 = MATRIX_BOTTOM_TEXT_ROW (current_matrix, w);
-         int delta_bytes = BYTEPOS (start) - MATRIX_ROW_START_BYTEPOS (r0);
+         /* We have to compute the window end anew since text
+            can have been added/removed after it.  */
+         w->window_end_pos
+           = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
+         w->window_end_bytepos
+           = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
 
-         increment_matrix_positions (w->current_matrix,
-                                     MATRIX_ROW_VPOS (r0, current_matrix),
-                                     MATRIX_ROW_VPOS (r1, current_matrix),
-                                     delta, delta_bytes);
+         /* Set the cursor.  */
+         row = row_containing_pos (w, PT, r0, NULL);
+         set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
+         return 2;
        }
-      
-#if 0  /* If changes are all in front of the window start, the
-         distance of the last displayed glyph from Z hasn't
-         changed.  */
-      w->window_end_pos
-       = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
-      w->window_end_bytepos
-       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
-#endif
-
-      row = row_containing_pos (w, PT, r0, NULL);
-      if (row == NULL)
-       return 0;
-      
-      set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-      return 1;
     }
 
-  /* Return quickly if changes are all below what is displayed in the
-     window, and if PT is in the window.  */
-  if (BEG_UNCHANGED > MATRIX_ROW_END_CHARPOS (row)
-      && PT < MATRIX_ROW_END_CHARPOS (row))
-    {
-      /* We have to update window end positions because the buffer's
-        size has changed.  */
-      w->window_end_pos
-       = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
-      w->window_end_bytepos
-       = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+  /* Give up if window start is in the changed area.
+     
+     The condition used to read
 
-      row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
-      row = row_containing_pos (w, PT, row, NULL);
-      set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-      return 2;
-    }
+     (BEG_UNCHANGED + END_UNCHANGED != Z - BEG && ...)
 
+     but why that was tested escapes me at the moment.  */
+  if (CHARPOS (start) >= first_changed_charpos
+      && CHARPOS (start) <= last_changed_charpos)
+    GIVE_UP (15);
+  
   /* Check that window start agrees with the start of the first glyph
      row in its current matrix.  Check this after we know the window
      start is not in changed text, otherwise positions would not be
      comparable.  */
-  row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  row = MATRIX_FIRST_TEXT_ROW (current_matrix);
   if (!TEXT_POS_EQUAL_P (start, row->start.pos))
-    return 0;
+    GIVE_UP (16);
 
   /* Compute the position at which we have to start displaying new
      lines.  Some of the lines at the top of the window might be
@@ -11150,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))
-       return 0;
-      
-      init_to_row_end (&it, w, last_unchanged_at_beg_row);
+       GIVE_UP (17);
+
+      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
@@ -11197,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.
@@ -11224,7 +11580,7 @@ try_window_id (w)
        }
     }
   else if (last_unchanged_at_beg_row == NULL)
-    return 0;
+    GIVE_UP (18);
 
 
 #if GLYPH_DEBUG
@@ -11243,7 +11599,7 @@ try_window_id (w)
   
 #endif /* GLYPH_DEBUG != 0 */
 
-
+  
   /* Display new lines.  Set last_text_row to the last new line
      displayed which has text on it, i.e. might end up as being the
      line where the window_end_vpos is.  */
@@ -11369,7 +11725,9 @@ try_window_id (w)
          int first_unchanged_at_end_vpos
            = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix);
          int from = XFASTINT (w->top) + first_unchanged_at_end_vpos;
-         int end = XFASTINT (w->top) + window_internal_height (w);
+         int end = (XFASTINT (w->top)
+                    + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0)
+                    + window_internal_height (w));
          
          /* Perform the operation on the screen.  */
          if (dvpos > 0)
@@ -11520,6 +11878,8 @@ try_window_id (w)
       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
       w->window_end_vpos
        = make_number (MATRIX_ROW_VPOS (row, w->current_matrix));
+      xassert (w->window_end_bytepos >= 0);
+      IF_DEBUG (debug_method_add (w, "A"));
     }
   else if (last_text_row_at_end)
     {
@@ -11529,6 +11889,8 @@ try_window_id (w)
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row_at_end);
       w->window_end_vpos
        = make_number (MATRIX_ROW_VPOS (last_text_row_at_end, desired_matrix));
+      xassert (w->window_end_bytepos >= 0);
+      IF_DEBUG (debug_method_add (w, "B"));
     }
   else if (last_text_row)
     {
@@ -11541,6 +11903,7 @@ try_window_id (w)
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
       w->window_end_vpos
        = make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix));
+      xassert (w->window_end_bytepos >= 0);
     }
   else if (first_unchanged_at_end_row == NULL
           && last_text_row == NULL
@@ -11548,26 +11911,42 @@ try_window_id (w)
     {
       /* Displayed to end of window, but no line containing text was
         displayed.  Lines were deleted at the end of the window.  */
-      int vpos;
-      int header_line_p = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
-
-      for (vpos = XFASTINT (w->window_end_vpos); vpos > 0; --vpos)
-       if ((w->desired_matrix->rows[vpos + header_line_p].enabled_p
-            && w->desired_matrix->rows[vpos + header_line_p].displays_text_p)
-           || (!w->desired_matrix->rows[vpos + header_line_p].enabled_p
-               && w->current_matrix->rows[vpos + header_line_p].displays_text_p))
-         break;
+      int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
+      int vpos = XFASTINT (w->window_end_vpos);
+      struct glyph_row *current_row = current_matrix->rows + vpos;
+      struct glyph_row *desired_row = desired_matrix->rows + vpos;
+
+      for (row = NULL;
+          row == NULL && vpos >= first_vpos;
+          --vpos, --current_row, --desired_row)
+       {
+         if (desired_row->enabled_p)
+           {
+             if (desired_row->displays_text_p)
+               row = desired_row;
+           }
+         else if (current_row->displays_text_p)
+           row  = current_row;
+       }
 
-      w->window_end_vpos = make_number (vpos);
+      xassert (row != NULL);
+      w->window_end_vpos = make_number (vpos + 1);
+      w->window_end_pos = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
+      w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
+      xassert (w->window_end_bytepos >= 0);
+      IF_DEBUG (debug_method_add (w, "C"));
     }
   else
     abort ();
 
+#if 0 /* This leads to problems, for instance when the cursor is
+        at ZV, and the cursor line displays no text.  */
   /* Disable rows below what's displayed in the window.  This makes
      debugging easier.  */
   enable_glyph_matrix_rows (current_matrix,
                            XFASTINT (w->window_end_vpos) + 1,
                            bottom_vpos, 0);
+#endif
   
   IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
            debug_end_vpos = XFASTINT (w->window_end_vpos));
@@ -11576,6 +11955,8 @@ try_window_id (w)
   w->window_end_valid = Qnil;
   w->desired_matrix->no_scrolling_p = 1;
   return 3;
+
+#undef GIVE_UP
 }
 
 
@@ -11586,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));
 
@@ -11604,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);
 }
 
 
@@ -11685,25 +12066,18 @@ 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");
       fprintf (stderr, "=======================================================================\n");
   
       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,
+%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d  %4d %4d %4d %4d %4d %4d %4d\n",
+              vpos,
               MATRIX_ROW_START_CHARPOS (row),
               MATRIX_ROW_END_CHARPOS (row),
               row->used[TEXT_AREA],
@@ -11728,8 +12102,9 @@ dump_glyph_row (matrix, vpos, glyphs)
               row->visible_height,
               row->ascent,
               row->phys_ascent);
-      fprintf (stderr, "%9d %5d\n", row->start.overlay_string_index,
-              row->end.overlay_string_index);
+      fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index,
+              row->end.overlay_string_index,
+              row->continuation_lines_width);
       fprintf (stderr, "%9d %5d\n",
               CHARPOS (row->start.string_pos),
               CHARPOS (row->end.string_pos));
@@ -11786,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);
@@ -11808,53 +12183,74 @@ 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-toggle", Ftrace_redisplay_toggle,
-       Strace_redisplay_toggle, 0, 0, "",
-  "Toggle tracing of redisplay.")
-     ()
+DEFUN ("trace-redisplay", Ftrace_redisplay, Strace_redisplay, 0, 1, "P",
+       /* Toggle tracing of redisplay.
+With ARG, turn tracing on if and only if ARG is positive.  */
+       (arg))
+     Lisp_Object arg;
 {
-  trace_redisplay_p = !trace_redisplay_p;
+  if (NILP (arg))
+    trace_redisplay_p = !trace_redisplay_p;
+  else
+    {
+      arg = Fprefix_numeric_value (arg);
+      trace_redisplay_p = XINT (arg) > 0;
+    }
+  
   return Qnil;
 }
 
 
-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;
 }
        
@@ -11999,7 +12395,7 @@ compute_line_metrics (it)
 
   if (FRAME_WINDOW_P (it->f))
     {
-      int i, header_line_height;
+      int i, min_y, max_y;
 
       /* The line may consist of one space only, that was added to
         place the cursor on it.  If so, the row's height hasn't been
@@ -12038,19 +12434,21 @@ compute_line_metrics (it)
       /* Compute how much of the line is visible.  */
       row->visible_height = row->height;
       
-      header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (it->w);
-      if (row->y < header_line_height)
-       row->visible_height -= header_line_height - row->y;
-      else
-       {
-         int max_y = WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (it->w);
-         if (row->y + row->height > max_y)
-           row->visible_height -= row->y + row->height - max_y;
-       }
+      min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (it->w);
+      max_y = WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (it->w);
+
+      if (row->y < min_y)
+       row->visible_height -= min_y - row->y;
+      if (row->y + row->height > max_y)
+       row->visible_height -= row->y + row->height - max_y;
     }
   else
     {
       row->pixel_width = row->used[TEXT_AREA];
+      if (row->continued_p)
+       row->pixel_width -= it->continuation_pixel_width;
+      else if (row->truncated_on_right_p)
+       row->pixel_width -= it->truncation_pixel_width;
       row->ascent = row->phys_ascent = 0;
       row->height = row->phys_height = row->visible_height = 1;
     }
@@ -12601,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);
@@ -12873,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;
 
@@ -12896,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))
@@ -12909,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));
        }
@@ -12928,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;
@@ -12948,6 +13348,8 @@ display_mode_lines (w)
       ++n;
     }
 
+  selected_frame = old_selected_frame;
+  selected_window = old_selected_window;
   return n;
 }
 
@@ -13061,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 == '%' */
              {
@@ -13093,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
@@ -13153,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))
              {
@@ -13402,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));
@@ -13418,6 +13833,7 @@ decode_mode_spec (w, c, field_width, precision)
   struct buffer *b = XBUFFER (w->buffer);
 
   obj = Qnil;
+  *multibyte = 0;
 
   switch (c)
     {
@@ -13751,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 "";
 }
@@ -13919,9 +14338,7 @@ display_string (string, lisp_string, face_string, face_string_pos,
   struct glyph_row *row = it->glyph_row;
 
   /* Initialize the iterator IT for iteration over STRING beginning
-     with index START.  We assume that IT may be modified here (which
-     means that display_line has to do something when displaying a
-     mini-buffer prompt, which it does).  */
+     with index START.  */
   reseat_to_string (it, string, lisp_string, start,
                    precision, field_width, multibyte);
 
@@ -14082,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)
@@ -14102,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))
@@ -14118,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;
            }
        }
     }
@@ -14126,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
@@ -14187,7 +14566,7 @@ syms_of_xdisp ()
   defsubr (&Sdump_glyph_matrix);
   defsubr (&Sdump_glyph_row);
   defsubr (&Sdump_tool_bar_row);
-  defsubr (&Strace_redisplay_toggle);
+  defsubr (&Strace_redisplay);
   defsubr (&Strace_to_stderr);
 #endif
 #ifdef HAVE_WINDOW_SYSTEM
@@ -14258,6 +14637,14 @@ syms_of_xdisp ()
   staticpro (&Qgrow_only);
   Qinhibit_menubar_update = intern ("inhibit-menubar-update");
   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;
@@ -14275,217 +14662,220 @@ 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.  */);
+  inhibit_eval_during_redisplay = 0;
 }