summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-display.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xlib-display.c')
-rw-r--r--src/cairo-xlib-display.c188
1 files changed, 175 insertions, 13 deletions
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 65df2b7..56ea7c8 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -38,8 +38,32 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-xrender-private.h"
+#include "cairo-freelist-private.h"
+
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
+struct _cairo_xlib_display {
+ cairo_xlib_display_t *next;
+ cairo_reference_count_t ref_count;
+ cairo_mutex_t mutex;
+
+ Display *display;
+ cairo_xlib_screen_t *screens;
+
+ int render_major;
+ int render_minor;
+ XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_A1 + 1];
+
+ cairo_xlib_job_t *workqueue;
+ cairo_freelist_t wq_freelist;
+
+ cairo_xlib_hook_t *close_display_hooks;
+ unsigned int buggy_gradients :1;
+ unsigned int buggy_pad_reflect :1;
+ unsigned int buggy_repeat :1;
+ unsigned int closed :1;
+};
+
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
@@ -71,14 +95,14 @@ _cairo_xlib_remove_close_display_hook_internal (cairo_xlib_display_t *display,
static void
_cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
{
- cairo_xlib_screen_info_t *screen;
+ cairo_xlib_screen_t *screen;
cairo_xlib_hook_t *hook;
/* call all registered shutdown routines */
CAIRO_MUTEX_LOCK (display->mutex);
for (screen = display->screens; screen != NULL; screen = screen->next)
- _cairo_xlib_screen_info_close_display (screen);
+ _cairo_xlib_screen_close_display (screen);
while (TRUE) {
hook = display->close_display_hooks;
@@ -99,7 +123,7 @@ _cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
static void
_cairo_xlib_display_discard_screens (cairo_xlib_display_t *display)
{
- cairo_xlib_screen_info_t *screens;
+ cairo_xlib_screen_t *screens;
CAIRO_MUTEX_LOCK (display->mutex);
screens = display->screens;
@@ -107,10 +131,10 @@ _cairo_xlib_display_discard_screens (cairo_xlib_display_t *display)
CAIRO_MUTEX_UNLOCK (display->mutex);
while (screens != NULL) {
- cairo_xlib_screen_info_t *screen = screens;
+ cairo_xlib_screen_t *screen = screens;
screens = screen->next;
- _cairo_xlib_screen_info_destroy (screen);
+ _cairo_xlib_screen_destroy (screen);
}
}
@@ -213,7 +237,7 @@ _cairo_xlib_display_get (Display *dpy,
cairo_xlib_display_t *display;
cairo_xlib_display_t **prev;
XExtCodes *codes;
- int render_major, render_minor;
+ const char *env;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* There is an apparent deadlock between this mutex and the
@@ -257,7 +281,24 @@ _cairo_xlib_display_get (Display *dpy,
* add our hook. For now, that means Render, so we call into its
* QueryVersion function to ensure it gets initialized.
*/
- XRenderQueryVersion (dpy, &render_major, &render_minor);
+ display->render_major = display->render_minor = -1;
+ XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
+ env = getenv ("CAIRO_DEBUG");
+ if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
+ int max_render_major, max_render_minor;
+
+ env += sizeof ("xrender-version=") - 1;
+ if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
+ max_render_major = max_render_minor = -1;
+
+ if (max_render_major < display->render_major ||
+ (max_render_major == display->render_major &&
+ max_render_minor < display->render_minor))
+ {
+ display->render_major = max_render_major;
+ display->render_minor = max_render_minor;
+ }
+ }
codes = XAddExtension (dpy);
if (unlikely (codes == NULL)) {
@@ -279,13 +320,19 @@ _cairo_xlib_display_get (Display *dpy,
display->close_display_hooks = NULL;
display->closed = FALSE;
- display->render_major = render_major;
- display->render_minor = render_minor;
memset (display->cached_xrender_formats, 0,
sizeof (display->cached_xrender_formats));
+ /* Prior to Render 0.10, there is no protocol support for gradients and
+ * we call function stubs instead, which would silently consume the drawing.
+ */
+#if RENDER_MAJOR == 0 && RENDER_MINOR < 10
+ display->buggy_gradients = TRUE;
+#else
+ display->buggy_gradients = FALSE;
+#endif
+ display->buggy_pad_reflect = FALSE;
display->buggy_repeat = FALSE;
- display->buggy_pad_reflect = TRUE;
/* This buggy_repeat condition is very complicated because there
* are multiple X server code bases (with multiple versioning
@@ -329,22 +376,33 @@ _cairo_xlib_display_get (Display *dpy,
* exactly when second the bug started, but since bug 1 is
* present through 6.8.2 and bug 2 is present in 6.9.0 it seems
* safest to just blacklist all old-versioning-scheme X servers,
- * (just using VendorRelase < 70000000), as buggy_repeat=TRUE.
+ * (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
*/
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
if (VendorRelease (dpy) >= 60700000) {
if (VendorRelease (dpy) < 70000000)
display->buggy_repeat = TRUE;
+
+ /* We know that gradients simply do not work in early Xorg servers */
+ if (VendorRelease (dpy) < 70200000)
+ display->buggy_gradients = TRUE;
+
+ /* And the extended repeat modes were not fixed until much later */
+ display->buggy_pad_reflect = TRUE;
} else {
if (VendorRelease (dpy) < 10400000)
display->buggy_repeat = TRUE;
- if (VendorRelease (dpy) >= 10699000)
- display->buggy_pad_reflect = FALSE;
+
+ /* Too many bugs in the early drivers */
+ if (VendorRelease (dpy) < 10699000)
+ display->buggy_pad_reflect = TRUE;
}
} else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
if (VendorRelease (dpy) <= 40500000)
display->buggy_repeat = TRUE;
+ display->buggy_gradients = TRUE;
+ display->buggy_pad_reflect = TRUE;
}
display->next = _cairo_xlib_display_list;
@@ -457,6 +515,12 @@ _cairo_xlib_display_notify (cairo_xlib_display_t *display)
cairo_xlib_job_t *jobs, *job, *freelist;
Display *dpy = display->display;
+ /* Optimistic atomic pointer read -- don't care if it is wrong due to
+ * contention as we will check again very shortly.
+ */
+ if (display->workqueue == NULL)
+ return;
+
CAIRO_MUTEX_LOCK (display->mutex);
jobs = display->workqueue;
while (jobs != NULL) {
@@ -508,6 +572,12 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
{
XRenderPictFormat *xrender_format;
+#if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
+ xrender_format = display->cached_xrender_formats[format];
+ if (likely (xrender_format != NULL))
+ return xrender_format;
+#endif
+
CAIRO_MUTEX_LOCK (display->mutex);
xrender_format = display->cached_xrender_formats[format];
if (xrender_format == NULL) {
@@ -533,3 +603,95 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
return xrender_format;
}
+
+Display *
+_cairo_xlib_display_get_dpy (cairo_xlib_display_t *display)
+{
+ return display->display;
+}
+
+void
+_cairo_xlib_display_remove_screen (cairo_xlib_display_t *display,
+ cairo_xlib_screen_t *screen)
+{
+ cairo_xlib_screen_t **prev;
+ cairo_xlib_screen_t *list;
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ for (prev = &display->screens; (list = *prev); prev = &list->next) {
+ if (list == screen) {
+ *prev = screen->next;
+ break;
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+}
+
+cairo_status_t
+_cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
+ Screen *screen,
+ cairo_xlib_screen_t **out)
+{
+ cairo_xlib_screen_t *info = NULL, **prev;
+
+ CAIRO_MUTEX_LOCK (display->mutex);
+ if (display->closed) {
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+ return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+ }
+
+ for (prev = &display->screens; (info = *prev); prev = &(*prev)->next) {
+ if (info->screen == screen) {
+ /*
+ * MRU the list
+ */
+ if (prev != &display->screens) {
+ *prev = info->next;
+ info->next = display->screens;
+ display->screens = info;
+ }
+ break;
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+
+ *out = info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+void
+_cairo_xlib_display_add_screen (cairo_xlib_display_t *display,
+ cairo_xlib_screen_t *screen)
+{
+ CAIRO_MUTEX_LOCK (display->mutex);
+ screen->next = display->screens;
+ display->screens = screen;
+ CAIRO_MUTEX_UNLOCK (display->mutex);
+}
+
+void
+_cairo_xlib_display_get_xrender_version (cairo_xlib_display_t *display,
+ int *major, int *minor)
+{
+ *major = display->render_major;
+ *minor = display->render_minor;
+}
+
+cairo_bool_t
+_cairo_xlib_display_has_repeat (cairo_xlib_display_t *display)
+{
+ return ! display->buggy_repeat;
+}
+
+cairo_bool_t
+_cairo_xlib_display_has_reflect (cairo_xlib_display_t *display)
+{
+ return ! display->buggy_pad_reflect;
+}
+
+cairo_bool_t
+_cairo_xlib_display_has_gradients (cairo_xlib_display_t *display)
+{
+ return ! display->buggy_gradients;
+}