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>
26 #include <xcb/xcb_atom.h>
29 #include "objects/tag.h"
31 #include "objects/client.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.
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 */
52 state
[i
++] = _NET_WM_STATE_MODAL
;
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
;
60 state
[i
++] = _NET_WM_STATE_STICKY
;
62 state
[i
++] = _NET_WM_STATE_SKIP_TASKBAR
;
64 state
[i
++] = _NET_WM_STATE_ABOVE
;
66 state
[i
++] = _NET_WM_STATE_BELOW
;
68 state
[i
++] = _NET_WM_STATE_HIDDEN
;
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
);
78 /** Update the desktop geometry.
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
);
92 ewmh_update_net_active_window(lua_State
*L
)
96 if(globalconf
.focus
.client
)
97 win
= globalconf
.focus
.client
->window
;
101 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
102 globalconf
.screen
->root
,
103 _NET_ACTIVE_WINDOW
, XCB_ATOM_WINDOW
, 32, 1, &win
);
109 ewmh_update_net_client_list(lua_State
*L
)
111 xcb_window_t
*wins
= p_alloca(xcb_window_t
, globalconf
.clients
.len
);
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
);
128 xcb_screen_t
*xscreen
= globalconf
.screen
;
132 _NET_SUPPORTING_WM_CHECK
,
135 _NET_CLIENT_LIST_STACKING
,
136 _NET_NUMBER_OF_DESKTOPS
,
137 _NET_CURRENT_DESKTOP
,
140 _NET_DESKTOP_GEOMETRY
,
143 _NET_WM_STRUT_PARTIAL
,
145 _NET_WM_VISIBLE_ICON_NAME
,
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
,
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
,
173 _NET_WM_STATE_HIDDEN
,
174 _NET_WM_STATE_DEMANDS_ATTENTION
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,
192 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
193 father
, _NET_SUPPORTING_WM_CHECK
, XCB_ATOM_WINDOW
, 32,
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 */
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.
226 ewmh_update_net_client_list_stacking(void)
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
);
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
);
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
);
260 ewmh_update_net_desktop_names(void)
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
);
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
)
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
)))
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)
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
]);
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],
418 else if(ev
->type
== _NET_ACTIVE_WINDOW
)
420 if((c
= client_getbywin(ev
->window
)))
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.
433 ewmh_client_update_desktop(client_t
*c
)
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
);
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.
454 ewmh_update_strut(xcb_window_t window
, strut_t
*strut
)
458 const uint32_t state
[] =
466 strut
->right_start_y
,
470 strut
->bottom_start_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.
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
);
491 ewmh_client_check_hints(client_t
*c
)
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
;
517 else if (desktop
>= 0 && desktop
< tags
->len
)
518 for(int i
= 0; i
< tags
->len
; i
++)
521 luaA_object_push(globalconf
.L
, tags
->tab
[i
]);
525 untag_client(c
, tags
->tab
[i
]);
527 /* Value out of bounds, just give it the first tag */
530 luaA_object_push(globalconf
.L
, tags
->tab
[0]);
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
);
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
);
571 /** Process the WM strut of a client.
572 * \param c The client.
573 * \param strut_r (Optional) An existing reply.
576 ewmh_process_client_strut(client_t
*c
)
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
);
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);
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
)
643 if(!r
|| r
->type
!= XCB_ATOM_CARDINAL
|| r
->format
!= 32 || r
->length
< 2)
646 data
= (uint32_t *) xcb_get_property_value(r
);
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)
658 return draw_surface_from_data(data
[0], data
[1], data
+ 2);
662 * \param cookie The cookie.
663 * \return The number of elements on stack.
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
);
674 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80