From 639763c9063f01e189fda0295762c6db6da44343 Mon Sep 17 00:00:00 2001 From: Bastien Dejean Date: Fri, 12 Jun 2015 22:05:22 +0200 Subject: [PATCH] Reinstate the motion recorder for FFP Because many clients (e.g. termite) prevent us (maybe unknowingly) from capturing motion events on their windows, we're forced to create a window for this sole purpose. Grabbing the pointer isn't an option, because it forces us to consider some of the enter notify events we should be ignoring. --- bspwm.c | 8 +++++++- bspwm.h | 2 +- events.c | 32 ++++++++++++++------------------ events.h | 1 - messages.c | 16 ++++++++++++---- monitor.c | 16 ++++++++++++++++ monitor.h | 1 + restore.c | 2 +- tree.c | 10 ++++++++++ types.h | 1 + window.c | 33 ++++++++++++++++++++++++++++++++- window.h | 3 +++ 12 files changed, 98 insertions(+), 27 deletions(-) diff --git a/bspwm.c b/bspwm.c index 2eedb1b..e65f16a 100644 --- a/bspwm.c +++ b/bspwm.c @@ -191,6 +191,7 @@ int main(int argc, char *argv[]) unlink(socket_path); xcb_ewmh_connection_wipe(ewmh); xcb_destroy_window(dpy, meta_window); + xcb_destroy_window(dpy, motion_recorder); free(ewmh); xcb_flush(dpy); xcb_disconnect(dpy); @@ -230,6 +231,11 @@ void setup(void) meta_window = xcb_generate_id(dpy); xcb_create_window(dpy, XCB_COPY_FROM_PARENT, meta_window, root, -1, -1, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_NONE, NULL); + motion_recorder = xcb_generate_id(dpy); + uint32_t values[] = {XCB_EVENT_MASK_POINTER_MOTION}; + xcb_create_window(dpy, XCB_COPY_FROM_PARENT, motion_recorder, root, 0, 0, screen_width, screen_height, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values); + + xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED, ewmh->_NET_SUPPORTING_WM_CHECK, ewmh->_NET_DESKTOP_NAMES, @@ -309,7 +315,7 @@ void setup(void) void register_events(void) { - uint32_t values[] = {ROOT_EVENT_MASK | (focus_follows_pointer ? FFP_MASK : 0)}; + uint32_t values[] = {ROOT_EVENT_MASK}; xcb_generic_error_t *e = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, root, XCB_CW_EVENT_MASK, values)); if (e != NULL) { xcb_disconnect(dpy); diff --git a/bspwm.h b/bspwm.h index 79586b0..dca65bc 100644 --- a/bspwm.h +++ b/bspwm.h @@ -29,7 +29,6 @@ #define ROOT_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY) #define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE) -#define FFP_MASK (XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW) xcb_connection_t *dpy; int default_screen, screen_width, screen_height; @@ -61,6 +60,7 @@ pending_rule_t *pending_rule_tail; pointer_state_t *frozen_pointer; xcb_window_t meta_window; +xcb_window_t motion_recorder; xcb_atom_t WM_TAKE_FOCUS; xcb_atom_t WM_DELETE_WINDOW; xcb_atom_t _BSPWM_FLOATING_WINDOW; diff --git a/events.c b/events.c index 9058cd1..f53a380 100644 --- a/events.c +++ b/events.c @@ -57,9 +57,6 @@ void handle_event(xcb_generic_event_t *evt) case XCB_ENTER_NOTIFY: enter_notify(evt); break; - case XCB_LEAVE_NOTIFY: - leave_notify(evt); - break; case XCB_MOTION_NOTIFY: motion_notify(evt); break; @@ -327,29 +324,24 @@ void enter_notify(xcb_generic_event_t *evt) return; } - xcb_grab_pointer(dpy, 1, win, XCB_EVENT_MASK_POINTER_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME); -} + xcb_get_window_attributes_reply_t *wa = xcb_get_window_attributes_reply(dpy, xcb_get_window_attributes(dpy, motion_recorder), NULL); -void leave_notify(xcb_generic_event_t *evt) -{ - xcb_leave_notify_event_t *e = (xcb_leave_notify_event_t *) evt; - xcb_window_t win = e->event; - - PRINTF("leave notify %X %d %d\n", win, e->mode, e->detail); - - if (e->mode != XCB_NOTIFY_MODE_NORMAL) { + if (wa == NULL) { return; } - xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME); + if (wa->map_state == XCB_MAP_STATE_UNMAPPED) { + enable_motion_recorder(); + } else { + disable_motion_recorder(); + } } void motion_notify(xcb_generic_event_t *evt) { xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; - xcb_window_t win = e->event; - PRINTF("motion notify %X %i %i\n", win, e->root_x, e->root_y); + PRINTF("motion notify %X %i %i\n", e->event, e->root_x, e->root_y); int dtime = e->time - last_motion_time; if (dtime > 1000) { @@ -364,6 +356,10 @@ void motion_notify(xcb_generic_event_t *evt) return; } + xcb_window_t win = XCB_NONE; + xcb_point_t pt = {e->root_x, e->root_y}; + query_pointer(&win, NULL); + bool pfm_backup = pointer_follows_monitor; bool pff_backup = pointer_follows_focus; auto_raise = false; @@ -373,10 +369,8 @@ void motion_notify(xcb_generic_event_t *evt) if (locate_window(win, &loc)) { if (loc.node != mon->desk->focus) { focus_node(loc.monitor, loc.desktop, loc.node); - xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME); } } else { - xcb_point_t pt = {e->root_x, e->root_y}; monitor_t *m = monitor_from_point(pt); if (m != NULL && m != mon) { focus_node(m, m->desk, m->desk->focus); @@ -385,6 +379,8 @@ void motion_notify(xcb_generic_event_t *evt) pointer_follows_monitor = pfm_backup; pointer_follows_focus = pff_backup; auto_raise = true; + + disable_motion_recorder(); } void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action) diff --git a/events.h b/events.h index 00af100..06588fc 100644 --- a/events.h +++ b/events.h @@ -41,7 +41,6 @@ void property_notify(xcb_generic_event_t *evt); void client_message(xcb_generic_event_t *evt); void focus_in(xcb_generic_event_t *evt); void enter_notify(xcb_generic_event_t *evt); -void leave_notify(xcb_generic_event_t *evt); void motion_notify(xcb_generic_event_t *evt); void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action); void process_error(xcb_generic_event_t *evt); diff --git a/messages.c b/messages.c index 0043848..3e4aee2 100644 --- a/messages.c +++ b/messages.c @@ -1015,16 +1015,24 @@ int set_setting(coordinates_t loc, char *name, char *value) bool b; if (parse_bool(value, &b) && b != focus_follows_pointer) { focus_follows_pointer = b; - uint32_t root_values[] = {ROOT_EVENT_MASK | (focus_follows_pointer ? FFP_MASK : 0)}; - uint32_t client_values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? FFP_MASK : 0)}; - xcb_change_window_attributes(dpy, root, XCB_CW_EVENT_MASK, root_values); + uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)}; for (monitor_t *m = mon_head; m != NULL; m = m->next) { for (desktop_t *d = m->desk_head; d != NULL; d = d->next) { for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) { - xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, client_values); + xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values); } } } + if (focus_follows_pointer) { + for (monitor_t *m = mon_head; m != NULL; m = m->next) { + window_show(m->root); + } + } else { + for (monitor_t *m = mon_head; m != NULL; m = m->next) { + window_hide(m->root); + } + disable_motion_recorder(); + } return MSG_SUCCESS; } else { return MSG_FAILURE; diff --git a/monitor.c b/monitor.c index 3fcf6c2..a23d2d6 100644 --- a/monitor.c +++ b/monitor.c @@ -46,6 +46,13 @@ monitor_t *make_monitor(xcb_rectangle_t rect) m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0; m->wired = true; m->num_sticky = 0; + uint32_t values[] = {XCB_EVENT_MASK_ENTER_WINDOW}; + m->root = xcb_generate_id(dpy); + xcb_create_window(dpy, XCB_COPY_FROM_PARENT, m->root, root, rect.x, rect.y, rect.width, rect.height, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values); + window_lower(m->root); + if (focus_follows_pointer) { + window_show(m->root); + } return m; } @@ -113,6 +120,12 @@ void translate_client(monitor_t *ms, monitor_t *md, client_t *c) c->floating_rectangle.y = md->rectangle.y + dy_d - top_adjust; } +void update_root(monitor_t *m) +{ + xcb_rectangle_t rect = m->rectangle; + window_move_resize(m->root, rect.x, rect.y, rect.width, rect.height); +} + void focus_monitor(monitor_t *m) { if (mon == m) @@ -173,6 +186,7 @@ void remove_monitor(monitor_t *m) if (mon != NULL && mon->desk != NULL) update_current(); } + xcb_destroy_window(dpy, m->root); free(m); num_monitors--; put_status(SBSC_MASK_REPORT); @@ -343,6 +357,7 @@ bool update_monitors(void) mm = get_monitor_by_id(outputs[i]); if (mm != NULL) { mm->rectangle = rect; + update_root(mm); for (desktop_t *d = mm->desk_head; d != NULL; d = d->next) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) translate_client(mm, mm, n->client); @@ -429,5 +444,6 @@ bool update_monitors(void) swap_monitors(mon_head, pri_mon); free(sres); + update_motion_recorder(); return (num_monitors > 0); } diff --git a/monitor.h b/monitor.h index 82b0e25..bdfedc8 100644 --- a/monitor.h +++ b/monitor.h @@ -32,6 +32,7 @@ monitor_t *find_monitor(char *name); monitor_t *get_monitor_by_id(xcb_randr_output_t id); void embrace_client(monitor_t *m, client_t *c); void translate_client(monitor_t *ms, monitor_t *md, client_t *c); +void update_root(monitor_t *m); void focus_monitor(monitor_t *m); monitor_t *add_monitor(xcb_rectangle_t rect); void remove_monitor(monitor_t *m); diff --git a/restore.c b/restore.c index 8a3ec67..6ae526f 100644 --- a/restore.c +++ b/restore.c @@ -183,7 +183,7 @@ void restore_tree(char *file_path) for (monitor_t *m = mon_head; m != NULL; m = m->next) for (desktop_t *d = m->desk_head; d != NULL; d = d->next) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) { - uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? FFP_MASK : 0)}; + uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)}; xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values); if (n->client->floating) { n->vacant = true; diff --git a/tree.c b/tree.c index 8ed18f6..206dcf1 100644 --- a/tree.c +++ b/tree.c @@ -355,6 +355,16 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n) history_add(m, d, n); set_input_focus(n); + if (focus_follows_pointer) { + xcb_window_t win = XCB_NONE; + query_pointer(&win, NULL); + if (win != n->client->window) { + enable_motion_recorder(); + } else { + disable_motion_recorder(); + } + } + if (pointer_follows_focus) { center_pointer(get_rectangle(n->client)); } diff --git a/types.h b/types.h index 040e4c8..be8e77a 100644 --- a/types.h +++ b/types.h @@ -214,6 +214,7 @@ struct monitor_t { char name[SMALEN]; xcb_randr_output_t id; xcb_rectangle_t rectangle; + xcb_window_t root; bool wired; int top_padding; int right_padding; diff --git a/window.c b/window.c index e30e771..abba3ff 100644 --- a/window.c +++ b/window.c @@ -171,7 +171,7 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd) else stack(n, STACK_ABOVE); - uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? FFP_MASK : 0)}; + uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)}; xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values); if (visible) { @@ -589,6 +589,8 @@ void restrain_floating_size(client_t *c, int *width, int *height) void query_pointer(xcb_window_t *win, xcb_point_t *pt) { + window_lower(motion_recorder); + xcb_query_pointer_reply_t *qpr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, root), NULL); if (qpr != NULL) { @@ -598,6 +600,8 @@ void query_pointer(xcb_window_t *win, xcb_point_t *pt) *pt = (xcb_point_t) {qpr->root_x, qpr->root_y}; free(qpr); } + + window_raise(motion_recorder); } void window_border_width(xcb_window_t win, uint32_t bw) @@ -707,6 +711,31 @@ void toggle_visibility(void) update_input_focus(); } +void enable_motion_recorder(void) +{ + PUTS("motion recorder on"); + window_raise(motion_recorder); + window_show(motion_recorder); +} + +void disable_motion_recorder(void) +{ + PUTS("motion recorder off"); + window_hide(motion_recorder); +} + +void update_motion_recorder(void) +{ + xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, root), NULL); + + if (geo != NULL) { + window_resize(motion_recorder, geo->width, geo->height); + PRINTF("update motion recorder size: %ux%u\n", geo->width, geo->height); + } + + free(geo); +} + void update_input_focus(void) { set_input_focus(mon->desk->focus); @@ -732,7 +761,9 @@ void center_pointer(xcb_rectangle_t r) { int16_t cx = r.x + r.width / 2; int16_t cy = r.y + r.height / 2; + window_lower(motion_recorder); xcb_warp_pointer(dpy, XCB_NONE, root, 0, 0, 0, 0, cx, cy); + window_raise(motion_recorder); } void get_atom(char *name, xcb_atom_t *atom) diff --git a/window.h b/window.h index 329e72b..18699b1 100644 --- a/window.h +++ b/window.h @@ -72,6 +72,9 @@ void window_set_visibility(xcb_window_t win, bool visible); void window_hide(xcb_window_t win); void window_show(xcb_window_t win); void toggle_visibility(void); +void enable_motion_recorder(void); +void disable_motion_recorder(void); +void update_motion_recorder(void); void update_input_focus(void); void set_input_focus(node_t *n); void clear_input_focus(void);