1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2007 Chris Wilson
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Chris Wilson.
33 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
38 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
40 #include "cairo-xlib-private.h"
41 #include "cairo-xlib-xrender-private.h"
42 #include "cairo-freelist-private.h"
43 #include "cairo-error-private.h"
45 #include <X11/Xlibint.h> /* For XESetCloseDisplay */
47 typedef int (*cairo_xlib_error_func_t) (Display *display,
50 static cairo_xlib_display_t *_cairo_xlib_display_list;
53 _noop_error_handler (Display *display,
56 return False; /* return value is ignored */
60 _cairo_xlib_display_finish (void *abstract_display)
62 cairo_xlib_display_t *display = abstract_display;
63 Display *dpy = display->display;
65 if (! cairo_device_acquire (&display->base)) {
66 cairo_xlib_error_func_t old_handler;
68 /* protect the notifies from triggering XErrors */
70 old_handler = XSetErrorHandler (_noop_error_handler);
72 while (! cairo_list_is_empty (&display->fonts)) {
73 _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
78 while (! cairo_list_is_empty (&display->screens)) {
79 _cairo_xlib_screen_destroy (display,
80 cairo_list_first_entry (&display->screens,
86 XSetErrorHandler (old_handler);
88 cairo_device_release (&display->base);
93 _cairo_xlib_display_destroy (void *abstract_display)
95 cairo_xlib_display_t *display = abstract_display;
101 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
103 cairo_xlib_display_t *display, **prev, *next;
105 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
106 for (display = _cairo_xlib_display_list; display; display = display->next)
107 if (display->display == dpy)
109 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
113 cairo_device_finish (&display->base);
116 * Unhook from the global list
118 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
119 prev = &_cairo_xlib_display_list;
120 for (display = _cairo_xlib_display_list; display; display = next) {
121 next = display->next;
122 if (display->display == dpy) {
126 prev = &display->next;
128 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
130 display->display = NULL; /* catch any later invalid access */
131 cairo_device_destroy (&display->base);
133 /* Return value in accordance with requirements of
134 * XESetCloseDisplay */
138 static const cairo_device_backend_t _cairo_xlib_device_backend = {
139 CAIRO_DEVICE_TYPE_XLIB,
145 _cairo_xlib_display_finish,
146 _cairo_xlib_display_destroy,
150 * cairo_xlib_device_create:
151 * @dpy: the display to create the device for
153 * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
155 * Returns: the device belonging to @dpy
158 _cairo_xlib_device_create (Display *dpy)
160 cairo_xlib_display_t *display;
161 cairo_xlib_display_t **prev;
162 cairo_device_t *device;
166 CAIRO_MUTEX_INITIALIZE ();
168 /* There is an apparent deadlock between this mutex and the
169 * mutex for the display, but it's actually safe. For the
170 * app to call XCloseDisplay() while any other thread is
171 * inside this function would be an error in the logic
172 * app, and the CloseDisplay hook is the only other place we
173 * acquire this mutex.
175 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
177 for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
179 if (display->display == dpy) {
183 if (prev != &_cairo_xlib_display_list) {
184 *prev = display->next;
185 display->next = _cairo_xlib_display_list;
186 _cairo_xlib_display_list = display;
188 device = cairo_device_reference (&display->base);
193 display = malloc (sizeof (cairo_xlib_display_t));
194 if (unlikely (display == NULL)) {
195 device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
199 /* Xlib calls out to the extension close_display hooks in LIFO
200 * order. So we have to ensure that all extensions that we depend
201 * on in our close_display hook are properly initialized before we
202 * add our hook. For now, that means Render, so we call into its
203 * QueryVersion function to ensure it gets initialized.
205 display->render_major = display->render_minor = -1;
206 XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
207 env = getenv ("CAIRO_DEBUG");
208 if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
209 int max_render_major, max_render_minor;
211 env += sizeof ("xrender-version=") - 1;
212 if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
213 max_render_major = max_render_minor = -1;
215 if (max_render_major < display->render_major ||
216 (max_render_major == display->render_major &&
217 max_render_minor < display->render_minor))
219 display->render_major = max_render_major;
220 display->render_minor = max_render_minor;
224 codes = XAddExtension (dpy);
225 if (unlikely (codes == NULL)) {
226 device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
231 _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
233 XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
235 cairo_device_reference (&display->base); /* add one for the CloseDisplay */
236 display->display = dpy;
237 cairo_list_init (&display->screens);
238 cairo_list_init (&display->fonts);
239 display->closed = FALSE;
241 display->white = NULL;
242 memset (display->alpha, 0, sizeof (display->alpha));
243 memset (display->solid, 0, sizeof (display->solid));
244 memset (display->solid_cache, 0, sizeof (display->solid_cache));
245 memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
247 memset (display->cached_xrender_formats, 0,
248 sizeof (display->cached_xrender_formats));
250 display->force_precision = -1;
252 /* Prior to Render 0.10, there is no protocol support for gradients and
253 * we call function stubs instead, which would silently consume the drawing.
255 #if RENDER_MAJOR == 0 && RENDER_MINOR < 10
256 display->buggy_gradients = TRUE;
258 display->buggy_gradients = FALSE;
260 display->buggy_pad_reflect = FALSE;
261 display->buggy_repeat = FALSE;
263 /* This buggy_repeat condition is very complicated because there
264 * are multiple X server code bases (with multiple versioning
265 * schemes within a code base), and multiple bugs.
269 * 1. The Vendor=="XFree86" code base with release numbers such
270 * as 4.7.0 (VendorRelease==40700000).
272 * 2. The Vendor=="X.Org" code base (a descendant of the
273 * XFree86 code base). It originally had things like
274 * VendorRelease==60700000 for release 6.7.0 but then changed
275 * its versioning scheme so that, for example,
276 * VendorRelease==10400000 for the 1.4.0 X server within the
281 * 1. The original bug that led to the buggy_repeat
282 * workaround. This was a bug that Owen Taylor investigated,
283 * understood well, and characterized against carious X
284 * servers. Confirmed X servers with this bug include:
286 * "XFree86" <= 40500000
287 * "X.Org" <= 60802000 (only with old numbering >= 60700000)
289 * 2. A separate bug resulting in a crash of the X server when
290 * using cairo's extend-reflect test case, (which, surprisingly
291 * enough was not passing RepeatReflect to the X server, but
292 * instead using RepeatNormal in a workaround). Nobody to date
293 * has understood the bug well, but it appears to be gone as of
294 * the X.Org 1.4.0 server. This bug is coincidentally avoided
295 * by using the same buggy_repeat workaround. Confirmed X
296 * servers with this bug include:
298 * "X.org" == 60900000 (old versioning scheme)
299 * "X.org" < 10400000 (new numbering scheme)
301 * For the old-versioning-scheme X servers we don't know
302 * exactly when second the bug started, but since bug 1 is
303 * present through 6.8.2 and bug 2 is present in 6.9.0 it seems
304 * safest to just blacklist all old-versioning-scheme X servers,
305 * (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
307 if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
308 if (VendorRelease (dpy) >= 60700000) {
309 if (VendorRelease (dpy) < 70000000)
310 display->buggy_repeat = TRUE;
312 /* We know that gradients simply do not work in early Xorg servers */
313 if (VendorRelease (dpy) < 70200000)
314 display->buggy_gradients = TRUE;
316 /* And the extended repeat modes were not fixed until much later */
317 display->buggy_pad_reflect = TRUE;
319 if (VendorRelease (dpy) < 10400000)
320 display->buggy_repeat = TRUE;
322 /* Too many bugs in the early drivers */
323 if (VendorRelease (dpy) < 10699000)
324 display->buggy_pad_reflect = TRUE;
326 } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
327 if (VendorRelease (dpy) <= 40500000)
328 display->buggy_repeat = TRUE;
330 display->buggy_gradients = TRUE;
331 display->buggy_pad_reflect = TRUE;
334 if (display->render_major > 0 || display->render_minor >= 4)
335 display->compositor = _cairo_xlib_traps_compositor_get ();
336 else if (display->render_major > 0 || display->render_minor >= 0)
337 display->compositor = _cairo_xlib_mask_compositor_get ();
339 display->compositor = _cairo_xlib_core_compositor_get ();
341 display->next = _cairo_xlib_display_list;
342 _cairo_xlib_display_list = display;
344 device = &display->base;
347 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
352 _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
354 cairo_status_t status;
356 status = cairo_device_acquire (device);
360 *display = (cairo_xlib_display_t *) device;
365 _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
366 pixman_format_code_t format)
368 Display *dpy = display->display;
369 XRenderPictFormat tmpl;
372 #define MASK(x) ((1<<(x))-1)
374 tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
375 mask = PictFormatType | PictFormatDepth;
377 switch (PIXMAN_FORMAT_TYPE(format)) {
378 case PIXMAN_TYPE_ARGB:
379 tmpl.type = PictTypeDirect;
381 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
382 if (PIXMAN_FORMAT_A(format))
383 tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
384 PIXMAN_FORMAT_G(format) +
385 PIXMAN_FORMAT_B(format));
387 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
388 tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
389 PIXMAN_FORMAT_B(format));
391 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
392 tmpl.direct.green = PIXMAN_FORMAT_B(format);
394 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
395 tmpl.direct.blue = 0;
397 mask |= PictFormatRed | PictFormatRedMask;
398 mask |= PictFormatGreen | PictFormatGreenMask;
399 mask |= PictFormatBlue | PictFormatBlueMask;
400 mask |= PictFormatAlpha | PictFormatAlphaMask;
403 case PIXMAN_TYPE_ABGR:
404 tmpl.type = PictTypeDirect;
406 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
407 if (tmpl.direct.alphaMask)
408 tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
409 PIXMAN_FORMAT_G(format) +
410 PIXMAN_FORMAT_R(format));
412 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
413 tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
414 PIXMAN_FORMAT_R(format));
416 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
417 tmpl.direct.green = PIXMAN_FORMAT_R(format);
419 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
422 mask |= PictFormatRed | PictFormatRedMask;
423 mask |= PictFormatGreen | PictFormatGreenMask;
424 mask |= PictFormatBlue | PictFormatBlueMask;
425 mask |= PictFormatAlpha | PictFormatAlphaMask;
428 case PIXMAN_TYPE_BGRA:
429 tmpl.type = PictTypeDirect;
431 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
432 tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
434 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
435 tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
436 PIXMAN_FORMAT_G(format));
438 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
439 tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
440 PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
442 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
443 tmpl.direct.alpha = 0;
445 mask |= PictFormatRed | PictFormatRedMask;
446 mask |= PictFormatGreen | PictFormatGreenMask;
447 mask |= PictFormatBlue | PictFormatBlueMask;
448 mask |= PictFormatAlpha | PictFormatAlphaMask;
452 tmpl.type = PictTypeDirect;
454 tmpl.direct.alpha = 0;
455 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
457 mask |= PictFormatAlpha | PictFormatAlphaMask;
460 case PIXMAN_TYPE_COLOR:
461 case PIXMAN_TYPE_GRAY:
462 /* XXX Find matching visual/colormap */
463 tmpl.type = PictTypeIndexed;
464 //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
465 //mask |= PictFormatColormap;
471 return XRenderFindFormat(dpy, mask, &tmpl, 1);
475 _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
476 cairo_format_t format)
478 XRenderPictFormat *xrender_format;
480 #if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
481 xrender_format = display->cached_xrender_formats[format];
482 if (likely (xrender_format != NULL))
483 return xrender_format;
486 xrender_format = display->cached_xrender_formats[format];
487 if (xrender_format == NULL) {
491 case CAIRO_FORMAT_A1:
492 pict_format = PictStandardA1; break;
493 case CAIRO_FORMAT_A8:
494 pict_format = PictStandardA8; break;
495 case CAIRO_FORMAT_RGB24:
496 pict_format = PictStandardRGB24; break;
497 case CAIRO_FORMAT_RGB16_565:
498 xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
501 case CAIRO_FORMAT_RGB30:
502 xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
505 case CAIRO_FORMAT_INVALID:
508 case CAIRO_FORMAT_ARGB32:
509 pict_format = PictStandardARGB32; break;
512 xrender_format = XRenderFindStandardFormat (display->display,
514 display->cached_xrender_formats[format] = xrender_format;
517 return xrender_format;
520 cairo_xlib_screen_t *
521 _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
524 cairo_xlib_screen_t *info;
526 cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
527 if (info->screen == screen) {
528 if (display->screens.next != &info->link)
529 cairo_list_move (&info->link, &display->screens);
538 _cairo_xlib_display_has_repeat (cairo_device_t *device)
540 return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
544 _cairo_xlib_display_has_reflect (cairo_device_t *device)
546 return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
550 _cairo_xlib_display_has_gradients (cairo_device_t *device)
552 return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
556 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
559 if (device == NULL || device->status)
561 if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
562 cairo_status_t status;
564 status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
569 ((cairo_xlib_display_t *) device)->force_precision = precision;
573 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
575 if (device == NULL || device->status)
577 if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
578 cairo_status_t status;
580 status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
585 return ((cairo_xlib_display_t *) device)->force_precision;
588 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */