gdkwindow: Remove the ability to call begin_paint_region more than once
Previously, each begin_paint_region added to a stack of current paints, and when end_paint was called, the paint was popped off of the stack and the surface was composited into the parent paint surface. However, the code was broken in the case of a backend like Wayland which didn't keep track of nested calls and simply wiped and returned the native impl backing surface every time. Since this feature is flat out unused by GTK+ and we don't want to really support tricksy things like these for other clients, just remove the feature. If somebody does call begin_paint_region more than once, warn and return without doing anything.
This commit is contained in:
@@ -205,7 +205,11 @@ struct _GdkWindow
|
||||
|
||||
cairo_pattern_t *background;
|
||||
|
||||
GSList *paint_stack;
|
||||
struct {
|
||||
cairo_region_t *region;
|
||||
cairo_surface_t *surface;
|
||||
gboolean surface_needs_composite;
|
||||
} current_paint;
|
||||
|
||||
cairo_region_t *update_area;
|
||||
guint update_freeze_count;
|
||||
|
||||
180
gdk/gdkwindow.c
180
gdk/gdkwindow.c
@@ -147,17 +147,8 @@ enum {
|
||||
PROP_CURSOR
|
||||
};
|
||||
|
||||
struct _GdkWindowPaint
|
||||
{
|
||||
cairo_region_t *region;
|
||||
cairo_surface_t *surface;
|
||||
gboolean surface_needs_composite;
|
||||
};
|
||||
|
||||
/* Global info */
|
||||
|
||||
static void gdk_window_free_paint_stack (GdkWindow *window);
|
||||
|
||||
static void gdk_window_finalize (GObject *object);
|
||||
|
||||
static void gdk_window_set_property (GObject *object,
|
||||
@@ -1826,6 +1817,18 @@ window_remove_from_pointer_info (GdkWindow *window,
|
||||
window);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_free_current_paint (GdkWindow *window)
|
||||
{
|
||||
cairo_surface_destroy (window->current_paint.surface);
|
||||
window->current_paint.surface = NULL;
|
||||
|
||||
cairo_region_destroy (window->current_paint.region);
|
||||
window->current_paint.region = NULL;
|
||||
|
||||
window->current_paint.surface_needs_composite = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* _gdk_window_destroy_hierarchy:
|
||||
* @window: a #GdkWindow
|
||||
@@ -1930,7 +1933,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
||||
gdk_window_set_frame_clock (window, NULL);
|
||||
}
|
||||
|
||||
gdk_window_free_paint_stack (window);
|
||||
gdk_window_free_current_paint (window);
|
||||
|
||||
if (window->background)
|
||||
{
|
||||
@@ -2722,8 +2725,6 @@ gdk_window_begin_paint_region (GdkWindow *window,
|
||||
{
|
||||
GdkRectangle clip_box;
|
||||
GdkWindowImplClass *impl_class;
|
||||
GdkWindowPaint *paint;
|
||||
GSList *list;
|
||||
double sx, sy;
|
||||
gboolean needs_surface;
|
||||
|
||||
@@ -2733,66 +2734,46 @@ gdk_window_begin_paint_region (GdkWindow *window,
|
||||
!gdk_window_has_impl (window))
|
||||
return;
|
||||
|
||||
if (window->current_paint.surface != NULL)
|
||||
{
|
||||
g_warning ("gdk_window_begin_paint_region called while a paint was "
|
||||
"alredy in progress. This is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
|
||||
|
||||
needs_surface = TRUE;
|
||||
if (impl_class->begin_paint_region)
|
||||
needs_surface = impl_class->begin_paint_region (window, region);
|
||||
|
||||
paint = g_new0 (GdkWindowPaint, 1);
|
||||
paint->region = cairo_region_copy (region);
|
||||
window->current_paint.region = cairo_region_copy (region);
|
||||
|
||||
cairo_region_intersect (paint->region, window->clip_region);
|
||||
cairo_region_get_extents (paint->region, &clip_box);
|
||||
cairo_region_intersect (window->current_paint.region, window->clip_region);
|
||||
cairo_region_get_extents (window->current_paint.region, &clip_box);
|
||||
|
||||
if (needs_surface)
|
||||
{
|
||||
paint->surface = gdk_window_create_similar_surface (window,
|
||||
gdk_window_get_content (window),
|
||||
MAX (clip_box.width, 1),
|
||||
MAX (clip_box.height, 1));
|
||||
window->current_paint.surface = gdk_window_create_similar_surface (window,
|
||||
gdk_window_get_content (window),
|
||||
MAX (clip_box.width, 1),
|
||||
MAX (clip_box.height, 1));
|
||||
sx = sy = 1;
|
||||
#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
|
||||
cairo_surface_get_device_scale (paint->surface, &sx, &sy);
|
||||
cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
|
||||
#endif
|
||||
cairo_surface_set_device_offset (paint->surface, -clip_box.x*sx, -clip_box.y*sy);
|
||||
cairo_surface_set_device_offset (window->current_paint.surface, -clip_box.x*sx, -clip_box.y*sy);
|
||||
|
||||
paint->surface_needs_composite = TRUE;
|
||||
window->current_paint.surface_needs_composite = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
paint->surface = gdk_window_ref_impl_surface (window);
|
||||
window->current_paint.surface = gdk_window_ref_impl_surface (window);
|
||||
window->current_paint.surface_needs_composite = FALSE;
|
||||
}
|
||||
|
||||
for (list = window->paint_stack; list != NULL; list = list->next)
|
||||
{
|
||||
GdkWindowPaint *tmp_paint = list->data;
|
||||
|
||||
cairo_region_subtract (tmp_paint->region, paint->region);
|
||||
}
|
||||
|
||||
window->paint_stack = g_slist_prepend (window->paint_stack, paint);
|
||||
|
||||
if (!cairo_region_is_empty (paint->region))
|
||||
gdk_window_clear_backing_region (window,
|
||||
paint->region);
|
||||
}
|
||||
|
||||
/* This returns either the current working surface on the paint stack
|
||||
* or the actual impl surface of the window. This should not be used
|
||||
* from very many places: be careful! */
|
||||
static cairo_surface_t *
|
||||
get_window_surface (GdkWindow *window)
|
||||
{
|
||||
if (window->impl_window->paint_stack)
|
||||
{
|
||||
GdkWindowPaint *paint = window->impl_window->paint_stack->data;
|
||||
return cairo_surface_reference (paint->surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
return gdk_window_ref_impl_surface (window);
|
||||
}
|
||||
if (!cairo_region_is_empty (window->current_paint.region))
|
||||
gdk_window_clear_backing_region (window, window->current_paint.region);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2812,7 +2793,6 @@ void
|
||||
gdk_window_end_paint (GdkWindow *window)
|
||||
{
|
||||
GdkWindow *composited;
|
||||
GdkWindowPaint *paint;
|
||||
GdkWindowImplClass *impl_class;
|
||||
GdkRectangle clip_box = { 0, };
|
||||
cairo_region_t *full_clip;
|
||||
@@ -2824,7 +2804,7 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
!gdk_window_has_impl (window))
|
||||
return;
|
||||
|
||||
if (window->paint_stack == NULL)
|
||||
if (window->current_paint.surface == NULL)
|
||||
{
|
||||
g_warning (G_STRLOC": no preceding call to gdk_window_begin_paint_region(), see documentation");
|
||||
return;
|
||||
@@ -2835,24 +2815,19 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
if (impl_class->end_paint)
|
||||
impl_class->end_paint (window);
|
||||
|
||||
paint = window->paint_stack->data;
|
||||
|
||||
window->paint_stack = g_slist_delete_link (window->paint_stack,
|
||||
window->paint_stack);
|
||||
|
||||
if (paint->surface_needs_composite)
|
||||
if (window->current_paint.surface_needs_composite)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
cairo_region_get_extents (paint->region, &clip_box);
|
||||
cairo_region_get_extents (window->current_paint.region, &clip_box);
|
||||
full_clip = cairo_region_copy (window->clip_region);
|
||||
cairo_region_intersect (full_clip, paint->region);
|
||||
cairo_region_intersect (full_clip, window->current_paint.region);
|
||||
|
||||
surface = get_window_surface (window);
|
||||
surface = gdk_window_ref_impl_surface (window);
|
||||
cr = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_set_source_surface (cr, paint->surface, 0, 0);
|
||||
cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
|
||||
gdk_cairo_region (cr, full_clip);
|
||||
cairo_clip (cr);
|
||||
if (gdk_window_has_impl (window) ||
|
||||
@@ -2871,10 +2846,7 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
cairo_region_destroy (full_clip);
|
||||
}
|
||||
|
||||
cairo_surface_destroy (paint->surface);
|
||||
|
||||
cairo_region_destroy (paint->region);
|
||||
g_free (paint);
|
||||
gdk_window_free_current_paint (window);
|
||||
|
||||
/* find a composited window in our hierarchy to signal its
|
||||
* parent to redraw, calculating the clip box as we go...
|
||||
@@ -2900,31 +2872,6 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_free_paint_stack (GdkWindow *window)
|
||||
{
|
||||
if (window->paint_stack)
|
||||
{
|
||||
GSList *tmp_list = window->paint_stack;
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
GdkWindowPaint *paint = tmp_list->data;
|
||||
|
||||
if (tmp_list == window->paint_stack)
|
||||
cairo_surface_destroy (paint->surface);
|
||||
|
||||
cairo_region_destroy (paint->region);
|
||||
g_free (paint);
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
g_slist_free (window->paint_stack);
|
||||
window->paint_stack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_window_flush:
|
||||
* @window: a #GdkWindow
|
||||
@@ -2962,23 +2909,8 @@ gdk_window_get_clip_region (GdkWindow *window)
|
||||
|
||||
result = cairo_region_copy (window->clip_region);
|
||||
|
||||
if (window->paint_stack)
|
||||
{
|
||||
cairo_region_t *paint_region = cairo_region_create ();
|
||||
GSList *tmp_list = window->paint_stack;
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
GdkWindowPaint *paint = tmp_list->data;
|
||||
|
||||
cairo_region_union (paint_region, paint->region);
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
cairo_region_intersect (result, paint_region);
|
||||
cairo_region_destroy (paint_region);
|
||||
}
|
||||
if (window->current_paint.region != NULL)
|
||||
cairo_region_intersect (result, window->current_paint.region);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -3007,7 +2939,6 @@ static void
|
||||
gdk_window_clear_backing_region (GdkWindow *window,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GdkWindowPaint *paint = window->paint_stack->data;
|
||||
cairo_region_t *clip;
|
||||
GdkWindow *bg_window;
|
||||
cairo_pattern_t *pattern = NULL;
|
||||
@@ -3017,7 +2948,7 @@ gdk_window_clear_backing_region (GdkWindow *window,
|
||||
if (GDK_WINDOW_DESTROYED (window))
|
||||
return;
|
||||
|
||||
cr = cairo_create (paint->surface);
|
||||
cr = cairo_create (window->current_paint.surface);
|
||||
|
||||
for (bg_window = window; bg_window; bg_window = bg_window->parent)
|
||||
{
|
||||
@@ -3038,7 +2969,7 @@ gdk_window_clear_backing_region (GdkWindow *window,
|
||||
else
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
clip = cairo_region_copy (paint->region);
|
||||
clip = cairo_region_copy (window->current_paint.region);
|
||||
cairo_region_intersect (clip, region);
|
||||
|
||||
gdk_cairo_region (cr, clip);
|
||||
@@ -3049,6 +2980,18 @@ gdk_window_clear_backing_region (GdkWindow *window,
|
||||
cairo_region_destroy (clip);
|
||||
}
|
||||
|
||||
/* This returns either the current working surface on the paint stack
|
||||
* or the actual impl surface of the window. This should not be used
|
||||
* from very many places: be careful! */
|
||||
static cairo_surface_t *
|
||||
get_window_surface (GdkWindow *window)
|
||||
{
|
||||
if (window->impl_window->current_paint.surface)
|
||||
return cairo_surface_reference (window->impl_window->current_paint.surface);
|
||||
else
|
||||
return gdk_window_ref_impl_surface (window);
|
||||
}
|
||||
|
||||
/* This is used in places like gdk_cairo_set_source_window and
|
||||
* other places to take "screenshots" of windows. Thus, we allow
|
||||
* it to be used outside of a begin_paint / end_paint. */
|
||||
@@ -3085,13 +3028,12 @@ _gdk_window_ref_cairo_surface (GdkWindow *window)
|
||||
cairo_t *
|
||||
gdk_cairo_create (GdkWindow *window)
|
||||
{
|
||||
GdkWindowPaint *paint;
|
||||
cairo_region_t *region;
|
||||
cairo_t *cr;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
|
||||
|
||||
if (window->impl_window->paint_stack == NULL)
|
||||
if (window->impl_window->current_paint.surface == NULL)
|
||||
{
|
||||
cairo_surface_t *dummy_surface;
|
||||
cairo_t *cr;
|
||||
@@ -3106,10 +3048,8 @@ gdk_cairo_create (GdkWindow *window)
|
||||
return cr;
|
||||
}
|
||||
|
||||
paint = window->impl_window->paint_stack->data;
|
||||
|
||||
cr = cairo_create (paint->surface);
|
||||
region = cairo_region_copy (paint->region);
|
||||
cr = cairo_create (window->impl_window->current_paint.surface);
|
||||
region = cairo_region_copy (window->impl_window->current_paint.region);
|
||||
cairo_region_translate (region, -window->abs_x, -window->abs_y);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_region_destroy (region);
|
||||
|
||||
@@ -137,37 +137,6 @@ gdk_window_impl_quartz_get_context (GdkWindowImplQuartz *window_impl,
|
||||
CGContextSaveGState (cg_context);
|
||||
CGContextSetAllowsAntialiasing (cg_context, antialias);
|
||||
|
||||
/* We'll emulate the clipping caused by double buffering here */
|
||||
if (window_impl->begin_paint_count != 0)
|
||||
{
|
||||
CGRect rect;
|
||||
CGRect *cg_rects;
|
||||
gint n_rects, i;
|
||||
|
||||
n_rects = cairo_region_num_rectangles (window_impl->paint_clip_region);
|
||||
|
||||
if (n_rects == 1)
|
||||
cg_rects = ▭
|
||||
else
|
||||
cg_rects = g_new (CGRect, n_rects);
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t cairo_rect;
|
||||
cairo_region_get_rectangle (window_impl->paint_clip_region,
|
||||
i, &cairo_rect);
|
||||
cg_rects[i].origin.x = cairo_rect.x;
|
||||
cg_rects[i].origin.y = cairo_rect.y;
|
||||
cg_rects[i].size.width = cairo_rect.width;
|
||||
cg_rects[i].size.height = cairo_rect.height;
|
||||
}
|
||||
|
||||
CGContextClipToRects (cg_context, cg_rects, n_rects);
|
||||
|
||||
if (cg_rects != &rect)
|
||||
g_free (cg_rects);
|
||||
}
|
||||
|
||||
return cg_context;
|
||||
}
|
||||
|
||||
@@ -379,12 +348,7 @@ gdk_window_impl_quartz_begin_paint_region (GdkWindow *window,
|
||||
cairo_region_translate (clipped_and_offset_region,
|
||||
window->abs_x, window->abs_y);
|
||||
|
||||
if (impl->begin_paint_count == 0)
|
||||
impl->paint_clip_region = cairo_region_reference (clipped_and_offset_region);
|
||||
else
|
||||
cairo_region_union (impl->paint_clip_region, clipped_and_offset_region);
|
||||
|
||||
impl->begin_paint_count++;
|
||||
impl->paint_clip_region = cairo_region_reference (clipped_and_offset_region);
|
||||
|
||||
if (cairo_region_is_empty (clipped_and_offset_region))
|
||||
goto done;
|
||||
@@ -423,13 +387,8 @@ gdk_window_impl_quartz_end_paint (GdkWindow *window)
|
||||
{
|
||||
GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
|
||||
|
||||
impl->begin_paint_count--;
|
||||
|
||||
if (impl->begin_paint_count == 0)
|
||||
{
|
||||
cairo_region_destroy (impl->paint_clip_region);
|
||||
impl->paint_clip_region = NULL;
|
||||
}
|
||||
cairo_region_destroy (impl->paint_clip_region);
|
||||
impl->paint_clip_region = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -51,7 +51,6 @@ struct _GdkWindowImplQuartz
|
||||
GdkWindowTypeHint type_hint;
|
||||
|
||||
cairo_region_t *paint_clip_region;
|
||||
gint begin_paint_count;
|
||||
gint in_paint_rect_count;
|
||||
|
||||
GdkWindow *transient_for;
|
||||
|
||||
Reference in New Issue
Block a user