]> code.delx.au - gnu-emacs/blobdiff - src/dispnew.c
Fix last change.
[gnu-emacs] / src / dispnew.c
index 14e4d968760a63dc2f844b2247596bad045d1b6d..dff5c91719df6370c92474170b3b6f2238440794 100644 (file)
@@ -1,5 +1,5 @@
 /* Updating of data structures for redisplay.
-   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 1999
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 1999, 2000
        Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -120,6 +120,8 @@ struct dim
 \f
 /* Function prototypes.  */
 
+static void save_or_restore_current_matrix P_ ((struct frame *, int));
+static void fake_current_matrices P_ ((Lisp_Object));
 static void redraw_overlapping_rows P_ ((struct window *, int));
 static void redraw_overlapped_rows P_ ((struct window *, int));
 static int count_blanks P_ ((struct glyph *, int));
@@ -139,7 +141,7 @@ static void adjust_glyph_matrix P_ ((struct window *, struct glyph_matrix *,
                                     int, int, struct dim));
 static void change_frame_size_1 P_ ((struct frame *, int, int, int, int, int));
 static void swap_glyph_pointers P_ ((struct glyph_row *, struct glyph_row *));
-#ifdef GLYPH_DEBUG
+#if GLYPH_DEBUG
 static int glyph_row_slice_p P_ ((struct glyph_row *, struct glyph_row *));
 #endif
 static void fill_up_frame_row_with_spaces P_ ((struct glyph_row *, int));
@@ -185,7 +187,6 @@ static int margin_glyphs_to_reserve P_ ((struct window *, int, Lisp_Object));
 static void sync_window_with_frame_matrix_rows P_ ((struct window *));
 struct window *frame_row_to_window P_ ((struct window *, int));
 
-
 \f
 /* Non-zero means don't pause redisplay for pending input.  (This is
    for debugging and for a future implementation of EDT-like
@@ -329,6 +330,105 @@ static int window_to_frame_hpos P_ ((struct window *, int));
 #define WINDOW_TO_FRAME_VPOS(W, VPOS) window_to_frame_vpos ((W), (VPOS))
 #define WINDOW_TO_FRAME_HPOS(W, HPOS) window_to_frame_hpos ((W), (HPOS))
 
+/* One element of the ring buffer containing redisplay history
+   information.  */
+
+struct redisplay_history
+{
+  char trace[512 + 100];
+};
+
+/* The size of the history buffer.  */
+
+#define REDISPLAY_HISTORY_SIZE 30
+
+/* The redisplay history buffer.  */
+
+static struct redisplay_history redisplay_history[REDISPLAY_HISTORY_SIZE];
+
+/* Next free entry in redisplay_history.  */
+
+static int history_idx;
+
+/* A tick that's incremented each time something is added to the
+   history.  */
+
+static unsigned history_tick;
+
+static void add_frame_display_history P_ ((struct frame *, int));
+static void add_window_display_history P_ ((struct window *, char *, int));
+
+
+/* Add to the redisplay history how window W has been displayed.
+   MSG is a trace containing the information how W's glyph matrix
+   has been contructed.  PAUSED_P non-zero means that the update
+   has been interrupted for pending input.  */
+
+static void
+add_window_display_history (w, msg, paused_p)
+     struct window *w;
+     char *msg;
+     int paused_p;
+{
+  char *buf;
+  
+  if (history_idx >= REDISPLAY_HISTORY_SIZE)
+    history_idx = 0;
+  buf = redisplay_history[history_idx].trace;
+  ++history_idx;
+  
+  sprintf (buf, "%d: window %p (`%s')%s\n",
+          history_tick++,
+          w,
+          ((BUFFERP (w->buffer)
+            && STRINGP (XBUFFER (w->buffer)->name))
+           ? (char *) XSTRING (XBUFFER (w->buffer)->name)->data
+           : "???"),
+          paused_p ? " ***paused***" : "");
+  strcat (buf, msg);
+}
+
+
+/* Add to the redisplay history that frame F has been displayed.
+   PAUSED_P non-zero means that the update has been interrupted for
+   pending input.  */
+
+static void
+add_frame_display_history (f, paused_p)
+     struct frame *f;
+     int paused_p;
+{
+  char *buf;
+  
+  if (history_idx >= REDISPLAY_HISTORY_SIZE)
+    history_idx = 0;
+  buf = redisplay_history[history_idx].trace;
+  ++history_idx;
+  
+  sprintf (buf, "%d: update frame %p%s",
+          history_tick++,
+          f, paused_p ? " ***paused***" : "");
+}
+
+
+DEFUN ("dump-redisplay-history", Fdump_redisplay_history,
+       Sdump_redisplay_history, 0, 0, "",
+   "Dump redisplay history to stderr.")
+     ()
+{
+  int i;
+
+  for (i = history_idx - 1; i != history_idx; --i)
+    {
+      if (i < 0)
+       i = REDISPLAY_HISTORY_SIZE - 1;
+      fprintf (stderr, "%s\n", redisplay_history[i].trace);
+    }
+
+  return Qnil;
+}
+
+
 #else /* GLYPH_DEBUG == 0 */
 
 #define WINDOW_TO_FRAME_VPOS(W, VPOS) ((VPOS) + XFASTINT ((W)->top))
