client: geometry() honors size hints hint
[awesome.git] / common / xutil.c
blob296467bb3b702a9ca44d62aed01c8156c6800992
1 /*
2 * common/xutil.c - X-related useful functions
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "common/util.h"
24 #include <xcb/xcb.h>
25 #include <xcb/xcb_atom.h>
26 #include <xcb/xcb_icccm.h>
28 /* CURSORFONT */
29 #include <X11/Xlibint.h>
31 #include "common/xutil.h"
32 #include "common/atoms.h"
34 /** Get the string value of an atom.
35 * \param conn X connection.
36 * \param w Window.
37 * \param atom The atom.
38 * \param text Buffer to fill.
39 * \param len Length of the filled buffer.
40 * \return True on sucess, false on failure.
42 bool
43 xutil_text_prop_get(xcb_connection_t *conn, xcb_window_t w, xcb_atom_t atom,
44 char **text, ssize_t *len)
46 xcb_get_text_property_reply_t reply;
48 p_clear(&reply, 1);
50 if(!xcb_get_text_property_reply(conn,
51 xcb_get_text_property_unchecked(conn, w,
52 atom),
53 &reply, NULL) ||
54 !reply.name_len || reply.format != 8)
56 xcb_get_text_property_reply_wipe(&reply);
57 return false;
60 if(text && len)
62 /* Check whether the returned property value is just an ascii
63 * string or utf8 string. At the moment it doesn't handle
64 * COMPOUND_TEXT and multibyte but it's not needed... */
65 if(reply.encoding == STRING || reply.encoding == UTF8_STRING)
67 *text = p_new(char, reply.name_len + 1);
68 /* Use memcpy() because the property name is not be \0
69 * terminated */
70 memcpy(*text, reply.name, reply.name_len);
71 (*text)[reply.name_len] = '\0';
72 *len = reply.name_len;
74 else
76 *text = NULL;
77 *len = 0;
81 xcb_get_text_property_reply_wipe(&reply);
82 return true;
85 /** Get the lock masks (shiftlock, numlock, capslock).
86 * \param connection The X connection.
87 * \param cookie The cookie of the request.
88 * \param keysyms Key symbols.
89 * \param numlockmask Numlock mask.
90 * \param shiftlockmask Shiftlock mask.
91 * \param capslockmask Capslock mask.
93 void
94 xutil_lock_mask_get(xcb_connection_t *connection,
95 xcb_get_modifier_mapping_cookie_t cookie,
96 xcb_key_symbols_t *keysyms,
97 unsigned int *numlockmask,
98 unsigned int *shiftlockmask,
99 unsigned int *capslockmask)
101 xcb_get_modifier_mapping_reply_t *modmap_r;
102 xcb_keycode_t *modmap, kc;
103 unsigned int mask;
104 int i, j;
106 modmap_r = xcb_get_modifier_mapping_reply(connection, cookie, NULL);
107 modmap = xcb_get_modifier_mapping_keycodes(modmap_r);
109 for(i = 0; i < 8; i++)
110 for(j = 0; j < modmap_r->keycodes_per_modifier; j++)
112 kc = modmap[i * modmap_r->keycodes_per_modifier + j];
113 mask = (1 << i);
115 if(numlockmask != NULL
116 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Num_Lock))
117 *numlockmask = mask;
118 else if(shiftlockmask != NULL
119 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Shift_Lock))
120 *shiftlockmask = mask;
121 else if(capslockmask != NULL
122 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Caps_Lock))
123 *capslockmask = mask;
126 p_delete(&modmap_r);
129 /* Number of different errors */
130 #define ERRORS_NBR 256
132 /* Number of different events */
133 #define EVENTS_NBR 126
135 void
136 xutil_error_handler_catch_all_set(xcb_event_handlers_t *evenths,
137 xcb_generic_error_handler_t handler,
138 void *data)
140 int err_num;
141 for(err_num = 0; err_num < ERRORS_NBR; err_num++)
142 xcb_event_set_error_handler(evenths, err_num, handler, data);
145 const char *
146 xutil_label_error[] =
148 "Success",
149 "BadRequest",
150 "BadValue",
151 "BadWindow",
152 "BadPixmap",
153 "BadAtom",
154 "BadCursor",
155 "BadFont",
156 "BadMatch",
157 "BadDrawable",
158 "BadAccess",
159 "BadAlloc",
160 "BadColor",
161 "BadGC",
162 "BadIDChoice",
163 "BadName",
164 "BadLength",
165 "BadImplementation",
168 const char *
169 xutil_label_request[] =
171 "None",
172 "CreateWindow",
173 "ChangeWindowAttributes",
174 "GetWindowAttributes",
175 "DestroyWindow",
176 "DestroySubwindows",
177 "ChangeSaveSet",
178 "ReparentWindow",
179 "MapWindow",
180 "MapSubwindows",
181 "UnmapWindow",
182 "UnmapSubwindows",
183 "ConfigureWindow",
184 "CirculateWindow",
185 "GetGeometry",
186 "QueryTree",
187 "InternAtom",
188 "GetAtomName",
189 "ChangeProperty",
190 "DeleteProperty",
191 "GetProperty",
192 "ListProperties",
193 "SetSelectionOwner",
194 "GetSelectionOwner",
195 "ConvertSelection",
196 "SendEvent",
197 "GrabPointer",
198 "UngrabPointer",
199 "GrabButton",
200 "UngrabButton",
201 "ChangeActivePointerGrab",
202 "GrabKeyboard",
203 "UngrabKeyboard",
204 "GrabKey",
205 "UngrabKey",
206 "AllowEvents",
207 "GrabServer",
208 "UngrabServer",
209 "QueryPointer",
210 "GetMotionEvents",
211 "TranslateCoords",
212 "WarpPointer",
213 "SetInputFocus",
214 "GetInputFocus",
215 "QueryKeymap",
216 "OpenFont",
217 "CloseFont",
218 "QueryFont",
219 "QueryTextExtents",
220 "ListFonts",
221 "ListFontsWithInfo",
222 "SetFontPath",
223 "GetFontPath",
224 "CreatePixmap",
225 "FreePixmap",
226 "CreateGC",
227 "ChangeGC",
228 "CopyGC",
229 "SetDashes",
230 "SetClipRectangles",
231 "FreeGC",
232 "ClearArea",
233 "CopyArea",
234 "CopyPlane",
235 "PolyPoint",
236 "PolyLine",
237 "PolySegment",
238 "PolyRectangle",
239 "PolyArc",
240 "FillPoly",
241 "PolyFillRectangle",
242 "PolyFillArc",
243 "PutImage",
244 "GetImage",
245 "PolyText",
246 "PolyText",
247 "ImageText",
248 "ImageText",
249 "CreateColormap",
250 "FreeColormap",
251 "CopyColormapAndFree",
252 "InstallColormap",
253 "UninstallColormap",
254 "ListInstalledColormaps",
255 "AllocColor",
256 "AllocNamedColor",
257 "AllocColorCells",
258 "AllocColorPlanes",
259 "FreeColors",
260 "StoreColors",
261 "StoreNamedColor",
262 "QueryColors",
263 "LookupColor",
264 "CreateCursor",
265 "CreateGlyphCursor",
266 "FreeCursor",
267 "RecolorCursor",
268 "QueryBestSize",
269 "QueryExtension",
270 "ListExtensions",
271 "ChangeKeyboardMapping",
272 "GetKeyboardMapping",
273 "ChangeKeyboardControl",
274 "GetKeyboardControl",
275 "Bell",
276 "ChangePointerControl",
277 "GetPointerControl",
278 "SetScreenSaver",
279 "GetScreenSaver",
280 "ChangeHosts",
281 "ListHosts",
282 "SetAccessControl",
283 "SetCloseDownMode",
284 "KillClient",
285 "RotateProperties",
286 "ForceScreenSaver",
287 "SetPointerMapping",
288 "GetPointerMapping",
289 "SetModifierMapping",
290 "GetModifierMapping",
291 "major 120",
292 "major 121",
293 "major 122",
294 "major 123",
295 "major 124",
296 "major 125",
297 "major 126",
298 "NoOperation",
301 bool
302 xutil_error_init(const xcb_generic_error_t *e, xutil_error_t *err)
304 if(e->response_type != 0)
305 /* This is not an error, this _should_ not happen */
306 return false;
309 * Get the request code, taken from 'xcb-util/wm'. I can't figure
310 * out how it works BTW, seems to get a byte in 'pad' member
311 * (second byte in second element of the array)
313 err->request_code = *((uint8_t *) e + 10);
315 /* Extensions generally provide their own requests so we just
316 * store the request code */
317 if(err->request_code >= (sizeof(xutil_label_request) / sizeof(char *)))
318 a_asprintf(&err->request_label, "%d", err->request_code);
319 else
320 err->request_label = a_strdup(xutil_label_request[err->request_code]);
322 /* Extensions may also define their own errors, so just store the
323 * error_code */
324 if(e->error_code >= (sizeof(xutil_label_error) / sizeof(char *)))
325 a_asprintf(&err->error_label, "%d", e->error_code);
326 else
327 err->error_label = a_strdup(xutil_label_error[e->error_code]);
329 return true;
332 xcb_keysym_t
333 xutil_key_mask_fromstr(const char *keyname, size_t len)
335 switch(a_tokenize(keyname, len))
337 case A_TK_SHIFT: return XCB_MOD_MASK_SHIFT;
338 case A_TK_LOCK: return XCB_MOD_MASK_LOCK;
339 case A_TK_CTRL:
340 case A_TK_CONTROL: return XCB_MOD_MASK_CONTROL;
341 case A_TK_MOD1: return XCB_MOD_MASK_1;
342 case A_TK_MOD2: return XCB_MOD_MASK_2;
343 case A_TK_MOD3: return XCB_MOD_MASK_3;
344 case A_TK_MOD4: return XCB_MOD_MASK_4;
345 case A_TK_MOD5: return XCB_MOD_MASK_5;
346 default: return XCB_NO_SYMBOL;
350 /** Permit to use mouse with many more buttons */
351 #ifndef XCB_BUTTON_INDEX_6
352 #define XCB_BUTTON_INDEX_6 6
353 #endif
354 #ifndef XCB_BUTTON_INDEX_7
355 #define XCB_BUTTON_INDEX_7 7
356 #endif
357 #ifndef XCB_BUTTON_INDEX_8
358 #define XCB_BUTTON_INDEX_8 8
359 #endif
360 #ifndef XCB_BUTTON_INDEX_9
361 #define XCB_BUTTON_INDEX_9 9
362 #endif
364 /** Link a name to a mouse button symbol */
365 typedef struct
367 int id;
368 unsigned int button;
369 } mouse_button_t;
371 /** Lookup for a mouse button from its index.
372 * \param button Mouse button index.
373 * \return Mouse button or 0 if not found.
375 unsigned int
376 xutil_button_fromint(int button)
378 /** List of button name and corresponding X11 mask codes */
379 static const mouse_button_t mouse_button_list[] =
381 { 1, XCB_BUTTON_INDEX_1 },
382 { 2, XCB_BUTTON_INDEX_2 },
383 { 3, XCB_BUTTON_INDEX_3 },
384 { 4, XCB_BUTTON_INDEX_4 },
385 { 5, XCB_BUTTON_INDEX_5 },
386 { 6, XCB_BUTTON_INDEX_6 },
387 { 7, XCB_BUTTON_INDEX_7 },
388 { 8, XCB_BUTTON_INDEX_8 },
389 { 9, XCB_BUTTON_INDEX_9 }
392 if(button >= 1 && button <= countof(mouse_button_list))
393 return mouse_button_list[button - 1].button;
395 return 0;
398 /** Equivalent to 'XCreateFontCursor()', error are handled by the
399 * default current error handler.
400 * \param conn The connection to the X server.
401 * \param cursor_font Type of cursor to use.
402 * \return Allocated cursor font.
404 xcb_cursor_t
405 xutil_cursor_new(xcb_connection_t *conn, unsigned int cursor_font)
407 static xcb_font_t font = XCB_NONE;
408 xcb_cursor_t cursor;
410 /* Get the font for the cursor */
411 if(!font)
413 font = xcb_generate_id(conn);
414 xcb_open_font(conn, font, sizeof(CURSORFONT) - 1, CURSORFONT);
417 cursor = xcb_generate_id(conn);
418 xcb_create_glyph_cursor(conn, cursor, font, font,
419 cursor_font, cursor_font + 1,
420 0, 0, 0,
421 65535, 65535, 65535);
423 return cursor;
426 /** Convert a root window a physical screen ID.
427 * \param connection The connection to the X server.
428 * \param root Root window.
429 * \return A physical screen number.
432 xutil_root2screen(xcb_connection_t *connection, xcb_window_t root)
434 xcb_screen_iterator_t iter;
435 int phys_screen = 0;
437 for(iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
438 iter.rem && iter.data->root != root; xcb_screen_next(&iter), ++phys_screen);
440 return phys_screen;
443 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80