New setting: 'focus_follows_pointer'

This commit is contained in:
Bastien Dejean 2013-03-04 11:25:12 +01:00
parent 0acdab744c
commit 829bc9b91f
12 changed files with 112 additions and 2 deletions

View file

@ -217,6 +217,8 @@ Colors are either [X color names](http://en.wikipedia.org/wiki/X11_color_names)
- `gapless_monocle` — Whether to remove gaps for tiled windows in monocle mode. - `gapless_monocle` — Whether to remove gaps for tiled windows in monocle mode.
- `focus_follows_pointer` — Wether to focus the window under the pointer.
- `adaptative_raise` — Prevent floating windows from being raised when they might cover other floating windows. - `adaptative_raise` — Prevent floating windows from being raised when they might cover other floating windows.
- `apply_shadow_property` — Enable shadows for floating windows via the `_COMPTON_SHADOW` property. - `apply_shadow_property` — Enable shadows for floating windows via the `_COMPTON_SHADOW` property.

View file

@ -329,6 +329,9 @@ Whether to remove borders for tiled windows in monocle mode.
.I gapless_monocle .I gapless_monocle
Whether to remove gaps for tiled windows in monocle mode. Whether to remove gaps for tiled windows in monocle mode.
.TP .TP
.I focus_follows_pointer
Wether to focus the window under the pointer.
.TP
.I adaptative_raise .I adaptative_raise
Prevent floating windows from being raised when they might cover other floating windows. Prevent floating windows from being raised when they might cover other floating windows.
.TP .TP

View file

@ -62,6 +62,11 @@ void setup(void)
screen_height = screen->height_in_pixels; screen_height = screen->height_in_pixels;
root_depth = screen->root_depth; root_depth = screen->root_depth;
uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t values[] = {XCB_EVENT_MASK_POINTER_MOTION};
motion_recorder = xcb_generate_id(dpy);
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, mask, values);
xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED, xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED,
ewmh->_NET_DESKTOP_NAMES, ewmh->_NET_DESKTOP_NAMES,
ewmh->_NET_NUMBER_OF_DESKTOPS, ewmh->_NET_NUMBER_OF_DESKTOPS,
@ -238,6 +243,7 @@ int main(int argc, char *argv[])
if (status_fifo != NULL) if (status_fifo != NULL)
fclose(status_fifo); fclose(status_fifo);
xcb_ewmh_connection_wipe(ewmh); xcb_ewmh_connection_wipe(ewmh);
xcb_destroy_window(dpy, motion_recorder);
free(ewmh); free(ewmh);
xcb_flush(dpy); xcb_flush(dpy);
xcb_disconnect(dpy); xcb_disconnect(dpy);

View file

@ -5,6 +5,7 @@
#define ROOT_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY) #define ROOT_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY)
#define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE) #define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE)
#define CLIENT_EVENT_MASK_FFP (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW)
xcb_connection_t *dpy; xcb_connection_t *dpy;
int default_screen, screen_width, screen_height; int default_screen, screen_width, screen_height;
@ -30,6 +31,7 @@ rule_t *rule_head;
rule_t *rule_tail; rule_t *rule_tail;
pointer_state_t *frozen_pointer; pointer_state_t *frozen_pointer;
xcb_window_t motion_recorder;
xcb_atom_t compton_shadow; xcb_atom_t compton_shadow;
int exit_status; int exit_status;

View file

@ -35,6 +35,12 @@ void handle_event(xcb_generic_event_t *evt)
case XCB_PROPERTY_NOTIFY: case XCB_PROPERTY_NOTIFY:
property_notify(evt); property_notify(evt);
break; break;
case XCB_ENTER_NOTIFY:
enter_notify(evt);
break;
case XCB_MOTION_NOTIFY:
motion_notify();
break;
default: default:
break; break;
} }
@ -220,6 +226,32 @@ void client_message(xcb_generic_event_t *evt)
} }
} }
void enter_notify(xcb_generic_event_t *evt)
{
xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
xcb_window_t win = e->event;
PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail);
if (e->mode != XCB_NOTIFY_MODE_NORMAL
|| (mon->desk->focus != NULL && mon->desk->focus->client->window == win))
return;
enable_motion_recorder();
}
void motion_notify(void)
{
PUTS("motion notify");
disable_motion_recorder();
xcb_window_t win = XCB_NONE;
get_pointed_window(&win);
if (win != XCB_NONE)
window_focus(win);
}
void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action) void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
{ {
if (state == ewmh->_NET_WM_STATE_FULLSCREEN) { if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {

View file

@ -11,6 +11,8 @@ void unmap_notify(xcb_generic_event_t *);
void configure_request(xcb_generic_event_t *); void configure_request(xcb_generic_event_t *);
void client_message(xcb_generic_event_t *); void client_message(xcb_generic_event_t *);
void property_notify(xcb_generic_event_t *); void property_notify(xcb_generic_event_t *);
void enter_notify(xcb_generic_event_t *);
void motion_notify(void);
void handle_state(monitor_t *, desktop_t *, node_t *, xcb_atom_t, unsigned int); void handle_state(monitor_t *, desktop_t *, node_t *, xcb_atom_t, unsigned int);
void grab_pointer(pointer_action_t); void grab_pointer(pointer_action_t);
void track_pointer(int, int); void track_pointer(int, int);

View file

@ -491,6 +491,20 @@ void set_setting(char *name, char *value, char *rsp)
bool b; bool b;
if (parse_bool(value, &b)) if (parse_bool(value, &b))
gapless_monocle = b; gapless_monocle = b;
} else if (strcmp(name, "focus_follows_pointer") == 0) {
bool b;
if (parse_bool(value, &b) && b != focus_follows_pointer) {
uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK : CLIENT_EVENT_MASK_FFP)};
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))
xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
if (focus_follows_pointer)
disable_motion_recorder();
else
enable_motion_recorder();
focus_follows_pointer = b;
}
} else if (strcmp(name, "adaptative_raise") == 0) { } else if (strcmp(name, "adaptative_raise") == 0) {
bool b; bool b;
if (parse_bool(value, &b)) if (parse_bool(value, &b))
@ -548,6 +562,8 @@ void get_setting(char *name, char* rsp)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(borderless_monocle)); snprintf(rsp, BUFSIZ, "%s", BOOLSTR(borderless_monocle));
else if (strcmp(name, "gapless_monocle") == 0) else if (strcmp(name, "gapless_monocle") == 0)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(gapless_monocle)); snprintf(rsp, BUFSIZ, "%s", BOOLSTR(gapless_monocle));
else if (strcmp(name, "focus_follows_pointer") == 0)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_follows_pointer));
else if (strcmp(name, "adaptative_raise") == 0) else if (strcmp(name, "adaptative_raise") == 0)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(adaptative_raise)); snprintf(rsp, BUFSIZ, "%s", BOOLSTR(adaptative_raise));
else if (strcmp(name, "apply_shadow_property") == 0) else if (strcmp(name, "apply_shadow_property") == 0)

