XEmacs 21.4.10 "Military Intelligence".
[chise/xemacs-chise.git.1] / src / redisplay.c
index 17de60e..e664075 100644 (file)
@@ -40,7 +40,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include "lisp.h"
-#include <limits.h>
 
 #include "buffer.h"
 #include "commands.h"
@@ -64,11 +63,10 @@ Boston, MA 02111-1307, USA.  */
 #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 @@ Boston, MA 02111-1307, USA.  */
 #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. */
@@ -155,9 +147,9 @@ typedef struct position_redisplay_data_type
                           to be skipped before anything is displayed. */
   Bytind bi_start_col_enabled;
   int start_col_xoffset;       /* Number of pixels that still need to
-                          be skipped.  This is used for
-                          horizontal scrolling of glyphs, where we want
-                          to be able to scroll over part of the glyph. */
+                                   be skipped.  This is used for
+                                   horizontal scrolling of glyphs, where we want
+                                   to be able to scroll over part of the glyph. */
 
   int hscroll_glyph_width_adjust;  /* how much the width of the hscroll
                                      glyph differs from space_width (w).
@@ -171,18 +163,20 @@ typedef struct position_redisplay_data_type
   struct extent_fragment *ef;
   face_index findex;
 
-  /* The height of a pixmap may either be predetermined if the user
-     has set a baseline value, or it may be dependent on whatever the
-     line ascent and descent values end up being, based just on font
-     information.  In the first case we can immediately update the
-     values, thus their inclusion here.  In the last case we cannot
-     determine the actual contribution to the line height until we
-     have finished laying out all text on the line.  Thus we propagate
-     the max height of such pixmaps and do a final calculation after
-     all text has been added to the line. */
+  /* The height of a pixmap may either be predetermined if the user has set a
+     baseline value, or it may be dependent on whatever the line ascent and
+     descent values end up being, based just on font and pixmap-ascent
+     information.  In the first case we can immediately update the values, thus
+     their inclusion here.  In the last case we cannot determine the actual
+     contribution to the line height until we have finished laying out all text
+     on the line.  Thus we propagate the max height of such pixmaps and do a
+     final calculation (in calculate_baseline()) after all text has been added
+     to the line. */
   int new_ascent;
   int new_descent;
   int max_pixmap_height;
+  int need_baseline_computation;
+  int end_glyph_width;         /* Well, it is the kitchen sink after all ... */
 
   Lisp_Object result_str; /* String where we put the result of
                             generating a formatted string in the modeline. */
@@ -200,15 +194,24 @@ enum prop_type
   PROP_STRING,
   PROP_CHAR,
   PROP_MINIBUF_PROMPT,
-  PROP_BLANK
+  PROP_BLANK,
+  PROP_GLYPH
 };
 
 /* Data that should be propagated to the next line.  Either a single
-   Emchar or a string of Bufbyte's.
+   Emchar, a string of Bufbyte's or a glyph.
 
    The actual data that is propagated ends up as a Dynarr of these
    blocks.
 
+   prop_blocks are used to indicate that data that was supposed to go
+   on the previous line couldn't actually be displayed. Generally this
+   shouldn't happen if we are clipping the end of lines. If we are
+   wrapping then we need to display the propagation data before moving
+   on. Its questionable whether we should wrap or clip glyphs in this
+   instance. Most e-lisp relies on clipping so we preserve this
+   behavior.
+
    #### It's unclean that both Emchars and Bufbytes are here.
    */
 
@@ -237,6 +240,14 @@ struct prop_block
       int width;
       face_index findex;
     } p_blank;
+
+    struct
+    {
+      /* Not used as yet, but could be used to wrap rather than clip glyphs. */
+      int width;               
+      Lisp_Object glyph;
+    } p_glyph;
+
   } data;
 };
 
@@ -273,6 +284,9 @@ static void free_display_line (struct display_line *dl);
 static void update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
                                     Bufpos point, int no_regen);
 static int point_visible (struct window *w, Bufpos point, int type);
+static void calculate_yoffset (struct display_line *dl,
+                               struct display_block *fixup);
+static void calculate_baseline (pos_data *data);
 
 /* This used to be 10 but 30 seems to give much better performance. */
 #define INIT_MAX_PREEMPTS      30
@@ -308,7 +322,7 @@ static Bytecount_dynarr *formatted_string_extent_end_dynarr;
 
 
 /* #### probably temporary */
-int cache_adjustment;
+Fixnum cache_adjustment;
 
 /* This holds a string representing the text corresponding to a single
    modeline % spec. */
@@ -323,13 +337,10 @@ int disable_preemption;   /* Used for debugging redisplay and for
 static int preemption_count;
 
 /* Minimum pixel height of clipped bottom display line. */
-int vertical_clip;
+Fixnum vertical_clip;
 
 /* 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;
+Fixnum horizontal_clip;
 
 /* Nonzero means reading single-character input with prompt
    so put cursor on minibuffer after the prompt.  */
@@ -364,8 +375,7 @@ int frame_changed;
 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;
 
@@ -404,6 +414,10 @@ int asynch_device_change_pending;
 int toolbar_changed;
 int toolbar_changed_set;
 
+/* Nonzero if some frame has changed the layout of internal elements
+   (gutters or toolbars). */
+int frame_layout_changed;
+
 /* non-nil if any gutter has changed */
 int gutter_changed;
 int gutter_changed_set;
@@ -419,9 +433,9 @@ int windows_structure_changed;
 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,
@@ -437,10 +451,10 @@ Lisp_Object Vglobal_mode_string;
 
 /* The number of lines scroll a window by when point leaves the window; if
   it is <=0 then point is centered in the window */
-int scroll_step;
+Fixnum scroll_step;
 
 /* Scroll up to this many lines, to bring point back on screen. */
-int scroll_conservatively;
+Fixnum scroll_conservatively;
 
 /* Marker for where to display an arrow on top of the buffer text.  */
 Lisp_Object Voverlay_arrow_position;
@@ -451,6 +465,9 @@ Lisp_Object Vwindow_size_change_functions;
 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
@@ -460,7 +477,8 @@ Lisp_Object Vpre_redisplay_hook, Vpost_redisplay_hook;
 Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook;
 #endif /* INHIBIT_REDISPLAY_HOOKS */
 
-static int last_display_warning_tick, display_warning_tick;
+static Fixnum last_display_warning_tick;
+static Fixnum display_warning_tick;
 Lisp_Object Qdisplay_warning_buffer;
 int inhibit_warning_display;
 
@@ -471,8 +489,9 @@ Lisp_Object Vtext_cursor_visible_p;
 
 int column_number_start_at_one;
 
