1 /*
2  * Copyright © 2008 Bart Massey <bart@cs.pdx.edu>
3  * Copyright © 2008 Ian Osgood <iano@quirkster.com>
4  * Copyright © 2008 Jamey Sharp <jamey@minilop.net>
5  * Copyright © 2008 Josh Triplett <josh@freedesktop.org>
6  *
7  * Permission is hereby granted, free of charge, to any person
8  * obtaining a copy of this software and associated documentation
9  * files (the "Software"), to deal in the Software without
10  * restriction, including without limitation the rights to use, copy,
11  * modify, merge, publish, distribute, sublicense, and/or sell copies
12  * of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * Except as contained in this notice, the names of the authors or
27  * their institutions shall not be used in advertising or otherwise to
28  * promote the sale, use or other dealings in this Software without
29  * prior written authorization from the authors.
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <xcb/xcb.h>
41 #include "xcb_aux.h"
42 
43 /* Connection related functions */
44 
45 uint8_t
xcb_aux_get_depth(xcb_connection_t * c,xcb_screen_t * screen)46 xcb_aux_get_depth (xcb_connection_t *c,
47                    xcb_screen_t     *screen)
48 {
49   xcb_drawable_t            drawable;
50   xcb_get_geometry_reply_t *geom;
51   int                       depth = 0;
52 
53   drawable = screen->root;
54   geom = xcb_get_geometry_reply (c, xcb_get_geometry(c, drawable), 0);
55 
56   if (geom) {
57     depth = geom->depth;
58     free (geom);
59   }
60 
61   return depth;
62 }
63 
64 uint8_t
xcb_aux_get_depth_of_visual(xcb_screen_t * screen,xcb_visualid_t id)65 xcb_aux_get_depth_of_visual (xcb_screen_t *screen,
66 			     xcb_visualid_t id)
67 {
68     xcb_depth_iterator_t i;
69     xcb_visualtype_iterator_t j;
70     for (i = xcb_screen_allowed_depths_iterator(screen);
71 	 i.rem; xcb_depth_next(&i))
72 	for (j = xcb_depth_visuals_iterator(i.data);
73 	     j.rem; xcb_visualtype_next(&j))
74 	    if (j.data->visual_id == id)
75 		return i.data->depth;
76     return 0;
77 }
78 
79 xcb_screen_t *
xcb_aux_get_screen(xcb_connection_t * c,int screen)80 xcb_aux_get_screen (xcb_connection_t *c,
81                     int               screen)
82 {
83   xcb_screen_iterator_t i = xcb_setup_roots_iterator(xcb_get_setup(c));
84   for (; i.rem; --screen, xcb_screen_next(&i))
85     if (screen == 0)
86       return i.data;
87   return 0;
88 }
89 
90 xcb_visualtype_t *
xcb_aux_get_visualtype(xcb_connection_t * c,int scr,xcb_visualid_t vid)91 xcb_aux_get_visualtype (xcb_connection_t *c,
92                         int               scr,
93                         xcb_visualid_t    vid)
94 {
95   xcb_screen_t        *screen;
96   xcb_depth_t         *depth;
97   xcb_visualtype_iterator_t iter;
98   int               cur;
99 
100   screen = xcb_aux_get_screen (c, scr);
101   if (!screen) return NULL;
102 
103   depth = xcb_screen_allowed_depths_iterator(screen).data;
104   if (!depth) return NULL;
105 
106    iter = xcb_depth_visuals_iterator(depth);
107    for (cur = 0 ; cur < iter.rem ; xcb_visualtype_next(&iter), ++cur)
108       if (vid == iter.data->visual_id)
109 	 return iter.data;
110 
111    return NULL;
112 }
113 
114 xcb_visualtype_t *
xcb_aux_find_visual_by_id(xcb_screen_t * screen,xcb_visualid_t id)115 xcb_aux_find_visual_by_id (xcb_screen_t *screen,
116 			   xcb_visualid_t id)
117 {
118     xcb_depth_iterator_t i;
119     xcb_visualtype_iterator_t j;
120     for (i = xcb_screen_allowed_depths_iterator(screen);
121 	 i.rem; xcb_depth_next(&i))
122 	for (j = xcb_depth_visuals_iterator(i.data);
123 	     j.rem; xcb_visualtype_next(&j))
124 	    if (j.data->visual_id == id)
125 		return j.data;
126     return 0;
127 }
128 
129 xcb_visualtype_t *
xcb_aux_find_visual_by_attrs(xcb_screen_t * screen,int8_t class,int8_t depth)130 xcb_aux_find_visual_by_attrs (xcb_screen_t *screen,
131 			      int8_t class,
132 			      int8_t depth)
133 {
134     xcb_depth_iterator_t i;
135     xcb_visualtype_iterator_t j;
136     for (i = xcb_screen_allowed_depths_iterator(screen);
137 	 i.rem; xcb_depth_next(&i)) {
138 	if (depth != -1 && i.data->depth != depth)
139 	    continue;
140 	for (j = xcb_depth_visuals_iterator(i.data);
141 	     j.rem; xcb_visualtype_next(&j))
142 	    if (class == -1 || j.data->_class == class)
143 		return j.data;
144     }
145     return 0;
146 }
147 
148 void
xcb_aux_sync(xcb_connection_t * c)149 xcb_aux_sync (xcb_connection_t *c)
150 {
151     free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
152 }
153 
154 /* structs instead of value lists */
155 /* TODO: generate the struct types and functions from protocol masks and descriptions */
156 
157 /* This generic implementation of pack_list depends on:
158    a) structs packed to uint32_t size
159    b) structs consist of just uint32_t/int32_t fields in the same order as bitmask
160 */
161 
162 static void
pack_list(uint32_t mask,const uint32_t * src,uint32_t * dest)163 pack_list( uint32_t mask, const uint32_t *src, uint32_t *dest )
164 {
165 	for ( ; mask; mask >>= 1, src++)
166 		if (mask & 1)
167 			*dest++ = *src;
168 }
169 
170 xcb_void_cookie_t
xcb_aux_create_window(xcb_connection_t * c,uint8_t depth,xcb_window_t wid,xcb_window_t parent,int16_t x,int16_t y,uint16_t width,uint16_t height,uint16_t border_width,uint16_t _class,xcb_visualid_t visual,uint32_t mask,const xcb_params_cw_t * params)171 xcb_aux_create_window (xcb_connection_t       *c,
172                        uint8_t                depth,
173                        xcb_window_t           wid,
174                        xcb_window_t           parent,
175                        int16_t                x,
176                        int16_t                y,
177                        uint16_t               width,
178                        uint16_t               height,
179                        uint16_t               border_width,
180                        uint16_t               _class,
181                        xcb_visualid_t         visual,
182                        uint32_t               mask,
183                        const xcb_params_cw_t *params)
184 {
185 	uint32_t value_list[16];
186 	pack_list(mask, (const uint32_t *)params, value_list);
187 	return xcb_create_window(c, depth, wid, parent,
188 		x, y, width, height, border_width,
189 		_class, visual, mask, value_list);
190 }
191 
192 xcb_void_cookie_t
xcb_aux_create_window_checked(xcb_connection_t * c,uint8_t depth,xcb_window_t wid,xcb_window_t parent,int16_t x,int16_t y,uint16_t width,uint16_t height,uint16_t border_width,uint16_t _class,xcb_visualid_t visual,uint32_t mask,const xcb_params_cw_t * params)193 xcb_aux_create_window_checked (xcb_connection_t       *c,
194 			       uint8_t                depth,
195 			       xcb_window_t           wid,
196 			       xcb_window_t           parent,
197 			       int16_t                x,
198 			       int16_t                y,
199 			       uint16_t               width,
200 			       uint16_t               height,
201 			       uint16_t               border_width,
202 			       uint16_t               _class,
203 			       xcb_visualid_t         visual,
204 			       uint32_t               mask,
205 			       const xcb_params_cw_t *params)
206 {
207 	uint32_t value_list[16];
208 	pack_list(mask, (const uint32_t *)params, value_list);
209 	return xcb_create_window_checked(c, depth, wid, parent,
210 					 x, y, width, height, border_width,
211 					 _class, visual, mask, value_list);
212 }
213 
214 xcb_void_cookie_t
xcb_aux_change_window_attributes_checked(xcb_connection_t * c,xcb_window_t window,uint32_t mask,const xcb_params_cw_t * params)215 xcb_aux_change_window_attributes_checked (xcb_connection_t      *c,
216                                           xcb_window_t           window,
217                                           uint32_t               mask,
218                                           const xcb_params_cw_t *params)
219 {
220 	uint32_t value_list[16];
221 	pack_list(mask, (const uint32_t *)params, value_list);
222 	return xcb_change_window_attributes_checked( c, window, mask, value_list );
223 }
224 
225 xcb_void_cookie_t
xcb_aux_change_window_attributes(xcb_connection_t * c,xcb_window_t window,uint32_t mask,const xcb_params_cw_t * params)226 xcb_aux_change_window_attributes (xcb_connection_t      *c,
227                                   xcb_window_t           window,
228                                   uint32_t               mask,
229                                   const xcb_params_cw_t *params)
230 {
231 	uint32_t value_list[16];
232 	pack_list(mask, (const uint32_t *)params, value_list);
233 	return xcb_change_window_attributes( c, window, mask, value_list );
234 }
235 
236 xcb_void_cookie_t
xcb_aux_configure_window(xcb_connection_t * c,xcb_window_t window,uint16_t mask,const xcb_params_configure_window_t * params)237 xcb_aux_configure_window (xcb_connection_t                    *c,
238                           xcb_window_t                         window,
239                           uint16_t                             mask,
240                           const xcb_params_configure_window_t *params)
241 {
242 	uint32_t value_list[8];
243 	pack_list(mask, (const uint32_t *)params, value_list);
244 	return xcb_configure_window( c, window, mask, value_list );
245 }
246 
247 xcb_void_cookie_t
xcb_aux_create_gc(xcb_connection_t * c,xcb_gcontext_t gid,xcb_drawable_t drawable,uint32_t mask,const xcb_params_gc_t * params)248 xcb_aux_create_gc (xcb_connection_t      *c,
249                    xcb_gcontext_t         gid,
250                    xcb_drawable_t         drawable,
251                    uint32_t               mask,
252                    const xcb_params_gc_t *params)
253 {
254 	uint32_t value_list[32];
255 	pack_list(mask, (const uint32_t *)params, value_list);
256 	return xcb_create_gc( c, gid, drawable, mask, value_list );
257 }
258 
259 xcb_void_cookie_t
xcb_aux_create_gc_checked(xcb_connection_t * c,xcb_gcontext_t gid,xcb_drawable_t drawable,uint32_t mask,const xcb_params_gc_t * params)260 xcb_aux_create_gc_checked (xcb_connection_t      *c,
261 			   xcb_gcontext_t         gid,
262 			   xcb_drawable_t         drawable,
263 			   uint32_t               mask,
264 			   const xcb_params_gc_t *params)
265 {
266 	uint32_t value_list[32];
267 	pack_list(mask, (const uint32_t *)params, value_list);
268 	return xcb_create_gc_checked( c, gid, drawable, mask, value_list);
269 }
270 
271 xcb_void_cookie_t
xcb_aux_change_gc(xcb_connection_t * c,xcb_gcontext_t gc,uint32_t mask,const xcb_params_gc_t * params)272 xcb_aux_change_gc (xcb_connection_t     *c,
273                    xcb_gcontext_t        gc,
274                    uint32_t              mask,
275                    const xcb_params_gc_t *params)
276 {
277 	uint32_t value_list[32];
278 	pack_list(mask, (const uint32_t *)params, value_list);
279 	return xcb_change_gc( c, gc, mask, value_list );
280 }
281 
282 xcb_void_cookie_t
xcb_aux_change_gc_checked(xcb_connection_t * c,xcb_gcontext_t gc,uint32_t mask,const xcb_params_gc_t * params)283 xcb_aux_change_gc_checked (xcb_connection_t     *c,
284 			   xcb_gcontext_t        gc,
285 			   uint32_t              mask,
286 			   const xcb_params_gc_t *params)
287 {
288 	uint32_t value_list[32];
289 	pack_list(mask, (const uint32_t *)params, value_list);
290 	return xcb_change_gc_checked( c, gc, mask, value_list );
291 }
292 
293 xcb_void_cookie_t
xcb_aux_change_keyboard_control(xcb_connection_t * c,uint32_t mask,const xcb_params_keyboard_t * params)294 xcb_aux_change_keyboard_control (xcb_connection_t            *c,
295                                  uint32_t                     mask,
296                                  const xcb_params_keyboard_t *params)
297 {
298 	uint32_t value_list[16];
299 	pack_list(mask, (const uint32_t *)params, value_list);
300 	return xcb_change_keyboard_control( c, mask, value_list );
301 }
302 
303 /* Color related functions */
304 
305 /* Return true if the given color name can be translated locally,
306    in which case load the components.  Otherwise, a lookup_color request
307    will be needed, so return false. */
308 int
xcb_aux_parse_color(const char * color_name,uint16_t * red,uint16_t * green,uint16_t * blue)309 xcb_aux_parse_color(const char *color_name,
310 		    uint16_t *red,  uint16_t *green,  uint16_t *blue)
311 {
312     int n, r, g, b, i;
313     if (!color_name || *color_name != '#')
314 	return 0;
315     /*
316      * Excitingly weird RGB parsing code from Xlib.
317      */
318     n = strlen (color_name);
319     color_name++;
320     n--;
321     if (n != 3 && n != 6 && n != 9 && n != 12)
322 	return 0;
323     n /= 3;
324     g = b = 0;
325     do {
326 	r = g;
327 	g = b;
328 	b = 0;
329 	for (i = n; --i >= 0; ) {
330 	    char c = *color_name++;
331 	    b <<= 4;
332 	    if (c >= '0' && c <= '9')
333 		b |= c - '0';
334 	    else if (c >= 'A' && c <= 'F')
335 		b |= c - ('A' - 10);
336 	    else if (c >= 'a' && c <= 'f')
337 		b |= c - ('a' - 10);
338 	    else return 0;
339 	}
340     } while (*color_name != '\0');
341     n <<= 2;
342     n = 16 - n;
343     *red = r << n;
344     *green = g << n;
345     *blue = b << n;
346     return 1;
347 }
348 
349 /* Drawing related functions */
350 
351 /* Adapted from Xlib */
352 xcb_void_cookie_t
xcb_aux_set_line_attributes_checked(xcb_connection_t * dpy,xcb_gcontext_t gc,uint16_t linewidth,int32_t linestyle,int32_t capstyle,int32_t joinstyle)353 xcb_aux_set_line_attributes_checked (xcb_connection_t *dpy,
354 				     xcb_gcontext_t gc,
355 				     uint16_t linewidth,
356 				     int32_t linestyle,
357 				     int32_t capstyle,
358 				     int32_t joinstyle)
359 {
360     uint32_t mask = 0;
361     xcb_params_gc_t gv;
362 
363     XCB_AUX_ADD_PARAM(&mask, &gv, line_width, linewidth);
364     XCB_AUX_ADD_PARAM(&mask, &gv, line_style, linestyle);
365     XCB_AUX_ADD_PARAM(&mask, &gv, cap_style, capstyle);
366     XCB_AUX_ADD_PARAM(&mask, &gv, join_style, joinstyle);
367     return xcb_aux_change_gc_checked(dpy, gc, mask, &gv);
368 }
369 
370 /* Adapted from Xlib */
371 /* XXX It would be wiser for apps just to call
372    clear_area() directly. */
373 xcb_void_cookie_t
xcb_aux_clear_window(xcb_connection_t * dpy,xcb_window_t w)374 xcb_aux_clear_window(xcb_connection_t *  dpy,
375 		     xcb_window_t        w)
376 {
377     return xcb_clear_area(dpy, 0, w, 0, 0, 0, 0);
378 }
379