@@ -525,7 +625,7 @@ adjust_glyph_matrix (w, matrix, x, y, dim)
   int header_line_changed_p = 0;
   int header_line_p = 0;
   int left = -1, right = -1;
-  int window_x, window_y, window_width, window_height;
+  int window_x, window_y, window_width = -1, window_height;
 
   /* See if W had a top line that has disappeared now, or vice versa.  */
   if (w)
@@ -550,6 +650,7 @@ adjust_glyph_matrix (w, matrix, x, y, dim)
       if (!marginal_areas_changed_p
          && !fonts_changed_p
          && !header_line_changed_p
+         && matrix->window_left_x == XFASTINT (w->left)
          && matrix->window_top_y == XFASTINT (w->top)
          && matrix->window_height == window_height
          && matrix->window_vscroll == w->vscroll
@@ -679,12 +780,16 @@ adjust_glyph_matrix (w, matrix, x, y, dim)
      when this function runs.  */
   if (w && matrix == w->current_matrix)
     {
+      if (window_width < 0)
+       window_width = window_box_width (w, -1);
+      
       /* Optimize the case that only the height has changed (C-x 2,
          upper window).  Invalidate all rows that are no longer part
          of the window.  */
       if (!marginal_areas_changed_p
+         && matrix->window_left_x == XFASTINT (w->left)
          && matrix->window_top_y == XFASTINT (w->top)
-         && matrix->window_width == window_width)
+         && matrix->window_width == window_box_width (w, -1))
        {
          i = 0;
          while (matrix->rows[i].enabled_p
@@ -718,6 +823,7 @@ adjust_glyph_matrix (w, matrix, x, y, dim)
      was last adjusted.  This is used to optimize redisplay above.  */
   if (w)
     {
+      matrix->window_left_x = XFASTINT (w->left);
       matrix->window_top_y = XFASTINT (w->top);
       matrix->window_height = window_height;
       matrix->window_width = window_width;
@@ -976,12 +1082,13 @@ clear_window_matrices (w, desired_p)
    changes in the glyph_row structure, i.e. addition or removal of
    structure members.  */
 
+static struct glyph_row null_row;
+
 void
 clear_glyph_row (row)
      struct glyph_row *row;
 {
   struct glyph *p[1 + LAST_AREA];
-  static struct glyph_row null_row;
 
   /* Save pointers.  */
   p[LEFT_MARGIN_AREA] = row->glyphs[LEFT_MARGIN_AREA];
@@ -1197,7 +1304,7 @@ assign_row (to, from)
    is non-zero if the glyph memory of WINDOW_ROW is part of the glyph
    memory of FRAME_ROW.  */
 
-#ifdef GLYPH_DEBUG
+#if GLYPH_DEBUG
 
 static int
 glyph_row_slice_p (window_row, frame_row)
@@ -1316,7 +1423,7 @@ line_draw_cost (matrix, vpos)
   if (!must_write_spaces)
     {
       /* Skip from the end over trailing spaces.  */
-      while (end != beg && CHAR_GLYPH_SPACE_P (*end))
+      while (end > beg && CHAR_GLYPH_SPACE_P (*(end - 1)))
        --end;
 
       /* All blank line.  */      
@@ -1994,6 +2101,90 @@ adjust_frame_glyphs (f)
 }
 
 
+/* In the window tree with root W, build current matrices of leaf
+   windows from the frame's current matrix.  */
+
+static void
+fake_current_matrices (window)
+     Lisp_Object window;
+{
+  struct window *w;
+      
+  for (; !NILP (window); window = w->next)
+    {
+      w = XWINDOW (window);
+      
+      if (!NILP (w->hchild))
+       fake_current_matrices (w->hchild);
+      else if (!NILP (w->vchild))
+       fake_current_matrices (w->vchild);
+      else
+       {
+         int i;
+         struct frame *f = XFRAME (w->frame);
+         struct glyph_matrix *m = w->current_matrix;
+         struct glyph_matrix *fm = f->current_matrix;
+
+         xassert (m->matrix_h == XFASTINT (w->height));
+         xassert (m->matrix_w == XFASTINT (w->width));
+         
+         for (i = 0; i < m->matrix_h; ++i)
+           {
+             struct glyph_row *r = m->rows + i;
+             struct glyph_row *fr = fm->rows + i + XFASTINT (w->top);
+
+             xassert (r->glyphs[TEXT_AREA] >= fr->glyphs[TEXT_AREA]
+                      && r->glyphs[LAST_AREA] <= fr->glyphs[LAST_AREA]);
+
+             r->enabled_p = fr->enabled_p;
+             if (r->enabled_p)
+               {
+                 r->used[LEFT_MARGIN_AREA] = m->left_margin_glyphs;
+                 r->used[RIGHT_MARGIN_AREA] = m->right_margin_glyphs;
+                 r->used[TEXT_AREA] = (m->matrix_w
+                                       - r->used[LEFT_MARGIN_AREA]
+                                       - r->used[RIGHT_MARGIN_AREA]);
+                 r->mode_line_p = 0;
+                 r->inverse_p = fr->inverse_p;
+               }
+           }
+       }
+    }
+}
+
+
+/* Save or restore the contents of frame F's current frame matrix.
+   SAVE_P non-zero means save it.  */
+
+static void
+save_or_restore_current_matrix (f, save_p)
+     struct frame *f;
+     int save_p;
+{
+  struct glyph_row *from, *to, *end;
+
+  if (save_p)
+    {
+      from = f->current_matrix->rows;
+      end = from + f->current_matrix->nrows;
+      to = f->desired_matrix->rows;
+    }
+  else
+    {
+      from = f->desired_matrix->rows;
+      end = from + f->desired_matrix->nrows;
+      to = f->current_matrix->rows;
+    }
+  
+  for (; from < end; ++from, ++to)
+    {
+      size_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+      bcopy (from->glyphs[TEXT_AREA], to->glyphs[TEXT_AREA], nbytes);
+      to->used[TEXT_AREA] = from->used[TEXT_AREA];
+    }
+}
+
+
 /* Allocate/reallocate glyph matrices of a single frame F for
    frame-based redisplay.  */
 
@@ -2029,7 +2220,7 @@ adjust_frame_glyphs_for_frame_redisplay (f)
       f->desired_matrix = new_glyph_matrix (f->desired_pool);
       f->current_matrix = new_glyph_matrix (f->current_pool);
     }
-      
+  
   /* Compute window glyph matrices.  (This takes the mini-buffer
      window into account).  The result is the size of the frame glyph
      matrix needed.  The variable window_change_flags is set to a bit
@@ -2067,12 +2258,31 @@ adjust_frame_glyphs_for_frame_redisplay (f)
   
       /* Resize frame matrices.  */
       adjust_glyph_matrix (NULL, f->desired_matrix, 0, 0, matrix_dim);
-      adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
 
-      /* Since location and size of sub-matrices within the pool may
-        have changed, and current matrices don't have meaningful
-        contents anymore, mark the frame garbaged.  */
-      SET_FRAME_GARBAGED (f);
+      /* Pointers to glyph memory in glyph rows are exchanged during
+        the update phase of redisplay, which means in general that a
+        frame's current matrix consists of pointers into both the
+        desired and current glyph pool of the frame.  Adjusting a
+        matrix sets the frame matrix up so that pointers are all into
+        the same pool.  If we want to preserve glyph contents of the
+        current matrix over a call to adjust_glyph_matrix, we must
+        make a copy of the current glyphs, and restore the current
+        matrix' contents from that copy.  */
+      if (display_completed
+         && !FRAME_GARBAGED_P (f)
+         && matrix_dim.width == f->current_matrix->matrix_w
+         && matrix_dim.height == f->current_matrix->matrix_h)
+       {
+         save_or_restore_current_matrix (f, 1);
+         adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
+         save_or_restore_current_matrix (f, 0);
+         fake_current_matrices (FRAME_ROOT_WINDOW (f));
+       }
+      else
+       {
+         adjust_glyph_matrix (NULL, f->current_matrix, 0, 0, matrix_dim);
+         SET_FRAME_GARBAGED (f);
+       }
     }
 }
 
@@ -2501,29 +2711,6 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
              SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph);
            }
 
