summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2011-07-03 17:45:58 +0200
committerUli Schlachter <psychon@znc.in>2011-07-09 09:42:22 +0200
commit5b9205cc52f50f997c9cd6c5a64faf783d83310f (patch)
tree6d2305649de8dcd3e3788713ec0da15eee807e4e
parent05a0b24ecbafccf63e0114889301fc23268a9efc (diff)
xlib-xcb: Register a XCloseDisplay hook
This commits makes the xlib-xcb backend produce its own cairo_device_t. This per-Display* device is used to manage the registration of a XCloseDisplay hook via XAddExtension/XESetCloseDisplay in the same way that the xlib backend does this. The device is necessary to see if we already registered an extension. This fixes weird errors when running cairo-test-suite with -a -s. They were caused because the backend didn't see the XCloseDisplay and the next XOpenDisplay happened to create a xcb_connection_t with the same address as the last display. This caused the xcb backend to assume lots of wrongness. This commit makes use of _cairo_xlib_display_mutex which is otherwise compiled in but not used anywhere when xlib-xcb is enabled. Patch v2: Fixed the xcb_device == NULL case and made sure the xcb_device is only finished on XCloseDisplay, not when all xlib-xcb surfaces are destroyed. Signed-off-by: Uli Schlachter <psychon@znc.in>
-rw-r--r--src/cairo-xlib-xcb-surface.c145
1 files changed, 142 insertions, 3 deletions
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 8fe0e50f..0ffbc4c5 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -47,6 +47,22 @@
#include "cairo-xlib-xrender-private.h"
#include <X11/Xlib-xcb.h>
+#include <X11/Xlibint.h> /* For XESetCloseDisplay */
+
+struct cairo_xlib_xcb_display_t {
+ cairo_device_t base;
+
+ Display *dpy;
+ cairo_device_t *xcb_device;
+ XExtCodes *codes;
+
+ cairo_list_t link;
+};
+typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t;
+
+/* List of all cairo_xlib_xcb_display_t alive,
+ * protected by _cairo_xlib_display_mutex */
+static cairo_list_t displays;
static cairo_surface_t *
_cairo_xlib_xcb_surface_create (void *dpy,
@@ -245,6 +261,124 @@ static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
_cairo_xlib_xcb_surface_glyphs,
};
+static void
+_cairo_xlib_xcb_display_finish (void *abstract_display)
+{
+ cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display;
+
+ CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+ cairo_list_del (&display->link);
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+ cairo_device_destroy (display->xcb_device);
+ display->xcb_device = NULL;
+
+ XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
+}
+
+static int
+_cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
+{
+ cairo_xlib_xcb_display_t *display;
+
+ CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+ cairo_list_foreach_entry (display,
+ cairo_xlib_xcb_display_t,
+ &displays,
+ link)
+ {
+ if (display->dpy == dpy)
+ {
+ /* _cairo_xlib_xcb_display_finish will lock the mutex again
+ * -> deadlock (This mutex isn't recursive) */
+ cairo_device_reference (&display->base);
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+ /* Make sure the xcb and xlib-xcb devices are finished */
+ cairo_device_finish (display->xcb_device);
+ cairo_device_finish (&display->base);
+ cairo_device_destroy (&display->base);
+ return 0;
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+ return 0;
+}
+
+static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = {
+ CAIRO_DEVICE_TYPE_XLIB,
+
+ NULL,
+ NULL,
+
+ NULL, /* flush */
+ _cairo_xlib_xcb_display_finish,
+ free, /* destroy */
+};
+
+static cairo_device_t *
+_cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
+{
+ cairo_xlib_xcb_display_t *display = NULL;
+ cairo_device_t *device;
+
+ if (xcb_device == NULL)
+ return NULL;
+
+ CAIRO_MUTEX_INITIALIZE ();
+
+ CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
+ if (displays.next == NULL) {
+ cairo_list_init (&displays);
+ }
+
+ cairo_list_foreach_entry (display,
+ cairo_xlib_xcb_display_t,
+ &displays,
+ link)
+ {
+ if (display->dpy == dpy) {
+ /* Maintain MRU order. */
+ if (displays.next != &display->link)
+ cairo_list_move (&display->link, &displays);
+
+ /* Grab a reference for our caller */
+ device = cairo_device_reference (&display->base);
+ assert (display->xcb_device == xcb_device);
+ goto unlock;
+ }
+ }
+
+ display = malloc (sizeof (cairo_xlib_xcb_display_t));
+ if (unlikely (display == NULL)) {
+ device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ goto unlock;
+ }
+
+ display->codes = XAddExtension (dpy);
+ if (unlikely (display->codes == NULL)) {
+ device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ free (display);
+ goto unlock;
+ }
+
+ _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);
+
+ XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
+
+ display->dpy = dpy;
+ display->xcb_device = cairo_device_reference(xcb_device);
+
+ cairo_list_add (&display->link, &displays);
+ device = &display->base;
+
+unlock:
+ CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+ return device;
+}
+
static cairo_surface_t *
_cairo_xlib_xcb_surface_create (void *dpy,
void *scr,
@@ -265,9 +399,12 @@ _cairo_xlib_xcb_surface_create (void *dpy,
_cairo_surface_init (&surface->base,
&_cairo_xlib_xcb_surface_backend,
- xcb->device,
+ _cairo_xlib_xcb_device_create (dpy, xcb->device),
xcb->content);
+ /* _cairo_surface_init() got another reference to the device, drop ours */
+ cairo_device_destroy (surface->base.device);
+
surface->display = dpy;
surface->screen = scr;
surface->visual = visual;
@@ -604,13 +741,15 @@ void
cairo_xlib_device_debug_set_precision (cairo_device_t *device,
int precision)
{
- cairo_xcb_device_debug_set_precision (device, precision);
+ cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
+ cairo_xcb_device_debug_set_precision (display->xcb_device, precision);
}
int
cairo_xlib_device_debug_get_precision (cairo_device_t *device)
{
- return cairo_xcb_device_debug_get_precision (device);
+ cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
+ return cairo_xcb_device_debug_get_precision (display->xcb_device);
}
#endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */