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