(Vcharacter_attribute_table): New variable.
[chise/xemacs-chise.git-] / src / redisplay.c
index af19d9b..47a876a 100644 (file)
@@ -51,6 +51,7 @@ Boston, MA 02111-1307, USA.  */
 #include "faces.h"
 #include "frame.h"
 #include "glyphs.h"
+#include "gutter.h"
 #include "insdel.h"
 #include "menubar.h"
 #include "objects.h"
@@ -107,6 +108,9 @@ typedef struct position_redisplay_data_type
   /* This information is normally filled in by the create_*_block
      routines and is used by the add_*_rune routines. */
   Lisp_Object window;
+  /* if we are working with strings rather than buffers we need a
+     handle to the string */
+  Lisp_Object string;
   struct device *d;
   struct display_block *db;
   struct display_line *dl;
@@ -256,7 +260,8 @@ static prop_block_dynarr *add_glyph_rune (pos_data *data,
                                          struct glyph_cachel *cachel);
 static Bytind create_text_block (struct window *w, struct display_line *dl,
                                 Bytind bi_start_pos, int start_col,
-                                prop_block_dynarr **prop, int type);
+                                prop_block_dynarr **prop,
+                                int type);
 static int create_overlay_glyph_block (struct window *w,
                                       struct display_line *dl);
 static void create_left_glyph_block (struct window *w,
@@ -270,6 +275,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);
+extern Bytind bi_find_next_emchar_in_string (struct Lisp_String* str, Emchar target, 
+                                            Bytind st, EMACS_INT count);
+extern int string_column_at_point (struct Lisp_String* s, Bufpos init_pos, int tab_width);
 
 /* This used to be 10 but 30 seems to give much better performance. */
 #define INIT_MAX_PREEMPTS      30
@@ -365,6 +373,11 @@ int frame_changed;
 int glyphs_changed;
 int glyphs_changed_set;
 
+/* non-zero if any displayed subwindow is in need of updating
+   somewhere. */
+int subwindows_changed;
+int subwindows_changed_set;
+
 /* This variable is 1 if the icon has to be updated.
  It is set to 1 when `frame-icon-glyph' changes. */
 int icon_changed;
@@ -395,6 +408,10 @@ int asynch_device_change_pending;
 int toolbar_changed;
 int toolbar_changed_set;
 
+/* non-nil if any gutter has changed */
+int gutter_changed;
+int gutter_changed_set;
+
 /* non-nil if any window has changed since the last time redisplay completed */
 int windows_changed;
 
@@ -469,7 +486,7 @@ static int
 redisplay_text_width_emchar_string (struct window *w, int findex,
                                    Emchar *str, Charcount len)
 {
-  unsigned char charsets[NUM_LEADING_BYTES];
+  Charset_ID charsets[NUM_LEADING_BYTES];
   Lisp_Object window;
 
   find_charsets_in_emchar_string (charsets, str, len);
@@ -506,7 +523,7 @@ redisplay_frame_text_width_string (struct frame *f, Lisp_Object face,
                                   Bufbyte *nonreloc, Lisp_Object reloc,
                                   Bytecount offset, Bytecount len)
 {
-  unsigned char charsets[NUM_LEADING_BYTES];
+  Charset_ID charsets[NUM_LEADING_BYTES];
   Lisp_Object frame;
   struct face_cachel cachel;
 
@@ -681,7 +698,8 @@ calculate_display_line_boundaries (struct window *w, int modeline)
 static Bufpos
 generate_display_line (struct window *w, struct display_line *dl, int bounds,
                       Bufpos start_pos, int start_col,
-                      prop_block_dynarr **prop, int type)
+                      prop_block_dynarr **prop,
+                      int type)
 {
   Bufpos ret_bufpos;
   int overlay_width;
@@ -895,9 +913,15 @@ add_emchar_rune (pos_data *data)
   crb->xpos = data->pixpos;
   crb->width = width;
   if (data->bi_bufpos)
-    crb->bufpos =
-      bytind_to_bufpos (XBUFFER (WINDOW_BUFFER (XWINDOW (data->window))),
-                       data->bi_bufpos);
+    {
+      if (NILP (data->string))
+       crb->bufpos =
+         bytind_to_bufpos (XBUFFER (WINDOW_BUFFER (XWINDOW (data->window))),
+                           data->bi_bufpos);
+      else
+       crb->bufpos =
+         bytecount_to_charcount (XSTRING_DATA (data->string), data->bi_bufpos);
+    }
   else if (data->is_modeline)
     crb->bufpos = data->modeline_charpos;
   else
@@ -1233,66 +1257,12 @@ add_control_char_runes (pos_data *data, struct buffer *b)
     }
 }
 
-/* Given a display table entry, call the appropriate functions to
-   display each element of the entry. */
-
 static prop_block_dynarr *
-add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
+add_disp_table_entry_runes_1 (pos_data *data, Lisp_Object entry)
 {
   prop_block_dynarr *prop = NULL;
 
-  if (VECTORP (entry))
-    {
-      struct Lisp_Vector *de = XVECTOR (entry);
-      long len = vector_length (de);
-      int elt;
-
-      for (elt = 0; elt < len; elt++)
-       {
-         if (NILP (de->contents[elt]))
-           continue;
-         else if (STRINGP (de->contents[elt]))
-           {
-             prop =
-               add_bufbyte_string_runes
-                 (data,
-                  XSTRING_DATA   (de->contents[elt]),
-                  XSTRING_LENGTH (de->contents[elt]),
-                  0);
-           }
-         else if (GLYPHP (de->contents[elt]))
-           {
-             if (data->start_col)
-               data->start_col--;
-
-             if (!data->start_col && data->bi_start_col_enabled)
-               {
-                 prop = add_hscroll_rune (data);
-               }
-             else
-               {
-                 struct glyph_block gb;
-
-                 gb.glyph = de->contents[elt];
-                 gb.extent = Qnil;
-                 prop = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
-               }
-           }
-         else if (CHAR_OR_CHAR_INTP (de->contents[elt]))
-           {
-             data->ch = XCHAR_OR_CHAR_INT (de->contents[elt]);
-             prop = add_emchar_rune (data);
-           }
-         /* Else blow it off because someone added a bad entry and we
-             don't have any safe way of signaling an error. */
-
-         /* #### Still need to add any remaining elements to the
-             propagation information. */
-         if (prop)
-           return prop;
-       }
-    }
-  else if (STRINGP (entry))
+  if (STRINGP (entry))
     {
       prop = add_bufbyte_string_runes (data,
                                       XSTRING_DATA   (entry),
@@ -1322,10 +1292,79 @@ add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
       data->ch = XCHAR_OR_CHAR_INT (entry);
       prop = add_emchar_rune (data);
     }
+  else if (CONSP (entry))
+    {
+      if (EQ (XCAR (entry), Qformat)
+         && CONSP (XCDR (entry))
+         && STRINGP (XCAR (XCDR (entry))))
+       {
+         Lisp_Object format = XCAR (XCDR (entry));
+         Bytind len = XSTRING_LENGTH (format);
+         Bufbyte *src = XSTRING_DATA (format), *end = src + len;
+         Bufbyte *result = alloca_array (Bufbyte, len);
+         Bufbyte *dst = result;
+
+         while (src < end)
+           {
+             Emchar c = charptr_emchar (src);
+             INC_CHARPTR (src);
+             if (c != '%' || src == end)
+               dst += set_charptr_emchar (dst, c);
+             else
+               {
+                 c = charptr_emchar (src);
+                 INC_CHARPTR (src);
+                 switch (c)
+                   {
+                     /*case 'x':
+                     dst += long_to_string_base ((char *)dst, data->ch, 16);
+                     break;*/
+                   case '%':
+                     dst += set_charptr_emchar (dst, '%');
+                     break;
+                   }
+               }
+           }
+         prop = add_bufbyte_string_runes (data, result, dst - result, 0);
+       }
+    }
 
   /* Else blow it off because someone added a bad entry and we don't
-     have any safe way of signaling an error.  Hey, this comment
-     sounds familiar. */
+     have any safe way of signaling an error. */
+  return prop;
+}
+
+/* Given a display table entry, call the appropriate functions to
+   display each element of the entry. */
+
+static prop_block_dynarr *
+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);
+      EMACS_INT len = vector_length (de);
+      int elt;
+
+      for (elt = 0; elt < len; elt++)
+       {
+         if (NILP (vector_data (de)[elt]))
+           continue;
+         else
+           prop = add_disp_table_entry_runes_1 (data, vector_data (de)[elt]);
+         /* Else blow it off because someone added a bad entry and we
+            don't have any safe way of signaling an error.  Hey, this
+            comment sounds familiar. */
+
+         /* #### Still need to add any remaining elements to the
+             propagation information. */
+         if (prop)
+           return prop;
+       }
+    }
+  else
+    prop = add_disp_table_entry_runes_1 (data, entry);
   return prop;
 }
 