-#if 0 /* This shouldn't be necessary.  Let's check it.  */
-         /* Due to hooks installed, it normally doesn't happen that
-            window rows and frame rows of the same matrix are out of
-            sync, i.e. have a different understanding of where to
-            find glyphs for the row.  The following is a safety-belt
-            that doesn't cost much and makes absolutely sure that
-            window and frame matrices are in sync.  */
-         if (!glyph_row_slice_p (window_row, frame_row))
-           {
-             /* Find the row in the window being a slice.  There
-                should exist one from program logic.  */
-             struct glyph_row *slice_row
-               = find_glyph_row_slice (window_matrix, frame_matrix, frame_y);
-             xassert (slice_row != 0);
-             
-             /* Exchange glyphs between both window rows.  */
-             swap_glyphs_in_rows (window_row, slice_row);
-             
-             /* Exchange pointers between both rows.  */
-             swap_glyph_pointers (window_row, slice_row);
-           }
-#endif
-
          /* Window row window_y must be a slice of frame row
             frame_y.  */
          xassert (glyph_row_slice_p (window_row, frame_row));
@@ -2533,6 +2720,7 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
          
 #if GLYPH_DEBUG
          strcpy (w->current_matrix->method, w->desired_matrix->method);
+         add_window_display_history (w, w->current_matrix->method, 0);
 #endif
        }
 
