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