-#define WINDOW_SCROLLED(w) \
-(w->hscroll > 0 || w->left_xoffset)
+Lisp_Object Qtop_bottom;
+
+#define WINDOW_SCROLLED(w) ((w)->hscroll > 0 || (w)->left_xoffset)
 
 \f
 /***************************************************************************/
@@ -687,6 +706,108 @@ calculate_display_line_boundaries (struct window *w, int modeline)
   return bounds;
 }
 
+/* This takes a display_block and its containing line and corrects the yoffset
+   of each glyph in the block to cater for the ascent of the line as a
+   whole. Must be called *after* the line-ascent is known! */
+
+static void
+calculate_yoffset (struct display_line *dl, struct display_block *fixup)
+{
+  int i;
+  for (i=0; i<Dynarr_length (fixup->runes); i++)
+    {
+      struct rune *r = Dynarr_atp (fixup->runes,i);
+      if (r->type == RUNE_DGLYPH)
+        {
+          if (r->object.dglyph.ascent < dl->ascent)
+            r->object.dglyph.yoffset = dl->ascent - r->object.dglyph.ascent +
+             r->object.dglyph.descent;
+        }
+    }
+}
+
+/* Calculate the textual baseline (the ascent and descent values for the
+   display_line as a whole).
+
+   If the baseline is completely blank, or contains no manually positioned
+   glyphs, then the textual baseline is simply the baseline of the default font.
+   (The `contains no manually positioned glyphs' part is actually done for
+   us by `add_emchar_rune'.)
+
+   If the baseline contains pixmaps, and they're all manually positioned, then
+   the textual baseline location is constrained that way, and we need do no
+   work.
+
+   If the baseline contains pixmaps, and at least one is automatically
+   positioned, then the textual ascent is the largest ascent on the line, and
+   the textual descent is the largest descent (which is how things are set up at
+   entry to this function anyway): except that if the max_ascent + max_descent
+   is too small for the height of the line (say you've adjusted the baseline of
+   a short glyph, and there's a tall one next to it), then take the ascent and
+   descent for the line individually from the largest of the explicitly set
+   ascent/descent, and the rescaled ascent/descent of the default font, scaled
+   such that the largest glyph will fit.
+
+   This means that if you have a short glyph (but taller than the default
+   font's descent) forced right under the baseline, and a really tall
+   automatically positioned glyph, that the descent for the line is just big
+   enough for the manually positioned short glyph, and the tall one uses as
+   much of that space as the default font would were it as tall as the tall
+   glyph; but that the ascent is big enough for the tall glyph to fit.
+
+   This behaviour means that under no circumstances will changing the baseline
+   of a short glyph cause a tall glyph to move around; nor will it move the
+   textual baseline more than necessary. (Changing a tall glyph's baseline
+   might move the text's baseline arbitrarily, of course.) */
+
+static void
+calculate_baseline (pos_data *data)
+{
+  /* Blank line: baseline is default font's baseline. */
+
+  if (!data->new_ascent && !data->new_descent)
+    {
+      /* We've got a blank line so initialize these values from the default
+         face. */
+      default_face_font_info (data->window, &data->new_ascent,
+                             &data->new_descent, 0, 0, 0);
+    }
+  
+  /* No automatically positioned glyphs? Return at once. */
+  if (!data->need_baseline_computation)
+    return;
+
+  /* Is the tallest glyph on the line automatically positioned?
+     If it's manually positioned, or it's automatically positioned
+     and there's enough room for it anyway, we need do no more work. */
+  if (data->max_pixmap_height > data->new_ascent + data->new_descent)
+    {
+      int default_font_ascent, default_font_descent, default_font_height;
+      int scaled_default_font_ascent, scaled_default_font_descent;
+      
+      default_face_font_info (data->window, &default_font_ascent,
+                             &default_font_descent, &default_font_height,
+                             0, 0);
+
+      scaled_default_font_ascent = data->max_pixmap_height *
+       default_font_ascent / default_font_height;
+
+      data->new_ascent = max (data->new_ascent, scaled_default_font_ascent);
+
+      /* The ascent may have expanded now. Do we still need to grow the descent,
+         or are things big enough?
+
+         The +1 caters for the baseline row itself. */
+      if (data->max_pixmap_height > data->new_ascent + data->new_descent)
+        {
+          scaled_default_font_descent = (data->max_pixmap_height *
+                                        default_font_descent / default_font_height) + 1;
+
+          data->new_descent = max (data->new_descent, scaled_default_font_descent);
+        }
+    }
+}
+
 /* Given a display line and a starting position, ensure that the
    contents of the display line accurately represent the visual
    representation of the buffer contents starting from the given
@@ -803,7 +924,7 @@ add_hscroll_rune (pos_data *data)
   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 =
@@ -818,12 +939,14 @@ add_hscroll_rune (pos_data *data)
   return retval;
 }
 
-/* Adds a character rune to a display block.  If there is not enough
-   room to fit the rune on the display block (as determined by the
-   MAX_PIXPOS) then it adds nothing and returns ADD_FAILED. */
+/* Adds a character rune to a display block.  If there is not enough room
+   to fit the rune on the display block (as determined by the MAX_PIXPOS)
+   then it adds nothing and returns ADD_FAILED.  If
+   NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't allow the char's height
+   to affect the total line height. (See add_intbyte_string_runes()). */
 
 static prop_block_dynarr *
-add_emchar_rune (pos_data *data)
+add_emchar_rune_1 (pos_data *data, int no_contribute_to_line_height)
 {
   struct rune rb, *crb;
   int width, local;
@@ -859,7 +982,7 @@ add_emchar_rune (pos_data *data)
          Lisp_Object font_instance =
            ensure_face_cachel_contains_charset (cachel, data->window,
                                                 charset);
-         struct Lisp_Font_Instance *fi;
+         Lisp_Font_Instance *fi;
 
          if (EQ (font_instance, Vthe_null_font_instance))
            {
@@ -875,8 +998,13 @@ add_emchar_rune (pos_data *data)
            data->last_char_width = fi->width;
          else
            data->last_char_width = -1;
-         data->new_ascent  = max (data->new_ascent,  (int) fi->ascent);
-         data->new_descent = max (data->new_descent, (int) fi->descent);
+
+         if (!no_contribute_to_line_height)
+           {
+             data->new_ascent  = max (data->new_ascent,  (int) fi->ascent);
+             data->new_descent = max (data->new_descent, (int) fi->descent);
+           }
+
          data->last_charset = charset;
          data->last_findex = data->findex;
        }
@@ -923,9 +1051,7 @@ add_emchar_rune (pos_data *data)
   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;
@@ -962,13 +1088,24 @@ add_emchar_rune (pos_data *data)
   return NULL;
 }
 
