[PATCH 1/2] xlib-xcb: Register a XCloseDisplay hook
Uli Schlachter
psychon at znc.in
Sun Jul 3 08:45:58 PDT 2011
This commits makes the xlib-xcb backend produce its own cairo_device_t. When
such a device is finished, the underlying xcb device is finished, too.
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.
Signed-off-by: Uli Schlachter <psychon at znc.in>
---
src/cairo-xlib-xcb-surface.c | 143 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 140 insertions(+), 3 deletions(-)
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 8fe0e50..1d1a45b 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -45,8 +45,25 @@
#include "cairo-xcb-private.h"
#include "cairo-xlib-xrender-private.h"
+#include "cairo-xlib-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 +262,121 @@ 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_finish (display->xcb_device);
+ 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_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
+
+ /* Make sure the xlib-xcb (and thus the xcb) device is finished
+ * when the X11 connection is closed. */
+ cairo_device_finish (&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;
+
+ 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;
+ }
+ printf("still have %p in list\n", display);
+ }
+
+ 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 +397,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 +739,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 */
--
1.7.5.4
--------------030606010808080108020706
Content-Type: text/x-diff;
name="0002-xlib-xcb-xcb-Check-for-right-device-in-gs-et_precisi.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename*0="0002-xlib-xcb-xcb-Check-for-right-device-in-gs-et_precisi.pa";
filename*1="tch"
More information about the cairo
mailing list