@@ -3065,7 +3253,7 @@ DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
     return Qnil;
 
   update_begin (f);
-  if (FRAME_MSDOS_P (f))
+  if (FRAME_MSDOS_P (f) || FRAME_W32_CONSOLE_P (f))
     set_terminal_modes ();
   clear_frame ();
   clear_current_matrices (f);
@@ -3173,8 +3361,10 @@ direct_output_for_insert (g)
       || !display_completed
       /* Give up if buffer appears in two places.  */
       || buffer_shared > 1
-      /* Give up if w is mini-buffer and a message is being displayed there */
-      || (MINI_WINDOW_P (w) && !NILP (echo_area_buffer[0]))
+      /* Give up if currently displaying a message instead of the
+        minibuffer contents.  */
+      || (EQ (selected_window, minibuf_window)
+         && EQ (minibuf_window, echo_area_window))
       /* Give up for hscrolled mini-buffer because display of the prompt
         is handled specially there (see display_line).  */
       || (MINI_WINDOW_P (w) && XFASTINT (w->hscroll))
@@ -3551,13 +3741,6 @@ update_frame (f, force_p, inhibit_hairy_id_p)
              tem = f->current_tool_bar_string;
              f->current_tool_bar_string = f->desired_tool_bar_string;
              f->desired_tool_bar_string = tem;