-/* Given a string C_STRING of length C_LENGTH, call add_emchar_rune
-   for each character in the string.  Propagate any left-over data
-   unless NO_PROP is non-zero. */
-
+static prop_block_dynarr *
+add_emchar_rune (pos_data *data)
+{
+  return add_emchar_rune_1 (data, 0);
+}
+  
+/* Given a string C_STRING of length C_LENGTH, call add_emchar_rune for
+   each character in the string.  Propagate any left-over data unless
+   NO_PROP is non-zero.  If NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't
+   allow this character to increase the total height of the line. (This is
+   used when the character is part of a text glyph.  In that case, the
+   glyph code itself adjusts the line height as necessary, depending on
+   whether glyph-contrib-p is true.) */
+  
 static prop_block_dynarr *
 add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
-                         Bytecount c_length, int no_prop)
+                         Bytecount c_length, int no_prop,
+                         int no_contribute_to_line_height)
 {
   Bufbyte *pos, *end = c_string + c_length;
   prop_block_dynarr *prop;
@@ -981,9 +1118,11 @@ add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
 
   for (pos = c_string; pos < end;)
     {
+      Bufbyte *old_pos = pos;
+
       data->ch = charptr_emchar (pos);
 
-      prop = add_emchar_rune (data);
+      prop = add_emchar_rune_1 (data, no_contribute_to_line_height);
 
       if (prop)
        {
@@ -1006,6 +1145,9 @@ add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
        }
       INC_CHARPTR (pos);
       assert (pos <= end);
+      /* #### Duplicate code from add_string_to_fstring_db_runes
+        should we do more?*/
+      data->bytepos += pos - old_pos;
     }
 
   return NULL;
@@ -1115,12 +1257,11 @@ add_blank_rune (pos_data *data, struct window *w, int char_tab_width)
 static prop_block_dynarr *
 add_octal_runes (pos_data *data)
 {
-  prop_block_dynarr *prop, *add_failed;
+  prop_block_dynarr *add_failed, *prop = 0;
   Emchar orig_char = data->ch;
   unsigned int orig_cursor_type = data->cursor_type;
 
   /* Initialize */
-  prop = NULL;
   add_failed = NULL;
 
   if (data->start_col)
@@ -1180,7 +1321,7 @@ add_octal_runes (pos_data *data)
   ADD_NEXT_OCTAL_RUNE_CHAR;
 
   data->cursor_type = orig_cursor_type;
-  return prop;
+  return NULL;
 }
 
 #undef ADD_NEXT_OCTAL_RUNE_CHAR
@@ -1265,7 +1406,7 @@ add_disp_table_entry_runes_1 (pos_data *data, Lisp_Object entry)
       prop = add_bufbyte_string_runes (data,
                                       XSTRING_DATA   (entry),
                                       XSTRING_LENGTH (entry),
-                                      0);
+                                      0, 0);
     }
   else if (GLYPHP (entry))
     {
@@ -1320,10 +1461,11 @@ add_disp_table_entry_runes_1 (pos_data *data, Lisp_Object entry)
                    case '%':
                      dst += set_charptr_emchar (dst, '%');
                      break;
+                     /* #### unimplemented */
                    }
                }
            }
-         prop = add_bufbyte_string_runes (data, result, dst - result, 0);
+         prop = add_bufbyte_string_runes (data, result, dst - result, 0, 0);
        }
     }
 
@@ -1341,7 +1483,7 @@ add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
   prop_block_dynarr *prop = NULL;
   if (VECTORP (entry))
     {
-      struct Lisp_Vector *de = XVECTOR (entry);
+      Lisp_Vector *de = XVECTOR (entry);
       EMACS_INT len = vector_length (de);
       int elt;
 
@@ -1524,12 +1666,25 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 {
   struct window *w = XWINDOW (data->window);
 
+  /* If window faces changed, and glyph instance is text, then
+     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;
@@ -1537,6 +1692,9 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       int ascent, descent;
       Lisp_Object baseline;
       Lisp_Object face;
+      Lisp_Object instance;
+      face_index findex;
+      prop_block_dynarr *retval = 0;
 
       if (cachel)
        width = cachel->width;
@@ -1548,7 +1706,6 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
       if (data->start_col || data->start_col_xoffset)
        {
-         prop_block_dynarr *retval;
          int glyph_char_width = width / space_width (w);
 
          /* If we still have not fully scrolled horizontally after
@@ -1584,17 +1741,41 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       if (data->pixpos + width > data->max_pixpos)
        {
          /* If this is the first object we are attempting to add to
-             the line then we ignore the horizontal_clip threshold.
-             Otherwise we will loop until the bottom of the window
-             continually failing to add this glyph because it is wider
-             than the window.  We could alternatively just completely
-             ignore the glyph and proceed from there but I think that
-             this is a better solution. */
+            the line then we ignore the horizontal_clip threshold.
+            Otherwise we will loop until the bottom of the window
+            continually failing to add this glyph because it is wider
+            than the window.  We could alternatively just completely
+            ignore the glyph and proceed from there but I think that
+            this is a better solution.
+            
+            This does, however, create a different problem in that we
+            can end up adding the object to every single line, never
+            getting any further - for instance an extent with a long
+            start-glyph that covers multitple following
+            characters.  */
          if (Dynarr_length (data->db->runes)
              && data->max_pixpos - data->pixpos < horizontal_clip)
            return ADD_FAILED;
-         else
+         else {
+           struct prop_block pb;
+
+           /* We need to account for the width of the end-of-line
+              glyph if there is nothing more in the line to display,
+              since we will not display it in this instance. It seems
+              kind of gross doing it here, but otherwise we have to
+              search the runes in create_text_block(). */
+           if (data->ch == '\n')
+             data->max_pixpos += data->end_glyph_width;
            width = data->max_pixpos - data->pixpos;
+           /* Add the glyph we are displaying, but clipping, to the
+              propagation data so that we don't try and do it
+              again. */ 
+           retval = Dynarr_new (prop_block);
+           pb.type = PROP_GLYPH;
+           pb.data.p_glyph.glyph = gb->glyph;
+           pb.data.p_glyph.width = width;
+           Dynarr_add (retval, pb);
+         }
        }
 
       if (cachel)
@@ -1610,6 +1791,8 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
       baseline = glyph_baseline (gb->glyph, data->window);
 
+      rb.object.dglyph.descent = 0; /* Gets reset lower down, if it is known. */
+
       if (glyph_contrib_p (gb->glyph, data->window))
        {
          /* A pixmap that has not had a baseline explicitly set.  Its
@@ -1617,6 +1800,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
          if (NILP (baseline))
            {
              int height = ascent + descent;
+             data->need_baseline_computation = 1;
              data->max_pixmap_height = max (data->max_pixmap_height, height);
            }
 
@@ -1639,6 +1823,9 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
              data->new_ascent = max (data->new_ascent, pix_ascent);
              data->new_descent = max (data->new_descent, pix_descent);
+             data->max_pixmap_height = max (data->max_pixmap_height, height);
+             
+             rb.object.dglyph.descent = pix_descent;
            }
 
          /* Otherwise something is screwed up. */
@@ -1648,10 +1835,32 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
       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, 1);
+         data->findex = orig_findex;
+         data->bi_bufpos = orig_bufpos;
+         data->bi_start_col_enabled = orig_start_col_enabled;
+         return retval;
+       }
+
+      rb.findex = findex;
       rb.xpos = data->pixpos;
       rb.width = width;
       rb.bufpos = 0;                   /* glyphs are never "at" anywhere */
