b48add17b6ac3d528e50481055bba95af41d38e0
[framework/graphics/cairo.git] / src / cairo-xcb-connection.c
1 /* Cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Intel Corporation
4  *
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.
12  *
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
18  *
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/
23  *
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.
27  *
28  * Authors:
29  *    Chris Wilson <chris@chris-wilson.co.uk>
30  */
31
32
33 #include "cairoint.h"
34
35 #include "cairo-xcb-private.h"
36 #include "cairo-hash-private.h"
37 #include "cairo-freelist-private.h"
38 #include "cairo-list-inline.h"
39
40 #include <xcb/xcbext.h>
41 #include <xcb/bigreq.h>
42 #include <errno.h>
43
44 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
45 #include <sys/ipc.h>
46 #include <sys/shm.h>
47 #include <xcb/shm.h>
48 #endif
49
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;
54
55 typedef struct _cairo_xcb_xid {
56     cairo_list_t link;
57     uint32_t xid;
58 } cairo_xcb_xid_t;
59
60 #define XCB_RENDER_AT_LEAST(V, major, minor)    \
61         (((V)->major_version > major) ||                        \
62          (((V)->major_version == major) && ((V)->minor_version >= minor)))
63
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)
67
68 #define XCB_RENDER_HAS_FILL_RECTANGLES(surface)         XCB_RENDER_AT_LEAST((surface), 0, 1)
69
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)
72
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)
77
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
81 #define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
82 #define XCB_RENDER_HAS_GRADIENTS(surface)       XCB_RENDER_AT_LEAST((surface), 0, 10)
83
84 #define XCB_RENDER_HAS_PDF_OPERATORS(surface)   XCB_RENDER_AT_LEAST((surface), 0, 11)
85
86 static cairo_list_t connections;
87
88 static cairo_status_t
89 _cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection,
90                                           const xcb_render_query_pict_formats_reply_t *formats)
91 {
92     xcb_render_pictscreen_iterator_t screens;
93     xcb_render_pictdepth_iterator_t depths;
94     xcb_render_pictvisual_iterator_t visuals;
95
96     for (screens = xcb_render_query_pict_formats_screens_iterator (formats);
97          screens.rem;
98          xcb_render_pictscreen_next (&screens))
99     {
100         for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
101              depths.rem;
102              xcb_render_pictdepth_next (&depths))
103         {
104             for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
105                  visuals.rem;
106                  xcb_render_pictvisual_next (&visuals))
107             {
108                 cairo_xcb_xrender_format_t *f;
109                 cairo_status_t status;
110
111                 f = malloc (sizeof (cairo_xcb_xrender_format_t));
112                 if (unlikely (f == NULL))
113                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
114
115                 f->key.hash = visuals.data->visual;
116                 f->xrender_format = visuals.data->format;
117                 status = _cairo_hash_table_insert (connection->visual_to_xrender_format,
118                                                    &f->key);
119                 if (unlikely (status))
120                     return status;
121             }
122         }
123     }
124
125     return CAIRO_STATUS_SUCCESS;
126 }
127
128 #if 0
129 static xcb_format_t *
130 find_format_for_depth (const xcb_setup_t *setup, uint8_t depth)
131 {
132     xcb_format_t *fmt = xcb_setup_pixmap_formats (setup);
133     xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup);
134
135     for (; fmt != fmtend; ++fmt)
136         if (fmt->depth == depth)
137             return fmt;
138
139     return 0;
140 }
141 #endif
142
143 static cairo_status_t
144 _cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection,
145                                              const xcb_render_query_pict_formats_reply_t *formats)
146 {
147     xcb_render_pictforminfo_iterator_t i;
148     cairo_status_t status;
149
150     for (i = xcb_render_query_pict_formats_formats_iterator (formats);
151          i.rem;
152          xcb_render_pictforminfo_next (&i))
153     {
154         cairo_format_masks_t masks;
155         pixman_format_code_t pixman_format;
156
157         if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT)
158             continue;
159
160         masks.alpha_mask =
161             (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
162         masks.red_mask =
163             (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
164         masks.green_mask =
165             (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
166         masks.blue_mask =
167             (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift;
168         masks.bpp = i.data->depth;
169
170         if (_pixman_format_from_masks (&masks, &pixman_format)) {
171             cairo_hash_entry_t key;
172
173             key.hash = pixman_format;
174             if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) {
175                 cairo_xcb_xrender_format_t *f;
176
177                 f = malloc (sizeof (cairo_xcb_xrender_format_t));
178                 if (unlikely (f == NULL))
179                     return _cairo_error (CAIRO_STATUS_NO_MEMORY);
180
181                 f->key.hash = pixman_format;
182                 f->xrender_format = i.data->id;
183                 status = _cairo_hash_table_insert (connection->xrender_formats,
184                                                    &f->key);
185                 if (unlikely (status))
186                     return status;
187
188 #if 0
189                 printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
190                         i.data->id,
191                         masks.alpha_mask,
192                         masks.red_mask,
193                         masks.green_mask,
194                         masks.blue_mask,
195                         masks.bpp,
196                         pixman_format,
197                         PIXMAN_FORMAT_DEPTH(pixman_format),
198                         PIXMAN_FORMAT_BPP(pixman_format));
199 #endif
200             }
201         }
202     }
203
204     status = _cairo_xcb_connection_find_visual_formats (connection, formats);
205     if (unlikely (status))
206         return status;
207
208     connection->standard_formats[CAIRO_FORMAT_A1] =
209         _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1);
210
211     connection->standard_formats[CAIRO_FORMAT_A8] =
212         _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8);
213
214     connection->standard_formats[CAIRO_FORMAT_RGB24] =
215         _cairo_xcb_connection_get_xrender_format (connection,
216                                                   PIXMAN_FORMAT (24,
217                                                                  PIXMAN_TYPE_ARGB,
218                                                                  0, 8, 8, 8));
219     if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) {
220         connection->standard_formats[CAIRO_FORMAT_RGB24] =
221             _cairo_xcb_connection_get_xrender_format (connection,
222                                                       PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR,
223                                                                      0, 8, 8, 8));
224     }
225
226     connection->standard_formats[CAIRO_FORMAT_ARGB32] =
227         _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8);
228     if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) {
229         connection->standard_formats[CAIRO_FORMAT_ARGB32] =
230             _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8);
231     }
232
233     return CAIRO_STATUS_SUCCESS;
234 }
235
236 /*
237  * We require support for depth 1, 8, 24 and 32 pixmaps
238  */
239 #define DEPTH_MASK(d)   (1 << ((d) - 1))
240 #define REQUIRED_DEPTHS (DEPTH_MASK(1) | \
241                          DEPTH_MASK(8) | \
242                          DEPTH_MASK(24) | \
243                          DEPTH_MASK(32))
244 static cairo_bool_t
245 pixmap_depths_usable (cairo_xcb_connection_t *connection,
246                       uint32_t missing,
247                       xcb_drawable_t root)
248 {
249     xcb_connection_t *c = connection->xcb_connection;
250     xcb_void_cookie_t create_cookie[32];
251     xcb_pixmap_t pixmap;
252     cairo_bool_t success = TRUE;
253     int depth, i, j;
254
255     pixmap = _cairo_xcb_connection_get_xid (connection);
256
257     for (depth = 1, i = 0; depth <= 32; depth++) {
258         if (missing & DEPTH_MASK(depth)) {
259             create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1);
260             xcb_free_pixmap (c, pixmap);
261             if (!create_cookie[i].sequence) {
262                 success = FALSE;
263                 break;
264             }
265             i++;
266         }
267     }
268
269     for (j = 0; j < i; j++) {
270         xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]);
271         success &= create_error == NULL;
272         free (create_error);
273     }
274
275     _cairo_xcb_connection_put_xid (connection, pixmap);
276
277     return success;
278 }
279
280 static cairo_bool_t
281 has_required_depths (cairo_xcb_connection_t *connection)
282 {
283     xcb_screen_iterator_t screens;
284
285     for (screens = xcb_setup_roots_iterator (connection->root);
286          screens.rem;
287          xcb_screen_next (&screens))
288     {
289         xcb_depth_iterator_t depths;
290         uint32_t missing = REQUIRED_DEPTHS;
291
292         for (depths = xcb_screen_allowed_depths_iterator (screens.data);
293              depths.rem;
294              xcb_depth_next (&depths))
295         {
296             missing &= ~DEPTH_MASK (depths.data->depth);
297         }
298         if (missing == 0)
299             continue;
300
301         /*
302          * Ok, this is ugly.  It should be sufficient at this
303          * point to just return false, but Xinerama is broken at
304          * this point and only advertises depths which have an
305          * associated visual.  Of course, the other depths still
306          * work, but the only way to find out is to try them.
307          */
308         if (! pixmap_depths_usable (connection, missing, screens.data->root))
309             return FALSE;
310     }
311
312     return TRUE;
313 }
314
315 static xcb_render_query_version_reply_t *
316 _render_restrict_env(xcb_render_query_version_reply_t *version)
317 {
318     const char *env;
319
320     if (version == NULL)
321         return NULL;
322
323     env = getenv ("CAIRO_DEBUG");
324     if (env != NULL)
325         env = strstr (env, "xrender-version=");
326     if (env != NULL) {
327         int max_render_major, max_render_minor;
328
329         env += sizeof ("xrender-version=") - 1;
330         if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
331             max_render_major = max_render_minor = -1;
332
333         if (max_render_major < 0 || max_render_minor < 0) {
334             free (version);
335             return NULL;
336         }
337
338         if (max_render_major < (int) version->major_version ||
339             (max_render_major == (int) version->major_version &&
340              max_render_minor < (int) version->minor_version))
341         {
342             version->major_version = max_render_major;
343             version->minor_version = max_render_minor;
344         }
345     }
346
347     return version;
348 }
349
350 static cairo_status_t
351 _cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
352 {
353     xcb_connection_t *c = connection->xcb_connection;
354     xcb_render_query_version_cookie_t version_cookie;
355     xcb_render_query_pict_formats_cookie_t formats_cookie;
356     xcb_render_query_version_reply_t *version;
357     xcb_render_query_pict_formats_reply_t *formats;
358     cairo_status_t status;
359     cairo_bool_t present;
360
361     version_cookie = xcb_render_query_version (c, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION);
362     formats_cookie = xcb_render_query_pict_formats (c);
363
364     present = has_required_depths (connection);
365     version = xcb_render_query_version_reply (c, version_cookie, 0);
366     formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
367
368     version = _render_restrict_env (version);
369
370     if (! present || version == NULL || formats == NULL) {
371         free (version);
372         free (formats);
373         return CAIRO_STATUS_SUCCESS;
374     }
375
376     /* always true if the extension is present (i.e. >= 0.0) */
377     connection->flags |= CAIRO_XCB_HAS_RENDER;
378     connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE;
379     connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS;
380
381     if (XCB_RENDER_HAS_FILL_RECTANGLES (version))
382         connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
383
384     if (XCB_RENDER_HAS_TRAPEZOIDS (version))
385         connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
386
387     if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version))
388         connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
389
390     if (XCB_RENDER_HAS_FILTERS (version))
391         connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
392
393     if (XCB_RENDER_HAS_PDF_OPERATORS (version))
394         connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
395
396     if (XCB_RENDER_HAS_EXTENDED_REPEAT (version))
397         connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
398
399     if (XCB_RENDER_HAS_GRADIENTS (version))
400         connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS;
401
402     free (version);
403
404     status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
405     free (formats);
406
407     return status;
408 }
409
410 #if 0
411 static void
412 _cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection)
413 {
414     xcb_connection_t *c = connection->xcb_connection;
415     xcb_cairo_query_version_reply_t *version;
416
417     version = xcb_cairo_query_version_reply (c,
418                                              xcb_cairo_query_version (c, 0, 0),
419                                              0);
420
421     free (version);
422 }
423 #endif
424
425 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
426 static cairo_bool_t
427 can_use_shm (cairo_xcb_connection_t *connection)
428 {
429     cairo_bool_t success = TRUE;
430     xcb_connection_t *c = connection->xcb_connection;
431     xcb_void_cookie_t cookie[2];
432     xcb_generic_error_t *error;
433     int shmid;
434     uint32_t shmseg;
435     void *ptr;
436
437     shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
438     if (shmid == -1)
439         return FALSE;
440
441     ptr = shmat (shmid, NULL, 0);
442     if (ptr == (char *) -1) {
443         shmctl (shmid, IPC_RMID, NULL);
444         return FALSE;
445     }
446
447     shmseg = _cairo_xcb_connection_get_xid (connection);
448     cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE);
449     cookie[1] = xcb_shm_detach_checked (c, shmseg);
450     _cairo_xcb_connection_put_xid (connection, shmseg);
451
452     error = xcb_request_check (c, cookie[0]);
453     if (error != NULL)
454         success = FALSE;
455
456     error = xcb_request_check (c, cookie[1]);
457     if (error != NULL)
458         success = FALSE;
459
460     shmctl (shmid, IPC_RMID, NULL);
461     shmdt (ptr);
462
463     return success;
464 }
465
466 static void
467 _cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
468 {
469     xcb_connection_t *c = connection->xcb_connection;
470     xcb_shm_query_version_reply_t *version;
471
472     version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0);
473     if (version == NULL)
474         return;
475
476     free (version);
477
478     if (can_use_shm (connection))
479         connection->flags |= CAIRO_XCB_HAS_SHM;
480 }
481 #endif
482
483 static cairo_status_t
484 _device_flush (void *device)
485 {
486     cairo_xcb_connection_t *connection = device;
487     cairo_status_t status;
488
489     status = cairo_device_acquire (&connection->device);
490     if (unlikely (status))
491         return status;
492
493 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
494     _cairo_xcb_connection_shm_mem_pools_flush (connection);
495 #endif
496
497     xcb_flush (connection->xcb_connection);
498
499     cairo_device_release (&connection->device);
500     return CAIRO_STATUS_SUCCESS;
501 }
502
503 static void
504 _pluck_xrender_format (void *entry,
505                        void *closure)
506 {
507     _cairo_hash_table_remove (closure, entry);
508     free (entry);
509 }
510
511 static void
512 _device_finish (void *device)
513 {
514     cairo_xcb_connection_t *connection = device;
515     cairo_bool_t was_cached = FALSE;
516
517     if (! cairo_list_is_empty (&connection->link)) {
518         CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
519         cairo_list_del (&connection->link);
520         CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
521         was_cached = TRUE;
522     }
523
524     while (! cairo_list_is_empty (&connection->fonts)) {
525         cairo_xcb_font_t *font;
526
527         font = cairo_list_first_entry (&connection->fonts,
528                                        cairo_xcb_font_t,
529                                        link);
530         _cairo_xcb_font_close (font);
531     }
532
533     while (! cairo_list_is_empty (&connection->screens)) {
534         cairo_xcb_screen_t *screen;
535
536         screen = cairo_list_first_entry (&connection->screens,
537                                          cairo_xcb_screen_t,
538                                          link);
539         _cairo_xcb_screen_finish (screen);
540     }
541
542 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
543     /* _cairo_xcb_screen_finish finishes surfaces. If any of those surfaces had
544      * a fallback image, we might have done a SHM PutImage. */
545     _cairo_xcb_connection_shm_mem_pools_flush (connection);
546 #endif
547
548     if (was_cached)
549         cairo_device_destroy (device);
550 }
551
552 static void
553 _device_destroy (void *device)
554 {
555     cairo_xcb_connection_t *connection = device;
556
557     _cairo_hash_table_foreach (connection->xrender_formats,
558                                _pluck_xrender_format, connection->xrender_formats);
559     _cairo_hash_table_destroy (connection->xrender_formats);
560
561     _cairo_hash_table_foreach (connection->visual_to_xrender_format,
562                                _pluck_xrender_format,
563                                connection->visual_to_xrender_format);
564     _cairo_hash_table_destroy (connection->visual_to_xrender_format);
565
566 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
567     _cairo_xcb_connection_shm_mem_pools_fini (connection);
568 #endif
569     _cairo_freepool_fini (&connection->shm_info_freelist);
570
571     _cairo_freepool_fini (&connection->xid_pool);
572
573     CAIRO_MUTEX_FINI (connection->shm_mutex);
574     CAIRO_MUTEX_FINI (connection->screens_mutex);
575
576     free (connection);
577 }
578
579 static const cairo_device_backend_t _cairo_xcb_device_backend = {
580     CAIRO_DEVICE_TYPE_XCB,
581
582     NULL, NULL, /* lock, unlock */
583
584     _device_flush,
585     _device_finish,
586     _device_destroy,
587 };
588
589 cairo_xcb_connection_t *
590 _cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
591 {
592     cairo_xcb_connection_t *connection;
593     const xcb_query_extension_reply_t *ext;
594     cairo_status_t status;
595
596     CAIRO_MUTEX_INITIALIZE ();
597
598     CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
599     if (connections.next == NULL) {
600         /* XXX _cairo_init () */
601         cairo_list_init (&connections);
602     }
603
604     cairo_list_foreach_entry (connection,
605                               cairo_xcb_connection_t,
606                               &connections,
607                               link)
608     {
609         if (connection->xcb_connection == xcb_connection) {
610             /* Maintain MRU order. */
611             if (connections.next != &connection->link)
612                 cairo_list_move (&connection->link, &connections);
613
614             goto unlock;
615         }
616     }
617
618     connection = malloc (sizeof (cairo_xcb_connection_t));
619     if (unlikely (connection == NULL))
620         goto unlock;
621
622     _cairo_device_init (&connection->device, &_cairo_xcb_device_backend);
623
624     connection->xcb_connection = xcb_connection;
625
626     cairo_list_init (&connection->fonts);
627     cairo_list_init (&connection->screens);
628     cairo_list_init (&connection->link);
629     connection->xrender_formats = _cairo_hash_table_create (NULL);
630     if (connection->xrender_formats == NULL) {
631         CAIRO_MUTEX_FINI (connection->device.mutex);
632         free (connection);
633         connection = NULL;
634         goto unlock;
635     }
636
637     connection->visual_to_xrender_format = _cairo_hash_table_create (NULL);
638     if (connection->visual_to_xrender_format == NULL) {
639         _cairo_hash_table_destroy (connection->xrender_formats);
640         CAIRO_MUTEX_FINI (connection->device.mutex);
641         free (connection);
642         connection = NULL;
643         goto unlock;
644     }
645
646     cairo_list_init (&connection->free_xids);
647     _cairo_freepool_init (&connection->xid_pool,
648                           sizeof (cairo_xcb_xid_t));
649
650     cairo_list_init (&connection->shm_pools);
651     cairo_list_init (&connection->shm_pending);
652     _cairo_freepool_init (&connection->shm_info_freelist,
653                           sizeof (cairo_xcb_shm_info_t));
654
655     connection->maximum_request_length =
656         xcb_get_maximum_request_length (xcb_connection);
657
658     CAIRO_MUTEX_INIT (connection->shm_mutex);
659     CAIRO_MUTEX_INIT (connection->screens_mutex);
660
661     CAIRO_MUTEX_LOCK (connection->device.mutex);
662
663     connection->flags = 0;
664     connection->force_precision = -1;
665
666     xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id);
667     xcb_prefetch_extension_data (xcb_connection, &xcb_render_id);
668 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
669     xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id);
670 #endif
671 #if 0
672     xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
673 #endif
674
675     xcb_prefetch_maximum_request_length (xcb_connection);
676
677     connection->root = xcb_get_setup (xcb_connection);
678     connection->render = NULL;
679     ext = xcb_get_extension_data (xcb_connection, &xcb_render_id);
680     if (ext != NULL && ext->present) {
681         status = _cairo_xcb_connection_query_render (connection);
682         if (unlikely (status)) {
683             CAIRO_MUTEX_UNLOCK (connection->device.mutex);
684             _cairo_xcb_connection_destroy (connection);
685             connection = NULL;
686             goto unlock;
687         }
688
689         connection->render = ext;
690     }
691
692 #if 0
693     ext = xcb_get_extension_data (connection, &xcb_cairo_id);
694     if (ext != NULL && ext->present)
695         _cairo_xcb_connection_query_cairo (connection);
696 #endif
697
698     connection->shm = NULL;
699 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
700     ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id);
701     if (ext != NULL && ext->present) {
702         _cairo_xcb_connection_query_shm (connection);
703         connection->shm = ext;
704     }
705 #endif
706
707     connection->original_flags = connection->flags;
708
709     CAIRO_MUTEX_UNLOCK (connection->device.mutex);
710
711     cairo_list_add (&connection->link, &connections);
712 unlock:
713     CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
714
715     return connection;
716 }
717
718 xcb_render_pictformat_t
719 _cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
720                                           pixman_format_code_t pixman_format)
721 {
722     cairo_hash_entry_t key;
723     cairo_xcb_xrender_format_t *format;
724
725     key.hash = pixman_format;
726     format = _cairo_hash_table_lookup (connection->xrender_formats, &key);
727     return format ? format->xrender_format : XCB_NONE;
728 }
729
730 xcb_render_pictformat_t
731 _cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
732                                                      const xcb_visualid_t visual)
733 {
734     cairo_hash_entry_t key;
735     cairo_xcb_xrender_format_t *format;
736
737     key.hash = visual;
738     format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
739     return format ? format->xrender_format : XCB_NONE;
740 }
741
742 void
743 _cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
744                                uint32_t xid)
745 {
746     cairo_xcb_xid_t *cache;
747
748     assert (CAIRO_MUTEX_IS_LOCKED (connection->device.mutex));
749     cache = _cairo_freepool_alloc (&connection->xid_pool);
750     if (likely (cache != NULL)) {
751         cache->xid = xid;
752         cairo_list_add (&cache->link, &connection->free_xids);
753     }
754 }
755
756 uint32_t
757 _cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
758 {
759     uint32_t xid;
760
761     assert (CAIRO_MUTEX_IS_LOCKED (connection->device.mutex));
762     if (! cairo_list_is_empty (&connection->free_xids)) {
763         cairo_xcb_xid_t *cache;
764
765         cache = cairo_list_first_entry (&connection->free_xids,
766                                         cairo_xcb_xid_t,
767                                         link);
768         xid = cache->xid;
769
770         cairo_list_del (&cache->link);
771         _cairo_freepool_free (&connection->xid_pool, cache);
772     } else {
773         xid = xcb_generate_id (connection->xcb_connection);
774     }
775
776     return xid;
777 }
778
779 /**
780  * cairo_xcb_device_get_connection:
781  * @device: a #cairo_device_t for the XCB backend
782  *
783  * Get the connection for the XCB device.
784  *
785  * Returns: the #xcb_connection_t for the connection
786  *
787  * Since: 1.12
788  **/
789 xcb_connection_t *
790 cairo_xcb_device_get_connection (cairo_device_t *device)
791 {
792     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB)
793             return NULL;
794
795     return ((cairo_xcb_connection_t *)device)->xcb_connection;
796 }
797
798 /* public (debug) interface */
799
800 /**
801  * cairo_xcb_device_debug_cap_xshm_version:
802  * @device: a #cairo_device_t for the XCB backend
803  * @major_version: major version to restrict to
804  * @minor_version: minor version to restrict to
805  *
806  * Restricts all future XCB surfaces for this devices to the specified version
807  * of the SHM extension. This function exists solely for debugging purpose.
808  * It let's you find out how cairo would behave with an older version of
809  * the SHM extension.
810  *
811  * Use the special values -1 and -1 for disabling the SHM extension.
812  *
813  * Since: 1.12
814  **/
815 void
816 cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
817                                          int major_version,
818                                          int minor_version)
819 {
820     cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
821
822     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
823         cairo_status_t status;
824
825         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
826         (void) status;
827         return;
828     }
829
830     /* First reset all the SHM flags to their original value. This works
831      * because we only ever clear bits after the connection was created.
832      */
833     connection->flags |= (connection->original_flags & CAIRO_XCB_SHM_MASK);
834
835     /* clear any flags that are inappropriate for the desired version */
836     if (major_version < 0 && minor_version < 0) {
837         connection->flags &= ~(CAIRO_XCB_HAS_SHM);
838     }
839 }
840
841 /**
842  * cairo_xcb_device_debug_cap_xrender_version:
843  * @device: a #cairo_device_t for the XCB backend
844  * @major_version: major version to restrict to
845  * @minor_version: minor version to restrict to
846  *
847  * Restricts all future XCB surfaces for this devices to the specified version
848  * of the RENDER extension. This function exists solely for debugging purpose.
849  * It let's you find out how cairo would behave with an older version of
850  * the RENDER extension.
851  *
852  * Use the special values -1 and -1 for disabling the RENDER extension.
853  *
854  * Since: 1.12
855  **/
856 void
857 cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
858                                             int major_version,
859                                             int minor_version)
860 {
861     cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
862
863     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
864         cairo_status_t status;
865
866         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
867         (void) status;
868         return;
869     }
870
871     /* First reset all the RENDER flags to their original value. This works
872      * because we only ever clear bits after the connection was created.
873      */
874     connection->flags |= (connection->original_flags & CAIRO_XCB_RENDER_MASK);
875
876     /* clear any flags that are inappropriate for the desired version */
877     if (major_version < 0 && minor_version < 0) {
878         connection->flags &= ~(CAIRO_XCB_HAS_RENDER |
879                                CAIRO_XCB_RENDER_HAS_COMPOSITE |
880                                CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS |
881                                CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
882                                CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
883                                CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
884                                CAIRO_XCB_RENDER_HAS_FILTERS |
885                                CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
886                                CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
887                                CAIRO_XCB_RENDER_HAS_GRADIENTS);
888     } else {
889         xcb_render_query_version_reply_t version;
890
891         version.major_version = major_version;
892         version.minor_version = minor_version;
893
894         if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version))
895             connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
896
897         if (! XCB_RENDER_HAS_TRAPEZOIDS (&version))
898             connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
899
900         if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version))
901             connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
902
903         if (! XCB_RENDER_HAS_FILTERS (&version))
904             connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS;
905
906         if (! XCB_RENDER_HAS_PDF_OPERATORS (&version))
907             connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
908
909         if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version))
910             connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
911
912         if (! XCB_RENDER_HAS_GRADIENTS (&version))
913             connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS;
914     }
915 }
916 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
917 slim_hidden_def (cairo_xcb_device_debug_cap_xrender_version);
918 #endif
919
920 /**
921  * cairo_xcb_device_debug_set_precision:
922  * @device: a #cairo_device_t for the XCB backend
923  * @precision: the precision to use
924  *
925  * Render supports two modes of precision when rendering trapezoids. Set
926  * the precision to the desired mode.
927  *
928  * Since: 1.12
929  **/
930 void
931 cairo_xcb_device_debug_set_precision (cairo_device_t *device,
932                                       int precision)
933 {
934     if (device == NULL || device->status)
935         return;
936     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
937         cairo_status_t status;
938
939         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
940         (void) status;
941         return;
942     }
943
944     ((cairo_xcb_connection_t *) device)->force_precision = precision;
945 }
946 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
947 slim_hidden_def (cairo_xcb_device_debug_set_precision);
948 #endif
949
950 /**
951  * cairo_xcb_device_debug_get_precision:
952  * @device: a #cairo_device_t for the XCB backend
953  *
954  * Get the Xrender precision mode.
955  *
956  * Returns: the render precision mode
957  *
958  * Since: 1.12
959  **/
960 int
961 cairo_xcb_device_debug_get_precision (cairo_device_t *device)
962 {
963     if (device == NULL || device->status)
964         return -1;
965     if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
966         cairo_status_t status;
967
968         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
969         (void) status;
970         return -1;
971     }
972
973     return ((cairo_xcb_connection_t *) device)->force_precision;
974 }
975 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
976 slim_hidden_def (cairo_xcb_device_debug_get_precision);
977 #endif