diff src/redisplay.c @ 442:abe6d1db359e r21-2-36

Import from CVS: tag r21-2-36
author cvs
date Mon, 13 Aug 2007 11:35:02 +0200
parents 8de8e3f6228a
children 576fb035e263
line wrap: on
line diff
--- a/src/redisplay.c	Mon Aug 13 11:33:40 2007 +0200
+++ b/src/redisplay.c	Mon Aug 13 11:35:02 2007 +0200
@@ -40,7 +40,6 @@
 
 #include <config.h>
 #include "lisp.h"
-#include <limits.h>
 
 #include "buffer.h"
 #include "commands.h"
@@ -64,11 +63,10 @@
 #include "file-coding.h"
 #endif
 
+#include "sysfile.h"
+
 #ifdef HAVE_TTY
 #include "console-tty.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for isatty() */
-#endif
 #endif /* HAVE_TTY */
 
 /* Note: We have to be careful throughout this code to properly handle
@@ -87,16 +85,10 @@
 #define LEFT_GLYPHS	2
 #define RIGHT_GLYPHS	3
 
-/* Set the vertical clip to 0 if we are currently updating the line
-   start cache.  Otherwise for buffers of line height 1 it may fail to
-   be able to work properly because regenerate_window will not layout
-   a single line.  */
 #define VERTICAL_CLIP(w, display)					\
-  (updating_line_start_cache						\
-   ? 0									\
-   : ((WINDOW_TTY_P (w) | (!display && scroll_on_clipped_lines))	\
+    ((WINDOW_TTY_P (w) | (!display && scroll_on_clipped_lines))	        \
       ? INT_MAX								\
-      : vertical_clip))
+      : vertical_clip)
 
 /* The following structures are completely private to redisplay.c so
    we put them here instead of in a header file, for modularity. */
@@ -328,9 +320,6 @@
 /* Minimum visible pixel width of clipped glyphs at right margin. */
 int horizontal_clip;
 
-/* Set if currently inside update_line_start_cache. */
-static int updating_line_start_cache;
-
 /* Nonzero means reading single-character input with prompt
    so put cursor on minibuffer after the prompt.  */
 int cursor_in_echo_area;
@@ -364,8 +353,7 @@
 int glyphs_changed;
 int glyphs_changed_set;
 
-/* non-zero if any displayed subwindow is in need of updating
-   somewhere. */
+/* non-zero if any subwindow has been deleted. */
 int subwindows_changed;
 int subwindows_changed_set;
 
@@ -419,9 +407,9 @@
 Lisp_Object Vbar_cursor;
 Lisp_Object Qbar_cursor;
 
-int visible_bell;	/* If true and the terminal will support it
-			   then the frame will flash instead of
-			   beeping when an error occurs */
+Lisp_Object Vvisible_bell;	/* If true and the terminal will support it
+				   then the frame will flash instead of
+				   beeping when an error occurs */
 
 /* Nonzero means no need to redraw the entire frame on resuming
    a suspended Emacs.  This is useful on terminals with multiple pages,
@@ -451,6 +439,9 @@
 Lisp_Object Vwindow_scroll_functions;
 Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
 
+Lisp_Object Qbuffer_list_changed_hook, Vbuffer_list_changed_hook;
+
+
 #define INHIBIT_REDISPLAY_HOOKS  /* #### Until we've thought about
 				    this more. */
 #ifndef INHIBIT_REDISPLAY_HOOKS
@@ -471,6 +462,8 @@
 
 int column_number_start_at_one;
 
+Lisp_Object Qtop_bottom;
+
 #define WINDOW_SCROLLED(w) \
 (w->hscroll > 0 || w->left_xoffset)
 
@@ -803,7 +796,7 @@
   gb.glyph = Vhscroll_glyph;
   {
     int oldpixpos = data->pixpos;
-    retval = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
+    retval = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0,
 			     GLYPH_CACHEL (XWINDOW (data->window),
 					   HSCROLL_GLYPH_INDEX));
     data->hscroll_glyph_width_adjust =
@@ -923,9 +916,7 @@
   else if (data->is_modeline)
     crb->bufpos = data->modeline_charpos;
   else
-    /* fuckme if this shouldn't be an abort. */
-    /* abort (); fuckme harder, this abort gets tripped quite often,
-		 in propagation and whatnot.  #### fixme */
+    /* Text but not in buffer */
     crb->bufpos = 0;
   crb->type = RUNE_CHAR;
   crb->object.chr.ch = data->font_is_bogus ? '~' : data->ch;
@@ -1320,6 +1311,7 @@
 		    case '%':
 		      dst += set_charptr_emchar (dst, '%');
 		      break;
+		      /* #### unimplemented */
 		    }
 		}
 	    }
@@ -1528,12 +1520,21 @@
      glyph sizes might have changed too */
   invalidate_glyph_geometry_maybe (gb->glyph, w);
 