-             f->n_current_tool_bar_items = f->n_desired_tool_bar_items;
-             
-             /* Swap tool-bar items.  We swap because we want to
-                reuse vectors.  */
-             tem = f->current_tool_bar_items;
-             f->current_tool_bar_items = f->desired_tool_bar_items;
-             f->desired_tool_bar_items = tem;
            }
        }
   
@@ -3590,7 +3773,10 @@ update_frame (f, force_p, inhibit_hairy_id_p)
       fflush (stdout);
 
       /* Check window matrices for lost pointers.  */
-      IF_DEBUG (check_window_matrix_pointers (root_window));
+#if GLYPH_DEBUG
+      check_window_matrix_pointers (root_window);
+      add_frame_display_history (f, paused_p);
+#endif
     }
 
   /* Reset flags indicating that a window should be updated.  */
@@ -3754,6 +3940,31 @@ redraw_overlapping_rows (w, yb)
 }
 
 
+#ifdef GLYPH_DEBUG
+
+/* Check that no row in the current matrix of window W is enabled
+   which is below what's displayed in the window.  */
+
+void
+check_current_matrix_flags (w)
+     struct window *w;
+{
+  int last_seen_p = 0;
+  int i, yb = window_text_bottom_y (w);
+
+  for (i = 0; i < w->current_matrix->nrows - 1; ++i)
+    {
+      struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
+      if (!last_seen_p && MATRIX_ROW_BOTTOM_Y (row) >= yb)
+       last_seen_p = 1;
+      else if (last_seen_p && row->enabled_p)
+       abort ();
+    }
+}
+
+#endif /* GLYPH_DEBUG */
+
+
 /* Update display of window W.  FORCE_P non-zero means that we should
    not stop when detecting pending input.  */
 
@@ -3766,6 +3977,7 @@ update_window (w, force_p)
   int paused_p;
   int preempt_count = baud_rate / 2400 + 1;
   extern int input_pending;
+  extern Lisp_Object do_mouse_tracking;
 #if GLYPH_DEBUG
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   extern struct frame *updating_frame;
@@ -3783,12 +3995,12 @@ update_window (w, force_p)
 
   /* If forced to complete the update, or if no input is pending, do
      the update.  */
-  if (force_p || !input_pending)
+  if (force_p || !input_pending || !NILP (do_mouse_tracking))
     {
       struct glyph_row *row, *end;
       struct glyph_row *mode_line_row;
       struct glyph_row *header_line_row = NULL;
-      int yb, changed_p = 0, mouse_face_overwritten_p = 0;
+      int yb, changed_p = 0, mouse_face_overwritten_p = 0, n_updated;
 
       rif->update_window_begin_hook (w);
       yb = window_text_bottom_y (w);
@@ -3843,7 +4055,7 @@ update_window (w, force_p)
        }
 
       /* Update the rest of the lines.  */
