XEmacs 21.2.33 "Melpomene".
[chise/xemacs-chise.git.1] / src / glyphs.c
index 1d71858..66b05c5 100644 (file)
@@ -59,6 +59,7 @@ Lisp_Object Qcolor_pixmap_image_instance_p;
 Lisp_Object Qpointer_image_instance_p;
 Lisp_Object Qsubwindow_image_instance_p;
 Lisp_Object Qlayout_image_instance_p;
+Lisp_Object Qupdate_widget_instances;
 Lisp_Object Qwidget_image_instance_p;
 Lisp_Object Qconst_glyph_variable;
 Lisp_Object Qmono_pixmap, Qcolor_pixmap, Qsubwindow;
@@ -128,6 +129,7 @@ static void image_validate (Lisp_Object instantiator);
 static void glyph_property_was_changed (Lisp_Object glyph,
                                        Lisp_Object property,
                                        Lisp_Object locale);
+static void set_image_instance_dirty_p (Lisp_Object instance, int dirty);
 static void register_ignored_expose (struct frame* f, int x, int y, int width, int height);
 /* Unfortunately windows and X are different. In windows BeginPaint()
    will prevent WM_PAINT messages being generated so it is unnecessary
@@ -137,6 +139,7 @@ int hold_ignored_expose_registration;
 
 EXFUN (Fimage_instance_type, 1);
 EXFUN (Fglyph_type, 1);
+EXFUN (Fnext_window, 4);
 
 \f
 /****************************************************************************
@@ -168,7 +171,7 @@ decode_device_ii_format (Lisp_Object device, Lisp_Object format,
          if ((NILP (d) && NILP (device))
              ||
              (!NILP (device) &&
-              EQ (CONSOLE_TYPE (XCONSOLE 
+              EQ (CONSOLE_TYPE (XCONSOLE
                                 (DEVICE_CONSOLE (XDEVICE (device)))), d)))
            return Dynarr_at (the_image_instantiator_format_entry_dynarr, i).meths;
        }
@@ -563,7 +566,7 @@ normalize_image_instantiator (Lisp_Object instantiator,
     struct image_instantiator_methods *meths;
 
     GCPRO1 (instantiator);
-    
+
     meths = decode_image_instantiator_format (XVECTOR_DATA (instantiator)[0],
                                              ERROR_ME);
     RETURN_UNGCPRO (IIFORMAT_METH_OR_GIVEN (meths, normalize,
@@ -579,6 +582,7 @@ instantiate_image_instantiator (Lisp_Object device, Lisp_Object domain,
                                int dest_mask, Lisp_Object glyph)
 {
   Lisp_Object ii = allocate_image_instance (device, glyph);
+  Lisp_Image_Instance* p = XIMAGE_INSTANCE (ii);
   struct image_instantiator_methods *meths;
   struct gcpro gcpro1;
   int  methp = 0;
@@ -594,7 +598,7 @@ instantiate_image_instantiator (Lisp_Object device, Lisp_Object domain,
   methp = (int)HAS_IIFORMAT_METH_P (meths, instantiate);
   MAYBE_IIFORMAT_METH (meths, instantiate, (ii, instantiator, pointer_fg,
                                            pointer_bg, dest_mask, domain));
-  
+
   /* now do device specific instantiation */
   meths = decode_device_ii_format (device, XVECTOR_DATA (instantiator)[0],
                                   ERROR_ME_NOT);
@@ -607,6 +611,18 @@ instantiate_image_instantiator (Lisp_Object device, Lisp_Object domain,
                                            pointer_bg, dest_mask, domain));
   UNGCPRO;
 
+  /* Some code may have already laid out the widget, if not then do it
+     here. */
+  if (IMAGE_INSTANCE_LAYOUT_CHANGED (p))
+    image_instance_layout (ii, IMAGE_UNSPECIFIED_GEOMETRY,
+                          IMAGE_UNSPECIFIED_GEOMETRY, domain);
+
+  /* We *must* have a clean image at this point. */
+  IMAGE_INSTANCE_TEXT_CHANGED (p) = 0;
+  IMAGE_INSTANCE_SIZE_CHANGED (p) = 0;
+  IMAGE_INSTANCE_LAYOUT_CHANGED (p) = 0;
+  IMAGE_INSTANCE_DIRTYP (p) = 0;
+
   return ii;
 }
 
