1 /* * Copyright (c) 2012-2013 Bastien Dejean
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
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.
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.
35 void handle_event(xcb_generic_event_t *evt)
37 uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
42 case XCB_DESTROY_NOTIFY:
45 case XCB_UNMAP_NOTIFY:
48 case XCB_CLIENT_MESSAGE:
51 case XCB_CONFIGURE_REQUEST:
52 configure_request(evt);
54 case XCB_PROPERTY_NOTIFY:
57 case XCB_ENTER_NOTIFY:
60 case XCB_MOTION_NOTIFY:
70 if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
76 void map_request(xcb_generic_event_t *evt)
78 xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;
80 PRINTF("map request %X\n", e->window);
82 schedule_window(e->window);
85 void configure_request(xcb_generic_event_t *evt)
87 xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
89 PRINTF("configure request %X\n", e->window);
92 bool is_managed = locate_window(e->window, &loc);
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;
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;
109 if (loc.node->client->fullscreen)
110 rect = loc.monitor->rectangle;
112 rect = loc.node->client->tiled_rectangle;
114 evt.response_type = XCB_CONFIGURE_NOTIFY;
117 evt.above_sibling = XCB_NONE;
120 evt.width = rect.width;
121 evt.height = rect.height;
122 evt.border_width = bw;
123 evt.override_redirect = false;
125 xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
129 unsigned short i = 0;
131 if (e->value_mask & XCB_CONFIG_WINDOW_X) {
132 mask |= XCB_CONFIG_WINDOW_X;
135 loc.node->client->floating_rectangle.x = e->x;
138 if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
139 mask |= XCB_CONFIG_WINDOW_Y;
142 loc.node->client->floating_rectangle.y = e->y;
145 if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
146 mask |= XCB_CONFIG_WINDOW_WIDTH;
147 values[i++] = e->width;
149 loc.node->client->floating_rectangle.width = e->width;
152 if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
153 mask |= XCB_CONFIG_WINDOW_HEIGHT;
154 values[i++] = e->height;
156 loc.node->client->floating_rectangle.height = e->height;
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;
164 if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
165 mask |= XCB_CONFIG_WINDOW_SIBLING;
166 values[i++] = e->sibling;
169 if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
170 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
171 values[i++] = e->stack_mode;
174 xcb_configure_window(dpy, e->window, mask, values);
177 translate_client(monitor_from_client(loc.node->client), loc.monitor, loc.node->client);
180 void destroy_notify(xcb_generic_event_t *evt)
182 xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
184 PRINTF("destroy notify %X\n", e->window);
186 unmanage_window(e->window);
189 void unmap_notify(xcb_generic_event_t *evt)
191 xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
193 PRINTF("unmap notify %X\n", e->window);
195 unmanage_window(e->window);
198 void property_notify(xcb_generic_event_t *evt)
200 xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;
201 xcb_icccm_wm_hints_t hints;
203 /* PRINTF("property notify %X\n", e->window); */
205 if (e->atom != XCB_ATOM_WM_HINTS)
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));
214 void client_message(xcb_generic_event_t *evt)
216 xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
218 PRINTF("client message %X %u\n", e->window, e->type);
220 if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
222 if (ewmh_locate_desktop(e->data.data32[0], &loc))
223 focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
228 if (!locate_window(e->window, &loc))
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)
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);
241 focus_node(loc.monitor, loc.desktop, loc.node);
242 } else if (e->type == ewmh->_NET_WM_DESKTOP) {
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);
251 void focus_in(xcb_generic_event_t *evt)
253 xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) evt;
255 /* PRINTF("focus in %X %d %d\n", e->event, e->mode, e->detail); */
257 if (e->mode == XCB_NOTIFY_MODE_GRAB
258 || e->mode == XCB_NOTIFY_MODE_UNGRAB)
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();
270 void expose(xcb_generic_event_t *evt)
272 xcb_expose_event_t *e = (xcb_expose_event_t *) evt;
274 PRINTF("expose %X\n", e->window);
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);
281 void enter_notify(xcb_generic_event_t *evt)
283 xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
284 xcb_window_t win = e->event;
286 PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail);
288 if (e->mode != XCB_NOTIFY_MODE_NORMAL
289 || (mon->desk->focus != NULL && mon->desk->focus->client->window == win))
292 enable_motion_recorder();
295 void motion_notify(xcb_generic_event_t *evt)
297 PUTS("motion notify");
299 xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;
301 int dtime = e->time - last_motion_time;
303 last_motion_time = e->time;
304 last_motion_x = e->event_x;
305 last_motion_y = e->event_y;
309 int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y);
313 disable_motion_recorder();
315 xcb_window_t win = XCB_NONE;
316 xcb_point_t pt = {e->root_x, e->root_y};
317 query_pointer(&win, NULL);
319 bool backup = pointer_follows_monitor;
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);
327 pointer_follows_monitor = backup;
331 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
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);
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);