diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c index 2faf4f9cc..64286cd29 100644 --- a/src/cairo-xlib-display.c +++ b/src/cairo-xlib-display.c @@ -40,8 +40,29 @@ #include /* For XESetCloseDisplay */ #include +typedef int (*cairo_xlib_error_func_t) (Display *display, + XErrorEvent *event); -static cairo_xlib_display_t *_cairo_xlib_display_list = NULL; +struct _cairo_xlib_job { + cairo_xlib_job_t *next; + enum { + RESOURCE, + WORK + } type; + union { + struct { + cairo_xlib_notify_resource_func notify; + XID xid; + } resource; + struct { + cairo_xlib_notify_func notify; + void *data; + void (*destroy) (void *); + } work; + } func; +}; + +static cairo_xlib_display_t *_cairo_xlib_display_list; static void _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) @@ -50,6 +71,7 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) /* call all registered shutdown routines */ CAIRO_MUTEX_LOCK (display->mutex); + hooks = display->close_display_hooks; while (hooks != NULL) { display->close_display_hooks = NULL; @@ -68,6 +90,7 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display) hooks = display->close_display_hooks; } display->closed = TRUE; + CAIRO_MUTEX_UNLOCK (display->mutex); } @@ -97,6 +120,18 @@ _cairo_xlib_display_destroy (cairo_xlib_display_t *display) CAIRO_MUTEX_LOCK (display->mutex); assert (display->ref_count > 0); if (--display->ref_count == 0) { + /* destroy all outstanding notifies */ + while (display->workqueue != NULL) { + cairo_xlib_job_t *job = display->workqueue; + display->workqueue = job->next; + + if (job->type == WORK && job->func.work.destroy != NULL) + job->func.work.destroy (job->func.work.data); + + _cairo_freelist_free (&display->wq_freelist, job); + } + _cairo_freelist_fini (&display->wq_freelist); + CAIRO_MUTEX_UNLOCK (display->mutex); free (display); @@ -104,6 +139,12 @@ _cairo_xlib_display_destroy (cairo_xlib_display_t *display) CAIRO_MUTEX_UNLOCK (display->mutex); } +static int +_noop_error_handler (Display *display, + XErrorEvent *event) +{ + return False; /* return value is ignored */ +} static int _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) { @@ -117,13 +158,26 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes) for (display = _cairo_xlib_display_list; display; display = next) { next = display->next; if (display->display == dpy) { + cairo_xlib_error_func_t old_handler; + /* drop the list mutex whilst triggering the hooks */ CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + /* protect the notifies from triggering XErrors */ + XSync (dpy, False); + old_handler = XSetErrorHandler (_noop_error_handler); + + _cairo_xlib_display_notify (display); _cairo_xlib_call_close_display_hooks (display); - _cairo_xlib_display_destroy (display); + + /* catch any that arrived before marking the display as closed */ + _cairo_xlib_display_notify (display); + + XSync (dpy, False); + XSetErrorHandler (old_handler); CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + _cairo_xlib_display_destroy (display); *prev = next; break; } else @@ -185,10 +239,12 @@ _cairo_xlib_display_get (Display *dpy) XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); + _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t)); display->ref_count = 2; /* add one for the CloseDisplay */ CAIRO_MUTEX_INIT (display->mutex); display->display = dpy; display->screens = NULL; + display->workqueue = NULL; display->close_display_hooks = NULL; display->closed = FALSE; @@ -256,3 +312,112 @@ _cairo_xlib_remove_close_display_hooks (Display *dpy, const void *key) _cairo_xlib_display_destroy (display); } + +cairo_status_t +_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, + cairo_xlib_notify_resource_func notify, + XID xid) +{ + cairo_xlib_job_t *job; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + job = _cairo_freelist_alloc (&display->wq_freelist); + if (job == NULL) + return CAIRO_STATUS_NO_MEMORY; + + job->type = RESOURCE; + job->func.resource.xid = xid; + job->func.resource.notify = notify; + + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed == FALSE) { + job->next = display->workqueue; + display->workqueue = job; + } else { + _cairo_freelist_free (&display->wq_freelist, job); + job = NULL; + status = CAIRO_STATUS_NO_MEMORY; + } + CAIRO_MUTEX_UNLOCK (display->mutex); + + return status; +} + +cairo_status_t +_cairo_xlib_display_queue_work (cairo_xlib_display_t *display, + cairo_xlib_notify_func notify, + void *data, + void (*destroy) (void *)) +{ + cairo_xlib_job_t *job; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + job = _cairo_freelist_alloc (&display->wq_freelist); + if (job == NULL) + return CAIRO_STATUS_NO_MEMORY; + + job->type = WORK; + job->func.work.data = data; + job->func.work.notify = notify; + job->func.work.destroy = destroy; + + CAIRO_MUTEX_LOCK (display->mutex); + if (display->closed == FALSE) { + job->next = display->workqueue; + display->workqueue = job; + } else { + _cairo_freelist_free (&display->wq_freelist, job); + job = NULL; + status = CAIRO_STATUS_NO_MEMORY; + } + CAIRO_MUTEX_UNLOCK (display->mutex); + + return status; +} + +void +_cairo_xlib_display_notify (cairo_xlib_display_t *display) +{ + cairo_xlib_job_t *jobs, *job; + + CAIRO_MUTEX_LOCK (display->mutex); + jobs = display->workqueue; + while (jobs != NULL) { + display->workqueue = NULL; + CAIRO_MUTEX_UNLOCK (display->mutex); + + /* reverse the list to obtain FIFO order */ + job = NULL; + do { + cairo_xlib_job_t *next = jobs->next; + jobs->next = job; + job = jobs; + jobs = next; + } while (jobs != NULL); + jobs = job; + + do { + job = jobs; + jobs = job->next; + + switch (job->type){ + case WORK: + job->func.work.notify (display->display, job->func.work.data); + if (job->func.work.destroy != NULL) + job->func.work.destroy (job->func.work.data); + break; + + case RESOURCE: + job->func.resource.notify (display->display, + job->func.resource.xid); + break; + } + + _cairo_freelist_free (&display->wq_freelist, job); + } while (jobs != NULL); + + CAIRO_MUTEX_LOCK (display->mutex); + jobs = display->workqueue; + } + CAIRO_MUTEX_UNLOCK (display->mutex); +} diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h index 63b4a98d5..436c67f90 100644 --- a/src/cairo-xlib-private.h +++ b/src/cairo-xlib-private.h @@ -35,9 +35,13 @@ #include "cairoint.h" #include "cairo-xlib.h" +#include "cairo-freelist-private.h" typedef struct _cairo_xlib_display cairo_xlib_display_t; typedef struct _cairo_xlib_hook cairo_xlib_hook_t; +typedef struct _cairo_xlib_job cairo_xlib_job_t; +typedef void (*cairo_xlib_notify_func) (Display *, void *); +typedef void (*cairo_xlib_notify_resource_func) (Display *, XID); struct _cairo_xlib_hook { cairo_xlib_hook_t *next; @@ -54,6 +58,9 @@ struct _cairo_xlib_display { Display *display; cairo_xlib_screen_info_t *screens; + cairo_xlib_job_t *workqueue; + cairo_freelist_t wq_freelist; + cairo_xlib_hook_t *close_display_hooks; unsigned int closed :1; }; @@ -82,6 +89,17 @@ _cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, v cairo_private void _cairo_xlib_remove_close_display_hooks (Display *display, const void *key); +cairo_private cairo_status_t +_cairo_xlib_display_queue_work (cairo_xlib_display_t *display, + cairo_xlib_notify_func notify, + void *data, + void (*destroy)(void *)); +cairo_private cairo_status_t +_cairo_xlib_display_queue_resource (cairo_xlib_display_t *display, + cairo_xlib_notify_resource_func notify, + XID resource); +cairo_private void +_cairo_xlib_display_notify (cairo_xlib_display_t *display); cairo_private cairo_xlib_screen_info_t * _cairo_xlib_screen_info_get (Display *display, Screen *screen); diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c index 4a38b912a..470524462 100644 --- a/src/cairo-xlib-screen.c +++ b/src/cairo-xlib-screen.c @@ -242,7 +242,6 @@ _cairo_xlib_init_screen_font_options (Display *dpy, cairo_xlib_screen_info_t *in cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON); } - cairo_xlib_screen_info_t * _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info) { diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index f7b01a4cf..fcc9b5769 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -220,6 +220,8 @@ _cairo_xlib_surface_create_similar (void *abstract_src, cairo_xlib_surface_t *surface; Pixmap pix; + _cairo_xlib_display_notify (src->screen_info->display); + /* Start by examining the surface's XRenderFormat, or if it * doesn't have one, then look one up through its visual (in the * case of a bitmap, it won't even have that). */ @@ -754,6 +756,8 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf cairo_image_surface_t *image; cairo_status_t status; + _cairo_xlib_display_notify (surface->screen_info->display); + status = _get_image_surface (surface, NULL, &image, NULL); if (status) return status; @@ -783,6 +787,8 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac cairo_image_surface_t *image; cairo_status_t status; + _cairo_xlib_display_notify (surface->screen_info->display); + status = _get_image_surface (surface, interest_rect, &image, image_rect_out); if (status) return status; @@ -834,6 +840,8 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface, cairo_xlib_surface_t *clone; cairo_status_t status; + _cairo_xlib_display_notify (surface->screen_info->display); + if (src->backend == surface->base.backend ) { cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src; @@ -1268,6 +1276,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op, int itx, ity; cairo_bool_t is_integer_translation; + _cairo_xlib_display_notify (dst->screen_info->display); + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1417,6 +1427,8 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, cairo_xlib_surface_t *surface = abstract_surface; XRenderColor render_color; + _cairo_xlib_display_notify (surface->screen_info->display); + if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1549,6 +1561,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op, int render_src_x, render_src_y; XRenderPictFormat *pict_format; + _cairo_xlib_display_notify (dst->screen_info->display); + if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1661,6 +1675,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, if (surface->have_clip_rects == FALSE && region == NULL) return CAIRO_STATUS_SUCCESS; + _cairo_xlib_display_notify (surface->screen_info->display); + if (surface->clip_rects != surface->embedded_clip_rects) { free (surface->clip_rects); surface->clip_rects = surface->embedded_clip_rects; @@ -2266,7 +2282,7 @@ typedef struct _cairo_xlib_surface_font_private { static void _cairo_xlib_surface_remove_scaled_font (Display *dpy, - void *data) + void *data) { cairo_scaled_font_t *scaled_font = data; cairo_xlib_surface_font_private_t *font_private; @@ -2278,7 +2294,7 @@ _cairo_xlib_surface_remove_scaled_font (Display *dpy, _cairo_scaled_font_reset_cache (scaled_font); CAIRO_MUTEX_UNLOCK (scaled_font->mutex); - if (font_private) { + if (font_private != NULL) { XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset); free (font_private); } @@ -2947,6 +2963,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst, _cairo_pattern_fini (&solid_pattern.base); BAIL0: _cairo_scaled_font_thaw_cache (scaled_font); + _cairo_xlib_display_notify (dst->screen_info->display); return status; }