+ * subwindow functions *
+ *****************************************************************************/
+
+/* Update the displayed characteristics of a subwindow. This function
+ should generally only get called if the subwindow is actually
+ dirty. */
+void
+redisplay_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);
+
+ ERROR_CHECK_IMAGE_INSTANCE (subwindow);
+
+ if (WIDGET_IMAGE_INSTANCEP (subwindow))
+ {
+ if (image_instance_changed (subwindow))
+ redisplay_widget (subwindow);
+ /* Reset the changed flags. */
+ IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii) = 0;
+ IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0;
+ IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii) = 0;
+ IMAGE_INSTANCE_TEXT_CHANGED (ii) = 0;
+ }
+ else if (IMAGE_INSTANCE_TYPE (ii) == IMAGE_SUBWINDOW
+ &&
+ !NILP (IMAGE_INSTANCE_FRAME (ii)))
+ {
+ MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain),
+ redisplay_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);
+
+ unbind_to (count, Qnil);
+}
+
+/* Determine whether an image_instance has changed structurally and
+ hence needs redisplaying in some way.
+
+ #### This should just look at the instantiator differences when we
+ get rid of the stored items altogether. In fact we should probably
+ store the new instantiator as well as the old - as we do with
+ gui_items currently - and then pick-up the new on the next
+ redisplay. This would obviate the need for any of this trickery
+ with hashcodes. */
+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;
+ /* #### I think there is probably a bug here. This gets called for
+ layouts - and yet the pending items are always nil for
+ layouts. We are saved by layout optimization, but I'm undecided
+ as to what the correct fix is. */
+ else if (WIDGET_IMAGE_INSTANCEP (subwindow)
+ && (!internal_equal (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
+ IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii), 0)
+ || !NILP (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))
+ || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii)))
+ return 1;
+ else
+ return 0;
+}
+
+/* Update all the subwindows on a frame. */
+void
+update_widget_instances (Lisp_Object frame)
+{
+ struct frame* f;
+ Lisp_Object rest;
+
+ /* Its possible for the preceding callback to have deleted the
+ frame, so cope with this. */
+ if (!FRAMEP (frame) || !FRAME_LIVE_P (XFRAME (frame)))
+ return;
+
+ CHECK_FRAME (frame);
+ f = XFRAME (frame);
+
+ /* If we get called we know something has changed. */
+ LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))
+ {
+ Lisp_Object widget = XCAR (rest);
+
+ if (XIMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (widget)
+ &&
+ image_instance_changed (widget))
+ {
+ set_image_instance_dirty_p (widget, 1);
+ MARK_FRAME_GLYPHS_CHANGED (f);
+ }
+ }
+}
+
+/* remove a subwindow from its frame */
+void unmap_subwindow (Lisp_Object subwindow)
+{
+ Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+ struct frame* f;
+
+ ERROR_CHECK_IMAGE_INSTANCE (subwindow);
+
+ if (!image_instance_type_to_mask (IMAGE_INSTANCE_TYPE (ii))
+ & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK)
+ ||
+ !IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii))
+ return;
+
+#ifdef DEBUG_WIDGETS
+ stderr_out ("unmapping subwindow %p\n", IMAGE_INSTANCE_SUBWINDOW_ID (ii));
+#endif
+ f = XFRAME (IMAGE_INSTANCE_FRAME (ii));
+
+ /* make sure we don't get expose events */
+ register_ignored_expose (f, IMAGE_INSTANCE_DISPLAY_X (ii),
+ IMAGE_INSTANCE_DISPLAY_Y (ii),
+ IMAGE_INSTANCE_DISPLAY_WIDTH (ii),
+ IMAGE_INSTANCE_DISPLAY_HEIGHT (ii));
+ IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
+
+ MAYBE_DEVMETH (XDEVICE (IMAGE_INSTANCE_DEVICE (ii)),
+ unmap_subwindow, (ii));
+}
+
+/* show a subwindow in its frame */
+void map_subwindow (Lisp_Object subwindow, int x, int y,
+ struct display_glyph_area *dga)
+{
+ Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
+ struct frame* f;
+
+ ERROR_CHECK_IMAGE_INSTANCE (subwindow);
+
+ if (!image_instance_type_to_mask (IMAGE_INSTANCE_TYPE (ii))
+ & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK))
+ return;
+
+#ifdef DEBUG_WIDGETS
+ stderr_out ("mapping subwindow %p, %dx%d@%d+%d\n",
+ IMAGE_INSTANCE_SUBWINDOW_ID (ii),
+ dga->width, dga->height, x, y);
+#endif
+ f = XFRAME (IMAGE_INSTANCE_FRAME (ii));
+ IMAGE_INSTANCE_DISPLAY_X (ii) = x;
+ IMAGE_INSTANCE_DISPLAY_Y (ii) = y;
+ IMAGE_INSTANCE_DISPLAY_WIDTH (ii) = dga->width;
+ IMAGE_INSTANCE_DISPLAY_HEIGHT (ii) = dga->height;
+
+ MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain),
+ map_subwindow, (ii, x, y, dga));
+ IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 1;
+}
+
+static int
+subwindow_possible_dest_types (void)
+{
+ return IMAGE_SUBWINDOW_MASK;
+}
+
+int
+subwindow_governing_domain (void)
+{
+ return GOVERNING_DOMAIN_WINDOW;
+}
+
+/* Partially instantiate a subwindow. */
+void
+subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object device = image_instance_device (image_instance);
+ Lisp_Object frame = DOMAIN_FRAME (domain);
+ Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width);
+ Lisp_Object height = find_keyword_in_vector (instantiator, Q_pixel_height);
+
+ 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);
+
+ ii->data = 0;
+ IMAGE_INSTANCE_SUBWINDOW_ID (ii) = 0;
+ IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
+
+ if (INTP (width))
+ {
+ int w = 1;
+ if (XINT (width) > 1)
+ w = XINT (width);
+ IMAGE_INSTANCE_WIDTH (ii) = w;
+ IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
+ }
+
+ if (INTP (height))
+ {
+ int h = 1;
+ if (XINT (height) > 1)
+ h = XINT (height);
+ IMAGE_INSTANCE_HEIGHT (ii) = h;
+ IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
+ }
+}
+
+/* This is just a backup in case no-one has assigned a suitable geometry.
+ #### It should really query the enclose window for geometry. */
+static void
+subwindow_query_geometry (Lisp_Object image_instance, int* width,
+ int* height, enum image_instance_geometry disp,
+ Lisp_Object domain)
+{
+ if (width) *width = 20;
+ if (height) *height = 20;
+}
+
+DEFUN ("subwindowp", Fsubwindowp, 1, 1, 0, /*
+Return non-nil if OBJECT is a subwindow.
+*/
+ (object))
+{
+ CHECK_IMAGE_INSTANCE (object);
+ return (XIMAGE_INSTANCE_TYPE (object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
+}
+
+DEFUN ("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
+Return the window id of SUBWINDOW as a number.
+*/
+ (subwindow))
+{
+ CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
+ return make_int ((EMACS_INT) XIMAGE_INSTANCE_SUBWINDOW_ID (subwindow));
+}
+
+DEFUN ("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
+Resize SUBWINDOW to WIDTH x HEIGHT.
+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 = IMAGE_INSTANCE_WIDTH (ii);
+ else
+ neww = XINT (width);
+
+ if (NILP (height))
+ newh = IMAGE_INSTANCE_HEIGHT (ii);
+ else
+ newh = XINT (height);
+
+ /* The actual resizing gets done asynchronously by
+ update_subwindow. */
+ IMAGE_INSTANCE_HEIGHT (ii) = newh;
+ IMAGE_INSTANCE_WIDTH (ii) = neww;
+ IMAGE_INSTANCE_SIZE_CHANGED (ii) = 1;
+
+ return subwindow;
+}
+
+DEFUN ("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
+Generate a Map event for SUBWINDOW.
+*/
+ (subwindow))
+{
+ CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
+#if 0
+ map_subwindow (subwindow, 0, 0);
+#endif
+ return subwindow;
+}
+
+\f
+/*****************************************************************************
+ * display tables *
+ *****************************************************************************/
+
+/* Get the display tables for use currently on window W with face
+ FACE. #### This will have to be redone. */
+
+void
+get_display_tables (struct window *w, face_index findex,
+ Lisp_Object *face_table, Lisp_Object *window_table)
+{
+ Lisp_Object tem;
+ tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE (w, findex);
+ if (UNBOUNDP (tem))
+ tem = Qnil;
+ if (!LISTP (tem))
+ tem = noseeum_cons (tem, Qnil);
+ *face_table = tem;
+ tem = w->display_table;
+ if (UNBOUNDP (tem))
+ tem = Qnil;
+ if (!LISTP (tem))
+ tem = noseeum_cons (tem, Qnil);
+ *window_table = tem;
+}
+
+Lisp_Object
+display_table_entry (Emchar ch, Lisp_Object face_table,
+ Lisp_Object window_table)
+{
+ Lisp_Object tail;
+
+ /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
+ for (tail = face_table; 1; tail = XCDR (tail))
+ {
+ Lisp_Object table;
+ if (NILP (tail))
+ {
+ if (!NILP (window_table))
+ {
+ tail = window_table;
+ window_table = Qnil;
+ }
+ else
+ return Qnil;
+ }
+ table = XCAR (tail);
+
+ if (VECTORP (table))
+ {
+ if (ch < XVECTOR_LENGTH (table) && !NILP (XVECTOR_DATA (table)[ch]))
+ return XVECTOR_DATA (table)[ch];
+ else
+ continue;
+ }
+ else if (CHAR_TABLEP (table)
+ && XCHAR_TABLE_TYPE (table) == CHAR_TABLE_TYPE_CHAR)
+ {
+ return get_char_table (ch, XCHAR_TABLE (table));
+ }
+ else if (CHAR_TABLEP (table)
+ && XCHAR_TABLE_TYPE (table) == CHAR_TABLE_TYPE_GENERIC)
+ {
+ Lisp_Object gotit = get_char_table (ch, XCHAR_TABLE (table));
+ if (!NILP (gotit))
+ return gotit;
+ else
+ continue;
+ }
+ else if (RANGE_TABLEP (table))
+ {
+ Lisp_Object gotit = Fget_range_table (make_char (ch), table, Qnil);
+ if (!NILP (gotit))
+ return gotit;
+ else
+ continue;
+ }
+ else
+ abort ();
+ }
+}
+
+/*****************************************************************************
+ * timeouts for animated glyphs *
+ *****************************************************************************/
+static Lisp_Object Qglyph_animated_timeout_handler;
+
+DEFUN ("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
+Callback function for updating animated images.
+Don't use this.
+*/
+ (arg))
+{
+ CHECK_WEAK_LIST (arg);
+
+ if (!NILP (XWEAK_LIST_LIST (arg)) && !NILP (XCAR (XWEAK_LIST_LIST (arg))))
+ {
+ Lisp_Object value = XCAR (XWEAK_LIST_LIST (arg));
+
+ if (IMAGE_INSTANCEP (value))
+ {
+ Lisp_Image_Instance* ii = XIMAGE_INSTANCE (value);
+
+ if (COLOR_PIXMAP_IMAGE_INSTANCEP (value)
+ &&
+ IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) > 1
+ &&
+ !disable_animated_pixmaps)
+ {
+ /* Increment the index of the image slice we are currently
+ viewing. */
+ IMAGE_INSTANCE_PIXMAP_SLICE (ii) =
+ (IMAGE_INSTANCE_PIXMAP_SLICE (ii) + 1)
+ % IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii);
+ /* We might need to kick redisplay at this point - but we
+ also might not. */
+ MARK_DEVICE_FRAMES_GLYPHS_CHANGED
+ (XDEVICE (image_instance_device (value)));
+ /* Cascade dirtiness so that we can have an animated glyph in a layout
+ for instance. */
+ set_image_instance_dirty_p (value, 1);
+ }
+ }
+ }
+ return Qnil;
+}
+
+Lisp_Object add_glyph_animated_timeout (EMACS_INT tickms, Lisp_Object image)
+{
+ Lisp_Object ret = Qnil;
+
+ if (tickms > 0 && IMAGE_INSTANCEP (image))
+ {
+ double ms = ((double)tickms) / 1000.0;
+ struct gcpro gcpro1;
+ Lisp_Object holder = make_weak_list (WEAK_LIST_SIMPLE);
+
+ GCPRO1 (holder);
+ XWEAK_LIST_LIST (holder) = Fcons (image, Qnil);
+
+ ret = Fadd_timeout (make_float (ms),
+ Qglyph_animated_timeout_handler,
+ holder, make_float (ms));
+
+ UNGCPRO;
+ }
+ return ret;
+}
+
+void disable_glyph_animated_timeout (int i)
+{
+ Lisp_Object id;
+ XSETINT (id, i);
+
+ Fdisable_timeout (id);
+}
+
+\f
+/*****************************************************************************