circulate forward|backward
Circulate the leaves in the given direction.
- mouse move|resize|focus
- Perform the given mouse action on the window under the pointer.
+ grab_pointer move|resize|focus
+ Begin the specified pointer action.
+
+ track_pointer ROOT_X ROOT_Y
+ Pass the pointer root coordinates for the current pointer action.
+
+ ungrab_pointer
+ End the current pointer action.
toggle_fullscreen
Toggle the fullscreen state of the current window.
gapless_monocle
Whether to remove gaps for tiled windows in monocle mode.
- focus_follows_mouse
- Wether to focus the window under the mouse pointer.
+ 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.
.BI circulate " forward|backward"
Circulate the leaves in the given direction.
.TP
-.BI mouse " move|resize|focus"
-Perform the given mouse action on the window under the pointer.
+.BI grab_pointer " move|resize|focus"
+Begin the specified pointer action.
+.TP
+.BI track_pointer " ROOT_X ROOT_Y"
+Pass the pointer root coordinates for the current pointer action.
+.TP
+.BI ungrab_pointer
+End the current pointer action.
.TP
.BI toggle_fullscreen
Toggle the fullscreen state of the current window.
.I gapless_monocle
Whether to remove gaps for tiled windows in monocle mode.
.TP
-.I focus_follows_mouse
-Wether to focus the window under the mouse pointer.
+.I focus_follows_pointer
+Wether to focus the window under the pointer.
.TP
.I adaptative_raise
Prevent floating windows from being raised when they might cover other floating windows.
ewmh_update_current_desktop();
rule_head = rule_tail = NULL;
frozen_pointer = make_pointer_state();
- update_pointer_position(&pointer_position);
- last_entered = XCB_NONE;
+ under_pointer = XCB_NONE;
split_mode = MODE_AUTOMATIC;
visible = true;
exit_status = 0;
#include "types.h"
-#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_ENTER_WINDOW)
+#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_FFP (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_POINTER_MOTION)
xcb_connection_t *dpy;
int default_screen, screen_width, screen_height;
rule_t *rule_tail;
pointer_state_t *frozen_pointer;
-xcb_point_t pointer_position;
-xcb_window_t last_entered;
+xcb_window_t under_pointer;
int exit_status;
case XCB_PROPERTY_NOTIFY:
property_notify(evt);
break;
- case XCB_ENTER_NOTIFY:
- enter_notify(evt);
- break;
case XCB_MOTION_NOTIFY:
motion_notify(evt);
break;
- case XCB_BUTTON_RELEASE:
- button_release();
- break;
default:
break;
}
}
}
-void enter_notify(xcb_generic_event_t *evt)
-{
- xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt;
-
- PRINTF("enter notify %X %d %d\n", e->event, e->mode, e->detail);
-
- if (!focus_follows_mouse
- || (e->mode != XCB_NOTIFY_MODE_NORMAL && e->detail == XCB_NOTIFY_DETAIL_INFERIOR)
- || (pointer_position.x == e->root_x && pointer_position.y == e->root_y)
- || last_entered == e->event)
- return;
-
- window_location_t loc;
- if (locate_window(e->event, &loc)) {
- select_monitor(loc.monitor);
- focus_node(loc.monitor, loc.desktop, loc.node, true);
- pointer_position = (xcb_point_t) {e->root_x, e->root_y};
- last_entered = e->event;
- }
-}
-
void client_message(xcb_generic_event_t *evt)
{
xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt;
}
}
-void mouse_do(mouse_action_t mac)
+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\n", win);
+
+ window_location_t loc;
+ if (locate_window(win, &loc)) {
+ if (loc.node == mon->desk->focus)
+ return;
+ select_monitor(loc.monitor);
+ select_desktop(loc.desktop);
+ focus_node(loc.monitor, loc.desktop, loc.node, true);
+ }
+}
+
+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) {
+ bool fs = n->client->fullscreen;
+ if (action == XCB_EWMH_WM_STATE_TOGGLE
+ || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
+ || (!fs && action == XCB_EWMH_WM_STATE_ADD)) {
+ toggle_fullscreen(m, n->client);
+ arrange(m, d);
+ }
+ }
+}
+
+void grab_pointer(pointer_action_t pac)
{
- PRINTF("mouse action %u\n", mac);
+ PRINTF("grab pointer %u\n", pac);
xcb_window_t win;
xcb_point_t pos;
window_location_t loc;
if (locate_window(win, &loc)) {
client_t *c = loc.node->client;
- switch (mac) {
- case MOUSE_FOCUS:
+ switch (pac) {
+ case POINTER_FOCUS:
focus_node(loc.monitor, loc.desktop, loc.node, true);
break;
- case MOUSE_MOVE:
- case MOUSE_RESIZE:
+ case POINTER_MOVE:
+ case POINTER_RESIZE:
if (is_tiled(loc.node->client)) {
loc.node->client->floating_rectangle = loc.node->client->tiled_rectangle;
toggle_floating(loc.node);
frozen_pointer->node = loc.node;
frozen_pointer->rectangle = c->floating_rectangle;
frozen_pointer->position = pos;
- frozen_pointer->action = mac;
- if (mac == MOUSE_RESIZE) {
+ frozen_pointer->action = pac;
+ if (pac == POINTER_RESIZE) {
int16_t mid_x, mid_y;
mid_x = c->floating_rectangle.x + (c->floating_rectangle.width / 2);
mid_y = c->floating_rectangle.y + (c->floating_rectangle.height / 2);
frozen_pointer->corner = TOP_LEFT;
}
}
- xcb_grab_pointer(dpy, false, root, XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
break;
}
}
}
-void motion_notify(xcb_generic_event_t *evt)
+void track_pointer(int root_x, int root_y)
{
- xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt;
-
int16_t delta_x, delta_y, x, y, w, h;
uint16_t width, height;
x = y = 0;
w = h = 1;
- /* PRINTF("motion notify %X\n", win); */
-
- delta_x = e->root_x - frozen_pointer->position.x;
- delta_y = e->root_y - frozen_pointer->position.y;
+ delta_x = root_x - frozen_pointer->position.x;
+ delta_y = root_y - frozen_pointer->position.y;
switch (frozen_pointer->action) {
- case MOUSE_MOVE:
+ case POINTER_MOVE:
x = rect.x + delta_x;
y = rect.y + delta_y;
window_move(win, x, y);
break;
- case MOUSE_RESIZE:
+ case POINTER_RESIZE:
switch (frozen_pointer->corner) {
case TOP_LEFT:
x = rect.x + delta_x;
c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
window_draw_border(n, d->focus == n, mon == m);
break;
- case MOUSE_FOCUS:
+ case POINTER_FOCUS:
break;
}
}
-void button_release(void)
+void ungrab_pointer(void)
{
- PUTS("button release");
+ PUTS("ungrab pointer");
- xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME);
update_floating_rectangle(frozen_pointer->node->client);
monitor_t *m = underlying_monitor(frozen_pointer->node->client);
if (m != NULL && m != frozen_pointer->monitor) {
select_monitor(m);
}
}
-
-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) {
- bool fs = n->client->fullscreen;
- if (action == XCB_EWMH_WM_STATE_TOGGLE
- || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
- || (!fs && action == XCB_EWMH_WM_STATE_ADD)) {
- toggle_fullscreen(m, n->client);
- arrange(m, d);
- }
- }
-}
void property_notify(xcb_generic_event_t *);
void mapping_notify(xcb_generic_event_t *);
void enter_notify(xcb_generic_event_t *);
-void mouse_do(mouse_action_t);
void motion_notify(xcb_generic_event_t *);
-void button_release(void);
void handle_state(monitor_t *, desktop_t *, node_t *, xcb_atom_t, unsigned int);
-
+void grab_pointer(pointer_action_t);
+void track_pointer(int, int);
+void ungrab_pointer(void);
#endif
return pxl;
}
-
-void update_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);
- }
-}
__attribute__((noreturn))
void err(char *, ...);
uint32_t get_color(char *);
-void update_pointer_position(xcb_point_t *);
#endif
rotate_tree(mon->desk->root, r);
}
}
- } else if (strcmp(cmd, "mouse") == 0) {
- char *mac = strtok(NULL, TOK_SEP);
- if (mac != NULL) {
- mouse_action_t a;
- if (parse_mouse_action(mac, &a))
- mouse_do(a);
+ } else if (strcmp(cmd, "grab_pointer") == 0) {
+ char *pac = strtok(NULL, TOK_SEP);
+ if (pac != NULL) {
+ pointer_action_t a;
+ if (parse_pointer_action(pac, &a))
+ grab_pointer(a);
}
+ } else if (strcmp(cmd, "track_pointer") == 0) {
+ char *arg1 = strtok(NULL, TOK_SEP);
+ if (arg1 == NULL)
+ return;
+ char *arg2 = strtok(NULL, TOK_SEP);
+ if (arg2 == NULL)
+ return;
+ int root_x, root_y;
+ if (sscanf(arg1, "%i", &root_x) == 1 && sscanf(arg2, "%i", &root_y) == 1)
+ track_pointer(root_x, root_y);
+ return;
+ } else if (strcmp(cmd, "ungrab_pointer") == 0) {
+ ungrab_pointer();
} else if (strcmp(cmd, "layout") == 0) {
char *lyt = strtok(NULL, TOK_SEP);
if (lyt != NULL) {
bool b;
if (parse_bool(value, &b))
gapless_monocle = b;
- } else if (strcmp(name, "focus_follows_mouse") == 0) {
+ } else if (strcmp(name, "focus_follows_pointer") == 0) {
bool b;
- if (parse_bool(value, &b))
- focus_follows_mouse = b;
+ if (parse_bool(value, &b)) {
+ if (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);
+
+ }
+ focus_follows_pointer = b;
+ }
} else if (strcmp(name, "adaptative_raise") == 0) {
bool b;
if (parse_bool(value, &b))
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(borderless_monocle));
else if (strcmp(name, "gapless_monocle") == 0)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(gapless_monocle));
- else if (strcmp(name, "focus_follows_mouse") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_follows_mouse));
+ else if (strcmp(name, "focus_follows_pointer") == 0)
+ snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_follows_pointer));
else if (strcmp(name, "adaptative_raise") == 0)
snprintf(rsp, BUFSIZ, "%s", BOOLSTR(adaptative_raise));
else if (strcmp(name, "wm_name") == 0)
return false;
}
-bool parse_mouse_action(char *s, mouse_action_t *a)
+bool parse_pointer_action(char *s, pointer_action_t *a)
{
if (strcmp(s, "move") == 0) {
- *a = MOUSE_MOVE;
+ *a = POINTER_MOVE;
return true;
} else if (strcmp(s, "focus") == 0) {
- *a = MOUSE_FOCUS;
+ *a = POINTER_FOCUS;
return true;
} else if (strcmp(s, "resize") == 0) {
- *a = MOUSE_RESIZE;
+ *a = POINTER_RESIZE;
return true;
}
return false;
bool parse_skip_desktop(char *, skip_desktop_t *);
bool parse_rotate(char *, rotate_t *);
bool parse_fence_move(char *, fence_move_t *);
-bool parse_mouse_action(char *, mouse_action_t *);
+bool parse_pointer_action(char *, pointer_action_t *);
#endif
borderless_monocle = BORDERLESS_MONOCLE;
gapless_monocle = GAPLESS_MONOCLE;
- focus_follows_mouse = FOCUS_FOLLOWS_MOUSE;
+ focus_follows_pointer = FOCUS_FOLLOWS_POINTER;
adaptative_raise = ADAPTATIVE_RAISE;
}
#define WINDOW_GAP 6
#define SPLIT_RATIO 0.5
-#define BORDERLESS_MONOCLE false
-#define GAPLESS_MONOCLE false
-#define FOCUS_FOLLOWS_MOUSE false
-#define ADAPTATIVE_RAISE false
+#define BORDERLESS_MONOCLE false
+#define GAPLESS_MONOCLE false
+#define FOCUS_FOLLOWS_POINTER false
+#define ADAPTATIVE_RAISE false
char focused_border_color[MAXLEN];
char active_border_color[MAXLEN];
bool borderless_monocle;
bool gapless_monocle;
-bool focus_follows_mouse;
+bool focus_follows_pointer;
bool adaptative_raise;
char wm_name[MAXLEN];
rect.y += m->top_padding + wg;
rect.width -= m->left_padding + m->right_padding + wg;
rect.height -= m->top_padding + m->bottom_padding + wg;
- if (focus_follows_mouse)
- update_pointer_position(&pointer_position);
apply_layout(m, d, d->root, rect, rect);
}
window_draw_border(d->focus, false, true);
window_draw_border(n, true, true);
}
- if (focus_follows_mouse)
- update_pointer_position(&pointer_position);
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
+ if (focus_follows_pointer) {
+ if (under_pointer != XCB_NONE) {
+ uint32_t values[] = {CLIENT_EVENT_MASK_FFP};
+ xcb_change_window_attributes(dpy, under_pointer, XCB_CW_EVENT_MASK, values);
+ }
+ uint32_t values[] = {CLIENT_EVENT_MASK};
+ xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
+ under_pointer = n->client->window;
+ }
}
if (!is_tiled(n->client)) {
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)) {
- 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);
if (n->client->floating) {
n->vacant = true;
} corner_t;
typedef enum {
- MOUSE_MOVE,
- MOUSE_RESIZE,
- MOUSE_FOCUS
-} mouse_action_t;
+ POINTER_MOVE,
+ POINTER_RESIZE,
+ POINTER_FOCUS
+} pointer_action_t;
typedef struct {
xcb_window_t window;
typedef struct {
xcb_point_t position;
- mouse_action_t action;
+ pointer_action_t action;
xcb_rectangle_t rectangle;
monitor_t *monitor;
desktop_t *desktop;
if (takes_focus)
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);
num_clients++;
void toggle_visibility(void)
{
- uint32_t values_off[] = {CLIENT_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW};
- uint32_t values_on[] = {CLIENT_EVENT_MASK};
visible = !visible;
for (monitor_t *m = mon_head; m != NULL; m = m->next)
- for (node_t *n = first_extrema(m->desk->root); n != NULL; n = next_leaf(n)) {
- xcb_window_t win = n->client->window;
- xcb_change_window_attributes(dpy, win, XCB_CW_EVENT_MASK, values_off);
- window_set_visibility(win, visible);
- xcb_change_window_attributes(dpy, win, XCB_CW_EVENT_MASK, values_on);
- }
+ for (node_t *n = first_extrema(m->desk->root); n != NULL; n = next_leaf(n))
+ window_set_visibility(n->client->window, visible);
if (visible)
update_current();
}