+  /* This makes sure the glyph is in the cachels.
+
+     #### We do this to make sure the glyph is in the glyph cachels,
+     so that the dirty flag can be reset after redisplay has
+     finished. We should do this some other way, maybe by iterating
+     over the window cache of subwindows. */
+  get_glyph_cachel_index (w, gb->glyph);
+
   /* A nil extent indicates a special glyph (ex. truncator). */
   if (NILP (gb->extent)
       || (pos_type == BEGIN_GLYPHS &&
 	  extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT)
       || (pos_type == END_GLYPHS &&
-	  extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT))
+	  extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT)
+      || pos_type == LEFT_GLYPHS || pos_type == RIGHT_GLYPHS)
     {
       struct rune rb;
       int width;
@@ -1541,6 +1542,8 @@
       int ascent, descent;
       Lisp_Object baseline;
       Lisp_Object face;
+      Lisp_Object instance;
+      face_index findex;
 
       if (cachel)
 	width = cachel->width;
@@ -1652,10 +1655,32 @@
 
       face = glyph_face (gb->glyph, data->window);
       if (NILP (face))
-	rb.findex = data->findex;
+	findex = data->findex;
       else
-	rb.findex = get_builtin_face_cache_index (w, face);
-
+	findex = get_builtin_face_cache_index (w, face);
+
+      instance = glyph_image_instance (gb->glyph, data->window,
+				       ERROR_ME_NOT, 1);
+      if (TEXT_IMAGE_INSTANCEP (instance))
+	{
+	  Lisp_Object string = XIMAGE_INSTANCE_TEXT_STRING (instance);
+	  face_index orig_findex = data->findex;
+	  Bytind orig_bufpos = data->bi_bufpos;
+	  Bytind orig_start_col_enabled = data->bi_start_col_enabled;
+
+	  data->findex = findex;
+	  data->bi_start_col_enabled = 0;
+	  if (!allow_cursor)
+	    data->bi_bufpos = 0;
+	  add_bufbyte_string_runes (data, XSTRING_DATA (string),
+				    XSTRING_LENGTH (string), 0);
+	  data->findex = orig_findex;
+	  data->bi_bufpos = orig_bufpos;
+	  data->bi_start_col_enabled = orig_start_col_enabled;
+	  return NULL;
+	}
+
+      rb.findex = findex;
       rb.xpos = data->pixpos;
       rb.width = width;
       rb.bufpos = 0;			/* glyphs are never "at" anywhere */
@@ -1666,13 +1691,6 @@
       else
         rb.endpos = 0;
       rb.type = RUNE_DGLYPH;
-      /* #### Ben sez: this is way bogus if the glyph is a string.
-	 You should not make the output routines have to cope with
-	 this.  The string could contain Mule characters, or non-
-	 printable characters, or characters to be passed through
-	 the display table, or non-character objects (when this gets
-	 implemented), etc.  Instead, this routine here should parse
-	 the string into a series of runes. */
       rb.object.dglyph.glyph = gb->glyph;
       rb.object.dglyph.extent = gb->extent;
       rb.object.dglyph.xoffset = xoffset;
@@ -1875,6 +1893,7 @@
 
   dl->used_prop_data = 0;
   dl->num_chars = 0;
+  dl->line_continuation = 0;
 
   xzero (data);
   data.ef = extent_fragment_new (w->buffer, f);
@@ -2465,11 +2484,12 @@
 
 	      /* data.bi_bufpos is already at the start of the next line. */
 
+	      dl->line_continuation = 1;
 	      gb.glyph = Vcontinuation_glyph;
 	      cachel = GLYPH_CACHEL (w, CONT_GLYPH_INDEX);
 	    }
 
-	  add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 1, cachel);
+	  add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, cachel);
 
 	  if (truncate_win && data.bi_bufpos == BI_BUF_ZV (b)
 	      && BI_BUF_FETCH_CHAR (b, prev_bytind (b, BI_BUF_ZV (b))) != '\n')
@@ -2717,8 +2737,26 @@
 			     ? dl->left_glyphs
 			     : dl->right_glyphs);
   int elt, end;
-  int xpos = start;
   int reverse;
+  struct window *w = XWINDOW (window);
+  struct frame *f = XFRAME (w->frame);
+  struct device *d = XDEVICE (f->device);
+  pos_data data;
+
+  xzero (data);
+  data.d = d;
+  data.window = window;
+  data.db = db;
+  data.dl = dl;
+  data.pixpos = start;
+  data.cursor_type = NO_CURSOR;
+  data.cursor_x = -1;
+  data.last_charset = Qunbound;
+  data.last_findex = DEFAULT_INDEX;
+  data.result_str = Qnil;
+  data.string = Qnil;
+  data.new_ascent = dl->ascent;
+  data.new_descent = dl->descent;
 
   if ((layout == GL_WHITESPACE && side == LEFT_GLYPHS)
       || (layout == GL_INSIDE_MARGIN && side == RIGHT_GLYPHS))
