Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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
  978.