@@ -1662,16 +1871,12 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       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;
+      rb.object.dglyph.ascent = ascent;
+      rb.object.dglyph.yoffset = 0;   /* Until we know better, assume that it has
+                                        a normal (textual) baseline. */
 
       if (allow_cursor)
        {
@@ -1707,7 +1912,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       Dynarr_add (data->db->runes, rb);
       data->pixpos += width;
 
-      return NULL;
+      return retval;
     }
   else
     {
@@ -1736,7 +1941,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
        abort ();       /* there are no unknown types */
     }
 
-  return NULL; /* shut up compiler */
+  return NULL;
 }
 
 /* Add all glyphs at position POS_TYPE that are contained in the given
@@ -1796,7 +2001,6 @@ create_text_block (struct window *w, struct display_line *dl,
                           is_surrogate_for_selected_frame (f));
 
   int truncate_win = window_truncation_on (w);
-  int end_glyph_width;
 
   /* If the buffer's value of selective_display is an integer then
      only lines that start with less than selective_display columns of
@@ -1871,6 +2075,7 @@ create_text_block (struct window *w, struct display_line *dl,
 
   dl->used_prop_data = 0;
   dl->num_chars = 0;
+  dl->line_continuation = 0;
 
   xzero (data);
   data.ef = extent_fragment_new (w->buffer, f);
@@ -1893,10 +2098,10 @@ create_text_block (struct window *w, struct display_line *dl,
      glyph.  Save the width of the end glyph for later use. */
   data.max_pixpos = dl->bounds.right_in;
   if (truncate_win)
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
+    data.end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
   else
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
-  data.max_pixpos -= end_glyph_width;
+    data.end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
+  data.max_pixpos -= data.end_glyph_width;
 
   if (cursor_in_echo_area && MINI_WINDOW_P (w) && echo_area_active (f))
     {
@@ -1989,10 +2194,25 @@ create_text_block (struct window *w, struct display_line *dl,
       /* Check for face changes. */
       if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end))
        {
+         Lisp_Object last_glyph = Qnil;
+
+         /* Deal with glyphs that we have already displayed. The
+            theory is that if we end up with a PROP_GLYPH in the
+            propagation data then we are clipping the glyph and there
+            can be no propagation data before that point. The theory
+            works because we always recalculate the extent-fragments
+            for propagated data, we never actually propagate the
+            fragments that still need to be displayed. */
+         if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 
+           {
+             last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph;
+             Dynarr_free (*prop);
+             *prop = 0;
+           }
          /* Now compute the face and begin/end-glyph information. */
          data.findex =
            /* Remember that the extent-fragment routines deal in Bytind's. */
-           extent_fragment_update (w, data.ef, data.bi_bufpos);
+           extent_fragment_update (w, data.ef, data.bi_bufpos, last_glyph);
 
          get_display_tables (w, data.findex, &face_dt, &window_dt);
 
@@ -2062,9 +2282,9 @@ create_text_block (struct window *w, struct display_line *dl,
        }
 
       /* If there is propagation data, then it represents the current
-         buffer position being displayed.  Add them and advance the
-         position counter.  This might also add the minibuffer
-         prompt. */
+        buffer position being displayed.  Add them and advance the
+        position counter.  This might also add the minibuffer
+        prompt. */
       else if (*prop)
        {
          dl->used_prop_data = 1;
@@ -2086,19 +2306,59 @@ create_text_block (struct window *w, struct display_line *dl,
         here rather than doing them at the end of handling the
         previous run so that glyphs at the beginning and end of
         a line are handled correctly. */
-      else if (Dynarr_length (data.ef->end_glyphs) > 0)
+      else if (Dynarr_length (data.ef->end_glyphs) > 0
+              || Dynarr_length (data.ef->begin_glyphs) > 0)
        {
-         *prop = add_glyph_runes (&data, END_GLYPHS);
-         if (*prop)
-           goto done;
-       }
+         glyph_block_dynarr* tmpglyphs = 0;
+         /* #### I think this is safe, but could be wrong. */
+         data.ch = BI_BUF_FETCH_CHAR (b, data.bi_bufpos);
 
-      /* If there are begin glyphs, add them to the line. */
-      else if (Dynarr_length (data.ef->begin_glyphs) > 0)
-       {
-         *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-         if (*prop)
-           goto done;
+         if (Dynarr_length (data.ef->end_glyphs) > 0) 
+           {
+             *prop = add_glyph_runes (&data, END_GLYPHS);
+             tmpglyphs = data.ef->end_glyphs;
+           }
+
+         /* If there are begin glyphs, add them to the line. */
+         if (!*prop && Dynarr_length (data.ef->begin_glyphs) > 0) 
+           {
+             *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
+             tmpglyphs = data.ef->begin_glyphs;
+           }
+
+         if (*prop) 
+           {
+             /* If we just clipped a glyph and we are at the end of a
+                line and there are more glyphs to display then do
+                appropriate processing to not get a continuation
+                glyph. */
+             if (*prop != ADD_FAILED 
+                 && Dynarr_atp (*prop, 0)->type == PROP_GLYPH
+                 && data.ch == '\n')
+               { 
+                 /* If there are no more glyphs then do the normal
+                    processing. 
+
+                    #### This doesn't actually work if the same glyph is
+                    present more than once in the block. To solve
+                    this we would have to carry the index around
+                    which might be problematic since the fragment is
+                    recalculated for each line. */
+                 if (EQ (Dynarr_end (tmpglyphs)->glyph,
+                         Dynarr_atp (*prop, 0)->data.p_glyph.glyph))
+                   {
+                     Dynarr_free (*prop);
+                     *prop = 0;
+                   }
+                 else {
+                   data.blank_width = DEVMETH (d, eol_cursor_width, ());
+                   add_emchar_rune (&data); /* discard prop data. */
+                   goto done;
+                 }
+               }
+             else
+               goto done;
+           }
        }
 
       /* If at end-of-buffer, we've already processed begin and
@@ -2132,7 +2392,7 @@ create_text_block (struct window *w, struct display_line *dl,
              /* We aren't going to be adding an end glyph so give its
                  space back in order to make sure that the cursor can
                  fit. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
 
              if (selective > 0
                  && (bi_spaces_at_point
@@ -2213,7 +2473,7 @@ create_text_block (struct window *w, struct display_line *dl,
 
              /* We won't be adding a truncation or continuation glyph
                  so give up the room allocated for them. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
 
              if (!NILP (b->selective_display_ellipses))
                {
@@ -2422,7 +2682,7 @@ done:
              for the next newline.  We also add the end-of-line glyph which
              we know will fit because we adjusted the right border before
              we starting laying out the line. */
-         data.max_pixpos += end_glyph_width;
+         data.max_pixpos += data.end_glyph_width;
          data.findex = DEFAULT_INDEX;
          gb.extent = Qnil;
 
@@ -2461,11 +2721,12 @@ done:
 
              /* 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')
@@ -2556,26 +2817,7 @@ done:
   else
     db->end_pos = dl->bounds.right_white;
 
-  /* update line height parameters */
-  if (!data.new_ascent && !data.new_descent)
-    {
-      /* We've got a blank line so initialize these values from the default
-         face. */
-      default_face_font_info (data.window, &data.new_ascent,
-                             &data.new_descent, 0, 0, 0);
-    }
-
-  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);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -2593,6 +2835,8 @@ done:
       dl->descent = descent;
   }
 
+  calculate_yoffset (dl, db);
+
   dl->cursor_elt = data.cursor_x;
   /* #### lossage lossage lossage! Fix this shit! */
   if (data.bi_bufpos > BI_BUF_ZV (b))
@@ -2671,7 +2915,7 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
        (&data,
         XSTRING_DATA   (Voverlay_arrow_string),
         XSTRING_LENGTH (Voverlay_arrow_string),
-        1);
+        1, 0);
     }
   else if (GLYPHP (Voverlay_arrow_string))
     {
@@ -2682,17 +2926,7 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
       add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, 0);
     }
 