@@ -2747,79 +2785,31 @@
 	   || (side == RIGHT_GLYPHS &&
 	       extent_end_glyph_layout (XEXTENT (gb->extent)) == layout)))
 	{
-	  struct rune rb;
-
-	  rb.width = gb->width;
-	  rb.findex = gb->findex;
-	  rb.xpos = xpos;
-	  rb.bufpos = -1;
-	  rb.endpos = 0;
-	  rb.type = RUNE_DGLYPH;
-	  rb.object.dglyph.glyph = gb->glyph;
-	  rb.object.dglyph.extent = gb->extent;
-	  rb.object.dglyph.xoffset = 0;
-	  rb.cursor_type = CURSOR_OFF;
-
-	  Dynarr_add (db->runes, rb);
-	  xpos += rb.width;
+	  data.findex = gb->findex;
+	  data.max_pixpos = data.pixpos + gb->width;
+	  add_glyph_rune (&data, gb, side, 0, NULL);
 	  count--;
 	  gb->active = 0;
-
-	  if (glyph_contrib_p (gb->glyph, window))
-	    {
-	      unsigned short ascent, descent;
-	      Lisp_Object baseline = glyph_baseline (gb->glyph, window);
-
-	      ascent = glyph_ascent (gb->glyph, window);
-	      descent = glyph_descent (gb->glyph, window);
-
-	      /* A pixmap that has not had a baseline explicitly set.
-                 We use the existing ascent / descent ratio of the
-                 line. */
-	      if (NILP (baseline))
-		{
-		  int gheight = ascent + descent;
-		  int line_height = dl->ascent + dl->descent;
-		  int pix_ascent, pix_descent;
-
-		  pix_descent = (int) (gheight * dl->descent) / line_height;
-		  pix_ascent = gheight - pix_descent;
-
-		  dl->ascent = max ((int) dl->ascent, pix_ascent);
-		  dl->descent = max ((int) dl->descent, pix_descent);
-		}
-
-	      /* A string so determine contribution normally. */
-	      else if (EQ (baseline, Qt))
-		{
-		  dl->ascent = max (dl->ascent, ascent);
-		  dl->descent = max (dl->descent, descent);
-		}
-
-	      /* A pixmap with an explicitly set baseline.  We determine the
-		 contribution here. */
-	      else if (INTP (baseline))
-		{
-		  int height = ascent + descent;
-		  int pix_ascent, pix_descent;
-
-		  pix_ascent = height * XINT (baseline) / 100;
-		  pix_descent = height - pix_ascent;
-
-		  dl->ascent = max ((int) dl->ascent, pix_ascent);
-		  dl->descent = max ((int) dl->descent, pix_descent);
-		}
-
-	      /* Otherwise something is screwed up. */
-	      else
-		abort ();
-	    }
 	}
 
       (reverse ? elt-- : elt++);
     }
 
-  return xpos;
+  if (data.max_pixmap_height)
+    {
+      int height = data.new_ascent + data.new_descent;
+      int pix_ascent, pix_descent;
+
+      pix_descent = data.max_pixmap_height * data.new_descent / height;
+      pix_ascent = data.max_pixmap_height - pix_descent;
+      data.new_ascent = max (data.new_ascent, pix_ascent);
+      data.new_descent = max (data.new_descent, pix_descent);
+    }
+
+  dl->ascent = data.new_ascent;
+  dl->descent = data.new_descent;
+
+  return data.pixpos;
 }
 
 /* Add a blank to a margin display block. */
@@ -3510,7 +3500,7 @@
 
   /* result_str is nil when we're building a frame or icon title. Otherwise,
      we're building a modeline, so the offset starts at the modeline
-     horizontal scrolling ammount */
+     horizontal scrolling amount */
   if (! NILP (result_str))
     offset = w->modeline_hscroll;
   generate_fstring_runes (w, &data, 0, 0, -1, format_str, 0,
@@ -3547,6 +3537,8 @@
       Bufbyte *strdata;
       struct buffer *buf = XBUFFER (WINDOW_BUFFER (w));
 
+      in_modeline_generation = 1;
+
       detach_all_extents (result_str);
       resize_string (XSTRING (result_str), -1,
                      data.bytepos - XSTRING_LENGTH (result_str));
@@ -3583,6 +3575,8 @@
              Dynarr_at (formatted_string_extent_end_dynarr, elt),
              result_str);
         }
+
+      in_modeline_generation = 0;
     }
 }
 
@@ -3626,10 +3620,6 @@
       /* The modeline is at the bottom of the gutters. */
       dl->ypos = WINDOW_BOTTOM (w);
 
-      /* adjust for the bottom gutter */
-      if (window_is_lowest (w))
-	dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
-
       rb.findex = MODELINE_INDEX;
       rb.xpos = dl->bounds.left_out;
       rb.width = dl->bounds.right_out - dl->bounds.left_out;
@@ -3683,18 +3673,15 @@
      set this until we've generated the modeline in order to account
      for any embedded faces. */
   dl->ypos = WINDOW_BOTTOM (w) - dl->descent - ypos_adj;
-  /* adjust for the bottom gutter */
-  if (window_is_lowest (w))
-    dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
 }
 
 static Charcount
