Skip to content

Commit ccc5299

Browse files
committed
fix: make tiled and scroller interactive resize work again
1 parent 3e4577d commit ccc5299

2 files changed

Lines changed: 154 additions & 128 deletions

File tree

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# Misc
1515
- Rework the docs to be easier to use
1616
- Improve the README (include video, images, better info)
17-
- Interactive resize appears broken in tiled and scrolling layouts
1817

1918
# Potential
2019
- Per desktop rules (e.g. floating, master_stack)

src/cursor.c

Lines changed: 154 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -172,99 +172,106 @@ static uint32_t get_tiled_resizable_edges(node_t *node) {
172172
return edges;
173173
}
174174

175-
static void update_scene_positions(node_t *n, struct wlr_box rect, desktop_t *d) {
176-
if (!n || !d)
175+
static void apply_leaf_positions(desktop_t *d) {
176+
if (!d || !d->root)
177177
return;
178178

179-
n->pending.rectangle = rect;
180-
n->current.rectangle = rect;
181-
182-
if (is_leaf(n)) {
183-
if (n->client) {
184-
// apply window gap and border width to leaf nodes
185-
struct wlr_box r = rect;
186-
unsigned int bw = effective_border_width(d);
187-
int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE) ? 0 : compute_window_gap(d);
188-
r = apply_bleed(r, bw, wg);
189-
190-
n->client->tiled_rectangle = r;
191-
n->client->committed_tiled_rectangle = r;
192-
193-
struct wlr_scene_tree *st = client_get_scene_tree(n->client);
194-
if (st) {
195-
wlr_scene_node_set_position(&st->node, r.x, r.y);
196-
197-
if (n->client->toplevel)
198-
wlr_xdg_toplevel_set_size(n->client->toplevel->xdg_toplevel, r.width, r.height);
199-
else if (n->client->xwayland_view)
200-
wlr_xwayland_surface_configure(n->client->xwayland_view->xwayland_surface, r.x, r.y, r.width,
201-
r.height);
202-
203-
if (bw != 0) {
204-
const struct wlr_box geo = {
205-
0,
206-
0,
207-
r.width,
208-
r.height
209-
};
210-
update_borders(client_border_tree(n->client), client_border_rects(n->client), geo, bw);
211-
update_border_colors(n->client);
212-
if (n->client->border_radius > 0.0f) {
213-
surface_rounded_t *rounded = client_get_rounded(n->client);
214-
if (rounded) {
215-
int new_fw = r.width + 2 * (int)bw;
216-
int new_fh = r.height + 2 * (int)bw;
217-
if (new_fw > 0 && new_fh > 0 && (rounded->border_shader_buf_w != new_fw ||
218-
rounded->border_shader_buf_h != new_fh)) {
219-
rounded->border_dirty = true;
220-
rounded->corner_mask_dirty = true;
221-
}
222-
}
179+
for (node_t *n = first_extrema(d->root); n; n = next_leaf(n, d->root)) {
180+
if (!n->client)
181+
continue;
182+
183+
struct wlr_box r = n->client->arranged_rectangle;
184+
if (r.width < 1 || r.height < 1)
185+
continue;
186+
187+
struct wlr_scene_tree *st = client_get_scene_tree(n->client);
188+
if (!st)
189+
continue;
190+
191+
wlr_scene_node_set_position(&st->node, r.x, r.y);
192+
193+
if (n->client->toplevel)
194+
wlr_xdg_toplevel_set_size(n->client->toplevel->xdg_toplevel, r.width, r.height);
195+
else if (n->client->xwayland_view)
196+
wlr_xwayland_surface_configure(n->client->xwayland_view->xwayland_surface, r.x, r.y, r.width,
197+
r.height);
198+
199+
unsigned int bw = effective_border_width(d);
200+
if (bw != 0) {
201+
struct wlr_box geo = {0, 0, r.width, r.height};
202+
update_borders(client_border_tree(n->client), client_border_rects(n->client), geo, bw);
203+
update_border_colors(n->client);
204+
if (n->client->border_radius > 0.0f) {
205+
surface_rounded_t *rounded = client_get_rounded(n->client);
206+
if (rounded) {
207+
int new_fw = r.width + 2 * (int)bw;
208+
int new_fh = r.height + 2 * (int)bw;
209+
if (new_fw > 0 && new_fh > 0 && (rounded->border_shader_buf_w != new_fw ||
210+
rounded->border_shader_buf_h != new_fh)) {
211+
rounded->border_dirty = true;
212+
rounded->corner_mask_dirty = true;
223213
}
224214
}
225215
}
226216
}
227-
} else if (n->split_type == TYPE_VERTICAL) {
228-
int split_x = rect.x + (int)(rect.width * n->split_ratio);
229-
struct wlr_box left = {
230-
rect.x,
231-
rect.y,
232-
split_x - rect.x,
233-
rect.height
234-
};
235-
struct wlr_box right = {
236-
split_x,
237-
rect.y,
238-
rect.x + rect.width - split_x,
239-
rect.height
240-
};
241-
update_scene_positions(n->first_child, left, d);
242-
update_scene_positions(n->second_child, right, d);
243-
} else if (n->split_type == TYPE_HORIZONTAL) {
244-
int split_y = rect.y + (int)(rect.height * n->split_ratio);
245-
struct wlr_box top = {
246-
rect.x,
247-
rect.y,
248-
rect.width,
249-
split_y - rect.y
250-
};
251-
struct wlr_box bottom = {
252-
rect.x,
253-
split_y,
254-
rect.width,
255-
rect.y + rect.height - split_y
256-
};
257-
update_scene_positions(n->first_child, top, d);
258-
update_scene_positions(n->second_child, bottom, d);
259217
}
260218
}
261219

220+
static int find_scroller_tile_idx(scroller_column_t *col, client_t *c) {
221+
for (int j = 0; j < col->tile_count; j++)
222+
if (col->tiles[j].client == c)
223+
return j;
224+
return -1;
225+
}
226+
227+
static int find_scroller_column(scroller_state_t *s, client_t *c) {
228+
for (int i = 0; i < s->column_count; i++)
229+
if (find_scroller_tile_idx(&s->columns[i], c) >= 0)
230+
return i;
231+
return -1;
232+
}
233+
234+
static double max_d(double a, double b) {
235+
return a > b ? a : b;
236+
}
237+
262238
// process cursor motion for tiled window resizing
263239
static void process_cursor_tiled_resize(void) {
264240
node_t *node = server.tiled_resize_node;
265241
if (!node || !node->client)
266242
return;
267243

244+
desktop_t *d = node->desktop;
245+
if (!d)
246+
return;
247+
248+
// Handle scroller layout
249+
if (d->layout == LAYOUT_SCROLLER && d->scroller_state) {
250+
scroller_state_t *s = d->scroller_state;
251+
if (s->column_count == 0)
252+
return;
253+
254+
int col = find_scroller_column(s, node->client);
255+
if (col < 0)
256+
return;
257+
258+
double delta_x = server.cursor->x - server.grab_x;
259+
260+
if (server.resize_edges & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) {
261+
double area_w = max_d(1.0, (double)s->working_area.width);
262+
s->columns[col].width.value += delta_x / area_w;
263+
if (s->columns[col].width.value < 0.1)
264+
s->columns[col].width.value = 0.1;
265+
if (s->columns[col].width.value > 1.0)
266+
s->columns[col].width.value = 1.0;
267+
s->columns[col].width.type = SCROLLER_WIDTH_PROPORTION;
268+
}
269+
270+
arrange(node->output, d, false);
271+
apply_leaf_positions(d);
272+
return;
273+
}
274+
268275
// handle horizontal resizing
269276
if (server.tiled_resize_parent_vertical &&
270277
(server.resize_edges & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT))) {
@@ -319,13 +326,10 @@ static void process_cursor_tiled_resize(void) {
319326
parent->current.split_ratio = new_ratio;
320327
}
321328

322-
if (server.tiled_resize_parent_vertical && node->desktop) {
323-
update_scene_positions(server.tiled_resize_parent_vertical,
324-
server.tiled_resize_parent_vertical->rectangle, node->desktop);
325-
}
326-
if (server.tiled_resize_parent_horizontal && node->desktop) {
327-
update_scene_positions(server.tiled_resize_parent_horizontal,
328-
server.tiled_resize_parent_horizontal->rectangle, node->desktop);
329+
// Use the proper layout function to recompute all positions
330+
if (node->output && d) {
331+
arrange(node->output, d, false);
332+
apply_leaf_positions(d);
329333
}
330334
}
331335

@@ -831,6 +835,7 @@ void cursor_button(struct wl_listener *listener, void *data) {
831835
tiling_drag_begin(toplevel->node);
832836
} else if (matched_kb->action == BIND_INTERACTIVE_RESIZE) {
833837
client_t *c = toplevel->node->client;
838+
desktop_t *d = toplevel->node->desktop;
834839
uint32_t edges = 0;
835840

836841
if (c->state == STATE_FLOATING) {
@@ -877,61 +882,83 @@ void cursor_button(struct wl_listener *listener, void *data) {
877882
edges = WLR_EDGE_RIGHT;
878883
}
879884
} else if (IS_TILED(c)) {
880-
edges = get_tiled_resizable_edges(toplevel->node);
881-
882-
if (edges != 0) {
883-
// determine edge
885+
// for scroller layouts, only allow horizontal edges (column width resize)
886+
if (d && d->layout == LAYOUT_SCROLLER) {
884887
double wx = c->tiled_rectangle.x;
885-
double wy = c->tiled_rectangle.y;
886888
double ww = c->tiled_rectangle.width;
887-
double wh = c->tiled_rectangle.height;
888889
double cx = server.cursor->x;
889-
double cy = server.cursor->y;
890890

891891
double third_w = ww / 3.0;
892-
double third_h = wh / 3.0;
893892

894893
bool in_left = cx < wx + third_w;
895894
bool in_right = cx > wx + ww - third_w;
896-
bool in_top = cy < wy + third_h;
897-
bool in_bottom = cy > wy + wh - third_h;
898-
899-
uint32_t clicked_edges = 0;
900895

901-
if (in_left || in_right)
902-
clicked_edges |= in_left ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT;
903-
904-
if (in_top || in_bottom)
905-
clicked_edges |= in_top ? WLR_EDGE_TOP : WLR_EDGE_BOTTOM;
906-
907-
if (clicked_edges == 0) {
896+
if (in_left)
897+
edges = WLR_EDGE_LEFT;
898+
else if (in_right)
899+
edges = WLR_EDGE_RIGHT;
900+
else {
908901
double dist_left = cx - wx;
909902
double dist_right = (wx + ww) - cx;
910-
double dist_top = cy - wy;
911-
double dist_bottom = (wy + wh) - cy;
912-
913-
double min_dist = INFINITY;
914-
915-
if ((edges & WLR_EDGE_LEFT) && dist_left < min_dist) {
916-
min_dist = dist_left;
917-
clicked_edges = WLR_EDGE_LEFT;
918-
}
919-
if ((edges & WLR_EDGE_RIGHT) && dist_right < min_dist) {
920-
min_dist = dist_right;
921-
clicked_edges = WLR_EDGE_RIGHT;
922-
}
923-
if ((edges & WLR_EDGE_TOP) && dist_top < min_dist) {
924-
min_dist = dist_top;
925-
clicked_edges = WLR_EDGE_TOP;
926-
}
927-
if ((edges & WLR_EDGE_BOTTOM) && dist_bottom < min_dist) {
928-
min_dist = dist_bottom;
929-
clicked_edges = WLR_EDGE_BOTTOM;
930-
}
903+
edges = dist_left < dist_right ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT;
931904
}
905+
} else {
906+
edges = get_tiled_resizable_edges(toplevel->node);
907+
908+
if (edges != 0) {
909+
// determine edge
910+
double wx = c->tiled_rectangle.x;
911+
double wy = c->tiled_rectangle.y;
912+
double ww = c->tiled_rectangle.width;
913+
double wh = c->tiled_rectangle.height;
914+
double cx = server.cursor->x;
915+
double cy = server.cursor->y;
916+
917+
double third_w = ww / 3.0;
918+
double third_h = wh / 3.0;
919+
920+
bool in_left = cx < wx + third_w;
921+
bool in_right = cx > wx + ww - third_w;
922+
bool in_top = cy < wy + third_h;
923+
bool in_bottom = cy > wy + wh - third_h;
924+
925+
uint32_t clicked_edges = 0;
926+
927+
if (in_left || in_right)
928+
clicked_edges |= in_left ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT;
929+
930+
if (in_top || in_bottom)
931+
clicked_edges |= in_top ? WLR_EDGE_TOP : WLR_EDGE_BOTTOM;
932+
933+
if (clicked_edges == 0) {
934+
double dist_left = cx - wx;
935+
double dist_right = (wx + ww) - cx;
936+
double dist_top = cy - wy;
937+
double dist_bottom = (wy + wh) - cy;
938+
939+
double min_dist = INFINITY;
940+
941+
if ((edges & WLR_EDGE_LEFT) && dist_left < min_dist) {
942+
min_dist = dist_left;
943+
clicked_edges = WLR_EDGE_LEFT;
944+
}
945+
if ((edges & WLR_EDGE_RIGHT) && dist_right < min_dist) {
946+
min_dist = dist_right;
947+
clicked_edges = WLR_EDGE_RIGHT;
948+
}
949+
if ((edges & WLR_EDGE_TOP) && dist_top < min_dist) {
950+
min_dist = dist_top;
951+
clicked_edges = WLR_EDGE_TOP;
952+
}
953+
if ((edges & WLR_EDGE_BOTTOM) && dist_bottom < min_dist) {
954+
min_dist = dist_bottom;
955+
clicked_edges = WLR_EDGE_BOTTOM;
956+
}
957+
}
932958

933-
// intersect clicked edges with resizable edges
934-
edges = clicked_edges & edges;
959+
// intersect clicked edges with resizable edges
960+
edges = clicked_edges & edges;
961+
}
935962
}
936963
}
937964

0 commit comments

Comments
 (0)