Add gdk_window_set_invalidate_handler

This lets you register callbacks for when child widgets invalidate
areas of the window read it and/or change it.

For instance, this lets you do rendering effects and keeping offscreen
caches uptodate.
This commit is contained in:
Alexander Larsson 2013-04-21 01:27:07 +02:00
parent 590366f0e7
commit e13fb1d3e0
3 changed files with 70 additions and 14 deletions

View File

@ -266,6 +266,7 @@ struct _GdkWindow
guint num_offscreen_children;
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
GdkWindowInvalidateHandlerFunc invalidate_handler;
};
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)

View File

@ -3647,6 +3647,30 @@ gdk_window_invalidate_rect (GdkWindow *window,
gdk_window_invalidate_rect_full (window, rect, invalidate_children);
}
/**
* gdk_window_set_invalidate_handler:
* @window: a #GdkWindow
* @handler: a #GdkWindowInvalidateHandlerFunc callback function
*
* Registers an invalidate handler for a specific window. This
* will get called whenever a region in the window or its children
* is invalidated.
*
* This can be used to record the invalidated region, which is
* useful if you are keeping an offscreen copy of some region
* and want to keep it up to date. You can also modify the
* invalidated region in case you're doing some effect where
* e.g. a child widget appears in multiple places.
*
* Since: 3.10
**/
void
gdk_window_set_invalidate_handler (GdkWindow *window,
GdkWindowInvalidateHandlerFunc handler)
{
window->invalidate_handler = handler;
}
static void
draw_ugly_color (GdkWindow *window,
const cairo_region_t *region)
@ -3734,8 +3758,8 @@ gdk_window_invalidate_maybe_recurse_full (GdkWindow *window,
GdkWindowChildFunc child_func,
gpointer user_data)
{
GdkWindow *impl_window;
cairo_region_t *visible_region;
cairo_rectangle_int_t r;
g_return_if_fail (GDK_IS_WINDOW (window));
@ -3748,26 +3772,37 @@ gdk_window_invalidate_maybe_recurse_full (GdkWindow *window,
window->window_type == GDK_WINDOW_ROOT)
return;
visible_region = gdk_window_get_visible_region (window);
cairo_region_intersect (visible_region, region);
r.x = 0;
r.y = 0;
visible_region = cairo_region_copy (region);
invalidate_impl_subwindows (window, region, child_func, user_data, 0, 0);
impl_window = gdk_window_get_impl_window (window);
if (!cairo_region_is_empty (visible_region))
{
if (debug_updates)
draw_ugly_color (window, visible_region);
/* Convert to impl coords */
cairo_region_translate (visible_region, window->abs_x, window->abs_y);
while (window != NULL &&
!cairo_region_is_empty (visible_region))
{
if (window->invalidate_handler)
window->invalidate_handler (window, visible_region);
/* Only invalidate area if app requested expose events or if
we need to clear the area (by request or to emulate background
clearing for non-native windows or native windows with no support
for window backgrounds */
impl_window_add_update_area (impl_window, visible_region);
r.width = window->width;
r.height = window->height;
cairo_region_intersect_rectangle (visible_region, &r);
if (gdk_window_has_impl (window))
{
impl_window_add_update_area (window, visible_region);
break;
}
else
{
cairo_region_translate (visible_region,
window->x, window->y);
window = window->parent;
}
}
cairo_region_destroy (visible_region);

View File

@ -679,6 +679,26 @@ gboolean gdk_window_set_static_gravities (GdkWindow *window,
/* GdkWindow */
/**
* GdkWindowInvalidateHandlerFunc:
* @window: a #GdkWindow
* @region: a #cairo_region_t
*
* Whenever some area of the window is invalidated (directly in the
* window or in a child window) this gets called with @region in
* the coordinate space of @window. You can use @region to just
* keep track of the dirty region, or you can actually change
* @region in case you are doing display tricks like showing
* a child in multiple places.
*
* Since: 3.10
*/
typedef void (*GdkWindowInvalidateHandlerFunc) (GdkWindow *window,
cairo_region_t *region);
GDK_AVAILABLE_IN_3_10
void gdk_window_set_invalidate_handler (GdkWindow *window,
GdkWindowInvalidateHandlerFunc handler);
GDK_AVAILABLE_IN_ALL
gboolean gdk_window_has_native (GdkWindow *window);
GDK_AVAILABLE_IN_ALL