View file

@ -61,6 +61,7 @@ void load_settings(void)
borderless_monocle = BORDERLESS_MONOCLE; borderless_monocle = BORDERLESS_MONOCLE;
gapless_monocle = GAPLESS_MONOCLE; gapless_monocle = GAPLESS_MONOCLE;
focus_follows_pointer = FOCUS_FOLLOWS_POINTER;
adaptative_raise = ADAPTATIVE_RAISE; adaptative_raise = ADAPTATIVE_RAISE;
apply_shadow_property = APPLY_SHADOW_PROPERTY; apply_shadow_property = APPLY_SHADOW_PROPERTY;
} }

View file

@ -22,6 +22,7 @@
#define BORDERLESS_MONOCLE false #define BORDERLESS_MONOCLE false
#define GAPLESS_MONOCLE false #define GAPLESS_MONOCLE false
#define FOCUS_FOLLOWS_POINTER false
#define ADAPTATIVE_RAISE false #define ADAPTATIVE_RAISE false
#define APPLY_SHADOW_PROPERTY false #define APPLY_SHADOW_PROPERTY false
@ -48,6 +49,7 @@ int window_gap;
bool borderless_monocle; bool borderless_monocle;
bool gapless_monocle; bool gapless_monocle;
bool focus_follows_pointer;
bool adaptative_raise; bool adaptative_raise;
bool apply_shadow_property; bool apply_shadow_property;

11
tree.c
View file

@ -386,6 +386,15 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n, bool is_mapped)
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME); xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
} }
if (focus_follows_pointer) {
xcb_window_t win = XCB_NONE;
get_pointed_window(&win);
if (win != n->client->window)
enable_motion_recorder();
else
disable_motion_recorder();
}
if (!is_tiled(n->client)) { if (!is_tiled(n->client)) {
if (!adaptative_raise || !might_cover(d, n)) if (!adaptative_raise || !might_cover(d, n))
window_raise(n->client->window); window_raise(n->client->window);
@ -940,7 +949,7 @@ void restore(char *file_path)
for (monitor_t *m = mon_head; m != NULL; m = m->next) for (monitor_t *m = mon_head; m != NULL; m = m->next)
for (desktop_t *d = m->desk_head; d != NULL; d = d->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)) { for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n)) {
uint32_t values[] = {CLIENT_EVENT_MASK}; uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values); xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
if (n->client->floating) { if (n->client->floating) {
n->vacant = true; n->vacant = true;

View file

@ -154,7 +154,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
if (takes_focus) if (takes_focus)
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME); xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
uint32_t values[] = {CLIENT_EVENT_MASK}; uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values); xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
num_clients++; num_clients++;
@ -411,6 +411,27 @@ void update_floating_rectangle(client_t *c)
} }
} }
void save_pointer_position(xcb_point_t *pos)
{
xcb_query_pointer_reply_t *qpr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, root), NULL);
if (qpr != NULL) {
*pos = (xcb_point_t) {qpr->root_x, qpr->root_y};
free(qpr);
}
}
void get_pointed_window(xcb_window_t *win)
{
window_lower(motion_recorder);
xcb_query_pointer_reply_t *qpr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, root), NULL);
if (qpr != NULL) {
*win = qpr->child;
free(qpr);
}
window_raise(motion_recorder);
}
void window_focus(xcb_window_t win) void window_focus(xcb_window_t win)
{ {
window_location_t loc; window_location_t loc;
@ -490,3 +511,14 @@ void toggle_visibility(void)
if (visible) if (visible)
update_current(); update_current();
} }
void enable_motion_recorder(void)
{
window_raise(motion_recorder);
window_show(motion_recorder);
}
void disable_motion_recorder(void)
{
window_hide(motion_recorder);
}

View file

@ -34,9 +34,12 @@ void window_lower(xcb_window_t);
void window_set_visibility(xcb_window_t, bool); void window_set_visibility(xcb_window_t, bool);
void window_hide(xcb_window_t); void window_hide(xcb_window_t);
void window_show(xcb_window_t); void window_show(xcb_window_t);
void enable_motion_recorder(void);
void disable_motion_recorder(void);
void toggle_visibility(void); void toggle_visibility(void);
uint32_t get_border_color(client_t *, bool, bool); uint32_t get_border_color(client_t *, bool, bool);
void update_floating_rectangle(client_t *); void update_floating_rectangle(client_t *);
void get_pointed_window(xcb_window_t *);
void list_windows(char *); void list_windows(char *);
#endif #endif