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>
35 #include "common/atoms.h"
36 #include "common/buffer.h"
37 #include "common/xutil.h"
39 #define _NET_WM_STATE_REMOVE 0
40 #define _NET_WM_STATE_ADD 1
41 #define _NET_WM_STATE_TOGGLE 2
43 /** Update the desktop geometry.
44 * \param phys_screen The physical screen id.
47 ewmh_update_desktop_geometry(int phys_screen
)
49 area_t geom
= screen_area_get(&globalconf
.screens
.tab
[phys_screen
], false);
50 uint32_t sizes
[] = { geom
.width
, geom
.height
};
52 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
53 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
54 _NET_DESKTOP_GEOMETRY
, CARDINAL
, 32, countof(sizes
), sizes
);
58 ewmh_init(int phys_screen
)
61 xcb_screen_t
*xscreen
= xutil_screen_get(globalconf
.connection
, phys_screen
);
65 _NET_SUPPORTING_WM_CHECK
,
68 _NET_CLIENT_LIST_STACKING
,
69 _NET_NUMBER_OF_DESKTOPS
,
74 _NET_DESKTOP_GEOMETRY
,
77 _NET_WM_STRUT_PARTIAL
,
79 _NET_WM_VISIBLE_ICON_NAME
,
82 _NET_WM_WINDOW_TYPE_DESKTOP
,
83 _NET_WM_WINDOW_TYPE_DOCK
,
84 _NET_WM_WINDOW_TYPE_TOOLBAR
,
85 _NET_WM_WINDOW_TYPE_MENU
,
86 _NET_WM_WINDOW_TYPE_UTILITY
,
87 _NET_WM_WINDOW_TYPE_SPLASH
,
88 _NET_WM_WINDOW_TYPE_DIALOG
,
89 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU
,
90 _NET_WM_WINDOW_TYPE_POPUP_MENU
,
91 _NET_WM_WINDOW_TYPE_TOOLTIP
,
92 _NET_WM_WINDOW_TYPE_NOTIFICATION
,
93 _NET_WM_WINDOW_TYPE_COMBO
,
94 _NET_WM_WINDOW_TYPE_DND
,
95 _NET_WM_WINDOW_TYPE_NORMAL
,
100 _NET_WM_STATE_SKIP_TASKBAR
,
101 _NET_WM_STATE_FULLSCREEN
,
102 _NET_WM_STATE_MAXIMIZED_HORZ
,
103 _NET_WM_STATE_MAXIMIZED_VERT
,
107 _NET_WM_STATE_HIDDEN
,
108 _NET_WM_STATE_DEMANDS_ATTENTION
112 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
113 xscreen
->root
, _NET_SUPPORTED
, ATOM
, 32,
114 countof(atom
), atom
);
116 /* create our own window */
117 father
= xcb_generate_id(globalconf
.connection
);
118 xcb_create_window(globalconf
.connection
, xscreen
->root_depth
,
119 father
, xscreen
->root
, -1, -1, 1, 1, 0,
120 XCB_COPY_FROM_PARENT
, xscreen
->root_visual
, 0, NULL
);
122 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
123 xscreen
->root
, _NET_SUPPORTING_WM_CHECK
, WINDOW
, 32,
126 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
127 father
, _NET_SUPPORTING_WM_CHECK
, WINDOW
, 32,
130 /* set the window manager name */
131 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
132 father
, _NET_WM_NAME
, UTF8_STRING
, 8, 7, "awesome");
134 /* set the window manager PID */
136 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
137 father
, _NET_WM_PID
, CARDINAL
, 32, 1, &i
);
139 ewmh_update_desktop_geometry(phys_screen
);
143 ewmh_update_net_client_list(int phys_screen
)
145 xcb_window_t
*wins
= p_alloca(xcb_window_t
, globalconf
.clients
.len
);
148 foreach(_c
, globalconf
.clients
)
151 if(c
->phys_screen
== phys_screen
)
152 wins
[n
++] = c
->window
;
155 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
156 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
157 _NET_CLIENT_LIST
, WINDOW
, 32, n
, wins
);
160 /** Set the client list in stacking order, bottom to top.
161 * \param phys_screen The physical screen id.
164 ewmh_update_net_client_list_stacking(int phys_screen
)
167 xcb_window_t
*wins
= p_alloca(xcb_window_t
, globalconf
.stack
.len
);
169 foreach(client
, globalconf
.stack
)
170 if((*client
)->phys_screen
== phys_screen
)
171 wins
[n
++] = (*client
)->window
;
173 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
174 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
175 _NET_CLIENT_LIST_STACKING
, WINDOW
, 32, n
, wins
);
179 ewmh_update_net_numbers_of_desktop(int phys_screen
)
181 uint32_t count
= globalconf
.screens
.tab
[phys_screen
].tags
.len
;
183 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
184 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
185 _NET_NUMBER_OF_DESKTOPS
, CARDINAL
, 32, 1, &count
);
189 ewmh_update_net_current_desktop(int phys_screen
)
191 uint32_t idx
= tags_get_first_selected_index(&globalconf
.screens
.tab
[phys_screen
]);
193 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
194 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
195 _NET_CURRENT_DESKTOP
, CARDINAL
, 32, 1, &idx
);
199 ewmh_update_net_desktop_names(int phys_screen
)
203 buffer_inita(&buf
, BUFSIZ
);
205 foreach(tag
, globalconf
.screens
.tab
[phys_screen
].tags
)
207 buffer_adds(&buf
, tag_get_name(*tag
));
208 buffer_addc(&buf
, '\0');
211 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
212 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
213 _NET_DESKTOP_NAMES
, UTF8_STRING
, 8, buf
.len
, buf
.s
);
217 /** Update the work area space for each physical screen and each desktop.
218 * \param phys_screen The physical screen id.
221 ewmh_update_workarea(int phys_screen
)
223 tag_array_t
*tags
= &globalconf
.screens
.tab
[phys_screen
].tags
;
224 uint32_t *area
= p_alloca(uint32_t, tags
->len
* 4);
225 area_t geom
= screen_area_get(&globalconf
.screens
.tab
[phys_screen
], true);
227 for(int i
= 0; i
< tags
->len
; i
++)
229 area
[4 * i
+ 0] = geom
.x
;
230 area
[4 * i
+ 1] = geom
.y
;
231 area
[4 * i
+ 2] = geom
.width
;
232 area
[4 * i
+ 3] = geom
.height
;
235 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
236 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
237 _NET_WORKAREA
, CARDINAL
, 32, tags
->len
* 4, area
);
241 ewmh_update_net_active_window(int phys_screen
)
245 if(globalconf
.screen_focus
->client_focus
246 && globalconf
.screen_focus
->client_focus
->phys_screen
== phys_screen
)
247 win
= globalconf
.screen_focus
->client_focus
->window
;
251 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
252 xutil_screen_get(globalconf
.connection
, phys_screen
)->root
,
253 _NET_ACTIVE_WINDOW
, WINDOW
, 32, 1, &win
);
257 ewmh_process_state_atom(client_t
*c
, xcb_atom_t state
, int set
)
259 luaA_object_push(globalconf
.L
, c
);
261 if(state
== _NET_WM_STATE_STICKY
)
263 if(set
== _NET_WM_STATE_REMOVE
)
264 client_set_sticky(globalconf
.L
, -1, false);
265 else if(set
== _NET_WM_STATE_ADD
)
266 client_set_sticky(globalconf
.L
, -1, true);
267 else if(set
== _NET_WM_STATE_TOGGLE
)
268 client_set_sticky(globalconf
.L
, -1, !c
->sticky
);
270 else if(state
== _NET_WM_STATE_SKIP_TASKBAR
)
272 if(set
== _NET_WM_STATE_REMOVE
)
274 client_set_skip_taskbar(globalconf
.L
, -1, false);
275 ewmh_client_update_hints(c
);
277 else if(set
== _NET_WM_STATE_ADD
)
279 client_set_skip_taskbar(globalconf
.L
, -1, true);
280 ewmh_client_update_hints(c
);
282 else if(set
== _NET_WM_STATE_TOGGLE
)
284 client_set_skip_taskbar(globalconf
.L
, -1, !c
->skip_taskbar
);
285 ewmh_client_update_hints(c
);
288 else if(state
== _NET_WM_STATE_FULLSCREEN
)
290 if(set
== _NET_WM_STATE_REMOVE
)
291 client_set_fullscreen(globalconf
.L
, -1, false);
292 else if(set
== _NET_WM_STATE_ADD
)
293 client_set_fullscreen(globalconf
.L
, -1, true);
294 else if(set
== _NET_WM_STATE_TOGGLE
)
295 client_set_fullscreen(globalconf
.L
, -1, !c
->fullscreen
);
297 else if(state
== _NET_WM_STATE_MAXIMIZED_HORZ
)
299 if(set
== _NET_WM_STATE_REMOVE
)
300 client_set_maximized_horizontal(globalconf
.L
, -1, false);
301 else if(set
== _NET_WM_STATE_ADD
)
302 client_set_maximized_horizontal(globalconf
.L
, -1, true);
303 else if(set
== _NET_WM_STATE_TOGGLE
)
304 client_set_maximized_horizontal(globalconf
.L
, -1, c
->maximized_horizontal
);
306 else if(state
== _NET_WM_STATE_MAXIMIZED_VERT
)
308 if(set
== _NET_WM_STATE_REMOVE
)
309 client_set_maximized_vertical(globalconf
.L
, -1, false);
310 else if(set
== _NET_WM_STATE_ADD
)
311 client_set_maximized_vertical(globalconf
.L
, -1, true);
312 else if(set
== _NET_WM_STATE_TOGGLE
)
313 client_set_maximized_vertical(globalconf
.L
, -1, !c
->maximized_vertical
);
315 else if(state
== _NET_WM_STATE_ABOVE
)
317 if(set
== _NET_WM_STATE_REMOVE
)
318 client_set_above(globalconf
.L
, -1, false);
319 else if(set
== _NET_WM_STATE_ADD
)
320 client_set_above(globalconf
.L
, -1, true);
321 else if(set
== _NET_WM_STATE_TOGGLE
)
322 client_set_above(globalconf
.L
, -1, !c
->above
);
324 else if(state
== _NET_WM_STATE_BELOW
)
326 if(set
== _NET_WM_STATE_REMOVE
)
327 client_set_below(globalconf
.L
, -1, false);
328 else if(set
== _NET_WM_STATE_ADD
)
329 client_set_below(globalconf
.L
, -1, true);
330 else if(set
== _NET_WM_STATE_TOGGLE
)
331 client_set_below(globalconf
.L
, -1, !c
->below
);
333 else if(state
== _NET_WM_STATE_MODAL
)
335 if(set
== _NET_WM_STATE_REMOVE
)
336 client_set_modal(globalconf
.L
, -1, false);
337 else if(set
== _NET_WM_STATE_ADD
)
338 client_set_modal(globalconf
.L
, -1, true);
339 else if(set
== _NET_WM_STATE_TOGGLE
)
340 client_set_modal(globalconf
.L
, -1, !c
->modal
);
342 else if(state
== _NET_WM_STATE_HIDDEN
)
344 if(set
== _NET_WM_STATE_REMOVE
)
345 client_set_minimized(globalconf
.L
, -1, false);
346 else if(set
== _NET_WM_STATE_ADD
)
347 client_set_minimized(globalconf
.L
, -1, true);
348 else if(set
== _NET_WM_STATE_TOGGLE
)
349 client_set_minimized(globalconf
.L
, -1, !c
->minimized
);
351 else if(state
== _NET_WM_STATE_DEMANDS_ATTENTION
)
353 if(set
== _NET_WM_STATE_REMOVE
)
354 client_set_urgent(globalconf
.L
, -1, false);
355 else if(set
== _NET_WM_STATE_ADD
)
356 client_set_urgent(globalconf
.L
, -1, true);
357 else if(set
== _NET_WM_STATE_TOGGLE
)
358 client_set_urgent(globalconf
.L
, -1, !c
->urgent
);
363 ewmh_process_client_message(xcb_client_message_event_t
*ev
)
368 if(ev
->type
== _NET_CURRENT_DESKTOP
)
370 screen
< xcb_setup_roots_length(xcb_get_setup(globalconf
.connection
));
373 if(ev
->window
== xutil_screen_get(globalconf
.connection
, screen
)->root
)
374 tag_view_only_byindex(&globalconf
.screens
.tab
[screen
], ev
->data
.data32
[0]);
376 else if(ev
->type
== _NET_CLOSE_WINDOW
)
378 if((c
= client_getbywin(ev
->window
)))
381 else if(ev
->type
== _NET_WM_DESKTOP
)
383 if((c
= client_getbywin(ev
->window
)))
385 tag_array_t
*tags
= &c
->screen
->tags
;
387 if(ev
->data
.data32
[0] == 0xffffffff)
390 for(int i
= 0; i
< tags
->len
; i
++)
391 if((int)ev
->data
.data32
[0] == i
)
393 luaA_object_push(globalconf
.L
, tags
->tab
[i
]);
397 untag_client(c
, tags
->tab
[i
]);
400 else if(ev
->type
== _NET_WM_STATE
)
402 if((c
= client_getbywin(ev
->window
)))
404 ewmh_process_state_atom(c
, (xcb_atom_t
) ev
->data
.data32
[1], ev
->data
.data32
[0]);
405 if(ev
->data
.data32
[2])
406 ewmh_process_state_atom(c
, (xcb_atom_t
) ev
->data
.data32
[2],
410 else if(ev
->type
== _NET_ACTIVE_WINDOW
)
412 if((c
= client_getbywin(ev
->window
)))
419 /** Update client EWMH hints.
420 * \param c The client.
423 ewmh_client_update_hints(client_t
*c
)
425 xcb_atom_t state
[10]; /* number of defined state atoms */
429 state
[i
++] = _NET_WM_STATE_MODAL
;
431 state
[i
++] = _NET_WM_STATE_FULLSCREEN
;
432 if(c
->maximized_vertical
)
433 state
[i
++] = _NET_WM_STATE_MAXIMIZED_VERT
;
434 if(c
->maximized_horizontal
)
435 state
[i
++] = _NET_WM_STATE_MAXIMIZED_HORZ
;
437 state
[i
++] = _NET_WM_STATE_STICKY
;
439 state
[i
++] = _NET_WM_STATE_SKIP_TASKBAR
;
441 state
[i
++] = _NET_WM_STATE_ABOVE
;
443 state
[i
++] = _NET_WM_STATE_BELOW
;
445 state
[i
++] = _NET_WM_STATE_HIDDEN
;
447 state
[i
++] = _NET_WM_STATE_DEMANDS_ATTENTION
;
449 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
450 c
->window
, _NET_WM_STATE
, ATOM
, 32, i
, state
);
453 /** Update the client active desktop.
454 * This is "wrong" since it can be on several tags, but EWMH has a strict view
455 * of desktop system so just take the first tag.
456 * \param c The client.
459 ewmh_client_update_desktop(client_t
*c
)
462 tag_array_t
*tags
= &c
->screen
->tags
;
464 for(i
= 0; i
< tags
->len
; i
++)
465 if(is_client_tagged(c
, tags
->tab
[i
]))
467 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
468 c
->window
, _NET_WM_DESKTOP
, CARDINAL
, 32, 1, &i
);
473 /** Update the client struts.
474 * \param window The window to update the struts for.
475 * \param strut The strut type to update the window with.
478 ewmh_update_strut(xcb_window_t window
, strut_t
*strut
)
480 const uint32_t state
[] =
488 strut
->right_start_y
,
492 strut
->bottom_start_x
,
496 xcb_change_property(globalconf
.connection
, XCB_PROP_MODE_REPLACE
,
497 window
, _NET_WM_STRUT_PARTIAL
, CARDINAL
, 32, countof(state
), state
);
501 ewmh_client_check_hints(client_t
*c
)
506 xcb_get_property_cookie_t c0
, c1
, c2
;
507 xcb_get_property_reply_t
*reply
;
509 /* Send the GetProperty requests which will be processed later */
510 c0
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
511 _NET_WM_DESKTOP
, XCB_GET_PROPERTY_TYPE_ANY
, 0, 1);
513 c1
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
514 _NET_WM_STATE
, ATOM
, 0, UINT32_MAX
);
516 c2
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
517 _NET_WM_WINDOW_TYPE
, ATOM
, 0, UINT32_MAX
);
519 reply
= xcb_get_property_reply(globalconf
.connection
, c0
, NULL
);
520 if(reply
&& reply
->value_len
&& (data
= xcb_get_property_value(reply
)))
522 tag_array_t
*tags
= &c
->screen
->tags
;
524 desktop
= *(uint32_t *) data
;
528 for(int i
= 0; i
< tags
->len
; i
++)
531 luaA_object_push(globalconf
.L
, tags
->tab
[i
]);
535 untag_client(c
, tags
->tab
[i
]);
540 reply
= xcb_get_property_reply(globalconf
.connection
, c1
, NULL
);
541 if(reply
&& (data
= xcb_get_property_value(reply
)))
543 state
= (xcb_atom_t
*) data
;
544 for(int i
= 0; i
< xcb_get_property_value_length(reply
) / ssizeof(xcb_atom_t
); i
++)
545 ewmh_process_state_atom(c
, state
[i
], _NET_WM_STATE_ADD
);
550 reply
= xcb_get_property_reply(globalconf
.connection
, c2
, NULL
);
551 if(reply
&& (data
= xcb_get_property_value(reply
)))
553 state
= (xcb_atom_t
*) data
;
554 for(int i
= 0; i
< xcb_get_property_value_length(reply
) / ssizeof(xcb_atom_t
); i
++)
555 if(state
[i
] == _NET_WM_WINDOW_TYPE_DESKTOP
)
556 c
->type
= MAX(c
->type
, WINDOW_TYPE_DESKTOP
);
557 else if(state
[i
] == _NET_WM_WINDOW_TYPE_DIALOG
)
558 c
->type
= MAX(c
->type
, WINDOW_TYPE_DIALOG
);
559 else if(state
[i
] == _NET_WM_WINDOW_TYPE_SPLASH
)
560 c
->type
= MAX(c
->type
, WINDOW_TYPE_SPLASH
);
561 else if(state
[i
] == _NET_WM_WINDOW_TYPE_DOCK
)
562 c
->type
= MAX(c
->type
, WINDOW_TYPE_DOCK
);
563 else if(state
[i
] == _NET_WM_WINDOW_TYPE_MENU
)
564 c
->type
= MAX(c
->type
, WINDOW_TYPE_MENU
);
565 else if(state
[i
] == _NET_WM_WINDOW_TYPE_TOOLBAR
)
566 c
->type
= MAX(c
->type
, WINDOW_TYPE_TOOLBAR
);
567 else if(state
[i
] == _NET_WM_WINDOW_TYPE_UTILITY
)
568 c
->type
= MAX(c
->type
, WINDOW_TYPE_UTILITY
);
574 /** Process the WM strut of a client.
575 * \param c The client.
576 * \param strut_r (Optional) An existing reply.
579 ewmh_process_client_strut(client_t
*c
, xcb_get_property_reply_t
*strut_r
)
582 xcb_get_property_reply_t
*mstrut_r
= NULL
;
586 xcb_get_property_cookie_t strut_q
= xcb_get_property_unchecked(globalconf
.connection
, false, c
->window
,
587 _NET_WM_STRUT_PARTIAL
, CARDINAL
, 0, 12);
588 strut_r
= mstrut_r
= xcb_get_property_reply(globalconf
.connection
, strut_q
, NULL
);
592 && strut_r
->value_len
593 && (data
= xcb_get_property_value(strut_r
)))
595 uint32_t *strut
= data
;
597 if(c
->strut
.left
!= strut
[0]
598 || c
->strut
.right
!= strut
[1]
599 || c
->strut
.top
!= strut
[2]
600 || c
->strut
.bottom
!= strut
[3]
601 || c
->strut
.left_start_y
!= strut
[4]
602 || c
->strut
.left_end_y
!= strut
[5]
603 || c
->strut
.right_start_y
!= strut
[6]
604 || c
->strut
.right_end_y
!= strut
[7]
605 || c
->strut
.top_start_x
!= strut
[8]
606 || c
->strut
.top_end_x
!= strut
[9]
607 || c
->strut
.bottom_start_x
!= strut
[10]
608 || c
->strut
.bottom_end_x
!= strut
[11])
610 c
->strut
.left
= strut
[0];
611 c
->strut
.right
= strut
[1];
612 c
->strut
.top
= strut
[2];
613 c
->strut
.bottom
= strut
[3];
614 c
->strut
.left_start_y
= strut
[4];
615 c
->strut
.left_end_y
= strut
[5];
616 c
->strut
.right_start_y
= strut
[6];
617 c
->strut
.right_end_y
= strut
[7];
618 c
->strut
.top_start_x
= strut
[8];
619 c
->strut
.top_end_x
= strut
[9];
620 c
->strut
.bottom_start_x
= strut
[10];
621 c
->strut
.bottom_end_x
= strut
[11];
623 hook_property(c
, "struts");
624 luaA_object_push(globalconf
.L
, c
);
625 luaA_object_emit_signal(globalconf
.L
, -1, "property::struts", 0);
626 lua_pop(globalconf
.L
, 1);
633 /** Send request to get NET_WM_ICON (EWMH)
634 * \param w The window.
635 * \return The cookie associated with the request.
637 xcb_get_property_cookie_t
638 ewmh_window_icon_get_unchecked(xcb_window_t w
)
640 return xcb_get_property_unchecked(globalconf
.connection
, false, w
,
641 _NET_WM_ICON
, CARDINAL
, 0, UINT32_MAX
);
645 ewmh_window_icon_from_reply(xcb_get_property_reply_t
*r
)
650 if(!r
|| r
->type
!= CARDINAL
|| r
->format
!= 32 || r
->length
< 2)
653 data
= (uint32_t *) xcb_get_property_value(r
);
657 /* Check that the property is as long as it should be, handling integer
658 * overflow. <uint32_t> times <another uint32_t casted to uint64_t> always
659 * fits into an uint64_t and thus this multiplication cannot overflow.
661 len
= data
[0] * (uint64_t) data
[1];
662 if (!data
[0] || !data
[1] || len
> r
->length
- 2)
665 return image_new_from_argb32(data
[0], data
[1], data
+ 2);
669 * \param cookie The cookie.
670 * \return The number of elements on stack.
673 ewmh_window_icon_get_reply(xcb_get_property_cookie_t cookie
)
675 xcb_get_property_reply_t
*r
= xcb_get_property_reply(globalconf
.connection
, cookie
, NULL
);
676 int ret
= ewmh_window_icon_from_reply(r
);
681 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80