banning: remove passive refresh support (FS#629)
[awesome.git] / ewmh.c
blobb84e18c74524cc3b3fb362e7f870c856de9ab209
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, 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_WORKAREA,
74 _NET_DESKTOP_GEOMETRY,
75 _NET_CLOSE_WINDOW,
76 _NET_WM_NAME,
77 _NET_WM_STRUT_PARTIAL,
78 _NET_WM_ICON_NAME,
79 _NET_WM_VISIBLE_ICON_NAME,
80 _NET_WM_DESKTOP,
81 _NET_WM_WINDOW_TYPE,
82 _NET_WM_WINDOW_TYPE_DESKTOP,
83 _NET_WM_WINDOW_TYPE_DOCK,
84 _NET_WM_WINDOW_TYPE_TOOLBAR,
85 _NET_WM_WINDOW_TYPE_MENU,
86 _NET_WM_WINDOW_TYPE_UTILITY,
87 _NET_WM_WINDOW_TYPE_SPLASH,
88 _NET_WM_WINDOW_TYPE_DIALOG,
89 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
90 _NET_WM_WINDOW_TYPE_POPUP_MENU,
91 _NET_WM_WINDOW_TYPE_TOOLTIP,
92 _NET_WM_WINDOW_TYPE_NOTIFICATION,
93 _NET_WM_WINDOW_TYPE_COMBO,
94 _NET_WM_WINDOW_TYPE_DND,
95 _NET_WM_WINDOW_TYPE_NORMAL,
96 _NET_WM_ICON,
97 _NET_WM_PID,
98 _NET_WM_STATE,
99 _NET_WM_STATE_STICKY,
100 _NET_WM_STATE_SKIP_TASKBAR,
101 _NET_WM_STATE_FULLSCREEN,
102 _NET_WM_STATE_MAXIMIZED_HORZ,
103 _NET_WM_STATE_MAXIMIZED_VERT,
104 _NET_WM_STATE_ABOVE,
105 _NET_WM_STATE_BELOW,
106 _NET_WM_STATE_MODAL,
107 _NET_WM_STATE_HIDDEN,
108 _NET_WM_STATE_DEMANDS_ATTENTION
110 int i;
112 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
113 xscreen->root, _NET_SUPPORTED, ATOM, 32,
114 countof(atom), atom);
116 /* create our own window */
117 father = xcb_generate_id(globalconf.connection);
118 xcb_create_window(globalconf.connection, xscreen->root_depth,
119 father, xscreen->root, -1, -1, 1, 1, 0,
120 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
122 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
123 xscreen->root, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
124 1, &father);
126 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
127 father, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
128 1, &father);
130 /* set the window manager name */
131 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
132 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
134 /* set the window manager PID */
135 i = getpid();
136 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
137 father, _NET_WM_PID, CARDINAL, 32, 1, &i);
139 ewmh_update_desktop_geometry(phys_screen);
142 void
143 ewmh_update_net_client_list(int phys_screen)
145 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
147 int n = 0;
148 foreach(_c, globalconf.clients)
150 client_t *c = *_c;
151 if(c->phys_screen == phys_screen)
152 wins[n++] = c->window;
155 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
156 xutil_screen_get(globalconf.connection, phys_screen)->root,
157 _NET_CLIENT_LIST, WINDOW, 32, n, wins);
160 /** Set the client list in stacking order, bottom to top.
161 * \param phys_screen The physical screen id.
163 void
164 ewmh_update_net_client_list_stacking(int phys_screen)
166 int n = 0;
167 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
169 foreach(client, globalconf.stack)
170 if((*client)->phys_screen == phys_screen)
171 wins[n++] = (*client)->window;
173 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
174 xutil_screen_get(globalconf.connection, phys_screen)->root,
175 _NET_CLIENT_LIST_STACKING, WINDOW, 32, n, wins);
178 void
179 ewmh_update_net_numbers_of_desktop(int phys_screen)
181 uint32_t count = globalconf.screens.tab[phys_screen].tags.len;
183 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
184 xutil_screen_get(globalconf.connection, phys_screen)->root,
185 _NET_NUMBER_OF_DESKTOPS, CARDINAL, 32, 1, &count);
188 void
189 ewmh_update_net_current_desktop(int phys_screen)
191 uint32_t idx = tags_get_first_selected_index(&globalconf.screens.tab[phys_screen]);
193 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
194 xutil_screen_get(globalconf.connection, phys_screen)->root,
195 _NET_CURRENT_DESKTOP, CARDINAL, 32, 1, &idx);
198 void
199 ewmh_update_net_desktop_names(int phys_screen)
201 buffer_t buf;
203 buffer_inita(&buf, BUFSIZ);
205 foreach(tag, globalconf.screens.tab[phys_screen].tags)
207 buffer_adds(&buf, tag_get_name(*tag));
208 buffer_addc(&buf, '\0');
211 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
212 xutil_screen_get(globalconf.connection, phys_screen)->root,
213 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
214 buffer_wipe(&buf);
217 /** Update the work area space for each physical screen and each desktop.
218 * \param phys_screen The physical screen id.
220 void
221 ewmh_update_workarea(int phys_screen)
223 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
224 uint32_t *area = p_alloca(uint32_t, tags->len * 4);
225 area_t geom = screen_area_get(&globalconf.screens.tab[phys_screen], true);
227 for(int i = 0; i < tags->len; i++)
229 area[4 * i + 0] = geom.x;
230 area[4 * i + 1] = geom.y;
231 area[4 * i + 2] = geom.width;
232 area[4 * i + 3] = geom.height;
235 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
236 xutil_screen_get(globalconf.connection, phys_screen)->root,
237 _NET_WORKAREA, CARDINAL, 32, tags->len * 4, area);
240 void
241 ewmh_update_net_active_window(int phys_screen)
243 xcb_window_t win;
245 if(globalconf.screen_focus->client_focus
246 && globalconf.screen_focus->client_focus->phys_screen == phys_screen)
247 win = globalconf.screen_focus->client_focus->window;
248 else
249 win = XCB_NONE;
251 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
252 xutil_screen_get(globalconf.connection, phys_screen)->root,
253 _NET_ACTIVE_WINDOW, WINDOW, 32, 1, &win);
256 static void
257 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
259 luaA_object_push(globalconf.L, c);
261 if(state == _NET_WM_STATE_STICKY)
263 if(set == _NET_WM_STATE_REMOVE)
264 client_set_sticky(globalconf.L, -1, false);
265 else if(set == _NET_WM_STATE_ADD)
266 client_set_sticky(globalconf.L, -1, true);
267 else if(set == _NET_WM_STATE_TOGGLE)
268 client_set_sticky(globalconf.L, -1, !c->sticky);
270 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
272 if(set == _NET_WM_STATE_REMOVE)
274 client_set_skip_taskbar(globalconf.L, -1, false);
275 ewmh_client_update_hints(c);
277 else if(set == _NET_WM_STATE_ADD)
279 client_set_skip_taskbar(globalconf.L, -1, true);
280 ewmh_client_update_hints(c);
282 else if(set == _NET_WM_STATE_TOGGLE)
284 client_set_skip_taskbar(globalconf.L, -1, !c->skip_taskbar);
285 ewmh_client_update_hints(c);
288 else if(state == _NET_WM_STATE_FULLSCREEN)
290 if(set == _NET_WM_STATE_REMOVE)
291 client_set_fullscreen(globalconf.L, -1, false);
292 else if(set == _NET_WM_STATE_ADD)
293 client_set_fullscreen(globalconf.L, -1, true);
294 else if(set == _NET_WM_STATE_TOGGLE)
295 client_set_fullscreen(globalconf.L, -1, !c->fullscreen);
297 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
299 if(set == _NET_WM_STATE_REMOVE)
300 client_set_maximized_horizontal(globalconf.L, -1, false);
301 else if(set == _NET_WM_STATE_ADD)
302 client_set_maximized_horizontal(globalconf.L, -1, true);
303 else if(set == _NET_WM_STATE_TOGGLE)
304 client_set_maximized_horizontal(globalconf.L, -1, c->maximized_horizontal);
306 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
308 if(set == _NET_WM_STATE_REMOVE)
309 client_set_maximized_vertical(globalconf.L, -1, false);
310 else if(set == _NET_WM_STATE_ADD)
311 client_set_maximized_vertical(globalconf.L, -1, true);
312 else if(set == _NET_WM_STATE_TOGGLE)
313 client_set_maximized_vertical(globalconf.L, -1, !c->maximized_vertical);
315 else if(state == _NET_WM_STATE_ABOVE)
317 if(set == _NET_WM_STATE_REMOVE)
318 client_set_above(globalconf.L, -1, false);
319 else if(set == _NET_WM_STATE_ADD)
320 client_set_above(globalconf.L, -1, true);
321 else if(set == _NET_WM_STATE_TOGGLE)
322 client_set_above(globalconf.L, -1, !c->above);
324 else if(state == _NET_WM_STATE_BELOW)
326 if(set == _NET_WM_STATE_REMOVE)
327 client_set_below(globalconf.L, -1, false);
328 else if(set == _NET_WM_STATE_ADD)
329 client_set_below(globalconf.L, -1, true);
330 else if(set == _NET_WM_STATE_TOGGLE)
331 client_set_below(globalconf.L, -1, !c->below);
333 else if(state == _NET_WM_STATE_MODAL)
335 if(set == _NET_WM_STATE_REMOVE)
336 client_set_modal(globalconf.L, -1, false);
337 else if(set == _NET_WM_STATE_ADD)
338 client_set_modal(globalconf.L, -1, true);
339 else if(set == _NET_WM_STATE_TOGGLE)
340 client_set_modal(globalconf.L, -1, !c->modal);
342 else if(state == _NET_WM_STATE_HIDDEN)
344 if(set == _NET_WM_STATE_REMOVE)
345 client_set_minimized(globalconf.L, -1, false);
346 else if(set == _NET_WM_STATE_ADD)
347 client_set_minimized(globalconf.L, -1, true);
348 else if(set == _NET_WM_STATE_TOGGLE)
349 client_set_minimized(globalconf.L, -1, !c->minimized);
351 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
353 if(set == _NET_WM_STATE_REMOVE)
354 client_set_urgent(globalconf.L, -1, false);
355 else if(set == _NET_WM_STATE_ADD)
356 client_set_urgent(globalconf.L, -1, true);
357 else if(set == _NET_WM_STATE_TOGGLE)
358 client_set_urgent(globalconf.L, -1, !c->urgent);
363 ewmh_process_client_message(xcb_client_message_event_t *ev)
365 client_t *c;
366 int screen;
368 if(ev->type == _NET_CURRENT_DESKTOP)
369 for(screen = 0;
370 screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
371 screen++)
373 if(ev->window == xutil_screen_get(globalconf.connection, screen)->root)
374 tag_view_only_byindex(&globalconf.screens.tab[screen], ev->data.data32[0]);
376 else if(ev->type == _NET_CLOSE_WINDOW)
378 if((c = client_getbywin(ev->window)))
379 client_kill(c);
381 else if(ev->type == _NET_WM_DESKTOP)
383 if((c = client_getbywin(ev->window)))
385 tag_array_t *tags = &c->screen->tags;
387 if(ev->data.data32[0] == 0xffffffff)
388 c->sticky = true;
389 else
390 for(int i = 0; i < tags->len; i++)
391 if((int)ev->data.data32[0] == i)
393 luaA_object_push(globalconf.L, tags->tab[i]);
394 tag_client(c);
396 else
397 untag_client(c, tags->tab[i]);
400 else if(ev->type == _NET_WM_STATE)
402 if((c = client_getbywin(ev->window)))
404 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
405 if(ev->data.data32[2])
406 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
407 ev->data.data32[0]);
410 else if(ev->type == _NET_ACTIVE_WINDOW)
412 if((c = client_getbywin(ev->window)))
413 client_focus(c);
416 return 0;
419 /** Update client EWMH hints.
420 * \param c The client.
422 void
423 ewmh_client_update_hints(client_t *c)
425 xcb_atom_t state[10]; /* number of defined state atoms */
426 int i = 0;
428 if(c->modal)
429 state[i++] = _NET_WM_STATE_MODAL;
430 if(c->fullscreen)
431 state[i++] = _NET_WM_STATE_FULLSCREEN;
432 if(c->maximized_vertical)
433 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
434 if(c->maximized_horizontal)
435 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
436 if(c->sticky)
437 state[i++] = _NET_WM_STATE_STICKY;
438 if(c->skip_taskbar)
439 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
440 if(c->above)
441 state[i++] = _NET_WM_STATE_ABOVE;
442 if(c->below)
443 state[i++] = _NET_WM_STATE_BELOW;
444 if(c->minimized)
445 state[i++] = _NET_WM_STATE_HIDDEN;
446 if(c->urgent)
447 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
449 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
450 c->window, _NET_WM_STATE, ATOM, 32, i, state);
453 /** Update the client active desktop.
454 * This is "wrong" since it can be on several tags, but EWMH has a strict view
455 * of desktop system so just take the first tag.
456 * \param c The client.
458 void
459 ewmh_client_update_desktop(client_t *c)
461 int i;
462 tag_array_t *tags = &c->screen->tags;
464 for(i = 0; i < tags->len; i++)
465 if(is_client_tagged(c, tags->tab[i]))
467 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
468 c->window, _NET_WM_DESKTOP, CARDINAL, 32, 1, &i);
469 return;
473 /** Update the client struts.
474 * \param window The window to update the struts for.
475 * \param strut The strut type to update the window with.
477 void
478 ewmh_update_strut(xcb_window_t window, strut_t *strut)
480 const uint32_t state[] =
482 strut->left,
483 strut->right,
484 strut->top,
485 strut->bottom,
486 strut->left_start_y,
487 strut->left_end_y,
488 strut->right_start_y,
489 strut->right_end_y,
490 strut->top_start_x,
491 strut->top_end_x,
492 strut->bottom_start_x,
493 strut->bottom_end_x
496 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
497 window, _NET_WM_STRUT_PARTIAL, CARDINAL, 32, countof(state), state);
500 void
501 ewmh_client_check_hints(client_t *c)
503 xcb_atom_t *state;
504 void *data = NULL;
505 int desktop;
506 xcb_get_property_cookie_t c0, c1, c2;
507 xcb_get_property_reply_t *reply;
509 /* Send the GetProperty requests which will be processed later */
510 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
511 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
513 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
514 _NET_WM_STATE, ATOM, 0, UINT32_MAX);
516 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
517 _NET_WM_WINDOW_TYPE, ATOM, 0, UINT32_MAX);
519 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
520 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
522 tag_array_t *tags = &c->screen->tags;
524 desktop = *(uint32_t *) data;
525 if(desktop == -1)
526 c->sticky = true;
527 else
528 for(int i = 0; i < tags->len; i++)
529 if(desktop == i)
531 luaA_object_push(globalconf.L, tags->tab[i]);
532 tag_client(c);
534 else
535 untag_client(c, tags->tab[i]);
538 p_delete(&reply);
540 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
541 if(reply && (data = xcb_get_property_value(reply)))
543 state = (xcb_atom_t *) data;
544 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
545 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
548 p_delete(&reply);
550 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
551 if(reply && (data = xcb_get_property_value(reply)))
553 state = (xcb_atom_t *) data;
554 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
555 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
556 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
557 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
558 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
559 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
560 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
561 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
562 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
563 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
564 c->type = MAX(c->type, WINDOW_TYPE_MENU);
565 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
566 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
567 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
568 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
571 p_delete(&reply);
574 /** Process the WM strut of a client.
575 * \param c The client.
576 * \param strut_r (Optional) An existing reply.
578 void
579 ewmh_process_client_strut(client_t *c, xcb_get_property_reply_t *strut_r)
581 void *data;
582 xcb_get_property_reply_t *mstrut_r = NULL;
584 if(!strut_r)
586 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->window,
587 _NET_WM_STRUT_PARTIAL, CARDINAL, 0, 12);
588 strut_r = mstrut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
591 if(strut_r
592 && strut_r->value_len
593 && (data = xcb_get_property_value(strut_r)))
595 uint32_t *strut = data;
597 if(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 c->strut.left = strut[0];
611 c->strut.right = strut[1];
612 c->strut.top = strut[2];
613 c->strut.bottom = strut[3];
614 c->strut.left_start_y = strut[4];
615 c->strut.left_end_y = strut[5];
616 c->strut.right_start_y = strut[6];
617 c->strut.right_end_y = strut[7];
618 c->strut.top_start_x = strut[8];
619 c->strut.top_end_x = strut[9];
620 c->strut.bottom_start_x = strut[10];
621 c->strut.bottom_end_x = strut[11];
623 hook_property(c, "struts");
624 luaA_object_push(globalconf.L, c);
625 luaA_object_emit_signal(globalconf.L, -1, "property::struts", 0);
626 lua_pop(globalconf.L, 1);
630 p_delete(&mstrut_r);
633 /** Send request to get NET_WM_ICON (EWMH)
634 * \param w The window.
635 * \return The cookie associated with the request.
637 xcb_get_property_cookie_t
638 ewmh_window_icon_get_unchecked(xcb_window_t w)
640 return xcb_get_property_unchecked(globalconf.connection, false, w,
641 _NET_WM_ICON, CARDINAL, 0, UINT32_MAX);
645 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
647 uint32_t *data;
648 uint64_t len;
650 if(!r || r->type != CARDINAL || r->format != 32 || r->length < 2)
651 return 0;
653 data = (uint32_t *) xcb_get_property_value(r);
654 if (!data)
655 return 0;
657 /* Check that the property is as long as it should be, handling integer
658 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
659 * fits into an uint64_t and thus this multiplication cannot overflow.
661 len = data[0] * (uint64_t) data[1];
662 if (!data[0] || !data[1] || len > r->length - 2)
663 return 0;
665 return image_new_from_argb32(data[0], data[1], data + 2);
668 /** Get NET_WM_ICON.
669 * \param cookie The cookie.
670 * \return The number of elements on stack.
673 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
675 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
676 int ret = ewmh_window_icon_from_reply(r);
677 p_delete(&r);
678 return ret;
681 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80