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"
44 #include "cairo-list-inline.h"
46 #include <X11/Xlibint.h> /* For XESetCloseDisplay */
48 typedef int (*cairo_xlib_error_func_t
) (Display
*display
,
51 static cairo_xlib_display_t
*_cairo_xlib_display_list
;
54 _noop_error_handler (Display
*display
,
57 return False
; /* return value is ignored */
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 */
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
,
81 while (! cairo_list_is_empty (&display
->screens
)) {
82 _cairo_xlib_screen_destroy (display
,
83 cairo_list_first_entry (&display
->screens
,
89 XSetErrorHandler (old_handler
);
91 cairo_device_release (&display
->base
);
96 _cairo_xlib_display_destroy (void *abstract_display
)
98 cairo_xlib_display_t
*display
= abstract_display
;
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
)
112 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex
);
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
) {
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 */
141 static const cairo_device_backend_t _cairo_xlib_device_backend
= {
142 CAIRO_DEVICE_TYPE_XLIB
,
148 _cairo_xlib_display_finish
,
149 _cairo_xlib_display_destroy
,
152 static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t
*display
)
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 ();
160 display
->compositor
= _cairo_xlib_core_compositor_get ();
162 display
->compositor
= _cairo_xlib_fallback_compositor_get ();
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
175 _cairo_xlib_device_create (Display
*dpy
)
177 cairo_xlib_display_t
*display
;
178 cairo_xlib_display_t
**prev
;
179 cairo_device_t
*device
;
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
) {
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
);
210 display
= malloc (sizeof (cairo_xlib_display_t
));
211 if (unlikely (display
== NULL
)) {
212 device
= _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY
);
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
;
269 display
->buggy_gradients
= FALSE
;
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.
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
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
;
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
);
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
;
361 CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex
);
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
);
374 *display
= (cairo_xlib_display_t
*) device
;
375 return CAIRO_STATUS_SUCCESS
;
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
;
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
;
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
));
436 mask
|= PictFormatRed
| PictFormatRedMask
;
437 mask
|= PictFormatGreen
| PictFormatGreenMask
;
438 mask
|= PictFormatBlue
| PictFormatBlueMask
;
439 mask
|= PictFormatAlpha
| PictFormatAlphaMask
;
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
;
466 tmpl
.type
= PictTypeDirect
;
468 tmpl
.direct
.alpha
= 0;
469 tmpl
.direct
.alphaMask
= MASK(PIXMAN_FORMAT_A(format
));
471 mask
|= PictFormatAlpha
| PictFormatAlphaMask
;
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;
485 return XRenderFindFormat(dpy
, mask
, &tmpl
, 0);
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
;
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
,
509 case CAIRO_FORMAT_RGB30
:
510 xrender_format
= _cairo_xlib_display_get_xrender_format_for_pixman(display
,
513 case CAIRO_FORMAT_INVALID
:
516 case CAIRO_FORMAT_ARGB32
:
517 pict_format
= PictStandardARGB32
; break;
519 if (pict_format
!= PictStandardNUM
)
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
,
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
);
546 _cairo_xlib_display_has_repeat (cairo_device_t
*device
)
548 return ! ((cairo_xlib_display_t
*) device
)->buggy_repeat
;
552 _cairo_xlib_display_has_reflect (cairo_device_t
*device
)
554 return ! ((cairo_xlib_display_t
*) device
)->buggy_pad_reflect
;
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.
579 cairo_xlib_device_debug_cap_xrender_version (cairo_device_t
*device
,
583 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*) device
;
585 if (device
== NULL
|| device
->status
)
588 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XLIB
)
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.
613 cairo_xlib_device_debug_set_precision (cairo_device_t
*device
,
616 if (device
== NULL
|| device
->status
)
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
);
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
640 cairo_xlib_device_debug_get_precision (cairo_device_t
*device
)
642 if (device
== NULL
|| device
->status
)
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
);
652 return ((cairo_xlib_display_t
*) device
)->force_precision
;
655 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */