fix: improved resizing to be less clanky and smoother

This commit is contained in:
ernestoCruz05 2026-04-05 10:05:56 +01:00
parent 2193ebe8cb
commit 2b8c9971ad
4 changed files with 117 additions and 36 deletions

View file

@ -1102,7 +1102,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
c->mon->resizing_count_pending++; c->mon->resizing_count_pending++;
} }
if (c == grabc || (cursor_mode == CurResize && ISTILED(c))) { if (c == grabc || c->snap_to_geom) {
c->animation.running = false; c->animation.running = false;
c->need_output_flush = false; c->need_output_flush = false;

View file

@ -119,7 +119,7 @@ int32_t exchange_client(const Arg *arg) {
if (c->mon && c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == DWINDLE) { if (c->mon && c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == DWINDLE) {
uint32_t tag = c->mon->pertag->curtag; uint32_t tag = c->mon->pertag->curtag;
dwindle_move_client(&c->mon->pertag->dwindle_root[tag], c, tc, dwindle_move_client(&c->mon->pertag->dwindle_root[tag], c, tc,
c->mon->pertag->mfacts[tag]); c->mon->pertag->mfacts[tag], arg->i);
arrange(c->mon, false, false); arrange(c->mon, false, false);
} else { } else {
exchange_two_client(c, tc); exchange_two_client(c, tc);
@ -454,6 +454,20 @@ int32_t moveresize(const Arg *arg) {
} else { } else {
grabcx = (int32_t)round(cursor->x); grabcx = (int32_t)round(cursor->x);
grabcy = (int32_t)round(cursor->y); grabcy = (int32_t)round(cursor->y);
if (grabc->mon &&
grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag]->id ==
DWINDLE) {
int32_t bx = -1, by = -1;
if (dwindle_get_resize_border(grabc->mon, grabc, &bx, &by)) {
if (bx >= 0)
grabcx = bx;
if (by >= 0)
grabcy = by;
wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy);
}
drag_begin_cursorx = grabcx;
drag_begin_cursory = grabcy;
}
wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab");
} }
break; break;

View file

@ -3,6 +3,9 @@ struct DwindleNode {
bool is_split; bool is_split;
bool split_h; bool split_h;
float ratio; float ratio;
float drag_init_ratio;
int32_t container_x;
int32_t container_y;
int32_t container_w; int32_t container_w;
int32_t container_h; int32_t container_h;
DwindleNode *parent; DwindleNode *parent;
@ -11,6 +14,9 @@ struct DwindleNode {
Client *client; Client *client;
}; };
static DwindleNode *dwindle_locked_h_node = NULL;
static DwindleNode *dwindle_locked_v_node = NULL;
static DwindleNode *dwindle_new_leaf(Client *c) { static DwindleNode *dwindle_new_leaf(Client *c) {
DwindleNode *n = calloc(1, sizeof(DwindleNode)); DwindleNode *n = calloc(1, sizeof(DwindleNode));
n->client = c; n->client = c;
@ -43,7 +49,7 @@ static void dwindle_free_tree(DwindleNode *node) {
} }
static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused, static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
float ratio) { float ratio, bool as_first) {
DwindleNode *new_leaf = dwindle_new_leaf(new_c); DwindleNode *new_leaf = dwindle_new_leaf(new_c);
if (!*root) { if (!*root) {
@ -58,8 +64,13 @@ static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
DwindleNode *split = calloc(1, sizeof(DwindleNode)); DwindleNode *split = calloc(1, sizeof(DwindleNode));
split->is_split = true; split->is_split = true;
split->ratio = ratio; split->ratio = ratio;
split->first = target; if (as_first) {
split->second = new_leaf; split->first = new_leaf;
split->second = target;
} else {
split->first = target;
split->second = new_leaf;
}
split->parent = target->parent; split->parent = target->parent;
target->parent = split; target->parent = split;
new_leaf->parent = split; new_leaf->parent = split;
@ -90,6 +101,8 @@ static void dwindle_remove(DwindleNode **root, Client *c) {
(parent->first == leaf) ? parent->second : parent->first; (parent->first == leaf) ? parent->second : parent->first;
DwindleNode *grandparent = parent->parent; DwindleNode *grandparent = parent->parent;
sibling->parent = grandparent; sibling->parent = grandparent;
sibling->container_w = 0;
sibling->container_h = 0;
if (!grandparent) { if (!grandparent) {
*root = sibling; *root = sibling;
@ -120,6 +133,8 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
if (node->container_w == 0 && node->container_h == 0) if (node->container_w == 0 && node->container_h == 0)
node->split_h = (aw >= ah); node->split_h = (aw >= ah);
node->container_x = ax;
node->container_y = ay;
node->container_w = aw; node->container_w = aw;
node->container_h = ah; node->container_h = ah;
if (node->split_h) { if (node->split_h) {
@ -136,13 +151,14 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
} }
static void dwindle_move_client(DwindleNode **root, Client *c, Client *target, static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
float ratio) { float ratio, int32_t dir) {
if (!c || !target || c == target) if (!c || !target || c == target)
return; return;
if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target)) if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target))
return; return;
dwindle_remove(root, c); dwindle_remove(root, c);
dwindle_insert(root, c, target, ratio); bool as_first = (dir == UP || dir == LEFT);
dwindle_insert(root, c, target, ratio, as_first);
} }
static void dwindle_swap_clients(DwindleNode **root, Client *a, Client *b) { static void dwindle_swap_clients(DwindleNode **root, Client *a, Client *b) {
@ -161,34 +177,84 @@ static void dwindle_resize_client(Monitor *m, Client *c, int32_t dx,
if (!leaf) if (!leaf)
return; return;
bool want_h = abs(dx) >= abs(dy); if (!start_drag_window) {
start_drag_window = true;
DwindleNode *node = leaf->parent; dwindle_locked_h_node = NULL;
while (node) { dwindle_locked_v_node = NULL;
if (node->split_h == want_h) { DwindleNode *node = leaf->parent;
float container_sz = want_h ? (float)MAX(1, node->container_w) while (node) {
: (float)MAX(1, node->container_h); if (node->split_h && !dwindle_locked_h_node) {
dwindle_locked_h_node = node;
float delta = node->drag_init_ratio = node->ratio;
want_h ? (float)dx / container_sz : (float)dy / container_sz; }
if (!node->split_h && !dwindle_locked_v_node) {
node->ratio += delta; dwindle_locked_v_node = node;
node->ratio = CLAMP_FLOAT(node->ratio, 0.05f, 0.95f); node->drag_init_ratio = node->ratio;
}
int32_t n = m->visible_tiling_clients; if (dwindle_locked_h_node && dwindle_locked_v_node)
int32_t gap_ih = enablegaps ? m->gappih : 0; break;
int32_t gap_iv = enablegaps ? m->gappiv : 0; node = node->parent;
int32_t gap_oh = enablegaps ? m->gappoh : 0;
int32_t gap_ov = enablegaps ? m->gappov : 0;
if (config.smartgaps && n == 1)
gap_ih = gap_iv = gap_oh = gap_ov = 0;
dwindle_assign(m->pertag->dwindle_root[tag], m->w.x + gap_oh,
m->w.y + gap_ov, m->w.width - 2 * gap_oh,
m->w.height - 2 * gap_ov, gap_ih, gap_iv);
return;
} }
node = node->parent;
} }
if (!dwindle_locked_h_node && !dwindle_locked_v_node)
return;
if (dwindle_locked_h_node) {
float cw = (float)MAX(1, dwindle_locked_h_node->container_w);
float ox = (float)(cursor->x - drag_begin_cursorx);
dwindle_locked_h_node->ratio =
dwindle_locked_h_node->drag_init_ratio + ox / cw;
dwindle_locked_h_node->ratio =
CLAMP_FLOAT(dwindle_locked_h_node->ratio, 0.05f, 0.95f);
}
if (dwindle_locked_v_node) {
float ch = (float)MAX(1, dwindle_locked_v_node->container_h);
float oy = (float)(cursor->y - drag_begin_cursory);
dwindle_locked_v_node->ratio =
dwindle_locked_v_node->drag_init_ratio + oy / ch;
dwindle_locked_v_node->ratio =
CLAMP_FLOAT(dwindle_locked_v_node->ratio, 0.05f, 0.95f);
}
int32_t n = m->visible_tiling_clients;
int32_t gap_ih = enablegaps ? m->gappih : 0;
int32_t gap_iv = enablegaps ? m->gappiv : 0;
int32_t gap_oh = enablegaps ? m->gappoh : 0;
int32_t gap_ov = enablegaps ? m->gappov : 0;
if (config.smartgaps && n == 1)
gap_ih = gap_iv = gap_oh = gap_ov = 0;
Client *tc;
wl_list_for_each(tc, &clients, link) if (VISIBLEON(tc, m) && ISTILED(tc))
tc->snap_to_geom = true;
dwindle_assign(m->pertag->dwindle_root[tag], m->w.x + gap_oh,
m->w.y + gap_ov, m->w.width - 2 * gap_oh,
m->w.height - 2 * gap_ov, gap_ih, gap_iv);
wl_list_for_each(tc, &clients, link) if (VISIBLEON(tc, m) && ISTILED(tc))
tc->snap_to_geom = false;
}
static bool dwindle_get_resize_border(Monitor *m, Client *c, int32_t *out_x,
int32_t *out_y) {
uint32_t tag = m->pertag->curtag;
DwindleNode *leaf = dwindle_find_leaf(m->pertag->dwindle_root[tag], c);
if (!leaf || !leaf->parent)
return false;
DwindleNode *parent = leaf->parent;
bool is_first = (parent->first == leaf);
if (parent->split_h) {
*out_x = is_first ? (c->geom.x + c->geom.width) : c->geom.x;
*out_y = -1;
} else {
*out_x = -1;
*out_y = is_first ? (c->geom.y + c->geom.height) : c->geom.y;
}
return true;
} }
static void dwindle_remove_client(Client *c) { static void dwindle_remove_client(Client *c) {
@ -255,7 +321,7 @@ void dwindle(Monitor *m) {
focused = m->sel; focused = m->sel;
for (int32_t i = 0; i < count; i++) { for (int32_t i = 0; i < count; i++) {
if (!dwindle_find_leaf(*root, vis[i])) if (!dwindle_find_leaf(*root, vis[i]))
dwindle_insert(root, vis[i], focused, ratio); dwindle_insert(root, vis[i], focused, ratio, false);
} }
int32_t gap_ih = enablegaps ? m->gappih : 0; int32_t gap_ih = enablegaps ? m->gappih : 0;

View file

@ -401,6 +401,7 @@ struct Client {
bool is_clip_to_hide; bool is_clip_to_hide;
bool canvas_floating; bool canvas_floating;
bool drag_to_tile; bool drag_to_tile;
bool snap_to_geom;
bool scratchpad_switching_mon; bool scratchpad_switching_mon;
bool fake_no_border; bool fake_no_border;
int32_t nofocus; int32_t nofocus;
@ -1045,12 +1046,12 @@ static struct wl_event_source *sync_keymap;
#include "animation/tag.h" #include "animation/tag.h"
static void canvas_reposition(Monitor *m); static void canvas_reposition(Monitor *m);
static void canvas_pan_to_client(Monitor *m, Client *c); static void canvas_pan_to_client(Monitor *m, Client *c);
#include "layout/dwindle.h"
#include "dispatch/bind_define.h" #include "dispatch/bind_define.h"
#include "ext-protocol/all.h" #include "ext-protocol/all.h"
#include "fetch/fetch.h" #include "fetch/fetch.h"
#include "layout/arrange.h" #include "layout/arrange.h"
#include "layout/canvas.h" #include "layout/canvas.h"
#include "layout/dwindle.h"
#include "layout/horizontal.h" #include "layout/horizontal.h"
#include "layout/vertical.h" #include "layout/vertical.h"
@ -2169,7 +2170,7 @@ void place_drag_tile_client(Client *c) {
c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == DWINDLE) { c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == DWINDLE) {
uint32_t tag = c->mon->pertag->curtag; uint32_t tag = c->mon->pertag->curtag;
dwindle_insert(&c->mon->pertag->dwindle_root[tag], c, dwindle_insert(&c->mon->pertag->dwindle_root[tag], c,
closest_client, c->mon->pertag->mfacts[tag]); closest_client, c->mon->pertag->mfacts[tag], false);
} else if (closest_client->link.prev != &c->link) { } else if (closest_client->link.prev != &c->link) {
wl_list_remove(&c->link); wl_list_remove(&c->link);
c->link.next = &closest_client->link; c->link.next = &closest_client->link;