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
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;
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;
}
/* 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
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;
}
(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),
}
}
+/* 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)
}
}
- /* 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;
/* 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;
}
/* 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;
}
/*
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;
/* 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));
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,
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));
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);
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);
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);
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);
}
}
+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
* 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)
{
* 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. */
{
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);
}
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));
}
(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);
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);
}
}
}
void
syms_of_glyphs (void)
{
+ INIT_LRECORD_IMPLEMENTATION (glyph);
+ INIT_LRECORD_IMPLEMENTATION (image_instance);
+
/* image instantiators */
DEFSUBR (Fimage_instantiator_format_list);