beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xlib-display.c
bloba2a3bc7924b1e3335ab0a3c7a0815c3872029533
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.
32 * Contributor(s):
33 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
36 #include "cairoint.h"
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"
44 #include "cairo-list-inline.h"
46 #include <X11/Xlibint.h> /* For XESetCloseDisplay */
48 typedef int (*cairo_xlib_error_func_t) (Display *display,
49 XErrorEvent *event);
51 static cairo_xlib_display_t *_cairo_xlib_display_list;
53 static int
54 _noop_error_handler (Display *display,
55 XErrorEvent *event)
57 return False; /* return value is ignored */
60 static void
61 _cairo_xlib_display_finish (void *abstract_display)
63 cairo_xlib_display_t *display = abstract_display;
64 Display *dpy = display->display;
66 _cairo_xlib_display_fini_shm (display);
68 if (! cairo_device_acquire (&display->base)) {
69 cairo_xlib_error_func_t old_handler;
71 /* protect the notifies from triggering XErrors */
72 XSync (dpy, False);
73 old_handler = XSetErrorHandler (_noop_error_handler);
75 while (! cairo_list_is_empty (&display->fonts)) {
76 _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
77 cairo_xlib_font_t,
78 link));
81 while (! cairo_list_is_empty (&display->screens)) {
82 _cairo_xlib_screen_destroy (display,
83 cairo_list_first_entry (&display->screens,
84 cairo_xlib_screen_t,
85 link));
88 XSync (dpy, False);
89 XSetErrorHandler (old_handler);
91 cairo_device_release (&display->base);
95 static void
96 _cairo_xlib_display_destroy (void *abstract_display)
98 cairo_xlib_display_t *display = abstract_display;
100 free (display);
103 static int
104 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
106 cairo_xlib_display_t *display, **prev, *next;
108 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
109 for (display = _cairo_xlib_display_list; display; display = display->next)
110 if (display->display == dpy)
111 break;
112 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
113 if (display == NULL)
114 return 0;
116 cairo_device_finish (&display->base);
119 * Unhook from the global list
121 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
122 prev = &_cairo_xlib_display_list;
123 for (display = _cairo_xlib_display_list; display; display = next) {
124 next = display->next;
125 if (display->display == dpy) {
126 *prev = next;
127 break;
128 } else
129 prev = &display->next;
131 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
133 display->display = NULL; /* catch any later invalid access */
134 cairo_device_destroy (&display->base);
136 /* Return value in accordance with requirements of
137 * XESetCloseDisplay */
138 return 0;
141 static const cairo_device_backend_t _cairo_xlib_device_backend = {
142 CAIRO_DEVICE_TYPE_XLIB,
144 NULL,
145 NULL,
147 NULL, /* flush */
148 _cairo_xlib_display_finish,
149 _cairo_xlib_display_destroy,
152 static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
154 #if 1
155 if (display->render_major > 0 || display->render_minor >= 4)
156 display->compositor = _cairo_xlib_traps_compositor_get ();
157 else if (display->render_major > 0 || display->render_minor >= 0)
158 display->compositor = _cairo_xlib_mask_compositor_get ();
159 else
160 display->compositor = _cairo_xlib_core_compositor_get ();
161 #else
162 display->compositor = _cairo_xlib_fallback_compositor_get ();
163 #endif
167 * _cairo_xlib_device_create:
168 * @dpy: the display to create the device for
170 * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
172 * Returns: the device belonging to @dpy
174 cairo_device_t *
175 _cairo_xlib_device_create (Display *dpy)
177 cairo_xlib_display_t *display;
178 cairo_xlib_display_t **prev;
179 cairo_device_t *device;
180 XExtCodes *codes;
181 const char *env;
183 CAIRO_MUTEX_INITIALIZE ();
185 /* There is an apparent deadlock between this mutex and the
186 * mutex for the display, but it's actually safe. For the
187 * app to call XCloseDisplay() while any other thread is
188 * inside this function would be an error in the logic
189 * app, and the CloseDisplay hook is the only other place we
190 * acquire this mutex.
192 CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
194 for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
196 if (display->display == dpy) {
198 * MRU the list
200 if (prev != &_cairo_xlib_display_list) {
201 *prev = display->next;
202 display->next = _cairo_xlib_display_list;
203 _cairo_xlib_display_list = display;
205 device = cairo_device_reference (&display->base);
206 goto UNLOCK;
210 display = malloc (sizeof (cairo_xlib_display_t));
211 if (unlikely (display == NULL)) {
212 device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
213 goto UNLOCK;
216 _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
218 display->display = dpy;
219 cairo_list_init (&display->screens);
220 cairo_list_init (&display->fonts);
221 display->closed = FALSE;
223 /* Xlib calls out to the extension close_display hooks in LIFO
224 * order. So we have to ensure that all extensions that we depend
225 * on in our close_display hook are properly initialized before we
226 * add our hook. For now, that means Render, so we call into its
227 * QueryVersion function to ensure it gets initialized.
229 display->render_major = display->render_minor = -1;
230 XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
231 env = getenv ("CAIRO_DEBUG");
232 if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
233 int max_render_major, max_render_minor;
235 env += sizeof ("xrender-version=") - 1;
236 if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
237 max_render_major = max_render_minor = -1;
239 if (max_render_major < display->render_major ||
240 (max_render_major == display->render_major &&
241 max_render_minor < display->render_minor))
243 display->render_major = max_render_major;
244 display->render_minor = max_render_minor;
248 _cairo_xlib_display_select_compositor (display);
250 display->white = NULL;
251 memset (display->alpha, 0, sizeof (display->alpha));
252 memset (display->solid, 0, sizeof (display->solid));
253 memset (display->solid_cache, 0, sizeof (display->solid_cache));
254 memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
256 memset (display->cached_xrender_formats, 0,
257 sizeof (display->cached_xrender_formats));
259 display->force_precision = -1;
261 _cairo_xlib_display_init_shm (display);
263 /* Prior to Render 0.10, there is no protocol support for gradients and
264 * we call function stubs instead, which would silently consume the drawing.
266 #if RENDER_MAJOR == 0 && RENDER_MINOR < 10
267 display->buggy_gradients = TRUE;
268 #else
269 display->buggy_gradients = FALSE;
270 #endif
271 display->buggy_pad_reflect = FALSE;
272 display->buggy_repeat = FALSE;
274 /* This buggy_repeat condition is very complicated because there
275 * are multiple X server code bases (with multiple versioning
276 * schemes within a code base), and multiple bugs.
278 * The X servers:
280 * 1. The Vendor=="XFree86" code base with release numbers such
281 * as 4.7.0 (VendorRelease==40700000).
283 * 2. The Vendor=="X.Org" code base (a descendant of the
284 * XFree86 code base). It originally had things like
285 * VendorRelease==60700000 for release 6.7.0 but then changed
286 * its versioning scheme so that, for example,
287 * VendorRelease==10400000 for the 1.4.0 X server within the
288 * X.Org 7.3 release.
290 * The bugs:
292 * 1. The original bug that led to the buggy_repeat
293 * workaround. This was a bug that Owen Taylor investigated,
294 * understood well, and characterized against various X
295 * servers. Confirmed X servers with this bug include:
297 * "XFree86" <= 40500000
298 * "X.Org" <= 60802000 (only with old numbering >= 60700000)
300 * 2. A separate bug resulting in a crash of the X server when
301 * using cairo's extend-reflect test case, (which, surprisingly
302 * enough was not passing RepeatReflect to the X server, but
303 * instead using RepeatNormal in a workaround). Nobody to date
304 * has understood the bug well, but it appears to be gone as of
305 * the X.Org 1.4.0 server. This bug is coincidentally avoided
306 * by using the same buggy_repeat workaround. Confirmed X
307 * servers with this bug include:
309 * "X.org" == 60900000 (old versioning scheme)
310 * "X.org" < 10400000 (new numbering scheme)
312 * For the old-versioning-scheme X servers we don't know
313 * exactly when second the bug started, but since bug 1 is
314 * present through 6.8.2 and bug 2 is present in 6.9.0 it seems
315 * safest to just blacklist all old-versioning-scheme X servers,
316 * (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
318 if (_cairo_xlib_vendor_is_xorg (dpy)) {
319 if (VendorRelease (dpy) >= 60700000) {
320 if (VendorRelease (dpy) < 70000000)
321 display->buggy_repeat = TRUE;
323 /* We know that gradients simply do not work in early Xorg servers */
324 if (VendorRelease (dpy) < 70200000)
325 display->buggy_gradients = TRUE;
327 /* And the extended repeat modes were not fixed until much later */
328 display->buggy_pad_reflect = TRUE;
329 } else {
330 if (VendorRelease (dpy) < 10400000)
331 display->buggy_repeat = TRUE;
333 /* Too many bugs in the early drivers */
334 if (VendorRelease (dpy) < 10699000)
335 display->buggy_pad_reflect = TRUE;
337 } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
338 if (VendorRelease (dpy) <= 40500000)
339 display->buggy_repeat = TRUE;
341 display->buggy_gradients = TRUE;
342 display->buggy_pad_reflect = TRUE;
345 codes = XAddExtension (dpy);
346 if (unlikely (codes == NULL)) {
347 device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
348 free (display);
349 goto UNLOCK;
352 XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
353 cairo_device_reference (&display->base); /* add one for the CloseDisplay */
355 display->next = _cairo_xlib_display_list;
356 _cairo_xlib_display_list = display;
358 device = &display->base;
360 UNLOCK:
361 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
362 return device;
365 cairo_status_t
366 _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
368 cairo_status_t status;
370 status = cairo_device_acquire (device);
371 if (status)
372 return status;
374 *display = (cairo_xlib_display_t *) device;
375 return CAIRO_STATUS_SUCCESS;
378 XRenderPictFormat *
379 _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
380 pixman_format_code_t format)
382 Display *dpy = display->display;
383 XRenderPictFormat tmpl;
384 int mask;
386 #define MASK(x) ((1<<(x))-1)
388 tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
389 mask = PictFormatType | PictFormatDepth;
391 switch (PIXMAN_FORMAT_TYPE(format)) {
392 case PIXMAN_TYPE_ARGB:
393 tmpl.type = PictTypeDirect;
395 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
396 if (PIXMAN_FORMAT_A(format))
397 tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
398 PIXMAN_FORMAT_G(format) +
399 PIXMAN_FORMAT_B(format));
401 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
402 tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
403 PIXMAN_FORMAT_B(format));
405 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
406 tmpl.direct.green = PIXMAN_FORMAT_B(format);
408 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
409 tmpl.direct.blue = 0;
411 mask |= PictFormatRed | PictFormatRedMask;
412 mask |= PictFormatGreen | PictFormatGreenMask;
413 mask |= PictFormatBlue | PictFormatBlueMask;
414 mask |= PictFormatAlpha | PictFormatAlphaMask;
415 break;
417 case PIXMAN_TYPE_ABGR:
418 tmpl.type = PictTypeDirect;
420 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
421 if (tmpl.direct.alphaMask)
422 tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
423 PIXMAN_FORMAT_G(format) +
424 PIXMAN_FORMAT_R(format));
426 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
427 tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
428 PIXMAN_FORMAT_R(format));
430 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
431 tmpl.direct.green = PIXMAN_FORMAT_R(format);
433 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
434 tmpl.direct.red = 0;
436 mask |= PictFormatRed | PictFormatRedMask;
437 mask |= PictFormatGreen | PictFormatGreenMask;
438 mask |= PictFormatBlue | PictFormatBlueMask;
439 mask |= PictFormatAlpha | PictFormatAlphaMask;
440 break;
442 case PIXMAN_TYPE_BGRA:
443 tmpl.type = PictTypeDirect;
445 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
446 tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
448 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
449 tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
450 PIXMAN_FORMAT_G(format));
452 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
453 tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
454 PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
456 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
457 tmpl.direct.alpha = 0;
459 mask |= PictFormatRed | PictFormatRedMask;
460 mask |= PictFormatGreen | PictFormatGreenMask;
461 mask |= PictFormatBlue | PictFormatBlueMask;
462 mask |= PictFormatAlpha | PictFormatAlphaMask;
463 break;
465 case PIXMAN_TYPE_A:
466 tmpl.type = PictTypeDirect;
468 tmpl.direct.alpha = 0;
469 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
471 mask |= PictFormatAlpha | PictFormatAlphaMask;
472 break;
474 case PIXMAN_TYPE_COLOR:
475 case PIXMAN_TYPE_GRAY:
476 /* XXX Find matching visual/colormap */
477 tmpl.type = PictTypeIndexed;
478 //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
479 //mask |= PictFormatColormap;
480 return NULL;
482 #undef MASK
484 /* XXX caching? */
485 return XRenderFindFormat(dpy, mask, &tmpl, 0);
488 XRenderPictFormat *
489 _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
490 cairo_format_t format)
492 XRenderPictFormat *xrender_format;
494 xrender_format = display->cached_xrender_formats[format];
495 if (xrender_format == NULL) {
496 int pict_format = PictStandardNUM;
498 switch (format) {
499 case CAIRO_FORMAT_A1:
500 pict_format = PictStandardA1; break;
501 case CAIRO_FORMAT_A8:
502 pict_format = PictStandardA8; break;
503 case CAIRO_FORMAT_RGB24:
504 pict_format = PictStandardRGB24; break;
505 case CAIRO_FORMAT_RGB16_565:
506 xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
507 PIXMAN_r5g6b5);
508 break;
509 case CAIRO_FORMAT_RGB30:
510 xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
511 PIXMAN_x2r10g10b10);
512 break;
513 case CAIRO_FORMAT_INVALID:
514 default:
515 ASSERT_NOT_REACHED;
516 case CAIRO_FORMAT_ARGB32:
517 pict_format = PictStandardARGB32; break;
519 if (pict_format != PictStandardNUM)
520 xrender_format =
521 XRenderFindStandardFormat (display->display, pict_format);
522 display->cached_xrender_formats[format] = xrender_format;
525 return xrender_format;
528 cairo_xlib_screen_t *
529 _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
530 Screen *screen)
532 cairo_xlib_screen_t *info;
534 cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
535 if (info->screen == screen) {
536 if (display->screens.next != &info->link)
537 cairo_list_move (&info->link, &display->screens);
538 return info;
542 return NULL;
545 cairo_bool_t
546 _cairo_xlib_display_has_repeat (cairo_device_t *device)
548 return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
551 cairo_bool_t
552 _cairo_xlib_display_has_reflect (cairo_device_t *device)
554 return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
557 cairo_bool_t
558 _cairo_xlib_display_has_gradients (cairo_device_t *device)
560 return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
564 * cairo_xlib_device_debug_cap_xrender_version:
565 * @device: a #cairo_device_t for the Xlib backend
566 * @major_version: major version to restrict to
567 * @minor_version: minor version to restrict to
569 * Restricts all future Xlib surfaces for this devices to the specified version
570 * of the RENDER extension. This function exists solely for debugging purpose.
571 * It lets you find out how cairo would behave with an older version of
572 * the RENDER extension.
574 * Use the special values -1 and -1 for disabling the RENDER extension.
576 * Since: 1.12
578 void
579 cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
580 int major_version,
581 int minor_version)
583 cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
585 if (device == NULL || device->status)
586 return;
588 if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
589 return;
591 if (major_version < display->render_major ||
592 (major_version == display->render_major &&
593 minor_version < display->render_minor))
595 display->render_major = major_version;
596 display->render_minor = minor_version;
599 _cairo_xlib_display_select_compositor (display);
603 * cairo_xlib_device_debug_set_precision:
604 * @device: a #cairo_device_t for the Xlib backend
605 * @precision: the precision to use
607 * Render supports two modes of precision when rendering trapezoids. Set
608 * the precision to the desired mode.
610 * Since: 1.12
612 void
613 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
614 int precision)
616 if (device == NULL || device->status)
617 return;
618 if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
619 cairo_status_t status;
621 status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
622 (void) status;
623 return;
626 ((cairo_xlib_display_t *) device)->force_precision = precision;
630 * cairo_xlib_device_debug_get_precision:
631 * @device: a #cairo_device_t for the Xlib backend
633 * Get the Xrender precision mode.
635 * Returns: the render precision mode
637 * Since: 1.12
640 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
642 if (device == NULL || device->status)
643 return -1;
644 if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
645 cairo_status_t status;
647 status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
648 (void) status;
649 return -1;
652 return ((cairo_xlib_display_t *) device)->force_precision;
655 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */