New arguments for `grab_pointer`: `{move,resize}_tiled`.
New setting: `fence_grip`.
- `circulate forward|backward` — Circulate the leaves in the given direction.
-- `grab_pointer move|resize|focus` — Begin the specified pointer action.
+- `grab_pointer move|resize|focus|move_tiled|resize_tiled` — Begin the specified pointer action.
- `track_pointer ROOT_X ROOT_Y` — Pass the pointer root coordinates for the current pointer action.
- `apply_shadow_property` — Enable shadows for floating windows via the `_COMPTON_SHADOW` property.
+- `fence_grip` — If the distance to the nearest fence is greater than `fence_grip`, the `resize_tiled` action will not be engaged.
+
## Key Features
- Configured and controlled through messages
.BI circulate " forward|backward"
Circulate the leaves in the given direction.
.TP
-.BI grab_pointer " move|resize|focus"
+.BI grab_pointer " move|resize|focus|move_tiled|resize_tiled"
Begin the specified pointer action.
.TP
.BI track_pointer " ROOT_X ROOT_Y"
Enable shadows for floating windows via the
.B _COMPTON_SHADOW
property.
+.TP
+.I fence_grip
+If the distance to the nearest fence is greater than
+.IR fence_grip ,
+the
+.B resize_tiled
+action will not be engaged.
.SH AUTHOR
.EX
Bastien Dejean <baskerville at lavabit.com>
}
window_location_t loc;
- if (locate_window(win, &loc)) {
- client_t *c = loc.node->client;
+ bool found_win = locate_window(win, &loc);
+ if (found_win || pac == ACTION_RESIZE_TILED) {
+ fence_distance_t fd;
+ client_t *c = NULL;
+ frozen_pointer->position = pos;
+ frozen_pointer->action = pac;
+ if (found_win) {
+ c = loc.node->client;
+ frozen_pointer->monitor = loc.monitor;
+ frozen_pointer->desktop = loc.desktop;
+ frozen_pointer->node = loc.node;
+ frozen_pointer->client = c;
+ frozen_pointer->window = c->window;
+ }
switch (pac) {
case ACTION_FOCUS:
focus_node(loc.monitor, loc.desktop, loc.node, true);
break;
case ACTION_MOVE:
case ACTION_RESIZE:
- if (is_tiled(loc.node->client)) {
- loc.node->client->floating_rectangle = loc.node->client->tiled_rectangle;
+ if (is_tiled(c)) {
+ loc.node->client->floating_rectangle = c->tiled_rectangle;
toggle_floating(loc.node);
arrange(loc.monitor, loc.desktop);
- } else if (loc.node->client->fullscreen) {
+ } else if (c->fullscreen) {
frozen_pointer->action = ACTION_NONE;
return;
}
- frozen_pointer->monitor = loc.monitor;
- frozen_pointer->desktop = loc.desktop;
- frozen_pointer->node = loc.node;
frozen_pointer->rectangle = c->floating_rectangle;
- frozen_pointer->position = pos;
- frozen_pointer->action = pac;
if (pac == ACTION_RESIZE) {
int16_t mid_x, mid_y;
mid_x = c->floating_rectangle.x + (c->floating_rectangle.width / 2);
}
}
break;
+ case ACTION_RESIZE_TILED:
+ fd = nearest_fence(pos, mon->desk->root);
+ if (fd.fence != NULL && fd.distance < fence_grip) {
+ frozen_pointer->node = fd.fence;
+ frozen_pointer->action = pac;
+ frozen_pointer->rectangle = fd.fence->rectangle;
+ } else {
+ frozen_pointer->action = ACTION_NONE;
+ }
+ break;
+ case ACTION_MOVE_TILED:
+ if (!is_tiled(c))
+ frozen_pointer->action = ACTION_NONE;
+ break;
case ACTION_NONE:
break;
}
monitor_t *m = frozen_pointer->monitor;
desktop_t *d = frozen_pointer->desktop;
node_t *n = frozen_pointer->node;
- client_t *c = n->client;
+ client_t *c = frozen_pointer->client;
+ xcb_window_t win = frozen_pointer->window;
xcb_rectangle_t rect = frozen_pointer->rectangle;
- xcb_window_t win = c->window;
x = y = 0;
w = h = 1;
delta_x = root_x - frozen_pointer->position.x;
delta_y = root_y - frozen_pointer->position.y;
+ double sr;
+ xcb_query_pointer_reply_t *qpr;
+ xcb_window_t pwin;
+ window_location_t loc;
switch (frozen_pointer->action) {
case ACTION_MOVE:
c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
window_draw_border(n, d->focus == n, mon == m);
break;
+ case ACTION_RESIZE_TILED:
+ if (n->split_type == TYPE_VERTICAL)
+ sr = (double) (root_x - rect.x + window_gap / 2) / rect.width;
+ else
+ sr = (double) (root_y - rect.y + window_gap / 2) / rect.height;
+ sr = MAX(0, sr);
+ sr = MIN(1, sr);
+ n->split_ratio = sr;
+ arrange(mon, mon->desk);
+ break;
+ case ACTION_MOVE_TILED:
+ qpr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, root), NULL);
+ if (qpr != NULL) {
+ pwin = qpr->child;
+ free(qpr);
+ if (locate_window(pwin, &loc) && loc.monitor == m && loc.desktop == d && is_tiled(loc.node->client)) {
+ swap_nodes(n, loc.node);
+ arrange(m, d);
+ }
+ }
+ break;
case ACTION_FOCUS:
case ACTION_NONE:
break;
if (frozen_pointer->action == ACTION_NONE)
return;
- update_floating_rectangle(frozen_pointer->node->client);
- monitor_t *m = underlying_monitor(frozen_pointer->node->client);
+ if (is_floating(frozen_pointer->client))
+ update_floating_rectangle(frozen_pointer->client);
+ monitor_t *m = underlying_monitor(frozen_pointer->client);
if (m != NULL && m != frozen_pointer->monitor) {
transfer_node(frozen_pointer->monitor, frozen_pointer->desktop, m, m->desk, frozen_pointer->node);
select_monitor(m);
#define LENGTH(x) (sizeof(x) / sizeof(*x))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define ABS(A) ((A) < 0 ? -(A) : (A))
#define BOOLSTR(A) ((A) ? "true" : "false")
#define XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT
} else if (strcmp(name, "outer_border_width") == 0) {
sscanf(value, "%u", &outer_border_width);
border_width = inner_border_width + main_border_width + outer_border_width;
+ } else if (strcmp(name, "fence_grip") == 0) {
+ sscanf(value, "%u", &fence_grip);
} else if (strcmp(name, "window_gap") == 0) {
sscanf(value, "%i", &window_gap);
} else if (strcmp(name, "left_padding") == 0) {
snprintf(rsp, BUFSIZ, "%u", outer_border_width);
else if (strcmp(name, "border_width") == 0)
snprintf(rsp, BUFSIZ, "%u", border_width);
+ else if (strcmp(name, "fence_grip") == 0)
+ snprintf(rsp, BUFSIZ, "%u", fence_grip);
else if (strcmp(name, "window_gap") == 0)
snprintf(rsp, BUFSIZ, "%i", window_gap);
else if (strcmp(name, "left_padding") == 0)
if (strcmp(s, "move") == 0) {
*a = ACTION_MOVE;
return true;
+ } else if (strcmp(s, "resize") == 0) {
+ *a = ACTION_RESIZE;
+ return true;
} else if (strcmp(s, "focus") == 0) {
*a = ACTION_FOCUS;
return true;
- } else if (strcmp(s, "resize") == 0) {
- *a = ACTION_RESIZE;
+ } else if (strcmp(s, "move_tiled") == 0) {
+ *a = ACTION_MOVE_TILED;
+ return true;
+ } else if (strcmp(s, "resize_tiled") == 0) {
+ *a = ACTION_RESIZE_TILED;
return true;
}
return false;
border_width = inner_border_width + main_border_width + outer_border_width;
window_gap = WINDOW_GAP;
+ fence_grip = FENCE_GRIP;
borderless_monocle = BORDERLESS_MONOCLE;
gapless_monocle = GAPLESS_MONOCLE;
#define WINDOW_GAP 6
#define SPLIT_RATIO 0.5
+#define FENCE_GRIP 20
#define BORDERLESS_MONOCLE false
#define GAPLESS_MONOCLE false
unsigned int border_width;
int window_gap;
+unsigned int fence_grip;
bool borderless_monocle;
bool gapless_monocle;
change_split_ratio(fence, CHANGE_DECREASE);
}
+unsigned int distance_to_fence(xcb_point_t pt, node_t *fence)
+{
+ xcb_rectangle_t rect = fence->rectangle;
+ if (fence->split_type == TYPE_VERTICAL) {
+ int fx = rect.x + fence->split_ratio * rect.width - window_gap / 2;
+ return ABS(pt.x - fx);
+ } else {
+ int fy = rect.y + fence->split_ratio * rect.height - window_gap / 2;
+ return ABS(pt.y - fy);
+ }
+}
+
+fence_distance_t nearest_fence(xcb_point_t pt, node_t *tree)
+{
+ fence_distance_t fd;
+ if (tree == NULL || is_leaf(tree)) {
+ fd.fence = NULL;
+ } else {
+ fd.fence = tree;
+ fd.distance = distance_to_fence(pt, tree);
+ fence_distance_t first_fd = nearest_fence(pt, tree->first_child);
+ fence_distance_t second_fd = nearest_fence(pt, tree->second_child);
+ if (first_fd.fence != NULL && fd.distance > first_fd.distance) {
+ fd.fence = first_fd.fence;
+ fd.distance = first_fd.distance;
+ }
+ if (second_fd.fence != NULL && fd.distance > second_fd.distance) {
+ fd.fence = second_fd.fence;
+ fd.distance = second_fd.distance;
+ }
+ }
+ return fd;
+}
+
void rotate_tree(node_t *n, rotate_t rot)
{
if (n == NULL || is_leaf(n))
node_t *find_fence(node_t *, direction_t);
node_t *find_neighbor(node_t *, direction_t);
void move_fence(node_t *, direction_t, fence_move_t);
+unsigned int distance_to_fence(xcb_point_t, node_t *);
+fence_distance_t nearest_fence(xcb_point_t, node_t *);
void rotate_tree(node_t *, rotate_t);
void arrange(monitor_t *, desktop_t *);
void apply_layout(monitor_t *, desktop_t *, node_t *, xcb_rectangle_t, xcb_rectangle_t);
pointer_state_t *make_pointer_state(void)
{
pointer_state_t *p = malloc(sizeof(pointer_state_t));
+ p->monitor = NULL;
+ p->desktop = NULL;
+ p->node = NULL;
+ p->client = NULL;
+ p->window = XCB_NONE;
return p;
}
} corner_t;
typedef enum {
+ ACTION_NONE,
ACTION_MOVE,
ACTION_RESIZE,
ACTION_FOCUS,
- ACTION_NONE
+ ACTION_MOVE_TILED,
+ ACTION_RESIZE_TILED
} pointer_action_t;
typedef struct {
monitor_t *monitor;
desktop_t *desktop;
node_t *node;
+ client_t *client;
+ xcb_window_t window;
corner_t corner;
} pointer_state_t;
+typedef struct {
+ node_t *fence;
+ unsigned int distance;
+} fence_distance_t;
+
node_t *make_node(void);
monitor_t *make_monitor(xcb_rectangle_t *);
monitor_t *find_monitor(char *);