beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xcb-connection.c
blob67897fa4eccda197b8126a4ffe7ef427351eb289
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.
28 * Authors:
29 * Chris Wilson <chris@chris-wilson.co.uk>
33 #include "cairoint.h"
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>
42 #include <errno.h>
44 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
45 #include <sys/ipc.h>
46 #include <sys/shm.h>
47 #include <xcb/shm.h>
48 #endif
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 {
56 cairo_list_t link;
57 uint32_t xid;
58 } cairo_xcb_xid_t;
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;
91 static cairo_status_t
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);
100 screens.rem;
101 xcb_render_pictscreen_next (&screens))
103 for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
104 depths.rem;
105 xcb_render_pictdepth_next (&depths))
107 for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
108 visuals.rem;
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,
121 &f->key);
122 if (unlikely (status))
123 return status;
128 return CAIRO_STATUS_SUCCESS;
131 #if 0
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)
140 return fmt;
142 return 0;
144 #endif
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);
154 i.rem;
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)
161 continue;
163 masks.alpha_mask =
164 (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
165 masks.red_mask =
166 (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
167 masks.green_mask =
168 (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
169 masks.blue_mask =
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,
187 &f->key);
188 if (unlikely (status))
189 return status;
191 #if 0
192 printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
193 i.data->id,
194 masks.alpha_mask,
195 masks.red_mask,
196 masks.green_mask,
197 masks.blue_mask,
198 masks.bpp,
199 pixman_format,
200 PIXMAN_FORMAT_DEPTH(pixman_format),
201 PIXMAN_FORMAT_BPP(pixman_format));
202 #endif
207 status = _cairo_xcb_connection_find_visual_formats (connection, formats);
208 if (unlikely (status))
209 return 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,
219 PIXMAN_FORMAT (24,
220 PIXMAN_TYPE_ARGB,
221 0, 8, 8, 8));
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,
226 0, 8, 8, 8));
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) | \
244 DEPTH_MASK(8) | \
245 DEPTH_MASK(24) | \
246 DEPTH_MASK(32))
247 static cairo_bool_t
248 pixmap_depths_usable (cairo_xcb_connection_t *connection,
249 uint32_t missing,
250 xcb_drawable_t root)
252 xcb_connection_t *c = connection->xcb_connection;
253 xcb_void_cookie_t create_cookie[32];
254 xcb_pixmap_t pixmap;
255 cairo_bool_t success = TRUE;
256 int depth, i, j;
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) {
265 success = FALSE;
266 break;
268 i++;
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;
275 free (create_error);
278 _cairo_xcb_connection_put_xid (connection, pixmap);
280 return success;
283 static cairo_bool_t
284 has_required_depths (cairo_xcb_connection_t *connection)
286 xcb_screen_iterator_t screens;
288 for (screens = xcb_setup_roots_iterator (connection->root);
289 screens.rem;
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);
296 depths.rem;
297 xcb_depth_next (&depths))
299 missing &= ~DEPTH_MASK (depths.data->depth);
301 if (missing == 0)
302 continue;
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))
312 return FALSE;
315 return TRUE;
318 static xcb_render_query_version_reply_t *
319 _render_restrict_env(xcb_render_query_version_reply_t *version)
321 const char *env;
323 if (version == NULL)
324 return NULL;
326 env = getenv ("CAIRO_DEBUG");
327 if (env != NULL)
328 env = strstr (env, "xrender-version=");
329 if (env != NULL) {
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) {
337 free (version);
338 return NULL;
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;
350 return version;
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) {
374 free (version);
375 free (formats);
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)) {
412 uint32_t screen;
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];
420 free (version);
422 status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
423 free (formats);
425 return status;
428 #if 0
429 static void
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),
439 free (version);
441 #endif
443 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
444 static cairo_bool_t
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;
451 int shmid;
452 uint32_t shmseg;
453 void *ptr;
455 shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
456 if (shmid == -1)
457 return FALSE;
459 ptr = shmat (shmid, NULL, 0);
460 if (ptr == (char *) -1) {
461 shmctl (shmid, IPC_RMID, NULL);
462 return FALSE;
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]);
471 if (error != NULL)
472 success = FALSE;
474 error = xcb_request_check (c, cookie[1]);
475 if (error != NULL)
476 success = FALSE;
478 shmctl (shmid, IPC_RMID, NULL);
479 shmdt (ptr);
481 return success;
484 static void
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);
491 if (version == NULL)
492 return;
494 free (version);
496 if (can_use_shm (connection))
497 connection->flags |= CAIRO_XCB_HAS_SHM;
499 #endif
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))
509 return status;
511 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
512 _cairo_xcb_connection_shm_mem_pools_flush (connection);
513 #endif
515 xcb_flush (connection->xcb_connection);
517 cairo_device_release (&connection->device);
518 return CAIRO_STATUS_SUCCESS;
521 static void
522 _pluck_xrender_format (void *entry,
523 void *closure)
525 _cairo_hash_table_remove (closure, entry);
526 free (entry);
529 static void
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);
539 was_cached = TRUE;
542 while (! cairo_list_is_empty (&connection->fonts)) {
543 cairo_xcb_font_t *font;
545 font = cairo_list_first_entry (&connection->fonts,
546 cairo_xcb_font_t,
547 link);
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,
555 cairo_xcb_screen_t,
556 link);
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);
564 #endif
566 if (was_cached)
567 cairo_device_destroy (device);
570 static void
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);
586 #endif
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);
595 free (connection);
598 static const cairo_device_backend_t _cairo_xcb_device_backend = {
599 CAIRO_DEVICE_TYPE_XCB,
601 NULL, NULL, /* lock, unlock */
603 _device_flush,
604 _device_finish,
605 _device_destroy,
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,
625 &connections,
626 link)
628 if (connection->xcb_connection == xcb_connection) {
629 /* Maintain MRU order. */
630 if (connections.next != &connection->link)
631 cairo_list_move (&connection->link, &connections);
633 goto unlock;
637 connection = malloc (sizeof (cairo_xcb_connection_t));
638 if (unlikely (connection == NULL))
639 goto unlock;
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);
651 free (connection);
652 connection = NULL;
653 goto unlock;
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);
660 free (connection);
661 connection = NULL;
662 goto unlock;
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);
689 #endif
690 #if 0
691 xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
692 #endif
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);
702 connection = NULL;
703 goto unlock;
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);
712 connection = NULL;
713 goto unlock;
716 connection->render = ext;
719 #if 0
720 ext = xcb_get_extension_data (connection, &xcb_cairo_id);
721 if (ext != NULL && ext->present)
722 _cairo_xcb_connection_query_cairo (connection);
723 #endif
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;
732 #endif
734 connection->original_flags = connection->flags;
736 CAIRO_MUTEX_UNLOCK (connection->device.mutex);
738 cairo_list_add (&connection->link, &connections);
739 unlock:
740 CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
742 return connection;
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;
764 key.hash = visual;
765 format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
766 return format ? format->xrender_format : XCB_NONE;
769 void
770 _cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
771 uint32_t xid)
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)) {
778 cache->xid = xid;
779 cairo_list_add (&cache->link, &connection->free_xids);
783 uint32_t
784 _cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
786 uint32_t xid;
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,
793 cairo_xcb_xid_t,
794 link);
795 xid = cache->xid;
797 cairo_list_del (&cache->link);
798 _cairo_freepool_free (&connection->xid_pool, cache);
799 } else {
800 xid = xcb_generate_id (connection->xcb_connection);
803 return xid;
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
814 * Since: 1.12
816 xcb_connection_t *
817 cairo_xcb_device_get_connection (cairo_device_t *device)
819 if (device->backend->type != CAIRO_DEVICE_TYPE_XCB)
820 return NULL;
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
836 * the SHM extension.
838 * Use the special values -1 and -1 for disabling the SHM extension.
840 * Since: 1.12
842 void
843 cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
844 int major_version,
845 int minor_version)
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);
853 (void) status;
854 return;
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.
881 * Since: 1.12
883 void
884 cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
885 int major_version,
886 int minor_version)
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);
894 (void) status;
895 return;
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);
917 } else {
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);
947 #endif
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.
957 * Since: 1.12
959 void
960 cairo_xcb_device_debug_set_precision (cairo_device_t *device,
961 int precision)
963 if (device == NULL || device->status)
964 return;
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);
969 (void) status;
970 return;
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);
977 #endif
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
987 * Since: 1.12
990 cairo_xcb_device_debug_get_precision (cairo_device_t *device)
992 if (device == NULL || device->status)
993 return -1;
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);
998 (void) status;
999 return -1;
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);
1006 #endif