1 /* Copyright © 2006 Jamey Sharp.
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
17 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 * Except as contained in this notice, the names of the authors or their
21 * institutions shall not be used in advertising or otherwise to promote the
22 * sale, use or other dealings in this Software without prior written
23 * authorization from the authors.
29 #include "xcb_renderutil.h"
33 typedef struct connection_cache {
34 struct connection_cache *next; /* keep a linked list */
35 xcb_connection_t *c; /* which display this is */
36 xcb_render_query_version_reply_t *version;
37 xcb_render_query_pict_formats_reply_t *formats;
42 connection_cache *head; /* start of the list */
43 connection_cache *cur; /* most recently used */
44 } connections = { PTHREAD_MUTEX_INITIALIZER };
47 * If the server is missing support for any of the required depths on
48 * any screen, tell the application that Render is not present.
51 #define DEPTH_MASK(d) (1 << ((d) - 1))
54 * Render requires support for depth 1, 4, 8, 24 and 32 pixmaps
57 #define REQUIRED_DEPTHS (DEPTH_MASK(1) | \
63 /* Test each depth not explicitly advertised to see if pixmap creation
64 * succeeds: if it does, that depth is usable. */
66 pixmap_depths_usable (xcb_connection_t *c, uint32_t missing, xcb_pixmap_t pixmap, xcb_drawable_t root)
68 xcb_void_cookie_t create_cookie[32] = { { 0 } };
69 xcb_void_cookie_t free_cookie[32] = { { 0 } };
72 for (d = 1; d <= 32; d++)
73 if (missing & DEPTH_MASK(d))
75 create_cookie[d - 1] = xcb_create_pixmap_checked (c, d, pixmap, root, 1, 1);
76 free_cookie[d - 1] = xcb_free_pixmap_checked (c, pixmap);
77 if (!create_cookie[d - 1].sequence || !free_cookie[d - 1].sequence)
83 for (d = 0; d < 32; d++)
84 if (create_cookie[d].sequence || free_cookie[d].sequence)
86 xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[d]);
87 xcb_generic_error_t *free_error = xcb_request_check (c, free_cookie[d]);
88 success = success && !create_error;
96 has_required_depths (xcb_connection_t *c)
98 xcb_screen_iterator_t screens;
99 xcb_pixmap_t pixmap = { -1 };
100 for (screens = xcb_setup_roots_iterator(xcb_get_setup(c)); screens.rem; xcb_screen_next(&screens))
102 xcb_depth_iterator_t depths;
103 uint32_t missing = REQUIRED_DEPTHS;
106 for (depths = xcb_screen_allowed_depths_iterator(screens.data); depths.rem; xcb_depth_next(&depths))
107 missing &= ~DEPTH_MASK(depths.data->depth);
112 * Ok, this is ugly. It should be sufficient at this
113 * point to just return false, but Xinerama is broken at
114 * this point and only advertises depths which have an
115 * associated visual. Of course, the other depths still
116 * work, but the only way to find out is to try them.
119 pixmap = xcb_generate_id(c);
120 root = screens.data->root;
121 if (!pixmap_depths_usable (c, missing, pixmap, root))
127 static connection_cache *
128 find_or_create_display (xcb_connection_t *c)
130 connection_cache *info;
131 xcb_render_query_version_cookie_t version_cookie;
132 xcb_render_query_pict_formats_cookie_t formats_cookie;
136 * look for display in list
138 for (info = connections.head; info; info = info->next)
140 connections.cur = info; /* cache most recently used */
145 * don't already have this display: add it.
147 info = malloc (sizeof (connection_cache));
152 version_cookie = xcb_render_query_version(c, 0, 10);
153 formats_cookie = xcb_render_query_pict_formats(c);
155 present = has_required_depths (c);
156 info->version = xcb_render_query_version_reply(c, version_cookie, 0);
157 info->formats = xcb_render_query_pict_formats_reply(c, formats_cookie, 0);
159 if (!present || !info->version || !info->formats)
166 /* Check for the lack of sub-pixel data */
167 else if (info->version->major_version == 0 && info->version->minor_version < 6)
168 info->formats->num_subpixel = 0;
171 * now, chain it onto the list
173 info->next = connections.head;
174 connections.head = info;
175 connections.cur = info;
180 static connection_cache *
181 find_display (xcb_connection_t *c)
183 connection_cache *info;
186 * see if this was the most recently accessed display
188 if ((info = connections.cur) && info->c == c)
191 pthread_mutex_lock(&connections.lock);
192 info = find_or_create_display (c);
193 pthread_mutex_unlock(&connections.lock);
197 const xcb_render_query_version_reply_t *
198 xcb_render_util_query_version (xcb_connection_t *c)
200 connection_cache *info = find_display (c);
203 return info->version;
206 const xcb_render_query_pict_formats_reply_t *
207 xcb_render_util_query_formats (xcb_connection_t *c)
209 connection_cache *info = find_display (c);
212 return info->formats;
216 xcb_render_util_disconnect (xcb_connection_t *c)
218 connection_cache **prev, *cur = NULL;
219 pthread_mutex_lock(&connections.lock);
220 for(prev = &connections.head; *prev; prev = &(*prev)->next)
225 if(cur == connections.cur)
226 connections.cur = NULL; /* flush cache */
232 pthread_mutex_unlock(&connections.lock);