-  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);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -2700,6 +2934,8 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
   data.db->start_pos = dl->bounds.left_in;
   data.db->end_pos = data.pixpos;
 
+  calculate_yoffset (dl, data.db);
+
   return data.pixpos - dl->bounds.left_in;
 }
 
@@ -2713,8 +2949,26 @@ add_margin_runes (struct display_line *dl, struct display_block *db, int start,
                             ? 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))
@@ -2743,79 +2997,24 @@ add_margin_runes (struct display_line *dl, struct display_block *db, int start,
           || (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;
+  calculate_baseline (&data);
+
+  dl->ascent = data.new_ascent;
+  dl->descent = data.new_descent;
+
+  calculate_yoffset (dl, data.db);
+
+  return data.pixpos;
 }
 
 /* Add a blank to a margin display block. */
@@ -3506,7 +3705,7 @@ generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
 
   /* 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,
@@ -3543,6 +3742,8 @@ generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
       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));
@@ -3579,6 +3780,8 @@ generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
              Dynarr_at (formatted_string_extent_end_dynarr, elt),
              result_str);
         }
+
+      in_modeline_generation = 0;
     }
 }
 
@@ -3622,10 +3825,6 @@ generate_modeline (struct window *w, struct display_line *dl, int type)
       /* 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;
@@ -3679,18 +3878,15 @@ generate_modeline (struct window *w, struct display_line *dl, int type)
      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));
@@ -3698,13 +3894,13 @@ add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str,
     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);
@@ -3816,7 +4012,7 @@ tail_recurse:
                {
                  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);
@@ -3873,7 +4069,7 @@ tail_recurse:
 
                   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)
                 {
@@ -3892,9 +4088,9 @@ tail_recurse:
                    *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
+                     /* #### NOTE: I don't understand why a tmp_max is not
                         computed and used here as in the plain string case
                         above. -- dv */
                      pos = add_string_to_fstring_db_runes (data, tmp_str,
@@ -3938,9 +4134,9 @@ tail_recurse:
                *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
+                 /* #### NOTE: I don't understand why a tmp_max is not
                     computed and used here as in the plain string case
                     above. -- dv */
                  pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
@@ -3979,8 +4175,8 @@ tail_recurse:
        * - 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;
@@ -4132,10 +4328,10 @@ tail_recurse:
          *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
+           /* #### NOTE: I don't understand why a tmp_max is not computed and
               used here as in the plain string case above. -- dv */
            pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
                                                  min_pos, max_pos);
@@ -4146,7 +4342,7 @@ tail_recurse:
 
   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);
     }
 
@@ -4247,9 +4443,9 @@ real_current_modeline_height (struct window *w)
 
 \f
 /***************************************************************************/
-/*                                                             */
-/*                            displayable string routines                      */
-/*                                                             */
+/*                                                                         */
+/*                            displayable string routines                  */
+/*                                                                         */
 /***************************************************************************/
 
 /* Given a position for a string in a window, ensure that the given
@@ -4281,7 +4477,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
      against this case. */
   struct buffer *b = BUFFERP (w->buffer) ? XBUFFER (w->buffer) : 0;
   struct device *d = XDEVICE (f->device);
-  struct Lisp_String* s = XSTRING (disp_string);
+  Lisp_String* s = XSTRING (disp_string);
 
   /* we're working with these a lot so precalculate them */
   Bytecount slen = XSTRING_LENGTH (disp_string);
@@ -4291,11 +4487,10 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
   pos_data data;
 
   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. */
 
@@ -4361,6 +4556,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
 
   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 */
@@ -4398,13 +4594,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
   /* Set the right boundary adjusting it to take into account any end
      glyph.  Save the width of the end glyph for later use. */
   data.max_pixpos = dl->bounds.right_in;
-#if 0
-  if (truncate_win)
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
-  else
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
-#endif
-  data.max_pixpos -= end_glyph_width;
+  data.max_pixpos -= data.end_glyph_width;
 
   data.cursor_type = NO_CURSOR;
   data.cursor_x = -1;
