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.
This commit is contained in:
Bastien Dejean 2015-06-12 22:05:22 +02:00
parent dfc03b5e26
commit 639763c906
12 changed files with 98 additions and 27 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

10
tree.c
View file

@ -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));
}

View file

@ -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;

View file

@ -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)

View file

@ -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);