[broadway] Ensure gdk_ref_cairo_surface object can be destroyed

If we return a direct ref that is not possible, since we own a ref to it.
This is problematic as the gdkwindow.c code uses destruction to track
outstanding surfaces.

We fix this by returning a subsurface.
This commit is contained in:
Alexander Larsson 2010-11-16 20:28:54 +01:00
parent f02b7c9ed2
commit db288f3233
3 changed files with 42 additions and 10 deletions

View File

@ -67,11 +67,18 @@ _gdk_broadway_drawable_finish (GdkDrawable *drawable)
{ {
GdkDrawableImplBroadway *impl = GDK_DRAWABLE_IMPL_BROADWAY (drawable); GdkDrawableImplBroadway *impl = GDK_DRAWABLE_IMPL_BROADWAY (drawable);
if (impl->ref_surface)
{
cairo_surface_finish (impl->ref_surface);
cairo_surface_set_user_data (impl->ref_surface, &gdk_broadway_cairo_key,
NULL, NULL);
}
if (impl->surface) if (impl->surface)
{ {
cairo_surface_finish (impl->surface); cairo_surface_destroy (impl->surface);
impl->surface = NULL; impl->surface = NULL;
cairo_surface_finish (impl->last_surface); cairo_surface_destroy (impl->last_surface);
impl->last_surface = NULL; impl->last_surface = NULL;
} }
} }
@ -103,8 +110,8 @@ _gdk_broadway_drawable_update_size (GdkDrawable *drawable)
/* TODO: copy old contents */ /* TODO: copy old contents */
cairo_surface_finish (old); cairo_surface_destroy (old);
cairo_surface_finish (last_old); cairo_surface_destroy (last_old);
} }
} }
@ -112,6 +119,14 @@ _gdk_broadway_drawable_update_size (GdkDrawable *drawable)
* Broadway specific implementations of generic functions * * Broadway specific implementations of generic functions *
*****************************************************/ *****************************************************/
static void
gdk_broadway_cairo_surface_destroy (void *data)
{
GdkDrawableImplBroadway *impl = data;
impl->ref_surface = NULL;
}
static cairo_surface_t * static cairo_surface_t *
gdk_broadway_ref_cairo_surface (GdkDrawable *drawable) gdk_broadway_ref_cairo_surface (GdkDrawable *drawable)
{ {
@ -123,10 +138,12 @@ gdk_broadway_ref_cairo_surface (GdkDrawable *drawable)
GDK_WINDOW_DESTROYED (impl->wrapper)) GDK_WINDOW_DESTROYED (impl->wrapper))
return NULL; return NULL;
w = gdk_window_get_width (impl->wrapper);
h = gdk_window_get_height (impl->wrapper);
/* Create actual backing store if missing */
if (!impl->surface) if (!impl->surface)
{ {
w = gdk_window_get_width (impl->wrapper);
h = gdk_window_get_height (impl->wrapper);
impl->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h); impl->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
impl->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h); impl->last_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
@ -143,5 +160,19 @@ gdk_broadway_ref_cairo_surface (GdkDrawable *drawable)
cairo_destroy (cr); cairo_destroy (cr);
} }
return cairo_surface_reference (impl->surface); /* Create a destroyable surface referencing the real one */
if (!impl->ref_surface)
{
impl->ref_surface =
cairo_surface_create_for_rectangle (impl->surface,
0, 0,
w, h);
if (impl->ref_surface)
cairo_surface_set_user_data (impl->ref_surface, &gdk_broadway_cairo_key,
drawable, gdk_broadway_cairo_surface_destroy);
}
else
cairo_surface_reference (impl->ref_surface);
return impl->ref_surface;
} }

View File

@ -53,6 +53,7 @@ struct _GdkDrawableImplBroadway
GdkScreen *screen; GdkScreen *screen;
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_surface_t *last_surface; cairo_surface_t *last_surface;
cairo_surface_t *ref_surface;
}; };
struct _GdkDrawableImplBroadwayClass struct _GdkDrawableImplBroadwayClass

View File

@ -230,9 +230,9 @@ _gdk_broadway_window_destroy (GdkWindow *window,
static cairo_surface_t * static cairo_surface_t *
gdk_window_broadway_resize_cairo_surface (GdkWindow *window, gdk_window_broadway_resize_cairo_surface (GdkWindow *window,
cairo_surface_t *surface, cairo_surface_t *surface,
gint width, gint width,
gint height) gint height)
{ {
/* Image surfaces cannot be resized */ /* Image surfaces cannot be resized */
cairo_surface_destroy (surface); cairo_surface_destroy (surface);