@@ -4460,10 +4650,18 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
       /* Check for face changes. */
       if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end))
        {
+         Lisp_Object last_glyph = Qnil;
+         /* Deal with clipped glyphs that we have already displayed. */
+         if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 
+           {
+             last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph;
+             Dynarr_free (*prop);
+             *prop = 0;
+           }
          /* Now compute the face and begin/end-glyph information. */
          data.findex =
            /* Remember that the extent-fragment routines deal in Bytind's. */
-           extent_fragment_update (w, data.ef, data.bi_bufpos);
+           extent_fragment_update (w, data.ef, data.bi_bufpos, last_glyph);
          /* This is somewhat cheesy but the alternative is to
              propagate default_face into extent_fragment_update. */
          if (data.findex == DEFAULT_INDEX)
@@ -4518,7 +4716,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
                goto done;
            }
 
-         /* #### What if we we're dealing with a display table? */
+         /* #### What if we're dealing with a display table? */
          if (data.start_col)
            data.start_col--;
 
@@ -4555,17 +4753,23 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
         a line are handled correctly. */
       else if (Dynarr_length (data.ef->end_glyphs) > 0)
        {
+         data.ch = string_char (s, data.bi_bufpos);
          *prop = add_glyph_runes (&data, END_GLYPHS);
-         if (*prop)
+
+         if (*prop) {
            goto done;
+         }
        }
 
       /* If there are begin glyphs, add them to the line. */
       else if (Dynarr_length (data.ef->begin_glyphs) > 0)
        {
+         data.ch = string_char (s, data.bi_bufpos);
          *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-         if (*prop)
+
+         if (*prop) {
            goto done;
+         }
        }
 
       /* If at end-of-buffer, we've already processed begin and
@@ -4599,7 +4803,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
              /* We aren't going to be adding an end glyph so give its
                  space back in order to make sure that the cursor can
                  fit. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
              goto done;
            }
 
@@ -4641,7 +4845,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
              *prop = add_blank_rune (&data, w, char_tab_width);
 
              /* add_blank_rune is only supposed to be called with
-                 sizes guaranteed to fit in the available space. */
+                sizes guaranteed to fit in the available space. */
              assert (!(*prop));
 
              if (prop_width)
@@ -4697,7 +4901,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
        }
     }
 
-done:
+ done:
 
   /* Determine the starting point of the next line if we did not hit the
      end of the buffer. */
@@ -4730,7 +4934,7 @@ done:
              for the next newline.  We also add the end-of-line glyph which
              we know will fit because we adjusted the right border before
              we starting laying out the line. */
-         data.max_pixpos += end_glyph_width;
+         data.max_pixpos += data.end_glyph_width;
          data.findex = default_face;
          gb.extent = Qnil;
 
@@ -4753,16 +4957,17 @@ done:
 
              /* 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);
            }
 
-         if (end_glyph_width)
+         if (data.end_glyph_width)
            add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, cachel);
 
          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')
                {
@@ -4836,26 +5041,7 @@ done:
   else
     db->end_pos = dl->bounds.right_white;
 
-  /* update line height parameters */
-  if (!data.new_ascent && !data.new_descent)
-    {
-      /* We've got a blank line so initialize these values from the default
-         face. */
-      default_face_font_info (data.window, &data.new_ascent,
-                             &data.new_descent, 0, 0, 0);
-    }
-
-  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);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -4873,6 +5059,8 @@ done:
       dl->descent = descent;
   }
 
+  calculate_yoffset (dl, db);
+
   dl->cursor_elt = data.cursor_x;
   /* #### lossage lossage lossage! Fix this shit! */
   if (data.bi_bufpos > bi_string_zv)
@@ -5094,6 +5282,7 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
   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;
@@ -5147,7 +5336,14 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
   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;
@@ -5200,7 +5396,7 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
             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);
@@ -5244,16 +5440,22 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
         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)
@@ -5584,20 +5786,9 @@ regenerate_window_incrementally (struct window *w, Bufpos startp,
       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)
@@ -5615,19 +5806,9 @@ regenerate_window_incrementally (struct window *w, Bufpos startp,
          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. */
@@ -5931,7 +6112,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
      the cache purely because glyphs have changed - this is now
      handled by the dirty flag.*/
   if ((!echo_active && b != window_display_buffer (w))
-      || !Dynarr_length (w->glyph_cachels))
+      || !Dynarr_length (w->glyph_cachels) || f->faces_changed)
     reset_glyph_cachels (w);
   else
     mark_glyph_cachels_as_not_updated (w);
@@ -6003,7 +6184,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
       && !(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))
       )
     {
@@ -6017,7 +6198,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
          && !f->faces_changed
          && !f->glyphs_changed
          && !f->subwindows_changed
-         && !f->subwindows_state_changed
+         /*      && !f->subwindows_state_changed*/
          && !f->point_changed
          && !f->windows_structure_changed)
        {
@@ -6039,7 +6220,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
              && !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)
@@ -6098,7 +6279,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
           && !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
@@ -6280,12 +6461,13 @@ call_redisplay_end_triggers (struct window *w, void *closure)
 
 /* 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);
 
-  if (preemption_check)
+  if (preemption_check
+      && !DEVICE_IMPL_FLAG (d, XDEVIMPF_DONT_PREEMPT_REDISPLAY))
     {
       /* The preemption check itself takes a lot of time,
         so normally don't do it here.  We do it if called
@@ -6297,6 +6479,16 @@ redisplay_frame (struct frame *f, int preemption_check)
        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)
@@ -6322,40 +6514,38 @@ redisplay_frame (struct frame *f, int preemption_check)
      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);
+  /* Update the toolbars geometry. We don't update the toolbars
+     themselves at this point since the space they are trying to
+     occupy may currently by occupied by gutter elements. Instead we
+     update the geometry, then update the gutter geometry, then update
+     the gutters - which will cause mapped windows to be repositioned
+     - and finally update the toolbars. */
+  update_frame_toolbars_geometry (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)
+  if (f->frame_changed)
+    reset_frame_subwindow_instance_cache (f);
+
+  if (f->frame_changed || f->subwindows_changed)
     {
-      reset_subwindow_cachels (f);
       /* 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 ();
 
@@ -6383,10 +6573,22 @@ redisplay_frame (struct frame *f, int preemption_check)
      #### 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. */
@@ -6395,14 +6597,18 @@ redisplay_frame (struct frame *f, int preemption_check)
   /* 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);
 
+#ifdef HAVE_TOOLBARS
+  /* Finally update the toolbars. It seems its possible to get in a
+     cycle between updating the gutter and the toolbars. Basically we
+     want to end up with both being up-to-date and this doesn't seem
+     possible in a single pass. */
+  update_frame_toolbars (f);
+#endif /* HAVE_TOOLBARS */
+
   CLASS_RESET_CHANGED_FLAGS (f);
   f->window_face_cache_reset = 0;
   f->echo_area_garbaged = 0;
@@ -6422,28 +6628,41 @@ redisplay_frame (struct frame *f, int preemption_check)
   return 0;
 }
 
