XEmacs 21.2.29 "Hestia".
[chise/xemacs-chise.git.1] / src / redisplay.c
index 7e29d59..42858ff 100644 (file)
@@ -246,18 +246,13 @@ typedef struct
 } prop_block_dynarr;
 
 
-static void generate_formatted_string_db (Lisp_Object format_str,
-                                         Lisp_Object result_str,
-                                         struct window *w,
-                                         struct display_line *dl,
-                                         struct display_block *db,
-                                         face_index findex, int min_pixpos,
-                                         int max_pixpos, int type);
 static Charcount generate_fstring_runes (struct window *w, pos_data *data,
                                         Charcount pos, Charcount min_pos,
                                         Charcount max_pos, Lisp_Object elt,
                                         int depth, int max_pixsize,
-                                        face_index findex, int type);
+                                        face_index findex, int type,
+                                        Charcount *offset,
+                                        Lisp_Object cur_ext);
 static prop_block_dynarr *add_glyph_rune (pos_data *data,
                                          struct glyph_block *gb,
                                          int pos_type, int allow_cursor,
@@ -300,10 +295,6 @@ static int max_preempts;
    isn't any reason we need more than a single set. */
 display_line_dynarr *cmotion_display_lines;
 
-/* Used by generate_formatted_string.  Global because they get used so
-   much that the dynamic allocation time adds up. */
-static Emchar_dynarr *formatted_string_emchar_dynarr;
-static struct display_line formatted_string_display_line;
 /* We store the extents that we need to generate in a Dynarr and then
    frob them all on at the end of generating the string.  We do it
    this way rather than adding them as we generate the string because
@@ -428,7 +419,6 @@ 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 */
@@ -869,7 +859,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))
            {
@@ -1351,7 +1341,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;
 
@@ -1534,6 +1524,16 @@ 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 need to change this so that we hold onto the glyph_index
+     here, not the glyph itself. */
+  get_glyph_cachel_index (w, gb->glyph);
+
   /* A nil extent indicates a special glyph (ex. truncator). */
   if (NILP (gb->extent)
       || (pos_type == BEGIN_GLYPHS &&
@@ -1551,7 +1551,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       if (cachel)
        width = cachel->width;
       else
-       width = glyph_width (gb->glyph, Qnil, data->findex, data->window);
+       width = glyph_width (gb->glyph, data->window);
 
       if (!width)
        return NULL;
@@ -1614,9 +1614,8 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
        }
       else
        {
-         ascent = glyph_ascent (gb->glyph, Qnil, data->findex, data->window);
-         descent = glyph_descent (gb->glyph, Qnil, data->findex,
-                                  data->window);
+         ascent = glyph_ascent (gb->glyph, data->window);
+         descent = glyph_descent (gb->glyph, data->window);
        }
 
       baseline = glyph_baseline (gb->glyph, data->window);
@@ -2777,8 +2776,8 @@ add_margin_runes (struct display_line *dl, struct display_block *db, int start,
              unsigned short ascent, descent;
              Lisp_Object baseline = glyph_baseline (gb->glyph, window);
 
-             ascent = glyph_ascent (gb->glyph, Qnil, gb->findex, window);
-             descent = glyph_descent (gb->glyph, Qnil, gb->findex, 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
@@ -2892,7 +2891,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
        {
          int width;
 
-         width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+         width = glyph_width (gb->glyph, window);
 
          if (white_in_start - width >= left_in_end)
            {
@@ -2943,7 +2942,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
        if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
            GL_INSIDE_MARGIN)
          {
-           gb->width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+           gb->width = glyph_width (gb->glyph, window);
            used_in += gb->width;
            Dynarr_add (ib, *gb);
          }
@@ -3012,7 +3011,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
        if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
            GL_INSIDE_MARGIN)
          {
-           int width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+           int width = glyph_width (gb->glyph, window);
 
            if (used_out)
              {
@@ -3054,7 +3053,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
       if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
          GL_OUTSIDE_MARGIN)
        {
-         int width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+         int width = glyph_width (gb->glyph, window);
 
          if (out_end + width <= in_out_start)
            {
@@ -3211,7 +3210,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
 
       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
        {
-         int width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+         int width = glyph_width (gb->glyph, window);
 
          if (white_in_end + width <= dl->bounds.right_in)
            {
@@ -3261,7 +3260,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
 
        if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
          {
-           gb->width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+           gb->width = glyph_width (gb->glyph, window);
            used_in += gb->width;
            Dynarr_add (ib, *gb);
          }
@@ -3325,7 +3324,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
 
        if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
          {
-           int width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+           int width = glyph_width (gb->glyph, window);
 
            if (used_out)
              {
@@ -3366,7 +3365,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
 
       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN)
        {
-         int width = glyph_width (gb->glyph, Qnil, gb->findex, window);
+         int width = glyph_width (gb->glyph, window);
 
          if (out_start - width >= in_out_end)
            {
@@ -3482,9 +3481,119 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
 /*                                                                        */
 /***************************************************************************/
 
+/* This function is also used in frame.c by `generate_title_string' */
+void
+generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
+                              struct window *w, struct display_line *dl,
+                              struct display_block *db, face_index findex,
+                              int min_pixpos, int max_pixpos, int type)
+{
+  struct frame *f = XFRAME (w->frame);
+  struct device *d = XDEVICE (f->device);
+
+  pos_data data;
+  int c_pixpos;
+  Charcount offset = 0;
+
+  xzero (data);
+  data.d = d;
+  data.db = db;
+  data.dl = dl;
+  data.findex = findex;
+  data.pixpos = min_pixpos;
+  data.max_pixpos = max_pixpos;
+  data.cursor_type = NO_CURSOR;
+  data.last_charset = Qunbound;
+  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);
+  Dynarr_reset (formatted_string_extent_start_dynarr);
+  Dynarr_reset (formatted_string_extent_end_dynarr);
+
+  /* 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 */
+  if (! NILP (result_str))
+    offset = w->modeline_hscroll;
+  generate_fstring_runes (w, &data, 0, 0, -1, format_str, 0,
+                          max_pixpos - min_pixpos, findex, type, &offset,
+                         Qnil);
+
+  if (Dynarr_length (db->runes))
+    {
+      struct rune *rb =
+        Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
+      c_pixpos = rb->xpos + rb->width;
+    }
+  else
+    c_pixpos = min_pixpos;
+
+  /* If we don't reach the right side of the window, add a blank rune
+     to make up the difference.  This usually only occurs if the
+     modeline face is using a proportional width font or a fixed width
+     font of a different size from the default face font. */
+
+  if (c_pixpos < max_pixpos)
+    {
+      data.pixpos = c_pixpos;
+      data.blank_width = max_pixpos - data.pixpos;
+
+      add_blank_rune (&data, NULL, 0);
+    }
+
+  /* Now create the result string and frob the extents into it. */
+  if (!NILP (result_str))
+    {
+      int elt;
+      Bytecount len;
+      Bufbyte *strdata;
+      struct buffer *buf = XBUFFER (WINDOW_BUFFER (w));
+
+      detach_all_extents (result_str);
+      resize_string (XSTRING (result_str), -1,
+                     data.bytepos - XSTRING_LENGTH (result_str));
+
+      strdata = XSTRING_DATA (result_str);
+
+      for (elt = 0, len = 0; elt < Dynarr_length (db->runes); elt++)
+        {
+          if (Dynarr_atp (db->runes, elt)->type == RUNE_CHAR)
+            {
+              len += (set_charptr_emchar
+                      (strdata + len, Dynarr_atp (db->runes,
+                                                  elt)->object.chr.ch));
+            }
+        }
+
+      for (elt = 0; elt < Dynarr_length (formatted_string_extent_dynarr);
+           elt++)
+        {
+          Lisp_Object extent = Qnil;
+          Lisp_Object child;
+
+          XSETEXTENT (extent, Dynarr_at (formatted_string_extent_dynarr, elt));
+          child = Fgethash (extent, buf->modeline_extent_table, Qnil);
+          if (NILP (child))
+            {
+              child = Fmake_extent (Qnil, Qnil, result_str);
+              Fputhash (extent, child, buf->modeline_extent_table);
+            }
+          Fset_extent_parent (child, extent);
+          set_extent_endpoints
+            (XEXTENT (child),
+             Dynarr_at (formatted_string_extent_start_dynarr, elt),
+             Dynarr_at (formatted_string_extent_end_dynarr, elt),
+             result_str);
+        }
+    }
+}
+
 /* Ensure that the given display line DL accurately represents the
    modeline for the given window. */
-
 static void
 generate_modeline (struct window *w, struct display_line *dl, int type)
 {
@@ -3585,117 +3694,13 @@ generate_modeline (struct window *w, struct display_line *dl, int type)
     dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
 }
 
-static void
-generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
-                              struct window *w, struct display_line *dl,
-                              struct display_block *db, face_index findex,
-                              int min_pixpos, int max_pixpos, int type)
-{
-  struct frame *f = XFRAME (w->frame);
-  struct device *d = XDEVICE (f->device);
-
-  pos_data data;
-  int c_pixpos;
-
-  xzero (data);
-  data.d = d;
-  data.db = db;
-  data.dl = dl;
-  data.findex = findex;
-  data.pixpos = min_pixpos;
-  data.max_pixpos = max_pixpos;
-  data.cursor_type = NO_CURSOR;
-  data.last_charset = Qunbound;
-  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);
-  Dynarr_reset (formatted_string_extent_start_dynarr);
-  Dynarr_reset (formatted_string_extent_end_dynarr);
-
-  /* This recursively builds up the modeline. */
-  generate_fstring_runes (w, &data, 0, 0, -1, format_str, 0,
-                          max_pixpos - min_pixpos, findex, type);
-
-  if (Dynarr_length (db->runes))
-    {
-      struct rune *rb =
-        Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
-      c_pixpos = rb->xpos + rb->width;
-    }
-  else
-    c_pixpos = min_pixpos;
-
-  /* If we don't reach the right side of the window, add a blank rune
-     to make up the difference.  This usually only occurs if the
-     modeline face is using a proportional width font or a fixed width
-     font of a different size from the default face font. */
-
-  if (c_pixpos < max_pixpos)
-    {
-      data.pixpos = c_pixpos;
-      data.blank_width = max_pixpos - data.pixpos;
-
-      add_blank_rune (&data, NULL, 0);
-    }
-
-  /* Now create the result string and frob the extents into it. */
-  if (!NILP (result_str))
-    {
-      int elt;
-      Bytecount len;
-      Bufbyte *strdata;
-      struct buffer *buf = XBUFFER (WINDOW_BUFFER (w));
-
-      detach_all_extents (result_str);
-      resize_string (XSTRING (result_str), -1,
-                     data.bytepos - XSTRING_LENGTH (result_str));
-
-      strdata = XSTRING_DATA (result_str);
-
-      for (elt = 0, len = 0; elt < Dynarr_length (db->runes); elt++)
-        {
-          if (Dynarr_atp (db->runes, elt)->type == RUNE_CHAR)
-            {
-              len += (set_charptr_emchar
-                      (strdata + len, Dynarr_atp (db->runes,
-                                                  elt)->object.chr.ch));
-            }
-        }
-
-      for (elt = 0; elt < Dynarr_length (formatted_string_extent_dynarr);
-           elt++)
-        {
-          Lisp_Object extent = Qnil;
-          Lisp_Object child;
-
-          XSETEXTENT (extent, Dynarr_at (formatted_string_extent_dynarr, elt));
-          child = Fgethash (extent, buf->modeline_extent_table, Qnil);
-          if (NILP (child))
-            {
-              child = Fmake_extent (Qnil, Qnil, result_str);
-              Fputhash (extent, child, buf->modeline_extent_table);
-            }
-          Fset_extent_parent (child, extent);
-          set_extent_endpoints
-            (XEXTENT (child),
-             Dynarr_at (formatted_string_extent_start_dynarr, elt),
-             Dynarr_at (formatted_string_extent_end_dynarr, elt),
-             result_str);
-        }
-    }
-}
-
 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));
@@ -3703,13 +3708,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);
@@ -3734,7 +3739,8 @@ add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str,
    modeline extents. */
 static Charcount
 add_glyph_to_fstring_db_runes (pos_data *data, Lisp_Object glyph,
-                               Charcount pos, Charcount min_pos, Charcount max_pos)
+                               Charcount pos, Charcount min_pos,
+                              Charcount max_pos, Lisp_Object extent)
 {
   /* This function has been Mule-ized. */
   Charcount end;
@@ -3750,7 +3756,7 @@ add_glyph_to_fstring_db_runes (pos_data *data, Lisp_Object glyph,
     end = min (max_pos, end);
 
   gb.glyph = glyph;
-  gb.extent = Qnil;
+  gb.extent = extent;
   add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
   pos++;
 
@@ -3777,7 +3783,8 @@ static Charcount
 generate_fstring_runes (struct window *w, pos_data *data, Charcount pos,
                         Charcount min_pos, Charcount max_pos,
                         Lisp_Object elt, int depth, int max_pixsize,
-                        face_index findex, int type)
+                        face_index findex, int type, Charcount *offset,
+                       Lisp_Object cur_ext)
 {
   /* This function has been Mule-ized. */
   /* #### The other losing things in this function are:
@@ -3809,13 +3816,22 @@ tail_recurse:
 
           if (this != last)
             {
-              /* The string is just a string. */
+              /* No %-construct */
               Charcount size =
-                bytecount_to_charcount (last, this - last) + pos;
-              Charcount tmp_max = (max_pos == -1 ? size : min (size, max_pos));
+               bytecount_to_charcount (last, this - last);
+
+             if (size <= *offset)
+               *offset -= size;
+             else
+               {
+                 Charcount tmp_max = (max_pos == -1 ? pos + size - *offset :
+                                      min (pos + size - *offset, max_pos));
+                 const Bufbyte *tmp_last = charptr_n_addr (last, *offset);
 
-              pos = add_string_to_fstring_db_runes (data, last, pos, pos,
-                                                    tmp_max);
+                 pos = add_string_to_fstring_db_runes (data, tmp_last,
+                                                       pos, pos, tmp_max);
+                 *offset = 0;
+               }
             }
           else /* *this == '%' */
             {
@@ -3840,7 +3856,7 @@ tail_recurse:
                   pos = generate_fstring_runes (w, data, pos, spec_width,
                                                 max_pos, Vglobal_mode_string,
                                                 depth, max_pixsize, findex,
-                                                type);
+                                                type, offset, cur_ext);
                 }
               else if (*this == '-')
                 {
@@ -3867,17 +3883,35 @@ 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)
                 {
-                  Bufbyte *str;
                   Emchar ch = charptr_emchar (this);
+                  Bufbyte *str;
+                 Charcount size;
+
                   decode_mode_spec (w, ch, type);
 
                   str = Dynarr_atp (mode_spec_bufbyte_string, 0);
-                  pos = add_string_to_fstring_db_runes (data,str, pos, pos,
-                                                        max_pos);
+                 size = bytecount_to_charcount
+                   /* Skip the null character added by `decode_mode_spec' */
+                   (str, Dynarr_length (mode_spec_bufbyte_string)) - 1;
+
+                 if (size <= *offset)
+                   *offset -= size;
+                 else
+                   {
+                     const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+
+                     /* #### NOTE: I don't understand why a tmp_max is not
+                        computed and used here as in the plain string case
+                        above. -- dv */
+                     pos = add_string_to_fstring_db_runes (data, tmp_str,
+                                                           pos, pos,
+                                                           max_pos);
+                     *offset = 0;
+                   }
                 }
 
               /* NOT this++.  There could be any sort of character at
@@ -3903,13 +3937,26 @@ tail_recurse:
 
       if (!UNBOUNDP (tem))
         {
-          /* If value is a string, output that string literally:
+         /* If value is a string, output that string literally:
              don't check for % within it.  */
           if (STRINGP (tem))
             {
-              pos =
-                add_string_to_fstring_db_runes
-                (data, XSTRING_DATA (tem), pos, min_pos, max_pos);
+             Bufbyte *str = XSTRING_DATA (tem);
+             Charcount size = XSTRING_CHAR_LENGTH (tem);
+
+             if (size <= *offset)
+               *offset -= size;
+             else
+               {
+                 const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+
+                 /* #### NOTE: I don't understand why a tmp_max is not
+                    computed and used here as in the plain string case
+                    above. -- dv */
+                 pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
+                                                       min_pos, max_pos);
+                 *offset = 0;
+               }
             }
           /* Give up right away for nil or t.  */
           else if (!EQ (tem, elt))
@@ -3934,50 +3981,53 @@ tail_recurse:
   else if (CONSP (elt))
     {
       /* A cons cell: four distinct cases.
-       * If first element is a string or a cons, process all the elements
-       * and effectively concatenate them.
-       * If first element is a negative number, truncate displaying cdr to
-       * at most that many characters.  If positive, pad (with spaces)
-       * to at least that many characters.
-       * If first element is a 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 a string or a cons, process all the elements
+       *   and effectively concatenate them.
+       * - If first element is a negative number, truncate displaying cdr to
+       *   at most that many characters.  If positive, pad (with spaces)
+       *   to at least that many characters.
+       * - 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.
        */
+
       Lisp_Object car, tem;
 
       car = XCAR (elt);
       if (SYMBOLP (car))
-        {
-          elt = XCDR (elt);
-          if (!CONSP (elt))
-            goto invalid;
-          tem = symbol_value_in_buffer (car, w->buffer);
-          /* elt is now the cdr, and we know it is a cons cell.
-             Use its car if CAR has a non-nil value.  */
-          if (!UNBOUNDP (tem))
-            {
-              if (!NILP (tem))
-                {
-                  elt = XCAR (elt);
-                  goto tail_recurse;
-                }
-            }
-          /* Symbol's value is nil (or symbol is unbound)
-           * Get the cddr of the original list
-           * and if possible find the caddr and use that.
-           */
-          elt = XCDR (elt);
-          if (NILP (elt))
-            ;
-          else if (!CONSP (elt))
-            goto invalid;
-          else
-            {
-              elt = XCAR (elt);
-              goto tail_recurse;
-            }
-        }
+       {
+         elt = XCDR (elt);
+         if (!CONSP (elt))
+           goto invalid;
+
+         tem = symbol_value_in_buffer (car, w->buffer);
+         /* elt is now the cdr, and we know it is a cons cell.
+            Use its car if CAR has a non-nil value.  */
+         if (!UNBOUNDP (tem))
+           {
+             if (!NILP (tem))
+               {
+                 elt = XCAR (elt);
+                 goto tail_recurse;
+               }
+           }
+         /* Symbol's value is nil (or symbol is unbound)
+          * Get the cddr of the original list
+          * and if possible find the caddr and use that.
+          */
+         elt = XCDR (elt);
+         if (NILP (elt))
+           ;
+         else if (!CONSP (elt))
+           goto invalid;
+         else
+           {
+             elt = XCAR (elt);
+             goto tail_recurse;
+           }
+       }
       else if (INTP (car))
         {
           Charcount lim = XINT (car);
@@ -4016,13 +4066,14 @@ tail_recurse:
       else if (STRINGP (car) || CONSP (car))
         {
           int limit = 50;
+
           /* LIMIT is to protect against circular lists.  */
           while (CONSP (elt) && --limit > 0
                  && (pos < max_pos || max_pos == -1))
             {
               pos = generate_fstring_runes (w, data, pos, pos, max_pos,
-                                            XCAR (elt), depth,
-                                            max_pixsize, findex, type);
+                                            XCAR (elt), depth, max_pixsize,
+                                           findex, type, offset, cur_ext);
               elt = XCDR (elt);
             }
         }
@@ -4061,7 +4112,8 @@ tail_recurse:
               data->findex = new_findex;
               pos = generate_fstring_runes (w, data, pos, pos, max_pos,
                                             XCDR (elt), depth - 1,
-                                            max_pixsize, new_findex, type);
+                                           max_pixsize, new_findex, type,
+                                           offset, car);
               data->findex = old_findex;
               Dynarr_add (formatted_string_extent_dynarr, ext);
               Dynarr_add (formatted_string_extent_start_dynarr, start);
@@ -4071,57 +4123,46 @@ tail_recurse:
     }
   else if (GLYPHP (elt))
     {
-      pos = add_glyph_to_fstring_db_runes (data, elt, pos, pos, max_pos);
+      /* Glyphs are considered as one character with respect to the modeline
+        horizontal scrolling facility. -- dv */
+      if (*offset > 0)
+       *offset -= 1;
+      else
+       pos = add_glyph_to_fstring_db_runes (data, elt, pos, pos, max_pos,
+                                            cur_ext);
     }
   else
     {
     invalid:
-      pos =
-        add_string_to_fstring_db_runes
-          (data, (CONST Bufbyte *) GETTEXT ("*invalid*"), pos, min_pos,
-           max_pos);
+      {
+       char *str = GETTEXT ("*invalid*");
+       Charcount size = (Charcount) strlen (str); /* is this ok ?? -- dv */
+
+       if (size <= *offset)
+         *offset -= size;
+       else
+         {
+           const Bufbyte *tmp_str =
+             charptr_n_addr ((const Bufbyte *) str, *offset);
+
+           /* #### NOTE: I don't understand why a tmp_max is not computed and
+              used here as in the plain string case above. -- dv */
+           pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
+                                                 min_pos, max_pos);
+           *offset = 0;
+         }
+      }
     }
 
   if (min_pos > pos)
     {
-      add_string_to_fstring_db_runes (data, (CONST Bufbyte *) "", pos, min_pos,
-                                      -1);
+      add_string_to_fstring_db_runes (data, (const Bufbyte *) "", pos,
+                                     min_pos, -1);
     }
 
   return pos;
 }
 
