6 #include <xcb/xcb_event.h>
7 #include <xcb/xcb_icccm.h>
18 void handle_event(xcb_generic_event_t *evt)
20 uint8_t resp_type = XCB_EVENT_RESPONSE_TYPE(evt);
25 case XCB_DESTROY_NOTIFY:
28 case XCB_UNMAP_NOTIFY:
31 case XCB_CLIENT_MESSAGE:
34 case XCB_CONFIGURE_REQUEST:
35 configure_request(evt);
37 case XCB_PROPERTY_NOTIFY:
40 case XCB_ENTER_NOTIFY:
43 case XCB_MOTION_NOTIFY:
47 if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
53 void map_request(xcb_generic_event_t *evt)
55 xcb_map_request_event_t *e = (xcb_map_request_event_t *) evt;
57 PRINTF("map request %X\n", e->window);
59 manage_window(mon, mon->desk, e->window);
62 void configure_request(xcb_generic_event_t *evt)
64 xcb_configure_request_event_t *e = (xcb_configure_request_event_t *) evt;
66 PRINTF("configure request %X\n", e->window);
68 window_location_t loc;
69 bool is_managed = locate_window(e->window, &loc);
71 if (!is_managed || is_floating(loc.node->client)) {
76 if (e->value_mask & XCB_CONFIG_WINDOW_X) {
77 mask |= XCB_CONFIG_WINDOW_X;
80 loc.node->client->floating_rectangle.x = e->x;
83 if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
84 mask |= XCB_CONFIG_WINDOW_Y;
87 loc.node->client->floating_rectangle.y = e->y;
90 if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
91 mask |= XCB_CONFIG_WINDOW_WIDTH;
92 values[i++] = e->width;
94 loc.node->client->floating_rectangle.width = e->width;
97 if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
98 mask |= XCB_CONFIG_WINDOW_HEIGHT;
99 values[i++] = e->height;
101 loc.node->client->floating_rectangle.height = e->height;
104 if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) {
105 mask |= XCB_CONFIG_WINDOW_BORDER_WIDTH;
106 values[i++] = e->border_width;
109 if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
110 mask |= XCB_CONFIG_WINDOW_SIBLING;
111 values[i++] = e->sibling;
114 if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
115 mask |= XCB_CONFIG_WINDOW_STACK_MODE;
116 values[i++] = e->stack_mode;
119 xcb_configure_window(dpy, e->window, mask, values);
121 window_draw_border(loc.node, loc.node == loc.desktop->focus, loc.monitor == mon);
123 xcb_configure_notify_event_t evt;
124 xcb_rectangle_t rect;
126 xcb_window_t win = loc.node->client->window;
128 if (is_tiled(loc.node->client)) {
129 rect = loc.node->client->tiled_rectangle;
132 rect = loc.monitor->rectangle;
136 evt.response_type = XCB_CONFIGURE_NOTIFY;
139 evt.above_sibling = XCB_NONE;
142 evt.width = rect.width;
143 evt.height = rect.height;
144 evt.border_width = bw;
145 evt.override_redirect = false;
147 xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
151 void destroy_notify(xcb_generic_event_t *evt)
153 xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *) evt;
155 PRINTF("destroy notify %X\n", e->window);
157 window_location_t loc;
158 if (locate_window(e->window, &loc)) {
159 remove_node(loc.desktop, loc.node);
160 arrange(loc.monitor, loc.desktop);
164 void unmap_notify(xcb_generic_event_t *evt)
166 xcb_unmap_notify_event_t *e = (xcb_unmap_notify_event_t *) evt;
168 PRINTF("unmap notify %X\n", e->window);
170 window_location_t loc;
171 if (locate_window(e->window, &loc)) {
172 remove_node(loc.desktop, loc.node);
173 arrange(loc.monitor, loc.desktop);
177 void property_notify(xcb_generic_event_t *evt)
179 xcb_property_notify_event_t *e = (xcb_property_notify_event_t *) evt;
180 xcb_icccm_wm_hints_t hints;
182 /* PRINTF("property notify %X\n", e->window); */
184 if (e->atom != XCB_ATOM_WM_HINTS)
187 window_location_t loc;
188 if (locate_window(e->window, &loc)
189 && xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1)
190 set_urgency(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
193 void client_message(xcb_generic_event_t *evt)
195 xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
197 PRINTF("client message %X %u\n", e->window, e->type);
199 if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
200 desktop_location_t loc;
201 if (ewmh_locate_desktop(e->data.data32[0], &loc))
202 focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
206 window_location_t loc;
207 if (!locate_window(e->window, &loc))
210 if (e->type == ewmh->_NET_WM_STATE) {
211 handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]);
212 handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]);
213 } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
214 if (loc.node == mon->desk->focus)
216 if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) {
217 toggle_fullscreen(loc.desktop, loc.desktop->focus);
218 arrange(loc.monitor, loc.desktop);
220 focus_node(loc.monitor, loc.desktop, loc.node);
221 } else if (e->type == ewmh->_NET_WM_DESKTOP) {
222 desktop_location_t dloc;
223 if (ewmh_locate_desktop(e->data.data32[0], &dloc))
224 transfer_node(loc.monitor, loc.desktop, dloc.monitor, dloc.desktop, loc.node);
228 void enter_notify(xcb_generic_event_t *evt)
230 xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
231 xcb_window_t win = e->event;
233 PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail);
235 if (e->mode != XCB_NOTIFY_MODE_NORMAL
236 || (mon->desk->focus != NULL && mon->desk->focus->client->window == win))
239 enable_motion_recorder();
242 void motion_notify(void)
244 PUTS("motion notify");
246 disable_motion_recorder();
248 xcb_window_t win = XCB_NONE;
249 query_pointer(&win, NULL);
250 if (win != XCB_NONE) {
251 bool backup = pointer_follows_monitor;
252 pointer_follows_monitor = false;
254 pointer_follows_monitor = backup;
258 void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
260 if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
261 bool fs = n->client->fullscreen;
262 if (action == XCB_EWMH_WM_STATE_TOGGLE
263 || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
264 || (!fs && action == XCB_EWMH_WM_STATE_ADD)) {
265 toggle_fullscreen(d, n);
268 } else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
269 if (action == XCB_EWMH_WM_STATE_ADD)
270 set_urgency(m, d, n, true);
271 else if (action == XCB_EWMH_WM_STATE_REMOVE)
272 set_urgency(m, d, n, false);
273 else if (action == XCB_EWMH_WM_STATE_TOGGLE)
274 set_urgency(m, d, n, !n->client->urgent);
278 void grab_pointer(pointer_action_t pac)
280 PRINTF("grab pointer %u\n", pac);
282 xcb_window_t win = XCB_NONE;
285 query_pointer(&win, &pos);
290 window_location_t loc;
291 if (locate_window(win, &loc)) {
293 frozen_pointer->position = pos;
294 frozen_pointer->action = pac;
295 c = loc.node->client;
296 frozen_pointer->monitor = loc.monitor;
297 frozen_pointer->desktop = loc.desktop;
298 frozen_pointer->node = loc.node;
299 frozen_pointer->client = c;
300 frozen_pointer->window = c->window;
301 frozen_pointer->horizontal_fence = NULL;
302 frozen_pointer->vertical_fence = NULL;
306 if (loc.node != mon->desk->focus) {
307 bool backup = pointer_follows_monitor;
308 pointer_follows_monitor = false;
309 focus_node(loc.monitor, loc.desktop, loc.node);
310 pointer_follows_monitor = backup;
314 case ACTION_RESIZE_SIDE:
315 case ACTION_RESIZE_CORNER:
317 frozen_pointer->rectangle = c->tiled_rectangle;
318 frozen_pointer->is_tiled = true;
319 } else if (is_floating(c)) {
320 frozen_pointer->rectangle = c->floating_rectangle;
321 frozen_pointer->is_tiled = false;
323 frozen_pointer->action = ACTION_NONE;
326 if (pac == ACTION_RESIZE_SIDE) {
327 float W = frozen_pointer->rectangle.width;
328 float H = frozen_pointer->rectangle.height;
330 float x = pos.x - frozen_pointer->rectangle.x;
331 float y = pos.y - frozen_pointer->rectangle.y;
332 float diag_a = ratio * y;
333 float diag_b = W - diag_a;
336 frozen_pointer->side = SIDE_LEFT;
338 frozen_pointer->side = SIDE_BOTTOM;
341 frozen_pointer->side = SIDE_TOP;
343 frozen_pointer->side = SIDE_RIGHT;
345 } else if (pac == ACTION_RESIZE_CORNER) {
346 int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2);
347 int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2);
350 frozen_pointer->corner = CORNER_BOTTOM_RIGHT;
352 frozen_pointer->corner = CORNER_TOP_RIGHT;
355 frozen_pointer->corner = CORNER_BOTTOM_LEFT;
357 frozen_pointer->corner = CORNER_TOP_LEFT;
360 if (frozen_pointer->is_tiled) {
361 if (pac == ACTION_RESIZE_SIDE) {
362 switch (frozen_pointer->side) {
364 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
367 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
370 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
373 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
376 } else if (pac == ACTION_RESIZE_CORNER) {
377 switch (frozen_pointer->corner) {
378 case CORNER_TOP_LEFT:
379 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
380 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
382 case CORNER_TOP_RIGHT:
383 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
384 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
386 case CORNER_BOTTOM_RIGHT:
387 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
388 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
390 case CORNER_BOTTOM_LEFT:
391 frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
392 frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
396 if (frozen_pointer->horizontal_fence != NULL)
397 frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio;
398 if (frozen_pointer->vertical_fence != NULL)
399 frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio;
406 frozen_pointer->action = ACTION_NONE;
410 void track_pointer(int root_x, int root_y)
412 if (frozen_pointer->action == ACTION_NONE)
415 int16_t delta_x, delta_y, x, y, w, h;
416 uint16_t width, height;
418 pointer_action_t pac = frozen_pointer->action;
419 monitor_t *m = frozen_pointer->monitor;
420 desktop_t *d = frozen_pointer->desktop;
421 node_t *n = frozen_pointer->node;
422 client_t *c = frozen_pointer->client;
423 xcb_window_t win = frozen_pointer->window;
424 xcb_rectangle_t rect = frozen_pointer->rectangle;
425 node_t *vertical_fence = frozen_pointer->vertical_fence;
426 node_t *horizontal_fence = frozen_pointer->horizontal_fence;
431 delta_x = root_x - frozen_pointer->position.x;
432 delta_y = root_y - frozen_pointer->position.y;
436 if (frozen_pointer->is_tiled) {
437 xcb_window_t pwin = XCB_NONE;
438 query_pointer(&pwin, NULL);
441 window_location_t loc;
442 bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
443 if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) {
444 swap_nodes(n, loc.node, true);
447 if (is_managed && loc.monitor == m) {
449 } else if (!is_managed) {
450 xcb_point_t pt = (xcb_point_t) {root_x, root_y};
451 monitor_t *pmon = monitor_from_point(pt);
452 if (pmon == NULL || pmon == m) {
456 loc.desktop = pmon->desk;
459 transfer_node(m, d, loc.monitor, loc.desktop, n);
460 frozen_pointer->monitor = loc.monitor;
461 frozen_pointer->desktop = loc.desktop;
464 x = rect.x + delta_x;
465 y = rect.y + delta_y;
466 window_move(win, x, y);
469 case ACTION_RESIZE_SIDE:
470 case ACTION_RESIZE_CORNER:
471 if (frozen_pointer->is_tiled) {
472 if (vertical_fence != NULL) {
473 double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width;
476 vertical_fence->split_ratio = sr;
478 if (horizontal_fence != NULL) {
479 double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height;
482 horizontal_fence->split_ratio = sr;
484 arrange(mon, mon->desk);
486 if (pac == ACTION_RESIZE_SIDE) {
487 switch (frozen_pointer->side) {
490 y = rect.y + delta_y;
492 h = rect.height - delta_y;
497 w = rect.width + delta_x;
504 h = rect.height + delta_y;
507 x = rect.x + delta_x;
509 w = rect.width - delta_x;
515 window_move_resize(win, x, y, width, height);
516 c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
517 window_draw_border(n, d->focus == n, mon == m);
518 } else if (pac == ACTION_RESIZE_CORNER) {
519 switch (frozen_pointer->corner) {
520 case CORNER_TOP_LEFT:
521 x = rect.x + delta_x;
522 y = rect.y + delta_y;
523 w = rect.width - delta_x;
524 h = rect.height - delta_y;
526 case CORNER_TOP_RIGHT:
528 y = rect.y + delta_y;
529 w = rect.width + delta_x;
530 h = rect.height - delta_y;
532 case CORNER_BOTTOM_LEFT:
533 x = rect.x + delta_x;
535 w = rect.width - delta_x;
536 h = rect.height + delta_y;
538 case CORNER_BOTTOM_RIGHT:
541 w = rect.width + delta_x;
542 h = rect.height + delta_y;
547 window_move_resize(win, x, y, width, height);
548 c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
549 window_draw_border(n, d->focus == n, mon == m);
559 void ungrab_pointer(void)
561 PUTS("ungrab pointer");
563 if (frozen_pointer->action == ACTION_NONE || frozen_pointer->is_tiled)
566 update_floating_rectangle(frozen_pointer->client);
567 monitor_t *m = underlying_monitor(frozen_pointer->client);
568 if (m != NULL && m != frozen_pointer->monitor)
569 transfer_node(frozen_pointer->monitor, frozen_pointer->desktop, m, m->desk, frozen_pointer->node);