-/* Ensure that all frames on the given device are correctly displayed. */
+/* Ensure that all frames on the given device are correctly displayed.
+   If AUTOMATIC is non-zero, and the device implementation indicates
+   no automatic redisplay, as printers do, then the device is not
+   redisplayed. AUTOMATIC is set to zero when called from lisp
+   functions (redraw-device) and (redisplay-device), and to non-zero
+   when called from "lazy" redisplay();
+*/
 
 static int
-redisplay_device (struct device *d)
+redisplay_device (struct device *d, int automatic)
 {
   Lisp_Object frame, frmcons;
-  int preempted = 0;
   int size_change_failed = 0;
   struct frame *f;
 
+  if (automatic && DEVICE_IMPL_FLAG (d, XDEVIMPF_NO_AUTO_REDISPLAY))
+    return 0;
+
   if (DEVICE_STREAM_P (d)) /* nothing to do */
     return 0;
 
   /* It is possible that redisplay has been called before the
-     device is fully initialized.  If so then continue with the
-     next device. */
+     device is fully initialized, or that the console implementation
+     allows frameless devices.  If so then continue with the next
+     device. */
   if (NILP (DEVICE_SELECTED_FRAME (d)))
     return 0;
 
-  REDISPLAY_PREEMPTION_CHECK;
-  if (preempted)
-    return 1;
+  if (!DEVICE_IMPL_FLAG (d, XDEVIMPF_DONT_PREEMPT_REDISPLAY))
+    {
+      int preempted;
+      REDISPLAY_PREEMPTION_CHECK;
+      if (preempted)
+       return 1;
+    }
 
   /* Always do the selected frame first. */
   frame = DEVICE_SELECTED_FRAME (d);
@@ -6457,12 +6676,11 @@ redisplay_device (struct device *d)
     {
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP(f))
        {
-         preempted = redisplay_frame (f, 0);
+         int preempted = redisplay_frame (f, 0);
+         if (preempted)
+           return 1;
        }
 
-      if (preempted)
-       return 1;
-
       /* If the frame redisplay did not get preempted, then this flag
          should have gotten set to 0.  It might be possible for that
          not to happen if a size change event were to occur at an odd
@@ -6487,12 +6705,11 @@ redisplay_device (struct device *d)
        {
          if (CLASS_REDISPLAY_FLAGS_CHANGEDP (f))
            {
-             preempted = redisplay_frame (f, 0);
+             int preempted = redisplay_frame (f, 0);
+             if (preempted)
+               return 1;
            }
 
-         if (preempted)
-           return 1;
-
          if (f->size_change_pending)
            size_change_failed = 1;
        }
@@ -6546,7 +6763,7 @@ redisplay_without_hooks (void)
 
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d))
        {
-         preempted = redisplay_device (d);
+         preempted = redisplay_device (d, 1);
 
          if (preempted)
            {
@@ -6660,7 +6877,7 @@ static void
 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);
@@ -6689,7 +6906,7 @@ decode_mode_spec (struct window *w, Emchar spec, int type)
        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;
       }
@@ -7026,7 +7243,9 @@ mark_glyph_block_dynarr (glyph_block_dynarr *gba)
     }
 }
 
-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);
@@ -7084,8 +7303,8 @@ mark_redisplay (void)
   FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
     {
       struct frame *f = XFRAME (XCAR (frmcons));
-      update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
+      mark_gutters (f);
     }
 }
 \f
@@ -7255,7 +7474,8 @@ point_in_line_start_cache (struct window *w, Bufpos point, int min_past)
 {
   struct buffer *b = XBUFFER (w->buffer);
   line_start_cache_dynarr *cache = w->line_start_cache;
-  unsigned int top, bottom, pos;
+  unsigned int top, bottom;
+  EMACS_INT pos;
 
   validate_line_start_cache (w);
   w->line_cache_validation_override++;
@@ -7383,7 +7603,7 @@ find_point_loop:
 
   while (1)
     {
-      unsigned int new_pos;
+      EMACS_INT new_pos;
       Bufpos start, end;
 
       pos = (bottom + top + 1) >> 1;
@@ -7522,11 +7742,18 @@ point_would_be_visible (struct window *w, Bufpos startp, Bufpos point)
    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;
@@ -7546,7 +7773,7 @@ start_end_of_last_line (struct window *w, Bufpos startp, int end)
 
   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)
     {
@@ -7610,7 +7837,7 @@ start_end_of_last_line (struct window *w, Bufpos startp, int end)
 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
@@ -7620,9 +7847,16 @@ start_of_last_line (struct window *w, Bufpos startp)
 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. */
 
@@ -7806,7 +8040,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
 
   validate_line_start_cache (w);
   w->line_cache_validation_override++;
-  updating_line_start_cache = 1;
 
   if (from < BUF_BEGV (b))
     from = BUF_BEGV (b);
@@ -7815,7 +8048,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
 
   if (from > to)
     {
-      updating_line_start_cache = 0;
       w->line_cache_validation_override--;
       return;
     }
@@ -7828,7 +8060,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
       /* 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;
        }
@@ -7857,7 +8088,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
       update_internal_cache_list (w, DESIRED_DISP);
       if (!Dynarr_length (internal_cache))
        {
-         updating_line_start_cache = 0;
          w->line_cache_validation_override--;
          return;
        }
@@ -7885,7 +8115,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
        {
          Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
                           Dynarr_length (internal_cache));
-         updating_line_start_cache = 0;
          w->line_cache_validation_override--;
          return;
        }
@@ -7894,7 +8123,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
          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;
        }
@@ -7917,7 +8145,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
              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;
            }
@@ -7943,7 +8170,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
              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;
            }
@@ -7952,7 +8178,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
                           Dynarr_length (internal_cache) - ic_elt);
        }
 
-      updating_line_start_cache = 0;
       w->line_cache_validation_override--;
       return;
     }
@@ -7972,23 +8197,9 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
          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;
@@ -8034,7 +8245,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
          startp = new_startp;
          if (startp > BUF_ZV (b))
            {
-             updating_line_start_cache = 0;
              w->line_cache_validation_override--;
              return;
            }
@@ -8068,7 +8278,6 @@ update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
       while (to > high_bound);
     }
 
-  updating_line_start_cache = 0;
   w->line_cache_validation_override--;
   assert (to <= high_bound);
 }
@@ -8776,7 +8985,7 @@ pixel_to_glyph_translation (struct frame *f, int x_coord, int y_coord,
   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;
@@ -8809,6 +9018,9 @@ Ensure that all minibuffers are correctly showing the echo area.
          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
@@ -8817,19 +9029,15 @@ Ensure that all minibuffers are correctly showing the echo area.
               */
              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;
@@ -8864,6 +9072,9 @@ input and is guaranteed to proceed to completion.
   f->clear = 1;
   redisplay_frame (f, 1);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -8891,6 +9102,15 @@ input and is guaranteed to proceed to completion.
 
   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);
 }
 
