change codename
[awesome.git] / ewmh.c
blobacadee52546c3f11890182f962e0fdd82cb7a3d5
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 "common/atoms.h"
35 #include "common/buffer.h"
36 #include "common/xutil.h"
38 #define _NET_WM_STATE_REMOVE 0
39 #define _NET_WM_STATE_ADD 1
40 #define _NET_WM_STATE_TOGGLE 2
42 /** Update the desktop geometry.
43 * \param phys_screen The physical screen id.
45 static void
46 ewmh_update_desktop_geometry(int phys_screen)
48 area_t geom = screen_area_get(&globalconf.screens.tab[phys_screen],
49 NULL,
50 NULL,
51 false);
52 uint32_t sizes[] = { geom.width, geom.height };
54 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
55 xutil_screen_get(globalconf.connection, phys_screen)->root,
56 _NET_DESKTOP_GEOMETRY, CARDINAL, 32, countof(sizes), sizes);
59 void
60 ewmh_init(int phys_screen)
62 xcb_window_t father;
63 xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
64 xcb_atom_t atom[] =
66 _NET_SUPPORTED,
67 _NET_SUPPORTING_WM_CHECK,
68 _NET_STARTUP_ID,
69 _NET_CLIENT_LIST,
70 _NET_CLIENT_LIST_STACKING,
71 _NET_NUMBER_OF_DESKTOPS,
72 _NET_CURRENT_DESKTOP,
73 _NET_DESKTOP_NAMES,
74 _NET_ACTIVE_WINDOW,
75 _NET_WORKAREA,
76 _NET_DESKTOP_GEOMETRY,
77 _NET_CLOSE_WINDOW,
78 _NET_WM_NAME,
79 _NET_WM_STRUT_PARTIAL,
80 _NET_WM_ICON_NAME,
81 _NET_WM_VISIBLE_ICON_NAME,
82 _NET_WM_DESKTOP,
83 _NET_WM_WINDOW_TYPE,
84 _NET_WM_WINDOW_TYPE_DESKTOP,
85 _NET_WM_WINDOW_TYPE_DOCK,
86 _NET_WM_WINDOW_TYPE_TOOLBAR,
87 _NET_WM_WINDOW_TYPE_MENU,
88 _NET_WM_WINDOW_TYPE_UTILITY,
89 _NET_WM_WINDOW_TYPE_SPLASH,
90 _NET_WM_WINDOW_TYPE_DIALOG,
91 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
92 _NET_WM_WINDOW_TYPE_POPUP_MENU,
93 _NET_WM_WINDOW_TYPE_TOOLTIP,
94 _NET_WM_WINDOW_TYPE_NOTIFICATION,
95 _NET_WM_WINDOW_TYPE_COMBO,
96 _NET_WM_WINDOW_TYPE_DND,
97 _NET_WM_WINDOW_TYPE_NORMAL,
98 _NET_WM_ICON,
99 _NET_WM_PID,
100 _NET_WM_STATE,
101 _NET_WM_STATE_STICKY,
102 _NET_WM_STATE_SKIP_TASKBAR,
103 _NET_WM_STATE_FULLSCREEN,
104 _NET_WM_STATE_MAXIMIZED_HORZ,
105 _NET_WM_STATE_MAXIMIZED_VERT,
106 _NET_WM_STATE_ABOVE,
107 _NET_WM_STATE_BELOW,
108 _NET_WM_STATE_MODAL,
109 _NET_WM_STATE_HIDDEN,
110 _NET_WM_STATE_DEMANDS_ATTENTION
112 int i;
114 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
115 xscreen->root, _NET_SUPPORTED, ATOM, 32,
116 countof(atom), atom);
118 /* create our own window */
119 father = xcb_generate_id(globalconf.connection);
120 xcb_create_window(globalconf.connection, xscreen->root_depth,
121 father, xscreen->root, -1, -1, 1, 1, 0,
122 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
124 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
125 xscreen->root, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
126 1, &father);
128 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
129 father, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
130 1, &father);
132 /* set the window manager name */
133 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
134 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
136 /* set the window manager PID */
137 i = getpid();
138 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
139 father, _NET_WM_PID, CARDINAL, 32, 1, &i);
141 ewmh_update_desktop_geometry(phys_screen);
144 void
145 ewmh_update_net_client_list(int phys_screen)
147 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
149 int n = 0;
150 foreach(_c, globalconf.clients)
152 client_t *c = *_c;
153 if(c->phys_screen == phys_screen)
154 wins[n++] = c->win;
157 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
158 xutil_screen_get(globalconf.connection, phys_screen)->root,
159 _NET_CLIENT_LIST, WINDOW, 32, n, wins);
162 /** Set the client list in stacking order, bottom to top.
163 * \param phys_screen The physical screen id.
165 void
166 ewmh_update_net_client_list_stacking(int phys_screen)
168 int n = 0;
169 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
171 foreach(client, globalconf.stack)
172 if((*client)->phys_screen == phys_screen)
173 wins[n++] = (*client)->win;
175 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
176 xutil_screen_get(globalconf.connection, phys_screen)->root,
177 _NET_CLIENT_LIST_STACKING, WINDOW, 32, n, wins);
180 void
181 ewmh_update_net_numbers_of_desktop(int phys_screen)
183 uint32_t count = globalconf.screens.tab[phys_screen].tags.len;
185 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
186 xutil_screen_get(globalconf.connection, phys_screen)->root,
187 _NET_NUMBER_OF_DESKTOPS, CARDINAL, 32, 1, &count);
190 void
191 ewmh_update_net_current_desktop(int phys_screen)
193 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
194 uint32_t count = 0;
195 tag_t **curtags = tags_get_current( &globalconf.screens.tab[phys_screen]);
197 while(count < (uint32_t) tags->len && tags->tab[count] != curtags[0])
198 count++;
200 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
201 xutil_screen_get(globalconf.connection, phys_screen)->root,
202 _NET_CURRENT_DESKTOP, CARDINAL, 32, 1, &count);
204 p_delete(&curtags);
207 void
208 ewmh_update_net_desktop_names(int phys_screen)
210 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
211 buffer_t buf;
213 buffer_inita(&buf, BUFSIZ);
215 for(int i = 0; i < tags->len; i++)
217 buffer_adds(&buf, tags->tab[i]->name);
218 buffer_addc(&buf, '\0');
221 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
222 xutil_screen_get(globalconf.connection, phys_screen)->root,
223 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
224 buffer_wipe(&buf);
227 /** Update the work area space for each physical screen and each desktop.
228 * \param phys_screen The physical screen id.
230 void
231 ewmh_update_workarea(int phys_screen)
233 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
234 uint32_t *area = p_alloca(uint32_t, tags->len * 4);
235 area_t geom = screen_area_get(&globalconf.screens.tab[phys_screen],
236 &globalconf.screens.tab[phys_screen].wiboxes,
237 &globalconf.screens.tab[phys_screen].padding,
238 true);
241 for(int i = 0; i < tags->len; i++)
243 area[4 * i + 0] = geom.x;
244 area[4 * i + 1] = geom.y;
245 area[4 * i + 2] = geom.width;
246 area[4 * i + 3] = geom.height;
249 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
250 xutil_screen_get(globalconf.connection, phys_screen)->root,
251 _NET_WORKAREA, CARDINAL, 32, tags->len * 4, area);
254 void
255 ewmh_update_net_active_window(int phys_screen)
257 xcb_window_t win;
259 if(globalconf.screen_focus->client_focus
260 && globalconf.screen_focus->client_focus->phys_screen == phys_screen)
261 win = globalconf.screen_focus->client_focus->win;
262 else
263 win = XCB_NONE;
265 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
266 xutil_screen_get(globalconf.connection, phys_screen)->root,
267 _NET_ACTIVE_WINDOW, WINDOW, 32, 1, &win);
270 static void
271 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
273 if(state == _NET_WM_STATE_STICKY)
275 if(set == _NET_WM_STATE_REMOVE)
276 client_setsticky(c, false);
277 else if(set == _NET_WM_STATE_ADD)
278 client_setsticky(c, true);
279 else if(set == _NET_WM_STATE_TOGGLE)
280 client_setsticky(c, !c->issticky);
282 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
284 if(set == _NET_WM_STATE_REMOVE)
286 c->skiptb = false;
287 ewmh_client_update_hints(c);
289 else if(set == _NET_WM_STATE_ADD)
291 c->skiptb = true;
292 ewmh_client_update_hints(c);
294 else if(set == _NET_WM_STATE_TOGGLE)
296 c->skiptb = !c->skiptb;
297 ewmh_client_update_hints(c);
300 else if(state == _NET_WM_STATE_FULLSCREEN)
302 if(set == _NET_WM_STATE_REMOVE)
303 client_setfullscreen(c, false);
304 else if(set == _NET_WM_STATE_ADD)
305 client_setfullscreen(c, true);
306 else if(set == _NET_WM_STATE_TOGGLE)
307 client_setfullscreen(c, !c->isfullscreen);
309 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
311 if(set == _NET_WM_STATE_REMOVE)
312 client_setmaxhoriz(c, false);
313 else if(set == _NET_WM_STATE_ADD)
314 client_setmaxhoriz(c, true);
315 else if(set == _NET_WM_STATE_TOGGLE)
316 client_setmaxhoriz(c, !c->ismaxhoriz);
318 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
320 if(set == _NET_WM_STATE_REMOVE)
321 client_setmaxvert(c, false);
322 else if(set == _NET_WM_STATE_ADD)
323 client_setmaxvert(c, true);
324 else if(set == _NET_WM_STATE_TOGGLE)
325 client_setmaxvert(c, !c->ismaxvert);
327 else if(state == _NET_WM_STATE_ABOVE)
329 if(set == _NET_WM_STATE_REMOVE)
330 client_setabove(c, false);
331 else if(set == _NET_WM_STATE_ADD)
332 client_setabove(c, true);
333 else if(set == _NET_WM_STATE_TOGGLE)
334 client_setabove(c, !c->isabove);
336 else if(state == _NET_WM_STATE_BELOW)
338 if(set == _NET_WM_STATE_REMOVE)
339 client_setbelow(c, false);
340 else if(set == _NET_WM_STATE_ADD)
341 client_setbelow(c, true);
342 else if(set == _NET_WM_STATE_TOGGLE)
343 client_setbelow(c, !c->isbelow);
345 else if(state == _NET_WM_STATE_MODAL)
347 if(set == _NET_WM_STATE_REMOVE)
348 client_setmodal(c, false);
349 else if(set == _NET_WM_STATE_ADD)
350 client_setmodal(c, true);
351 else if(set == _NET_WM_STATE_TOGGLE)
352 client_setmodal(c, !c->ismodal);
354 else if(state == _NET_WM_STATE_HIDDEN)
356 if(set == _NET_WM_STATE_REMOVE)
357 client_setminimized(c, false);
358 else if(set == _NET_WM_STATE_ADD)
359 client_setminimized(c, true);
360 else if(set == _NET_WM_STATE_TOGGLE)
361 client_setminimized(c, !c->isminimized);
363 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
365 if(set == _NET_WM_STATE_REMOVE)
366 client_seturgent(c, false);
367 else if(set == _NET_WM_STATE_ADD)
368 client_seturgent(c, true);
369 else if(set == _NET_WM_STATE_TOGGLE)
370 client_seturgent(c, !c->isurgent);
375 ewmh_process_client_message(xcb_client_message_event_t *ev)
377 client_t *c;
378 int screen;
380 if(ev->type == _NET_CURRENT_DESKTOP)
381 for(screen = 0;
382 screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
383 screen++)
385 if(ev->window == xutil_screen_get(globalconf.connection, screen)->root)
386 tag_view_only_byindex(&globalconf.screens.tab[screen], ev->data.data32[0]);
388 else if(ev->type == _NET_CLOSE_WINDOW)
390 if((c = client_getbywin(ev->window)))
391 client_kill(c);
393 else if(ev->type == _NET_WM_DESKTOP)
395 if((c = client_getbywin(ev->window)))
397 tag_array_t *tags = &c->screen->tags;
399 if(ev->data.data32[0] == 0xffffffff)
400 c->issticky = true;
401 else
402 for(int i = 0; i < tags->len; i++)
403 if((int)ev->data.data32[0] == i)
405 tag_push(globalconf.L, tags->tab[i]);
406 tag_client(c);
408 else
409 untag_client(c, tags->tab[i]);
412 else if(ev->type == _NET_WM_STATE)
414 if((c = client_getbywin(ev->window)))
416 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
417 if(ev->data.data32[2])
418 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
419 ev->data.data32[0]);
422 else if(ev->type == _NET_ACTIVE_WINDOW)
424 if((c = client_getbywin(ev->window)))
425 client_focus(c);
428 return 0;
431 /** Update client EWMH hints.
432 * \param c The client.
434 void
435 ewmh_client_update_hints(client_t *c)
437 xcb_atom_t state[10]; /* number of defined state atoms */
438 int i = 0;
440 if(c->ismodal)
441 state[i++] = _NET_WM_STATE_MODAL;
442 if(c->isfullscreen)
443 state[i++] = _NET_WM_STATE_FULLSCREEN;
444 if(c->ismaxvert)
445 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
446 if(c->ismaxhoriz)
447 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
448 if(c->issticky)
449 state[i++] = _NET_WM_STATE_STICKY;
450 if(c->skiptb)
451 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
452 if(c->isabove)
453 state[i++] = _NET_WM_STATE_ABOVE;
454 if(c->isbelow)
455 state[i++] = _NET_WM_STATE_BELOW;
456 if(c->isminimized)
457 state[i++] = _NET_WM_STATE_HIDDEN;
458 if(c->isurgent)
459 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
461 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
462 c->win, _NET_WM_STATE, ATOM, 32, i, state);
465 /** Update the client active desktop.
466 * This is "wrong" since it can be on several tags, but EWMH has a strict view
467 * of desktop system so just take the first tag.
468 * \param c The client.
470 void
471 ewmh_client_update_desktop(client_t *c)
473 int i;
474 tag_array_t *tags = &c->screen->tags;
476 for(i = 0; i < tags->len; i++)
477 if(is_client_tagged(c, tags->tab[i]))
479 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
480 c->win, _NET_WM_DESKTOP, CARDINAL, 32, 1, &i);
481 return;
485 /** Update the client struts.
486 * \param c The client.
488 void
489 ewmh_update_client_strut(client_t *c)
491 uint32_t state[] =
493 c->strut.left,
494 c->strut.right,
495 c->strut.top,
496 c->strut.bottom,
497 c->strut.left_start_y,
498 c->strut.left_end_y,
499 c->strut.right_start_y,
500 c->strut.right_end_y,
501 c->strut.top_start_x,
502 c->strut.top_end_x,
503 c->strut.bottom_start_x,
504 c->strut.bottom_end_x
507 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
508 c->win, _NET_WM_STRUT_PARTIAL, CARDINAL, 32, countof(state), state);
511 void
512 ewmh_client_check_hints(client_t *c)
514 xcb_atom_t *state;
515 void *data = NULL;
516 int desktop;
517 xcb_get_property_cookie_t c0, c1, c2;
518 xcb_get_property_reply_t *reply;
520 /* Send the GetProperty requests which will be processed later */
521 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
522 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
524 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
525 _NET_WM_STATE, ATOM, 0, UINT32_MAX);
527 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
528 _NET_WM_WINDOW_TYPE, ATOM, 0, UINT32_MAX);
530 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
531 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
533 tag_array_t *tags = &c->screen->tags;
535 desktop = *(uint32_t *) data;
536 if(desktop == -1)
537 c->issticky = true;
538 else
539 for(int i = 0; i < tags->len; i++)
540 if(desktop == i)
542 tag_push(globalconf.L, tags->tab[i]);
543 tag_client(c);
545 else
546 untag_client(c, tags->tab[i]);
549 p_delete(&reply);
551 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
552 if(reply && (data = xcb_get_property_value(reply)))
554 state = (xcb_atom_t *) data;
555 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
556 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
559 p_delete(&reply);
561 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
562 if(reply && (data = xcb_get_property_value(reply)))
564 state = (xcb_atom_t *) data;
565 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
566 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
567 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
568 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
569 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
570 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
571 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
572 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
573 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
574 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
575 c->type = MAX(c->type, WINDOW_TYPE_MENU);
576 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
577 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
578 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
579 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
581 if(c->type != WINDOW_TYPE_NORMAL
582 && c->type != WINDOW_TYPE_DESKTOP
583 && !c->transient_for)
584 client_setabove(c, true);
587 p_delete(&reply);
590 /** Process the WM strut of a client.
591 * \param c The client.
593 void
594 ewmh_process_client_strut(client_t *c, xcb_get_property_reply_t *strut_r)
596 void *data;
597 xcb_get_property_reply_t *mstrut_r = NULL;
599 if(!strut_r)
601 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
602 _NET_WM_STRUT_PARTIAL, CARDINAL, 0, 12);
603 strut_r = mstrut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
606 if(strut_r
607 && strut_r->value_len
608 && (data = xcb_get_property_value(strut_r)))
610 uint32_t *strut = data;
612 if(c->strut.left != strut[0]
613 || c->strut.right != strut[1]
614 || c->strut.top != strut[2]
615 || c->strut.bottom != strut[3]
616 || c->strut.left_start_y != strut[4]
617 || c->strut.left_end_y != strut[5]
618 || c->strut.right_start_y != strut[6]
619 || c->strut.right_end_y != strut[7]
620 || c->strut.top_start_x != strut[8]
621 || c->strut.top_end_x != strut[9]
622 || c->strut.bottom_start_x != strut[10]
623 || c->strut.bottom_end_x != strut[11])
625 c->strut.left = strut[0];
626 c->strut.right = strut[1];
627 c->strut.top = strut[2];
628 c->strut.bottom = strut[3];
629 c->strut.left_start_y = strut[4];
630 c->strut.left_end_y = strut[5];
631 c->strut.right_start_y = strut[6];
632 c->strut.right_end_y = strut[7];
633 c->strut.top_start_x = strut[8];
634 c->strut.top_end_x = strut[9];
635 c->strut.bottom_start_x = strut[10];
636 c->strut.bottom_end_x = strut[11];
638 client_need_arrange(c);
639 /* All the wiboxes (may) need to be repositioned. */
640 wibox_update_positions();
642 hooks_property(c, "struts");
646 p_delete(&mstrut_r);
649 /** Send request to get NET_WM_ICON (EWMH)
650 * \param w The window.
651 * \return The cookie associated with the request.
653 xcb_get_property_cookie_t
654 ewmh_window_icon_get_unchecked(xcb_window_t w)
656 return xcb_get_property_unchecked(globalconf.connection, false, w,
657 _NET_WM_ICON, CARDINAL, 0, UINT32_MAX);
661 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
663 uint32_t *data;
664 uint64_t len;
666 if(!r || r->type != CARDINAL || r->format != 32 || r->length < 2)
667 return 0;
669 data = (uint32_t *) xcb_get_property_value(r);
670 if (!data)
671 return 0;
673 /* Check that the property is as long as it should be, handling integer
674 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
675 * fits into an uint64_t and thus this multiplication cannot overflow.
677 len = data[0] * (uint64_t) data[1];
678 if (!data[0] || !data[1] || len > r->length - 2)
679 return 0;
681 return image_new_from_argb32(data[0], data[1], data + 2);
684 /** Get NET_WM_ICON.
685 * \param cookie The cookie.
686 * \return The number of elements on stack.
689 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
691 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
692 int ret = ewmh_window_icon_from_reply(r);
693 p_delete(&r);
694 return ret;
697 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80