]> git.lizzy.rs Git - bspwm.git/blob - src/events.c
bspwm: port rounded corners patch to latest version
[bspwm.git] / src / events.c
1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include <stdbool.h>
26 #include "bspwm.h"
27 #include "ewmh.h"
28 #include "monitor.h"
29 #include "query.h"
30 #include "settings.h"
31 #include "subscribe.h"
32 #include "tree.h"
33 #include "window.h"
34 #include "pointer.h"
35 #include "rule.h"
36 #include "events.h"
37
38 uint8_t randr_base;
39
40 void handle_event(xcb_generic_event_t *evt)
41 {
42         uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
43         switch (resp_type) {
44                 case XCB_MAP_REQUEST:
45                         map_request(evt);
46                         break;
47                 case XCB_DESTROY_NOTIFY:
48                         destroy_notify(evt);
49                         break;
50                 case XCB_UNMAP_NOTIFY:
51                         unmap_notify(evt);
52                         break;
53                 case XCB_CLIENT_MESSAGE:
54                         client_message(evt);
55                         break;
56                 case XCB_CONFIGURE_REQUEST:
57                         configure_request(evt);
58                         break;
59                 case XCB_CONFIGURE_NOTIFY:
60                         configure_notify(evt);
61                         break;
62                 case XCB_PROPERTY_NOTIFY:
63                         property_notify(evt);
64                         break;
65                 case XCB_ENTER_NOTIFY:
66                         enter_notify(evt);
67                         break;
68                 case XCB_MOTION_NOTIFY:
69                         motion_notify(evt);
70                         break;
71                 case XCB_BUTTON_PRESS:
72                         button_press(evt);
73                         break;
74                 case XCB_FOCUS_IN:
75                         focus_in(evt);
76                         break;
77                 case XCB_MAPPING_NOTIFY:
78                         mapping_notify(evt);
79                         break;
80                 case 0:
81                         process_error(evt);
82                         break;
83                 default:
84                         if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
85                                 update_monitors();
86                         }
87                         break;
88         }
89 }
90
91 void map_request(xcb_generic_event_t *evt)
92 {
93         xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;
94
95         schedule_window(e->window);
96 }
97
98 void configure_request(xcb_generic_event_t *evt)
99 {
100         xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
101
102         coordinates_t loc;
103         bool is_managed = locate_window(e->window, &loc);
104         client_t *c = (is_managed ? loc.node->client : NULL);
105         uint16_t width, height;
106
107         if (!is_managed) {
108                 uint16_t mask = 0;
109                 uint32_t values[7];
110                 unsigned short i = 0;
111
112                 if (e->value_mask & XCB_CONFIG_WINDOW_X) {
113                         mask |= XCB_CONFIG_WINDOW_X;
114                         values[i++] = e->x;
115                 }
116
117                 if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
118                         mask |= XCB_CONFIG_WINDOW_Y;
119                         values[i++] = e->y;
120                 }
121
122                 if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
123                         mask |= XCB_CONFIG_WINDOW_WIDTH;
124                         values[i++] = e->width;
125                 }
126
127                 if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
128                         mask |= XCB_CONFIG_WINDOW_HEIGHT;
129                         values[i++] = e->height;
130                 }
131
132                 if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
133                         mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
134                         values[i++] = e->border_width;
135                 }
136
137                 if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
138                         mask |= XCB_CONFIG_WINDOW_SIBLING;
139                         values[i++] = e->sibling;
140                 }
141
142                 if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
143                         mask |= XCB_CONFIG_WINDOW_STACK_MODE;
144                         values[i++] = e->stack_mode;
145                 }
146
147                 xcb_configure_window(dpy, e->window, mask, values);
148
149         } else if (IS_FLOATING(c)) {
150                 width = c->floating_rectangle.width;
151                 height = c->floating_rectangle.height;
152
153                 if (e->value_mask & XCB_CONFIG_WINDOW_X) {
154                         c->floating_rectangle.x = e->x;
155                 }
156
157                 if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
158                         c->floating_rectangle.y = e->y;
159                 }
160
161                 if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
162                         width = e->width;
163                 }
164
165                 if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
166                         height = e->height;
167                 }
168
169                 apply_size_hints(c, &width, &height);
170                 c->floating_rectangle.width = width;
171                 c->floating_rectangle.height = height;
172                 xcb_rectangle_t r = c->floating_rectangle;
173
174                 window_move_resize(e->window, r.x, r.y, r.width, r.height);
175
176                 put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc.monitor->id, loc.desktop->id, e->window, r.width, r.height, r.x, r.y);
177
178                 monitor_t *m = monitor_from_client(c);
179                 if (m != loc.monitor) {
180                         transfer_node(loc.monitor, loc.desktop, loc.node, m, m->desk, m->desk->focus, false);
181                 }
182         } else {
183                 if (c->state == STATE_PSEUDO_TILED) {
184                         width = c->floating_rectangle.width;
185                         height = c->floating_rectangle.height;
186                         if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
187                                 width = e->width;
188                         }
189                         if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
190                                 height = e->height;
191                         }
192                         apply_size_hints(c, &width, &height);
193                         if (width != c->floating_rectangle.width || height != c->floating_rectangle.height) {
194                                 c->floating_rectangle.width = width;
195                                 c->floating_rectangle.height = height;
196                                 arrange(loc.monitor, loc.desktop);
197                         }
198                 }
199
200
201                 xcb_configure_notify_event_t evt;
202                 unsigned int bw = c->border_width;
203
204                 xcb_rectangle_t r = IS_FULLSCREEN(c) ? loc.monitor->rectangle : c->tiled_rectangle;
205
206                 evt.response_type = XCB_CONFIGURE_NOTIFY;
207                 evt.event = e->window;
208                 evt.window = e->window;
209                 evt.above_sibling = XCB_NONE;
210                 evt.x = r.x;
211                 evt.y = r.y;
212                 evt.width = r.width;
213                 evt.height = r.height;
214                 evt.border_width = bw;
215                 evt.override_redirect = false;
216
217                 xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
218         }
219 }
220
221 void configure_notify(xcb_generic_event_t *evt)
222 {
223         xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *) evt;
224
225         if (e->window == root) {
226                 screen_width = e->width;
227                 screen_height = e->height;
228         }
229 }
230
231 void destroy_notify(xcb_generic_event_t *evt)
232 {
233         xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
234
235         unmanage_window(e->window);
236 }
237
238 void unmap_notify(xcb_generic_event_t *evt)
239 {
240         xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
241
242         if (e->window == motion_recorder.id) {
243                 /* Unmapping the motion recorder in `query_pointer` will produce
244                  * unwanted enter notify events. We can filter those events because
245                  * their sequence number is the same as the sequence number of the
246                  * related unmap notify event. This is a technique used by i3-wm to
247                  * filter enter notify events. */
248                 motion_recorder.sequence = e->sequence;
249                 return;
250         }
251
252         /* Filter out destroyed windows */
253         if (!window_exists(e->window)) {
254                 return;
255         }
256
257         set_window_state(e->window, XCB_ICCCM_WM_STATE_WITHDRAWN);
258         unmanage_window(e->window);
259 }
260
261 void property_notify(xcb_generic_event_t *evt)
262 {
263         xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;
264
265         if (!ignore_ewmh_struts && e->atom == ewmh->_NET_WM_STRUT_PARTIAL && ewmh_handle_struts(e->window)) {
266                 for (monitor_t *m = mon_head; m != NULL; m = m->next) {
267                         for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
268                                 arrange(m, d);
269                         }
270                 }
271         }
272
273         if (e->atom != XCB_ATOM_WM_HINTS && e->atom != XCB_ATOM_WM_NORMAL_HINTS) {
274                 return;
275         }
276
277         coordinates_t loc;
278         if (!locate_window(e->window, &loc)) {
279                 for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
280                         if (pr->win == e->window) {
281                                 postpone_event(pr, evt);
282                                 break;
283                         }
284                 }
285                 return;
286         }
287
288         if (e->atom == XCB_ATOM_WM_HINTS) {
289                 xcb_icccm_wm_hints_t hints;
290                 if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1 &&
291                     (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY))
292                         set_urgent(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
293         } else if (e->atom == XCB_ATOM_WM_NORMAL_HINTS) {
294                 client_t *c = loc.node->client;
295                 if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, e->window), &c->size_hints, NULL) == 1) {
296                         arrange(loc.monitor, loc.desktop);
297                 }
298         }
299 }
300
301 void client_message(xcb_generic_event_t *evt)
302 {
303         xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
304
305         if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
306                 coordinates_t loc;
307                 if (ewmh_locate_desktop(e->data.data32[0], &loc)) {
308                         focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
309                 }
310                 return;
311         }
312
313         coordinates_t loc;
314         if (!locate_window(e->window, &loc)) {
315                 for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
316                         if (pr->win == e->window) {
317                                 postpone_event(pr, evt);
318                                 break;
319                         }
320                 }
321                 return;
322         }
323
324         if (e->type == ewmh->_NET_WM_STATE) {
325                 handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]);
326                 handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]);
327         } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
328                 if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) ||
329                     loc.node == mon->desk->focus) {
330                         return;
331                 }
332                 focus_node(loc.monitor, loc.desktop, loc.node);
333         } else if (e->type == ewmh->_NET_WM_DESKTOP) {
334                 coordinates_t dloc;
335                 if (ewmh_locate_desktop(e->data.data32[0], &dloc)) {
336                         transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus, false);
337                 }
338         } else if (e->type == ewmh->_NET_CLOSE_WINDOW) {
339                 close_node(loc.node);
340         }
341 }
342
343 void focus_in(xcb_generic_event_t *evt)
344 {
345         xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) evt;
346
347         if (e->mode == XCB_NOTIFY_MODE_GRAB || e->mode == XCB_NOTIFY_MODE_UNGRAB
348             || e->detail == XCB_NOTIFY_DETAIL_POINTER || e->detail == XCB_NOTIFY_DETAIL_POINTER_ROOT
349             || e->detail == XCB_NOTIFY_DETAIL_NONE) {
350                 return;
351         }
352
353         if (mon->desk->focus != NULL && e->event == mon->desk->focus->id) {
354                 return;
355         }
356
357         coordinates_t loc;
358         if (locate_window(e->event, &loc)) {
359                 // prevent input focus stealing
360                 update_input_focus();
361         }
362 }
363
364 void button_press(xcb_generic_event_t *evt)
365 {
366         xcb_button_press_event_t *e = (xcb_button_press_event_t *) evt;
367         bool replay = false;
368         for (unsigned int i = 0; i < LENGTH(BUTTONS); i++) {
369                 if (e->detail != BUTTONS[i]) {
370                         continue;
371                 }
372                 if ((click_to_focus == (int8_t) XCB_BUTTON_INDEX_ANY || click_to_focus == (int8_t) BUTTONS[i]) &&
373                         cleaned_mask(e->state) == XCB_NONE) {
374                         bool pff = pointer_follows_focus;
375                         bool pfm = pointer_follows_monitor;
376                         pointer_follows_focus = false;
377                         pointer_follows_monitor = false;
378                         replay = !grab_pointer(ACTION_FOCUS) || !swallow_first_click;
379                         pointer_follows_focus = pff;
380                         pointer_follows_monitor = pfm;
381                 } else {
382                         grab_pointer(pointer_actions[i]);
383                 }
384         }
385         xcb_allow_events(dpy, replay ? XCB_ALLOW_REPLAY_POINTER : XCB_ALLOW_SYNC_POINTER, e->time);
386         xcb_flush(dpy);
387 }
388
389 void enter_notify(xcb_generic_event_t *evt)
390 {
391         xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
392         xcb_window_t win = e->event;
393
394         if (e->mode != XCB_NOTIFY_MODE_NORMAL || e->detail == XCB_NOTIFY_DETAIL_INFERIOR) {
395                 return;
396         }
397
398         /* Ignore the enter notify events that we generated by unmapping the motion
399          * recorder window in `query_pointer`. */
400         if (motion_recorder.enabled && motion_recorder.sequence == e->sequence) {
401                 return;
402         }
403
404         if (win == mon->root || (mon->desk->focus != NULL &&
405                                  (win == mon->desk->focus->id ||
406                                   (mon->desk->focus->presel != NULL &&
407                                    win == mon->desk->focus->presel->feedback)))) {
408                 return;
409         }
410
411         update_motion_recorder();
412 }
413
414 void motion_notify(xcb_generic_event_t *evt)
415 {
416         xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;
417
418         static uint16_t last_motion_x = 0, last_motion_y = 0;
419         static xcb_timestamp_t last_motion_time = 0;
420
421         int64_t dtime = e->time - last_motion_time;
422
423         /* Ignore unintentional pointer motions. */
424         if (dtime > 1000) {
425                 last_motion_time = e->time;
426                 last_motion_x = e->event_x;
427                 last_motion_y = e->event_y;
428                 return;
429         }
430         int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y);
431         if (mdist < 10) {
432                 return;
433         }
434
435         disable_motion_recorder();
436
437         xcb_window_t win = XCB_NONE;
438         query_pointer(&win, NULL);
439         coordinates_t loc;
440         bool pff = pointer_follows_focus;
441         bool pfm = pointer_follows_monitor;
442         pointer_follows_focus = false;
443         pointer_follows_monitor = false;
444         auto_raise = false;
445
446         if (locate_window(win, &loc)) {
447                 if (loc.monitor->desk == loc.desktop && loc.node != mon->desk->focus) {
448                         focus_node(loc.monitor, loc.desktop, loc.node);
449                 }
450         } else {
451                 xcb_point_t pt = {e->root_x, e->root_y};
452                 monitor_t *m = monitor_from_point(pt);
453                 if (m != NULL && m != mon) {
454                         focus_node(m, m->desk, m->desk->focus);
455                 }
456         }
457
458         pointer_follows_focus = pff;
459         pointer_follows_monitor = pfm;
460         auto_raise = true;
461 }
462
463 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
464 {
465         if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
466                 if (action == XCB_EWMH_WM_STATE_ADD && (ignore_ewmh_fullscreen & STATE_TRANSITION_ENTER) == 0) {
467                         set_state(m, d, n, STATE_FULLSCREEN);
468                 } else if (action == XCB_EWMH_WM_STATE_REMOVE && (ignore_ewmh_fullscreen & STATE_TRANSITION_EXIT) == 0) {
469                         if (n->client->state == STATE_FULLSCREEN) {
470                                 set_state(m, d, n, n->client->last_state);
471                         }
472                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
473                         client_state_t next_state = IS_FULLSCREEN(n->client) ? n->client->last_state : STATE_FULLSCREEN;
474                         if ((next_state == STATE_FULLSCREEN && (ignore_ewmh_fullscreen & STATE_TRANSITION_ENTER) == 0) ||
475                             (next_state != STATE_FULLSCREEN && (ignore_ewmh_fullscreen & STATE_TRANSITION_EXIT) == 0)) {
476                                 set_state(m, d, n, next_state);
477                         }
478                 }
479                 arrange(m, d);
480         } else if (state == ewmh->_NET_WM_STATE_BELOW) {
481                 if (action == XCB_EWMH_WM_STATE_ADD) {
482                         set_layer(m, d, n, LAYER_BELOW);
483                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
484                         if (n->client->layer == LAYER_BELOW) {
485                                 set_layer(m, d, n, n->client->last_layer);
486                         }
487                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
488                         set_layer(m, d, n, n->client->layer == LAYER_BELOW ? n->client->last_layer : LAYER_BELOW);
489                 }
490         } else if (state == ewmh->_NET_WM_STATE_ABOVE) {
491                 if (action == XCB_EWMH_WM_STATE_ADD) {
492                         set_layer(m, d, n, LAYER_ABOVE);
493                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
494                         if (n->client->layer == LAYER_ABOVE) {
495                                 set_layer(m, d, n, n->client->last_layer);
496                         }
497                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
498                         set_layer(m, d, n, n->client->layer == LAYER_ABOVE ? n->client->last_layer : LAYER_ABOVE);
499                 }
500         } else if (state == ewmh->_NET_WM_STATE_HIDDEN) {
501                 if (action == XCB_EWMH_WM_STATE_ADD) {
502                         set_hidden(m, d, n, true);
503                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
504                         set_hidden(m, d, n, false);
505                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
506                         set_hidden(m, d, n, !n->hidden);
507                 }
508         } else if (state == ewmh->_NET_WM_STATE_STICKY) {
509                 if (action == XCB_EWMH_WM_STATE_ADD) {
510                         set_sticky(m, d, n, true);
511                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
512                         set_sticky(m, d, n, false);
513                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
514                         set_sticky(m, d, n, !n->sticky);
515                 }
516         } else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
517                 if (action == XCB_EWMH_WM_STATE_ADD) {
518                         set_urgent(m, d, n, true);
519                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
520                         set_urgent(m, d, n, false);
521                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
522                         set_urgent(m, d, n, !n->client->urgent);
523                 }
524 #define HANDLE_WM_STATE(s)  \
525         } else if (state == ewmh->_NET_WM_STATE_##s) { \
526                 if (action == XCB_EWMH_WM_STATE_ADD) { \
527                         n->client->wm_flags |= WM_FLAG_##s; \
528                 } else if (action == XCB_EWMH_WM_STATE_REMOVE) { \
529                         n->client->wm_flags &= ~WM_FLAG_##s; \
530                 } else if (action == XCB_EWMH_WM_STATE_TOGGLE) { \
531                         n->client->wm_flags ^= WM_FLAG_##s; \
532                 } \
533                 ewmh_wm_state_update(n);
534         HANDLE_WM_STATE(MODAL)
535         HANDLE_WM_STATE(MAXIMIZED_VERT)
536         HANDLE_WM_STATE(MAXIMIZED_HORZ)
537         HANDLE_WM_STATE(SHADED)
538         HANDLE_WM_STATE(SKIP_TASKBAR)
539         HANDLE_WM_STATE(SKIP_PAGER)
540         }
541 #undef HANDLE_WM_STATE
542 }
543
544 void mapping_notify(xcb_generic_event_t *evt)
545 {
546         if (mapping_events_count == 0) {
547                 return;
548         }
549
550         xcb_mapping_notify_event_t *e = (xcb_mapping_notify_event_t *) evt;
551
552         if (e->request == XCB_MAPPING_POINTER) {
553                 return;
554         }
555
556         if (mapping_events_count > 0) {
557                 mapping_events_count--;
558         }
559
560         ungrab_buttons();
561         grab_buttons();
562 }
563
564 void process_error(xcb_generic_event_t *evt)
565 {
566         xcb_request_error_t *e = (xcb_request_error_t *) evt;
567         /* Ignore unavoidable failed requests */
568         if (e->error_code == ERROR_CODE_BAD_WINDOW) {
569                 return;
570         }
571         warn("Failed request: %s, %s: 0x%08X.\n", xcb_event_get_request_label(e->major_opcode), xcb_event_get_error_label(e->error_code), e->bad_value);
572 }