@@ -8918,7 +9138,10 @@ input and is guaranteed to proceed to completion.
     {
       XFRAME (XCAR (frmcons))->clear = 1;
     }
-  redisplay_device (d);
+  redisplay_device (d, 0);
+
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
 
   return unbind_to (count, Qnil);
 }
@@ -8945,7 +9168,10 @@ input and is guaranteed to proceed to completion.
       disable_preemption++;
     }
 
-  redisplay_device (d);
+  redisplay_device (d, 0);
+
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
 
   return unbind_to (count, Qnil);
 }
@@ -9125,12 +9351,18 @@ init_redisplay (void)
   if (!initialized)
 #endif
     {
-      cmotion_display_lines = Dynarr_new (display_line);
-      mode_spec_bufbyte_string = Dynarr_new (Bufbyte);
-      formatted_string_extent_dynarr = Dynarr_new (EXTENT);
-      formatted_string_extent_start_dynarr = Dynarr_new (Bytecount);
-      formatted_string_extent_end_dynarr = Dynarr_new (Bytecount);
-      internal_cache = Dynarr_new (line_start_cache);
+      if (!cmotion_display_lines)
+       cmotion_display_lines = Dynarr_new (display_line);
+      if (!mode_spec_bufbyte_string)
+       mode_spec_bufbyte_string = Dynarr_new (Bufbyte);
+      if (!formatted_string_extent_dynarr)
+       formatted_string_extent_dynarr = Dynarr_new (EXTENT);
+      if (!formatted_string_extent_start_dynarr)
+       formatted_string_extent_start_dynarr = Dynarr_new (Bytecount);
+      if (!formatted_string_extent_end_dynarr)
+       formatted_string_extent_end_dynarr = Dynarr_new (Bytecount);
+      if (!internal_cache)
+       internal_cache = Dynarr_new (line_start_cache);
     }
 
   /* window system is nil when in -batch mode */
@@ -9155,6 +9387,15 @@ init_redisplay (void)
     }
 #endif /* HAVE_X_WINDOWS */
 
+#ifdef HAVE_GTK
+  if (!strcmp (display_use, "gtk"))
+    {
+      Vwindow_system = Qgtk;
+      Vinitial_window_system = Qgtk;
+      return;
+    }
+#endif
+
 #ifdef HAVE_MS_WINDOWS
   if (!strcmp (display_use, "mswindows"))
     {
@@ -9203,6 +9444,8 @@ syms_of_redisplay (void)
   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);
@@ -9214,15 +9457,8 @@ syms_of_redisplay (void)
 }
 
 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);
@@ -9267,7 +9503,9 @@ See also `overlay-arrow-string'.
   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;
@@ -9291,10 +9529,19 @@ If this is zero, point is always centered after it moves off screen.
                     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.
@@ -9338,24 +9585,29 @@ Non-nil means put cursor in minibuffer, at end of any message there.
      maybe a caret cursor, etc. */
 
   DEFVAR_LISP ("bar-cursor", &Vbar_cursor /*
-Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.
+*Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.
 */ );
   Vbar_cursor = Qnil;
 
 #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
@@ -9417,7 +9669,7 @@ This is a specifier; use `set-specifier' to change it.
                         offsetof (struct window, left_margin_width),
                         some_window_value_changed,
                         offsetof (struct frame, left_margin_width),
-                        margin_width_changed_in_frame);
+                        margin_width_changed_in_frame, 0);
 
   DEFVAR_SPECIFIER ("right-margin-width", &Vright_margin_width /*
 *Width of right margin.
@@ -9429,7 +9681,7 @@ This is a specifier; use `set-specifier' to change it.
                         offsetof (struct window, right_margin_width),
                         some_window_value_changed,
                         offsetof (struct frame, right_margin_width),
-                        margin_width_changed_in_frame);
+                        margin_width_changed_in_frame, 0);
 
   DEFVAR_SPECIFIER ("minimum-line-ascent", &Vminimum_line_ascent /*
 *Minimum ascent height of lines.
@@ -9440,7 +9692,7 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_caching (Vminimum_line_ascent,
                         offsetof (struct window, minimum_line_ascent),
                         some_window_value_changed,
-                        0, 0);
+                        0, 0, 0);
 
   DEFVAR_SPECIFIER ("minimum-line-descent", &Vminimum_line_descent /*
 *Minimum descent height of lines.
@@ -9451,7 +9703,7 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_caching (Vminimum_line_descent,
                         offsetof (struct window, minimum_line_descent),
                         some_window_value_changed,
-                        0, 0);
+                        0, 0, 0);
 
   DEFVAR_SPECIFIER ("use-left-overflow", &Vuse_left_overflow /*
 *Non-nil means use the left outside margin as extra whitespace when
@@ -9463,7 +9715,7 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_caching (Vuse_left_overflow,
                         offsetof (struct window, use_left_overflow),
                         some_window_value_changed,
-                        0, 0);
+                        0, 0, 0);
 
   DEFVAR_SPECIFIER ("use-right-overflow", &Vuse_right_overflow /*
 *Non-nil means use the right outside margin as extra whitespace when
@@ -9475,7 +9727,7 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_caching (Vuse_right_overflow,
                         offsetof (struct window, use_right_overflow),
                         some_window_value_changed,
-                        0, 0);
+                        0, 0, 0);
 
   DEFVAR_SPECIFIER ("text-cursor-visible-p", &Vtext_cursor_visible_p /*
 *Non-nil means the text cursor is visible (this is usually the case).
@@ -9486,6 +9738,6 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_caching (Vtext_cursor_visible_p,
                         offsetof (struct window, text_cursor_visible_p),
                         text_cursor_visible_p_changed,
-                        0, 0);
+                        0, 0, 0);
 
 }