-/* The caller is responsible for freeing the returned string. */
-Bufbyte *
-generate_formatted_string (struct window *w, Lisp_Object format_str,
-                          Lisp_Object result_str, face_index findex, int type)
-{
-  struct display_line *dl;
-  struct display_block *db;
-  int elt = 0;
-
-  dl = &formatted_string_display_line;
-  db = get_display_block_from_line (dl, TEXT);
-  Dynarr_reset (db->runes);
-
-  generate_formatted_string_db (format_str, result_str, w, dl, db, findex, 0,
-                                -1, type);
-
-  Dynarr_reset (formatted_string_emchar_dynarr);
-  while (elt < Dynarr_length (db->runes))
-    {
-      if (Dynarr_atp (db->runes, elt)->type == RUNE_CHAR)
-       Dynarr_add (formatted_string_emchar_dynarr,
-                   Dynarr_atp (db->runes, elt)->object.chr.ch);
-      elt++;
-    }
-
-  return
-    convert_emchar_string_into_malloced_string
-    ( Dynarr_atp (formatted_string_emchar_dynarr, 0),
-      Dynarr_length (formatted_string_emchar_dynarr), 0);
-}
-
 /* Update just the modeline.  Assumes the desired display structs.  If
    they do not have a modeline block, it does nothing. */
 static void