-add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str,
+add_string_to_fstring_db_runes (pos_data *data, const Bufbyte *str,
                                 Charcount pos, Charcount min_pos, Charcount max_pos)
 {
   /* This function has been Mule-ized. */
   Charcount end;
-  CONST Bufbyte *cur_pos = str;
+  const Bufbyte *cur_pos = str;
   struct display_block *db = data->db;
 
   data->blank_width = space_width (XWINDOW (data->window));
@@ -3702,13 +3689,13 @@
     add_blank_rune (data, NULL, 0);
 
   end = (Dynarr_length (db->runes) +
-         bytecount_to_charcount (str, strlen ((CONST char *) str)));
+         bytecount_to_charcount (str, strlen ((const char *) str)));
   if (max_pos != -1)
     end = min (max_pos, end);
 
   while (pos < end && *cur_pos)
     {
-      CONST Bufbyte *old_cur_pos = cur_pos;
+      const Bufbyte *old_cur_pos = cur_pos;
       int succeeded;
 
       data->ch = charptr_emchar (cur_pos);
@@ -3820,7 +3807,7 @@
 		{
 		  Charcount tmp_max = (max_pos == -1 ? pos + size - *offset :
 				       min (pos + size - *offset, max_pos));
-		  CONST Bufbyte *tmp_last = charptr_n_addr (last, *offset);
+		  const Bufbyte *tmp_last = charptr_n_addr (last, *offset);
 
 		  pos = add_string_to_fstring_db_runes (data, tmp_last,
 							pos, pos, tmp_max);
@@ -3877,7 +3864,7 @@
 
                   while (num_to_add--)
                     pos = add_string_to_fstring_db_runes
-                      (data, (CONST Bufbyte *) "-", pos, pos, max_pos);
+                      (data, (const Bufbyte *) "-", pos, pos, max_pos);
                 }
               else if (*this != 0)
                 {
@@ -3896,7 +3883,7 @@
 		    *offset -= size;
 		  else
 		    {
-		      CONST Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+		      const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
 
 		      /* #### NOTE: I don't understand why a tmp_max is not
 			 computed and used here as in the plain string case
@@ -3942,7 +3929,7 @@
 		*offset -= size;
 	      else
 		{
-		  CONST Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+		  const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
 
 		  /* #### NOTE: I don't understand why a tmp_max is not
 		     computed and used here as in the plain string case
@@ -3983,8 +3970,8 @@
        * - If first element is another symbol, process the cadr or caddr
        *   recursively according to whether the symbol's value is non-nil or
        *   nil.
-       * - If first element is a face, process the cdr recursively
-       *   without altering the depth.
+       * - If first element is an extent, process the cdr recursively
+       *   and handle the extent's face.
        */
 
       Lisp_Object car, tem;
@@ -4136,8 +4123,8 @@
 	  *offset -= size;
 	else
 	  {
-	    CONST Bufbyte *tmp_str =
-	      charptr_n_addr ((CONST Bufbyte *) str, *offset);
+	    const Bufbyte *tmp_str =
+	      charptr_n_addr ((const Bufbyte *) str, *offset);
 
 	    /* #### NOTE: I don't understand why a tmp_max is not computed and
 	       used here as in the plain string case above. -- dv */
@@ -4150,7 +4137,7 @@
 
   if (min_pos > pos)
     {
-      add_string_to_fstring_db_runes (data, (CONST Bufbyte *) "", pos,
+      add_string_to_fstring_db_runes (data, (const Bufbyte *) "", pos,
 				      min_pos, -1);
     }
 
@@ -4297,9 +4284,9 @@
   int truncate_win = b ? window_truncation_on (w) : 0;
   int end_glyph_width = 0;
 
-  /* we're going to ditch selective display for static text, its an
-     FSF thing and invisble extents are the way to go
-     here. Implementing it also relies on a number of buffer-specific
+  /* We're going to ditch selective display for static text, it's an
+     FSF thing and invisible extents are the way to go here.
+     Implementing it also relies on a number of buffer-specific
      functions that we don't have the luxury of being able to use
      here. */
 
@@ -4365,6 +4352,7 @@
 
   dl->used_prop_data = 0;
   dl->num_chars = 0;
+  dl->line_continuation = 0;
 
   /* set up faces to use for clearing areas, used by
      output_display_line */
@@ -4757,6 +4745,7 @@
 
 	      /* data.bi_bufpos is already at the start of the next line. */
 
+	      dl->line_continuation = 1;
 	      gb.glyph = Vcontinuation_glyph;
 	      cachel = GLYPH_CACHEL (w, CONT_GLYPH_INDEX);
 	    }
@@ -4766,7 +4755,7 @@
 
 	  if (truncate_win && data.bi_bufpos == bi_string_zv)
 	    {
-	      CONST Bufbyte* endb = charptr_n_addr (string_data (s), bi_string_zv);
+	      const Bufbyte* endb = charptr_n_addr (string_data (s), bi_string_zv);
 	      DEC_CHARPTR (endb);
 	      if (charptr_emchar (endb) != '\n')
 		{
@@ -5098,6 +5087,7 @@
   int ypos = WINDOW_TEXT_TOP (w);
   int yend;	/* set farther down */
   int yclip = WINDOW_TEXT_TOP_CLIP (w);
+  int force;
 
   prop_block_dynarr *prop;
   layout_bounds bounds;
@@ -5151,7 +5141,14 @@
   else
     prop = 0;
 
-  while (ypos < yend)
+  /* When we are computing things for scrolling purposes, make
+     sure at least one line is always generated */
+  force = (type == CMOTION_DISP);
+
+  /* Make sure this is set always */
+  /* Note the conversion at end */
+  w->window_end_pos[type] = start_pos;
+  while (ypos < yend || force)
     {
       struct display_line dl;
       struct display_line *dlp;
@@ -5204,7 +5201,7 @@
 	     the top clip and the bottom clip. */
 	  visible_height -= (dlp->clip + dlp->top_clip);
 
-	  if (visible_height < VERTICAL_CLIP (w, 1))
+	  if (visible_height < VERTICAL_CLIP (w, 1) && !force)
 	    {
 	      if (local)
 		free_display_line (dlp);
@@ -5248,16 +5245,22 @@
 	 generate_display_line call. */
       if (start_pos > BUF_ZV (b))
 	break;
+
+      force = 0;
     }
 
   if (prop)
     Dynarr_free (prop);
 
   /* #### More not quite right, but close enough. */
-  /* #### Ben sez: apparently window_end_pos[] is measured
+  /* Ben sez: apparently window_end_pos[] is measured
      as the number of characters between the window end and the
      end of the buffer?  This seems rather weirdo.  What's
-     the justification for this? */
+     the justification for this?
+
+     JV sez: Because BUF_Z (b) would be a good initial value, however
+     that can change. This representation allows initalizing with 0.
+  */
   w->window_end_pos[type] = BUF_Z (b) - w->window_end_pos[type];
 
   if (need_modeline)
@@ -5588,20 +5591,9 @@
       assert (cdl->end_bufpos == ddl->end_bufpos);
       assert (cdl->offset == ddl->offset);
 
-      /* If the last rune is already a continuation glyph, fail.
-         #### We should be able to handle this better. */
-      {
-	struct display_block *db = get_display_block_from_line (ddl, TEXT);
-	if (Dynarr_length (db->runes))
-	  {
-	    struct rune *rb =
-	      Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-
-	    if (rb->type == RUNE_DGLYPH
-		&& EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
-	      return 0;
-	  }
-      }
+      /* If the line continues to next display line, fail. */
+      if (ddl->line_continuation)
+	return 0;
 
       /* If the line was generated using propagation data, fail. */
       if (ddl->used_prop_data)
@@ -5619,19 +5611,9 @@
 	  return 0;
 	}
 
-      /* If the last rune is now a continuation glyph, fail. */
-      {
-	struct display_block *db = get_display_block_from_line (ddl, TEXT);
-	if (Dynarr_length (db->runes))
-	  {
-	    struct rune *rb =
-	      Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-
-	    if (rb->type == RUNE_DGLYPH
-		&& EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
-	      return 0;
-	  }
-      }
+      /* If the line continues to next display line, fail. */
+      if (ddl->line_continuation)
+	return 0;
 
       /* If any line position parameters have changed or a
          cursor has disappeared or disappeared, fail. */
@@ -6007,7 +5989,7 @@
       && !(MINI_WINDOW_P (w) && f->buffers_changed)
       && !f->frame_changed
       && !truncation_changed
-      /* check whether start is really at the begining of a line  GE */
+      /* check whether start is really at the beginning of a line  GE */
       && (!w->start_at_line_beg || beginning_of_line_p (b, startp))
       )
     {
@@ -6021,7 +6003,7 @@
 	  && !f->faces_changed
 	  && !f->glyphs_changed
 	  && !f->subwindows_changed
-	  && !f->subwindows_state_changed
+	  /*	  && !f->subwindows_state_changed*/
 	  && !f->point_changed
 	  && !f->windows_structure_changed)
 	{
@@ -6043,7 +6025,7 @@
 	      && !f->faces_changed
 	      && !f->glyphs_changed
 	      && !f->subwindows_changed
-	      && !f->subwindows_state_changed
+	      /*	      && !f->subwindows_state_changed*/
 	      && !f->windows_structure_changed)
 	    {
 	      if (point_visible (w, pointm, CURRENT_DISP)
@@ -6102,7 +6084,7 @@
 	   && !f->faces_changed
 	   && !f->glyphs_changed
 	   && !f->subwindows_changed
-	   && !f->subwindows_state_changed
+	   /*	   && !f->subwindows_state_changed*/
 	   && !f->windows_structure_changed
 	   && !f->frame_changed
 	   && !truncation_changed
@@ -6284,7 +6266,7 @@
 
 /* Ensure that all windows on the given frame are correctly displayed. */
 
-static int
+int
 redisplay_frame (struct frame *f, int preemption_check)
 {
   struct device *d = XDEVICE (f->device);
@@ -6301,6 +6283,16 @@
 	return 1;
     }
 
+  if (!internal_equal (f->old_buffer_alist, f->buffer_alist, 0))
+    {
+      Lisp_Object frame;
+
+      f->old_buffer_alist = Freplace_list (f->old_buffer_alist,
+					   f->buffer_alist);
+      XSETFRAME (frame, f);
+      va_run_hook_with_args (Qbuffer_list_changed_hook, 1, frame);
+    }
+
   /* Before we put a hold on frame size changes, attempt to process
      any which are already pending. */
   if (f->size_change_pending)
@@ -6326,40 +6318,33 @@
      being handled. */
   update_frame_menubars (f);
 #endif /* HAVE_MENUBARS */
-  /* widgets are similar to menus in that they can call lisp to
-     determine activation etc. Therefore update them before we get
-     into redisplay. This is primarily for connected widgets such as
-     radio buttons. */
-  update_frame_subwindows (f);
 #ifdef HAVE_TOOLBARS
   /* Update the toolbars. */
   update_frame_toolbars (f);
 #endif /* HAVE_TOOLBARS */
+  /* Gutter update proper has to be done inside display when no frame
+     size changes can occur, thus we separately update the gutter
+     geometry here if it needs it. */
+  update_frame_gutter_geometry (f);
 
   /* If we clear the frame we have to force its contents to be redrawn. */
   if (f->clear)
     f->frame_changed = 1;
 
-  /* invalidate the subwindow cache. We use subwindows_changed here to
-     cause subwindows to get instantiated. This is because
+  /* Invalidate the subwindow caches. We use subwindows_changed here
+     to cause subwindows to get instantiated. This is because
      subwindows_state_changed is less strict - dealing with things
      like the clicked state of button. We have to do this before
      redisplaying the gutters as subwindows get unmapped in the
      process.*/
-  if (!Dynarr_length (f->subwindow_cachels)
-      || f->subwindows_changed
-      || f->faces_changed
-      || f->frame_changed)
-    {
-      reset_subwindow_cachels (f);
+  if (f->frame_changed)
+    reset_frame_subwindow_instance_cache (f);
+
+  if (f->frame_changed || f->subwindows_changed)
+    {
       /* we have to do this so the gutter gets regenerated. */
       reset_gutter_display_lines (f);
     }
-  else
-    mark_subwindow_cachels_as_not_updated (f);
-  /* We can now update the gutters, safe in the knowledge that our
-     efforts won't get undone. */
-  update_frame_gutters (f);
 
   hold_frame_size_changes ();
 
@@ -6387,10 +6372,22 @@
      #### If a frame-size change does occur we should probably
      actually be preempting redisplay. */
 
+  MAYBE_DEVMETH (d, frame_output_begin, (f));
+
+  /* We can now update the gutters, safe in the knowledge that our
+     efforts won't get undone. */
+
+  /* This can call lisp, but redisplay is protected by binding
+     inhibit_quit.  More importantly the code involving display lines
+     *assumes* that GC will not happen and so does not GCPRO
+     anything. Since we use this code the whole time with the gutters
+     we cannot allow GC to happen when manipulating the gutters. */
+  update_frame_gutters (f);
+
   /* Erase the frame before outputting its contents. */
   if (f->clear)
     {
-      DEVMETH (d, clear_frame, (f));
+      MAYBE_DEVMETH (d, clear_frame, (f));
     }
 
   /* Do the selected window first. */
@@ -6399,11 +6396,7 @@
   /* Then do the rest. */
   redisplay_windows (f->root_window, 1);
 
-  /* We now call the output_end routine for tty frames.  We delay
-     doing so in order to avoid cursor flicker.  So much for 100%
-     encapsulation. */
-  if (FRAME_TTY_P (f))
-    DEVMETH (d, output_end, (d));
+  MAYBE_DEVMETH (d, frame_output_end, (f));
 
   update_frame_title (f);
 
@@ -6675,7 +6668,7 @@
 decode_mode_spec (struct window *w, Emchar spec, int type)
 {
   Lisp_Object obj = Qnil;
-  CONST char *str = NULL;
+  const char *str = NULL;
   struct buffer *b = XBUFFER (w->buffer);
 
   Dynarr_reset (mode_spec_bufbyte_string);
@@ -6704,7 +6697,7 @@
 	long_to_string (buf, col);
 
 	Dynarr_add_many (mode_spec_bufbyte_string,
-			 (CONST Bufbyte *) buf, strlen (buf));
+			 (const Bufbyte *) buf, strlen (buf));
 
 	goto decode_mode_spec_done;
       }
@@ -7041,7 +7034,9 @@
     }
 }
 
-static void
+/* See the comment in image_instantiate_cache_result as to why marking
+   the glyph will also mark the image_instance. */
+void
 mark_redisplay_structs (display_line_dynarr *dla)
 {
   display_line *dl = Dynarr_atp (dla, 0);
@@ -7101,6 +7096,7 @@
       struct frame *f = XFRAME (XCAR (frmcons));
       update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
+      mark_gutters (f);
     }
 }
 
@@ -7537,11 +7533,18 @@
    displayed.  The end of the last line is also know as the window end
    position.
 
+   WARNING: It is possible that redisplay failed to layout any lines for the
+   windows. Under normal circumstances this is rare. However it seems that it
+   does occur in the following situation: A mouse event has come in and we
+   need to compute its location in a window. That code (in
+   pixel_to_glyph_translation) already can handle 0 as an error return value.
+
    #### With a little work this could probably be reworked as just a
    call to start_with_line_at_pixpos. */
 
 static Bufpos
-start_end_of_last_line (struct window *w, Bufpos startp, int end)
+start_end_of_last_line (struct window *w, Bufpos startp, int end,
+                        int may_error)
 {
   struct buffer *b = XBUFFER (w->buffer);
   line_start_cache_dynarr *cache = w->line_start_cache;
@@ -7561,7 +7564,7 @@
 
   start_elt = point_in_line_start_cache (w, cur_start, 0);
   if (start_elt == -1)
-    abort ();	/* this had better never happen */
+      return may_error ? 0 : startp;
 
   while (1)
     {
@@ -7625,7 +7628,7 @@
 Bufpos
 start_of_last_line (struct window *w, Bufpos startp)
 {
-  return start_end_of_last_line (w, startp, 0);
+  return start_end_of_last_line (w, startp, 0 , 0);
 }
 
 /* For the given window W, if display starts at STARTP, what will be
@@ -7635,9 +7638,16 @@
 Bufpos
 end_of_last_line (struct window *w, Bufpos startp)
 {
-  return start_end_of_last_line (w, startp, 1);
+  return start_end_of_last_line (w, startp, 1, 0);
 }
 
+static Bufpos
+end_of_last_line_may_error (struct window *w, Bufpos startp)
+{
+  return start_end_of_last_line (w, startp, 1, 1);
+}
+
+
 /* For window W, what does the starting position have to be so that
    the line containing POINT will cover pixel position PIXPOS. */
 
@@ -7821,7 +7831,6 @@
 
   validate_line_start_cache (w);
   w->line_cache_validation_override++;
-  updating_line_start_cache = 1;
 
   if (from < BUF_BEGV (b))
     from = BUF_BEGV (b);
@@ -7830,7 +7839,6 @@
 
   if (from > to)
     {
-      updating_line_start_cache = 0;
       w->line_cache_validation_override--;
       return;
     }
@@ -7843,7 +7851,6 @@
       /* Check to see if the desired range is already in the cache. */
       if (from >= low_bound && to <= high_bound)
 	{
-	  updating_line_start_cache = 0;
 	  w->line_cache_validation_override--;
 	  return;
 	}
@@ -7872,7 +7879,6 @@
       update_internal_cache_list (w, DESIRED_DISP);
       if (!Dynarr_length (internal_cache))
 	{
-	  updating_line_start_cache = 0;
 	  w->line_cache_validation_override--;
 	  return;
 	}
@@ -7900,7 +7906,6 @@
 	{
 	  Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
 			   Dynarr_length (internal_cache));
-	  updating_line_start_cache = 0;
 	  w->line_cache_validation_override--;
 	  return;
 	}
@@ -7909,7 +7914,6 @@
          the bounds of the DESIRED structs in the first place. */
       if (start >= low_bound && end <= high_bound)
 	{
-	  updating_line_start_cache = 0;
 	  w->line_cache_validation_override--;
 	  return;
 	}
@@ -7932,7 +7936,6 @@
 	      Dynarr_reset (cache);
 	      Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
 			       Dynarr_length (internal_cache));
-	      updating_line_start_cache = 0;
 	      w->line_cache_validation_override--;
 	      return;
 	    }
@@ -7958,7 +7961,6 @@
 	      Dynarr_reset (cache);
 	      Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
 			       Dynarr_length (internal_cache));
-	      updating_line_start_cache = 0;
 	      w->line_cache_validation_override--;
 	      return;
 	    }
@@ -7967,7 +7969,6 @@
 			   Dynarr_length (internal_cache) - ic_elt);
 	}
 
-      updating_line_start_cache = 0;
       w->line_cache_validation_override--;
       return;
     }
