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.
23 #include "objects/client.h"
24 #include "objects/tag.h"
25 #include "common/atoms.h"
27 #include <sys/types.h>
31 #include <xcb/xcb_atom.h>
33 #define _NET_WM_STATE_REMOVE 0
34 #define _NET_WM_STATE_ADD 1
35 #define _NET_WM_STATE_TOGGLE 2
37 /** Update client EWMH hints.
38 * \param c The client.
41 ewmh_client_update_hints(lua_State
*L
)
43 client_t
*c
= luaA_checkudata(L
, 1, &client_class
);
44 xcb_atom_t state
[10]; /* number of defined state atoms */
48 state
[i
++] = _NET_WM_STATE_MODAL
;
50 state
[i
++] = _NET_WM_STATE_FULLSCREEN
;
51 if(c
->maximized_vertical
)
52 state
[i
++] = _NET_WM_STATE_MAXIMIZED_VERT
;
53 if(c
->maximized_horizontal
)
54 state
[i
++] = _NET_WM_STATE_MAXIMIZED_HORZ
;
56 state
[i
++] = _NET_WM_STATE_STICKY
;
58 state
[i
++] = _NET_WM_STATE_SKIP_TASKBAR
;
60 state
[i
++] = _NET_WM_STATE_ABOVE
;
62 state
[i
++] = _NET_WM_STATE_BELOW
;
64 state
[i
++] = _NET_WM_STATE_HIDDEN
;
66 state
[i
++] = _NET_WM_STATE_DEMANDS_ATTENTION
;
68 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
69 c
->window
, _NET_WM_STATE
, XCB_ATOM_ATOM
, 32, i
, state
);
75 ewmh_update_net_active_window(lua_State
*L
)
79 if(globalconf
.focus
.client
)
80 win
= globalconf
.focus
.client
->window
;
84 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
85 globalconf
.screen
->root
,
86 _NET_ACTIVE_WINDOW
, XCB_ATOM_WINDOW
, 32, 1, &win
);
92 ewmh_update_net_client_list(lua_State
*L
)
94 xcb_window_t
*wins
= p_alloca(xcb_window_t
, globalconf
.clients
.len
);
97 foreach(client
, globalconf
.clients
)
98 wins
[n
++] = (*client
)->window
;
100 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
101 globalconf
.screen
->root
,
102 _NET_CLIENT_LIST
, XCB_ATOM_WINDOW
, 32, n
, wins
);
111 xcb_screen_t
*xscreen
= globalconf
.screen
;
115 _NET_SUPPORTING_WM_CHECK
,
118 _NET_CLIENT_LIST_STACKING
,
119 _NET_NUMBER_OF_DESKTOPS
,
120 _NET_CURRENT_DESKTOP
,
125 _NET_WM_STRUT_PARTIAL
,
127 _NET_WM_VISIBLE_ICON_NAME
,
130 _NET_WM_WINDOW_TYPE_DESKTOP
,
131 _NET_WM_WINDOW_TYPE_DOCK
,
132 _NET_WM_WINDOW_TYPE_TOOLBAR
,
133 _NET_WM_WINDOW_TYPE_MENU
,
134 _NET_WM_WINDOW_TYPE_UTILITY
,
135 _NET_WM_WINDOW_TYPE_SPLASH
,
136 _NET_WM_WINDOW_TYPE_DIALOG
,
137 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU
,
138 _NET_WM_WINDOW_TYPE_POPUP_MENU
,
139 _NET_WM_WINDOW_TYPE_TOOLTIP
,
140 _NET_WM_WINDOW_TYPE_NOTIFICATION
,
141 _NET_WM_WINDOW_TYPE_COMBO
,
142 _NET_WM_WINDOW_TYPE_DND
,
143 _NET_WM_WINDOW_TYPE_NORMAL
,
147 _NET_WM_STATE_STICKY
,
148 _NET_WM_STATE_SKIP_TASKBAR
,
149 _NET_WM_STATE_FULLSCREEN
,
150 _NET_WM_STATE_MAXIMIZED_HORZ
,
151 _NET_WM_STATE_MAXIMIZED_VERT
,
155 _NET_WM_STATE_HIDDEN
,
156 _NET_WM_STATE_DEMANDS_ATTENTION
160 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
161 xscreen
->root
, _NET_SUPPORTED
, XCB_ATOM_ATOM
, 32,
162 countof(atom
), atom
);
164 /* create our own window */
165 father
= xcb_generate_id(globalconf
.connection
);
166 xcb_create_window(globalconf
.connection
, xscreen
->root_depth
,
167 father
, xscreen
->root
, -1, -1, 1, 1, 0,
168 XCB_COPY_FROM_PARENT
, xscreen
->root_visual
, 0, NULL
);
170 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
171 xscreen
->root
, _NET_SUPPORTING_WM_CHECK
, XCB_ATOM_WINDOW
, 32,
174 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
175 father
, _NET_SUPPORTING_WM_CHECK
, XCB_ATOM_WINDOW
, 32,
178 /* set the window manager name */
179 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
180 father
, _NET_WM_NAME
, UTF8_STRING
, 8, 7, "awesome");
182 /* set the window manager PID */
184 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
185 father
, _NET_WM_PID
, XCB_ATOM_CARDINAL
, 32, 1, &i
);
188 luaA_class_connect_signal(globalconf
.L
, &client_class
, "focus", ewmh_update_net_active_window
);
189 luaA_class_connect_signal(globalconf
.L
, &client_class
, "unfocus", ewmh_update_net_active_window
);
190 luaA_class_connect_signal(globalconf
.L
, &client_class
, "manage", ewmh_update_net_client_list
);
191 luaA_class_connect_signal(globalconf
.L
, &client_class
, "unmanage", ewmh_update_net_client_list
);
192 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::modal" , ewmh_client_update_hints
);
193 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::fullscreen" , ewmh_client_update_hints
);
194 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::maximized_horizontal" , ewmh_client_update_hints
);
195 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::maximized_vertical" , ewmh_client_update_hints
);
196 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::sticky" , ewmh_client_update_hints
);
197 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::skip_taskbar" , ewmh_client_update_hints
);
198 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::above" , ewmh_client_update_hints
);
199 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::below" , ewmh_client_update_hints
);
200 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::minimized" , ewmh_client_update_hints
);
201 luaA_class_connect_signal(globalconf
.L
, &client_class
, "property::urgent" , ewmh_client_update_hints
);
204 /** Set the client list in stacking order, bottom to top.
207 ewmh_update_net_client_list_stacking(void)
210 xcb_window_t
*wins
= p_alloca(xcb_window_t
, globalconf
.stack
.len
);
212 foreach(client
, globalconf
.stack
)
213 wins
[n
++] = (*client
)->window
;
215 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
216 globalconf
.screen
->root
,
217 _NET_CLIENT_LIST_STACKING
, XCB_ATOM_WINDOW
, 32, n
, wins
);
221 ewmh_update_net_numbers_of_desktop(void)
223 uint32_t count
= globalconf
.tags
.len
;
225 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
226 globalconf
.screen
->root
,
227 _NET_NUMBER_OF_DESKTOPS
, XCB_ATOM_CARDINAL
, 32, 1, &count
);
231 ewmh_update_net_current_desktop(void)
233 uint32_t idx
= tags_get_first_selected_index();
235 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
236 globalconf
.screen
->root
,
237 _NET_CURRENT_DESKTOP
, XCB_ATOM_CARDINAL
, 32, 1, &idx
);
241 ewmh_update_net_desktop_names(void)
245 buffer_inita(&buf
, BUFSIZ
);
247 foreach(tag
, globalconf
.tags
)
249 buffer_adds(&buf
, tag_get_name(*tag
));
250 buffer_addc(&buf
, '\0');
253 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
254 globalconf
.screen
->root
,
255 _NET_DESKTOP_NAMES
, UTF8_STRING
, 8, buf
.len
, buf
.s
);
260 ewmh_process_state_atom(client_t
*c
, xcb_atom_t state
, int set
)
262 luaA_object_push(globalconf
.L
, c
);
264 if(state
== _NET_WM_STATE_STICKY
)
266 if(set
== _NET_WM_STATE_REMOVE
)
267 client_set_sticky(globalconf
.L
, -1, false);
268 else if(set
== _NET_WM_STATE_ADD
)
269 client_set_sticky(globalconf
.L
, -1, true);
270 else if(set
== _NET_WM_STATE_TOGGLE
)
271 client_set_sticky(globalconf
.L
, -1, !c
->sticky
);
273 else if(state
== _NET_WM_STATE_SKIP_TASKBAR
)
275 if(set
== _NET_WM_STATE_REMOVE
)
276 client_set_skip_taskbar(globalconf
.L
, -1, false);
277 else if(set
== _NET_WM_STATE_ADD
)
278 client_set_skip_taskbar(globalconf
.L
, -1, true);
279 else if(set
== _NET_WM_STATE_TOGGLE
)
280 client_set_skip_taskbar(globalconf
.L
, -1, !c
->skip_taskbar
);
282 else if(state
== _NET_WM_STATE_FULLSCREEN
)
284 if(set
== _NET_WM_STATE_REMOVE
)
285 client_set_fullscreen(globalconf
.L
, -1, false);
286 else if(set
== _NET_WM_STATE_ADD
)
287 client_set_fullscreen(globalconf
.L
, -1, true);
288 else if(set
== _NET_WM_STATE_TOGGLE
)
289 client_set_fullscreen(globalconf
.L
, -1, !c
->fullscreen
);
291 else if(state
== _NET_WM_STATE_MAXIMIZED_HORZ
)
293 if(set
== _NET_WM_STATE_REMOVE
)
294 client_set_maximized_horizontal(globalconf
.L
, -1, false);
295 else if(set
== _NET_WM_STATE_ADD
)
296 client_set_maximized_horizontal(globalconf
.L
, -1, true);
297 else if(set
== _NET_WM_STATE_TOGGLE
)
298 client_set_maximized_horizontal(globalconf
.L
, -1, !c
->maximized_horizontal
);
300 else if(state
== _NET_WM_STATE_MAXIMIZED_VERT
)
302 if(set
== _NET_WM_STATE_REMOVE
)
303 client_set_maximized_vertical(globalconf
.L
, -1, false);
304 else if(set
== _NET_WM_STATE_ADD
)
305 client_set_maximized_vertical(globalconf
.L
, -1, true);
306 else if(set
== _NET_WM_STATE_TOGGLE
)
307 client_set_maximized_vertical(globalconf
.L
, -1, !c
->maximized_vertical
);
309 else if(state
== _NET_WM_STATE_ABOVE
)
311 if(set
== _NET_WM_STATE_REMOVE
)
312 client_set_above(globalconf
.L
, -1, false);
313 else if(set
== _NET_WM_STATE_ADD
)
314 client_set_above(globalconf
.L
, -1, true);
315 else if(set
== _NET_WM_STATE_TOGGLE
)
316 client_set_above(globalconf
.L
, -1, !c
->above
);
318 else if(state
== _NET_WM_STATE_BELOW
)
320 if(set
== _NET_WM_STATE_REMOVE
)
321 client_set_below(globalconf
.L
, -1, false);
322 else if(set
== _NET_WM_STATE_ADD
)
323 client_set_below(globalconf
.L
, -1, true);
324 else if(set
== _NET_WM_STATE_TOGGLE
)
325 client_set_below(globalconf
.L
, -1, !c
->below
);
327 else if(state
== _NET_WM_STATE_MODAL
)
329 if(set
== _NET_WM_STATE_REMOVE
)
330 client_set_modal(globalconf
.L
, -1, false);
331 else if(set
== _NET_WM_STATE_ADD
)
332 client_set_modal(globalconf
.L
, -1, true);
333 else if(set
== _NET_WM_STATE_TOGGLE
)
334 client_set_modal(globalconf
.L
, -1, !c
->modal
);
336 else if(state
== _NET_WM_STATE_HIDDEN
)
338 if(set
== _NET_WM_STATE_REMOVE
)
339 client_set_minimized(globalconf
.L
, -1, false);
340 else if(set
== _NET_WM_STATE_ADD
)
341 client_set_minimized(globalconf
.L
, -1, true);
342 else if(set
== _NET_WM_STATE_TOGGLE
)
343 client_set_minimized(globalconf
.L
, -1, !c
->minimized
);
345 else if(state
== _NET_WM_STATE_DEMANDS_ATTENTION
)
347 if(set
== _NET_WM_STATE_REMOVE
)
348 client_set_urgent(globalconf
.L
, -1, false);
349 else if(set
== _NET_WM_STATE_ADD
)
350 client_set_urgent(globalconf
.L
, -1, true);
351 else if(set
== _NET_WM_STATE_TOGGLE
)
352 client_set_urgent(globalconf
.L
, -1, !c
->urgent
);
355 lua_pop(globalconf
.L
, 1);
359 ewmh_process_desktop(client_t
*c
, uint32_t desktop
)
362 if(desktop
== 0xffffffff)
364 luaA_object_push(globalconf
.L
, c
);
365 lua_pushnil(globalconf
.L
);
366 luaA_object_emit_signal(globalconf
.L
, -2, "request::tag", 1);
367 /* Pop the client, arguments are already popped */
368 lua_pop(globalconf
.L
, 1);
370 else if (idx
>= 0 && idx
< globalconf
.tags
.len
)
372 luaA_object_push(globalconf
.L
, c
);
373 luaA_object_push(globalconf
.L
, globalconf
.tags
.tab
[idx
]);
374 luaA_object_emit_signal(globalconf
.L
, -2, "request::tag", 1);
375 /* Pop the client, arguments are already popped */
376 lua_pop(globalconf
.L
, 1);
381 ewmh_process_client_message(xcb_client_message_event_t
*ev
)
385 if(ev
->type
== _NET_CURRENT_DESKTOP
)
387 int idx
= ev
->data
.data32
[0];
388 if (idx
>= 0 && idx
< globalconf
.tags
.len
)
390 luaA_object_push(globalconf
.L
, globalconf
.tags
.tab
[idx
]);
391 luaA_object_emit_signal(globalconf
.L
, -1, "request::select", 0);
392 lua_pop(globalconf
.L
, 1);
395 else if(ev
->type
== _NET_CLOSE_WINDOW
)
397 if((c
= client_getbywin(ev
->window
)))
400 else if(ev
->type
== _NET_WM_DESKTOP
)
402 if((c
= client_getbywin(ev
->window
)))
404 ewmh_process_desktop(c
, ev
->data
.data32
[0]);
407 else if(ev
->type
== _NET_WM_STATE
)
409 if((c
= client_getbywin(ev
->window
)))
411 ewmh_process_state_atom(c
, (xcb_atom_t
) ev
->data
.data32
[1], ev
->data
.data32
[0]);
412 if(ev
->data
.data32
[2])
413 ewmh_process_state_atom(c
, (xcb_atom_t
) ev
->data
.data32
[2],
417 else if(ev
->type
== _NET_ACTIVE_WINDOW
)
419 if((c
= client_getbywin(ev
->window
))) {
420 luaA_object_push(globalconf
.L
, c
);
421 lua_pushstring(globalconf
.L
,"ewmh");
422 luaA_object_emit_signal(globalconf
.L
, -2, "request::activate", 1);
423 lua_pop(globalconf
.L
, 1);
430 /** Update the client active desktop.
431 * This is "wrong" since it can be on several tags, but EWMH has a strict view
432 * of desktop system so just take the first tag.
433 * \param c The client.
436 ewmh_client_update_desktop(client_t
*c
)
440 for(i
= 0; i
< globalconf
.tags
.len
; i
++)
441 if(is_client_tagged(c
, globalconf
.tags
.tab
[i
]))
443 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
444 c
->window
, _NET_WM_DESKTOP
, XCB_ATOM_CARDINAL
, 32, 1, &i
);
447 /* It doesn't have any tags, remove the property */
448 xcb_delete_property(globalconf
.connection
, c
->window
, _NET_WM_DESKTOP
);
451 /** Update the client struts.
452 * \param window The window to update the struts for.
453 * \param strut The strut type to update the window with.
456 ewmh_update_strut(xcb_window_t window
, strut_t
*strut
)
460 const uint32_t state
[] =
468 strut
->right_start_y
,
472 strut
->bottom_start_x
,
476 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
477 window
, _NET_WM_STRUT_PARTIAL
, XCB_ATOM_CARDINAL
, 32, countof(state
), state
);
481 /** Update the window type.
482 * \param window The window to update.
483 * \param type The new type to set.
486 ewmh_update_window_type(xcb_window_t window
, uint32_t type
)
488 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
489 window
, _NET_WM_WINDOW_TYPE
, XCB_ATOM_ATOM
, 32, 1, &type
);
493 ewmh_client_check_hints(client_t
*c
)
497 xcb_get_property_cookie_t c0
, c1
, c2
;
498 xcb_get_property_reply_t
*reply
;
500 /* Send the GetProperty requests which will be processed later */
501 c0
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
502 _NET_WM_DESKTOP
, XCB_GET_PROPERTY_TYPE_ANY
, 0, 1);
504 c1
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
505 _NET_WM_STATE
, XCB_ATOM_ATOM
, 0, UINT32_MAX
);
507 c2
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
508 _NET_WM_WINDOW_TYPE
, XCB_ATOM_ATOM
, 0, UINT32_MAX
);
510 reply
= xcb_get_property_reply(globalconf
.connection
, c0
, NULL
);
511 if(reply
&& reply
->value_len
&& (data
= xcb_get_property_value(reply
)))
513 ewmh_process_desktop(c
, *(uint32_t *) data
);
518 reply
= xcb_get_property_reply(globalconf
.connection
, c1
, NULL
);
519 if(reply
&& (data
= xcb_get_property_value(reply
)))
521 state
= (xcb_atom_t
*) data
;
522 for(int i
= 0; i
< xcb_get_property_value_length(reply
) / ssizeof(xcb_atom_t
); i
++)
523 ewmh_process_state_atom(c
, state
[i
], _NET_WM_STATE_ADD
);
528 reply
= xcb_get_property_reply(globalconf
.connection
, c2
, NULL
);
529 if(reply
&& (data
= xcb_get_property_value(reply
)))
531 state
= (xcb_atom_t
*) data
;
532 for(int i
= 0; i
< xcb_get_property_value_length(reply
) / ssizeof(xcb_atom_t
); i
++)
533 if(state
[i
] == _NET_WM_WINDOW_TYPE_DESKTOP
)
534 c
->type
= MAX(c
->type
, WINDOW_TYPE_DESKTOP
);
535 else if(state
[i
] == _NET_WM_WINDOW_TYPE_DIALOG
)
536 c
->type
= MAX(c
->type
, WINDOW_TYPE_DIALOG
);
537 else if(state
[i
] == _NET_WM_WINDOW_TYPE_SPLASH
)
538 c
->type
= MAX(c
->type
, WINDOW_TYPE_SPLASH
);
539 else if(state
[i
] == _NET_WM_WINDOW_TYPE_DOCK
)
540 c
->type
= MAX(c
->type
, WINDOW_TYPE_DOCK
);
541 else if(state
[i
] == _NET_WM_WINDOW_TYPE_MENU
)
542 c
->type
= MAX(c
->type
, WINDOW_TYPE_MENU
);
543 else if(state
[i
] == _NET_WM_WINDOW_TYPE_TOOLBAR
)
544 c
->type
= MAX(c
->type
, WINDOW_TYPE_TOOLBAR
);
545 else if(state
[i
] == _NET_WM_WINDOW_TYPE_UTILITY
)
546 c
->type
= MAX(c
->type
, WINDOW_TYPE_UTILITY
);
552 /** Process the WM strut of a client.
553 * \param c The client.
554 * \param strut_r (Optional) An existing reply.
557 ewmh_process_client_strut(client_t
*c
)
560 xcb_get_property_reply_t
*strut_r
;
562 xcb_get_property_cookie_t strut_q
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
563 _NET_WM_STRUT_PARTIAL
, XCB_ATOM_CARDINAL
, 0, 12);
564 strut_r
= xcb_get_property_reply(globalconf
.connection
, strut_q
, NULL
);
567 && strut_r
->value_len
568 && (data
= xcb_get_property_value(strut_r
)))
570 uint32_t *strut
= data
;
572 if(c
->strut
.left
!= strut
[0]
573 || c
->strut
.right
!= strut
[1]
574 || c
->strut
.top
!= strut
[2]
575 || c
->strut
.bottom
!= strut
[3]
576 || c
->strut
.left_start_y
!= strut
[4]
577 || c
->strut
.left_end_y
!= strut
[5]
578 || c
->strut
.right_start_y
!= strut
[6]
579 || c
->strut
.right_end_y
!= strut
[7]
580 || c
->strut
.top_start_x
!= strut
[8]
581 || c
->strut
.top_end_x
!= strut
[9]
582 || c
->strut
.bottom_start_x
!= strut
[10]
583 || c
->strut
.bottom_end_x
!= strut
[11])
585 c
->strut
.left
= strut
[0];
586 c
->strut
.right
= strut
[1];
587 c
->strut
.top
= strut
[2];
588 c
->strut
.bottom
= strut
[3];
589 c
->strut
.left_start_y
= strut
[4];
590 c
->strut
.left_end_y
= strut
[5];
591 c
->strut
.right_start_y
= strut
[6];
592 c
->strut
.right_end_y
= strut
[7];
593 c
->strut
.top_start_x
= strut
[8];
594 c
->strut
.top_end_x
= strut
[9];
595 c
->strut
.bottom_start_x
= strut
[10];
596 c
->strut
.bottom_end_x
= strut
[11];
598 luaA_object_push(globalconf
.L
, c
);
599 luaA_object_emit_signal(globalconf
.L
, -1, "property::struts", 0);
600 lua_pop(globalconf
.L
, 1);
607 /** Send request to get NET_WM_ICON (EWMH)
608 * \param w The window.
609 * \return The cookie associated with the request.
611 xcb_get_property_cookie_t
612 ewmh_window_icon_get_unchecked(xcb_window_t w
)
614 return xcb_get_property_unchecked(globalconf
.connection
, false, w
,
615 _NET_WM_ICON
, XCB_ATOM_CARDINAL
, 0, UINT32_MAX
);
618 static cairo_surface_t
*
619 ewmh_window_icon_from_reply(xcb_get_property_reply_t
*r
)
624 if(!r
|| r
->type
!= XCB_ATOM_CARDINAL
|| r
->format
!= 32 || r
->length
< 2)
627 data
= (uint32_t *) xcb_get_property_value(r
);
631 /* Check that the property is as long as it should be, handling integer
632 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
633 * fits into an uint64_t and thus this multiplication cannot overflow.
635 len
= data
[0] * (uint64_t) data
[1];
636 if (!data
[0] || !data
[1] || len
> r
->length
- 2)
639 return draw_surface_from_data(data
[0], data
[1], data
+ 2);
643 * \param cookie The cookie.
644 * \return The number of elements on stack.
647 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie
)
649 xcb_get_property_reply_t
*r
= xcb_get_property_reply(globalconf
.connection
, cookie
, NULL
);
650 cairo_surface_t
*surface
= ewmh_window_icon_from_reply(r
);
655 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80