@@ -4250,7 +4291,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);
@@ -4731,7 +4772,7 @@ done:
 
          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')
                {
@@ -5900,7 +5941,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);
@@ -6164,7 +6205,9 @@ regeneration_done:
      somewhere else once tty updates occur on a per-frame basis. */
   mark_face_cachels_as_clean (w);
 
-  /* The glyph cachels only get dirty if someone changed something. */
+  /* The glyph cachels only get dirty if someone changed something.
+   Since redisplay has now effectively ended we can reset the dirty
+   flag since everything must be up-to-date. */
   if (glyphs_changed)
     mark_glyph_cachels_as_clean (w);
 
@@ -6389,16 +6432,27 @@ 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
+      && (MAYBE_INT_DEVMETH (d, device_implementation_flags, ())
+         & XDEVIMPF_NO_AUTO_REDISPLAY))
+    return 0;
+
   if (DEVICE_STREAM_P (d)) /* nothing to do */
     return 0;
 
@@ -6513,7 +6567,7 @@ redisplay_without_hooks (void)
 
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d))
        {
-         preempted = redisplay_device (d);
+         preempted = redisplay_device (d, 1);
 
          if (preempted)
            {
@@ -6627,7 +6681,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);
@@ -6656,7 +6710,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;
       }
@@ -8885,7 +8939,7 @@ input and is guaranteed to proceed to completion.
     {
       XFRAME (XCAR (frmcons))->clear = 1;
     }