-      for (; row < end && (force_p || !input_pending); ++row)
+      for (n_updated = 0; row < end && (force_p || !input_pending); ++row)
        if (row->enabled_p)
          {
            int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
@@ -3853,7 +4065,7 @@ update_window (w, force_p)
               detect_input_pending.  If it's done too often,
               scrolling large windows with repeated scroll-up
               commands will too quickly pause redisplay.  */
-           if (!force_p && vpos % preempt_count == 0)
+           if (!force_p && ++n_updated % preempt_count == 0)
              detect_input_pending ();
 
            changed_p |= update_window_line (w, vpos,
@@ -3907,6 +4119,11 @@ update_window (w, force_p)
   else
     paused_p = 1;
 
+#if GLYPH_DEBUG
+  /* check_current_matrix_flags (w); */
+  add_window_display_history (w, w->current_matrix->method, paused_p);
+#endif
+  
   clear_glyph_matrix (desired_matrix);
 
   return paused_p;
@@ -3980,13 +4197,16 @@ update_text_area (w, vpos)
       int stop, i, x;
       struct glyph *current_glyph = current_row->glyphs[TEXT_AREA];
       struct glyph *desired_glyph = desired_row->glyphs[TEXT_AREA];
+      int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p;
+      int desired_stop_pos = desired_row->used[TEXT_AREA];
 
+#if 0 /* This shouldn't be necessary.  Let's check it.  */
       /* If the desired row extends its face to the text area end,
         make sure we write at least one glyph, so that the face
         extension actually takes place.  */
-      int desired_stop_pos = (desired_row->used[TEXT_AREA]
-                             - (MATRIX_ROW_EXTENDS_FACE_P (desired_row)
-                                ? 1 : 0));
+      if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
+       --desired_stop_pos;
+#endif
       
       stop = min (current_row->used[TEXT_AREA], desired_stop_pos);
       i = 0;
@@ -3994,35 +4214,59 @@ update_text_area (w, vpos)
       
       while (i < stop)
        {
+         int can_skip_p = 1;
+         
          /* Skip over glyphs that both rows have in common.  These
-            don't have to be written.  */
-         while (i < stop
-                && GLYPH_EQUAL_P (desired_glyph, current_glyph))
-           {
-             x += desired_glyph->pixel_width;
-             ++desired_glyph, ++current_glyph, ++i;
-           }
-
-         /* Consider the case that the current row contains "xxx ppp
-            ggg" in italic Courier font, and the desired row is "xxx
-            ggg".  The character `p' has lbearing, `g' has not.  The
-            loop above will stop in front of the first `p' in the
-            current row.  If we would start writing glyphs there, we
-            wouldn't erase the lbearing of the `p'.  The rest of the
-            lbearing problem is then taken care of by x_draw_glyphs.  */
-         if (current_row->contains_overlapping_glyphs_p
-             && i > 0
-             && i < current_row->used[TEXT_AREA]
-             && current_row->used[TEXT_AREA] != desired_row->used[TEXT_AREA])
+            don't have to be written.  We can't skip if the last
+            current glyph overlaps the glyph to its right.  For
+            example, consider a current row of `if ' with the `f' in
+            Courier bold so that it overlaps the ` ' to its right.
+            If the desired row is ` ', we would skip over the space
+            after the `if' and there would remain a pixel from the
+            `f' on the screen.  */
+         if (overlapping_glyphs_p && i > 0)
            {
+             struct glyph *glyph = &current_row->glyphs[TEXT_AREA][i - 1];
              int left, right;
-             rif->get_glyph_overhangs (current_glyph, XFRAME (w->frame),
+             
+             rif->get_glyph_overhangs (glyph, XFRAME (w->frame),
                                        &left, &right);
-             while (left > 0 && i > 0)
+             can_skip_p = right == 0;
+           }
+         
+         if (can_skip_p)
+           {
+             while (i < stop
+                    && GLYPH_EQUAL_P (desired_glyph, current_glyph))
                {
-                 --i, --desired_glyph, --current_glyph;
-                 x -= desired_glyph->pixel_width;
-                 left -= desired_glyph->pixel_width;
+                 x += desired_glyph->pixel_width;
+                 ++desired_glyph, ++current_glyph, ++i;
+               }
+
+             /* Consider the case that the current row contains "xxx
+                ppp ggg" in italic Courier font, and the desired row
+                is "xxx ggg".  The character `p' has lbearing, `g'
+                has not.  The loop above will stop in front of the
+                first `p' in the current row.  If we would start
+                writing glyphs there, we wouldn't erase the lbearing
+                of the `p'.  The rest of the lbearing problem is then
+                taken care of by x_draw_glyphs.  */
+             if (overlapping_glyphs_p
+                 && i > 0
+                 && i < current_row->used[TEXT_AREA]
+                 && (current_row->used[TEXT_AREA]
+                     != desired_row->used[TEXT_AREA]))
+               {
+                 int left, right;
+             
+                 rif->get_glyph_overhangs (current_glyph, XFRAME (w->frame),
+                                           &left, &right);
+                 while (left > 0 && i > 0)
+                   {
+                     --i, --desired_glyph, --current_glyph;
+                     x -= desired_glyph->pixel_width;
+                     left -= desired_glyph->pixel_width;
+                   }
                }
            }
          
@@ -4035,15 +4279,18 @@ update_text_area (w, vpos)
              int start_x = x, start_hpos = i;
              struct glyph *start = desired_glyph;
              int current_x = x;
-             
+             int skip_first_p = !can_skip_p;
+
              /* Find the next glyph that's equal again.  */
              while (i < stop
-                    && !GLYPH_EQUAL_P (desired_glyph, current_glyph)
+                    && (skip_first_p
+                        || !GLYPH_EQUAL_P (desired_glyph, current_glyph))
                     && x == current_x)
                {
                  x += desired_glyph->pixel_width;
                  current_x += current_glyph->pixel_width;
                  ++desired_glyph, ++current_glyph, ++i;
+                 skip_first_p = 0;
                }
 
              if (i == start_hpos || x != current_x)
@@ -4053,7 +4300,7 @@ update_text_area (w, vpos)
                  desired_glyph = start;
                  break;
                }
-             
+
              rif->cursor_to (vpos, start_hpos, desired_row->y, start_x);
              rif->write_glyphs (start, i - start_hpos);
              changed_p = 1;
@@ -4071,11 +4318,13 @@ update_text_area (w, vpos)
       /* Maybe clear to end of line.  */
       if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
        {
+#if 0 
          /* If new row extends to the end of the text area, nothing
             has to be cleared, if and only if we did a write_glyphs
             above.  This is made sure by setting desired_stop_pos
             appropriately above.  */
          xassert (i < desired_row->used[TEXT_AREA]);
+#endif
        }
       else if (MATRIX_ROW_EXTENDS_FACE_P (current_row))
        {
@@ -4471,9 +4720,15 @@ scrolling_window (w, header_line_p)
      we plan to reuse part of the display even if other parts are
      disabled.  */
   i = first_old + 1;
-  while (i < current_matrix->nrows - 1
-        && MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (current_matrix, i)) <= yb)
-    ++i;
+  while (i < current_matrix->nrows - 1)
+    {
+      int bottom = MATRIX_ROW_BOTTOM_Y (MATRIX_ROW (current_matrix, i));
+      if (bottom <= yb)
+       ++i;
+      if (bottom >= yb)
+       break;
+    }
+
   last_old = i;
 
   /* Skip over rows equal at the bottom.  */
@@ -4619,7 +4874,7 @@ scrolling_window (w, header_line_p)
           case.  */
        for (j = 0; j < nruns && runs[j]->height > run->height; ++j)
          ;
-       for (k = nruns; k >= j; --k)
+       for (k = nruns; k > j; --k)
          runs[k] = runs[k - 1];
        runs[j] = run;
        ++nruns;
@@ -4997,7 +5252,7 @@ count_blanks (r, len)
      int len;
 {
   int i;
-
+  
   for (i = 0; i < len; ++i)
     if (!CHAR_GLYPH_SPACE_P (r[i]))
       break;
@@ -5047,6 +5302,12 @@ update_frame_line (frame, vpos)
   struct glyph_row *current_row = MATRIX_ROW (current_matrix, vpos);
   struct glyph_row *desired_row = MATRIX_ROW (desired_matrix, vpos);
   int must_write_whole_line_p;
+  int write_spaces_p = must_write_spaces;
+  int colored_spaces_p = (FACE_FROM_ID (frame, DEFAULT_FACE_ID)->background
+                         != FACE_TTY_DEFAULT_BG_COLOR);
+
+  if (colored_spaces_p)
+    write_spaces_p = 1;
 
   if (desired_row->inverse_p
       != (current_row->enabled_p && current_row->inverse_p))
@@ -5071,10 +5332,10 @@ update_frame_line (frame, vpos)
       obody = MATRIX_ROW_GLYPH_START (current_matrix, vpos);
       olen = current_row->used[TEXT_AREA];
       
-      if (! current_row->inverse_p)
+      if (!current_row->inverse_p)
        {
          /* Ignore trailing spaces, if we can.  */
-         if (!must_write_spaces)
+         if (!write_spaces_p)
            while (olen > 0 && CHAR_GLYPH_SPACE_P (obody[olen-1]))
              olen--;
        }
@@ -5107,7 +5368,7 @@ update_frame_line (frame, vpos)
   if (must_write_whole_line_p)
     {
       /* Ignore spaces at the end, if we can.  */
-      if (!must_write_spaces)
+      if (!write_spaces_p)
        while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
          --nlen;
 
@@ -5139,7 +5400,7 @@ update_frame_line (frame, vpos)
      unless for one reason or another we must write all spaces.  */
   if (!desired_row->inverse_p)
     {
-      if (!must_write_spaces)
+      if (!write_spaces_p)
        while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
          nlen--;
     }
@@ -5199,7 +5460,7 @@ update_frame_line (frame, vpos)
     {
       /* If current line is blank, skip over initial spaces, if
         possible, and write the rest.  */
-      if (must_write_spaces || desired_row->inverse_p)
+      if (write_spaces_p || desired_row->inverse_p)
        nsp = 0;
       else
        nsp = count_blanks (nbody, nlen);
@@ -5217,7 +5478,9 @@ update_frame_line (frame, vpos)
 
   /* Compute number of leading blanks in old and new contents.  */
   osp = count_blanks (obody, olen);
-  nsp = desired_row->inverse_p ? 0 : count_blanks (nbody, nlen);
+  nsp = (desired_row->inverse_p || colored_spaces_p
+        ? 0
+        : count_blanks (nbody, nlen));
 
   /* Compute number of matching chars starting with first non-blank.  */
   begmatch = count_match (obody + osp, obody + olen,
@@ -5225,7 +5488,7 @@ update_frame_line (frame, vpos)
 
   /* Spaces in new match implicit space past the end of old.  */
   /* A bug causing this to be a no-op was fixed in 18.29.  */
-  if (!must_write_spaces && osp + begmatch == olen)
+  if (!write_spaces_p && osp + begmatch == olen)
     {
       np1 = nbody + nsp;
       while (np1 + begmatch < nend && CHAR_GLYPH_SPACE_P (np1[begmatch]))
@@ -6255,6 +6518,10 @@ syms_of_display ()
   defsubr (&Sinternal_show_cursor);
   defsubr (&Sinternal_show_cursor_p);
 
+#if GLYPH_DEBUG
+  defsubr (&Sdump_redisplay_history);
+#endif
+
   frame_and_buffer_state = Fmake_vector (make_number (20), Qlambda);
   staticpro (&frame_and_buffer_state);