feat: support custom split direction

This commit is contained in:
DreamMaoMao 2026-05-09 16:12:55 +08:00
parent d8d2952d56
commit b7581392c4
2 changed files with 38 additions and 36 deletions

View file

@ -50,7 +50,8 @@ 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, bool as_first) { float ratio, bool as_first, bool split_h,
bool lock) {
DwindleNode *new_leaf = dwindle_new_leaf(new_c); DwindleNode *new_leaf = dwindle_new_leaf(new_c);
if (!*root) { if (!*root) {
@ -65,6 +66,9 @@ 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->split_h = split_h;
split->split_locked = lock;
if (as_first) { if (as_first) {
split->first = new_leaf; split->first = new_leaf;
split->second = target; split->second = target;
@ -164,7 +168,8 @@ static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
return; return;
dwindle_remove(root, c); dwindle_remove(root, c);
bool as_first = (dir == UP || dir == LEFT); bool as_first = (dir == UP || dir == LEFT);
dwindle_insert(root, c, target, ratio, as_first); bool split_h = (dir == LEFT || dir == RIGHT);
dwindle_insert(root, c, target, ratio, as_first, split_h, true);
} }
static void dwindle_swap_clients(DwindleNode **root, Client *a, Client *b) { static void dwindle_swap_clients(DwindleNode **root, Client *a, Client *b) {
@ -315,6 +320,8 @@ static void dwindle_remove_client(Client *c) {
static void dwindle_insert_with_config(DwindleNode **root, Client *new_c, static void dwindle_insert_with_config(DwindleNode **root, Client *new_c,
Client *focused, float ratio) { Client *focused, float ratio) {
bool as_first = false; bool as_first = false;
bool split_h = false;
bool lock = false;
if (focused) { if (focused) {
struct wlr_box *fg = &focused->geom; struct wlr_box *fg = &focused->geom;
@ -322,44 +329,36 @@ static void dwindle_insert_with_config(DwindleNode **root, Client *new_c,
double fcy = fg->y + fg->height * 0.5; double fcy = fg->y + fg->height * 0.5;
if (config.dwindle_smart_split) { if (config.dwindle_smart_split) {
/* Divide the focused window into 4 triangles using its diagonals.
* The triangle the cursor falls in determines both the split axis
* and which side the new window appears on. */
double nx = (cursor->x - fcx) / (fg->width * 0.5); double nx = (cursor->x - fcx) / (fg->width * 0.5);
double ny = (cursor->y - fcy) / (fg->height * 0.5); double ny = (cursor->y - fcy) / (fg->height * 0.5);
bool do_split_h;
if (fabs(ny) > fabs(nx)) {
do_split_h = false;
as_first = (ny < 0); /* top triangle → new window on top */
} else {
do_split_h = true;
as_first = (nx < 0); /* left triangle → new window on left */
}
dwindle_insert(root, new_c, focused, ratio, as_first);
DwindleNode *leaf = dwindle_find_leaf(*root, new_c);
if (leaf && leaf->parent) {
leaf->parent->split_h = do_split_h;
leaf->parent->split_locked = true;
}
return;
}
/* Predict likely split direction from the focused window's shape. */ if (fabs(ny) > fabs(nx)) {
bool likely_h = (fg->width >= fg->height); split_h = false; // vertical split
if (likely_h) { as_first = (ny < 0); // top → new window on top
if (config.dwindle_hsplit == 0) } else {
as_first = (cursor->x < fcx); /* follow mouse */ split_h = true; // horizontal split
else as_first = (nx < 0); // left → new window on left
as_first = (config.dwindle_hsplit == 2); /* 2=left, 1=right */ }
lock = true; // lock split direction
} else { } else {
if (config.dwindle_vsplit == 0) // normal mode, auto split
as_first = (cursor->y < fcy); /* follow mouse */ bool likely_h = (fg->width >= fg->height);
else if (likely_h) {
as_first = (config.dwindle_vsplit == 2); /* 2=top, 1=bottom */ if (config.dwindle_hsplit == 0)
as_first = (cursor->x < fcx);
else
as_first = (config.dwindle_hsplit == 2);
} else {
if (config.dwindle_vsplit == 0)
as_first = (cursor->y < fcy);
else
as_first = (config.dwindle_vsplit == 2);
}
// split_h and lock are false, decided by width/height ratio
} }
} }
dwindle_insert(root, new_c, focused, ratio, as_first); dwindle_insert(root, new_c, focused, ratio, as_first, split_h, lock);
} }
void dwindle(Monitor *m) { void dwindle(Monitor *m) {

View file

@ -2216,10 +2216,13 @@ void place_drag_tile_client(Client *c) {
} }
if (layout->id == DWINDLE) { if (layout->id == DWINDLE) {
uint32_t tag = c->mon->pertag->curtag; uint32_t tag = c->mon->pertag->curtag;
bool insert_before = closest->drop_direction == LEFT || bool insert_before = (closest->drop_direction == LEFT ||
closest->drop_direction == UP; closest->drop_direction == UP);
bool split_h = (closest->drop_direction == LEFT ||
closest->drop_direction == RIGHT);
dwindle_insert(&c->mon->pertag->dwindle_root[tag], c, closest, dwindle_insert(&c->mon->pertag->dwindle_root[tag], c, closest,
config.dwindle_split_ratio, insert_before); config.dwindle_split_ratio, insert_before, split_h,
true);
setfloating(c, 0); setfloating(c, 0);
return; return;
} }