1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
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.
29 * Chris Wilson <chris@chris-wilson.co.uk>
35 #include "cairo-xcb-private.h"
36 #include "cairo-hash-private.h"
37 #include "cairo-freelist-private.h"
38 #include "cairo-list-inline.h"
40 #include <xcb/xcbext.h>
41 #include <xcb/bigreq.h>
44 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
50 typedef struct _cairo_xcb_xrender_format
{
51 cairo_hash_entry_t key
;
52 xcb_render_pictformat_t xrender_format
;
53 } cairo_xcb_xrender_format_t
;
55 typedef struct _cairo_xcb_xid
{
60 #define XCB_RENDER_AT_LEAST(V, major, minor) \
61 (((V)->major_version > major) || \
62 (((V)->major_version == major) && ((V)->minor_version >= minor)))
64 #define XCB_RENDER_HAS_CREATE_PICTURE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
65 #define XCB_RENDER_HAS_COMPOSITE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
66 #define XCB_RENDER_HAS_COMPOSITE_TEXT(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
68 #define XCB_RENDER_HAS_FILL_RECTANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 1)
70 #define XCB_RENDER_HAS_DISJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
71 #define XCB_RENDER_HAS_CONJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
73 #define XCB_RENDER_HAS_TRAPEZOIDS(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
74 #define XCB_RENDER_HAS_TRIANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
75 #define XCB_RENDER_HAS_TRISTRIP(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
76 #define XCB_RENDER_HAS_TRIFAN(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
78 #define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
79 #define XCB_RENDER_HAS_FILTERS(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
80 #define XCB_RENDER_HAS_FILTER_GOOD(surface) FALSE
81 #define XCB_RENDER_HAS_FILTER_BEST(surface) FALSE
82 #define XCB_RENDER_HAS_SUBPIXEL_ORDER(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
84 #define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
85 #define XCB_RENDER_HAS_GRADIENTS(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
87 #define XCB_RENDER_HAS_PDF_OPERATORS(surface) XCB_RENDER_AT_LEAST((surface), 0, 11)
89 static cairo_list_t connections
;
92 _cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t
*connection
,
93 const xcb_render_query_pict_formats_reply_t
*formats
)
95 xcb_render_pictscreen_iterator_t screens
;
96 xcb_render_pictdepth_iterator_t depths
;
97 xcb_render_pictvisual_iterator_t visuals
;
99 for (screens
= xcb_render_query_pict_formats_screens_iterator (formats
);
101 xcb_render_pictscreen_next (&screens
))
103 for (depths
= xcb_render_pictscreen_depths_iterator (screens
.data
);
105 xcb_render_pictdepth_next (&depths
))
107 for (visuals
= xcb_render_pictdepth_visuals_iterator (depths
.data
);
109 xcb_render_pictvisual_next (&visuals
))
111 cairo_xcb_xrender_format_t
*f
;
112 cairo_status_t status
;
114 f
= malloc (sizeof (cairo_xcb_xrender_format_t
));
115 if (unlikely (f
== NULL
))
116 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
118 f
->key
.hash
= visuals
.data
->visual
;
119 f
->xrender_format
= visuals
.data
->format
;
120 status
= _cairo_hash_table_insert (connection
->visual_to_xrender_format
,
122 if (unlikely (status
))
128 return CAIRO_STATUS_SUCCESS
;
132 static xcb_format_t
*
133 find_format_for_depth (const xcb_setup_t
*setup
, uint8_t depth
)
135 xcb_format_t
*fmt
= xcb_setup_pixmap_formats (setup
);
136 xcb_format_t
*fmtend
= fmt
+ xcb_setup_pixmap_formats_length (setup
);
138 for (; fmt
!= fmtend
; ++fmt
)
139 if (fmt
->depth
== depth
)
146 static cairo_status_t
147 _cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t
*connection
,
148 const xcb_render_query_pict_formats_reply_t
*formats
)
150 xcb_render_pictforminfo_iterator_t i
;
151 cairo_status_t status
;
153 for (i
= xcb_render_query_pict_formats_formats_iterator (formats
);
155 xcb_render_pictforminfo_next (&i
))
157 cairo_format_masks_t masks
;
158 pixman_format_code_t pixman_format
;
160 if (i
.data
->type
!= XCB_RENDER_PICT_TYPE_DIRECT
)
164 (unsigned long) i
.data
->direct
.alpha_mask
<< i
.data
->direct
.alpha_shift
;
166 (unsigned long) i
.data
->direct
.red_mask
<< i
.data
->direct
.red_shift
;
168 (unsigned long) i
.data
->direct
.green_mask
<< i
.data
->direct
.green_shift
;
170 (unsigned long) i
.data
->direct
.blue_mask
<< i
.data
->direct
.blue_shift
;
171 masks
.bpp
= i
.data
->depth
;
173 if (_pixman_format_from_masks (&masks
, &pixman_format
)) {
174 cairo_hash_entry_t key
;
176 key
.hash
= pixman_format
;
177 if (! _cairo_hash_table_lookup (connection
->xrender_formats
, &key
)) {
178 cairo_xcb_xrender_format_t
*f
;
180 f
= malloc (sizeof (cairo_xcb_xrender_format_t
));
181 if (unlikely (f
== NULL
))
182 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
184 f
->key
.hash
= pixman_format
;
185 f
->xrender_format
= i
.data
->id
;
186 status
= _cairo_hash_table_insert (connection
->xrender_formats
,
188 if (unlikely (status
))
192 printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
200 PIXMAN_FORMAT_DEPTH(pixman_format
),
201 PIXMAN_FORMAT_BPP(pixman_format
));
207 status
= _cairo_xcb_connection_find_visual_formats (connection
, formats
);
208 if (unlikely (status
))
211 connection
->standard_formats
[CAIRO_FORMAT_A1
] =
212 _cairo_xcb_connection_get_xrender_format (connection
, PIXMAN_a1
);
214 connection
->standard_formats
[CAIRO_FORMAT_A8
] =
215 _cairo_xcb_connection_get_xrender_format (connection
, PIXMAN_a8
);
217 connection
->standard_formats
[CAIRO_FORMAT_RGB24
] =
218 _cairo_xcb_connection_get_xrender_format (connection
,
222 if (connection
->standard_formats
[CAIRO_FORMAT_RGB24
] == XCB_NONE
) {
223 connection
->standard_formats
[CAIRO_FORMAT_RGB24
] =
224 _cairo_xcb_connection_get_xrender_format (connection
,
225 PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR
,
229 connection
->standard_formats
[CAIRO_FORMAT_ARGB32
] =
230 _cairo_xcb_connection_get_xrender_format (connection
, PIXMAN_a8r8g8b8
);
231 if (connection
->standard_formats
[CAIRO_FORMAT_ARGB32
] == XCB_NONE
) {
232 connection
->standard_formats
[CAIRO_FORMAT_ARGB32
] =
233 _cairo_xcb_connection_get_xrender_format (connection
, PIXMAN_a8b8g8r8
);
236 return CAIRO_STATUS_SUCCESS
;
240 * We require support for depth 1, 8, 24 and 32 pixmaps
242 #define DEPTH_MASK(d) (1 << ((d) - 1))
243 #define REQUIRED_DEPTHS (DEPTH_MASK(1) | \
248 pixmap_depths_usable (cairo_xcb_connection_t
*connection
,
252 xcb_connection_t
*c
= connection
->xcb_connection
;
253 xcb_void_cookie_t create_cookie
[32];
255 cairo_bool_t success
= TRUE
;
258 pixmap
= _cairo_xcb_connection_get_xid (connection
);
260 for (depth
= 1, i
= 0; depth
<= 32; depth
++) {
261 if (missing
& DEPTH_MASK(depth
)) {
262 create_cookie
[i
] = xcb_create_pixmap_checked (c
, depth
, pixmap
, root
, 1, 1);
263 xcb_free_pixmap (c
, pixmap
);
264 if (!create_cookie
[i
].sequence
) {
272 for (j
= 0; j
< i
; j
++) {
273 xcb_generic_error_t
*create_error
= xcb_request_check (c
, create_cookie
[j
]);
274 success
&= create_error
== NULL
;
278 _cairo_xcb_connection_put_xid (connection
, pixmap
);
284 has_required_depths (cairo_xcb_connection_t
*connection
)
286 xcb_screen_iterator_t screens
;
288 for (screens
= xcb_setup_roots_iterator (connection
->root
);
290 xcb_screen_next (&screens
))
292 xcb_depth_iterator_t depths
;
293 uint32_t missing
= REQUIRED_DEPTHS
;
295 for (depths
= xcb_screen_allowed_depths_iterator (screens
.data
);
297 xcb_depth_next (&depths
))
299 missing
&= ~DEPTH_MASK (depths
.data
->depth
);
305 * Ok, this is ugly. It should be sufficient at this
306 * point to just return false, but Xinerama is broken at
307 * this point and only advertises depths which have an
308 * associated visual. Of course, the other depths still
309 * work, but the only way to find out is to try them.
311 if (! pixmap_depths_usable (connection
, missing
, screens
.data
->root
))
318 static xcb_render_query_version_reply_t
*
319 _render_restrict_env(xcb_render_query_version_reply_t
*version
)
326 env
= getenv ("CAIRO_DEBUG");
328 env
= strstr (env
, "xrender-version=");
330 int max_render_major
, max_render_minor
;
332 env
+= sizeof ("xrender-version=") - 1;
333 if (sscanf (env
, "%d.%d", &max_render_major
, &max_render_minor
) != 2)
334 max_render_major
= max_render_minor
= -1;
336 if (max_render_major
< 0 || max_render_minor
< 0) {
341 if (max_render_major
< (int) version
->major_version
||
342 (max_render_major
== (int) version
->major_version
&&
343 max_render_minor
< (int) version
->minor_version
))
345 version
->major_version
= max_render_major
;
346 version
->minor_version
= max_render_minor
;
353 static cairo_status_t
354 _cairo_xcb_connection_query_render (cairo_xcb_connection_t
*connection
)
356 xcb_connection_t
*c
= connection
->xcb_connection
;
357 xcb_render_query_version_cookie_t version_cookie
;
358 xcb_render_query_pict_formats_cookie_t formats_cookie
;
359 xcb_render_query_version_reply_t
*version
;
360 xcb_render_query_pict_formats_reply_t
*formats
;
361 cairo_status_t status
;
362 cairo_bool_t present
;
364 version_cookie
= xcb_render_query_version (c
, XCB_RENDER_MAJOR_VERSION
, XCB_RENDER_MINOR_VERSION
);
365 formats_cookie
= xcb_render_query_pict_formats (c
);
367 present
= has_required_depths (connection
);
368 version
= xcb_render_query_version_reply (c
, version_cookie
, 0);
369 formats
= xcb_render_query_pict_formats_reply (c
, formats_cookie
, 0);
371 version
= _render_restrict_env (version
);
373 if (! present
|| version
== NULL
|| formats
== NULL
) {
376 return CAIRO_STATUS_SUCCESS
;
379 /* always true if the extension is present (i.e. >= 0.0) */
380 connection
->flags
|= CAIRO_XCB_HAS_RENDER
;
381 connection
->flags
|= CAIRO_XCB_RENDER_HAS_COMPOSITE
;
382 connection
->flags
|= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS
;
384 if (XCB_RENDER_HAS_FILL_RECTANGLES (version
))
385 connection
->flags
|= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
;
387 if (XCB_RENDER_HAS_TRAPEZOIDS (version
))
388 connection
->flags
|= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
;
390 if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version
))
391 connection
->flags
|= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM
;
393 if (XCB_RENDER_HAS_FILTERS (version
))
394 connection
->flags
|= CAIRO_XCB_RENDER_HAS_FILTERS
;
396 if (XCB_RENDER_HAS_FILTER_GOOD (version
))
397 connection
->flags
|= CAIRO_XCB_RENDER_HAS_FILTER_GOOD
;
399 if (XCB_RENDER_HAS_FILTER_BEST (version
))
400 connection
->flags
|= CAIRO_XCB_RENDER_HAS_FILTER_BEST
;
402 if (XCB_RENDER_HAS_PDF_OPERATORS (version
))
403 connection
->flags
|= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS
;
405 if (XCB_RENDER_HAS_EXTENDED_REPEAT (version
))
406 connection
->flags
|= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT
;
408 if (XCB_RENDER_HAS_GRADIENTS (version
))
409 connection
->flags
|= CAIRO_XCB_RENDER_HAS_GRADIENTS
;
411 if (XCB_RENDER_HAS_SUBPIXEL_ORDER (version
)) {
413 uint32_t *subpixel
= xcb_render_query_pict_formats_subpixels(formats
);
415 /* The spec explicitly allows to have too few entries in the reply... */
416 for (screen
= 0; screen
< formats
->num_subpixel
&& screen
< connection
->root
->roots_len
; screen
++)
417 connection
->subpixel_orders
[screen
] = subpixel
[screen
];
422 status
= _cairo_xcb_connection_parse_xrender_formats (connection
, formats
);
430 _cairo_xcb_connection_query_cairo (cairo_xcb_connection_t
*connection
)
432 xcb_connection_t
*c
= connection
->xcb_connection
;
433 xcb_cairo_query_version_reply_t
*version
;
435 version
= xcb_cairo_query_version_reply (c
,
436 xcb_cairo_query_version (c
, 0, 0),
443 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
445 can_use_shm (cairo_xcb_connection_t
*connection
)
447 cairo_bool_t success
= TRUE
;
448 xcb_connection_t
*c
= connection
->xcb_connection
;
449 xcb_void_cookie_t cookie
[2];
450 xcb_generic_error_t
*error
;
455 shmid
= shmget (IPC_PRIVATE
, 0x1000, IPC_CREAT
| 0600);
459 ptr
= shmat (shmid
, NULL
, 0);
460 if (ptr
== (char *) -1) {
461 shmctl (shmid
, IPC_RMID
, NULL
);
465 shmseg
= _cairo_xcb_connection_get_xid (connection
);
466 cookie
[0] = xcb_shm_attach_checked (c
, shmseg
, shmid
, FALSE
);
467 cookie
[1] = xcb_shm_detach_checked (c
, shmseg
);
468 _cairo_xcb_connection_put_xid (connection
, shmseg
);
470 error
= xcb_request_check (c
, cookie
[0]);
474 error
= xcb_request_check (c
, cookie
[1]);
478 shmctl (shmid
, IPC_RMID
, NULL
);
485 _cairo_xcb_connection_query_shm (cairo_xcb_connection_t
*connection
)
487 xcb_connection_t
*c
= connection
->xcb_connection
;
488 xcb_shm_query_version_reply_t
*version
;
490 version
= xcb_shm_query_version_reply (c
, xcb_shm_query_version (c
), 0);
496 if (can_use_shm (connection
))
497 connection
->flags
|= CAIRO_XCB_HAS_SHM
;
501 static cairo_status_t
502 _device_flush (void *device
)
504 cairo_xcb_connection_t
*connection
= device
;
505 cairo_status_t status
;
507 status
= cairo_device_acquire (&connection
->device
);
508 if (unlikely (status
))
511 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
512 _cairo_xcb_connection_shm_mem_pools_flush (connection
);
515 xcb_flush (connection
->xcb_connection
);
517 cairo_device_release (&connection
->device
);
518 return CAIRO_STATUS_SUCCESS
;
522 _pluck_xrender_format (void *entry
,
525 _cairo_hash_table_remove (closure
, entry
);
530 _device_finish (void *device
)
532 cairo_xcb_connection_t
*connection
= device
;
533 cairo_bool_t was_cached
= FALSE
;
535 if (! cairo_list_is_empty (&connection
->link
)) {
536 CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex
);
537 cairo_list_del (&connection
->link
);
538 CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex
);
542 while (! cairo_list_is_empty (&connection
->fonts
)) {
543 cairo_xcb_font_t
*font
;
545 font
= cairo_list_first_entry (&connection
->fonts
,
548 _cairo_xcb_font_close (font
);
551 while (! cairo_list_is_empty (&connection
->screens
)) {
552 cairo_xcb_screen_t
*screen
;
554 screen
= cairo_list_first_entry (&connection
->screens
,
557 _cairo_xcb_screen_finish (screen
);
560 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
561 /* _cairo_xcb_screen_finish finishes surfaces. If any of those surfaces had
562 * a fallback image, we might have done a SHM PutImage. */
563 _cairo_xcb_connection_shm_mem_pools_flush (connection
);
567 cairo_device_destroy (device
);
571 _device_destroy (void *device
)
573 cairo_xcb_connection_t
*connection
= device
;
575 _cairo_hash_table_foreach (connection
->xrender_formats
,
576 _pluck_xrender_format
, connection
->xrender_formats
);
577 _cairo_hash_table_destroy (connection
->xrender_formats
);
579 _cairo_hash_table_foreach (connection
->visual_to_xrender_format
,
580 _pluck_xrender_format
,
581 connection
->visual_to_xrender_format
);
582 _cairo_hash_table_destroy (connection
->visual_to_xrender_format
);
584 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
585 _cairo_xcb_connection_shm_mem_pools_fini (connection
);
587 _cairo_freepool_fini (&connection
->shm_info_freelist
);
589 _cairo_freepool_fini (&connection
->xid_pool
);
591 CAIRO_MUTEX_FINI (connection
->shm_mutex
);
592 CAIRO_MUTEX_FINI (connection
->screens_mutex
);
594 free (connection
->subpixel_orders
);
598 static const cairo_device_backend_t _cairo_xcb_device_backend
= {
599 CAIRO_DEVICE_TYPE_XCB
,
601 NULL
, NULL
, /* lock, unlock */
608 cairo_xcb_connection_t
*
609 _cairo_xcb_connection_get (xcb_connection_t
*xcb_connection
)
611 cairo_xcb_connection_t
*connection
;
612 const xcb_query_extension_reply_t
*ext
;
613 cairo_status_t status
;
615 CAIRO_MUTEX_INITIALIZE ();
617 CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex
);
618 if (connections
.next
== NULL
) {
619 /* XXX _cairo_init () */
620 cairo_list_init (&connections
);
623 cairo_list_foreach_entry (connection
,
624 cairo_xcb_connection_t
,
628 if (connection
->xcb_connection
== xcb_connection
) {
629 /* Maintain MRU order. */
630 if (connections
.next
!= &connection
->link
)
631 cairo_list_move (&connection
->link
, &connections
);
637 connection
= malloc (sizeof (cairo_xcb_connection_t
));
638 if (unlikely (connection
== NULL
))
641 _cairo_device_init (&connection
->device
, &_cairo_xcb_device_backend
);
643 connection
->xcb_connection
= xcb_connection
;
645 cairo_list_init (&connection
->fonts
);
646 cairo_list_init (&connection
->screens
);
647 cairo_list_init (&connection
->link
);
648 connection
->xrender_formats
= _cairo_hash_table_create (NULL
);
649 if (connection
->xrender_formats
== NULL
) {
650 CAIRO_MUTEX_FINI (connection
->device
.mutex
);
656 connection
->visual_to_xrender_format
= _cairo_hash_table_create (NULL
);
657 if (connection
->visual_to_xrender_format
== NULL
) {
658 _cairo_hash_table_destroy (connection
->xrender_formats
);
659 CAIRO_MUTEX_FINI (connection
->device
.mutex
);
665 cairo_list_init (&connection
->free_xids
);
666 _cairo_freepool_init (&connection
->xid_pool
,
667 sizeof (cairo_xcb_xid_t
));
669 cairo_list_init (&connection
->shm_pools
);
670 cairo_list_init (&connection
->shm_pending
);
671 _cairo_freepool_init (&connection
->shm_info_freelist
,
672 sizeof (cairo_xcb_shm_info_t
));
674 connection
->maximum_request_length
=
675 xcb_get_maximum_request_length (xcb_connection
);
677 CAIRO_MUTEX_INIT (connection
->shm_mutex
);
678 CAIRO_MUTEX_INIT (connection
->screens_mutex
);
680 CAIRO_MUTEX_LOCK (connection
->device
.mutex
);
682 connection
->flags
= 0;
683 connection
->force_precision
= -1;
685 xcb_prefetch_extension_data (xcb_connection
, &xcb_big_requests_id
);
686 xcb_prefetch_extension_data (xcb_connection
, &xcb_render_id
);
687 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
688 xcb_prefetch_extension_data (xcb_connection
, &xcb_shm_id
);
691 xcb_prefetch_extension_data (xcb_connection
, &xcb_cairo_id
);
694 xcb_prefetch_maximum_request_length (xcb_connection
);
696 connection
->root
= xcb_get_setup (xcb_connection
);
697 connection
->render
= NULL
;
698 connection
->subpixel_orders
= calloc (connection
->root
->roots_len
, sizeof(*connection
->subpixel_orders
));
699 if (unlikely (connection
->subpixel_orders
== NULL
)) {
700 CAIRO_MUTEX_UNLOCK (connection
->device
.mutex
);
701 _cairo_xcb_connection_destroy (connection
);
706 ext
= xcb_get_extension_data (xcb_connection
, &xcb_render_id
);
707 if (ext
!= NULL
&& ext
->present
) {
708 status
= _cairo_xcb_connection_query_render (connection
);
709 if (unlikely (status
)) {
710 CAIRO_MUTEX_UNLOCK (connection
->device
.mutex
);
711 _cairo_xcb_connection_destroy (connection
);
716 connection
->render
= ext
;
720 ext
= xcb_get_extension_data (connection
, &xcb_cairo_id
);
721 if (ext
!= NULL
&& ext
->present
)
722 _cairo_xcb_connection_query_cairo (connection
);
725 connection
->shm
= NULL
;
726 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
727 ext
= xcb_get_extension_data (xcb_connection
, &xcb_shm_id
);
728 if (ext
!= NULL
&& ext
->present
) {
729 _cairo_xcb_connection_query_shm (connection
);
730 connection
->shm
= ext
;
734 connection
->original_flags
= connection
->flags
;
736 CAIRO_MUTEX_UNLOCK (connection
->device
.mutex
);
738 cairo_list_add (&connection
->link
, &connections
);
740 CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex
);
745 xcb_render_pictformat_t
746 _cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t
*connection
,
747 pixman_format_code_t pixman_format
)
749 cairo_hash_entry_t key
;
750 cairo_xcb_xrender_format_t
*format
;
752 key
.hash
= pixman_format
;
753 format
= _cairo_hash_table_lookup (connection
->xrender_formats
, &key
);
754 return format
? format
->xrender_format
: XCB_NONE
;
757 xcb_render_pictformat_t
758 _cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t
*connection
,
759 const xcb_visualid_t visual
)
761 cairo_hash_entry_t key
;
762 cairo_xcb_xrender_format_t
*format
;
765 format
= _cairo_hash_table_lookup (connection
->visual_to_xrender_format
, &key
);
766 return format
? format
->xrender_format
: XCB_NONE
;
770 _cairo_xcb_connection_put_xid (cairo_xcb_connection_t
*connection
,
773 cairo_xcb_xid_t
*cache
;
775 assert (CAIRO_MUTEX_IS_LOCKED (connection
->device
.mutex
));
776 cache
= _cairo_freepool_alloc (&connection
->xid_pool
);
777 if (likely (cache
!= NULL
)) {
779 cairo_list_add (&cache
->link
, &connection
->free_xids
);
784 _cairo_xcb_connection_get_xid (cairo_xcb_connection_t
*connection
)
788 assert (CAIRO_MUTEX_IS_LOCKED (connection
->device
.mutex
));
789 if (! cairo_list_is_empty (&connection
->free_xids
)) {
790 cairo_xcb_xid_t
*cache
;
792 cache
= cairo_list_first_entry (&connection
->free_xids
,
797 cairo_list_del (&cache
->link
);
798 _cairo_freepool_free (&connection
->xid_pool
, cache
);
800 xid
= xcb_generate_id (connection
->xcb_connection
);
807 * cairo_xcb_device_get_connection:
808 * @device: a #cairo_device_t for the XCB backend
810 * Get the connection for the XCB device.
812 * Returns: the #xcb_connection_t for the connection
817 cairo_xcb_device_get_connection (cairo_device_t
*device
)
819 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XCB
)
822 return ((cairo_xcb_connection_t
*)device
)->xcb_connection
;
825 /* public (debug) interface */
828 * cairo_xcb_device_debug_cap_xshm_version:
829 * @device: a #cairo_device_t for the XCB backend
830 * @major_version: major version to restrict to
831 * @minor_version: minor version to restrict to
833 * Restricts all future XCB surfaces for this devices to the specified version
834 * of the SHM extension. This function exists solely for debugging purpose.
835 * It let's you find out how cairo would behave with an older version of
838 * Use the special values -1 and -1 for disabling the SHM extension.
843 cairo_xcb_device_debug_cap_xshm_version (cairo_device_t
*device
,
847 cairo_xcb_connection_t
*connection
= (cairo_xcb_connection_t
*) device
;
849 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XCB
) {
850 cairo_status_t status
;
852 status
= _cairo_device_set_error (device
, CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
857 /* First reset all the SHM flags to their original value. This works
858 * because we only ever clear bits after the connection was created.
860 connection
->flags
|= (connection
->original_flags
& CAIRO_XCB_SHM_MASK
);
862 /* clear any flags that are inappropriate for the desired version */
863 if (major_version
< 0 && minor_version
< 0) {
864 connection
->flags
&= ~(CAIRO_XCB_HAS_SHM
);
869 * cairo_xcb_device_debug_cap_xrender_version:
870 * @device: a #cairo_device_t for the XCB backend
871 * @major_version: major version to restrict to
872 * @minor_version: minor version to restrict to
874 * Restricts all future XCB surfaces for this devices to the specified version
875 * of the RENDER extension. This function exists solely for debugging purpose.
876 * It let's you find out how cairo would behave with an older version of
877 * the RENDER extension.
879 * Use the special values -1 and -1 for disabling the RENDER extension.
884 cairo_xcb_device_debug_cap_xrender_version (cairo_device_t
*device
,
888 cairo_xcb_connection_t
*connection
= (cairo_xcb_connection_t
*) device
;
890 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XCB
) {
891 cairo_status_t status
;
893 status
= _cairo_device_set_error (device
, CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
898 /* First reset all the RENDER flags to their original value. This works
899 * because we only ever clear bits after the connection was created.
901 connection
->flags
|= (connection
->original_flags
& CAIRO_XCB_RENDER_MASK
);
903 /* clear any flags that are inappropriate for the desired version */
904 if (major_version
< 0 && minor_version
< 0) {
905 connection
->flags
&= ~(CAIRO_XCB_HAS_RENDER
|
906 CAIRO_XCB_RENDER_HAS_COMPOSITE
|
907 CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS
|
908 CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
|
909 CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
|
910 CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM
|
911 CAIRO_XCB_RENDER_HAS_FILTERS
|
912 CAIRO_XCB_RENDER_HAS_FILTER_GOOD
|
913 CAIRO_XCB_RENDER_HAS_FILTER_BEST
|
914 CAIRO_XCB_RENDER_HAS_PDF_OPERATORS
|
915 CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT
|
916 CAIRO_XCB_RENDER_HAS_GRADIENTS
);
918 xcb_render_query_version_reply_t version
;
920 version
.major_version
= major_version
;
921 version
.minor_version
= minor_version
;
923 if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version
))
924 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES
;
926 if (! XCB_RENDER_HAS_TRAPEZOIDS (&version
))
927 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS
;
929 if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version
))
930 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM
;
932 if (! XCB_RENDER_HAS_FILTERS (&version
))
933 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_FILTERS
;
935 if (! XCB_RENDER_HAS_PDF_OPERATORS (&version
))
936 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS
;
938 if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version
))
939 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT
;
941 if (! XCB_RENDER_HAS_GRADIENTS (&version
))
942 connection
->flags
&= ~CAIRO_XCB_RENDER_HAS_GRADIENTS
;
945 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
946 slim_hidden_def (cairo_xcb_device_debug_cap_xrender_version
);
950 * cairo_xcb_device_debug_set_precision:
951 * @device: a #cairo_device_t for the XCB backend
952 * @precision: the precision to use
954 * Render supports two modes of precision when rendering trapezoids. Set
955 * the precision to the desired mode.
960 cairo_xcb_device_debug_set_precision (cairo_device_t
*device
,
963 if (device
== NULL
|| device
->status
)
965 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XCB
) {
966 cairo_status_t status
;
968 status
= _cairo_device_set_error (device
, CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
973 ((cairo_xcb_connection_t
*) device
)->force_precision
= precision
;
975 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
976 slim_hidden_def (cairo_xcb_device_debug_set_precision
);
980 * cairo_xcb_device_debug_get_precision:
981 * @device: a #cairo_device_t for the XCB backend
983 * Get the Xrender precision mode.
985 * Returns: the render precision mode
990 cairo_xcb_device_debug_get_precision (cairo_device_t
*device
)
992 if (device
== NULL
|| device
->status
)
994 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_XCB
) {
995 cairo_status_t status
;
997 status
= _cairo_device_set_error (device
, CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
1002 return ((cairo_xcb_connection_t
*) device
)->force_precision
;
1004 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1005 slim_hidden_def (cairo_xcb_device_debug_get_precision
);