]> git.lizzy.rs Git - bspwm.git/blob - events.c
Use default sxhkd config path in DM session
[bspwm.git] / events.c
1 /* * Copyright (c) 2012-2013 Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation and/or
11  * other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 ON
20  * 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 <stdlib.h>
26 #include "bspwm.h"
27 #include "ewmh.h"
28 #include "monitor.h"
29 #include "query.h"
30 #include "settings.h"
31 #include "tree.h"
32 #include "window.h"
33 #include "events.h"
34
35 void handle_event(xcb_generic_event_t *evt)
36 {
37     uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
38     switch (resp_type) {
39         case XCB_MAP_REQUEST:
40             map_request(evt);
41             break;
42         case XCB_DESTROY_NOTIFY:
43             destroy_notify(evt);
44             break;
45         case XCB_UNMAP_NOTIFY:
46             unmap_notify(evt);
47             break;
48         case XCB_CLIENT_MESSAGE:
49             client_message(evt);
50             break;
51         case XCB_CONFIGURE_REQUEST:
52             configure_request(evt);
53             break;
54         case XCB_PROPERTY_NOTIFY:
55             property_notify(evt);
56             break;
57         case XCB_ENTER_NOTIFY:
58             enter_notify(evt);
59             break;
60         case XCB_MOTION_NOTIFY:
61             motion_notify(evt);
62             break;
63         case XCB_FOCUS_IN:
64             focus_in(evt);
65             break;
66         case XCB_EXPOSE:
67             expose(evt);
68             break;
69         default:
70             if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
71                 import_monitors();
72             break;
73     }
74 }
75
76 void map_request(xcb_generic_event_t *evt)
77 {
78     xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;
79
80     PRINTF("map request %X\n", e->window);
81
82     schedule_window(e->window);
83 }
84
85 void configure_request(xcb_generic_event_t *evt)
86 {
87     xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
88
89     PRINTF("configure request %X\n", e->window);
90
91     coordinates_t loc;
92     bool is_managed = locate_window(e->window, &loc);
93
94     if (is_managed && !is_floating(loc.node->client)) {
95         if (e->value_mask & XCB_CONFIG_WINDOW_X)
96             loc.node->client->floating_rectangle.x = e->x;
97         if (e->value_mask & XCB_CONFIG_WINDOW_Y)
98             loc.node->client->floating_rectangle.y = e->y;
99         if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
100             loc.node->client->floating_rectangle.width = e->width;
101         if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
102             loc.node->client->floating_rectangle.height = e->height;
103
104         xcb_configure_notify_event_t evt;
105         xcb_rectangle_t rect;
106         xcb_window_t win = loc.node->client->window;
107         unsigned int bw = loc.node->client->border_width;
108
109         if (loc.node->client->fullscreen)
110             rect = loc.monitor->rectangle;
111         else
112             rect = loc.node->client->tiled_rectangle;
113
114         evt.response_type = XCB_CONFIGURE_NOTIFY;
115         evt.event = win;
116         evt.window = win;
117         evt.above_sibling = XCB_NONE;
118         evt.x = rect.x;
119         evt.y = rect.y;
120         evt.width = rect.width;
121         evt.height = rect.height;
122         evt.border_width = bw;
123         evt.override_redirect = false;
124
125         xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
126     } else {
127         uint16_t mask = 0;
128         uint32_t values[7];
129         unsigned short i = 0;
130
131         if (e->value_mask & XCB_CONFIG_WINDOW_X) {
132             mask |= XCB_CONFIG_WINDOW_X;
133             values[i++] = e->x;
134             if (is_managed)
135                 loc.node->client->floating_rectangle.x = e->x;
136         }
137
138         if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
139             mask |= XCB_CONFIG_WINDOW_Y;
140             values[i++] = e->y;
141             if (is_managed)
142                 loc.node->client->floating_rectangle.y = e->y;
143         }
144
145         if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
146             mask |= XCB_CONFIG_WINDOW_WIDTH;
147             values[i++] = e->width;
148             if (is_managed)
149                 loc.node->client->floating_rectangle.width = e->width;
150         }
151
152         if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
153             mask |= XCB_CONFIG_WINDOW_HEIGHT;
154             values[i++] = e->height;
155             if (is_managed)
156                 loc.node->client->floating_rectangle.height = e->height;
157         }
158
159         if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
160             mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
161             values[i++] = e->border_width;
162         }
163
164         if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
165             mask |= XCB_CONFIG_WINDOW_SIBLING;
166             values[i++] = e->sibling;
167         }
168
169         if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
170             mask |= XCB_CONFIG_WINDOW_STACK_MODE;
171             values[i++] = e->stack_mode;
172         }
173
174         xcb_configure_window(dpy, e->window, mask, values);
175     }
176     if (is_managed)
177         translate_client(monitor_from_client(loc.node->client), loc.monitor, loc.node->client);
178 }
179
180 void destroy_notify(xcb_generic_event_t *evt)
181 {
182     xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
183
184     PRINTF("destroy notify %X\n", e->window);
185
186     unmanage_window(e->window);
187 }
188
189 void unmap_notify(xcb_generic_event_t *evt)
190 {
191     xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
192
193     PRINTF("unmap notify %X\n", e->window);
194
195     unmanage_window(e->window);
196 }
197
198 void property_notify(xcb_generic_event_t *evt)
199 {
200     xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;
201     xcb_icccm_wm_hints_t hints;
202
203     /* PRINTF("property notify %X\n", e->window); */
204
205     if (e->atom != XCB_ATOM_WM_HINTS)
206         return;
207
208     coordinates_t loc;
209     if (locate_window(e->window, &loc)
210             && xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1)
211         set_urgency(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
212 }
213
214 void client_message(xcb_generic_event_t *evt)
215 {
216     xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
217
218     PRINTF("client message %X %u\n", e->window, e->type);
219
220     if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
221         coordinates_t loc;
222         if (ewmh_locate_desktop(e->data.data32[0], &loc))
223             focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
224         return;
225     }
226
227     coordinates_t loc;
228     if (!locate_window(e->window, &loc))
229         return;
230
231     if (e->type == ewmh->_NET_WM_STATE) {
232         handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]);
233         handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]);
234     } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
235         if (ignore_ewmh_focus || loc.node == mon->desk->focus)
236             return;
237         if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) {
238             set_fullscreen(loc.desktop->focus, false);
239             arrange(loc.monitor, loc.desktop);
240         }
241         focus_node(loc.monitor, loc.desktop, loc.node);
242     } else if (e->type == ewmh->_NET_WM_DESKTOP) {
243         coordinates_t dloc;
244         if (ewmh_locate_desktop(e->data.data32[0], &dloc))
245             transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus);
246     } else if (e->type == ewmh->_NET_CLOSE_WINDOW) {
247         window_close(loc.node);
248     }
249 }
250
251 void focus_in(xcb_generic_event_t *evt)
252 {
253     xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) evt;
254
255     /* PRINTF("focus in %X %d %d\n", e->event, e->mode, e->detail); */
256
257     if (e->mode == XCB_NOTIFY_MODE_GRAB
258             || e->mode == XCB_NOTIFY_MODE_UNGRAB)
259         return;
260     /* prevent focus stealing */
261     if ((e->detail == XCB_NOTIFY_DETAIL_ANCESTOR ||
262                 e->detail == XCB_NOTIFY_DETAIL_INFERIOR ||
263                 e->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL ||
264                 e->detail == XCB_NOTIFY_DETAIL_NONLINEAR) &&
265             (mon->desk->focus == NULL
266              || mon->desk->focus->client->window != e->event))
267         update_input_focus();
268 }
269
270 void expose(xcb_generic_event_t *evt)
271 {
272     xcb_expose_event_t *e = (xcb_expose_event_t *) evt;
273
274     PRINTF("expose %X\n", e->window);
275
276     coordinates_t loc;
277     if (locate_window(e->window, &loc) && loc.node->client->frame)
278         draw_frame_background(loc.node, loc.desktop->focus == loc.node, loc.monitor == mon);
279 }
280
281 void enter_notify(xcb_generic_event_t *evt)
282 {
283     xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
284     xcb_window_t win = e->event;
285
286     PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail);
287
288     if (e->mode != XCB_NOTIFY_MODE_NORMAL
289             || (mon->desk->focus != NULL && mon->desk->focus->client->window == win))
290         return;
291
292     enable_motion_recorder();
293 }
294
295 void motion_notify(xcb_generic_event_t *evt)
296 {
297     PUTS("motion notify");
298
299     xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;
300
301     int dtime = e->time - last_motion_time;
302     if (dtime > 1000) {
303         last_motion_time = e->time;
304         last_motion_x = e->event_x;
305         last_motion_y = e->event_y;
306         return;
307     }
308
309     int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y);
310     if (mdist < 10)
311         return;
312
313     disable_motion_recorder();
314
315     xcb_window_t win = XCB_NONE;
316     xcb_point_t pt = {e->root_x, e->root_y};
317     query_pointer(&win, NULL);
318
319     bool backup = pointer_follows_monitor;
320     auto_raise = false;
321     pointer_follows_monitor = false;
322     if (!window_focus(win)) {
323         monitor_t *m = monitor_from_point(pt);
324         if (m != NULL && m != mon)
325             focus_node(m, m->desk, m->desk->focus);
326     }
327     pointer_follows_monitor = backup;
328     auto_raise = true;
329 }
330
331 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
332 {
333     if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
334         if (action == XCB_EWMH_WM_STATE_ADD)
335             set_fullscreen(n, true);
336         else if (action == XCB_EWMH_WM_STATE_REMOVE)
337             set_fullscreen(n, false);
338         else if (action == XCB_EWMH_WM_STATE_TOGGLE)
339             set_fullscreen(n, !n->client->fullscreen);
340         arrange(m, d);
341     } else if (state == ewmh->_NET_WM_STATE_STICKY) {
342         if (action == XCB_EWMH_WM_STATE_ADD)
343             set_sticky(m, d, n, true);
344         else if (action == XCB_EWMH_WM_STATE_REMOVE)
345             set_sticky(m, d, n, false);
346         else if (action == XCB_EWMH_WM_STATE_TOGGLE)
347             set_sticky(m, d, n, !n->client->sticky);
348     } else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
349         if (action == XCB_EWMH_WM_STATE_ADD)
350             set_urgency(m, d, n, true);
351         else if (action == XCB_EWMH_WM_STATE_REMOVE)
352             set_urgency(m, d, n, false);
353         else if (action == XCB_EWMH_WM_STATE_TOGGLE)
354             set_urgency(m, d, n, !n->client->urgent);
355     }
356 }