mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
gdkwindow: Remove the internal cairo_surface used for out-of-band painting
Traditionally, the way painting was done in GTK+ was with the "expose-event" handler, where you'd use GDK methods to do drawing on your surface. In GTK+ 2.24, we added cairo support with gdk_cairo_create, so you could paint your graphics with cairo. Since then, we've added client-side windows, double buffering, the paint clock, and various other enhancements, and the modern way to do drawing is to connect to the "draw" signal on GtkWidget, which hands you a cairo_t. To do double-buffering, the cairo_t we hand you is actually on a secret surface, not the actual backing store of the window, and when the draw handler completes we blit it into the main backing store atomically. The code to do this is with the APIs gdk_window_begin_paint_region, which creates the temporary surface, and gdk_window_end_paint which blits it back into the backing store. GTK+'s implementation of the "draw" signal uses these APIs. We've always sort-of supported people calling gdk_cairo_create "outside" of a begin_paint / end_paint like old times, but then you're not getting the benefit of double-buffering, and it's harder for GDK to optimize. Additionally, newer backends like Mir and Wayland can't actually support this model, since they're based on double-buffering and swapping buffers at various points in time. If we hand you a random cairo_t, we have no idea when is a good time to swap. Remove support for this. This is technically a GDK API break: a warning is added in cases where gdk_cairo_create is called outside of a paint cycle, and the returned surface is a dummy that won't ever be composited back onto the main surface. Testing with complex applications like Ardour didn't produce any warnings.
This commit is contained in:
parent
b875572f2a
commit
d48adf9cee
@ -368,16 +368,6 @@ _gdk_broadway_window_destroy (GdkWindow *window,
|
||||
impl->id);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_window_broadway_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* Image surfaces cannot be resized */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_broadway_window_destroy_foreign (GdkWindow *window)
|
||||
{
|
||||
@ -1552,7 +1542,6 @@ gdk_window_impl_broadway_class_init (GdkWindowImplBroadwayClass *klass)
|
||||
impl_class->queue_antiexpose = _gdk_broadway_window_queue_antiexpose;
|
||||
impl_class->destroy = _gdk_broadway_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_broadway_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_broadway_resize_cairo_surface;
|
||||
impl_class->get_shape = gdk_broadway_window_get_shape;
|
||||
impl_class->get_input_shape = gdk_broadway_window_get_input_shape;
|
||||
impl_class->beep = gdk_broadway_window_beep;
|
||||
|
@ -266,8 +266,6 @@ struct _GdkWindow
|
||||
cairo_region_t *shape;
|
||||
cairo_region_t *input_shape;
|
||||
|
||||
cairo_surface_t *cairo_surface;
|
||||
|
||||
GList *devices_inside;
|
||||
GHashTable *device_events;
|
||||
|
||||
|
@ -549,18 +549,6 @@ gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* No-op. The surface gets resized in
|
||||
* gdk_offscreen_window_move_resize_internal().
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_offscreen_window_set_embedder:
|
||||
* @window: a #GdkWindow
|
||||
@ -727,7 +715,6 @@ gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
|
||||
impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
|
||||
impl_class->destroy = gdk_offscreen_window_destroy;
|
||||
impl_class->destroy_foreign = NULL;
|
||||
impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
|
||||
impl_class->get_shape = NULL;
|
||||
impl_class->get_input_shape = NULL;
|
||||
impl_class->beep = NULL;
|
||||
|
185
gdk/gdkwindow.c
185
gdk/gdkwindow.c
@ -151,12 +151,11 @@ struct _GdkWindowPaint
|
||||
{
|
||||
cairo_region_t *region;
|
||||
cairo_surface_t *surface;
|
||||
gboolean surface_needs_composite;
|
||||
};
|
||||
|
||||
/* Global info */
|
||||
|
||||
static void gdk_window_drop_cairo_surface (GdkWindow *private);
|
||||
|
||||
static void gdk_window_free_paint_stack (GdkWindow *window);
|
||||
|
||||
static void gdk_window_finalize (GObject *object);
|
||||
@ -477,8 +476,6 @@ gdk_window_finalize (GObject *object)
|
||||
_gdk_window_destroy (window, TRUE);
|
||||
}
|
||||
|
||||
gdk_window_drop_cairo_surface (window);
|
||||
|
||||
if (window->impl)
|
||||
{
|
||||
g_object_unref (window->impl);
|
||||
@ -1002,18 +999,6 @@ recompute_visible_regions_internal (GdkWindow *private,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (private->cairo_surface)
|
||||
{
|
||||
if (!gdk_window_has_impl (private) ||
|
||||
!GDK_WINDOW_IMPL_GET_CLASS (private->impl)->resize_cairo_surface (private,
|
||||
private->cairo_surface,
|
||||
private->width,
|
||||
private->height))
|
||||
{
|
||||
gdk_window_drop_cairo_surface (private);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Call this when private has changed in one or more of these ways:
|
||||
@ -1531,10 +1516,6 @@ gdk_window_reparent (GdkWindow *window,
|
||||
if (is_parent_of (window, new_parent))
|
||||
return;
|
||||
|
||||
/* This might be wrong in the new parent, e.g. for non-native surfaces.
|
||||
To make sure we're ok, just wipe it. */
|
||||
gdk_window_drop_cairo_surface (window);
|
||||
|
||||
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
|
||||
old_parent = window->parent;
|
||||
|
||||
@ -1716,8 +1697,6 @@ gdk_window_ensure_native (GdkWindow *window)
|
||||
|
||||
/* Need to create a native window */
|
||||
|
||||
gdk_window_drop_cairo_surface (window);
|
||||
|
||||
screen = gdk_window_get_screen (window);
|
||||
display = gdk_screen_get_display (screen);
|
||||
parent = window->parent;
|
||||
@ -1889,7 +1868,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
||||
if (temp_window == window)
|
||||
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
|
||||
|
||||
|
||||
switch (window->window_type)
|
||||
{
|
||||
case GDK_WINDOW_ROOT:
|
||||
@ -1987,8 +1965,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
||||
|
||||
_gdk_window_clear_update_area (window);
|
||||
|
||||
gdk_window_drop_cairo_surface (window);
|
||||
|
||||
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
|
||||
|
||||
if (gdk_window_has_impl (window))
|
||||
@ -2780,6 +2756,12 @@ gdk_window_begin_paint_region (GdkWindow *window,
|
||||
cairo_surface_get_device_scale (paint->surface, &sx, &sy);
|
||||
#endif
|
||||
cairo_surface_set_device_offset (paint->surface, -clip_box.x*sx, -clip_box.y*sy);
|
||||
|
||||
paint->surface_needs_composite = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
paint->surface = gdk_window_ref_impl_surface (window);
|
||||
}
|
||||
|
||||
for (list = window->paint_stack; list != NULL; list = list->next)
|
||||
@ -2796,6 +2778,23 @@ gdk_window_begin_paint_region (GdkWindow *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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_window_end_paint:
|
||||
* @window: a #GdkWindow
|
||||
@ -2841,14 +2840,18 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
window->paint_stack = g_slist_delete_link (window->paint_stack,
|
||||
window->paint_stack);
|
||||
|
||||
|
||||
if (paint->surface != NULL)
|
||||
if (paint->surface_needs_composite)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
|
||||
cairo_region_get_extents (paint->region, &clip_box);
|
||||
full_clip = cairo_region_copy (window->clip_region);
|
||||
cairo_region_intersect (full_clip, paint->region);
|
||||
|
||||
cr = gdk_cairo_create (window);
|
||||
surface = get_window_surface (window);
|
||||
cr = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_set_source_surface (cr, paint->surface, 0, 0);
|
||||
gdk_cairo_region (cr, full_clip);
|
||||
cairo_clip (cr);
|
||||
@ -2866,10 +2869,10 @@ gdk_window_end_paint (GdkWindow *window)
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_region_destroy (full_clip);
|
||||
|
||||
cairo_surface_destroy (paint->surface);
|
||||
}
|
||||
|
||||
cairo_surface_destroy (paint->surface);
|
||||
|
||||
cairo_region_destroy (paint->region);
|
||||
g_free (paint);
|
||||
|
||||
@ -2908,8 +2911,7 @@ gdk_window_free_paint_stack (GdkWindow *window)
|
||||
{
|
||||
GdkWindowPaint *paint = tmp_list->data;
|
||||
|
||||
if (tmp_list == window->paint_stack &&
|
||||
paint->surface != NULL)
|
||||
if (tmp_list == window->paint_stack)
|
||||
cairo_surface_destroy (paint->surface);
|
||||
|
||||
cairo_region_destroy (paint->region);
|
||||
@ -3012,7 +3014,7 @@ gdk_window_clear_backing_region (GdkWindow *window,
|
||||
int x_offset = 0, y_offset = 0;
|
||||
cairo_t *cr;
|
||||
|
||||
if (GDK_WINDOW_DESTROYED (window) || paint->surface == NULL)
|
||||
if (GDK_WINDOW_DESTROYED (window))
|
||||
return;
|
||||
|
||||
cr = cairo_create (paint->surface);
|
||||
@ -3047,88 +3049,23 @@ gdk_window_clear_backing_region (GdkWindow *window,
|
||||
cairo_region_destroy (clip);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_drop_cairo_surface (GdkWindow *window)
|
||||
{
|
||||
if (window->cairo_surface)
|
||||
{
|
||||
cairo_surface_finish (window->cairo_surface);
|
||||
cairo_surface_set_user_data (window->cairo_surface, &gdk_window_cairo_key,
|
||||
NULL, NULL);
|
||||
window->cairo_surface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_cairo_surface_destroy (void *data)
|
||||
{
|
||||
GdkWindow *window = data;
|
||||
|
||||
window->cairo_surface = NULL;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
gdk_window_create_cairo_surface (GdkWindow *window,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_surface_t *surface, *subsurface;
|
||||
|
||||
surface = gdk_window_ref_impl_surface (window);
|
||||
if (gdk_window_has_impl (window))
|
||||
return surface;
|
||||
|
||||
subsurface = cairo_surface_create_for_rectangle (surface,
|
||||
window->abs_x,
|
||||
window->abs_y,
|
||||
width,
|
||||
height);
|
||||
cairo_surface_destroy (surface);
|
||||
return subsurface;
|
||||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
cairo_surface_t *
|
||||
_gdk_window_ref_cairo_surface (GdkWindow *window)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GdkWindowPaint *paint;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
|
||||
|
||||
paint = NULL;
|
||||
if (window->impl_window->paint_stack)
|
||||
paint = window->impl_window->paint_stack->data;
|
||||
surface = get_window_surface (window);
|
||||
|
||||
if (paint && paint->surface != NULL)
|
||||
{
|
||||
surface = cairo_surface_create_for_rectangle (paint->surface,
|
||||
window->abs_x,
|
||||
window->abs_y,
|
||||
window->width,
|
||||
window->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!window->cairo_surface)
|
||||
{
|
||||
window->cairo_surface = gdk_window_create_cairo_surface (window,
|
||||
window->width,
|
||||
window->height);
|
||||
|
||||
if (window->cairo_surface)
|
||||
{
|
||||
cairo_surface_set_user_data (window->cairo_surface, &gdk_window_cairo_key,
|
||||
window, gdk_window_cairo_surface_destroy);
|
||||
}
|
||||
}
|
||||
else
|
||||
cairo_surface_reference (window->cairo_surface);
|
||||
|
||||
surface = window->cairo_surface;
|
||||
}
|
||||
|
||||
return surface;
|
||||
return cairo_surface_create_for_rectangle (surface,
|
||||
window->abs_x,
|
||||
window->abs_y,
|
||||
window->width,
|
||||
window->height);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3149,31 +3086,35 @@ cairo_t *
|
||||
gdk_cairo_create (GdkWindow *window)
|
||||
{
|
||||
GdkWindowPaint *paint;
|
||||
cairo_surface_t *surface;
|
||||
cairo_region_t *region;
|
||||
cairo_t *cr;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
|
||||
|
||||
surface = _gdk_window_ref_cairo_surface (window);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
if (window->impl_window->paint_stack)
|
||||
if (window->impl_window->paint_stack == NULL)
|
||||
{
|
||||
paint = window->impl_window->paint_stack->data;
|
||||
cairo_surface_t *dummy_surface;
|
||||
cairo_t *cr;
|
||||
|
||||
region = cairo_region_copy (paint->region);
|
||||
cairo_region_translate (region, -window->abs_x, -window->abs_y);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_region_destroy (region);
|
||||
}
|
||||
else
|
||||
gdk_cairo_region (cr, window->clip_region);
|
||||
g_warning ("gdk_cairo_create called from outside a paint. Make sure to call "
|
||||
"gdk_window_begin_paint_region before calling gdk_cairo_create!");
|
||||
|
||||
/* Return a dummy surface to keep apps from crashing. */
|
||||
dummy_surface = cairo_image_surface_create (gdk_window_get_content (window), 0, 0);
|
||||
cr = cairo_create (dummy_surface);
|
||||
cairo_surface_destroy (dummy_surface);
|
||||
return cr;
|
||||
}
|
||||
|
||||
paint = window->impl_window->paint_stack->data;
|
||||
|
||||
cr = cairo_create (paint->surface);
|
||||
region = cairo_region_copy (paint->region);
|
||||
cairo_region_translate (region, -window->abs_x, -window->abs_y);
|
||||
gdk_cairo_region (cr, region);
|
||||
cairo_region_destroy (region);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return cr;
|
||||
}
|
||||
|
||||
|
@ -158,15 +158,6 @@ struct _GdkWindowImplClass
|
||||
*/
|
||||
void (*destroy_foreign) (GdkWindow *window);
|
||||
|
||||
/* Resizes @surface to a new size. If successful, return %TRUE.
|
||||
* If the backend cannot resize surfaces, return %FALSE and a new
|
||||
* surface will be created instead.
|
||||
*/
|
||||
gboolean (* resize_cairo_surface) (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
/* optional */
|
||||
gboolean (* beep) (GdkWindow *window);
|
||||
|
||||
|
@ -1104,16 +1104,6 @@ gdk_quartz_window_destroy (GdkWindow *window,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_window_quartz_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* Quartz surfaces cannot be resized */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_quartz_window_destroy_foreign (GdkWindow *window)
|
||||
{
|
||||
@ -2949,7 +2939,6 @@ gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
|
||||
impl_class->queue_antiexpose = gdk_quartz_window_queue_antiexpose;
|
||||
impl_class->destroy = gdk_quartz_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_quartz_resize_cairo_surface;
|
||||
impl_class->get_shape = gdk_quartz_window_get_shape;
|
||||
impl_class->get_input_shape = gdk_quartz_window_get_input_shape;
|
||||
impl_class->begin_paint_region = gdk_window_impl_quartz_begin_paint_region;
|
||||
|
@ -1350,16 +1350,6 @@ gdk_window_wayland_destroy_foreign (GdkWindow *window)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_window_wayland_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* cairo image surfaces cannot be resized */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static cairo_region_t *
|
||||
gdk_wayland_window_get_shape (GdkWindow *window)
|
||||
{
|
||||
@ -1994,7 +1984,6 @@ _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass)
|
||||
impl_class->queue_antiexpose = gdk_wayland_window_queue_antiexpose;
|
||||
impl_class->destroy = gdk_wayland_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_window_wayland_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_wayland_resize_cairo_surface;
|
||||
impl_class->get_shape = gdk_wayland_window_get_shape;
|
||||
impl_class->get_input_shape = gdk_wayland_window_get_input_shape;
|
||||
impl_class->begin_paint_region = gdk_window_impl_wayland_begin_paint_region;
|
||||
|
@ -796,16 +796,6 @@ gdk_win32_window_destroy (GdkWindow *window,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_win32_window_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
/* XXX: Make Cairo surface use DC clip */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_window_destroy_foreign (GdkWindow *window)
|
||||
{
|
||||
@ -3433,7 +3423,6 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
|
||||
impl_class->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
|
||||
impl_class->destroy = gdk_win32_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_win32_window_resize_cairo_surface;
|
||||
impl_class->get_shape = gdk_win32_window_get_shape;
|
||||
//FIXME?: impl_class->get_input_shape = gdk_win32_window_get_input_shape;
|
||||
|
||||
|
@ -1337,17 +1337,6 @@ gdk_x11_window_destroy (GdkWindow *window,
|
||||
XDestroyWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_window_x11_resize_cairo_surface (GdkWindow *window,
|
||||
cairo_surface_t *surface,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
cairo_xlib_surface_set_size (surface, width, height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_window_destroy_foreign (GdkWindow *window)
|
||||
{
|
||||
@ -5780,7 +5769,6 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
|
||||
impl_class->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
|
||||
impl_class->destroy = gdk_x11_window_destroy;
|
||||
impl_class->destroy_foreign = gdk_x11_window_destroy_foreign;
|
||||
impl_class->resize_cairo_surface = gdk_window_x11_resize_cairo_surface;
|
||||
impl_class->get_shape = gdk_x11_window_get_shape;
|
||||
impl_class->get_input_shape = gdk_x11_window_get_input_shape;
|
||||
impl_class->beep = gdk_x11_window_beep;
|
||||
|
Loading…
Reference in New Issue
Block a user