awful.completion: callback functions return table of matches
[awesome.git] / ewmh.c
blob0aa5de708a4b2bc40797682d3d59ac230ff3bc32
1 /*
2 * ewmh.c - EWMH support functions
4 * Copyright © 2007-2009 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 <sys/types.h>
23 #include <unistd.h>
25 #include <xcb/xcb.h>
26 #include <xcb/xcb_atom.h>
28 #include "ewmh.h"
29 #include "tag.h"
30 #include "screen.h"
31 #include "client.h"
32 #include "widget.h"
33 #include "wibox.h"
34 #include "luaa.h"
35 #include "common/atoms.h"
36 #include "common/buffer.h"
37 #include "common/xutil.h"
39 #define _NET_WM_STATE_REMOVE 0
40 #define _NET_WM_STATE_ADD 1
41 #define _NET_WM_STATE_TOGGLE 2
43 /** Update the desktop geometry.
44 * \param phys_screen The physical screen id.
46 static void
47 ewmh_update_desktop_geometry(int phys_screen)
49 area_t geom = screen_area_get(&globalconf.screens.tab[phys_screen], false);
50 uint32_t sizes[] = { geom.width, geom.height };
52 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
53 xutil_screen_get(globalconf.connection, phys_screen)->root,
54 _NET_DESKTOP_GEOMETRY, XCB_ATOM_CARDINAL, 32, countof(sizes), sizes);
57 void
58 ewmh_init(int phys_screen)
60 xcb_window_t father;
61 xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
62 xcb_atom_t atom[] =
64 _NET_SUPPORTED,
65 _NET_SUPPORTING_WM_CHECK,
66 _NET_STARTUP_ID,
67 _NET_CLIENT_LIST,
68 _NET_CLIENT_LIST_STACKING,
69 _NET_NUMBER_OF_DESKTOPS,
70 _NET_CURRENT_DESKTOP,
71 _NET_DESKTOP_NAMES,
72 _NET_ACTIVE_WINDOW,
73 _NET_DESKTOP_GEOMETRY,
74 _NET_CLOSE_WINDOW,
75 _NET_WM_NAME,
76 _NET_WM_STRUT_PARTIAL,
77 _NET_WM_ICON_NAME,
78 _NET_WM_VISIBLE_ICON_NAME,
79 _NET_WM_DESKTOP,
80 _NET_WM_WINDOW_TYPE,
81 _NET_WM_WINDOW_TYPE_DESKTOP,
82 _NET_WM_WINDOW_TYPE_DOCK,
83 _NET_WM_WINDOW_TYPE_TOOLBAR,
84 _NET_WM_WINDOW_TYPE_MENU,
85 _NET_WM_WINDOW_TYPE_UTILITY,
86 _NET_WM_WINDOW_TYPE_SPLASH,
87 _NET_WM_WINDOW_TYPE_DIALOG,
88 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
89 _NET_WM_WINDOW_TYPE_POPUP_MENU,
90 _NET_WM_WINDOW_TYPE_TOOLTIP,
91 _NET_WM_WINDOW_TYPE_NOTIFICATION,
92 _NET_WM_WINDOW_TYPE_COMBO,
93 _NET_WM_WINDOW_TYPE_DND,
94 _NET_WM_WINDOW_TYPE_NORMAL,
95 _NET_WM_ICON,
96 _NET_WM_PID,
97 _NET_WM_STATE,
98 _NET_WM_STATE_STICKY,
99 _NET_WM_STATE_SKIP_TASKBAR,
100 _NET_WM_STATE_FULLSCREEN,
101 _NET_WM_STATE_MAXIMIZED_HORZ,
102 _NET_WM_STATE_MAXIMIZED_VERT,
103 _NET_WM_STATE_ABOVE,
104 _NET_WM_STATE_BELOW,
105 _NET_WM_STATE_MODAL,
106 _NET_WM_STATE_HIDDEN,
107 _NET_WM_STATE_DEMANDS_ATTENTION
109 int i;
111 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
112 xscreen->root, _NET_SUPPORTED, XCB_ATOM_ATOM, 32,
113 countof(atom), atom);
115 /* create our own window */
116 father = xcb_generate_id(globalconf.connection);
117 xcb_create_window(globalconf.connection, xscreen->root_depth,
118 father, xscreen->root, -1, -1, 1, 1, 0,
119 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
121 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
122 xscreen->root, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
123 1, &father);
125 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
126 father, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
127 1, &father);
129 /* set the window manager name */
130 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
131 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
133 /* set the window manager PID */
134 i = getpid();
135 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
136 father, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &i);
138 ewmh_update_desktop_geometry(phys_screen);
141 void
142 ewmh_update_net_client_list(int phys_screen)
144 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
146 int n = 0;
147 foreach(_c, globalconf.clients)
149 client_t *c = *_c;
150 if(c->phys_screen == phys_screen)
151 wins[n++] = c->window;
154 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
155 xutil_screen_get(globalconf.connection, phys_screen)->root,
156 _NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, n, wins);
159 /** Set the client list in stacking order, bottom to top.
160 * \param phys_screen The physical screen id.
162 void
163 ewmh_update_net_client_list_stacking(int phys_screen)
165 int n = 0;
166 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
168 foreach(client, globalconf.stack)
169 if((*client)->phys_screen == phys_screen)
170 wins[n++] = (*client)->window;
172 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
173 xutil_screen_get(globalconf.connection, phys_screen)->root,
174 _NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, 32, n, wins);
177 void
178 ewmh_update_net_numbers_of_desktop(int phys_screen)
180 uint32_t count = globalconf.screens.tab[phys_screen].tags.len;
182 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
183 xutil_screen_get(globalconf.connection, phys_screen)->root,
184 _NET_NUMBER_OF_DESKTOPS, XCB_ATOM_CARDINAL, 32, 1, &count);
187 void
188 ewmh_update_net_current_desktop(int phys_screen)
190 uint32_t idx = tags_get_first_selected_index(&globalconf.screens.tab[phys_screen]);
192 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
193 xutil_screen_get(globalconf.connection, phys_screen)->root,
194 _NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &idx);
197 void
198 ewmh_update_net_desktop_names(int phys_screen)
200 buffer_t buf;
202 buffer_inita(&buf, BUFSIZ);
204 foreach(tag, globalconf.screens.tab[phys_screen].tags)
206 buffer_adds(&buf, tag_get_name(*tag));
207 buffer_addc(&buf, '\0');
210 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
211 xutil_screen_get(globalconf.connection, phys_screen)->root,
212 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
213 buffer_wipe(&buf);
216 void
217 ewmh_update_net_active_window(int phys_screen)
219 xcb_window_t win;
221 if(globalconf.screen_focus->client_focus
222 && globalconf.screen_focus->client_focus->phys_screen == phys_screen)
223 win = globalconf.screen_focus->client_focus->window;
224 else
225 win = XCB_NONE;
227 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
228 xutil_screen_get(globalconf.connection, phys_screen)->root,
229 _NET_ACTIVE_WINDOW, WINDOW, 32, 1, &win);
232 static void
233 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
235 luaA_object_push(globalconf.L, c);
237 if(state == _NET_WM_STATE_STICKY)
239 if(set == _NET_WM_STATE_REMOVE)
240 client_set_sticky(globalconf.L, -1, false);
241 else if(set == _NET_WM_STATE_ADD)
242 client_set_sticky(globalconf.L, -1, true);
243 else if(set == _NET_WM_STATE_TOGGLE)
244 client_set_sticky(globalconf.L, -1, !c->sticky);
246 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
248 if(set == _NET_WM_STATE_REMOVE)
250 client_set_skip_taskbar(globalconf.L, -1, false);
251 ewmh_client_update_hints(c);
253 else if(set == _NET_WM_STATE_ADD)
255 client_set_skip_taskbar(globalconf.L, -1, true);
256 ewmh_client_update_hints(c);
258 else if(set == _NET_WM_STATE_TOGGLE)
260 client_set_skip_taskbar(globalconf.L, -1, !c->skip_taskbar);
261 ewmh_client_update_hints(c);
264 else if(state == _NET_WM_STATE_FULLSCREEN)
266 if(set == _NET_WM_STATE_REMOVE)
267 client_set_fullscreen(globalconf.L, -1, false);
268 else if(set == _NET_WM_STATE_ADD)
269 client_set_fullscreen(globalconf.L, -1, true);
270 else if(set == _NET_WM_STATE_TOGGLE)
271 client_set_fullscreen(globalconf.L, -1, !c->fullscreen);
273 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
275 if(set == _NET_WM_STATE_REMOVE)
276 client_set_maximized_horizontal(globalconf.L, -1, false);
277 else if(set == _NET_WM_STATE_ADD)
278 client_set_maximized_horizontal(globalconf.L, -1, true);
279 else if(set == _NET_WM_STATE_TOGGLE)
280 client_set_maximized_horizontal(globalconf.L, -1, !c->maximized_horizontal);
282 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
284 if(set == _NET_WM_STATE_REMOVE)
285 client_set_maximized_vertical(globalconf.L, -1, false);
286 else if(set == _NET_WM_STATE_ADD)
287 client_set_maximized_vertical(globalconf.L, -1, true);
288 else if(set == _NET_WM_STATE_TOGGLE)
289 client_set_maximized_vertical(globalconf.L, -1, !c->maximized_vertical);
291 else if(state == _NET_WM_STATE_ABOVE)
293 if(set == _NET_WM_STATE_REMOVE)
294 client_set_above(globalconf.L, -1, false);
295 else if(set == _NET_WM_STATE_ADD)
296 client_set_above(globalconf.L, -1, true);
297 else if(set == _NET_WM_STATE_TOGGLE)
298 client_set_above(globalconf.L, -1, !c->above);
300 else if(state == _NET_WM_STATE_BELOW)
302 if(set == _NET_WM_STATE_REMOVE)
303 client_set_below(globalconf.L, -1, false);
304 else if(set == _NET_WM_STATE_ADD)
305 client_set_below(globalconf.L, -1, true);
306 else if(set == _NET_WM_STATE_TOGGLE)
307 client_set_below(globalconf.L, -1, !c->below);
309 else if(state == _NET_WM_STATE_MODAL)
311 if(set == _NET_WM_STATE_REMOVE)
312 client_set_modal(globalconf.L, -1, false);
313 else if(set == _NET_WM_STATE_ADD)
314 client_set_modal(globalconf.L, -1, true);
315 else if(set == _NET_WM_STATE_TOGGLE)
316 client_set_modal(globalconf.L, -1, !c->modal);
318 else if(state == _NET_WM_STATE_HIDDEN)
320 if(set == _NET_WM_STATE_REMOVE)
321 client_set_minimized(globalconf.L, -1, false);
322 else if(set == _NET_WM_STATE_ADD)
323 client_set_minimized(globalconf.L, -1, true);
324 else if(set == _NET_WM_STATE_TOGGLE)
325 client_set_minimized(globalconf.L, -1, !c->minimized);
327 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
329 if(set == _NET_WM_STATE_REMOVE)
330 client_set_urgent(globalconf.L, -1, false);
331 else if(set == _NET_WM_STATE_ADD)
332 client_set_urgent(globalconf.L, -1, true);
333 else if(set == _NET_WM_STATE_TOGGLE)
334 client_set_urgent(globalconf.L, -1, !c->urgent);
337 lua_pop(globalconf.L, 1);
341 ewmh_process_client_message(xcb_client_message_event_t *ev)
343 client_t *c;
344 int screen;
346 if(ev->type == _NET_CURRENT_DESKTOP)
347 for(screen = 0;
348 screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
349 screen++)
351 if(ev->window == xutil_screen_get(globalconf.connection, screen)->root)
352 tag_view_only_byindex(&globalconf.screens.tab[screen], ev->data.data32[0]);
354 else if(ev->type == _NET_CLOSE_WINDOW)
356 if((c = client_getbywin(ev->window)))
357 client_kill(c);
359 else if(ev->type == _NET_WM_DESKTOP)
361 if((c = client_getbywin(ev->window)))
363 tag_array_t *tags = &c->screen->tags;
365 if(ev->data.data32[0] == 0xffffffff)
366 c->sticky = true;
367 else
368 for(int i = 0; i < tags->len; i++)
369 if((int)ev->data.data32[0] == i)
371 luaA_object_push(globalconf.L, tags->tab[i]);
372 tag_client(c);
374 else
375 untag_client(c, tags->tab[i]);
378 else if(ev->type == _NET_WM_STATE)
380 if((c = client_getbywin(ev->window)))
382 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
383 if(ev->data.data32[2])
384 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
385 ev->data.data32[0]);
388 else if(ev->type == _NET_ACTIVE_WINDOW)
390 if((c = client_getbywin(ev->window)))
391 client_focus(c);
394 return 0;
397 /** Update client EWMH hints.
398 * \param c The client.
400 void
401 ewmh_client_update_hints(client_t *c)
403 xcb_atom_t state[10]; /* number of defined state atoms */
404 int i = 0;
406 if(c->modal)
407 state[i++] = _NET_WM_STATE_MODAL;
408 if(c->fullscreen)
409 state[i++] = _NET_WM_STATE_FULLSCREEN;
410 if(c->maximized_vertical)
411 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
412 if(c->maximized_horizontal)
413 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
414 if(c->sticky)
415 state[i++] = _NET_WM_STATE_STICKY;
416 if(c->skip_taskbar)
417 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
418 if(c->above)
419 state[i++] = _NET_WM_STATE_ABOVE;
420 if(c->below)
421 state[i++] = _NET_WM_STATE_BELOW;
422 if(c->minimized)
423 state[i++] = _NET_WM_STATE_HIDDEN;
424 if(c->urgent)
425 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
427 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
428 c->window, _NET_WM_STATE, ATOM, 32, i, state);
431 /** Update the client active desktop.
432 * This is "wrong" since it can be on several tags, but EWMH has a strict view
433 * of desktop system so just take the first tag.
434 * \param c The client.
436 void
437 ewmh_client_update_desktop(client_t *c)
439 int i;
440 tag_array_t *tags = &c->screen->tags;
442 for(i = 0; i < tags->len; i++)
443 if(is_client_tagged(c, tags->tab[i]))
445 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
446 c->window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &i);
447 return;
449 /* It doesn't have any tags, remove the property */
450 xcb_delete_property(globalconf.connection, c->window, _NET_WM_DESKTOP);
453 /** Update the client struts.
454 * \param window The window to update the struts for.
455 * \param strut The strut type to update the window with.
457 void
458 ewmh_update_strut(xcb_window_t window, strut_t *strut)
460 const uint32_t state[] =
462 strut->left,
463 strut->right,
464 strut->top,
465 strut->bottom,
466 strut->left_start_y,
467 strut->left_end_y,
468 strut->right_start_y,
469 strut->right_end_y,
470 strut->top_start_x,
471 strut->top_end_x,
472 strut->bottom_start_x,
473 strut->bottom_end_x
476 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
477 window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, countof(state), state);
480 void
481 ewmh_client_check_hints(client_t *c)
483 xcb_atom_t *state;
484 void *data = NULL;
485 int desktop;
486 xcb_get_property_cookie_t c0, c1, c2;
487 xcb_get_property_reply_t *reply;
489 /* Send the GetProperty requests which will be processed later */
490 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
491 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
493 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
494 _NET_WM_STATE, XCB_ATOM_ATOM, 0, UINT32_MAX);
496 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
497 _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 0, UINT32_MAX);
499 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
500 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
502 tag_array_t *tags = &c->screen->tags;
504 desktop = *(uint32_t *) data;
505 if(desktop == -1)
506 c->sticky = true;
507 else if (desktop >= 0 && desktop < tags->len)
508 for(int i = 0; i < tags->len; i++)
509 if(desktop == i)
511 luaA_object_push(globalconf.L, tags->tab[i]);
512 tag_client(c);
514 else
515 untag_client(c, tags->tab[i]);
516 else
517 /* Value out of bounds, just give it the first tag */
518 if (tags->len > 0)
520 luaA_object_push(globalconf.L, tags->tab[0]);
521 tag_client(c);
525 p_delete(&reply);
527 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
528 if(reply && (data = xcb_get_property_value(reply)))
530 state = (xcb_atom_t *) data;
531 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
532 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
535 p_delete(&reply);
537 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
538 if(reply && (data = xcb_get_property_value(reply)))
540 state = (xcb_atom_t *) data;
541 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
542 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
543 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
544 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
545 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
546 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
547 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
548 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
549 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
550 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
551 c->type = MAX(c->type, WINDOW_TYPE_MENU);
552 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
553 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
554 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
555 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
558 p_delete(&reply);
561 /** Process the WM strut of a client.
562 * \param c The client.
563 * \param strut_r (Optional) An existing reply.
565 void
566 ewmh_process_client_strut(client_t *c, xcb_get_property_reply_t *strut_r)
568 void *data;
569 xcb_get_property_reply_t *mstrut_r = NULL;
571 if(!strut_r)
573 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->window,
574 _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 0, 12);
575 strut_r = mstrut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
578 if(strut_r
579 && strut_r->value_len
580 && (data = xcb_get_property_value(strut_r)))
582 uint32_t *strut = data;
584 if(c->strut.left != strut[0]
585 || c->strut.right != strut[1]
586 || c->strut.top != strut[2]
587 || c->strut.bottom != strut[3]
588 || c->strut.left_start_y != strut[4]
589 || c->strut.left_end_y != strut[5]
590 || c->strut.right_start_y != strut[6]
591 || c->strut.right_end_y != strut[7]
592 || c->strut.top_start_x != strut[8]
593 || c->strut.top_end_x != strut[9]
594 || c->strut.bottom_start_x != strut[10]
595 || c->strut.bottom_end_x != strut[11])
597 c->strut.left = strut[0];
598 c->strut.right = strut[1];
599 c->strut.top = strut[2];
600 c->strut.bottom = strut[3];
601 c->strut.left_start_y = strut[4];
602 c->strut.left_end_y = strut[5];
603 c->strut.right_start_y = strut[6];
604 c->strut.right_end_y = strut[7];
605 c->strut.top_start_x = strut[8];
606 c->strut.top_end_x = strut[9];
607 c->strut.bottom_start_x = strut[10];
608 c->strut.bottom_end_x = strut[11];
610 hook_property(c, "struts");
611 luaA_object_push(globalconf.L, c);
612 luaA_object_emit_signal(globalconf.L, -1, "property::struts", 0);
613 lua_pop(globalconf.L, 1);
617 p_delete(&mstrut_r);
620 /** Send request to get NET_WM_ICON (EWMH)
621 * \param w The window.
622 * \return The cookie associated with the request.
624 xcb_get_property_cookie_t
625 ewmh_window_icon_get_unchecked(xcb_window_t w)
627 return xcb_get_property_unchecked(globalconf.connection, false, w,
628 _NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX);
632 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
634 uint32_t *data;
635 uint64_t len;
637 if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2)
638 return 0;
640 data = (uint32_t *) xcb_get_property_value(r);
641 if (!data)
642 return 0;
644 /* Check that the property is as long as it should be, handling integer
645 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
646 * fits into an uint64_t and thus this multiplication cannot overflow.
648 len = data[0] * (uint64_t) data[1];
649 if (!data[0] || !data[1] || len > r->length - 2)
650 return 0;
652 return image_new_from_argb32(data[0], data[1], data + 2);
655 /** Get NET_WM_ICON.
656 * \param cookie The cookie.
657 * \return The number of elements on stack.
660 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
662 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
663 int ret = ewmh_window_icon_from_reply(r);
664 p_delete(&r);
665 return ret;
668 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80