@@ -7987,23 +7988,9 @@
 	  update_internal_cache_list (w, CMOTION_DISP);
 
 	  /* If this assert is triggered then regenerate_window failed
-             to layout a single line.  That is not supposed to be
-             possible because we impose a minimum height on the buffer
-             and override vertical clip when we are in here. */
-	  /* #### Ah, but it is because the window may temporarily
-             exist but not have any lines at all if the minibuffer is
-             real big.  Look into that situation better. */
-	  if (!Dynarr_length (internal_cache))
-	    {
-	      if (old_lb == -1 && low_bound == -1)
-		{
-		  updating_line_start_cache = 0;
-		  w->line_cache_validation_override--;
-		  return;
-		}
-
-	      assert (Dynarr_length (internal_cache));
-	    }
+             to layout a single line. This is not possible since we
+	     force at least a single line to be layout for CMOTION_DISP */
+	  assert (Dynarr_length (internal_cache));
 	  assert (startp == Dynarr_atp (internal_cache, 0)->start);
 
 	  ic_elt = Dynarr_length (internal_cache) - 1;
@@ -8049,7 +8036,6 @@
 	  startp = new_startp;
 	  if (startp > BUF_ZV (b))
 	    {
-	      updating_line_start_cache = 0;
 	      w->line_cache_validation_override--;
 	      return;
 	    }
