titlebar: generate mouse_enter and button events for the entire titlebar (and redirec...
[awesome.git] / common / xutil.c
blob40891daaadc11495d97f2eae4a8ab693200465a7
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 /* asprintf() */
23 #define _GNU_SOURCE
25 #include <stdio.h>
27 #include <xcb/xcb.h>
28 #include <xcb/xcb_atom.h>
29 #include <xcb/xcb_icccm.h>
31 /* CURSORFONT */
32 #include <X11/Xlibint.h>
34 #include "common/util.h"
35 #include "common/xutil.h"
36 #include "common/atoms.h"
38 /** Get the string value of an atom.
39 * \param conn X connection.
40 * \param w Window.
41 * \param atom The atom.
42 * \param text Buffer to fill.
43 * \param len Length of the filled buffer.
44 * \return True on sucess, false on failure.
46 bool
47 xutil_text_prop_get(xcb_connection_t *conn, xcb_window_t w, xcb_atom_t atom,
48 char **text, ssize_t *len)
50 xcb_get_text_property_reply_t reply;
52 p_clear(&reply, 1);
54 if(!xcb_get_text_property_reply(conn,
55 xcb_get_text_property_unchecked(conn, w,
56 atom),
57 &reply, NULL) ||
58 !reply.name_len || reply.format != 8)
60 xcb_get_text_property_reply_wipe(&reply);
61 return false;
64 if(text && len)
66 /* Check whether the returned property value is just an ascii
67 * string or utf8 string. At the moment it doesn't handle
68 * COMPOUND_TEXT and multibyte but it's not needed... */
69 if(reply.encoding == STRING || reply.encoding == UTF8_STRING)
71 *text = p_new(char, reply.name_len + 1);
72 /* Use memcpy() because the property name is not be \0
73 * terminated */
74 memcpy(*text, reply.name, reply.name_len);
75 (*text)[reply.name_len] = '\0';
76 *len = reply.name_len;
78 else
80 *text = NULL;
81 *len = 0;
85 xcb_get_text_property_reply_wipe(&reply);
86 return true;
89 /** Get the lock masks (shiftlock, numlock, capslock).
90 * \param connection The X connection.
91 * \param cookie The cookie of the request.
92 * \param keysyms Key symbols.
93 * \param numlockmask Numlock mask.
94 * \param shiftlockmask Shiftlock mask.
95 * \param capslockmask Capslock mask.
97 void
98 xutil_lock_mask_get(xcb_connection_t *connection,
99 xcb_get_modifier_mapping_cookie_t cookie,
100 xcb_key_symbols_t *keysyms,
101 unsigned int *numlockmask,
102 unsigned int *shiftlockmask,
103 unsigned int *capslockmask)
105 xcb_get_modifier_mapping_reply_t *modmap_r;
106 xcb_keycode_t *modmap, kc;
107 unsigned int mask;
108 int i, j;
110 modmap_r = xcb_get_modifier_mapping_reply(connection, cookie, NULL);
111 modmap = xcb_get_modifier_mapping_keycodes(modmap_r);
113 for(i = 0; i < 8; i++)
114 for(j = 0; j < modmap_r->keycodes_per_modifier; j++)
116 kc = modmap[i * modmap_r->keycodes_per_modifier + j];
117 mask = (1 << i);
119 if(numlockmask != NULL
120 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Num_Lock))
121 *numlockmask = mask;
122 else if(shiftlockmask != NULL
123 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Shift_Lock))
124 *shiftlockmask = mask;
125 else if(capslockmask != NULL
126 && kc == xcb_key_symbols_get_keycode(keysyms, XK_Caps_Lock))
127 *capslockmask = mask;
130 p_delete(&modmap_r);
133 /* Number of different errors */
134 #define ERRORS_NBR 256
136 /* Number of different events */
137 #define EVENTS_NBR 126
139 void
140 xutil_error_handler_catch_all_set(xcb_event_handlers_t *evenths,
141 xcb_generic_error_handler_t handler,
142 void *data)
144 int err_num;
145 for(err_num = 0; err_num < ERRORS_NBR; err_num++)
146 xcb_event_set_error_handler(evenths, err_num, handler, data);
149 const char *
150 xutil_label_error[] =
152 "Success",
153 "BadRequest",
154 "BadValue",
155 "BadWindow",
156 "BadPixmap",
157 "BadAtom",
158 "BadCursor",
159 "BadFont",
160 "BadMatch",
161 "BadDrawable",
162 "BadAccess",
163 "BadAlloc",
164 "BadColor",
165 "BadGC",
166 "BadIDChoice",
167 "BadName",
168 "BadLength",
169 "BadImplementation",
172 const char *
173 xutil_label_request[] =
175 "None",
176 "CreateWindow",
177 "ChangeWindowAttributes",
178 "GetWindowAttributes",
179 "DestroyWindow",
180 "DestroySubwindows",
181 "ChangeSaveSet",
182 "ReparentWindow",
183 "MapWindow",
184 "MapSubwindows",
185 "UnmapWindow",
186 "UnmapSubwindows",
187 "ConfigureWindow",
188 "CirculateWindow",
189 "GetGeometry",
190 "QueryTree",
191 "InternAtom",
192 "GetAtomName",
193 "ChangeProperty",
194 "DeleteProperty",
195 "GetProperty",
196 "ListProperties",
197 "SetSelectionOwner",
198 "GetSelectionOwner",
199 "ConvertSelection",
200 "SendEvent",
201 "GrabPointer",
202 "UngrabPointer",
203 "GrabButton",
204 "UngrabButton",
205 "ChangeActivePointerGrab",
206 "GrabKeyboard",
207 "UngrabKeyboard",
208 "GrabKey",
209 "UngrabKey",
210 "AllowEvents",
211 "GrabServer",
212 "UngrabServer",
213 "QueryPointer",
214 "GetMotionEvents",
215 "TranslateCoords",
216 "WarpPointer",
217 "SetInputFocus",
218 "GetInputFocus",
219 "QueryKeymap",
220 "OpenFont",
221 "CloseFont",
222 "QueryFont",
223 "QueryTextExtents",
224 "ListFonts",
225 "ListFontsWithInfo",
226 "SetFontPath",
227 "GetFontPath",
228 "CreatePixmap",
229 "FreePixmap",
230 "CreateGC",
231 "ChangeGC",
232 "CopyGC",
233 "SetDashes",
234 "SetClipRectangles",
235 "FreeGC",
236 "ClearArea",
237 "CopyArea",
238 "CopyPlane",
239 "PolyPoint",
240 "PolyLine",
241 "PolySegment",
242 "PolyRectangle",
243 "PolyArc",
244 "FillPoly",
245 "PolyFillRectangle",
246 "PolyFillArc",
247 "PutImage",
248 "GetImage",
249 "PolyText",
250 "PolyText",
251 "ImageText",
252 "ImageText",
253 "CreateColormap",
254 "FreeColormap",
255 "CopyColormapAndFree",
256 "InstallColormap",
257 "UninstallColormap",
258 "ListInstalledColormaps",
259 "AllocColor",
260 "AllocNamedColor",
261 "AllocColorCells",
262 "AllocColorPlanes",
263 "FreeColors",
264 "StoreColors",
265 "StoreNamedColor",
266 "QueryColors",
267 "LookupColor",
268 "CreateCursor",
269 "CreateGlyphCursor",
270 "FreeCursor",
271 "RecolorCursor",
272 "QueryBestSize",
273 "QueryExtension",
274 "ListExtensions",
275 "ChangeKeyboardMapping",
276 "GetKeyboardMapping",
277 "ChangeKeyboardControl",
278 "GetKeyboardControl",
279 "Bell",
280 "ChangePointerControl",
281 "GetPointerControl",
282 "SetScreenSaver",
283 "GetScreenSaver",
284 "ChangeHosts",
285 "ListHosts",
286 "SetAccessControl",
287 "SetCloseDownMode",
288 "KillClient",
289 "RotateProperties",
290 "ForceScreenSaver",
291 "SetPointerMapping",
292 "GetPointerMapping",
293 "SetModifierMapping",
294 "GetModifierMapping",
295 "major 120",
296 "major 121",
297 "major 122",
298 "major 123",
299 "major 124",
300 "major 125",
301 "major 126",
302 "NoOperation",
305 bool
306 xutil_error_init(const xcb_generic_error_t *e, xutil_error_t *err)
308 if(e->response_type != 0)
309 /* This is not an error, this _should_ not happen */
310 return false;
313 * Get the request code, taken from 'xcb-util/wm'. I can't figure
314 * out how it works BTW, seems to get a byte in 'pad' member
315 * (second byte in second element of the array)
317 err->request_code = *((uint8_t *) e + 10);
319 /* Extensions generally provide their own requests so we just
320 * store the request code */
321 if(err->request_code >= (sizeof(xutil_label_request) / sizeof(char *)))
322 asprintf(&err->request_label, "%d", err->request_code);
323 else
324 err->request_label = a_strdup(xutil_label_request[err->request_code]);
326 /* Extensions may also define their own errors, so just store the
327 * error_code */
328 if(e->error_code >= (sizeof(xutil_label_error) / sizeof(char *)))
329 asprintf(&err->error_label, "%d", e->error_code);
330 else
331 err->error_label = a_strdup(xutil_label_error[e->error_code]);
333 return true;
336 xcb_keysym_t
337 xutil_key_mask_fromstr(const char *keyname, size_t len)
339 switch(a_tokenize(keyname, len))
341 case A_TK_SHIFT: return XCB_MOD_MASK_SHIFT;
342 case A_TK_LOCK: return XCB_MOD_MASK_LOCK;
343 case A_TK_CTRL:
344 case A_TK_CONTROL: return XCB_MOD_MASK_CONTROL;
345 case A_TK_MOD1: return XCB_MOD_MASK_1;
346 case A_TK_MOD2: return XCB_MOD_MASK_2;
347 case A_TK_MOD3: return XCB_MOD_MASK_3;
348 case A_TK_MOD4: return XCB_MOD_MASK_4;
349 case A_TK_MOD5: return XCB_MOD_MASK_5;
350 default: return XCB_NO_SYMBOL;
354 /** Permit to use mouse with many more buttons */
355 #ifndef XCB_BUTTON_INDEX_6
356 #define XCB_BUTTON_INDEX_6 6
357 #endif
358 #ifndef XCB_BUTTON_INDEX_7
359 #define XCB_BUTTON_INDEX_7 7
360 #endif
361 #ifndef XCB_BUTTON_INDEX_8
362 #define XCB_BUTTON_INDEX_8 8
363 #endif
364 #ifndef XCB_BUTTON_INDEX_9
365 #define XCB_BUTTON_INDEX_9 9
366 #endif
368 /** Link a name to a mouse button symbol */
369 typedef struct
371 int id;
372 unsigned int button;
373 } mouse_button_t;
375 /** Lookup for a mouse button from its index.
376 * \param button Mouse button index.
377 * \return Mouse button or 0 if not found.
379 unsigned int
380 xutil_button_fromint(int button)
382 /** List of button name and corresponding X11 mask codes */
383 static const mouse_button_t mouse_button_list[] =
385 { 1, XCB_BUTTON_INDEX_1 },
386 { 2, XCB_BUTTON_INDEX_2 },
387 { 3, XCB_BUTTON_INDEX_3 },
388 { 4, XCB_BUTTON_INDEX_4 },
389 { 5, XCB_BUTTON_INDEX_5 },
390 { 6, XCB_BUTTON_INDEX_6 },
391 { 7, XCB_BUTTON_INDEX_7 },
392 { 8, XCB_BUTTON_INDEX_8 },
393 { 9, XCB_BUTTON_INDEX_9 }
396 if(button >= 1 && button <= countof(mouse_button_list))
397 return mouse_button_list[button - 1].button;
399 return 0;
402 /** Equivalent to 'XCreateFontCursor()', error are handled by the
403 * default current error handler.
404 * \param conn The connection to the X server.
405 * \param cursor_font Type of cursor to use.
406 * \return Allocated cursor font.
408 xcb_cursor_t
409 xutil_cursor_new(xcb_connection_t *conn, unsigned int cursor_font)
411 static xcb_font_t font = XCB_NONE;
412 xcb_cursor_t cursor;
414 /* Get the font for the cursor */
415 if(!font)
417 font = xcb_generate_id(conn);
418 xcb_open_font(conn, font, sizeof(CURSORFONT) - 1, CURSORFONT);
421 cursor = xcb_generate_id(conn);
422 xcb_create_glyph_cursor(conn, cursor, font, font,
423 cursor_font, cursor_font + 1,
424 0, 0, 0,
425 65535, 65535, 65535);
427 return cursor;
430 /** Convert a root window a physical screen ID.
431 * \param connection The connection to the X server.
432 * \param root Root window.
433 * \return A physical screen number.
436 xutil_root2screen(xcb_connection_t *connection, xcb_window_t root)
438 xcb_screen_iterator_t iter;
439 int phys_screen = 0;
441 for(iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
442 iter.rem && iter.data->root != root; xcb_screen_next(&iter), ++phys_screen);
444 return phys_screen;
447 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80