-
-\f
-/*****************************************************************************
- * subwindow cachel functions *
- *****************************************************************************/
-/* Subwindows are curious in that you have to physically unmap them to
- not display them. It is problematic deciding what to do in
- redisplay. We have two caches - a per-window instance cache that
- keeps track of subwindows on a window, these are linked to their
- instantiator in the hashtable and when the instantiator goes away
- we want the instance to go away also. However we also have a
- per-frame instance cache that we use to determine if a subwindow is
- obscuring an area that we want to clear. We need to be able to flip
- through this quickly so a hashtable is not suitable hence the
- subwindow_cachels. This is a weak list so unreference instances
- will get deleted properly. */
-
-/* redisplay in general assumes that drawing something will erase
- what was there before. unfortunately this does not apply to
- subwindows that need to be specifically unmapped in order to
- disappear. we take a brute force approach - on the basis that its
- cheap - and unmap all subwindows in a display line */
-
-/* Put new instances in the frame subwindow cache. This is less costly than
- doing it every time something gets mapped, and deleted instances will be
- removed automatically. */
-static void
-cache_subwindow_instance_in_frame_maybe (Lisp_Object instance)
-{
- Lisp_Image_Instance* ii = XIMAGE_INSTANCE (instance);
- if (!NILP (DOMAIN_FRAME (IMAGE_INSTANCE_DOMAIN (ii))))
- {
- struct frame* f = DOMAIN_XFRAME (IMAGE_INSTANCE_DOMAIN (ii));
- XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))
- = Fcons (instance, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)));
- }
-}
-
-/* Unmap and finalize all subwindow instances in the frame cache. This
- is necessary because GC will not guarantee the order things get
- deleted in and moreover, frame finalization deletes the window
- system windows before deleting XEmacs windows, and hence
- subwindows. */
-int
-unmap_subwindow_instance_cache_mapper (Lisp_Object key, Lisp_Object value,
- void* finalize)
-{
- /* value can be nil; we cache failures as well as successes */
- if (!NILP (value))
- {
- struct frame* f = XFRAME (XIMAGE_INSTANCE_FRAME (value));
- unmap_subwindow (value);
- if (finalize)
- {
- /* In case GC doesn't catch up fast enough, remove from the frame
- cache also. Otherwise code that checks the sanity of the instance
- will fail. */
- XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))
- = delq_no_quit (value,
- XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)));
- finalize_image_instance (XIMAGE_INSTANCE (value), 0);
- }
- }
- return 0;
-}
-
-static void
-finalize_all_subwindow_instances (struct window *w)
-{
- if (!NILP (w->next)) finalize_all_subwindow_instances (XWINDOW (w->next));
- if (!NILP (w->vchild)) finalize_all_subwindow_instances (XWINDOW (w->vchild));
- if (!NILP (w->hchild)) finalize_all_subwindow_instances (XWINDOW (w->hchild));
-
- elisp_maphash (unmap_subwindow_instance_cache_mapper,
- w->subwindow_instance_cache, (void*)1);
-}
-
-void
-free_frame_subwindow_instances (struct frame* f)
-{
- /* Make sure all instances are finalized. We have to do this via the
- instance cache since some instances may be extant but not
- displayed (and hence not in the frame cache). */
- finalize_all_subwindow_instances (XWINDOW (f->root_window));
-}
-
-/* Unmap all instances in the frame cache. */
-void
-reset_frame_subwindow_instance_cache (struct frame* f)
-{
- Lisp_Object rest;
-
- LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))
- {
- Lisp_Object value = XCAR (rest);
- unmap_subwindow (value);
- }
-}
-
-/*****************************************************************************
- * subwindow exposure ignorance *
- *****************************************************************************/
-/* when we unmap subwindows the associated window system will generate
- expose events. This we do not want as redisplay already copes with
- the repainting necessary. Worse, we can get in an endless cycle of
- redisplay if we are not careful. Thus we keep a per-frame list of
- expose events that are going to come and ignore them as
- required. */
-
-struct expose_ignore_blocktype
-{
- Blocktype_declare (struct expose_ignore);
-} *the_expose_ignore_blocktype;
-
-int
-check_for_ignored_expose (struct frame* f, int x, int y, int width, int height)
-{
- struct expose_ignore *ei, *prev;
- /* the ignore list is FIFO so we should generally get a match with
- the first element in the list */
- for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next)
- {
- /* Checking for exact matches just isn't good enough as we
- might get exposures for partially obscured subwindows, thus
- 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
- && ei->x + ei->width >= x + width
- && ei->y + ei->height >= y + height)
- {
-#ifdef DEBUG_WIDGETS
- stderr_out ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
- x, y, width, height, ei->x, ei->y, ei->width, ei->height);
-#endif
- if (!prev)
- f->subwindow_exposures = ei->next;
- else
- prev->next = ei->next;
-
- if (ei == f->subwindow_exposures_tail)
- f->subwindow_exposures_tail = prev;
-
- Blocktype_free (the_expose_ignore_blocktype, ei);
- return 1;
- }
- prev = ei;
- }
- return 0;
-}
-
-static void
-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. */
- if (f->subwindow_exposures_tail)
- {
- f->subwindow_exposures_tail->next = ei;
- }
- if (!f->subwindow_exposures)
- {
- f->subwindow_exposures = ei;
- }
- f->subwindow_exposures_tail = ei;
- }
-}
-
-/****************************************************************************
- find_matching_subwindow
-
- See if there is a subwindow that completely encloses the requested
- area.
- ****************************************************************************/
-int find_matching_subwindow (struct frame* f, int x, int y, int width, int height)
-{
- Lisp_Object rest;
-
- LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))
- {
- Lisp_Image_Instance *ii = XIMAGE_INSTANCE (XCAR (rest));
-
- if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii)
- &&
- IMAGE_INSTANCE_DISPLAY_X (ii) <= x
- &&
- IMAGE_INSTANCE_DISPLAY_Y (ii) <= y
- &&
- IMAGE_INSTANCE_DISPLAY_X (ii)
- + IMAGE_INSTANCE_DISPLAY_WIDTH (ii) >= x + width
- &&
- IMAGE_INSTANCE_DISPLAY_Y (ii)
- + IMAGE_INSTANCE_DISPLAY_HEIGHT (ii) >= y + height)
- {
- return 1;
- }
- }
- return 0;
-}
-
-\f
-/*****************************************************************************
- * 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;
-}
-