Drop focus:raise() in magnifier.arrange
[awesome.git] / ewmh.c
blob817957db2d240d0e0d70a206f5c75bfcd220d64a
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 "objects/tag.h"
30 #include "screen.h"
31 #include "objects/client.h"
32 #include "luaa.h"
33 #include "common/atoms.h"
34 #include "common/buffer.h"
35 #include "common/xutil.h"
37 #define _NET_WM_STATE_REMOVE 0
38 #define _NET_WM_STATE_ADD 1
39 #define _NET_WM_STATE_TOGGLE 2
41 /** Update client EWMH hints.
42 * \param c The client.
44 static int
45 ewmh_client_update_hints(lua_State *L)
47 client_t *c = luaA_checkudata(L, 1, &client_class);
48 xcb_atom_t state[10]; /* number of defined state atoms */
49 int i = 0;
51 if(c->modal)
52 state[i++] = _NET_WM_STATE_MODAL;
53 if(c->fullscreen)
54 state[i++] = _NET_WM_STATE_FULLSCREEN;
55 if(c->maximized_vertical)
56 state[i++] = _NET_WM_STATE_MAXIMIZED_VERT;
57 if(c->maximized_horizontal)
58 state[i++] = _NET_WM_STATE_MAXIMIZED_HORZ;
59 if(c->sticky)
60 state[i++] = _NET_WM_STATE_STICKY;
61 if(c->skip_taskbar)
62 state[i++] = _NET_WM_STATE_SKIP_TASKBAR;
63 if(c->above)
64 state[i++] = _NET_WM_STATE_ABOVE;
65 if(c->below)
66 state[i++] = _NET_WM_STATE_BELOW;
67 if(c->minimized)
68 state[i++] = _NET_WM_STATE_HIDDEN;
69 if(c->urgent)
70 state[i++] = _NET_WM_STATE_DEMANDS_ATTENTION;
72 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
73 c->window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, i, state);
75 return 0;
78 static int
79 ewmh_update_net_active_window(lua_State *L)
81 xcb_window_t win;
83 if(globalconf.focus.client)
84 win = globalconf.focus.client->window;
85 else
86 win = XCB_NONE;
88 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
89 globalconf.screen->root,
90 _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, &win);
92 return 0;
95 static int
96 ewmh_update_net_client_list(lua_State *L)
98 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
100 int n = 0;
101 foreach(client, globalconf.clients)
102 wins[n++] = (*client)->window;
104 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
105 globalconf.screen->root,
106 _NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, n, wins);
108 return 0;
111 void
112 ewmh_init(void)
114 xcb_window_t father;
115 xcb_screen_t *xscreen = globalconf.screen;
116 xcb_atom_t atom[] =
118 _NET_SUPPORTED,
119 _NET_SUPPORTING_WM_CHECK,
120 _NET_STARTUP_ID,
121 _NET_CLIENT_LIST,
122 _NET_CLIENT_LIST_STACKING,
123 _NET_NUMBER_OF_DESKTOPS,
124 _NET_CURRENT_DESKTOP,
125 _NET_DESKTOP_NAMES,
126 _NET_ACTIVE_WINDOW,
127 _NET_CLOSE_WINDOW,
128 _NET_WM_NAME,
129 _NET_WM_STRUT_PARTIAL,
130 _NET_WM_ICON_NAME,
131 _NET_WM_VISIBLE_ICON_NAME,
132 _NET_WM_DESKTOP,
133 _NET_WM_WINDOW_TYPE,
134 _NET_WM_WINDOW_TYPE_DESKTOP,
135 _NET_WM_WINDOW_TYPE_DOCK,
136 _NET_WM_WINDOW_TYPE_TOOLBAR,
137 _NET_WM_WINDOW_TYPE_MENU,
138 _NET_WM_WINDOW_TYPE_UTILITY,
139 _NET_WM_WINDOW_TYPE_SPLASH,
140 _NET_WM_WINDOW_TYPE_DIALOG,
141 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
142 _NET_WM_WINDOW_TYPE_POPUP_MENU,
143 _NET_WM_WINDOW_TYPE_TOOLTIP,
144 _NET_WM_WINDOW_TYPE_NOTIFICATION,
145 _NET_WM_WINDOW_TYPE_COMBO,
146 _NET_WM_WINDOW_TYPE_DND,
147 _NET_WM_WINDOW_TYPE_NORMAL,
148 _NET_WM_ICON,
149 _NET_WM_PID,
150 _NET_WM_STATE,
151 _NET_WM_STATE_STICKY,
152 _NET_WM_STATE_SKIP_TASKBAR,
153 _NET_WM_STATE_FULLSCREEN,
154 _NET_WM_STATE_MAXIMIZED_HORZ,
155 _NET_WM_STATE_MAXIMIZED_VERT,
156 _NET_WM_STATE_ABOVE,
157 _NET_WM_STATE_BELOW,
158 _NET_WM_STATE_MODAL,
159 _NET_WM_STATE_HIDDEN,
160 _NET_WM_STATE_DEMANDS_ATTENTION
162 int i;
164 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
165 xscreen->root, _NET_SUPPORTED, XCB_ATOM_ATOM, 32,
166 countof(atom), atom);
168 /* create our own window */
169 father = xcb_generate_id(globalconf.connection);
170 xcb_create_window(globalconf.connection, xscreen->root_depth,
171 father, xscreen->root, -1, -1, 1, 1, 0,
172 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
174 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
175 xscreen->root, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
176 1, &father);
178 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
179 father, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
180 1, &father);
182 /* set the window manager name */
183 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
184 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
186 /* set the window manager PID */
187 i = getpid();
188 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
189 father, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &i);
192 luaA_class_connect_signal(globalconf.L, &client_class, "focus", ewmh_update_net_active_window);
193 luaA_class_connect_signal(globalconf.L, &client_class, "unfocus", ewmh_update_net_active_window);
194 luaA_class_connect_signal(globalconf.L, &client_class, "manage", ewmh_update_net_client_list);
195 luaA_class_connect_signal(globalconf.L, &client_class, "unmanage", ewmh_update_net_client_list);
196 luaA_class_connect_signal(globalconf.L, &client_class, "property::modal" , ewmh_client_update_hints);
197 luaA_class_connect_signal(globalconf.L, &client_class, "property::fullscreen" , ewmh_client_update_hints);
198 luaA_class_connect_signal(globalconf.L, &client_class, "property::maximized_horizontal" , ewmh_client_update_hints);
199 luaA_class_connect_signal(globalconf.L, &client_class, "property::maximized_vertical" , ewmh_client_update_hints);
200 luaA_class_connect_signal(globalconf.L, &client_class, "property::sticky" , ewmh_client_update_hints);
201 luaA_class_connect_signal(globalconf.L, &client_class, "property::skip_taskbar" , ewmh_client_update_hints);
202 luaA_class_connect_signal(globalconf.L, &client_class, "property::above" , ewmh_client_update_hints);
203 luaA_class_connect_signal(globalconf.L, &client_class, "property::below" , ewmh_client_update_hints);
204 luaA_class_connect_signal(globalconf.L, &client_class, "property::minimized" , ewmh_client_update_hints);
205 luaA_class_connect_signal(globalconf.L, &client_class, "property::urgent" , ewmh_client_update_hints);
208 /** Set the client list in stacking order, bottom to top.
210 void
211 ewmh_update_net_client_list_stacking(void)
213 int n = 0;
214 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
216 foreach(client, globalconf.stack)
217 wins[n++] = (*client)->window;
219 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
220 globalconf.screen->root,
221 _NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, 32, n, wins);
224 void
225 ewmh_update_net_numbers_of_desktop(void)
227 uint32_t count = globalconf.tags.len;
229 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
230 globalconf.screen->root,
231 _NET_NUMBER_OF_DESKTOPS, XCB_ATOM_CARDINAL, 32, 1, &count);
234 void
235 ewmh_update_net_current_desktop(void)
237 uint32_t idx = tags_get_first_selected_index();
239 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
240 globalconf.screen->root,
241 _NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &idx);
244 void
245 ewmh_update_net_desktop_names(void)
247 buffer_t buf;
249 buffer_inita(&buf, BUFSIZ);
251 foreach(tag, globalconf.tags)
253 buffer_adds(&buf, tag_get_name(*tag));
254 buffer_addc(&buf, '\0');
257 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
258 globalconf.screen->root,
259 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
260 buffer_wipe(&buf);
263 static void
264 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
266 luaA_object_push(globalconf.L, c);
268 if(state == _NET_WM_STATE_STICKY)
270 if(set == _NET_WM_STATE_REMOVE)
271 client_set_sticky(globalconf.L, -1, false);
272 else if(set == _NET_WM_STATE_ADD)
273 client_set_sticky(globalconf.L, -1, true);
274 else if(set == _NET_WM_STATE_TOGGLE)
275 client_set_sticky(globalconf.L, -1, !c->sticky);
277 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
279 if(set == _NET_WM_STATE_REMOVE)
280 client_set_skip_taskbar(globalconf.L, -1, false);
281 else if(set == _NET_WM_STATE_ADD)
282 client_set_skip_taskbar(globalconf.L, -1, true);
283 else if(set == _NET_WM_STATE_TOGGLE)
284 client_set_skip_taskbar(globalconf.L, -1, !c->skip_taskbar);
286 else if(state == _NET_WM_STATE_FULLSCREEN)
288 if(set == _NET_WM_STATE_REMOVE)
289 client_set_fullscreen(globalconf.L, -1, false);
290 else if(set == _NET_WM_STATE_ADD)
291 client_set_fullscreen(globalconf.L, -1, true);
292 else if(set == _NET_WM_STATE_TOGGLE)
293 client_set_fullscreen(globalconf.L, -1, !c->fullscreen);
295 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
297 if(set == _NET_WM_STATE_REMOVE)
298 client_set_maximized_horizontal(globalconf.L, -1, false);
299 else if(set == _NET_WM_STATE_ADD)
300 client_set_maximized_horizontal(globalconf.L, -1, true);
301 else if(set == _NET_WM_STATE_TOGGLE)
302 client_set_maximized_horizontal(globalconf.L, -1, !c->maximized_horizontal);
304 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
306 if(set == _NET_WM_STATE_REMOVE)
307 client_set_maximized_vertical(globalconf.L, -1, false);
308 else if(set == _NET_WM_STATE_ADD)
309 client_set_maximized_vertical(globalconf.L, -1, true);
310 else if(set == _NET_WM_STATE_TOGGLE)
311 client_set_maximized_vertical(globalconf.L, -1, !c->maximized_vertical);
313 else if(state == _NET_WM_STATE_ABOVE)
315 if(set == _NET_WM_STATE_REMOVE)
316 client_set_above(globalconf.L, -1, false);
317 else if(set == _NET_WM_STATE_ADD)
318 client_set_above(globalconf.L, -1, true);
319 else if(set == _NET_WM_STATE_TOGGLE)
320 client_set_above(globalconf.L, -1, !c->above);
322 else if(state == _NET_WM_STATE_BELOW)
324 if(set == _NET_WM_STATE_REMOVE)
325 client_set_below(globalconf.L, -1, false);
326 else if(set == _NET_WM_STATE_ADD)
327 client_set_below(globalconf.L, -1, true);
328 else if(set == _NET_WM_STATE_TOGGLE)
329 client_set_below(globalconf.L, -1, !c->below);
331 else if(state == _NET_WM_STATE_MODAL)
333 if(set == _NET_WM_STATE_REMOVE)
334 client_set_modal(globalconf.L, -1, false);
335 else if(set == _NET_WM_STATE_ADD)
336 client_set_modal(globalconf.L, -1, true);
337 else if(set == _NET_WM_STATE_TOGGLE)
338 client_set_modal(globalconf.L, -1, !c->modal);
340 else if(state == _NET_WM_STATE_HIDDEN)
342 if(set == _NET_WM_STATE_REMOVE)
343 client_set_minimized(globalconf.L, -1, false);
344 else if(set == _NET_WM_STATE_ADD)
345 client_set_minimized(globalconf.L, -1, true);
346 else if(set == _NET_WM_STATE_TOGGLE)
347 client_set_minimized(globalconf.L, -1, !c->minimized);
349 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
351 if(set == _NET_WM_STATE_REMOVE)
352 client_set_urgent(globalconf.L, -1, false);
353 else if(set == _NET_WM_STATE_ADD)
354 client_set_urgent(globalconf.L, -1, true);
355 else if(set == _NET_WM_STATE_TOGGLE)
356 client_set_urgent(globalconf.L, -1, !c->urgent);
359 lua_pop(globalconf.L, 1);
362 static void
363 ewmh_process_desktop(client_t *c, uint32_t desktop)
365 int idx = desktop;
366 if(desktop == 0xffffffff)
368 luaA_object_push(globalconf.L, c);
369 lua_pushnil(globalconf.L);
370 luaA_object_emit_signal(globalconf.L, -2, "request::tag", 1);
371 /* Pop the client, arguments are already popped */
372 lua_pop(globalconf.L, 1);
374 else if (idx >= 0 && idx < globalconf.tags.len)
376 luaA_object_push(globalconf.L, c);
377 luaA_object_push(globalconf.L, globalconf.tags.tab[idx]);
378 luaA_object_emit_signal(globalconf.L, -2, "request::tag", 1);
379 /* Pop the client, arguments are already popped */
380 lua_pop(globalconf.L, 1);
385 ewmh_process_client_message(xcb_client_message_event_t *ev)
387 client_t *c;
389 if(ev->type == _NET_CURRENT_DESKTOP)
391 int idx = ev->data.data32[0];
392 if (idx >= 0 && idx < globalconf.tags.len)
394 luaA_object_push(globalconf.L, globalconf.tags.tab[idx]);
395 luaA_object_emit_signal(globalconf.L, -1, "request::select", 0);
396 lua_pop(globalconf.L, 1);
399 else if(ev->type == _NET_CLOSE_WINDOW)
401 if((c = client_getbywin(ev->window)))
402 client_kill(c);
404 else if(ev->type == _NET_WM_DESKTOP)
406 if((c = client_getbywin(ev->window)))
408 ewmh_process_desktop(c, ev->data.data32[0]);
411 else if(ev->type == _NET_WM_STATE)
413 if((c = client_getbywin(ev->window)))
415 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
416 if(ev->data.data32[2])
417 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
418 ev->data.data32[0]);
421 else if(ev->type == _NET_ACTIVE_WINDOW)
423 if((c = client_getbywin(ev->window))) {
424 luaA_object_push(globalconf.L, c);
425 luaA_object_emit_signal(globalconf.L, -1, "request::activate", 0);
426 lua_pop(globalconf.L, 1);
430 return 0;
433 /** Update the client active desktop.
434 * This is "wrong" since it can be on several tags, but EWMH has a strict view
435 * of desktop system so just take the first tag.
436 * \param c The client.
438 void
439 ewmh_client_update_desktop(client_t *c)
441 int i;
443 for(i = 0; i < globalconf.tags.len; i++)
444 if(is_client_tagged(c, globalconf.tags.tab[i]))
446 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
447 c->window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &i);
448 return;
450 /* It doesn't have any tags, remove the property */
451 xcb_delete_property(globalconf.connection, c->window, _NET_WM_DESKTOP);
454 /** Update the client struts.
455 * \param window The window to update the struts for.
456 * \param strut The strut type to update the window with.
458 void
459 ewmh_update_strut(xcb_window_t window, strut_t *strut)
461 if(window)
463 const uint32_t state[] =
465 strut->left,
466 strut->right,
467 strut->top,
468 strut->bottom,
469 strut->left_start_y,
470 strut->left_end_y,
471 strut->right_start_y,
472 strut->right_end_y,
473 strut->top_start_x,
474 strut->top_end_x,
475 strut->bottom_start_x,
476 strut->bottom_end_x
479 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
480 window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, countof(state), state);
484 /** Update the window type.
485 * \param window The window to update.
486 * \param type The new type to set.
488 void
489 ewmh_update_window_type(xcb_window_t window, uint32_t type)
491 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
492 window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, &type);
495 void
496 ewmh_client_check_hints(client_t *c)
498 xcb_atom_t *state;
499 void *data = NULL;
500 xcb_get_property_cookie_t c0, c1, c2;
501 xcb_get_property_reply_t *reply;
503 /* Send the GetProperty requests which will be processed later */
504 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
505 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
507 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
508 _NET_WM_STATE, XCB_ATOM_ATOM, 0, UINT32_MAX);
510 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
511 _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 0, UINT32_MAX);
513 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
514 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
516 ewmh_process_desktop(c, *(uint32_t *) data);
519 p_delete(&reply);
521 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
522 if(reply && (data = xcb_get_property_value(reply)))
524 state = (xcb_atom_t *) data;
525 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
526 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
529 p_delete(&reply);
531 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
532 if(reply && (data = xcb_get_property_value(reply)))
534 state = (xcb_atom_t *) data;
535 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
536 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
537 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
538 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
539 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
540 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
541 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
542 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
543 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
544 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
545 c->type = MAX(c->type, WINDOW_TYPE_MENU);
546 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
547 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
548 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
549 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
552 p_delete(&reply);
555 /** Process the WM strut of a client.
556 * \param c The client.
557 * \param strut_r (Optional) An existing reply.
559 void
560 ewmh_process_client_strut(client_t *c)
562 void *data;
563 xcb_get_property_reply_t *strut_r;
565 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->window,
566 _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 0, 12);
567 strut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
569 if(strut_r
570 && strut_r->value_len
571 && (data = xcb_get_property_value(strut_r)))
573 uint32_t *strut = data;
575 if(c->strut.left != strut[0]
576 || c->strut.right != strut[1]
577 || c->strut.top != strut[2]
578 || c->strut.bottom != strut[3]
579 || c->strut.left_start_y != strut[4]
580 || c->strut.left_end_y != strut[5]
581 || c->strut.right_start_y != strut[6]
582 || c->strut.right_end_y != strut[7]
583 || c->strut.top_start_x != strut[8]
584 || c->strut.top_end_x != strut[9]
585 || c->strut.bottom_start_x != strut[10]
586 || c->strut.bottom_end_x != strut[11])
588 c->strut.left = strut[0];
589 c->strut.right = strut[1];
590 c->strut.top = strut[2];
591 c->strut.bottom = strut[3];
592 c->strut.left_start_y = strut[4];
593 c->strut.left_end_y = strut[5];
594 c->strut.right_start_y = strut[6];
595 c->strut.right_end_y = strut[7];
596 c->strut.top_start_x = strut[8];
597 c->strut.top_end_x = strut[9];
598 c->strut.bottom_start_x = strut[10];
599 c->strut.bottom_end_x = strut[11];
601 luaA_object_push(globalconf.L, c);
602 luaA_object_emit_signal(globalconf.L, -1, "property::struts", 0);
603 lua_pop(globalconf.L, 1);
607 p_delete(&strut_r);
610 /** Send request to get NET_WM_ICON (EWMH)
611 * \param w The window.
612 * \return The cookie associated with the request.
614 xcb_get_property_cookie_t
615 ewmh_window_icon_get_unchecked(xcb_window_t w)
617 return xcb_get_property_unchecked(globalconf.connection, false, w,
618 _NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX);
621 static cairo_surface_t *
622 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
624 uint32_t *data;
625 uint64_t len;
627 if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2)
628 return 0;
630 data = (uint32_t *) xcb_get_property_value(r);
631 if (!data)
632 return 0;
634 /* Check that the property is as long as it should be, handling integer
635 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
636 * fits into an uint64_t and thus this multiplication cannot overflow.
638 len = data[0] * (uint64_t) data[1];
639 if (!data[0] || !data[1] || len > r->length - 2)
640 return 0;
642 return draw_surface_from_data(data[0], data[1], data + 2);
645 /** Get NET_WM_ICON.
646 * \param cookie The cookie.
647 * \return The number of elements on stack.
649 cairo_surface_t *
650 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
652 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
653 cairo_surface_t *surface = ewmh_window_icon_from_reply(r);
654 p_delete(&r);
655 return surface;
658 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80