@@ -8083,7 +8069,6 @@
       while (to > high_bound);
     }
 
-  updating_line_start_cache = 0;
   w->line_cache_validation_override--;
   assert (to <= high_bound);
 }
@@ -8791,7 +8776,7 @@
   if (!MARKERP ((*w)->start[CURRENT_DISP]))
     *closest = 0;
   else
-    *closest = end_of_last_line (*w,
+    *closest = end_of_last_line_may_error (*w,
 				 marker_position ((*w)->start[CURRENT_DISP]));
   *col = 0;
   UPDATE_CACHE_RETURN;
@@ -8824,6 +8809,9 @@
 	  if (FRAME_REPAINT_P (f) && FRAME_HAS_MINIBUF_P (f))
 	    {
 	      Lisp_Object window = FRAME_MINIBUF_WINDOW (f);
+
+	      MAYBE_DEVMETH (d, frame_output_begin, (f));
+
 	      /*
 	       * If the frame size has changed, there may be random
 	       * chud on the screen left from previous messages
@@ -8832,19 +8820,15 @@
 	       */
 	      if (f->echo_area_garbaged)
 		{
-		  DEVMETH (d, clear_frame, (f));
+		  MAYBE_DEVMETH (d, clear_frame, (f));
 		  f->echo_area_garbaged = 0;
 		}
 	      redisplay_window (window, 0);
+	      MAYBE_DEVMETH (d, frame_output_end, (f));
+
 	      call_redisplay_end_triggers (XWINDOW (window), 0);
 	    }
 	}