@@ -1744,14 +1783,14 @@ add_glyph_runes (pos_data *data, int pos_type)
 static Bytind
 create_text_block (struct window *w, struct display_line *dl,
                   Bytind bi_start_pos, int start_col,
-                  prop_block_dynarr **prop, int type)
+                  prop_block_dynarr **prop,
+                  int type)
 {
   struct frame *f = XFRAME (w->frame);
   struct buffer *b = XBUFFER (w->buffer);
   struct device *d = XDEVICE (f->device);
 
   pos_data data;
-  struct Lisp_Vector *dt = 0;
 
   /* Don't display anything in the minibuffer if this window is not on
      a selected frame.  We consider all other windows to be active
@@ -1784,46 +1823,41 @@ create_text_block (struct window *w, struct display_line *dl,
      into a more general conversion mechanism.  Ideally you
      could specify a Lisp function that converts characters,
      but this violates the Second Golden Rule and besides would
-     make things way way way way slow.  An idea I like is to
-     be able to specify multiple display tables instead of just
-     one.  Each display table can specify conversions for some
-     characters and leave others unchanged.  The way the
-     character gets displayed is determined by the first display
-     table with a binding for that character.  This way, you
-     could call a function `enable-hex-display' that adds a
-     pre-defined hex display-table (or maybe computes one if
-     you give weird parameters to the function) and adds it
-     to the list of display tables for the current buffer.
-
-     Unfortunately there are still problems dealing with Mule
-     characters.  For example, maybe I want to specify that
-     all extended characters (i.e. >= 256) are displayed in hex.
-     It's not reasonable to create a mapping for all possible
-     such characters, because there are about 2^19 of them.
-     One way of dealing with this is to extend the concept
-     of what a display table is.  Currently it's only allowed
-     to be a 256-entry vector.  Instead, it should be something
-     like:
-
-     a) A 256-entry vector, for backward compatibility
-     b) Some sort of hash table, mapping characters to values
-     c) A list that specifies a range of values and the
-        mapping to provide for those values.
-
-     Also, extend the concept of "mapping" to include a
-     printf-like spec.  Then, you could make all extended
-     characters show up as hex with a display table like
-
-     ((256 . 524288) . "%x")
+     make things way way way way slow.
+
+     So instead, we extend the display-table concept, which was
+     historically limited to 256-byte vectors, to one of the
+     following:
+
+     a) A 256-entry vector, for backward compatibility;
+     b) char-table, mapping characters to values;
+     c) range-table, mapping ranges of characters to values;
+     d) a list of the above.
+
+     The (d) option allows you to specify multiple display tables
+     instead of just one.  Each display table can specify conversions
+     for some characters and leave others unchanged.  The way the
+     character gets displayed is determined by the first display table
+     with a binding for that character.  This way, you could call a
+     function `enable-hex-display' that adds a hex display-table to
+     the list of display tables for the current buffer.
+
+     #### ...not yet implemented...  Also, we extend the concept of
+     "mapping" to include a printf-like spec.  Thus you can make all
+     extended characters show up as hex with a display table like
+     this:
+
+         #s(range-table data ((256 524288) (format "%x")))
 
      Since more than one display table is possible, you have
-     great flexibility in mapping ranges of characters.
-     */
+     great flexibility in mapping ranges of characters.  */
   Emchar printable_min = (CHAR_OR_CHAR_INTP (b->ctl_arrow)
                          ? XCHAR_OR_CHAR_INT (b->ctl_arrow)
                          : ((EQ (b->ctl_arrow, Qt) || EQ (b->ctl_arrow, Qnil))
                             ? 255 : 160));
 
+  Lisp_Object face_dt, window_dt;
+
   /* The text display block for this display line. */
   struct display_block *db = get_display_block_from_line (dl, TEXT);
 
@@ -1849,6 +1883,7 @@ create_text_block (struct window *w, struct display_line *dl,
      them to this structure for ease of passing. */
   data.d = d;
   XSETWINDOW (data.window, w);
+  data.string = Qnil;
   data.db = db;
   data.dl = dl;
 
@@ -1962,10 +1997,10 @@ create_text_block (struct window *w, struct display_line *dl,
            /* Remember that the extent-fragment routines deal in Bytind's. */
            extent_fragment_update (w, data.ef, data.bi_bufpos);
 
+         get_display_tables (w, data.findex, &face_dt, &window_dt);
+
          if (data.bi_bufpos == data.ef->end)
            no_more_frags = 1;
-
-         dt = get_display_table (w, data.findex);
        }
       initial = 0;
 
@@ -2077,16 +2112,17 @@ create_text_block (struct window *w, struct display_line *dl,
 
       else
        {
+         Lisp_Object entry = Qnil;
          /* Get the character at the current buffer position. */
          data.ch = BI_BUF_FETCH_CHAR (b, data.bi_bufpos);
+         if (!NILP (face_dt) || !NILP (window_dt))
+           entry = display_table_entry (data.ch, face_dt, window_dt);
 
          /* If there is a display table entry for it, hand it off to
              add_disp_table_entry_runes and let it worry about it. */
-         if (dt && !NILP (DISP_CHAR_ENTRY (dt, data.ch)))
+         if (!NILP (entry) && !EQ (entry, make_char (data.ch)))
            {
-             *prop =
-               add_disp_table_entry_runes (&data,
-                                           DISP_CHAR_ENTRY (dt, data.ch));
+             *prop = add_disp_table_entry_runes (&data, entry);
 
              if (*prop)
                goto done;
@@ -2625,6 +2661,7 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
   data.last_charset = Qunbound;
   data.last_findex = DEFAULT_INDEX;
   data.result_str = Qnil;
+  data.string = Qnil;
 
   Dynarr_reset (data.db->runes);
 
@@ -3475,6 +3512,10 @@ 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;
@@ -3528,6 +3569,9 @@ 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 void
@@ -3554,6 +3598,7 @@ generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
   data.last_findex = DEFAULT_INDEX;
   data.result_str = result_str;
   data.is_modeline = 1;
+  data.string = Qnil;
   XSETWINDOW (data.window, w);
 
   Dynarr_reset (formatted_string_extent_dynarr);
@@ -4160,157 +4205,1001 @@ real_current_modeline_height (struct window *w)
 
 \f
 /***************************************************************************/
-/*                                                                        */
-/*                        window-regeneration routines                     */
-/*                                                                        */
+/*                                                             */
+/*                            displayable string routines                      */
+/*                                                             */
 /***************************************************************************/
 
-/* For a given window and starting position in the buffer it contains,
-   ensure that the TYPE display lines accurately represent the
-   presentation of the window.  We pass the buffer instead of getting
-   it from the window since redisplay_window may have temporarily
-   changed it to the echo area buffer. */
+/* Given a position for a string in a window, ensure that the given
+   display line DL accurately represents the text on a line starting
+   at the given position.
 
-static void
-regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
+   Yes, this is duplicating the code of create_text_block, but it
+   looked just too hard to change create_text_block to handle strings
+   *and* buffers. We already make a distinction between the two
+   elsewhere in the code so I think unifying them would require a
+   complete MULE rewrite. Besides, the other distinction is that these
+   functions cover text that the user *cannot edit* so we can remove
+   everything to do with cursors, minibuffers etc. Eventually the
+   modeline routines should be modified to use this code as it copes
+   with many more types of display situation. */
+
+static Bufpos
+create_string_text_block (struct window *w, Lisp_Object disp_string,
+                         struct display_line *dl,
+                         Bufpos start_pos,
+                         prop_block_dynarr **prop,
+                         face_index default_face)
 {
   struct frame *f = XFRAME (w->frame);
+  /* Note that a lot of the buffer controlled stuff has been left in
+     because you might well want to make use of it (selective display
+     etc), its just the buffer text that we do not use. */
   struct buffer *b = XBUFFER (w->buffer);
-  int ypos = WINDOW_TEXT_TOP (w);
-  int yend;    /* set farther down */
-
-  prop_block_dynarr *prop;
-  layout_bounds bounds;
-  display_line_dynarr *dla;
-  int need_modeline;
-
-  /* The lines had better exist by this point. */
-  if (!(dla = window_display_lines (w, type)))
-    abort ();
-  Dynarr_reset (dla);
-  w->max_line_len = 0;
-
-  /* Normally these get updated in redisplay_window but it is possible
-     for this function to get called from some other points where that
-     update may not have occurred.  This acts as a safety check. */
-  if (!Dynarr_length (w->face_cachels))
-    reset_face_cachels (w);
-  if (!Dynarr_length (w->glyph_cachels))
-    reset_glyph_cachels (w);
+  struct device *d = XDEVICE (f->device);
+  struct Lisp_String* s = XSTRING (disp_string);
 
-  Fset_marker (w->start[type], make_int (start_pos), w->buffer);
-  Fset_marker (w->pointm[type], make_int (point), w->buffer);
-  w->last_point_x[type] = -1;
-  w->last_point_y[type] = -1;
+  /* we're working with these a lot so precalculate them */
+  Bytecount slen = XSTRING_LENGTH (disp_string);
+  Bytecount bi_string_zv = slen;
+  Bytind bi_start_pos = charcount_to_bytecount (string_data (s), start_pos);
 
-  /* Make sure a modeline is in the structs if needed. */
-  need_modeline = ensure_modeline_generated (w, type);
+  pos_data data;
 
-  /* Wait until here to set this so that the structs have a modeline
-     generated in the case where one didn't exist. */
-  yend = WINDOW_TEXT_BOTTOM (w);
+  int truncate_win = window_truncation_on (w);
+  int end_glyph_width = 0;
 
-  bounds = calculate_display_line_boundaries (w, 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
+     functions that we don't have the luxury of being able to use
+     here. */
 
-  /* 97/3/14 jhod: stuff added here to support pre-prompts (used for input systems) */
-  if (MINI_WINDOW_P (w)
-      && (!NILP (Vminibuf_prompt) || !NILP (Vminibuf_preprompt))
-      && !echo_area_active (f)
-      && start_pos == BUF_BEGV (b))
-    {
-      struct prop_block pb;
-      Lisp_Object string;
-      prop = Dynarr_new (prop_block);
+  /* The variable ctl-arrow allows the user to specify what characters
+     can actually be displayed and which octal should be used for.
+     #### This variable should probably have some rethought done to
+     it.
 
-      string = concat2(Vminibuf_preprompt, Vminibuf_prompt);
-      pb.type = PROP_MINIBUF_PROMPT;
-      pb.data.p_string.str = XSTRING_DATA(string);
-      pb.data.p_string.len = XSTRING_LENGTH(string);
-      Dynarr_add (prop, pb);
-    }
-  else
-    prop = 0;
+     #### It would also be really nice if you could specify that
+     the characters come out in hex instead of in octal.  Mule
+     does that by adding a ctl-hexa variable similar to ctl-arrow,
+     but that's bogus -- we need a more general solution.  I
+     think you need to extend the concept of display tables
+     into a more general conversion mechanism.  Ideally you
+     could specify a Lisp function that converts characters,
+     but this violates the Second Golden Rule and besides would
+     make things way way way way slow.
 
-  while (ypos < yend)
-    {
-      struct display_line dl;
-      struct display_line *dlp;
-      int local;
+     So instead, we extend the display-table concept, which was
+     historically limited to 256-byte vectors, to one of the
+     following:
 
-      if (Dynarr_length (dla) < Dynarr_largest (dla))
-       {
-         dlp = Dynarr_atp (dla, Dynarr_length (dla));
-         local = 0;
-       }
-      else
-       {
-         xzero (dl);
-         dlp = &dl;
-         local = 1;
-       }
+     a) A 256-entry vector, for backward compatibility;
+     b) char-table, mapping characters to values;
+     c) range-table, mapping ranges of characters to values;
+     d) a list of the above.
 
-      dlp->bounds = bounds;
-      dlp->offset = 0;
-      start_pos = generate_display_line (w, dlp, 1, start_pos,
-                                        w->hscroll, &prop, type);
-      dlp->ypos = ypos + dlp->ascent;
-      ypos = dlp->ypos + dlp->descent;
+     The (d) option allows you to specify multiple display tables
+     instead of just one.  Each display table can specify conversions
+     for some characters and leave others unchanged.  The way the
+     character gets displayed is determined by the first display table
+     with a binding for that character.  This way, you could call a
+     function `enable-hex-display' that adds a hex display-table to
+     the list of display tables for the current buffer.
 
-      if (ypos > yend)
-       {
-         int visible_height = dlp->ascent + dlp->descent;
+     #### ...not yet implemented...  Also, we extend the concept of
+     "mapping" to include a printf-like spec.  Thus you can make all
+     extended characters show up as hex with a display table like
+     this:
 
-         dlp->clip = (ypos - yend);
-         visible_height -= dlp->clip;
+         #s(range-table data ((256 524288) (format "%x")))
 
-         if (visible_height < VERTICAL_CLIP (w, 1))
-           {
-             if (local)
-               free_display_line (dlp);
-             break;
-           }
-       }
-      else
-       dlp->clip = 0;
+     Since more than one display table is possible, you have
+     great flexibility in mapping ranges of characters.  */
+  Emchar printable_min = (CHAR_OR_CHAR_INTP (b->ctl_arrow)
+                         ? XCHAR_OR_CHAR_INT (b->ctl_arrow)
+                         : ((EQ (b->ctl_arrow, Qt) || EQ (b->ctl_arrow, Qnil))
+                            ? 255 : 160));
 
-      if (dlp->cursor_elt != -1)
-       {
-         /* #### This check is steaming crap.  Have to get things
-             fixed so when create_text_block hits EOB, we're done,
-             period. */
-         if (w->last_point_x[type] == -1)
-           {
-             w->last_point_x[type] = dlp->cursor_elt;
-             w->last_point_y[type] = Dynarr_length (dla);
-           }
-         else
-           {
-             /* #### This means that we've added a cursor at EOB
-                 twice.  Yuck oh yuck. */
-             struct display_block *db =
-               get_display_block_from_line (dlp, TEXT);
+  Lisp_Object face_dt, window_dt;
 
-             Dynarr_atp (db->runes, dlp->cursor_elt)->cursor_type = NO_CURSOR;
-             dlp->cursor_elt = -1;
-           }
-       }
+  /* The text display block for this display line. */
+  struct display_block *db = get_display_block_from_line (dl, TEXT);
 
-      if (dlp->num_chars > w->max_line_len)
-       w->max_line_len = dlp->num_chars;
+  /* The first time through the main loop we need to force the glyph
+     data to be updated. */
+  int initial = 1;
 
-      Dynarr_add (dla, *dlp);
+  /* Apparently the new extent_fragment_update returns an end position
+     equal to the position passed in if there are no more runs to be
+     displayed. */
+  int no_more_frags = 0;
 
-      /* #### This isn't right, but it is close enough for now. */
-      w->window_end_pos[type] = start_pos;
+  dl->used_prop_data = 0;
+  dl->num_chars = 0;
 
-      /* #### This type of check needs to be done down in the
-        generate_display_line call. */
-      if (start_pos > BUF_ZV (b))
-       break;
+  /* set up faces to use for clearing areas, used by
+     output_display_line */
+  dl->default_findex = default_face;
+  if (default_face)
+    {
+      dl->left_margin_findex = default_face;
+      dl->right_margin_findex = default_face;
+    }
+  else
+    {
+      dl->left_margin_findex = 
+       get_builtin_face_cache_index (w, Vleft_margin_face);
+      dl->right_margin_findex = 
+       get_builtin_face_cache_index (w, Vright_margin_face);
+    }
+
+  xzero (data);
+  data.ef = extent_fragment_new (disp_string, f);
+
+  /* These values are used by all of the rune addition routines.  We add
+     them to this structure for ease of passing. */
+  data.d = d;
+  XSETWINDOW (data.window, w);
+  data.db = db;
+  data.dl = dl;
+
+  data.bi_bufpos = bi_start_pos;
+  data.pixpos = dl->bounds.left_in;
+  data.last_charset = Qunbound;
+  data.last_findex = default_face;
+  data.result_str = Qnil;
+  data.string = 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.cursor_type = NO_CURSOR;
+  data.cursor_x = -1;
+
+  data.start_col = 0;
+  /* I don't think we want this, string areas should not scroll with
+     the window 
+  data.start_col = w->hscroll;
+  data.bi_start_col_enabled = (w->hscroll ? bi_start_pos : 0);
+  */
+  data.bi_start_col_enabled = 0;
+  data.hscroll_glyph_width_adjust = 0;
+
+  /* We regenerate the line from the very beginning. */
+  Dynarr_reset (db->runes);
+
+  /* Why is this less than or equal and not just less than?  If the
+     starting position is already equal to the maximum we can't add
+     anything else, right?  Wrong.  We might still have a newline to
+     add.  A newline can use the room allocated for an end glyph since
+     if we add it we know we aren't going to be adding any end
+     glyph. */
+
+  /* #### Chuck -- I think this condition should be while (1).
+     Otherwise if (e.g.) there is one begin-glyph and one end-glyph
+     and the begin-glyph ends exactly at the end of the window, the
+     end-glyph and text might not be displayed.  while (1) ensures
+     that the loop terminates only when either (a) there is
+     propagation data or (b) the end-of-line or end-of-buffer is hit.
+
+     #### Also I think you need to ensure that the operation
+     "add begin glyphs; add end glyphs; add text" is atomic and
+     can't get interrupted in the middle.  If you run off the end
+     of the line during that operation, then you keep accumulating
+     propagation data until you're done.  Otherwise, if the (e.g.)
+     there's a begin glyph at a particular position and attempting
+     to display that glyph results in window-end being hit and
+     propagation data being generated, then the character at that
+     position won't be displayed.
+
+     #### See also the comment after the end of this loop, below.
+     */
+  while (data.pixpos <= data.max_pixpos)
+    {
+      /* #### This check probably should not be necessary. */
+      if (data.bi_bufpos > bi_string_zv)
+       {
+         /* #### urk!  More of this lossage! */
+         data.bi_bufpos--;
+         goto done;
+       }
+
+      /* Check for face changes. */
+      if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end))
+       {
+         /* 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);
+         /* This is somewhat cheesy but the alternative is to
+             propagate default_face into extent_fragment_update. */
+         if (data.findex == DEFAULT_INDEX)
+           data.findex = default_face;
+
+         get_display_tables (w, data.findex, &face_dt, &window_dt);
+
+         if (data.bi_bufpos == data.ef->end)
+           no_more_frags = 1;
+       }
+      initial = 0;
+
+      /* Determine what is next to be displayed.  We first handle any
+         glyphs returned by glyphs_at_bufpos.  If there are no glyphs to
+         display then we determine what to do based on the character at the
+         current buffer position. */
+
+      /* If the current position is covered by an invisible extent, do
+         nothing (except maybe add some ellipses).
+
+        #### The behavior of begin and end-glyphs at the edge of an
+        invisible extent should be investigated further.  This is
+        fairly low priority though. */
+      if (data.ef->invisible)
+       {
+         /* #### Chuck, perhaps you could look at this code?  I don't
+            really know what I'm doing. */
+         if (*prop)
+           {
+             Dynarr_free (*prop);
+             *prop = 0;
+           }
+
+         /* The extent fragment code only sets this when we should
+            really display the ellipses.  It makes sure the ellipses
+            don't get displayed more than once in a row. */
+         if (data.ef->invisible_ellipses)
+           {
+             struct glyph_block gb;
+
+             data.ef->invisible_ellipses_already_displayed = 1;
+             data.ef->invisible_ellipses = 0;
+             gb.extent = Qnil;
+             gb.glyph = Vinvisible_text_glyph;
+             *prop = add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0,
+                                     GLYPH_CACHEL (w, INVIS_GLYPH_INDEX));
+             /* Perhaps they shouldn't propagate if the very next thing
+                is to display a newline (for compatibility with
+                selective-display-ellipses)?  Maybe that's too
+                abstruse. */
+             if (*prop)
+               goto done;
+           }
+
+         /* #### What if we we're dealing with a display table? */
+         if (data.start_col)
+           data.start_col--;
+
+         if (data.bi_bufpos == bi_string_zv)
+           goto done;
+         else
+           INC_CHARBYTIND (string_data (s), data.bi_bufpos);
+       }
+
+      /* 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. */
+      else if (*prop)
+       {
+         dl->used_prop_data = 1;
+         *prop = add_propagation_runes (prop, &data);
+
+         if (*prop)
+           goto done;  /* gee, a really narrow window */
+         else if (data.bi_bufpos == bi_string_zv)
+           goto done;
+         else if (data.bi_bufpos < 0)
+           /* #### urk urk urk! Aborts are not very fun! Fix this please! */
+           data.bi_bufpos = 0;
+         else
+           INC_CHARBYTIND (string_data (s), data.bi_bufpos);
+       }
+
+      /* If there are end glyphs, add them to the line.  These are
+        the end glyphs for the previous run of text.  We add them
+        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)
+       {
+         *prop = add_glyph_runes (&data, END_GLYPHS);
+         if (*prop)
+           goto done;
+       }
+
+      /* 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 at end-of-buffer, we've already processed begin and
+        end-glyphs at this point and there's no text to process,
+        so we're done. */
+      else if (data.bi_bufpos == bi_string_zv)
+       goto done;
+
+      else
+       {
+         Lisp_Object entry = Qnil;
+         /* Get the character at the current buffer position. */
+         data.ch = string_char (s, data.bi_bufpos);
+         if (!NILP (face_dt) || !NILP (window_dt))
+           entry = display_table_entry (data.ch, face_dt, window_dt);
+
+         /* If there is a display table entry for it, hand it off to
+             add_disp_table_entry_runes and let it worry about it. */
+         if (!NILP (entry) && !EQ (entry, make_char (data.ch)))
+           {
+             *prop = add_disp_table_entry_runes (&data, entry);
+
+             if (*prop)
+               goto done;
+           }
+
+         /* Check if we have hit a newline character.  If so, add a marker
+             to the line and end this loop. */
+         else if (data.ch == '\n')
+           {
+             /* 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;
+             goto done;
+           }
+
+         /* If the current character is considered to be printable, then
+             just add it. */
+         else if (data.ch >= printable_min)
+           {
+             *prop = add_emchar_rune (&data);
+             if (*prop)
+               goto done;
+           }
+
+         /* If the current character is a tab, determine the next tab
+             starting position and add a blank rune which extends from the
+             current pixel position to that starting position. */
+         else if (data.ch == '\t')
+           {
+             int tab_start_pixpos = data.pixpos;
+             int next_tab_start;
+             int char_tab_width;
+             int prop_width = 0;
+
+             if (data.start_col > 1)
+               tab_start_pixpos -= (space_width (w) * (data.start_col - 1));
+
+             next_tab_start =
+               next_tab_position (w, tab_start_pixpos,
+                                  dl->bounds.left_in +
+                                  data.hscroll_glyph_width_adjust);
+             if (next_tab_start > data.max_pixpos)
+               {
+                 prop_width = next_tab_start - data.max_pixpos;
+                 next_tab_start = data.max_pixpos;
+               }
+             data.blank_width = next_tab_start - data.pixpos;
+             char_tab_width =
+               (next_tab_start - tab_start_pixpos) / space_width (w);
+
+             *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. */
+             assert (!(*prop));
+
+             if (prop_width)
+               {
+                 struct prop_block pb;
+                 *prop = Dynarr_new (prop_block);
+
+                 pb.type = PROP_BLANK;
+                 pb.data.p_blank.width = prop_width;
+                 pb.data.p_blank.findex = data.findex;
+                 Dynarr_add (*prop, pb);
+
+                 goto done;
+               }
+           }
+
+         /* If character is a control character, pass it off to
+             add_control_char_runes.
+
+            The is_*() routines have undefined results on
+            arguments outside of the range [-1, 255].  (This
+            often bites people who carelessly use `char' instead
+            of `unsigned char'.)
+            */
+         else if (data.ch < 0x100 && iscntrl ((Bufbyte) data.ch))
+           {
+             *prop = add_control_char_runes (&data, b);
+
+             if (*prop)
+               goto done;
+           }
+
+         /* If the character is above the ASCII range and we have not
+             already handled it, then print it as an octal number. */
+         else if (data.ch >= 0200)
+           {
+             *prop = add_octal_runes (&data);
+
+             if (*prop)
+               goto done;
+           }
+
+         /* Assume the current character is considered to be printable,
+             then just add it. */
+         else
+           {
+             *prop = add_emchar_rune (&data);
+             if (*prop)
+               goto done;
+           }
+
+         INC_CHARBYTIND (string_data (s), data.bi_bufpos);
+       }
+    }
+
+done:
+
+  /* Determine the starting point of the next line if we did not hit the
+     end of the buffer. */
+  if (data.bi_bufpos < bi_string_zv)
+    {
+      /* #### This check is not correct.  If the line terminated
+        due to a begin-glyph or end-glyph hitting window-end, then
+        data.ch will not point to the character at data.bi_bufpos.  If
+        you make the two changes mentioned at the top of this loop,
+        you should be able to say '(if (*prop))'.  That should also
+        make it possible to eliminate the data.bi_bufpos < BI_BUF_ZV (b)
+        check. */
+
+      /* The common case is that the line ended because we hit a newline.
+         In that case, the next character is just the next buffer
+         position. */
+      if (data.ch == '\n')
+       {
+         INC_CHARBYTIND (string_data (s), data.bi_bufpos);
+       }
+
+      /* Otherwise we have a buffer line which cannot fit on one display
+         line. */
+      else
+       {
+         struct glyph_block gb;
+         struct glyph_cachel *cachel;
+
+         /* If the line is to be truncated then we actually have to look
+             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.findex = default_face;
+         gb.extent = Qnil;
+
+         if (truncate_win)
+           {
+             Bytind bi_pos;
+
+             /* Now find the start of the next line. */
+             bi_pos = bi_find_next_emchar_in_string (s, '\n', data.bi_bufpos, 1);
+
+             data.cursor_type = NO_CURSOR;
+             data.bi_bufpos = bi_pos;
+             gb.glyph = Vtruncation_glyph;
+             cachel = GLYPH_CACHEL (w, TRUN_GLYPH_INDEX);
+           }
+         else
+           {
+             /* The cursor can never be on the continuation glyph. */
+             data.cursor_type = NO_CURSOR;
+
+             /* data.bi_bufpos is already at the start of the next line. */
+
+             gb.glyph = Vcontinuation_glyph;
+             cachel = GLYPH_CACHEL (w, CONT_GLYPH_INDEX);
+           }
+
+         if (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);
+             DEC_CHARPTR (endb);
+             if (charptr_emchar (endb) != '\n')
+               {
+                 /* #### Damn this losing shit. */
+                 data.bi_bufpos++;
+               }
+           }
+       }
+    }
+  else if (data.bi_bufpos == bi_string_zv)
+    {
+      /* We need to add a marker to the end of the line since there is no
+         newline character in order for the cursor to get drawn.  We label
+         it as a newline so that it gets handled correctly by the
+         whitespace routines below. */
+
+      data.ch = '\n';
+      data.blank_width = DEVMETH (d, eol_cursor_width, ());
+      data.findex = default_face;
+      data.start_col = 0;
+      data.bi_start_col_enabled = 0;
+
+      data.max_pixpos += data.blank_width;
+      add_emchar_rune (&data);
+      data.max_pixpos -= data.blank_width;
+
+      /* #### urk!  Chuck, this shit is bad news.  Going around
+        manipulating invalid positions is guaranteed to result in
+        trouble sooner or later. */
+      data.bi_bufpos = bi_string_zv + 1;
+    }
+
+  /* Calculate left whitespace boundary. */
+  {
+    int elt = 0;
+
+    /* Whitespace past a newline is considered right whitespace. */
+    while (elt < Dynarr_length (db->runes))
+      {
+       struct rune *rb = Dynarr_atp (db->runes, elt);
+
+       if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ')
+           || rb->type == RUNE_BLANK)
+         {
+           dl->bounds.left_white += rb->width;
+           elt++;
+         }
+       else
+         elt = Dynarr_length (db->runes);
+      }
+  }
+
+  /* Calculate right whitespace boundary. */
+  {
+    int elt = Dynarr_length (db->runes) - 1;
+    int done = 0;
+
+    while (!done && elt >= 0)
+      {
+       struct rune *rb = Dynarr_atp (db->runes, elt);
+
+       if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100
+           && isspace (rb->object.chr.ch))
+           && !rb->type == RUNE_BLANK)
+         {
+           dl->bounds.right_white = rb->xpos + rb->width;
+           done = 1;
+         }
+
+       elt--;
+
+      }
+
+    /* The line is blank so everything is considered to be right
+       whitespace. */
+    if (!done)
+      dl->bounds.right_white = dl->bounds.left_in;
+  }
+
+  /* Set the display blocks bounds. */
+  db->start_pos = dl->bounds.left_in;
+  if (Dynarr_length (db->runes))
+    {
+      struct rune *rb = Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
+
+      db->end_pos = rb->xpos + rb->width;
+    }
+  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);
+    }
+
+  dl->ascent = data.new_ascent;
+  dl->descent = data.new_descent;
+
+  {
+    unsigned short ascent = (unsigned short) XINT (w->minimum_line_ascent);
+
+    if (dl->ascent < ascent)
+      dl->ascent = ascent;
+  }
+  {
+    unsigned short descent = (unsigned short) XINT (w->minimum_line_descent);
+
+    if (dl->descent < descent)
+      dl->descent = descent;
+  }
+
+  dl->cursor_elt = data.cursor_x;
+  /* #### lossage lossage lossage! Fix this shit! */
+  if (data.bi_bufpos > bi_string_zv)
+    dl->end_bufpos = buffer_or_string_bytind_to_bufpos (disp_string, bi_string_zv);
+  else
+    dl->end_bufpos = buffer_or_string_bytind_to_bufpos (disp_string, data.bi_bufpos) - 1;
+  if (truncate_win)
+    data.dl->num_chars = 
+      string_column_at_point (s, dl->end_bufpos, XINT (b->tab_width));
+  else
+    /* This doesn't correctly take into account tabs and control
+       characters but if the window isn't being truncated then this
+       value isn't going to end up being used anyhow. */
+    data.dl->num_chars = dl->end_bufpos - dl->bufpos;
+
+  /* #### handle horizontally scrolled line with text none of which
+     was actually laid out. */
+
+  /* #### handle any remainder of overlay arrow */
+
+  if (*prop == ADD_FAILED)
+    *prop = NULL;
+
+  if (truncate_win && *prop)
+    {
+      Dynarr_free (*prop);
+      *prop = NULL;
+    }
+
+  extent_fragment_delete (data.ef);
+
+  /* #### If we started at EOB, then make sure we return a value past
+     it so that regenerate_window will exit properly.  This is bogus.
+     The main loop should get fixed so that it isn't necessary to call
+     this function if we are already at EOB. */
+
+  if (data.bi_bufpos == bi_string_zv && bi_start_pos == bi_string_zv)
+    return bytecount_to_charcount (string_data (s), data.bi_bufpos) + 1; /* Yuck! */
+  else
+    return bytecount_to_charcount (string_data (s), data.bi_bufpos);
+}
+
+/* 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
+   position when displayed in the given window.  The display line ends
+   when the contents of the line reach the right boundary of the given
+   window. 
+   
+   This is very similar to generate_display_line but with the same
+   limitations as create_string_text_block. I have taken the liberty
+   of fixing the bytind stuff though.*/
+
+static Bufpos
+generate_string_display_line (struct window *w, Lisp_Object disp_string,
+                             struct display_line *dl,
+                             Bufpos start_pos,
+                             prop_block_dynarr **prop,
+                             face_index default_face)
+{
+  Bufpos ret_bufpos;
+
+  /* you must set bounds before calling this. */
+
+  /* Reset what this line is using. */
+  if (dl->display_blocks)
+    Dynarr_reset (dl->display_blocks);
+  if (dl->left_glyphs)
+    {
+      Dynarr_free (dl->left_glyphs);
+      dl->left_glyphs = 0;
+    }
+  if (dl->right_glyphs)
+    {
+      Dynarr_free (dl->right_glyphs);
+      dl->right_glyphs = 0;
+    }
+
+  /* We aren't generating a modeline at the moment. */
+  dl->modeline = 0;
+
+  /* Create a display block for the text region of the line. */
+  ret_bufpos = create_string_text_block (w, disp_string, dl, start_pos,
+                                        prop, default_face);
+  dl->bufpos = start_pos;
+  if (dl->end_bufpos < dl->bufpos)
+    dl->end_bufpos = dl->bufpos;
+
+  /* If there are left glyphs associated with any character in the
+     text block, then create a display block to handle them. */
+  if (dl->left_glyphs != NULL && Dynarr_length (dl->left_glyphs))
+    create_left_glyph_block (w, dl, 0);
+
+  /* If there are right glyphs associated with any character in the
+     text block, then create a display block to handle them. */
+  if (dl->right_glyphs != NULL && Dynarr_length (dl->right_glyphs))
+    create_right_glyph_block (w, dl);
+
+  return ret_bufpos;
+}
+
+/* This is ripped off from regenerate_window. All we want to do is
+   loop through elements in the string creating display lines until we
+   have covered the provided area. Simple really.  */
+void
+generate_displayable_area (struct window *w, Lisp_Object disp_string,
+                          int xpos, int ypos, int width, int height,
+                          display_line_dynarr* dla,
+                          Bufpos start_pos,
+                          face_index default_face)
+{
+  int yend = ypos + height;
+  Charcount s_zv;
+
+  prop_block_dynarr *prop = 0;
+  layout_bounds bounds;
+  assert (dla);
+
+  Dynarr_reset (dla);
+  /* if there's nothing to do then do nothing. code after this assumes
+     there is something to do. */
+  if (NILP (disp_string))
+    return;
+
+  s_zv = XSTRING_CHAR_LENGTH (disp_string) - 1;
+
+  bounds.left_out = xpos;
+  bounds.right_out = xpos + width;
+  /* The inner boundaries mark where the glyph margins are located. */
+  bounds.left_in = bounds.left_out + window_left_margin_width (w);
+  bounds.right_in = bounds.right_out - window_right_margin_width (w);
+  /* We cannot fully calculate the whitespace boundaries as they
+     depend on the contents of the line being displayed. */
+  bounds.left_white = bounds.left_in;
+  bounds.right_white = bounds.right_in;
+
+  while (ypos < yend)
+    {
+      struct display_line dl;
+      struct display_line *dlp;
+      Bufpos next_pos;
+      int local;
+
+      if (Dynarr_length (dla) < Dynarr_largest (dla))
+       {
+         dlp = Dynarr_atp (dla, Dynarr_length (dla));
+         local = 0;
+       }
+      else
+       {
+
+         xzero (dl);
+         dlp = &dl;
+         local = 1;
+       }
+
+      dlp->bounds = bounds;
+      dlp->offset = 0;
+      next_pos = generate_string_display_line (w, disp_string, dlp, start_pos,
+                                              &prop, default_face);
+      /* we need to make sure that we continue along the line if there
+         is more left to display otherwise we just end up redisplaying
+         the same chunk over and over again. */
+      if (next_pos == start_pos && next_pos < s_zv)
+       start_pos++;
+      else
+       start_pos = next_pos;
+
+      dlp->ypos = ypos + dlp->ascent;
+      ypos = dlp->ypos + dlp->descent;
+
+      if (ypos > yend)
+       {
+         int visible_height = dlp->ascent + dlp->descent;
+
+         dlp->clip = (ypos - yend);
+         visible_height -= dlp->clip;
+
+         if (visible_height < VERTICAL_CLIP (w, 1))
+           {
+             if (local)
+               free_display_line (dlp);
+             break;
+           }
+       }
+      else
+       dlp->clip = 0;
+
+      Dynarr_add (dla, *dlp);
+
+      /* #### This type of check needs to be done down in the
+        generate_display_line call. */
+      if (start_pos >= s_zv)
+       break;
+    }
+
+  if (prop)
+    Dynarr_free (prop);
+}
+
+\f
+/***************************************************************************/
+/*                                                                        */
+/*                        window-regeneration routines                     */
+/*                                                                        */
+/***************************************************************************/
+
+/* For a given window and starting position in the buffer it contains,
+   ensure that the TYPE display lines accurately represent the
+   presentation of the window.  We pass the buffer instead of getting
+   it from the window since redisplay_window may have temporarily
+   changed it to the echo area buffer. */
+
+static void
+regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
+{
+  struct frame *f = XFRAME (w->frame);
+  struct buffer *b = XBUFFER (w->buffer);
+  int ypos = WINDOW_TEXT_TOP (w);
+  int yend;    /* set farther down */
+
+  prop_block_dynarr *prop;
+  layout_bounds bounds;
+  display_line_dynarr *dla;
+  int need_modeline;
+
+  /* The lines had better exist by this point. */
+  if (!(dla = window_display_lines (w, type)))
+    abort ();
+  Dynarr_reset (dla);
+  w->max_line_len = 0;
+
+  /* Normally these get updated in redisplay_window but it is possible
+     for this function to get called from some other points where that
+     update may not have occurred.  This acts as a safety check. */
+  if (!Dynarr_length (w->face_cachels))
+    reset_face_cachels (w);
+  if (!Dynarr_length (w->glyph_cachels))
+    reset_glyph_cachels (w);
+
+  Fset_marker (w->start[type], make_int (start_pos), w->buffer);
+  Fset_marker (w->pointm[type], make_int (point), w->buffer);
+  w->last_point_x[type] = -1;
+  w->last_point_y[type] = -1;
+
+  /* Make sure a modeline is in the structs if needed. */
+  need_modeline = ensure_modeline_generated (w, type);
+
+  /* Wait until here to set this so that the structs have a modeline
+     generated in the case where one didn't exist. */
+  yend = WINDOW_TEXT_BOTTOM (w);
+
+  bounds = calculate_display_line_boundaries (w, 0);
+
+  /* 97/3/14 jhod: stuff added here to support pre-prompts (used for input systems) */
+  if (MINI_WINDOW_P (w)
+      && (!NILP (Vminibuf_prompt) || !NILP (Vminibuf_preprompt))
+      && !echo_area_active (f)
+      && start_pos == BUF_BEGV (b))
+    {
+      struct prop_block pb;
+      Lisp_Object string;
+      prop = Dynarr_new (prop_block);
+
+      string = concat2(Vminibuf_preprompt, Vminibuf_prompt);
+      pb.type = PROP_MINIBUF_PROMPT;
+      pb.data.p_string.str = XSTRING_DATA(string);
+      pb.data.p_string.len = XSTRING_LENGTH(string);
+      Dynarr_add (prop, pb);
+    }
+  else
+    prop = 0;
+
+  while (ypos < yend)
+    {
+      struct display_line dl;
+      struct display_line *dlp;
+      int local;
+
+      if (Dynarr_length (dla) < Dynarr_largest (dla))
+       {
+         dlp = Dynarr_atp (dla, Dynarr_length (dla));
+         local = 0;
+       }
+      else
+       {
+
+         xzero (dl);
+         dlp = &dl;
+         local = 1;
+       }
+
+      dlp->bounds = bounds;
+      dlp->offset = 0;
+      start_pos = generate_display_line (w, dlp, 1, start_pos,
+                                        w->hscroll, &prop, type);
+      dlp->ypos = ypos + dlp->ascent;
+      ypos = dlp->ypos + dlp->descent;
+
+      if (ypos > yend)
+       {
+         int visible_height = dlp->ascent + dlp->descent;
+
+         dlp->clip = (ypos - yend);
+         visible_height -= dlp->clip;
+
+         if (visible_height < VERTICAL_CLIP (w, 1))
+           {
+             if (local)
+               free_display_line (dlp);
+             break;
+           }
+       }
+      else
+       dlp->clip = 0;
+
+      if (dlp->cursor_elt != -1)
+       {
+         /* #### This check is steaming crap.  Have to get things
+             fixed so when create_text_block hits EOB, we're done,
+             period. */
+         if (w->last_point_x[type] == -1)
+           {
+             w->last_point_x[type] = dlp->cursor_elt;
+             w->last_point_y[type] = Dynarr_length (dla);
+           }
+         else
+           {
+             /* #### This means that we've added a cursor at EOB
+                 twice.  Yuck oh yuck. */
+             struct display_block *db =
+               get_display_block_from_line (dlp, TEXT);
+
+             Dynarr_atp (db->runes, dlp->cursor_elt)->cursor_type = NO_CURSOR;
+             dlp->cursor_elt = -1;
+           }
+       }
+
+      if (dlp->num_chars > w->max_line_len)
+       w->max_line_len = dlp->num_chars;
+
+      Dynarr_add (dla, *dlp);
+
+      /* #### This isn't right, but it is close enough for now. */
+      w->window_end_pos[type] = start_pos;
+
+      /* #### This type of check needs to be done down in the
+        generate_display_line call. */
+      if (start_pos > BUF_ZV (b))
+       break;
     }
 
   if (prop)
-      Dynarr_free (prop);
+    Dynarr_free (prop);
 
   /* #### More not quite right, but close enough. */
   /* #### Ben sez: apparently window_end_pos[] is measured
@@ -4625,11 +5514,9 @@ regenerate_window_incrementally (struct window *w, Bufpos startp,
   /* If the changes are below the visible area then if point hasn't
      moved return success otherwise fail in order to be safe. */
   if (line > dla_end)
-    {
-      return regenerate_window_extents_only_changed (w, startp, pointm,
-                                                    extent_beg_unchanged,
-                                                    extent_end_unchanged);
-    }
+    return regenerate_window_extents_only_changed (w, startp, pointm,
+                                                  extent_beg_unchanged,
+                                                  extent_end_unchanged);
   else
     /* At this point we know what line the changes first affect.  We
        now redraw that line.  If the changes are contained within it
@@ -4753,12 +5640,9 @@ regenerate_window_incrementally (struct window *w, Bufpos startp,
              && extent_end_unchanged != -1
              && ((extent_beg_unchanged < ddl->bufpos)
                  || (extent_end_unchanged > ddl->end_bufpos)))
-           {
-             return
-               regenerate_window_extents_only_changed (w, startp, pointm,
-                                                       extent_beg_unchanged,
-                                                       extent_end_unchanged);
-           }
+           return regenerate_window_extents_only_changed (w, startp, pointm,
+                                                          extent_beg_unchanged,
+                                                          extent_end_unchanged);
          else
            return 1;
        }
@@ -4984,7 +5868,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
     }
   Fset_marker (w->pointm[DESIRED_DISP], make_int (pointm), the_buffer);
 
-  /* If the buffer has changed we have to invalid all of our face
+  /* If the buffer has changed we have to invalidate all of our face
      cache elements. */
   if ((!echo_active && b != window_display_buffer (w))
       || !Dynarr_length (w->face_cachels)
@@ -5081,6 +5965,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
          && !f->extents_changed
          && !f->faces_changed
          && !f->glyphs_changed
+         && !f->subwindows_changed
          && !f->point_changed
          && !f->windows_structure_changed)
        {
@@ -5101,6 +5986,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
              && !f->extents_changed
              && !f->faces_changed
              && !f->glyphs_changed
+             && !f->subwindows_changed
              && !f->windows_structure_changed)
            {
              if (point_visible (w, pointm, CURRENT_DISP)
@@ -5158,6 +6044,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
           && !f->clip_changed
           && !f->faces_changed
           && !f->glyphs_changed
+          && !f->subwindows_changed
           && !f->windows_structure_changed
           && !f->frame_changed
           && !truncation_changed
@@ -5237,8 +6124,9 @@ regeneration_done:
       Bufpos end = (w->window_end_pos[DESIRED_DISP] == -1
                    ? BUF_ZV (b)
                    : BUF_Z (b) - w->window_end_pos[DESIRED_DISP] - 1);
-
-      update_line_start_cache (w, start, end, pointm, 1);
+      /* Don't pollute the cache if not sure if we are correct */
+      if (w->start_at_line_beg)
+       update_line_start_cache (w, start, end, pointm, 1);
       redisplay_output_window (w);
       /*
        * If we just displayed the echo area, the line start cache is
@@ -5374,7 +6262,12 @@ redisplay_frame (struct frame *f, int preemption_check)
      being handled. */
   update_frame_menubars (f);
 #endif /* HAVE_MENUBARS */
-
+  update_frame_gutters (f);
+  /* 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);
@@ -5412,7 +6305,20 @@ redisplay_frame (struct frame *f, int preemption_check)
 
   /* Erase the frame before outputting its contents. */
   if (f->clear)
-    DEVMETH (d, clear_frame, (f));
+    {
+      DEVMETH (d, clear_frame, (f));
+    }
+
+  /* invalidate the subwindow cache. we are going to reuse the glyphs
+     flag here to cause subwindows to get instantiated. This is
+     because subwindows changed is less strict - dealing with things
+     like the clicked state of button. */
+  if (!Dynarr_length (f->subwindow_cachels)
+      || f->glyphs_changed
+      || f->frame_changed)
+    reset_subwindow_cachels (f);
+  else
+    mark_subwindow_cachels_as_not_updated (f);
 
   /* Do the selected window first. */
   redisplay_window (FRAME_SELECTED_WINDOW (f), 0);
@@ -5434,11 +6340,13 @@ redisplay_frame (struct frame *f, int preemption_check)
   f->faces_changed    = 0;
   f->frame_changed    = 0;
   f->glyphs_changed   = 0;
+  f->subwindows_changed   = 0;
   f->icon_changed     = 0;
   f->menubar_changed  = 0;
   f->modeline_changed = 0;
   f->point_changed    = 0;
   f->toolbar_changed  = 0;
+  f->gutter_changed  = 0;
   f->windows_changed  = 0;
   f->windows_structure_changed = 0;
   f->window_face_cache_reset = 0;
@@ -5497,7 +6405,8 @@ redisplay_device (struct device *d)
          f->faces_changed    || f->frame_changed || f->menubar_changed ||
          f->modeline_changed || f->point_changed || f->size_changed    ||
          f->toolbar_changed  || f->windows_changed || f->size_slipped  ||
-         f->windows_structure_changed || f->glyphs_changed)
+         f->windows_structure_changed || f->glyphs_changed || 
+         f->subwindows_changed || f->gutter_changed)
        {
          preempted = redisplay_frame (f, 0);
        }
@@ -5531,8 +6440,8 @@ redisplay_device (struct device *d)
              f->faces_changed    || f->frame_changed || f->menubar_changed ||
              f->modeline_changed || f->point_changed || f->size_changed    ||
              f->toolbar_changed  || f->windows_changed ||
-             f->windows_structure_changed ||
-             f->glyphs_changed)
+             f->windows_structure_changed || f->gutter_changed ||
+             f->glyphs_changed || f->subwindows_changed)
            {
              preempted = redisplay_frame (f, 0);
            }