@@ -620,7 +636,7 @@ Lisp_Object Qimage_instancep;
 static Lisp_Object
 mark_image_instance (Lisp_Object obj)
 {
-  struct Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
+  Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
 
   mark_object (i->name);
   /* We don't mark the glyph reference since that would create a
@@ -641,20 +657,18 @@ mark_image_instance (Lisp_Object obj)
       break;
 
     case IMAGE_WIDGET:
+    case IMAGE_LAYOUT:
       mark_object (IMAGE_INSTANCE_WIDGET_TYPE (i));
       mark_object (IMAGE_INSTANCE_WIDGET_PROPS (i));
       mark_object (IMAGE_INSTANCE_WIDGET_FACE (i));
       mark_object (IMAGE_INSTANCE_WIDGET_ITEMS (i));
+      mark_object (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (i));
+      mark_object (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (i));
+      mark_object (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (i));
     case IMAGE_SUBWINDOW:
       mark_object (IMAGE_INSTANCE_SUBWINDOW_FRAME (i));
       break;
 
-    case IMAGE_LAYOUT:
-      mark_object (IMAGE_INSTANCE_LAYOUT_CHILDREN (i));
-      mark_object (IMAGE_INSTANCE_LAYOUT_BORDER (i));
-      mark_object (IMAGE_INSTANCE_SUBWINDOW_FRAME (i));
-      break;
-
     default:
       break;
     }
@@ -669,7 +683,7 @@ print_image_instance (Lisp_Object obj, Lisp_Object printcharfun,
                      int escapeflag)
 {
   char buf[100];
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (obj);
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (obj);
 
   if (print_readably)
     error ("printing unreadable object #<image-instance 0x%x>",
@@ -757,16 +771,21 @@ print_image_instance (Lisp_Object obj, Lisp_Object printcharfun,
       break;
 
     case IMAGE_WIDGET:
+      print_internal (IMAGE_INSTANCE_WIDGET_TYPE (ii), printcharfun, 0);
+
+      if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
+       {
+         write_c_string (" ", printcharfun);
+         print_internal (IMAGE_INSTANCE_WIDGET_TEXT (ii), printcharfun, 1);
+       }
+
       if (!NILP (IMAGE_INSTANCE_WIDGET_FACE (ii)))
        {
-         write_c_string (" (", printcharfun);
+         write_c_string (" face=", printcharfun);
          print_internal
            (IMAGE_INSTANCE_WIDGET_FACE (ii), printcharfun, 0);
-         write_c_string (")", printcharfun);
        }
 
-      if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
-       print_internal (IMAGE_INSTANCE_WIDGET_TEXT (ii), printcharfun, 0);
 
     case IMAGE_SUBWINDOW:
     case IMAGE_LAYOUT:
@@ -781,19 +800,17 @@ print_image_instance (Lisp_Object obj, Lisp_Object printcharfun,
       write_c_string (" on #<", printcharfun);
       {
        struct frame* f  = XFRAME (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii));
-       
+
        if (!FRAME_LIVE_P (f))
          write_c_string ("dead", printcharfun);
-       else 
+       else
          write_c_string (DEVICE_TYPE_NAME (XDEVICE (FRAME_DEVICE (f))),
                          printcharfun);
-
-       write_c_string ("-frame ", printcharfun);
       }
-      write_c_string (">", printcharfun);
+      write_c_string ("-frame>", printcharfun);
       sprintf (buf, " 0x%p", IMAGE_INSTANCE_SUBWINDOW_ID (ii));
       write_c_string (buf, printcharfun);
-      
+
       break;
 
     default:
@@ -809,7 +826,7 @@ print_image_instance (Lisp_Object obj, Lisp_Object printcharfun,
 static void
 finalize_image_instance (void *header, int for_disksave)
 {
-  struct Lisp_Image_Instance *i = (struct Lisp_Image_Instance *) header;
+  Lisp_Image_Instance *i = (Lisp_Image_Instance *) header;
 
   if (IMAGE_INSTANCE_TYPE (i) == IMAGE_NOTHING)
     /* objects like this exist at dump time, so don't bomb out. */
@@ -819,9 +836,11 @@ finalize_image_instance (void *header, int for_disksave)
   /* do this so that the cachels get reset */
   if (IMAGE_INSTANCE_TYPE (i) == IMAGE_WIDGET
       ||
+      IMAGE_INSTANCE_TYPE (i) == IMAGE_SUBWINDOW
+      ||
       IMAGE_INSTANCE_TYPE (i) == IMAGE_SUBWINDOW)
     {
-      MARK_FRAME_SUBWINDOWS_CHANGED 
+      MARK_FRAME_SUBWINDOWS_CHANGED
        (XFRAME (IMAGE_INSTANCE_SUBWINDOW_FRAME (i)));
     }
 
@@ -831,8 +850,8 @@ finalize_image_instance (void *header, int for_disksave)
 static int
 image_instance_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
 {
-  struct Lisp_Image_Instance *i1 = XIMAGE_INSTANCE (obj1);
-  struct Lisp_Image_Instance *i2 = XIMAGE_INSTANCE (obj2);
+  Lisp_Image_Instance *i1 = XIMAGE_INSTANCE (obj1);
+  Lisp_Image_Instance *i2 = XIMAGE_INSTANCE (obj2);
   struct device *d1 = XDEVICE (i1->device);
   struct device *d2 = XDEVICE (i2->device);
 
@@ -881,32 +900,30 @@ image_instance_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
       break;
 
     case IMAGE_WIDGET:
+    case IMAGE_LAYOUT:
       if (!(EQ (IMAGE_INSTANCE_WIDGET_TYPE (i1),
                IMAGE_INSTANCE_WIDGET_TYPE (i2))
            && IMAGE_INSTANCE_SUBWINDOW_ID (i1) ==
            IMAGE_INSTANCE_SUBWINDOW_ID (i2)
+           &&
+           EQ (IMAGE_INSTANCE_WIDGET_FACE (i1),
+               IMAGE_INSTANCE_WIDGET_TYPE (i2))
            && internal_equal (IMAGE_INSTANCE_WIDGET_ITEMS (i1),
                               IMAGE_INSTANCE_WIDGET_ITEMS (i2),
                               depth + 1)
            && internal_equal (IMAGE_INSTANCE_WIDGET_PROPS (i1),
                               IMAGE_INSTANCE_WIDGET_PROPS (i2),
                               depth + 1)
+           && internal_equal (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (i1),
+                              IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (i2),
+                              depth + 1)
+           && internal_equal (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (i1),
+                              IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (i2),
+                              depth + 1)
            ))
        return 0;
       break;
-      
-    case IMAGE_LAYOUT:
-      if (IMAGE_INSTANCE_TYPE (i1) == IMAGE_LAYOUT
-         &&
-         !(EQ (IMAGE_INSTANCE_LAYOUT_BORDER (i1),
-               IMAGE_INSTANCE_LAYOUT_BORDER (i2))
-           &&
-           internal_equal (IMAGE_INSTANCE_LAYOUT_CHILDREN (i1),
-                           IMAGE_INSTANCE_LAYOUT_CHILDREN (i2),
-                           depth + 1)))
-       return 0;
-      break;
-      
+
     case IMAGE_SUBWINDOW:
       if (!(IMAGE_INSTANCE_SUBWINDOW_ID (i1) ==
            IMAGE_INSTANCE_SUBWINDOW_ID (i2)))
@@ -920,10 +937,32 @@ image_instance_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
   return DEVMETH_OR_GIVEN (d1, image_instance_equal, (i1, i2, depth), 1);
 }
 
+#if 0
+/* internal_hash will not go very far down a list because of the way
+   its written. For items we need to hash all elements so we provide
+   our own list hashing function. */
+static unsigned long
+full_list_hash (Lisp_Object obj, int depth)
+{
+  unsigned long hash = 0;
+  Lisp_Object rest;
+
+  if (!CONSP (obj))
+    return internal_hash (obj, depth + 1);
+
+  hash = LISP_HASH (XCAR (obj));
+  LIST_LOOP (rest, XCDR (obj))
+    {
+      hash = HASH2 (hash, internal_hash (XCAR (rest), depth + 1));
+    }
+  return hash;
+}
+#endif
+
 static unsigned long
 image_instance_hash (Lisp_Object obj, int depth)
 {
-  struct Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
+  Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
   struct device *d = XDEVICE (i->device);
   unsigned long hash = HASH3 ((unsigned long) d,
                              IMAGE_INSTANCE_WIDTH (i),
@@ -949,21 +988,17 @@ image_instance_hash (Lisp_Object obj, int depth)
       break;
 
     case IMAGE_WIDGET:
-      hash = HASH4 (hash, 
-                   internal_hash (IMAGE_INSTANCE_WIDGET_TYPE (i), depth + 1),
+    case IMAGE_LAYOUT:
+      /* We need the hash to be equivalent to what should be
+         displayed. */
+      hash = HASH4 (hash,
+                   LISP_HASH (IMAGE_INSTANCE_WIDGET_TYPE (i)),
                    internal_hash (IMAGE_INSTANCE_WIDGET_PROPS (i), depth + 1),
                    internal_hash (IMAGE_INSTANCE_WIDGET_ITEMS (i), depth + 1));
     case IMAGE_SUBWINDOW:
       hash = HASH2 (hash, (int) IMAGE_INSTANCE_SUBWINDOW_ID (i));
       break;
 
-    case IMAGE_LAYOUT:
-      hash = HASH3 (hash,
-                   internal_hash (IMAGE_INSTANCE_LAYOUT_BORDER (i), depth + 1),
-                   internal_hash (IMAGE_INSTANCE_LAYOUT_CHILDREN (i),
-                                  depth + 1));
-      break;
-
     default:
       abort ();
     }
@@ -976,13 +1011,13 @@ DEFINE_LRECORD_IMPLEMENTATION ("image-instance", image_instance,
                               mark_image_instance, print_image_instance,
                               finalize_image_instance, image_instance_equal,
                               image_instance_hash, 0,
-                              struct Lisp_Image_Instance);
+                              Lisp_Image_Instance);
 
 static Lisp_Object
 allocate_image_instance (Lisp_Object device, Lisp_Object glyph)
 {
-  struct Lisp_Image_Instance *lp =
-    alloc_lcrecord_type (struct Lisp_Image_Instance, &lrecord_image_instance);
+  Lisp_Image_Instance *lp =
+    alloc_lcrecord_type (Lisp_Image_Instance, &lrecord_image_instance);
   Lisp_Object val;
 
   zero_lcrecord (lp);
@@ -993,10 +1028,13 @@ allocate_image_instance (Lisp_Object device, Lisp_Object glyph)
   lp->y_offset = 0;
   lp->width = 0;
   lp->height = 0;
-  lp->glyph = glyph;
-  MARK_IMAGE_INSTANCE_CHANGED (lp); /* So that layouts get done. */
+  lp->parent = glyph;
+  /* So that layouts get done. */
+  lp->layout_changed = 1;
+
   XSETIMAGE_INSTANCE (val, lp);
-  MARK_GLYPHS_CHANGED; /* So that the dirty flag gets reset. */
+  MARK_GLYPHS_CHANGED;
+
   return val;
 }
 
@@ -1103,7 +1141,7 @@ incompatible_image_types (Lisp_Object instantiator, int given_dest_mask,
     (Qerror,
      list2
      (emacs_doprnt_string_lisp_2
-      ((CONST Bufbyte *)
+      ((const Bufbyte *)
        "No compatible image-instance types given: wanted one of %s, got %s",
        Qnil, -1, 2,
        encode_image_instance_type_list (desired_dest_mask),
@@ -1157,6 +1195,19 @@ encode_error_behavior_flag (Error_behavior errb)
     }
 }
 
+/* Recurse up the hierarchy looking for the topmost glyph. This means
+   that instances in layouts will inherit face properties from their
+   parent. */
+Lisp_Object image_instance_parent_glyph (Lisp_Image_Instance* ii)
+{
+  if (IMAGE_INSTANCEP (IMAGE_INSTANCE_PARENT (ii)))
+    {
+      return image_instance_parent_glyph
+       (XIMAGE_INSTANCE (IMAGE_INSTANCE_PARENT (ii)));
+    }
+  return IMAGE_INSTANCE_PARENT (ii);
+}
+
 static Lisp_Object
 make_image_instance_1 (Lisp_Object data, Lisp_Object device,
                       Lisp_Object dest_types)
@@ -1241,7 +1292,7 @@ If DEST-TYPES is omitted, all possible types are allowed.
 NO-ERROR controls what happens when the image cannot be generated.
 If nil, an error message is generated.  If t, no messages are
 generated and this function returns nil.  If anything else, a warning
-message is generated and this function returns nil.  
+message is generated and this function returns nil.
 */
        (data, device, dest_types, no_error))
 {
@@ -1296,13 +1347,13 @@ This will only be non-nil for text image instances and widgets.
 }
 
 DEFUN ("image-instance-property", Fimage_instance_property, 2, 2, 0, /*
-Return the given property of the given image instance.  
+Return the given property of the given image instance.
 Returns nil if the property or the property method do not exist for
-the image instance in the domain.  
+the image instance in the domain.
 */
        (image_instance, prop))
 {
-  struct Lisp_Image_Instance* ii;
+  Lisp_Image_Instance* ii;
   Lisp_Object type, ret;
   struct image_instantiator_methods* meths;
 
@@ -1312,10 +1363,10 @@ the image instance in the domain.
 
   /* ... then try device specific methods ... */
   type = encode_image_instance_type (IMAGE_INSTANCE_TYPE (ii));
-  meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), 
+  meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
                                   type, ERROR_ME_NOT);
   if (meths && HAS_IIFORMAT_METH_P (meths, property)
-      && 
+      &&
       !UNBOUNDP (ret =  IIFORMAT_METH (meths, property, (image_instance, prop))))
     {
       return ret;
@@ -1333,13 +1384,13 @@ the image instance in the domain.
 }
 
 DEFUN ("set-image-instance-property", Fset_image_instance_property, 3, 3, 0, /*
-Set the given property of the given image instance.  
+Set the given property of the given image instance.
 Does nothing if the property or the property method do not exist for
 the image instance in the domain.
 */
        (image_instance, prop, val))
 {
-  struct Lisp_Image_Instance* ii;
+  Lisp_Image_Instance* ii;
   Lisp_Object type, ret;
   struct image_instantiator_methods* meths;
 
@@ -1348,11 +1399,11 @@ the image instance in the domain.
   ii = XIMAGE_INSTANCE (image_instance);
   type = encode_image_instance_type (IMAGE_INSTANCE_TYPE (ii));
   /* try device specific methods first ... */
-  meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), 
+  meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
                                   type, ERROR_ME_NOT);
   if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
       &&
-      !UNBOUNDP (ret = 
+      !UNBOUNDP (ret =
                 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
     {
       val = ret;
@@ -1363,7 +1414,7 @@ the image instance in the domain.
       meths = decode_device_ii_format (Qnil, type, ERROR_ME_NOT);
       if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
          &&
-         !UNBOUNDP (ret = 
+         !UNBOUNDP (ret =
                     IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
        {
          val = ret;
@@ -1375,7 +1426,10 @@ the image instance in the domain.
     }
 
   /* Make sure the image instance gets redisplayed. */
-  MARK_IMAGE_INSTANCE_CHANGED (ii);
+  set_image_instance_dirty_p (image_instance, 1);
+  /* Force the glyph to be laid out again. */
+  IMAGE_INSTANCE_LAYOUT_CHANGED (ii) = 1;
+
   MARK_SUBWINDOWS_STATE_CHANGED;
   MARK_GLYPHS_CHANGED;
 
@@ -1551,7 +1605,7 @@ colorized mono pixmaps and for pointers.)
     case IMAGE_WIDGET:
       return FACE_FOREGROUND (
                              XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
-                             XIMAGE_INSTANCE_SUBWINDOW_FRAME 
+                             XIMAGE_INSTANCE_SUBWINDOW_FRAME
                              (image_instance));
 
     default:
@@ -1578,7 +1632,7 @@ colorized mono pixmaps and for pointers.)
     case IMAGE_WIDGET:
       return FACE_BACKGROUND (
                              XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
-                             XIMAGE_INSTANCE_SUBWINDOW_FRAME 
+                             XIMAGE_INSTANCE_SUBWINDOW_FRAME
                              (image_instance));
 
     default:
@@ -1628,21 +1682,21 @@ instance is a mono pixmap; otherwise, the same image instance is returned.
 /* Find out desired geometry of the image instance. If there is no
    special function then just return the width and / or height. */
 void
-image_instance_query_geometry (Lisp_Object image_instance, 
-                              unsigned int* width, unsigned int* height, 
+image_instance_query_geometry (Lisp_Object image_instance,
+                              unsigned int* width, unsigned int* height,
                               enum image_instance_geometry disp,
                               Lisp_Object domain)
 {
-  struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
   Lisp_Object type;
   struct image_instantiator_methods* meths;
 
   type = encode_image_instance_type (IMAGE_INSTANCE_TYPE (ii));
   meths = decode_device_ii_format (Qnil, type, ERROR_ME_NOT);
-  
+
   if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
     {
-      IIFORMAT_METH (meths, query_geometry, (image_instance, width, height, 
+      IIFORMAT_METH (meths, query_geometry, (image_instance, width, height,
                                             disp, domain));
     }
   else
@@ -1662,11 +1716,11 @@ image_instance_query_geometry (Lisp_Object image_instance,
    don't mind what size you have (normal widgets) and one where you
    want to specifiy something (layout widgets). */
 void
-image_instance_layout (Lisp_Object image_instance, 
-                      unsigned int width, unsigned int height, 
+image_instance_layout (Lisp_Object image_instance,
+                      unsigned int width, unsigned int height,
                       Lisp_Object domain)
 {
-  struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
   Lisp_Object type;
   struct image_instantiator_methods* meths;
 
@@ -1683,8 +1737,8 @@ image_instance_layout (Lisp_Object image_instance,
       /* Get the desired geometry. */
       if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
        {
-         IIFORMAT_METH (meths, query_geometry, (image_instance, &dwidth, &dheight, 
-                                                IMAGE_DESIRED_GEOMETRY, 
+         IIFORMAT_METH (meths, query_geometry, (image_instance, &dwidth, &dheight,
+                                                IMAGE_DESIRED_GEOMETRY,
                                                 domain));
        }
       else
@@ -1702,14 +1756,59 @@ image_instance_layout (Lisp_Object image_instance,
 
   /* At this point width and height should contain sane values. Thus
      we set the glyph geometry and lay it out. */
+  if (IMAGE_INSTANCE_WIDTH (ii) != width
+      ||
+      IMAGE_INSTANCE_HEIGHT (ii) != height)
+    {
+      IMAGE_INSTANCE_SIZE_CHANGED (ii) = 1;
+    }
+
   IMAGE_INSTANCE_WIDTH (ii) = width;
   IMAGE_INSTANCE_HEIGHT (ii) = height;
-  
+
   if (meths && HAS_IIFORMAT_METH_P (meths, layout))
     {
       IIFORMAT_METH (meths, layout, (image_instance, width, height, domain));
     }
   /* else no change to the geometry. */
+
+  /* Do not clear the dirty flag here - redisplay will do this for
+     us at the end. */
+  IMAGE_INSTANCE_LAYOUT_CHANGED (ii) = 0;
+}
+
+/*
+ * Mark image instance in W as dirty if (a) W's faces have changed and
+ * (b) GLYPH_OR_II instance in W is a string.
+ *
+ * Return non-zero if instance has been marked dirty.
+ */
+int
+invalidate_glyph_geometry_maybe (Lisp_Object glyph_or_ii, struct window* w)
+{
+  if (XFRAME(WINDOW_FRAME(w))->faces_changed)
+    {
+      Lisp_Object image = glyph_or_ii;
+
+      if (GLYPHP (glyph_or_ii))
+       {
+         Lisp_Object window;
+         XSETWINDOW (window, w);
+         image = glyph_image_instance (glyph_or_ii, window, ERROR_ME_NOT, 1);
+       }
+
+      if (TEXT_IMAGE_INSTANCEP (image))
+       {
+         Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image);
+         IMAGE_INSTANCE_DIRTYP (ii) = 1;
+         IMAGE_INSTANCE_LAYOUT_CHANGED (ii) = 1;
+         if (GLYPHP (glyph_or_ii))
+           XGLYPH_DIRTYP (glyph_or_ii) = 1;
+         return 1;
+       }
+    }
+
+  return 0;
 }
 
 \f
@@ -1717,14 +1816,14 @@ image_instance_layout (Lisp_Object image_instance,
 /*                              error helpers                           */
 /************************************************************************/
 DOESNT_RETURN
-signal_image_error (CONST char *reason, Lisp_Object frob)
+signal_image_error (const char *reason, Lisp_Object frob)
 {
   signal_error (Qimage_conversion_error,
                list2 (build_translated_string (reason), frob));
 }
 
 DOESNT_RETURN
-signal_image_error_2 (CONST char *reason, Lisp_Object frob0, Lisp_Object frob1)
+signal_image_error_2 (const char *reason, Lisp_Object frob0, Lisp_Object frob1)
 {
   signal_error (Qimage_conversion_error,
                list3 (build_translated_string (reason), frob0, frob1));
@@ -1745,7 +1844,7 @@ nothing_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
                     int dest_mask, Lisp_Object domain)
 {
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
 
   if (dest_mask & IMAGE_NOTHING_MASK)
     IMAGE_INSTANCE_TYPE (ii) = IMAGE_NOTHING;
@@ -1815,8 +1914,8 @@ string_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
                    int dest_mask, Lisp_Object domain)
 {
   Lisp_Object string = find_keyword_in_vector (instantiator, Q_data);
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
-  
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
   /* Should never get here with a domain other than a window. */
   assert (!NILP (string) && WINDOWP (domain));
   if (dest_mask & IMAGE_TEXT_MASK)
@@ -1835,7 +1934,7 @@ string_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
    helper that is used elsewhere for calculating text geometry. */
 void
 query_string_geometry (Lisp_Object string, Lisp_Object face,
-                      unsigned int* width, unsigned int* height, 
+                      unsigned int* width, unsigned int* height,
                       unsigned int* descent, Lisp_Object domain)
 {
   struct font_metric_info fm;
@@ -1851,7 +1950,7 @@ query_string_geometry (Lisp_Object string, Lisp_Object face,
       find_charsets_in_bufbyte_string (charsets,
                                       XSTRING_DATA   (string),
                                       XSTRING_LENGTH (string));
-      
+
       /* Fallback to the default face if none was provided. */
       if (!NILP (face))
        {
@@ -1863,16 +1962,16 @@ query_string_geometry (Lisp_Object string, Lisp_Object face,
        {
          cachel = WINDOW_FACE_CACHEL (XWINDOW (domain), DEFAULT_INDEX);
        }
-      
+
       ensure_face_cachel_complete (cachel, domain, charsets);
       face_cachel_charset_font_metric_info (cachel, charsets, &fm);
-      
+
       *height = fm.ascent + fm.descent;
       /* #### descent only gets set if we query the height as well. */
       if (descent)
        *descent = fm.descent;
     }
-    
+
   /* Compute width */
   if (width)
     {
@@ -1900,22 +1999,22 @@ query_string_font (Lisp_Object string, Lisp_Object face, Lisp_Object domain)
   find_charsets_in_bufbyte_string (charsets,
                                   XSTRING_DATA   (string),
                                   XSTRING_LENGTH (string));
+
   reset_face_cachel (&frame_cachel);
   update_face_cachel_data (&frame_cachel, frame, face);
   cachel = &frame_cachel;
 
   ensure_face_cachel_complete (cachel, domain, charsets);
-  
+
   for (i = 0; i < NUM_LEADING_BYTES; i++)
     {
       if (charsets[i])
        {
-         return FACE_CACHEL_FONT (cachel, 
-                                  CHARSET_BY_LEADING_BYTE (i + 
+         return FACE_CACHEL_FONT (cachel,
+                                  CHARSET_BY_LEADING_BYTE (i +
                                                            MIN_LEADING_BYTE));
 
-       }  
+       }
     }
 
   return Qnil;                 /* NOT REACHED */
@@ -1923,10 +2022,10 @@ query_string_font (Lisp_Object string, Lisp_Object face, Lisp_Object domain)
 
 static void
 text_query_geometry (Lisp_Object image_instance,
-                    unsigned int* width, unsigned int* height, 
+                    unsigned int* width, unsigned int* height,
                     enum image_instance_geometry disp, Lisp_Object domain)
 {
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
   unsigned int descent = 0;
 
   query_string_geometry (IMAGE_INSTANCE_TEXT_STRING (ii),
@@ -1943,7 +2042,7 @@ static Lisp_Object
 text_set_property (Lisp_Object image_instance, Lisp_Object prop,
                   Lisp_Object val)
 {
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
 
   if (EQ (prop, Q_data))
     {
@@ -1982,7 +2081,7 @@ formatted_string_instantiate (Lisp_Object image_instance,
   warn_when_safe (Qunimplemented, Qnotice,
                  "`formatted-string' not yet implemented; assuming `string'");
 
-  string_instantiate (image_instance, instantiator, 
+  string_instantiate (image_instance, instantiator,
                      pointer_fg, pointer_bg, dest_mask, domain);
 }
 
@@ -2147,9 +2246,11 @@ bitmap_to_lisp_data (Lisp_Object name, int *xhot, int *yhot,
   unsigned int w, h;
   Extbyte *data;
   int result;
-  CONST char *filename_ext;
+  const char *filename_ext;
 
-  GET_C_STRING_FILENAME_DATA_ALLOCA (name, filename_ext);
+  TO_EXTERNAL_FORMAT (LISP_STRING, name,
+                     C_STRING_ALLOCA, filename_ext,
+                     Qfile_name);
   result = read_bitmap_data_from_file (filename_ext, &w, &h,
                                       &data, xhot, yhot);
 
@@ -2159,7 +2260,7 @@ bitmap_to_lisp_data (Lisp_Object name, int *xhot, int *yhot,
       int len = (w + 7) / 8 * h;
 
       retval = list3 (make_int (w), make_int (h),
-                     make_ext_string (data, len, FORMAT_BINARY));
+                     make_ext_string (data, len, Qbinary));
       XFree ((char *) data);
       return retval;
     }
@@ -2392,8 +2493,10 @@ pixmap_to_lisp_data (Lisp_Object name, int ok_if_data_invalid)
   char **data;
   int result;
   char *fname = 0;
-  
-  GET_C_STRING_FILENAME_DATA_ALLOCA (name, fname);
+
+  TO_EXTERNAL_FORMAT (LISP_STRING, name,
+                     C_STRING_ALLOCA, fname,
+                     Qfile_name);
   result = XpmReadFileToData (fname, &data);
 
   if (result == XpmSuccess)
@@ -2603,7 +2706,7 @@ DEFINE_SPECIFIER_TYPE (image);
 static void
 image_create (Lisp_Object obj)
 {
-  struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
+  Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
 
   IMAGE_SPECIFIER_ALLOWED (image) = ~0; /* all are allowed */
   IMAGE_SPECIFIER_ATTACHEE (image) = Qnil;
@@ -2613,7 +2716,7 @@ image_create (Lisp_Object obj)
 static void
 image_mark (Lisp_Object obj)
 {
-  struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
+  Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
 
   mark_object (IMAGE_SPECIFIER_ATTACHEE (image));
   mark_object (IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image));
@@ -2622,7 +2725,14 @@ image_mark (Lisp_Object obj)
 static Lisp_Object
 image_instantiate_cache_result (Lisp_Object locative)
 {
-  /* locative = (instance instantiator . subtable) */
+  /* locative = (instance instantiator . subtable)
+
+     So we are using the instantiator as the key and the instance as
+     the value. Since the hashtable is key-weak this means that the
+     image instance will stay around as long as the instantiator stays
+     around. The instantiator is stored in the `image' slot of the
+     glyph, so as long as the glyph is marked the instantiator will be
+     as well and hence the cached image instance also.*/
   Fputhash (XCAR (XCDR (locative)), XCAR (locative), XCDR (XCDR (locative)));
   free_cons (XCONS (XCDR (locative)));
   free_cons (XCONS (locative));
@@ -2679,6 +2789,12 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
       Lisp_Object pointer_fg = Qnil;
       Lisp_Object pointer_bg = Qnil;
 
+      /* We have to put subwindow, widget and text image instances in
+        a per-window cache so that we can see the same glyph in
+        different windows. Unfortunately we do not know the type of
+        image_instance until after it has been created. We thus need
+        to be really careful how we place things.  */
+
       if (pointerp)
        {
          pointer_fg = FACE_FOREGROUND (Vpointer_face, domain);
@@ -2694,7 +2810,7 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
          /* For the image instance cache, we do comparisons with EQ rather
             than with EQUAL, as we do for color and font names.
             The reasons are:
-            
+
             1) pixmap data can be very long, and thus the hashing and
             comparing will take awhile.
             2) It's not so likely that we'll run into things that are EQUAL
@@ -2730,15 +2846,14 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
             round it. */
          if (UNBOUNDP (instance)
              &&
-             dest_mask & (IMAGE_SUBWINDOW_MASK 
+             dest_mask & (IMAGE_SUBWINDOW_MASK
                           | IMAGE_WIDGET_MASK
-                          | IMAGE_TEXT_MASK))
+                          | IMAGE_LAYOUT_MASK
+                          | IMAGE_TEXT_MASK)
+             && WINDOWP (domain))
            {
-             if (!WINDOWP (domain))
-               signal_simple_error ("Can't instantiate text or subwindow outside a window",
-                                    instantiator);
-             instance = Fgethash (instantiator, 
-                                  XWINDOW (domain)->subwindow_instance_cache, 
+             instance = Fgethash (instantiator,
+                                  XWINDOW (domain)->subwindow_instance_cache,
                                   Qunbound);
            }
        }
@@ -2750,7 +2865,7 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
                          noseeum_cons (pointerp ? ls3 : instantiator,
                                        subtable));
          int speccount = specpdl_depth ();
-         
+
          /* make sure we cache the failures, too.
             Use an unwind-protect to catch such errors.
             If we fail, the unwind-protect records nil in
@@ -2765,22 +2880,45 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
                                                     pointer_fg, pointer_bg,
                                                     dest_mask,
                                                     glyph);
-         
+
          Fsetcar (locative, instance);
          /* only after the image has been instantiated do we know
              whether we need to put it in the per-window image instance
              cache. */
          if (image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instance))
              &
-             (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
+             (IMAGE_SUBWINDOW_MASK 
+              | IMAGE_WIDGET_MASK
+              | IMAGE_LAYOUT_MASK
+              | IMAGE_TEXT_MASK ))
            {
+#ifdef ERROR_CHECK_GLYPHS
+             if (XIMAGE_INSTANCE_TYPE (instance) != IMAGE_TEXT)
+               assert (EQ (XIMAGE_INSTANCE_SUBWINDOW_FRAME (instance),
+                           FW_FRAME (domain)));
+#endif
              if (!WINDOWP (domain))
-               signal_simple_error ("Can't instantiate subwindow outside a window",
+               signal_simple_error ("Can't instantiate text or subwindow outside a window",
                                     instantiator);
-             
-             Fsetcdr (XCDR (locative), XWINDOW (domain)->subwindow_instance_cache );
+#ifdef ERROR_CHECK_GLYPHS
+             if (XIMAGE_INSTANCE_TYPE (instance) != IMAGE_TEXT)
+               assert (EQ (XIMAGE_INSTANCE_SUBWINDOW_FRAME (instance),
+                           FW_FRAME (domain)));
+#endif
+             Fsetcdr (XCDR (locative), XWINDOW (domain)->subwindow_instance_cache);
            }
          unbind_to (speccount, Qnil);
+#ifdef ERROR_CHECK_GLYPHS
+         if (image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instance))
+             &
+             (IMAGE_SUBWINDOW_MASK 
+              | IMAGE_WIDGET_MASK
+              | IMAGE_LAYOUT_MASK
+              | IMAGE_TEXT_MASK ))
+           assert (EQ (Fgethash ((pointerp ? ls3 : instantiator),
+                                 XWINDOW (domain)->subwindow_instance_cache,
+                                 Qunbound), instance));
+#endif
        }
       else
        free_list (ls3);
@@ -2788,6 +2926,12 @@ image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
       if (NILP (instance))
        signal_simple_error ("Can't instantiate image (probably cached)",
                             instantiator);
+#ifdef ERROR_CHECK_GLYPHS
+      if (image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instance))
+         & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
+       assert (EQ (XIMAGE_INSTANCE_SUBWINDOW_FRAME (instance),
+                   FW_FRAME (domain)));
+#endif
       return instance;
     }
 
@@ -2875,7 +3019,7 @@ void
 set_image_attached_to (Lisp_Object obj, Lisp_Object face_or_glyph,
                       Lisp_Object property)
 {
-  struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
+  Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
 
   IMAGE_SPECIFIER_ATTACHEE (image) = face_or_glyph;
   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = property;
@@ -2946,7 +3090,7 @@ image_copy_vector_instantiator (Lisp_Object instantiator)
   instantiator = Fcopy_sequence (instantiator);
   elt = XVECTOR_DATA (instantiator);
   instantiator_len = XVECTOR_LENGTH (instantiator);
-  
+
   meths = decode_image_instantiator_format (elt[0], ERROR_ME);
 
   for (i = 1; i < instantiator_len; i += 2)
@@ -3197,7 +3341,7 @@ file).
 static Lisp_Object
 mark_glyph (Lisp_Object obj)
 {
-  struct Lisp_Glyph *glyph = XGLYPH (obj);
+  Lisp_Glyph *glyph = XGLYPH (obj);
 
   mark_object (glyph->image);
   mark_object (glyph->contrib_p);
@@ -3210,7 +3354,7 @@ mark_glyph (Lisp_Object obj)
 static void
 print_glyph (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
 {
-  struct Lisp_Glyph *glyph = XGLYPH (obj);
+  Lisp_Glyph *glyph = XGLYPH (obj);
   char buf[20];
 
   if (print_readably)
@@ -3233,8 +3377,8 @@ print_glyph (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
 static int
 glyph_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
 {
-  struct Lisp_Glyph *g1 = XGLYPH (obj1);
-  struct Lisp_Glyph *g2 = XGLYPH (obj2);
+  Lisp_Glyph *g1 = XGLYPH (obj1);
+  Lisp_Glyph *g2 = XGLYPH (obj2);
 
   depth++;
 
@@ -3259,7 +3403,7 @@ glyph_hash (Lisp_Object obj, int depth)
 static Lisp_Object
 glyph_getprop (Lisp_Object obj, Lisp_Object prop)
 {
-  struct Lisp_Glyph *g = XGLYPH (obj);
+  Lisp_Glyph *g = XGLYPH (obj);
 
   if (EQ (prop, Qimage))     return g->image;
   if (EQ (prop, Qcontrib_p)) return g->contrib_p;
@@ -3307,7 +3451,7 @@ glyph_remprop (Lisp_Object obj, Lisp_Object prop)
 static Lisp_Object
 glyph_plist (Lisp_Object obj)
 {
-  struct Lisp_Glyph *glyph = XGLYPH (obj);
+  Lisp_Glyph *glyph = XGLYPH (obj);
   Lisp_Object result = glyph->plist;
 
   result = cons3 (Qface,      glyph->face,      result);
@@ -3319,7 +3463,11 @@ glyph_plist (Lisp_Object obj)
 }
 
 static const struct lrecord_description glyph_description[] = {
-  { XD_LISP_OBJECT, offsetof(struct Lisp_Glyph, image), 5 },
+  { XD_LISP_OBJECT, offsetof (Lisp_Glyph, image) },
+  { XD_LISP_OBJECT, offsetof (Lisp_Glyph, contrib_p) },
+  { XD_LISP_OBJECT, offsetof (Lisp_Glyph, baseline) },
+  { XD_LISP_OBJECT, offsetof (Lisp_Glyph, face) },
+  { XD_LISP_OBJECT, offsetof (Lisp_Glyph, plist) },
   { XD_END }
 };
 
@@ -3328,7 +3476,7 @@ DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("glyph", glyph,
                                          glyph_equal, glyph_hash, glyph_description,
                                          glyph_getprop, glyph_putprop,
                                          glyph_remprop, glyph_plist,
-                                         struct Lisp_Glyph);
+                                         Lisp_Glyph);
 \f
 Lisp_Object
 allocate_glyph (enum glyph_type type,
@@ -3337,8 +3485,7 @@ allocate_glyph (enum glyph_type type,
 {
   /* This function can GC */
   Lisp_Object obj = Qnil;
-  struct Lisp_Glyph *g =
-    alloc_lcrecord_type (struct Lisp_Glyph, &lrecord_glyph);
+  Lisp_Glyph *g = alloc_lcrecord_type (Lisp_Glyph, &lrecord_glyph);
 
   g->type = type;
   g->image = Fmake_specifier (Qimage); /* This function can GC */
@@ -3347,8 +3494,8 @@ allocate_glyph (enum glyph_type type,
     {
     case GLYPH_BUFFER:
       XIMAGE_SPECIFIER_ALLOWED (g->image) =
-       IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK 
-       | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK 
+       IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK
+       | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
        | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK
        | IMAGE_LAYOUT_MASK;
       break;
@@ -3500,9 +3647,10 @@ glyph_image_instance (Lisp_Object glyph, Lisp_Object domain,
 
   /* This can never return Qunbound.  All glyphs have 'nothing as
      a fallback. */
-  Lisp_Object image_instance = specifier_instance (specifier, Qunbound, 
+  Lisp_Object image_instance = specifier_instance (specifier, Qunbound,
                                                   domain, errb, no_quit, 0,
                                                   Qzero);
+  assert (!UNBOUNDP (image_instance));
 
   return image_instance;
 }
@@ -3533,7 +3681,7 @@ glyph_width (Lisp_Object glyph_or_image, Lisp_Object domain)
   if (!IMAGE_INSTANCEP (instance))
     return 0;
 
-  if (XIMAGE_INSTANCE_DIRTYP (instance))
+  if (XIMAGE_INSTANCE_NEEDS_LAYOUT (instance))
     image_instance_layout (instance, IMAGE_UNSPECIFIED_GEOMETRY,
                           IMAGE_UNSPECIFIED_GEOMETRY, domain);
 
@@ -3561,7 +3709,7 @@ glyph_ascent (Lisp_Object glyph_or_image, Lisp_Object domain)
   if (!IMAGE_INSTANCEP (instance))
     return 0;
 
-  if (XIMAGE_INSTANCE_DIRTYP (instance))
+  if (XIMAGE_INSTANCE_NEEDS_LAYOUT (instance))
     image_instance_layout (instance, IMAGE_UNSPECIFIED_GEOMETRY,
                           IMAGE_UNSPECIFIED_GEOMETRY, domain);
 
@@ -3579,7 +3727,7 @@ glyph_descent (Lisp_Object glyph_or_image, Lisp_Object domain)
   if (!IMAGE_INSTANCEP (instance))
     return 0;
 
-  if (XIMAGE_INSTANCE_DIRTYP (instance))
+  if (XIMAGE_INSTANCE_NEEDS_LAYOUT (instance))
     image_instance_layout (instance, IMAGE_UNSPECIFIED_GEOMETRY,
                           IMAGE_UNSPECIFIED_GEOMETRY, domain);
 
@@ -3595,11 +3743,11 @@ glyph_height (Lisp_Object glyph_or_image, Lisp_Object domain)
 {
   Lisp_Object instance = glyph_image_instance_maybe (glyph_or_image,
                                                     domain);
-  
+
   if (!IMAGE_INSTANCEP (instance))
     return 0;
 
-  if (XIMAGE_INSTANCE_DIRTYP (instance))
+  if (XIMAGE_INSTANCE_NEEDS_LAYOUT (instance))
     image_instance_layout (instance, IMAGE_UNSPECIFIED_GEOMETRY,
                           IMAGE_UNSPECIFIED_GEOMETRY, domain);
 
@@ -3646,13 +3794,6 @@ that redisplay will.
   return make_int (glyph_height (glyph, window));
 }
 
-static unsigned int
-glyph_dirty_p (Lisp_Object glyph_or_image, Lisp_Object window)
-{
-  return XIMAGE_INSTANCE_DIRTYP (glyph_image_instance_maybe 
-                                (glyph_or_image, window));
-}
-
 static void
 set_glyph_dirty_p (Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
 {
@@ -3671,6 +3812,22 @@ set_glyph_dirty_p (Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
     }
 }
 
+static void
+set_image_instance_dirty_p (Lisp_Object instance, int dirty)
+{
+  if (IMAGE_INSTANCEP (instance))
+    {
+      XIMAGE_INSTANCE_DIRTYP (instance) = dirty;
+      /* Now cascade up the hierarchy. */
+      set_image_instance_dirty_p (XIMAGE_INSTANCE_PARENT (instance),
+                                 dirty);
+    }
+  else if (GLYPHP (instance))
+    {
+      XGLYPH_DIRTYP (instance) = dirty;
+    }
+}
+
 /* #### do we need to cache this info to speed things up? */
 
 Lisp_Object
@@ -3728,14 +3885,14 @@ glyph_property_was_changed (Lisp_Object glyph, Lisp_Object property,
 #if 0                          /* Not used for now */
 static void
 glyph_query_geometry (Lisp_Object glyph_or_image, Lisp_Object window,
-                     unsigned int* width, unsigned int* height, 
+                     unsigned int* width, unsigned int* height,
                      enum image_instance_geometry disp, Lisp_Object domain)
 {
   Lisp_Object instance = glyph_or_image;
 
   if (GLYPHP (glyph_or_image))
     instance = glyph_image_instance (glyph_or_image, window, ERROR_ME_NOT, 1);
-  
+
   image_instance_query_geometry (instance, width, height, disp, domain);
 }
 
@@ -3747,7 +3904,7 @@ glyph_layout (Lisp_Object glyph_or_image, Lisp_Object window,
 
   if (GLYPHP (glyph_or_image))
     instance = glyph_image_instance (glyph_or_image, window, ERROR_ME_NOT, 1);
-  
+
   image_instance_layout (instance, width, height, domain);
 }
 #endif
@@ -3757,11 +3914,17 @@ glyph_layout (Lisp_Object glyph_or_image, Lisp_Object window,
  *                     glyph cachel functions                               *
  *****************************************************************************/
 
-/*
- #### All of this is 95% copied from face cachels.
-      Consider consolidating.
- */
-
+/* #### All of this is 95% copied from face cachels.  Consider
+  consolidating.
+
+  Why do we need glyph_cachels? Simply because a glyph_cachel captures
+  per-window information about a particular glyph. A glyph itself is
+  not created in any particular context, so if we were to rely on a
+  glyph to tell us about its dirtiness we would not be able to reset
+  the dirty flag after redisplaying it as it may exist in other
+  contexts. When we have redisplayed we need to know which glyphs to
+  reset the dirty flags on - the glyph_cachels give us a nice list we
+  can iterate through doing this.  */
 void
 mark_glyph_cachels (glyph_cachel_dynarr *elements)
 {
@@ -3782,17 +3945,25 @@ update_glyph_cachel_data (struct window *w, Lisp_Object glyph,
                          struct glyph_cachel *cachel)
 {
   if (!cachel->updated || NILP (cachel->glyph) || !EQ (cachel->glyph, glyph)
-      || XGLYPH_DIRTYP (cachel->glyph))
+      || XGLYPH_DIRTYP (cachel->glyph)
+      || XFRAME(WINDOW_FRAME(w))->faces_changed)
     {
       Lisp_Object window, instance;
 
       XSETWINDOW (window, w);
 
       cachel->glyph   = glyph;
-    /* Speed things up slightly by grabbing the glyph instantiation
-       and passing it to the size functions. */
+      /* Speed things up slightly by grabbing the glyph instantiation
+        and passing it to the size functions. */
       instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
-      cachel->dirty = XGLYPH_DIRTYP (glyph) = glyph_dirty_p (glyph, window);
+
+      /* Mark text instance of the glyph dirty if faces have changed,
+        because its geometry might have changed. */
+      invalidate_glyph_geometry_maybe (instance, w);
+
+      /* #### Do the following 2 lines buy us anything? --kkm */
+      XGLYPH_DIRTYP (glyph) = XIMAGE_INSTANCE_DIRTYP (instance);
+      cachel->dirty   = XGLYPH_DIRTYP (glyph);
       cachel->width   = glyph_width   (instance, window);
       cachel->ascent  = glyph_ascent  (instance, window);
       cachel->descent = glyph_descent (instance, window);
@@ -3877,7 +4048,7 @@ mark_glyph_cachels_as_not_updated (struct window *w)
 }
 
 /* Unset the dirty bit on all the glyph cachels that have it. */
-void 
+void
 mark_glyph_cachels_as_clean (struct window* w)
 {
   int elt;
@@ -4010,7 +4181,7 @@ update_subwindow_cachel (Lisp_Object subwindow)
     {
       struct subwindow_cachel *cachel =
        Dynarr_atp (f->subwindow_cachels, elt);
-      
+
       if (EQ (cachel->subwindow, subwindow) && !NILP (subwindow))
        {
          update_subwindow_cachel_data (f, subwindow, cachel);
@@ -4082,7 +4253,7 @@ check_for_ignored_expose (struct frame* f, int x, int y, int width, int height)
         we have to check for overlaps. Being conservative we will
         check for exposures wholly contained by the subwindow, this
         might give us what we want.*/
-      if (ei->x <= x && ei->y <= y 
+      if (ei->x <= x && ei->y <= y
          && ei->x + ei->width >= x + width
          && ei->y + ei->height >= y + height)
        {
@@ -4094,7 +4265,7 @@ check_for_ignored_expose (struct frame* f, int x, int y, int width, int height)
            f->subwindow_exposures = ei->next;
          else
            prev->next = ei->next;
-         
+
          if (ei == f->subwindow_exposures_tail)
            f->subwindow_exposures_tail = prev;
 
@@ -4112,15 +4283,15 @@ register_ignored_expose (struct frame* f, int x, int y, int width, int height)
   if (!hold_ignored_expose_registration)
     {
       struct expose_ignore *ei;
-      
+
       ei = Blocktype_alloc (the_expose_ignore_blocktype);
-      
+
       ei->next = NULL;
       ei->x = x;
       ei->y = y;
       ei->width = width;
       ei->height = height;
-      
+
       /* we have to add the exposure to the end of the list, since we
         want to check the oldest events first. for speed we keep a record
         of the end so that we can add right to it. */
@@ -4154,7 +4325,7 @@ int find_matching_subwindow (struct frame* f, int x, int y, int width, int heigh
       if (cachel->being_displayed
          &&
          cachel->x <= x && cachel->y <= y
-         && 
+         &&
          cachel->x + cachel->width >= x + width
          &&
          cachel->y + cachel->height >= y + height)
@@ -4170,49 +4341,104 @@ int find_matching_subwindow (struct frame* f, int x, int y, int width, int heigh
  *                              subwindow functions                          *
  *****************************************************************************/
 
-/* update the displayed characteristics of a subwindow */
-static void
+/* Update the displayed characteristics of a subwindow. This function
+   should generally only get called if the subwindow is actually
+   dirty. */
+void
 update_subwindow (Lisp_Object subwindow)
 {
-  struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+  int count = specpdl_depth ();
 
-  if (!IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
+  /* The update method is allowed to call eval.  Since it is quite
+     common for this function to get called from somewhere in
+     redisplay we need to make sure that quits are ignored.  Otherwise
+     Fsignal will abort. */
+  specbind (Qinhibit_quit, Qt);
+
+  if (IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
       ||
-      NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
-    return;
+      IMAGE_INSTANCE_TYPE (ii) == IMAGE_LAYOUT)
+    {
+      if (image_instance_changed (subwindow))
+       update_widget (subwindow);
+      /* Reset the changed flags. */
+      IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii) = 0;
+      IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0;
+      IMAGE_INSTANCE_TEXT_CHANGED (ii) = 0;
+    }
+  else if (IMAGE_INSTANCE_TYPE (ii) == IMAGE_SUBWINDOW
+          &&
+          !NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
+    {
+      MAYBE_DEVMETH (XDEVICE (ii->device), update_subwindow, (ii));
+    }
+
+  IMAGE_INSTANCE_SIZE_CHANGED (ii) = 0;
+  /* This function is typically called by redisplay just before
+     outputting the information to the screen. Thus we record a hash
+     of the output to determine whether on-screen is the same as
+     recorded structure. This approach has limitations in there is a
+     good chance that hash values will be different for the same
+     visual appearance. However, we would rather that then the other
+     way round - it simply means that we will get more displays than
+     we might need. We can get better hashing by making the depth
+     negative - currently it will recurse down 7 levels.*/
+  IMAGE_INSTANCE_DISPLAY_HASH (ii) = internal_hash (subwindow, 
+                                                   IMAGE_INSTANCE_HASH_DEPTH);
 
-  MAYBE_DEVMETH (XDEVICE (ii->device), update_subwindow, (ii));
-  /* We must update the window's size as it may have been changed by
-     the the layout routines. We also do this here so that explicit resizing
-     from lisp does not result in synchronous updates. */
-  MAYBE_DEVMETH (XDEVICE (ii->device), resize_subwindow, (ii,
-                IMAGE_INSTANCE_WIDTH (ii),
-                IMAGE_INSTANCE_HEIGHT (ii)));
+  unbind_to (count, Qnil);
+}
+
+int
+image_instance_changed (Lisp_Object subwindow)
+{
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+
+  if (internal_hash (subwindow, IMAGE_INSTANCE_HASH_DEPTH) != 
+      IMAGE_INSTANCE_DISPLAY_HASH (ii))
+    return 1;
+  else if ((WIDGET_IMAGE_INSTANCEP (subwindow)
+           || LAYOUT_IMAGE_INSTANCEP (subwindow))
+          && !internal_equal (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
+                              IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii), 0))
+    return 1;
+  else
+    return 0;
 }
 
 /* Update all the subwindows on a frame. */
-void
-update_frame_subwindows (struct frame *f)
+DEFUN ("update-widget-instances", Fupdate_widget_instances,1, 1, 0, /*
+Given a FRAME, re-evaluate the display hash code for all widgets in the frame.
+Don't use this.
+*/
+       (frame))
 {
   int elt;
+  struct frame* f;
+  CHECK_FRAME (frame);
+  f = XFRAME (frame);
 
-  if (f->subwindows_changed || f->subwindows_state_changed || f->faces_changed)
-    for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
+  /* If we get called we know something has changed. */
+  for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
       {
        struct subwindow_cachel *cachel =
          Dynarr_atp (f->subwindow_cachels, elt);
-       
-       if (cachel->being_displayed)
+
+       if (cachel->being_displayed &&
+           image_instance_changed (cachel->subwindow))
          {
-           update_subwindow (cachel->subwindow);
+           set_image_instance_dirty_p (cachel->subwindow, 1);
+           MARK_FRAME_GLYPHS_CHANGED (f);
          }
       }
+  return Qnil;
 }
 
 /* remove a subwindow from its frame */
 void unmap_subwindow (Lisp_Object subwindow)
 {
-  struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
   int elt;
   struct subwindow_cachel* cachel;
   struct frame* f;
@@ -4244,8 +4470,8 @@ void unmap_subwindow (Lisp_Object subwindow)
 void map_subwindow (Lisp_Object subwindow, int x, int y,
                    struct display_glyph_area *dga)
 {
-  struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
-  int elt; 
+  Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+  int elt;
   struct subwindow_cachel* cachel;
   struct frame* f;
 
@@ -4271,15 +4497,6 @@ void map_subwindow (Lisp_Object subwindow, int x, int y,
   cachel->height = dga->height;
   cachel->being_displayed = 1;
 
-  /* This forces any pending display changes to happen to the image
-     before we show it. I'm not sure whether or not we need mark as
-     clean here, but for now we will. */
-  if (IMAGE_INSTANCE_DIRTYP (ii))
-    {
-      update_subwindow (subwindow);
-      IMAGE_INSTANCE_DIRTYP (ii) = 0; 
-    }
-
   MAYBE_DEVMETH (XDEVICE (ii->device), map_subwindow, (ii, x, y, dga));
 }
 
@@ -4295,7 +4512,7 @@ subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
                       int dest_mask, Lisp_Object domain)
 {
-  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
   Lisp_Object frame = FW_FRAME (domain);
   Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width);
@@ -4303,7 +4520,7 @@ subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
 
   if (NILP (frame))
     signal_simple_error ("No selected frame", device);
-  
+
   if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
     incompatible_image_types (instantiator, dest_mask, IMAGE_SUBWINDOW_MASK);
 
@@ -4315,27 +4532,26 @@ subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
   /* #### This stuff may get overidden by the widget code and is
      actually really dumb now that we have dynamic geometry
      calculations. What should really happen is that the subwindow
-     should query its child for and appropriate geometry. */
-  if (NILP (width))
-    IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = 20;
-  else
+     should query its child for an appropriate geometry. */
+  if (INTP (width))
     {
       int w = 1;
-      CHECK_INT (width);
       if (XINT (width) > 1)
        w = XINT (width);
       IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = w;
     }
-  if (NILP (height))
-    IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = 20;
   else
+    IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = 20;
+
+  if (INTP (height))
     {
       int h = 1;
-      CHECK_INT (height);
       if (XINT (height) > 1)
        h = XINT (height);
       IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = h;
     }
+  else
+    IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = 20;
 }
 
 DEFUN ("subwindowp", Fsubwindowp, 1, 1, 0, /*
@@ -4363,23 +4579,26 @@ If a value is nil that parameter is not changed.
        (subwindow, width, height))
 {
   int neww, newh;
+  Lisp_Image_Instance* ii;
 
   CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
+  ii = XIMAGE_INSTANCE (subwindow);
 
   if (NILP (width))
-    neww = XIMAGE_INSTANCE_WIDTH (subwindow);
+    neww = IMAGE_INSTANCE_WIDTH (ii);
   else
     neww = XINT (width);
 
   if (NILP (height))
-    newh = XIMAGE_INSTANCE_HEIGHT (subwindow);
+    newh = IMAGE_INSTANCE_HEIGHT (ii);
   else
     newh = XINT (height);
 
   /* The actual resizing gets done asychronously by
      update_subwindow. */
-  XIMAGE_INSTANCE_HEIGHT (subwindow) = newh;
-  XIMAGE_INSTANCE_WIDTH (subwindow) = neww;
+  IMAGE_INSTANCE_HEIGHT (ii) = newh;
+  IMAGE_INSTANCE_WIDTH (ii) = neww;
+  IMAGE_INSTANCE_SIZE_CHANGED (ii) = 1;
 
   /* need to update the cachels as redisplay will not do this */
   update_subwindow_cachel (subwindow);
@@ -4498,10 +4717,10 @@ Don't use this.
   if (!NILP (XWEAK_LIST_LIST (arg)) && !NILP (XCAR (XWEAK_LIST_LIST (arg))))
     {
       Lisp_Object value = XCAR (XWEAK_LIST_LIST (arg));
-      
+
       if (IMAGE_INSTANCEP (value))
        {
-         struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (value);
+         Lisp_Image_Instance* ii = XIMAGE_INSTANCE (value);
 
          if (COLOR_PIXMAP_IMAGE_INSTANCEP (value)
              &&
@@ -4516,9 +4735,11 @@ Don't use this.
                % IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii);
              /* We might need to kick redisplay at this point - but we
                 also might not. */
-             MARK_DEVICE_FRAMES_GLYPHS_CHANGED 
+             MARK_DEVICE_FRAMES_GLYPHS_CHANGED
                (XDEVICE (IMAGE_INSTANCE_DEVICE (ii)));
-             MARK_IMAGE_INSTANCE_CHANGED (ii);
+             /* Cascade dirtiness so that we can have an animated glyph in a layout
+                for instance. */
+             set_image_instance_dirty_p (value, 1);
            }
        }
     }
@@ -4563,12 +4784,16 @@ void disable_glyph_animated_timeout (int i)
 void
 syms_of_glyphs (void)
 {
+  INIT_LRECORD_IMPLEMENTATION (glyph);
+  INIT_LRECORD_IMPLEMENTATION (image_instance);
+
   /* image instantiators */
 
   DEFSUBR (Fimage_instantiator_format_list);
   DEFSUBR (Fvalid_image_instantiator_format_p);
   DEFSUBR (Fset_console_type_image_conversion_list);
   DEFSUBR (Fconsole_type_image_conversion_list);
+  DEFSUBR (Fupdate_widget_instances);
 
   defkeyword (&Q_file, ":file");
   defkeyword (&Q_data, ":data");
@@ -4604,6 +4829,7 @@ syms_of_glyphs (void)
   defsymbol (&Qwidget_image_instance_p, "widget-image-instance-p");
   defsymbol (&Qsubwindow_image_instance_p, "subwindow-image-instance-p");
   defsymbol (&Qlayout_image_instance_p, "layout-image-instance-p");
+  defsymbol (&Qupdate_widget_instances, "update-widget-instances");
 
   DEFSUBR (Fmake_image_instance);
   DEFSUBR (Fimage_instance_p);
@@ -4676,7 +4902,8 @@ syms_of_glyphs (void)
 }
 
 static const struct lrecord_description image_specifier_description[] = {
-  { XD_LISP_OBJECT, specifier_data_offset + offsetof(struct image_specifier, attachee), 2 },
+  { XD_LISP_OBJECT, specifier_data_offset + offsetof (struct image_specifier, attachee) },
+  { XD_LISP_OBJECT, specifier_data_offset + offsetof (struct image_specifier, attachee_property) },
   { XD_END }
 };
 
@@ -4704,50 +4931,52 @@ reinit_specifier_type_create_image (void)
 
 
 static const struct lrecord_description iike_description_1[] = {
-  { XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword), 1 },
+  { XD_LISP_OBJECT, offsetof (ii_keyword_entry, keyword) },
   { XD_END }
 };
 
 static const struct struct_description iike_description = {
-  sizeof(ii_keyword_entry),
+  sizeof (ii_keyword_entry),
   iike_description_1
 };
 
 static const struct lrecord_description iiked_description_1[] = {
-  XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
+  XD_DYNARR_DESC (ii_keyword_entry_dynarr, &iike_description),
   { XD_END }
 };
 
 static const struct struct_description iiked_description = {
-  sizeof(ii_keyword_entry_dynarr),
+  sizeof (ii_keyword_entry_dynarr),
   iiked_description_1
 };
 
 static const struct lrecord_description iife_description_1[] = {
-  { XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol), 2 },
-  { XD_STRUCT_PTR,  offsetof(image_instantiator_format_entry, meths),  1, &iim_description },
+  { XD_LISP_OBJECT, offsetof (image_instantiator_format_entry, symbol) },
+  { XD_LISP_OBJECT, offsetof (image_instantiator_format_entry, device) },
+  { XD_STRUCT_PTR,  offsetof (image_instantiator_format_entry, meths),  1, &iim_description },
   { XD_END }
 };
 
 static const struct struct_description iife_description = {
-  sizeof(image_instantiator_format_entry),
+  sizeof (image_instantiator_format_entry),
   iife_description_1
 };
 
 static const struct lrecord_description iifed_description_1[] = {
-  XD_DYNARR_DESC(image_instantiator_format_entry_dynarr, &iife_description),
+  XD_DYNARR_DESC (image_instantiator_format_entry_dynarr, &iife_description),
   { XD_END }
 };
 
 static const struct struct_description iifed_description = {
-  sizeof(image_instantiator_format_entry_dynarr),
+  sizeof (image_instantiator_format_entry_dynarr),
   iifed_description_1
 };
 
 static const struct lrecord_description iim_description_1[] = {
-  { XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol), 2 },
-  { XD_STRUCT_PTR,  offsetof(struct image_instantiator_methods, keywords), 1, &iiked_description },
-  { XD_STRUCT_PTR,  offsetof(struct image_instantiator_methods, consoles), 1, &cted_description },
+  { XD_LISP_OBJECT, offsetof (struct image_instantiator_methods, symbol) },
+  { XD_LISP_OBJECT, offsetof (struct image_instantiator_methods, device) },
+  { XD_STRUCT_PTR,  offsetof (struct image_instantiator_methods, keywords), 1, &iiked_description },
+  { XD_STRUCT_PTR,  offsetof (struct image_instantiator_methods, consoles), 1, &cted_description },
   { XD_END }
 };
 
@@ -4874,8 +5103,8 @@ vars_of_glyphs (void)
 
   /* image instances */
 
-  Vimage_instance_type_list = Fcons (Qnothing, 
-                                    list6 (Qtext, Qmono_pixmap, Qcolor_pixmap, 
+  Vimage_instance_type_list = Fcons (Qnothing,
+                                    list6 (Qtext, Qmono_pixmap, Qcolor_pixmap,
                                            Qpointer, Qsubwindow, Qwidget));
   staticpro (&Vimage_instance_type_list);