-  redisplay_device (d);
+  redisplay_device (d, 0);
 
   return unbind_to (count, Qnil);
 }
@@ -8912,7 +8966,7 @@ input and is guaranteed to proceed to completion.
       disable_preemption++;
     }
 
-  redisplay_device (d);
+  redisplay_device (d, 0);
 
   return unbind_to (count, Qnil);
 }
@@ -9092,14 +9146,18 @@ init_redisplay (void)
   if (!initialized)
 #endif
     {
-      cmotion_display_lines = Dynarr_new (display_line);
-      mode_spec_bufbyte_string = Dynarr_new (Bufbyte);
-      formatted_string_emchar_dynarr = Dynarr_new (Emchar);
-      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);
-      xzero (formatted_string_display_line);
+      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 */
@@ -9383,9 +9441,9 @@ This is a specifier; use `set-specifier' to change it.
   Vleft_margin_width = Fmake_specifier (Qnatnum);
   set_specifier_fallback (Vleft_margin_width, list1 (Fcons (Qnil, Qzero)));
   set_specifier_caching (Vleft_margin_width,
-                        slot_offset (struct window, left_margin_width),
+                        offsetof (struct window, left_margin_width),
                         some_window_value_changed,
-                        slot_offset (struct frame, left_margin_width),
+                        offsetof (struct frame, left_margin_width),
                         margin_width_changed_in_frame);
 
   DEFVAR_SPECIFIER ("right-margin-width", &Vright_margin_width /*
@@ -9395,9 +9453,9 @@ This is a specifier; use `set-specifier' to change it.
   Vright_margin_width = Fmake_specifier (Qnatnum);
   set_specifier_fallback (Vright_margin_width, list1 (Fcons (Qnil, Qzero)));
   set_specifier_caching (Vright_margin_width,
-                        slot_offset (struct window, right_margin_width),
+                        offsetof (struct window, right_margin_width),
                         some_window_value_changed,
-                        slot_offset (struct frame, right_margin_width),
+                        offsetof (struct frame, right_margin_width),
                         margin_width_changed_in_frame);
 
   DEFVAR_SPECIFIER ("minimum-line-ascent", &Vminimum_line_ascent /*
@@ -9407,7 +9465,7 @@ This is a specifier; use `set-specifier' to change it.
   Vminimum_line_ascent = Fmake_specifier (Qnatnum);
   set_specifier_fallback (Vminimum_line_ascent, list1 (Fcons (Qnil, Qzero)));
   set_specifier_caching (Vminimum_line_ascent,
-                        slot_offset (struct window, minimum_line_ascent),
+                        offsetof (struct window, minimum_line_ascent),
                         some_window_value_changed,
                         0, 0);
 
@@ -9418,7 +9476,7 @@ This is a specifier; use `set-specifier' to change it.
   Vminimum_line_descent = Fmake_specifier (Qnatnum);
   set_specifier_fallback (Vminimum_line_descent, list1 (Fcons (Qnil, Qzero)));
   set_specifier_caching (Vminimum_line_descent,
-                        slot_offset (struct window, minimum_line_descent),
+                        offsetof (struct window, minimum_line_descent),
                         some_window_value_changed,
                         0, 0);
 
@@ -9430,7 +9488,7 @@ This is a specifier; use `set-specifier' to change it.
   Vuse_left_overflow = Fmake_specifier (Qboolean);
   set_specifier_fallback (Vuse_left_overflow, list1 (Fcons (Qnil, Qnil)));
   set_specifier_caching (Vuse_left_overflow,
-                        slot_offset (struct window, use_left_overflow),
+                        offsetof (struct window, use_left_overflow),
                         some_window_value_changed,
                         0, 0);
 
@@ -9442,7 +9500,7 @@ This is a specifier; use `set-specifier' to change it.
   Vuse_right_overflow = Fmake_specifier (Qboolean);
   set_specifier_fallback (Vuse_right_overflow, list1 (Fcons (Qnil, Qnil)));
   set_specifier_caching (Vuse_right_overflow,
-                        slot_offset (struct window, use_right_overflow),
+                        offsetof (struct window, use_right_overflow),
                         some_window_value_changed,
                         0, 0);
 
@@ -9453,7 +9511,7 @@ This is a specifier; use `set-specifier' to change it.
   Vtext_cursor_visible_p = Fmake_specifier (Qboolean);
   set_specifier_fallback (Vtext_cursor_visible_p, list1 (Fcons (Qnil, Qt)));
   set_specifier_caching (Vtext_cursor_visible_p,
-                        slot_offset (struct window, text_cursor_visible_p),
+                        offsetof (struct window, text_cursor_visible_p),
                         text_cursor_visible_p_changed,
                         0, 0);