This commit was manufactured by cvs2svn to create branch 'XEmacs-21_4'.
[chise/xemacs-chise.git.1] / src / glyphs.c
index ce856cf..ad542b1 100644 (file)
@@ -128,6 +128,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
@@ -579,6 +580,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;
@@ -607,6 +609,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;
 }
 
@@ -814,6 +828,8 @@ 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
@@ -971,10 +987,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;
 }
 
@@ -1081,7 +1100,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),
@@ -1135,6 +1154,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)
@@ -1352,11 +1384,11 @@ the image instance in the domain.
        }
     }
 
-  /* Make sure the image instance gets redisplayed.
+  /* Make sure the image instance gets redisplayed. */
+  set_image_instance_dirty_p (image_instance, 1);
+  /* Force the glyph to be laid out again. */
+  IMAGE_INSTANCE_LAYOUT_CHANGED (ii) = 1;
 
-     ### This currently does not change the dirty state of an
-     enclosing layout which may be bad. */
-  MARK_IMAGE_INSTANCE_CHANGED (ii);
   MARK_SUBWINDOWS_STATE_CHANGED;
   MARK_GLYPHS_CHANGED;
 
@@ -1683,6 +1715,13 @@ 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;
 
@@ -1692,7 +1731,9 @@ image_instance_layout (Lisp_Object image_instance,
     }
   /* else no change to the geometry. */
 
-  XIMAGE_INSTANCE_DIRTYP (image_instance) = 0;
+  /* Do not clear the dirty flag here - redisplay will do this for
+     us at the end. */
+  IMAGE_INSTANCE_LAYOUT_CHANGED (ii) = 0;
 }
 
 /*
@@ -1717,7 +1758,9 @@ invalidate_glyph_geometry_maybe (Lisp_Object glyph_or_ii, struct window* w)
 
       if (TEXT_IMAGE_INSTANCEP (image))
        {
-         XIMAGE_INSTANCE_DIRTYP (image) = 1;
+         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;
@@ -1732,14 +1775,14 @@ invalidate_glyph_geometry_maybe (Lisp_Object glyph_or_ii, struct window* w)
 /*                              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));
@@ -2162,7 +2205,7 @@ 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;
 
   TO_EXTERNAL_FORMAT (LISP_STRING, name,
                      C_STRING_ALLOCA, filename_ext,
@@ -2641,7 +2684,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));
@@ -3556,7 +3606,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);
 
@@ -3584,7 +3634,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);
 
@@ -3602,7 +3652,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);
 
@@ -3622,7 +3672,7 @@ glyph_height (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);
 
@@ -3687,6 +3737,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
@@ -3773,11 +3839,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)
 {
@@ -4194,24 +4266,48 @@ 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. The only other time it gets called is if subwindow state
+   changed, when we can't actually tell whether its going to be dirty
+   or not. 
+   #### I suspect what we should really do is re-evaluate all the
+   gui slots that could affect this and then mark the instance as
+   dirty. Right now, updating everything is safe but expensive. */
+void
 update_subwindow (Lisp_Object subwindow)
 {
   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+  int count = specpdl_depth ();
+
+  /* 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
+  if (IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
       ||
-      NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
-    return;
+      IMAGE_INSTANCE_TYPE (ii) == IMAGE_LAYOUT)
+    {
+      if (IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET)
+       update_widget (subwindow);
+      /* Reset the changed flags. */
+      IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii) = 0;
+      IMAGE_INSTANCE_WIDGET_PERCENT_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;
 
-  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);
 }
 
 /* Update all the subwindows on a frame. */
@@ -4220,13 +4316,21 @@ update_frame_subwindows (struct frame *f)
 {
   int elt;
 
+  /* #### Checking all of these might be overkill now that we update
+     subwindows in the actual redisplay code. */
   if (f->subwindows_changed || f->subwindows_state_changed || f->faces_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
+           &&
+           /* We only want to update if something has really
+               changed. */
+           (f->subwindows_state_changed
+            ||
+            XIMAGE_INSTANCE_DIRTYP (cachel->subwindow)))
          {
            update_subwindow (cachel->subwindow);
          }
@@ -4295,15 +4399,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));
 }
 
@@ -4387,23 +4482,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);
@@ -4542,7 +4640,9 @@ Don't use this.
                 also might not. */
              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);
            }
        }
     }
@@ -4587,6 +4687,9 @@ 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);