awful.hooks: replace already existing timer hooks instead of creating new ones
[awesome.git] / ewmh.c
blobb4a8cc0ccf1da75940ccdd2859abd2465aa87065
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 "cnode.h"
34 #include "wibox.h"
35 #include "common/atoms.h"
36 #include "common/buffer.h"
38 extern awesome_t globalconf;
40 #define _NET_WM_STATE_REMOVE 0
41 #define _NET_WM_STATE_ADD 1
42 #define _NET_WM_STATE_TOGGLE 2
44 /** Update the desktop geometry.
45 * \param phys_screen The physical screen id.
47 static void
48 ewmh_update_desktop_geometry(int phys_screen)
50 area_t geom = screen_area_get(phys_screen,
51 NULL,
52 NULL,
53 false);
54 uint32_t sizes[] = { geom.width, geom.height };
56 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
57 xutil_screen_get(globalconf.connection, phys_screen)->root,
58 _NET_DESKTOP_GEOMETRY, CARDINAL, 32, countof(sizes), sizes);
61 void
62 ewmh_init(int phys_screen)
64 xcb_window_t father;
65 xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
66 xcb_atom_t atom[] =
68 _NET_SUPPORTED,
69 _NET_SUPPORTING_WM_CHECK,
70 _NET_CLIENT_LIST,
71 _NET_CLIENT_LIST_STACKING,
72 _NET_NUMBER_OF_DESKTOPS,
73 _NET_CURRENT_DESKTOP,
74 _NET_DESKTOP_NAMES,
75 _NET_ACTIVE_WINDOW,
76 _NET_WORKAREA,
77 _NET_DESKTOP_GEOMETRY,
78 _NET_CLOSE_WINDOW,
79 _NET_WM_NAME,
80 _NET_WM_STRUT_PARTIAL,
81 _NET_WM_ICON_NAME,
82 _NET_WM_VISIBLE_ICON_NAME,
83 _NET_WM_DESKTOP,
84 _NET_WM_WINDOW_TYPE,
85 _NET_WM_WINDOW_TYPE_DESKTOP,
86 _NET_WM_WINDOW_TYPE_DOCK,
87 _NET_WM_WINDOW_TYPE_TOOLBAR,
88 _NET_WM_WINDOW_TYPE_MENU,
89 _NET_WM_WINDOW_TYPE_UTILITY,
90 _NET_WM_WINDOW_TYPE_SPLASH,
91 _NET_WM_WINDOW_TYPE_DIALOG,
92 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
93 _NET_WM_WINDOW_TYPE_POPUP_MENU,
94 _NET_WM_WINDOW_TYPE_TOOLTIP,
95 _NET_WM_WINDOW_TYPE_NOTIFICATION,
96 _NET_WM_WINDOW_TYPE_COMBO,
97 _NET_WM_WINDOW_TYPE_DND,
98 _NET_WM_WINDOW_TYPE_NORMAL,
99 _NET_WM_ICON,
100 _NET_WM_PID,
101 _NET_WM_STATE,
102 _NET_WM_STATE_STICKY,
103 _NET_WM_STATE_SKIP_TASKBAR,
104 _NET_WM_STATE_FULLSCREEN,
105 _NET_WM_STATE_MAXIMIZED_HORZ,
106 _NET_WM_STATE_MAXIMIZED_VERT,
107 _NET_WM_STATE_ABOVE,
108 _NET_WM_STATE_BELOW,
109 _NET_WM_STATE_MODAL,
110 _NET_WM_STATE_HIDDEN,
111 _NET_WM_STATE_DEMANDS_ATTENTION
113 int i;
115 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
116 xscreen->root, _NET_SUPPORTED, ATOM, 32,
117 countof(atom), atom);
119 /* create our own window */
120 father = xcb_generate_id(globalconf.connection);
121 xcb_create_window(globalconf.connection, xscreen->root_depth,
122 father, xscreen->root, -1, -1, 1, 1, 0,
123 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
125 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
126 xscreen->root, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
127 1, &father);
129 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
130 father, _NET_SUPPORTING_WM_CHECK, WINDOW, 32,
131 1, &father);
133 /* set the window manager name */
134 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
135 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
137 /* set the window manager PID */
138 i = getpid();
139 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
140 father, _NET_WM_PID, CARDINAL, 32, 1, &i);
142 ewmh_update_desktop_geometry(phys_screen);
145 void
146 ewmh_update_net_client_list(int phys_screen)
148 xcb_window_t *wins;
149 client_t *c;
150 int n = 0;
152 for(c = globalconf.clients; c; c = c->next)
153 n++;
155 wins = p_alloca(xcb_window_t, n);
157 for(n = 0, c = globalconf.clients; c; c = c->next, n++)
158 if(c->phys_screen == phys_screen)
159 wins[n] = c->win;
161 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
162 xutil_screen_get(globalconf.connection, phys_screen)->root,
163 _NET_CLIENT_LIST, WINDOW, 32, n, wins);
166 /** Set the client list in stacking order, bottom to top.
167 * \param phys_screen The physical screen id.
169 void
170 ewmh_update_net_client_list_stacking(int phys_screen)
172 xcb_window_t *wins;
173 client_node_t *c;
174 int n = 0;
176 for(c = globalconf.stack; c; c = c->next)
177 n++;
179 wins = p_alloca(xcb_window_t, n);
181 for(n = 0, c = *client_node_list_last(&globalconf.stack); c; c = c->prev, n++)
182 if(c->client->phys_screen == phys_screen)
183 wins[n] = c->client->win;
185 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
186 xutil_screen_get(globalconf.connection, phys_screen)->root,
187 _NET_CLIENT_LIST_STACKING, WINDOW, 32, n, wins);
190 void
191 ewmh_update_net_numbers_of_desktop(int phys_screen)
193 uint32_t count = globalconf.screens[phys_screen].tags.len;
195 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
196 xutil_screen_get(globalconf.connection, phys_screen)->root,
197 _NET_NUMBER_OF_DESKTOPS, CARDINAL, 32, 1, &count);
200 void
201 ewmh_update_net_current_desktop(int phys_screen)
203 tag_array_t *tags = &globalconf.screens[phys_screen].tags;
204 uint32_t count = 0;
205 tag_t **curtags = tags_get_current(phys_screen);
207 while(count < (uint32_t) tags->len && tags->tab[count] != curtags[0])
208 count++;
210 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
211 xutil_screen_get(globalconf.connection, phys_screen)->root,
212 _NET_CURRENT_DESKTOP, CARDINAL, 32, 1, &count);
214 p_delete(&curtags);
217 void
218 ewmh_update_net_desktop_names(int phys_screen)
220 tag_array_t *tags = &globalconf.screens[phys_screen].tags;
221 buffer_t buf;
223 buffer_inita(&buf, BUFSIZ);
225 for(int i = 0; i < tags->len; i++)
227 buffer_adds(&buf, tags->tab[i]->name);
228 buffer_addc(&buf, '\0');
231 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
232 xutil_screen_get(globalconf.connection, phys_screen)->root,
233 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
234 buffer_wipe(&buf);
237 /** Update the work area space for each physical screen and each desktop.
238 * \param phys_screen The physical screen id.
240 void
241 ewmh_update_workarea(int phys_screen)
243 tag_array_t *tags = &globalconf.screens[phys_screen].tags;
244 uint32_t *area = p_alloca(uint32_t, tags->len * 4);
245 area_t geom = screen_area_get(phys_screen,
246 &globalconf.screens[phys_screen].wiboxes,
247 &globalconf.screens[phys_screen].padding,
248 true);
251 for(int i = 0; i < tags->len; i++)
253 area[4 * i + 0] = geom.x;
254 area[4 * i + 1] = geom.y;
255 area[4 * i + 2] = geom.width;
256 area[4 * i + 3] = geom.height;
259 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
260 xutil_screen_get(globalconf.connection, phys_screen)->root,
261 _NET_WORKAREA, CARDINAL, 32, tags->len * 4, area);
264 void
265 ewmh_update_net_active_window(int phys_screen)
267 xcb_window_t win;
269 if(globalconf.screen_focus->client_focus
270 && globalconf.screen_focus->client_focus->phys_screen == phys_screen)
271 win = globalconf.screen_focus->client_focus->win;
272 else
273 win = XCB_NONE;
275 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
276 xutil_screen_get(globalconf.connection, phys_screen)->root,
277 _NET_ACTIVE_WINDOW, WINDOW, 32, 1, &win);
280 static void
281 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
283 if(state == _NET_WM_STATE_STICKY)
285 if(set == _NET_WM_STATE_REMOVE)
286 client_setsticky(c, false);
287 else if(set == _NET_WM_STATE_ADD)
288 client_setsticky(c, true);
289 else if(set == _NET_WM_STATE_TOGGLE)
290 client_setsticky(c, !c->issticky);
292 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
294 if(set == _NET_WM_STATE_REMOVE)
296 c->skiptb = false;
297 ewmh_client_update_hints(c);
299 else if(set == _NET_WM_STATE_ADD)
301 c->skiptb = true;
302 ewmh_client_update_hints(c);
304 else if(set == _NET_WM_STATE_TOGGLE)
306 c->skiptb = !c->skiptb;
307 ewmh_client_update_hints(c);
310 else if(state == _NET_WM_STATE_FULLSCREEN)
312 if(set == _NET_WM_STATE_REMOVE)
313 client_setfullscreen(c, false);
314 else if(set == _NET_WM_STATE_ADD)
315 client_setfullscreen(c, true);
316 else if(set == _NET_WM_STATE_TOGGLE)
317 client_setfullscreen(c, !c->isfullscreen);
319 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
321 if(set == _NET_WM_STATE_REMOVE)
322 client_setmaxhoriz(c, false);
323 else if(set == _NET_WM_STATE_ADD)
324 client_setmaxhoriz(c, true);
325 else if(set == _NET_WM_STATE_TOGGLE)
326 client_setmaxhoriz(c, !c->ismaxhoriz);
328 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
330 if(set == _NET_WM_STATE_REMOVE)
331 client_setmaxvert(c, false);
332 else if(set == _NET_WM_STATE_ADD)
333 client_setmaxvert(c, true);
334 else if(set == _NET_WM_STATE_TOGGLE)
335 client_setmaxvert(c, !c->ismaxvert);
337 else if(state == _NET_WM_STATE_ABOVE)
339 if(set == _NET_WM_STATE_REMOVE)
340 client_setabove(c, false);
341 else if(set == _NET_WM_STATE_ADD)
342 client_setabove(c, true);
343 else if(set == _NET_WM_STATE_TOGGLE)
344 client_setabove(c, !c->isabove);
346 else if(state == _NET_WM_STATE_BELOW)
348 if(set == _NET_WM_STATE_REMOVE)
349 client_setbelow(c, false);
350 else if(set == _NET_WM_STATE_ADD)
351 client_setbelow(c, true);
352 else if(set == _NET_WM_STATE_TOGGLE)
353 client_setbelow(c, !c->isbelow);
355 else if(state == _NET_WM_STATE_MODAL)
357 if(set == _NET_WM_STATE_REMOVE)
358 client_setmodal(c, false);
359 else if(set == _NET_WM_STATE_ADD)
360 client_setmodal(c, true);
361 else if(set == _NET_WM_STATE_TOGGLE)
362 client_setmodal(c, !c->ismodal);
364 else if(state == _NET_WM_STATE_HIDDEN)
366 if(set == _NET_WM_STATE_REMOVE)
367 client_setminimized(c, false);
368 else if(set == _NET_WM_STATE_ADD)
369 client_setminimized(c, true);
370 else if(set == _NET_WM_STATE_TOGGLE)
371 client_setminimized(c, !c->isminimized);
373 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
375 if(set == _NET_WM_STATE_REMOVE)
376 client_seturgent(c, false);
377 else if(set == _NET_WM_STATE_ADD)
378 client_seturgent(c, true);
379 else if(set == _NET_WM_STATE_TOGGLE)
380 client_seturgent(c, !c->isurgent);
385 ewmh_process_client_message(xcb_client_message_event_t *ev)
387 client_t *c;
388 int screen;
390 if(ev->type == _NET_CURRENT_DESKTOP)
391 for(screen = 0;
392 screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
393 screen++)
395 if(ev->window == xutil_screen_get(globalconf.connection, screen)->root)
396 tag_view_only_byindex(screen, ev->data.data32[0]);
398 else if(ev->type == _NET_CLOSE_WINDOW)
400 if((c = client_getbywin(ev->window)))
401 client_kill(c);
403 else if(ev->type == _NET_WM_DESKTOP)
405 if((c = client_getbywin(ev->window)))
407 tag_array_t *tags = &globalconf.screens[c->screen].tags;
409 if(ev->data.data32[0] == 0xffffffff)
410 c->issticky = true;
411 else
412 for(int i = 0; i < tags->len; i++)
413 if((int)ev->data.data32[0] == i)
414 tag_client(c, tags->tab[i]);
415 else
416 untag_client(c, tags->tab[i]);
419 else if(ev->type == _NET_WM_STATE)
421 if((c = client_getbywin(ev->window)))
423 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
424 if(ev->data.data32[2])
425 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
426 ev->data.data32[0]);
429 else if(ev->type == _NET_ACTIVE_WINDOW)
431 if((c = client_getbywin(ev->window)))
432 client_focus(c);
435 return 0;
438 /** Update client EWMH hints.
439 * \param c The client.
441 void
442 ewmh_client_update_hints(client_t *c)
444 xcb_atom_t state[10]; /* number of defined state atoms */
445 int i = 0;
447 if(c->ismodal)
448 state[i++] = _NET_WM_STATE_MODAL;
449 if(c->isfullscreen)
450 state[i++] = _NET_WM_STATE_FULLSCREEN;
451 if(c->ismaxvert)
452 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
453 if(c->ismaxhoriz)
454 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
455 if(c->issticky)
456 state[i++] = _NET_WM_STATE_STICKY;
457 if(c->skiptb)
458 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
459 if(c->isabove)
460 state[i++] = _NET_WM_STATE_ABOVE;
461 if(c->isbelow)
462 state[i++] = _NET_WM_STATE_BELOW;
463 if(c->isminimized)
464 state[i++] = _NET_WM_STATE_HIDDEN;
465 if(c->isurgent)
466 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
468 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
469 c->win, _NET_WM_STATE, ATOM, 32, i, state);
472 /** Update the client active desktop.
473 * This is "wrong" since it can be on several tags, but EWMH has a strict view
474 * of desktop system so just take the first tag.
475 * \param c The client.
477 void
478 ewmh_client_update_desktop(client_t *c)
480 int i;
481 tag_array_t *tags = &globalconf.screens[c->screen].tags;
483 for(i = 0; i < tags->len; i++)
484 if(is_client_tagged(c, tags->tab[i]))
486 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
487 c->win, _NET_WM_DESKTOP, CARDINAL, 32, 1, &i);
488 return;
492 /** Update the client struts.
493 * \param c The client.
495 void
496 ewmh_update_client_strut(client_t *c)
498 uint32_t state[] =
500 c->strut.left,
501 c->strut.right,
502 c->strut.top,
503 c->strut.bottom,
504 c->strut.left_start_y,
505 c->strut.left_end_y,
506 c->strut.right_start_y,
507 c->strut.right_end_y,
508 c->strut.top_start_x,
509 c->strut.top_end_x,
510 c->strut.bottom_start_x,
511 c->strut.bottom_end_x
514 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
515 c->win, _NET_WM_STRUT_PARTIAL, CARDINAL, 32, countof(state), state);
518 void
519 ewmh_client_check_hints(client_t *c)
521 xcb_atom_t *state;
522 void *data = NULL;
523 int desktop;
524 xcb_get_property_cookie_t c0, c1, c2;
525 xcb_get_property_reply_t *reply;
527 /* Send the GetProperty requests which will be processed later */
528 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
529 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
531 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
532 _NET_WM_STATE, ATOM, 0, UINT32_MAX);
534 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->win,
535 _NET_WM_WINDOW_TYPE, ATOM, 0, UINT32_MAX);
537 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
538 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
540 tag_array_t *tags = &globalconf.screens[c->screen].tags;
542 desktop = *(uint32_t *) data;
543 if(desktop == -1)
544 c->issticky = true;
545 else
546 for(int i = 0; i < tags->len; i++)
547 if(desktop == i)
548 tag_client(c, tags->tab[i]);
549 else
550 untag_client(c, tags->tab[i]);
553 p_delete(&reply);
555 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
556 if(reply && (data = xcb_get_property_value(reply)))
558 state = (xcb_atom_t *) data;
559 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
560 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
563 p_delete(&reply);
565 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
566 if(reply && (data = xcb_get_property_value(reply)))
568 state = (xcb_atom_t *) data;
569 for(int i = 0; i < xcb_get_property_value_length(reply); i++)
570 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
571 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
572 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
573 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
574 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
575 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
576 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
577 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
578 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
579 c->type = MAX(c->type, WINDOW_TYPE_MENU);
580 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
581 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
582 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
583 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
586 p_delete(&reply);
589 /** Process the WM strut of a client.
590 * \param c The client.
592 void
593 ewmh_process_client_strut(client_t *c, xcb_get_property_reply_t *strut_r)
595 void *data;
596 xcb_get_property_reply_t *mstrut_r = NULL;
598 if(!strut_r)
600 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->win,
601 _NET_WM_STRUT_PARTIAL, CARDINAL, 0, 12);
602 strut_r = mstrut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
605 if(strut_r
606 && strut_r->value_len
607 && (data = xcb_get_property_value(strut_r)))
609 uint32_t *strut = data;
611 if(c->strut.left != strut[0]
612 || c->strut.right != strut[1]
613 || c->strut.top != strut[2]
614 || c->strut.bottom != strut[3]
615 || c->strut.left_start_y != strut[4]
616 || c->strut.left_end_y != strut[5]
617 || c->strut.right_start_y != strut[6]
618 || c->strut.right_end_y != strut[7]
619 || c->strut.top_start_x != strut[8]
620 || c->strut.top_end_x != strut[9]
621 || c->strut.bottom_start_x != strut[10]
622 || c->strut.bottom_end_x != strut[11])
624 c->strut.left = strut[0];
625 c->strut.right = strut[1];
626 c->strut.top = strut[2];
627 c->strut.bottom = strut[3];
628 c->strut.left_start_y = strut[4];
629 c->strut.left_end_y = strut[5];
630 c->strut.right_start_y = strut[6];
631 c->strut.right_end_y = strut[7];
632 c->strut.top_start_x = strut[8];
633 c->strut.top_end_x = strut[9];
634 c->strut.bottom_start_x = strut[10];
635 c->strut.bottom_end_x = strut[11];
637 client_need_arrange(c);
638 /* All the wiboxes (may) need to be repositioned. */
639 wibox_update_positions();
643 p_delete(&mstrut_r);
646 /** Send request to get NET_WM_ICON (EWMH)
647 * \param w The window.
648 * \return The cookie associated with the request.
650 xcb_get_property_cookie_t
651 ewmh_window_icon_get_unchecked(xcb_window_t w)
653 return xcb_get_property_unchecked(globalconf.connection, false, w,
654 _NET_WM_ICON, CARDINAL, 0, UINT32_MAX);
657 image_t *
658 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
660 uint32_t *data;
662 if(!r || r->type != CARDINAL || r->format != 32 || r->length < 2 ||
663 !(data = (uint32_t *) xcb_get_property_value(r)))
664 return NULL;
666 if(data[0] && data[1])
667 return image_new_from_argb32(data[0], data[1], data + 2);
669 return NULL;
672 /** Get NET_WM_ICON.
673 * \param cookie The cookie.
674 * \return A draw_image_t structure which must be deleted after usage.
676 image_t *
677 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
679 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
680 image_t *icon = ewmh_window_icon_from_reply(r);
681 p_delete(&r);
682 return icon;
685 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80