awful.util: add table.keys
[awesome.git] / ewmh.c
blob2fb48a44265c2e63b502d9f26d4903ddac30c738
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], false);
49 uint32_t sizes[] = { geom.width, geom.height };
51 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
52 xutil_screen_get(globalconf.connection, phys_screen)->root,
53 _NET_DESKTOP_GEOMETRY, CARDINAL, 32, countof(sizes), sizes);
56 void
57 ewmh_init(int phys_screen)
59 xcb_window_t father;
60 xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
61 xcb_atom_t atom[] =
63 _NET_SUPPORTED,
64 _NET_SUPPORTING_WM_CHECK,
65 _NET_STARTUP_ID,
66 _NET_CLIENT_LIST,
67 _NET_CLIENT_LIST_STACKING,
68 _NET_NUMBER_OF_DESKTOPS,
69 _NET_CURRENT_DESKTOP,
70 _NET_DESKTOP_NAMES,
71 _NET_ACTIVE_WINDOW,
72 _NET_WORKAREA,
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, 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, WINDOW, 32,
123 1, &father);
125 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
126 father, _NET_SUPPORTING_WM_CHECK, 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, 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->win;
154 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
155 xutil_screen_get(globalconf.connection, phys_screen)->root,
156 _NET_CLIENT_LIST, 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)->win;
172 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
173 xutil_screen_get(globalconf.connection, phys_screen)->root,
174 _NET_CLIENT_LIST_STACKING, 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, CARDINAL, 32, 1, &count);
187 void
188 ewmh_update_net_current_desktop(int phys_screen)
190 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
191 uint32_t count = 0;
192 tag_t **curtags = tags_get_current( &globalconf.screens.tab[phys_screen]);
194 while(count < (uint32_t) tags->len && tags->tab[count] != curtags[0])
195 count++;
197 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
198 xutil_screen_get(globalconf.connection, phys_screen)->root,
199 _NET_CURRENT_DESKTOP, CARDINAL, 32, 1, &count);
201 p_delete(&curtags);
204 void
205 ewmh_update_net_desktop_names(int phys_screen)
207 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
208 buffer_t buf;
210 buffer_inita(&buf, BUFSIZ);
212 for(int i = 0; i < tags->len; i++)
214 buffer_adds(&buf, tags->tab[i]->name);
215 buffer_addc(&buf, '\0');
218 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
219 xutil_screen_get(globalconf.connection, phys_screen)->root,
220 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
221 buffer_wipe(&buf);
224 /** Update the work area space for each physical screen and each desktop.
225 * \param phys_screen The physical screen id.
227 void
228 ewmh_update_workarea(int phys_screen)
230 tag_array_t *tags = &globalconf.screens.tab[phys_screen].tags;
231 uint32_t *area = p_alloca(uint32_t, tags->len * 4);
232 area_t geom = screen_area_get(&globalconf.screens.tab[phys_screen], true);
234 for(int i = 0; i < tags->len; i++)
236 area[4 * i + 0] = geom.x;
237 area[4 * i + 1] = geom.y;
238 area[4 * i + 2] = geom.width;
239 area[4 * i + 3] = geom.height;
242 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
243 xutil_screen_get(globalconf.connection, phys_screen)->root,
244 _NET_WORKAREA, CARDINAL, 32, tags->len * 4, area);
247 void
248 ewmh_update_net_active_window(int phys_screen)
250 xcb_window_t win;
252 if(globalconf.screen_focus->client_focus
253 && globalconf.screen_focus->client_focus->phys_screen == phys_screen)
254 win = globalconf.screen_focus->client_focus->win;
255 else
256 win = XCB_NONE;
258 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
259 xutil_screen_get(globalconf.connection, phys_screen)->root,
260 _NET_ACTIVE_WINDOW, WINDOW, 32, 1, &win);
263 static void
264 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
266 if(state == _NET_WM_STATE_STICKY)
268 if(set == _NET_WM_STATE_REMOVE)
269 client_setsticky(c, false);
270 else if(set == _NET_WM_STATE_ADD)
271 client_setsticky(c, true);
272 else if(set == _NET_WM_STATE_TOGGLE)
273 client_setsticky(c, !c->issticky);
275 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
277 if(set == _NET_WM_STATE_REMOVE)
279 c->skiptb = false;
280 ewmh_client_update_hints(c);
282 else if(set == _NET_WM_STATE_ADD)
284 c->skiptb = true;
285 ewmh_client_update_hints(c);
287 else if(set == _NET_WM_STATE_TOGGLE)
289 c->skiptb = !c->skiptb;
290 ewmh_client_update_hints(c);
293 else if(state == _NET_WM_STATE_FULLSCREEN)
295 if(set == _NET_WM_STATE_REMOVE)
296 client_setfullscreen(c, false);
297 else if(set == _NET_WM_STATE_ADD)
298 client_setfullscreen(c, true);
299 else if(set == _NET_WM_STATE_TOGGLE)
300 client_setfullscreen(c, !c->isfullscreen);
302 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
304 if(set == _NET_WM_STATE_REMOVE)
305 client_setmaxhoriz(c, false);
306 else if(set == _NET_WM_STATE_ADD)
307 client_setmaxhoriz(c, true);
308 else if(set == _NET_WM_STATE_TOGGLE)
309 client_setmaxhoriz(c, !c->ismaxhoriz);
311 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
313 if(set == _NET_WM_STATE_REMOVE)
314 client_setmaxvert(c, false);
315 else if(set == _NET_WM_STATE_ADD)
316 client_setmaxvert(c, true);
317 else if(set == _NET_WM_STATE_TOGGLE)
318 client_setmaxvert(c, !c->ismaxvert);
320 else if(state == _NET_WM_STATE_ABOVE)
322 if(set == _NET_WM_STATE_REMOVE)
323 client_setabove(c, false);
324 else if(set == _NET_WM_STATE_ADD)
325 client_setabove(c, true);
326 else if(set == _NET_WM_STATE_TOGGLE)
327 client_setabove(c, !c->isabove);
329 else if(state == _NET_WM_STATE_BELOW)
331 if(set == _NET_WM_STATE_REMOVE)
332 client_setbelow(c, false);
333 else if(set == _NET_WM_STATE_ADD)
334 client_setbelow(c, true);
335 else if(set == _NET_WM_STATE_TOGGLE)
336 client_setbelow(c, !c->isbelow);
338 else if(state == _NET_WM_STATE_MODAL)
340 if(set == _NET_WM_STATE_REMOVE)
341 client_setmodal(c, false);
342 else if(set == _NET_WM_STATE_ADD)
343 client_setmodal(c, true);
344 else if(set == _NET_WM_STATE_TOGGLE)
345 client_setmodal(c, !c->ismodal);
347 else if(state == _NET_WM_STATE_HIDDEN)
349 if(set == _NET_WM_STATE_REMOVE)
350 client_setminimized(c, false);
351 else if(set == _NET_WM_STATE_ADD)
352 client_setminimized(c, true);
353 else if(set == _NET_WM_STATE_TOGGLE)
354 client_setminimized(c, !c->isminimized);
356 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
358 if(set == _NET_WM_STATE_REMOVE)
359 client_seturgent(c, false);
360 else if(set == _NET_WM_STATE_ADD)
361 client_seturgent(c, true);
362 else if(set == _NET_WM_STATE_TOGGLE)
363 client_seturgent(c, !c->isurgent);
368 ewmh_process_client_message(xcb_client_message_event_t *ev)
370 client_t *c;
371 int screen;
373 if(ev->type == _NET_CURRENT_DESKTOP)
374 for(screen = 0;
375 screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
376 screen++)
378 if(ev->window == xutil_screen_get(globalconf.connection, screen)->root)
379 tag_view_only_byindex(&globalconf.screens.tab[screen], ev->data.data32[0]);
381 else if(ev->type == _NET_CLOSE_WINDOW)
383 if((c = client_getbywin(ev->window)))
384 client_kill(c);
386 else if(ev->type == _NET_WM_DESKTOP)
388 if((c = client_getbywin(ev->window)))
390 tag_array_t *tags = &c->screen->tags;
392 if(ev->data.data32[0] == 0xffffffff)
393 c->issticky = true;
394 else
395 for(int i = 0; i < tags->len; i++)
396 if((int)ev->data.data32[0] == i)
398 tag_push(globalconf.L, tags->tab[i]);
399 tag_client(c);
401 else
402 untag_client(c, tags->tab[i]);
405 else if(ev->type == _NET_WM_STATE)
407 if((c = client_getbywin(ev->window)))
409 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
410 if(ev->data.data32[2])
411 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
412 ev->data.data32[0]);
415 else if(ev->type == _NET_ACTIVE_WINDOW)
417 if((c = client_getbywin(ev->window)))
418 client_focus(c);
421 return 0;
424 /** Update client EWMH hints.
425 * \param c The client.
427 void
428 ewmh_client_update_hints(client_t *c)
430 xcb_atom_t state[10]; /* number of defined state atoms */
431 int i = 0;
433 if(c->ismodal)
434 state[i++] = _NET_WM_STATE_MODAL;
435 if(c->isfullscreen)
436 state[i++] = _NET_WM_STATE_FULLSCREEN;
437 if(c->ismaxvert)
438 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
439 if(c->ismaxhoriz)
440 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
441 if(c->issticky)
442 state[i++] = _NET_WM_STATE_STICKY;
443 if(c->skiptb)
444 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
445 if(c->isabove)
446 state[i++] = _NET_WM_STATE_ABOVE;
447 if(c->isbelow)
448 state[i++] = _NET_WM_STATE_BELOW;
449 if(c->isminimized)
450 state[i++] = _NET_WM_STATE_HIDDEN;
451 if(c->isurgent)
452 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
454 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
455 c->win, _NET_WM_STATE, ATOM, 32, i, state);
458 /** Update the client active desktop.
459 * This is "wrong" since it can be on several tags, but EWMH has a strict view
460 * of desktop system so just take the first tag.
461 * \param c The client.
463 void
464 ewmh_client_update_desktop(client_t *c)
466 int i;
467 tag_array_t *tags = &c->screen->tags;
469 for(i = 0; i < tags->len; i++)
470 if(is_client_tagged(c, tags->tab[i]))
472 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
473 c->win, _NET_WM_DESKTOP, CARDINAL, 32, 1, &i);
474 return;
478 /** Update the client struts.
479 * \param c The client.
481 void
482 ewmh_update_client_strut(client_t *c)
484 uint32_t state[] =
486 c->strut.left,
487 c->strut.right,
488 c->strut.top,
489 c->strut.bottom,
490 c->strut.left_start_y,
491 c->strut.left_end_y,
492 c->strut.right_start_y,
493 c->strut.right_end_y,
494 c->strut.top_start_x,
495 c->strut.top_end_x,
496 c->strut.bottom_start_x,
497 c->strut.bottom_end_x
500 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
501 c->win, _NET_WM_STRUT_PARTIAL, CARDINAL, 32, countof(state), state);
504 void
505 ewmh_client_check_hints(client_t *c)
507 xcb_atom_t *state;
508 void *data = NULL;
509 int desktop;
510 xcb_get_property_cookie_t c0, c1, c2;
511 xcb_get_property_reply_t *reply;
513 /* Send the GetProperty requests which will be processed later */
514 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
515 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
517 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
518 _NET_WM_STATE, ATOM, 0, UINT32_MAX);
520 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
521 _NET_WM_WINDOW_TYPE, ATOM, 0, UINT32_MAX);
523 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
524 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
526 tag_array_t *tags = &c->screen->tags;
528 desktop = *(uint32_t *) data;
529 if(desktop == -1)
530 c->issticky = true;
531 else
532 for(int i = 0; i < tags->len; i++)
533 if(desktop == i)
535 tag_push(globalconf.L, tags->tab[i]);
536 tag_client(c);
538 else
539 untag_client(c, tags->tab[i]);
542 p_delete(&reply);
544 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
545 if(reply && (data = xcb_get_property_value(reply)))
547 state = (xcb_atom_t *) data;
548 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
549 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
552 p_delete(&reply);
554 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
555 if(reply && (data = xcb_get_property_value(reply)))
557 state = (xcb_atom_t *) data;
558 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
559 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
560 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
561 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
562 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
563 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
564 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
565 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
566 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
567 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
568 c->type = MAX(c->type, WINDOW_TYPE_MENU);
569 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
570 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
571 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
572 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
575 p_delete(&reply);
578 /** Process the WM strut of a client.
579 * \param c The client.
581 void
582 ewmh_process_client_strut(client_t *c, xcb_get_property_reply_t *strut_r)
584 void *data;
585 xcb_get_property_reply_t *mstrut_r = NULL;
587 if(!strut_r)
589 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
590 _NET_WM_STRUT_PARTIAL, CARDINAL, 0, 12);
591 strut_r = mstrut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
594 if(strut_r
595 && strut_r->value_len
596 && (data = xcb_get_property_value(strut_r)))
598 uint32_t *strut = data;
600 if(c->strut.left != strut[0]
601 || c->strut.right != strut[1]
602 || c->strut.top != strut[2]
603 || c->strut.bottom != strut[3]
604 || c->strut.left_start_y != strut[4]
605 || c->strut.left_end_y != strut[5]
606 || c->strut.right_start_y != strut[6]
607 || c->strut.right_end_y != strut[7]
608 || c->strut.top_start_x != strut[8]
609 || c->strut.top_end_x != strut[9]
610 || c->strut.bottom_start_x != strut[10]
611 || c->strut.bottom_end_x != strut[11])
613 c->strut.left = strut[0];
614 c->strut.right = strut[1];
615 c->strut.top = strut[2];
616 c->strut.bottom = strut[3];
617 c->strut.left_start_y = strut[4];
618 c->strut.left_end_y = strut[5];
619 c->strut.right_start_y = strut[6];
620 c->strut.right_end_y = strut[7];
621 c->strut.top_start_x = strut[8];
622 c->strut.top_end_x = strut[9];
623 c->strut.bottom_start_x = strut[10];
624 c->strut.bottom_end_x = strut[11];
626 hook_property(client, c, "struts");
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