gears.object: Give better error messages
[awesome.git] / ewmh.c
blob3bd94f5348a43a0be6ad6b9fd6b41322378cdfa3
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 /** Update the desktop geometry.
80 static void
81 ewmh_update_desktop_geometry(void)
83 area_t geom = screen_area_get(&globalconf.screens.tab[0], false);
84 uint32_t sizes[] = { geom.width, geom.height };
86 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
87 globalconf.screen->root,
88 _NET_DESKTOP_GEOMETRY, XCB_ATOM_CARDINAL, 32, countof(sizes), sizes);
91 static int
92 ewmh_update_net_active_window(lua_State *L)
94 xcb_window_t win;
96 if(globalconf.focus.client)
97 win = globalconf.focus.client->window;
98 else
99 win = XCB_NONE;
101 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
102 globalconf.screen->root,
103 _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, &win);
105 return 0;
108 static int
109 ewmh_update_net_client_list(lua_State *L)
111 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.clients.len);
113 int n = 0;
114 foreach(client, globalconf.clients)
115 wins[n++] = (*client)->window;
117 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
118 globalconf.screen->root,
119 _NET_CLIENT_LIST, XCB_ATOM_WINDOW, 32, n, wins);
121 return 0;
124 void
125 ewmh_init(void)
127 xcb_window_t father;
128 xcb_screen_t *xscreen = globalconf.screen;
129 xcb_atom_t atom[] =
131 _NET_SUPPORTED,
132 _NET_SUPPORTING_WM_CHECK,
133 _NET_STARTUP_ID,
134 _NET_CLIENT_LIST,
135 _NET_CLIENT_LIST_STACKING,
136 _NET_NUMBER_OF_DESKTOPS,
137 _NET_CURRENT_DESKTOP,
138 _NET_DESKTOP_NAMES,
139 _NET_ACTIVE_WINDOW,
140 _NET_DESKTOP_GEOMETRY,
141 _NET_CLOSE_WINDOW,
142 _NET_WM_NAME,
143 _NET_WM_STRUT_PARTIAL,
144 _NET_WM_ICON_NAME,
145 _NET_WM_VISIBLE_ICON_NAME,
146 _NET_WM_DESKTOP,
147 _NET_WM_WINDOW_TYPE,
148 _NET_WM_WINDOW_TYPE_DESKTOP,
149 _NET_WM_WINDOW_TYPE_DOCK,
150 _NET_WM_WINDOW_TYPE_TOOLBAR,
151 _NET_WM_WINDOW_TYPE_MENU,
152 _NET_WM_WINDOW_TYPE_UTILITY,
153 _NET_WM_WINDOW_TYPE_SPLASH,
154 _NET_WM_WINDOW_TYPE_DIALOG,
155 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
156 _NET_WM_WINDOW_TYPE_POPUP_MENU,
157 _NET_WM_WINDOW_TYPE_TOOLTIP,
158 _NET_WM_WINDOW_TYPE_NOTIFICATION,
159 _NET_WM_WINDOW_TYPE_COMBO,
160 _NET_WM_WINDOW_TYPE_DND,
161 _NET_WM_WINDOW_TYPE_NORMAL,
162 _NET_WM_ICON,
163 _NET_WM_PID,
164 _NET_WM_STATE,
165 _NET_WM_STATE_STICKY,
166 _NET_WM_STATE_SKIP_TASKBAR,
167 _NET_WM_STATE_FULLSCREEN,
168 _NET_WM_STATE_MAXIMIZED_HORZ,
169 _NET_WM_STATE_MAXIMIZED_VERT,
170 _NET_WM_STATE_ABOVE,
171 _NET_WM_STATE_BELOW,
172 _NET_WM_STATE_MODAL,
173 _NET_WM_STATE_HIDDEN,
174 _NET_WM_STATE_DEMANDS_ATTENTION
176 int i;
178 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
179 xscreen->root, _NET_SUPPORTED, XCB_ATOM_ATOM, 32,
180 countof(atom), atom);
182 /* create our own window */
183 father = xcb_generate_id(globalconf.connection);
184 xcb_create_window(globalconf.connection, xscreen->root_depth,
185 father, xscreen->root, -1, -1, 1, 1, 0,
186 XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
188 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
189 xscreen->root, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
190 1, &father);
192 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
193 father, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32,
194 1, &father);
196 /* set the window manager name */
197 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
198 father, _NET_WM_NAME, UTF8_STRING, 8, 7, "awesome");
200 /* set the window manager PID */
201 i = getpid();
202 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
203 father, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &i);
205 ewmh_update_desktop_geometry();
207 luaA_class_connect_signal(globalconf.L, &client_class, "focus", ewmh_update_net_active_window);
208 luaA_class_connect_signal(globalconf.L, &client_class, "unfocus", ewmh_update_net_active_window);
209 luaA_class_connect_signal(globalconf.L, &client_class, "manage", ewmh_update_net_client_list);
210 luaA_class_connect_signal(globalconf.L, &client_class, "unmanage", ewmh_update_net_client_list);
211 luaA_class_connect_signal(globalconf.L, &client_class, "property::modal" , ewmh_client_update_hints);
212 luaA_class_connect_signal(globalconf.L, &client_class, "property::fullscreen" , ewmh_client_update_hints);
213 luaA_class_connect_signal(globalconf.L, &client_class, "property::maximized_horizontal" , ewmh_client_update_hints);
214 luaA_class_connect_signal(globalconf.L, &client_class, "property::maximized_vertical" , ewmh_client_update_hints);
215 luaA_class_connect_signal(globalconf.L, &client_class, "property::sticky" , ewmh_client_update_hints);
216 luaA_class_connect_signal(globalconf.L, &client_class, "property::skip_taskbar" , ewmh_client_update_hints);
217 luaA_class_connect_signal(globalconf.L, &client_class, "property::above" , ewmh_client_update_hints);
218 luaA_class_connect_signal(globalconf.L, &client_class, "property::below" , ewmh_client_update_hints);
219 luaA_class_connect_signal(globalconf.L, &client_class, "property::minimized" , ewmh_client_update_hints);
220 luaA_class_connect_signal(globalconf.L, &client_class, "property::urgent" , ewmh_client_update_hints);
223 /** Set the client list in stacking order, bottom to top.
225 void
226 ewmh_update_net_client_list_stacking(void)
228 int n = 0;
229 xcb_window_t *wins = p_alloca(xcb_window_t, globalconf.stack.len);
231 foreach(client, globalconf.stack)
232 wins[n++] = (*client)->window;
234 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
235 globalconf.screen->root,
236 _NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, 32, n, wins);
239 void
240 ewmh_update_net_numbers_of_desktop(void)
242 uint32_t count = globalconf.screens.tab[0].tags.len;
244 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
245 globalconf.screen->root,
246 _NET_NUMBER_OF_DESKTOPS, XCB_ATOM_CARDINAL, 32, 1, &count);
249 void
250 ewmh_update_net_current_desktop(void)
252 uint32_t idx = tags_get_first_selected_index(&globalconf.screens.tab[0]);
254 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
255 globalconf.screen->root,
256 _NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &idx);
259 void
260 ewmh_update_net_desktop_names(void)
262 buffer_t buf;
264 buffer_inita(&buf, BUFSIZ);
266 foreach(tag, globalconf.screens.tab[0].tags)
268 buffer_adds(&buf, tag_get_name(*tag));
269 buffer_addc(&buf, '\0');
272 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
273 globalconf.screen->root,
274 _NET_DESKTOP_NAMES, UTF8_STRING, 8, buf.len, buf.s);
275 buffer_wipe(&buf);
278 static void
279 ewmh_process_state_atom(client_t *c, xcb_atom_t state, int set)
281 luaA_object_push(globalconf.L, c);
283 if(state == _NET_WM_STATE_STICKY)
285 if(set == _NET_WM_STATE_REMOVE)
286 client_set_sticky(globalconf.L, -1, false);
287 else if(set == _NET_WM_STATE_ADD)
288 client_set_sticky(globalconf.L, -1, true);
289 else if(set == _NET_WM_STATE_TOGGLE)
290 client_set_sticky(globalconf.L, -1, !c->sticky);
292 else if(state == _NET_WM_STATE_SKIP_TASKBAR)
294 if(set == _NET_WM_STATE_REMOVE)
295 client_set_skip_taskbar(globalconf.L, -1, false);
296 else if(set == _NET_WM_STATE_ADD)
297 client_set_skip_taskbar(globalconf.L, -1, true);
298 else if(set == _NET_WM_STATE_TOGGLE)
299 client_set_skip_taskbar(globalconf.L, -1, !c->skip_taskbar);
301 else if(state == _NET_WM_STATE_FULLSCREEN)
303 if(set == _NET_WM_STATE_REMOVE)
304 client_set_fullscreen(globalconf.L, -1, false);
305 else if(set == _NET_WM_STATE_ADD)
306 client_set_fullscreen(globalconf.L, -1, true);
307 else if(set == _NET_WM_STATE_TOGGLE)
308 client_set_fullscreen(globalconf.L, -1, !c->fullscreen);
310 else if(state == _NET_WM_STATE_MAXIMIZED_HORZ)
312 if(set == _NET_WM_STATE_REMOVE)
313 client_set_maximized_horizontal(globalconf.L, -1, false);
314 else if(set == _NET_WM_STATE_ADD)
315 client_set_maximized_horizontal(globalconf.L, -1, true);
316 else if(set == _NET_WM_STATE_TOGGLE)
317 client_set_maximized_horizontal(globalconf.L, -1, !c->maximized_horizontal);
319 else if(state == _NET_WM_STATE_MAXIMIZED_VERT)
321 if(set == _NET_WM_STATE_REMOVE)
322 client_set_maximized_vertical(globalconf.L, -1, false);
323 else if(set == _NET_WM_STATE_ADD)
324 client_set_maximized_vertical(globalconf.L, -1, true);
325 else if(set == _NET_WM_STATE_TOGGLE)
326 client_set_maximized_vertical(globalconf.L, -1, !c->maximized_vertical);
328 else if(state == _NET_WM_STATE_ABOVE)
330 if(set == _NET_WM_STATE_REMOVE)
331 client_set_above(globalconf.L, -1, false);
332 else if(set == _NET_WM_STATE_ADD)
333 client_set_above(globalconf.L, -1, true);
334 else if(set == _NET_WM_STATE_TOGGLE)
335 client_set_above(globalconf.L, -1, !c->above);
337 else if(state == _NET_WM_STATE_BELOW)
339 if(set == _NET_WM_STATE_REMOVE)
340 client_set_below(globalconf.L, -1, false);
341 else if(set == _NET_WM_STATE_ADD)
342 client_set_below(globalconf.L, -1, true);
343 else if(set == _NET_WM_STATE_TOGGLE)
344 client_set_below(globalconf.L, -1, !c->below);
346 else if(state == _NET_WM_STATE_MODAL)
348 if(set == _NET_WM_STATE_REMOVE)
349 client_set_modal(globalconf.L, -1, false);
350 else if(set == _NET_WM_STATE_ADD)
351 client_set_modal(globalconf.L, -1, true);
352 else if(set == _NET_WM_STATE_TOGGLE)
353 client_set_modal(globalconf.L, -1, !c->modal);
355 else if(state == _NET_WM_STATE_HIDDEN)
357 if(set == _NET_WM_STATE_REMOVE)
358 client_set_minimized(globalconf.L, -1, false);
359 else if(set == _NET_WM_STATE_ADD)
360 client_set_minimized(globalconf.L, -1, true);
361 else if(set == _NET_WM_STATE_TOGGLE)
362 client_set_minimized(globalconf.L, -1, !c->minimized);
364 else if(state == _NET_WM_STATE_DEMANDS_ATTENTION)
366 if(set == _NET_WM_STATE_REMOVE)
367 client_set_urgent(globalconf.L, -1, false);
368 else if(set == _NET_WM_STATE_ADD)
369 client_set_urgent(globalconf.L, -1, true);
370 else if(set == _NET_WM_STATE_TOGGLE)
371 client_set_urgent(globalconf.L, -1, !c->urgent);
374 lua_pop(globalconf.L, 1);
378 ewmh_process_client_message(xcb_client_message_event_t *ev)
380 client_t *c;
382 if(ev->type == _NET_CURRENT_DESKTOP)
383 tag_view_only_byindex(&globalconf.screens.tab[0], ev->data.data32[0]);
384 else if(ev->type == _NET_CLOSE_WINDOW)
386 if((c = client_getbywin(ev->window)))
387 client_kill(c);
389 else if(ev->type == _NET_WM_DESKTOP)
391 if((c = client_getbywin(ev->window)))
393 tag_array_t *tags = &c->screen->tags;
395 if(ev->data.data32[0] == 0xffffffff)
396 c->sticky = true;
397 else
398 for(int i = 0; i < tags->len; i++)
399 if((int)ev->data.data32[0] == i)
401 luaA_object_push(globalconf.L, tags->tab[i]);
402 tag_client(c);
404 else
405 untag_client(c, tags->tab[i]);
408 else if(ev->type == _NET_WM_STATE)
410 if((c = client_getbywin(ev->window)))
412 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[1], ev->data.data32[0]);
413 if(ev->data.data32[2])
414 ewmh_process_state_atom(c, (xcb_atom_t) ev->data.data32[2],
415 ev->data.data32[0]);
418 else if(ev->type == _NET_ACTIVE_WINDOW)
420 if((c = client_getbywin(ev->window)))
421 client_focus(c);
424 return 0;
427 /** Update the client active desktop.
428 * This is "wrong" since it can be on several tags, but EWMH has a strict view
429 * of desktop system so just take the first tag.
430 * \param c The client.
432 void
433 ewmh_client_update_desktop(client_t *c)
435 int i;
436 tag_array_t *tags = &c->screen->tags;
438 for(i = 0; i < tags->len; i++)
439 if(is_client_tagged(c, tags->tab[i]))
441 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
442 c->window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &i);
443 return;
445 /* It doesn't have any tags, remove the property */
446 xcb_delete_property(globalconf.connection, c->window, _NET_WM_DESKTOP);
449 /** Update the client struts.
450 * \param window The window to update the struts for.
451 * \param strut The strut type to update the window with.
453 void
454 ewmh_update_strut(xcb_window_t window, strut_t *strut)
456 if(window)
458 const uint32_t state[] =
460 strut->left,
461 strut->right,
462 strut->top,
463 strut->bottom,
464 strut->left_start_y,
465 strut->left_end_y,
466 strut->right_start_y,
467 strut->right_end_y,
468 strut->top_start_x,
469 strut->top_end_x,
470 strut->bottom_start_x,
471 strut->bottom_end_x
474 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
475 window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, countof(state), state);
479 /** Update the window type.
480 * \param window The window to update.
481 * \param type The new type to set.
483 void
484 ewmh_update_window_type(xcb_window_t window, uint32_t type)
486 xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE,
487 window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, &type);
490 void
491 ewmh_client_check_hints(client_t *c)
493 xcb_atom_t *state;
494 void *data = NULL;
495 int desktop;
496 xcb_get_property_cookie_t c0, c1, c2;
497 xcb_get_property_reply_t *reply;
499 /* Send the GetProperty requests which will be processed later */
500 c0 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
501 _NET_WM_DESKTOP, XCB_GET_PROPERTY_TYPE_ANY, 0, 1);
503 c1 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
504 _NET_WM_STATE, XCB_ATOM_ATOM, 0, UINT32_MAX);
506 c2 = xcb_get_property_unchecked(globalconf.connection, false, c->window,
507 _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 0, UINT32_MAX);
509 reply = xcb_get_property_reply(globalconf.connection, c0, NULL);
510 if(reply && reply->value_len && (data = xcb_get_property_value(reply)))
512 tag_array_t *tags = &c->screen->tags;
514 desktop = *(uint32_t *) data;
515 if(desktop == -1)
516 c->sticky = true;
517 else if (desktop >= 0 && desktop < tags->len)
518 for(int i = 0; i < tags->len; i++)
519 if(desktop == i)
521 luaA_object_push(globalconf.L, tags->tab[i]);
522 tag_client(c);
524 else
525 untag_client(c, tags->tab[i]);
526 else
527 /* Value out of bounds, just give it the first tag */
528 if (tags->len > 0)
530 luaA_object_push(globalconf.L, tags->tab[0]);
531 tag_client(c);
535 p_delete(&reply);
537 reply = xcb_get_property_reply(globalconf.connection, c1, NULL);
538 if(reply && (data = xcb_get_property_value(reply)))
540 state = (xcb_atom_t *) data;
541 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
542 ewmh_process_state_atom(c, state[i], _NET_WM_STATE_ADD);
545 p_delete(&reply);
547 reply = xcb_get_property_reply(globalconf.connection, c2, NULL);
548 if(reply && (data = xcb_get_property_value(reply)))
550 state = (xcb_atom_t *) data;
551 for(int i = 0; i < xcb_get_property_value_length(reply) / ssizeof(xcb_atom_t); i++)
552 if(state[i] == _NET_WM_WINDOW_TYPE_DESKTOP)
553 c->type = MAX(c->type, WINDOW_TYPE_DESKTOP);
554 else if(state[i] == _NET_WM_WINDOW_TYPE_DIALOG)
555 c->type = MAX(c->type, WINDOW_TYPE_DIALOG);
556 else if(state[i] == _NET_WM_WINDOW_TYPE_SPLASH)
557 c->type = MAX(c->type, WINDOW_TYPE_SPLASH);
558 else if(state[i] == _NET_WM_WINDOW_TYPE_DOCK)
559 c->type = MAX(c->type, WINDOW_TYPE_DOCK);
560 else if(state[i] == _NET_WM_WINDOW_TYPE_MENU)
561 c->type = MAX(c->type, WINDOW_TYPE_MENU);
562 else if(state[i] == _NET_WM_WINDOW_TYPE_TOOLBAR)
563 c->type = MAX(c->type, WINDOW_TYPE_TOOLBAR);
564 else if(state[i] == _NET_WM_WINDOW_TYPE_UTILITY)
565 c->type = MAX(c->type, WINDOW_TYPE_UTILITY);
568 p_delete(&reply);
571 /** Process the WM strut of a client.
572 * \param c The client.
573 * \param strut_r (Optional) An existing reply.
575 void
576 ewmh_process_client_strut(client_t *c)
578 void *data;
579 xcb_get_property_reply_t *strut_r;
581 xcb_get_property_cookie_t strut_q = xcb_get_property_unchecked(globalconf.connection, false, c->window,
582 _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 0, 12);
583 strut_r = xcb_get_property_reply(globalconf.connection, strut_q, NULL);
585 if(strut_r
586 && strut_r->value_len
587 && (data = xcb_get_property_value(strut_r)))
589 uint32_t *strut = data;
591 if(c->strut.left != strut[0]
592 || c->strut.right != strut[1]
593 || c->strut.top != strut[2]
594 || c->strut.bottom != strut[3]
595 || c->strut.left_start_y != strut[4]
596 || c->strut.left_end_y != strut[5]
597 || c->strut.right_start_y != strut[6]
598 || c->strut.right_end_y != strut[7]
599 || c->strut.top_start_x != strut[8]
600 || c->strut.top_end_x != strut[9]
601 || c->strut.bottom_start_x != strut[10]
602 || c->strut.bottom_end_x != strut[11])
604 c->strut.left = strut[0];
605 c->strut.right = strut[1];
606 c->strut.top = strut[2];
607 c->strut.bottom = strut[3];
608 c->strut.left_start_y = strut[4];
609 c->strut.left_end_y = strut[5];
610 c->strut.right_start_y = strut[6];
611 c->strut.right_end_y = strut[7];
612 c->strut.top_start_x = strut[8];
613 c->strut.top_end_x = strut[9];
614 c->strut.bottom_start_x = strut[10];
615 c->strut.bottom_end_x = strut[11];
617 luaA_object_push(globalconf.L, c);
618 luaA_object_emit_signal(globalconf.L, -1, "property::struts", 0);
619 lua_pop(globalconf.L, 1);
623 p_delete(&strut_r);
626 /** Send request to get NET_WM_ICON (EWMH)
627 * \param w The window.
628 * \return The cookie associated with the request.
630 xcb_get_property_cookie_t
631 ewmh_window_icon_get_unchecked(xcb_window_t w)
633 return xcb_get_property_unchecked(globalconf.connection, false, w,
634 _NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX);
637 static cairo_surface_t *
638 ewmh_window_icon_from_reply(xcb_get_property_reply_t *r)
640 uint32_t *data;
641 uint64_t len;
643 if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2)
644 return 0;
646 data = (uint32_t *) xcb_get_property_value(r);
647 if (!data)
648 return 0;
650 /* Check that the property is as long as it should be, handling integer
651 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
652 * fits into an uint64_t and thus this multiplication cannot overflow.
654 len = data[0] * (uint64_t) data[1];
655 if (!data[0] || !data[1] || len > r->length - 2)
656 return 0;
658 return draw_surface_from_data(data[0], data[1], data + 2);
661 /** Get NET_WM_ICON.
662 * \param cookie The cookie.
663 * \return The number of elements on stack.
665 cairo_surface_t *
666 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie)
668 xcb_get_property_reply_t *r = xcb_get_property_reply(globalconf.connection, cookie, NULL);
669 cairo_surface_t *surface = ewmh_window_icon_from_reply(r);
670 p_delete(&r);
671 return surface;
674 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80