-
-      /* We now call the output_end routine for tty frames.  We delay
-	 doing so in order to avoid cursor flicker.  So much for 100%
-	 encapsulation. */
-      if (DEVICE_TTY_P (d))
-	DEVMETH (d, output_end, (d));
     }
 
   return Qnil;
@@ -8879,6 +8863,9 @@
   f->clear = 1;
   redisplay_frame (f, 1);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -8906,6 +8893,15 @@
 
   redisplay_frame (f, 1);
 
+  /* If we don't reset the global redisplay flags here, subsequent
+     changes to the display will not get registered by redisplay
+     because it thinks it already has registered changes. If you
+     really knew what you were doing you could confuse redisplay by
+     calling Fredisplay_frame while updating another frame. We assume
+     that if you know what you are doing you will not be that
+     stupid. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -8935,6 +8931,9 @@
     }
   redisplay_device (d, 0);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -8962,6 +8961,9 @@
 
   redisplay_device (d, 0);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -9224,6 +9226,8 @@
   defsymbol (&Qbar_cursor, "bar-cursor");
   defsymbol (&Qredisplay_end_trigger_functions,
 	     "redisplay-end-trigger-functions");
+  defsymbol (&Qtop_bottom, "top-bottom");
+  defsymbol (&Qbuffer_list_changed_hook, "buffer-list-changed-hook");
 
   DEFSUBR (Fredisplay_echo_area);
   DEFSUBR (Fredraw_frame);
@@ -9235,15 +9239,8 @@
 }
 
 void
-reinit_vars_of_redisplay (void)
-{
-  updating_line_start_cache = 0;
-}
-
-void
 vars_of_redisplay (void)
 {
-  reinit_vars_of_redisplay ();
 
 #if 0
   staticpro (&last_arrow_position);
@@ -9288,7 +9285,9 @@
   Voverlay_arrow_position = Qnil;
 
   DEFVAR_LISP_MAGIC ("overlay-arrow-string", &Voverlay_arrow_string /*
-String to display as an arrow.  See also `overlay-arrow-position'.
+String or glyph to display as an arrow.  See also `overlay-arrow-position'.
+(Note that despite the name of this variable, it can be set to a glyph as
+well as a string.)
 */ ,
 		     redisplay_variable_changed);
   Voverlay_arrow_string = Qnil;