@@ -5553,11 +6462,13 @@ redisplay_device (struct device *d)
   d->faces_changed    = 0;
   d->frame_changed    = 0;
   d->glyphs_changed   = 0;
+  d->subwindows_changed   = 0;
   d->icon_changed     = 0;
   d->menubar_changed  = 0;
   d->modeline_changed = 0;
   d->point_changed    = 0;
   d->toolbar_changed  = 0;
+  d->gutter_changed  = 0;
   d->windows_changed  = 0;
   d->windows_structure_changed = 0;
 
@@ -5598,9 +6509,9 @@ redisplay_without_hooks (void)
       !faces_changed   && !frame_changed    && !icon_changed    &&
       !menubar_changed && !modeline_changed && !point_changed   &&
       !size_changed    && !toolbar_changed  && !windows_changed &&
-      !glyphs_changed  &&
-      !windows_structure_changed && !disable_preemption &&
-      preemption_count < max_preempts)
+      !glyphs_changed  && !subwindows_changed &&
+      !gutter_changed && !windows_structure_changed &&
+      !disable_preemption && preemption_count < max_preempts)
     goto done;
 
   DEVICE_LOOP_NO_BREAK (devcons, concons)
@@ -5612,8 +6523,8 @@ redisplay_without_hooks (void)
          d->faces_changed    || d->frame_changed    || d->icon_changed    ||
          d->menubar_changed  || d->modeline_changed || d->point_changed   ||
          d->size_changed     || d->toolbar_changed  || d->windows_changed ||
-         d->windows_structure_changed ||
-         d->glyphs_changed)
+         d->windows_structure_changed || d->gutter_changed ||
+         d->glyphs_changed || d->subwindows_changed)
        {
          preempted = redisplay_device (d);
 
@@ -5637,11 +6548,13 @@ redisplay_without_hooks (void)
   extents_changed  = 0;
   frame_changed    = 0;
   glyphs_changed   = 0;
+  subwindows_changed   = 0;
   icon_changed     = 0;
   menubar_changed  = 0;
   modeline_changed = 0;
   point_changed    = 0;
   toolbar_changed  = 0;
+  gutter_changed  = 0;
   windows_changed  = 0;
   windows_structure_changed = 0;
   RESET_CHANGED_SET_FLAGS;
@@ -6242,7 +7155,7 @@ update_internal_cache_list (struct window *w, int type)
       else
        {
          struct line_start_cache lsc;
-
+         
          lsc.start = dl->bufpos;
          lsc.end = dl->end_bufpos;
          lsc.height = dl->ascent + dl->descent;