@@ -9312,10 +9311,19 @@
 		     redisplay_variable_changed);
   truncate_partial_width_windows = 1;
 
-  DEFVAR_BOOL ("visible-bell", &visible_bell /*
-*Non-nil means try to flash the frame to represent a bell.
+  DEFVAR_LISP ("visible-bell", &Vvisible_bell /*
+*Non-nil substitutes a visual signal for the audible bell.
+
+Default behavior is to flash the whole screen.  On some platforms,
+special effects are available using the following values:
+
+'display       Flash the whole screen (ie, the default behavior).
+'top-bottom    Flash only the top and bottom lines of the selected frame.
+
+When effects are unavailable on a platform, the visual bell is the
+default, whole screen.  (Currently only X supports any special effects.)
 */ );
-  visible_bell = 0;
+  Vvisible_bell = Qnil;
 
   DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter /*
 *Non-nil means no need to redraw entire frame after suspending.
@@ -9366,17 +9374,22 @@
 #ifndef INHIBIT_REDISPLAY_HOOKS
   xxDEFVAR_LISP ("pre-redisplay-hook", &Vpre_redisplay_hook /*
 Function or functions to run before every redisplay.
-Functions on this hook must be careful to avoid signalling errors!
 */ );
   Vpre_redisplay_hook = Qnil;
 
   xxDEFVAR_LISP ("post-redisplay-hook", &Vpost_redisplay_hook /*
 Function or functions to run after every redisplay.
-Functions on this hook must be careful to avoid signalling errors!
 */ );
   Vpost_redisplay_hook = Qnil;
 #endif /* INHIBIT_REDISPLAY_HOOKS */
 
+  DEFVAR_LISP ("buffer-list-changed-hook", &Vbuffer_list_changed_hook /*
+Function or functions to call when a frame's buffer list has changed.
+This is called during redisplay, before redisplaying each frame.
+Functions on this hook are called with one argument, the frame.
+*/ );
+  Vbuffer_list_changed_hook = Qnil;
+
   DEFVAR_INT ("display-warning-tick", &display_warning_tick /*
 Bump this to tell the C code to call `display-warning-buffer'
 at next redisplay.  You should not normally change this; the function