mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-05-09 23:50:21 -04:00
feat: dwindle layout support
This commit is contained in:
parent
b7a55a15d7
commit
b0bd70d225
6 changed files with 549 additions and 3 deletions
|
|
@ -237,6 +237,14 @@ typedef struct {
|
|||
int32_t center_master_overspread;
|
||||
int32_t center_when_single_stack;
|
||||
|
||||
/* dwindle layout */
|
||||
int32_t dwindle_vsplit;
|
||||
int32_t dwindle_hsplit;
|
||||
int32_t dwindle_preserve_split;
|
||||
int32_t dwindle_smart_split;
|
||||
int32_t dwindle_smart_resize;
|
||||
float dwindle_split_ratio;
|
||||
|
||||
uint32_t hotarea_size;
|
||||
uint32_t hotarea_corner;
|
||||
uint32_t enable_hotarea;
|
||||
|
|
@ -1558,6 +1566,18 @@ bool parse_option(Config *config, char *key, char *value) {
|
|||
config->center_master_overspread = atoi(value);
|
||||
} else if (strcmp(key, "center_when_single_stack") == 0) {
|
||||
config->center_when_single_stack = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_vsplit") == 0) {
|
||||
config->dwindle_vsplit = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_hsplit") == 0) {
|
||||
config->dwindle_hsplit = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_preserve_split") == 0) {
|
||||
config->dwindle_preserve_split = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_smart_split") == 0) {
|
||||
config->dwindle_smart_split = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_smart_resize") == 0) {
|
||||
config->dwindle_smart_resize = atoi(value);
|
||||
} else if (strcmp(key, "dwindle_split_ratio") == 0) {
|
||||
config->dwindle_split_ratio = atof(value);
|
||||
} else if (strcmp(key, "hotarea_size") == 0) {
|
||||
config->hotarea_size = atoi(value);
|
||||
} else if (strcmp(key, "hotarea_corner") == 0) {
|
||||
|
|
@ -3092,6 +3112,14 @@ void override_config(void) {
|
|||
config.center_when_single_stack =
|
||||
CLAMP_INT(config.center_when_single_stack, 0, 1);
|
||||
config.new_is_master = CLAMP_INT(config.new_is_master, 0, 1);
|
||||
config.dwindle_vsplit = CLAMP_INT(config.dwindle_vsplit, 0, 2);
|
||||
config.dwindle_hsplit = CLAMP_INT(config.dwindle_hsplit, 0, 2);
|
||||
config.dwindle_preserve_split =
|
||||
CLAMP_INT(config.dwindle_preserve_split, 0, 1);
|
||||
config.dwindle_smart_split = CLAMP_INT(config.dwindle_smart_split, 0, 1);
|
||||
config.dwindle_smart_resize = CLAMP_INT(config.dwindle_smart_resize, 0, 1);
|
||||
config.dwindle_split_ratio =
|
||||
CLAMP_FLOAT(config.dwindle_split_ratio, 0.05f, 0.95f);
|
||||
config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
|
||||
config.hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3);
|
||||
config.enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1);
|
||||
|
|
@ -3206,6 +3234,13 @@ void set_value_default() {
|
|||
config.center_master_overspread = 0;
|
||||
config.center_when_single_stack = 1;
|
||||
|
||||
config.dwindle_vsplit = 0;
|
||||
config.dwindle_hsplit = 0;
|
||||
config.dwindle_preserve_split = 0;
|
||||
config.dwindle_smart_split = 0;
|
||||
config.dwindle_smart_resize = 0;
|
||||
config.dwindle_split_ratio = 0.5f;
|
||||
|
||||
config.log_level = WLR_ERROR;
|
||||
config.numlockon = 0;
|
||||
config.capslock = 0;
|
||||
|
|
@ -3553,7 +3588,7 @@ void reapply_rootbg(void) {
|
|||
wlr_scene_rect_set_color(root_bg, config.rootcolor);
|
||||
}
|
||||
|
||||
void reapply_border(void) {
|
||||
void reapply_property(void) {
|
||||
Client *c = NULL;
|
||||
|
||||
// reset border width when config change
|
||||
|
|
@ -3562,6 +3597,8 @@ void reapply_border(void) {
|
|||
if (!c->isnoborder && !c->isfullscreen) {
|
||||
c->bw = config.borderpx;
|
||||
}
|
||||
|
||||
wlr_scene_rect_set_color(c->droparea, config.dropcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3706,7 +3743,7 @@ void reset_option(void) {
|
|||
run_exec();
|
||||
|
||||
reapply_cursor_style();
|
||||
reapply_border();
|
||||
reapply_property();
|
||||
reapply_rootbg();
|
||||
reapply_keyboard();
|
||||
reapply_pointer();
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ int32_t exchange_client(const Arg *arg) {
|
|||
|
||||
Client *tc = direction_select(arg);
|
||||
tc = get_focused_stack_client(tc);
|
||||
|
||||
if (!tc)
|
||||
return 0;
|
||||
|
||||
exchange_two_client(c, tc);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -488,6 +488,21 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
}
|
||||
}
|
||||
|
||||
void resize_tile_dwindle(Client *grabc, bool isdrag, int32_t offsetx,
|
||||
int32_t offsety, uint32_t time, bool isvertical) {
|
||||
|
||||
if (!isdrag) {
|
||||
dwindle_resize_client_step(grabc->mon, grabc, offsetx, offsety);
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_apply_drap_time == 0 ||
|
||||
time - last_apply_drap_time > config.drag_tile_refresh_interval) {
|
||||
dwindle_resize_client(grabc->mon, grabc);
|
||||
last_apply_drap_time = time;
|
||||
}
|
||||
}
|
||||
|
||||
void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
|
||||
int32_t offsety, uint32_t time, bool isvertical) {
|
||||
Client *tc = NULL;
|
||||
|
|
@ -706,6 +721,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, false);
|
||||
} else if (current_layout->id == VERTICAL_SCROLLER) {
|
||||
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true);
|
||||
} else if (current_layout->id == DWINDLE) {
|
||||
resize_tile_dwindle(grabc, isdrag, offsetx, offsety, time, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
433
src/layout/dwindle.h
Normal file
433
src/layout/dwindle.h
Normal file
|
|
@ -0,0 +1,433 @@
|
|||
typedef struct DwindleNode DwindleNode;
|
||||
struct DwindleNode {
|
||||
bool is_split;
|
||||
bool split_h;
|
||||
bool split_locked;
|
||||
float ratio;
|
||||
float drag_init_ratio;
|
||||
int32_t container_x;
|
||||
int32_t container_y;
|
||||
int32_t container_w;
|
||||
int32_t container_h;
|
||||
DwindleNode *parent;
|
||||
DwindleNode *first;
|
||||
DwindleNode *second;
|
||||
Client *client;
|
||||
};
|
||||
|
||||
static DwindleNode *dwindle_locked_h_node = NULL;
|
||||
static DwindleNode *dwindle_locked_v_node = NULL;
|
||||
|
||||
static DwindleNode *dwindle_new_leaf(Client *c) {
|
||||
DwindleNode *n = calloc(1, sizeof(DwindleNode));
|
||||
n->client = c;
|
||||
return n;
|
||||
}
|
||||
|
||||
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c) {
|
||||
if (!node)
|
||||
return NULL;
|
||||
if (!node->is_split)
|
||||
return node->client == c ? node : NULL;
|
||||
DwindleNode *r = dwindle_find_leaf(node->first, c);
|
||||
return r ? r : dwindle_find_leaf(node->second, c);
|
||||
}
|
||||
|
||||
static DwindleNode *dwindle_first_leaf(DwindleNode *node) {
|
||||
if (!node)
|
||||
return NULL;
|
||||
while (node->is_split)
|
||||
node = node->first;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void dwindle_free_tree(DwindleNode *node) {
|
||||
if (!node)
|
||||
return;
|
||||
dwindle_free_tree(node->first);
|
||||
dwindle_free_tree(node->second);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
|
||||
float ratio, bool as_first, bool split_h,
|
||||
bool lock) {
|
||||
DwindleNode *new_leaf = dwindle_new_leaf(new_c);
|
||||
|
||||
if (!*root) {
|
||||
*root = new_leaf;
|
||||
return;
|
||||
}
|
||||
|
||||
DwindleNode *target = focused ? dwindle_find_leaf(*root, focused) : NULL;
|
||||
if (!target)
|
||||
target = dwindle_first_leaf(*root);
|
||||
|
||||
DwindleNode *split = calloc(1, sizeof(DwindleNode));
|
||||
split->is_split = true;
|
||||
split->ratio = ratio;
|
||||
split->split_h = split_h;
|
||||
split->split_locked = lock;
|
||||
|
||||
if (as_first) {
|
||||
split->first = new_leaf;
|
||||
split->second = target;
|
||||
} else {
|
||||
split->first = target;
|
||||
split->second = new_leaf;
|
||||
}
|
||||
split->parent = target->parent;
|
||||
target->parent = split;
|
||||
new_leaf->parent = split;
|
||||
|
||||
if (!split->parent) {
|
||||
*root = split;
|
||||
} else {
|
||||
if (split->parent->first == target)
|
||||
split->parent->first = split;
|
||||
else
|
||||
split->parent->second = split;
|
||||
}
|
||||
}
|
||||
|
||||
static void dwindle_remove(DwindleNode **root, Client *c) {
|
||||
DwindleNode *leaf = dwindle_find_leaf(*root, c);
|
||||
if (!leaf)
|
||||
return;
|
||||
|
||||
DwindleNode *parent = leaf->parent;
|
||||
if (!parent) {
|
||||
free(leaf);
|
||||
*root = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
DwindleNode *sibling =
|
||||
(parent->first == leaf) ? parent->second : parent->first;
|
||||
DwindleNode *grandparent = parent->parent;
|
||||
sibling->parent = grandparent;
|
||||
|
||||
/* Preserve split direction on sibling split-nodes when requested. */
|
||||
if (!sibling->is_split ||
|
||||
(!config.dwindle_preserve_split && !config.dwindle_smart_split)) {
|
||||
sibling->container_w = 0;
|
||||
sibling->container_h = 0;
|
||||
}
|
||||
|
||||
if (!grandparent) {
|
||||
*root = sibling;
|
||||
} else {
|
||||
if (grandparent->first == parent)
|
||||
grandparent->first = sibling;
|
||||
else
|
||||
grandparent->second = sibling;
|
||||
}
|
||||
|
||||
free(leaf);
|
||||
free(parent);
|
||||
}
|
||||
|
||||
static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
|
||||
int32_t aw, int32_t ah, int32_t gap_h,
|
||||
int32_t gap_v) {
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (!node->is_split) {
|
||||
if (node->client) {
|
||||
struct wlr_box box = {ax, ay, MAX(1, aw), MAX(1, ah)};
|
||||
resize(node->client, box, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node->split_locked && node->container_w == 0 && node->container_h == 0)
|
||||
node->split_h = (aw >= ah);
|
||||
node->container_x = ax;
|
||||
node->container_y = ay;
|
||||
node->container_w = aw;
|
||||
node->container_h = ah;
|
||||
if (node->split_h) {
|
||||
int32_t w1 = MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2);
|
||||
dwindle_assign(node->first, ax, ay, w1, ah, gap_h, gap_v);
|
||||
dwindle_assign(node->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah,
|
||||
gap_h, gap_v);
|
||||
} else {
|
||||
int32_t h1 = MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2);
|
||||
dwindle_assign(node->first, ax, ay, aw, h1, gap_h, gap_v);
|
||||
dwindle_assign(node->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v,
|
||||
gap_h, gap_v);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
|
||||
float ratio, int32_t dir) {
|
||||
if (!c || !target || c == target)
|
||||
return;
|
||||
if (!dwindle_find_leaf(*root, c) || !dwindle_find_leaf(*root, target))
|
||||
return;
|
||||
dwindle_remove(root, c);
|
||||
bool as_first = (dir == UP || dir == LEFT);
|
||||
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) {
|
||||
DwindleNode *la = dwindle_find_leaf(*root, a);
|
||||
DwindleNode *lb = dwindle_find_leaf(*root, b);
|
||||
if (!la || !lb || la == lb)
|
||||
return;
|
||||
la->client = b;
|
||||
lb->client = a;
|
||||
}
|
||||
|
||||
static void dwindle_resize_client(Monitor *m, Client *c) {
|
||||
uint32_t tag = m->pertag->curtag;
|
||||
DwindleNode *leaf = dwindle_find_leaf(m->pertag->dwindle_root[tag], c);
|
||||
if (!leaf)
|
||||
return;
|
||||
|
||||
if (!start_drag_window) {
|
||||
start_drag_window = true;
|
||||
dwindle_locked_h_node = NULL;
|
||||
dwindle_locked_v_node = NULL;
|
||||
drag_begin_cursorx = cursor->x;
|
||||
drag_begin_cursory = cursor->y;
|
||||
DwindleNode *node = leaf->parent;
|
||||
while (node) {
|
||||
if (node->split_h && !dwindle_locked_h_node) {
|
||||
dwindle_locked_h_node = node;
|
||||
node->drag_init_ratio = node->ratio;
|
||||
}
|
||||
if (!node->split_h && !dwindle_locked_v_node) {
|
||||
dwindle_locked_v_node = node;
|
||||
node->drag_init_ratio = node->ratio;
|
||||
}
|
||||
if (dwindle_locked_h_node && dwindle_locked_v_node)
|
||||
break;
|
||||
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);
|
||||
if (config.dwindle_smart_resize) {
|
||||
/* Move the boundary toward the cursor: invert direction when
|
||||
* the drag started on the right side of the split line. */
|
||||
float split_x = dwindle_locked_h_node->container_x +
|
||||
cw * dwindle_locked_h_node->drag_init_ratio;
|
||||
if (drag_begin_cursorx >= split_x)
|
||||
ox = -ox;
|
||||
}
|
||||
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);
|
||||
if (config.dwindle_smart_resize) {
|
||||
/* Same logic for the vertical split line. */
|
||||
float split_y = dwindle_locked_v_node->container_y +
|
||||
ch * dwindle_locked_v_node->drag_init_ratio;
|
||||
if (drag_begin_cursory >= split_y)
|
||||
oy = -oy;
|
||||
}
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx,
|
||||
int32_t dy) {
|
||||
uint32_t tag = m->pertag->curtag;
|
||||
DwindleNode *leaf = dwindle_find_leaf(m->pertag->dwindle_root[tag], c);
|
||||
if (!leaf)
|
||||
return;
|
||||
|
||||
DwindleNode *h_node = NULL;
|
||||
DwindleNode *v_node = NULL;
|
||||
DwindleNode *node = leaf->parent;
|
||||
|
||||
while (node) {
|
||||
if (node->split_h && !h_node)
|
||||
h_node = node;
|
||||
if (!node->split_h && !v_node)
|
||||
v_node = node;
|
||||
if (h_node && v_node)
|
||||
break;
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
if (!h_node && !v_node)
|
||||
return;
|
||||
|
||||
if (h_node && dx) {
|
||||
float cw = (float)MAX(1, h_node->container_w);
|
||||
float delta = (float)dx / cw;
|
||||
h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f);
|
||||
}
|
||||
|
||||
if (v_node && dy) {
|
||||
float ch = (float)MAX(1, v_node->container_h);
|
||||
float delta = (float)dy / ch;
|
||||
v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f);
|
||||
}
|
||||
|
||||
int32_t n_clients = 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_clients == 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);
|
||||
}
|
||||
|
||||
static void dwindle_remove_client(Client *c) {
|
||||
Monitor *m;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
for (uint32_t t = 0; t < LENGTH(tags) + 1; t++)
|
||||
dwindle_remove(&m->pertag->dwindle_root[t], c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert a new client respecting dwindle_vsplit, dwindle_hsplit, and
|
||||
* dwindle_smart_split config options. */
|
||||
static void dwindle_insert_with_config(DwindleNode **root, Client *new_c,
|
||||
Client *focused, float ratio) {
|
||||
bool as_first = false;
|
||||
bool split_h = false;
|
||||
bool lock = false;
|
||||
|
||||
if (focused) {
|
||||
struct wlr_box *fg = &focused->geom;
|
||||
double fcx = fg->x + fg->width * 0.5;
|
||||
double fcy = fg->y + fg->height * 0.5;
|
||||
|
||||
if (config.dwindle_smart_split) {
|
||||
double nx = (cursor->x - fcx) / (fg->width * 0.5);
|
||||
double ny = (cursor->y - fcy) / (fg->height * 0.5);
|
||||
|
||||
if (fabs(ny) > fabs(nx)) {
|
||||
split_h = false; // vertical split
|
||||
as_first = (ny < 0); // top → new window on top
|
||||
} else {
|
||||
split_h = true; // horizontal split
|
||||
as_first = (nx < 0); // left → new window on left
|
||||
}
|
||||
lock = true; // lock split direction
|
||||
} else {
|
||||
// normal mode, auto split
|
||||
bool likely_h = (fg->width >= fg->height);
|
||||
if (likely_h) {
|
||||
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, split_h, lock);
|
||||
}
|
||||
|
||||
void dwindle(Monitor *m) {
|
||||
int32_t n = m->visible_tiling_clients;
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
uint32_t tag = m->pertag->curtag;
|
||||
DwindleNode **root = &m->pertag->dwindle_root[tag];
|
||||
float ratio = config.dwindle_split_ratio;
|
||||
|
||||
Client *vis[512];
|
||||
int32_t count = 0;
|
||||
Client *c;
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (VISIBLEON(c, m) && ISTILED(c))
|
||||
vis[count++] = c;
|
||||
if (count >= 512)
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
DwindleNode *leaves[512];
|
||||
int32_t lc = 0;
|
||||
|
||||
DwindleNode *stack[1024];
|
||||
int32_t sp = 0;
|
||||
if (*root)
|
||||
stack[sp++] = *root;
|
||||
while (sp > 0) {
|
||||
DwindleNode *nd = stack[--sp];
|
||||
if (!nd->is_split) {
|
||||
leaves[lc++] = nd;
|
||||
} else {
|
||||
if (nd->second)
|
||||
stack[sp++] = nd->second;
|
||||
if (nd->first)
|
||||
stack[sp++] = nd->first;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < lc; i++) {
|
||||
bool found = false;
|
||||
for (int32_t j = 0; j < count; j++)
|
||||
if (vis[j] == leaves[i]->client) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
dwindle_remove(root, leaves[i]->client);
|
||||
}
|
||||
}
|
||||
|
||||
Client *focused = focustop(m);
|
||||
if (focused && !dwindle_find_leaf(*root, focused))
|
||||
focused = m->sel;
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
if (!dwindle_find_leaf(*root, vis[i]))
|
||||
dwindle_insert_with_config(root, vis[i], focused, ratio);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
dwindle_assign(*root, 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);
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ static void vertical_grid(Monitor *m);
|
|||
static void vertical_scroller(Monitor *m);
|
||||
static void vertical_deck(Monitor *mon);
|
||||
static void tgmix(Monitor *m);
|
||||
static void dwindle(Monitor *m);
|
||||
|
||||
/* layout(s) */
|
||||
Layout overviewlayout = {"", overview, "overview"};
|
||||
|
|
@ -29,6 +30,7 @@ enum {
|
|||
VERTICAL_DECK,
|
||||
RIGHT_TILE,
|
||||
TGMIX,
|
||||
DWINDLE,
|
||||
};
|
||||
|
||||
Layout layouts[] = {
|
||||
|
|
@ -47,4 +49,5 @@ Layout layouts[] = {
|
|||
{"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局
|
||||
{"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局
|
||||
{"TG", tgmix, "tgmix", TGMIX}, // 混合布局
|
||||
{"DW", dwindle, "dwindle", DWINDLE},
|
||||
};
|
||||
54
src/mango.c
54
src/mango.c
|
|
@ -570,6 +570,7 @@ struct capture_session_tracker {
|
|||
struct wl_listener session_destroy;
|
||||
struct wlr_ext_image_copy_capture_session_v1 *session;
|
||||
};
|
||||
typedef struct DwindleNode DwindleNode;
|
||||
|
||||
/* function declarations */
|
||||
static void applybounds(
|
||||
|
|
@ -827,6 +828,11 @@ static void client_pending_maximized_state(Client *c, int32_t ismaximized);
|
|||
static void client_pending_minimized_state(Client *c, int32_t isminimized);
|
||||
static void scroller_insert_stack(Client *c, Client *target_client,
|
||||
bool insert_before);
|
||||
static void dwindle_move_client(DwindleNode **root, Client *c, Client *target,
|
||||
float ratio, int32_t dir);
|
||||
static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx,
|
||||
int32_t dy);
|
||||
static void dwindle_resize_client(Monitor *m, Client *c);
|
||||
|
||||
#include "data/static_keymap.h"
|
||||
#include "dispatch/bind_declare.h"
|
||||
|
|
@ -965,6 +971,7 @@ struct Pertag {
|
|||
int32_t no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
|
||||
int32_t no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
|
||||
int32_t open_as_floating[LENGTH(tags) + 1]; /* open_as_floating per tag */
|
||||
struct DwindleNode *dwindle_root[LENGTH(tags) + 1];
|
||||
const Layout
|
||||
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
|
||||
};
|
||||
|
|
@ -1039,6 +1046,7 @@ static struct wl_event_source *sync_keymap;
|
|||
#include "ext-protocol/all.h"
|
||||
#include "fetch/fetch.h"
|
||||
#include "layout/arrange.h"
|
||||
#include "layout/dwindle.h"
|
||||
#include "layout/horizontal.h"
|
||||
#include "layout/vertical.h"
|
||||
|
||||
|
|
@ -1200,6 +1208,17 @@ void swallow(Client *c, Client *w) {
|
|||
client_pending_fullscreen_state(c, w->isfullscreen);
|
||||
client_pending_maximized_state(c, w->ismaximizescreen);
|
||||
client_pending_minimized_state(c, w->isminimized);
|
||||
|
||||
Monitor *m;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
for (uint32_t t = 0; t < LENGTH(tags) + 1; t++) {
|
||||
DwindleNode **root = &m->pertag->dwindle_root[t];
|
||||
dwindle_remove(root, c);
|
||||
DwindleNode *wn = dwindle_find_leaf(*root, w);
|
||||
if (wn)
|
||||
wn->client = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_scratchpad_client_state(Client *c) {
|
||||
|
|
@ -2085,6 +2104,13 @@ Client *find_closest_tiled_client(Client *c) {
|
|||
if (tc == c || !ISTILED(tc) || !VISIBLEON(tc, c->mon))
|
||||
continue;
|
||||
|
||||
if (cursor->x >= tc->geom.x &&
|
||||
cursor->x < tc->geom.x + tc->geom.width &&
|
||||
cursor->y >= tc->geom.y &&
|
||||
cursor->y < tc->geom.y + tc->geom.height) {
|
||||
return tc;
|
||||
}
|
||||
|
||||
int32_t dx = tc->geom.x + (int32_t)(tc->geom.width / 2) - cursor->x;
|
||||
int32_t dy = tc->geom.y + (int32_t)(tc->geom.height / 2) - cursor->y;
|
||||
long dist = (long)dx * dx + (long)dy * dy;
|
||||
|
|
@ -2200,8 +2226,8 @@ void place_drag_tile_client(Client *c) {
|
|||
closest->mon->pertag->ltidxs[closest->mon->pertag->curtag];
|
||||
|
||||
if (closest->drop_direction == UNDIR) {
|
||||
exchange_two_client(c, closest);
|
||||
setfloating(c, 0);
|
||||
exchange_two_client(c, closest);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2213,6 +2239,18 @@ void place_drag_tile_client(Client *c) {
|
|||
try_scroller_drop(c, closest, 1);
|
||||
return;
|
||||
}
|
||||
if (layout->id == DWINDLE) {
|
||||
uint32_t tag = c->mon->pertag->curtag;
|
||||
bool insert_before = (closest->drop_direction == LEFT ||
|
||||
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,
|
||||
config.dwindle_split_ratio, insert_before, split_h,
|
||||
true);
|
||||
setfloating(c, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (closest->drop_direction == LEFT || closest->drop_direction == UP) {
|
||||
wl_list_remove(&c->link);
|
||||
|
|
@ -2525,6 +2563,9 @@ void cleanupmon(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
|
||||
m->wlr_output->data = NULL;
|
||||
|
||||
for (uint32_t t = 0; t < LENGTH(tags) + 1; t++)
|
||||
dwindle_free_tree(m->pertag->dwindle_root[t]);
|
||||
free(m->pertag);
|
||||
free(m);
|
||||
}
|
||||
|
|
@ -5101,10 +5142,20 @@ void exchange_two_client(Client *c1, Client *c2) {
|
|||
tmp_tags = c2->tags;
|
||||
setmon(c2, c1->mon, c1->tags, false);
|
||||
setmon(c1, tmp_mon, tmp_tags, false);
|
||||
if (c1->mon &&
|
||||
c1->mon->pertag->ltidxs[c1->mon->pertag->curtag]->id == DWINDLE)
|
||||
dwindle_swap_clients(
|
||||
&c1->mon->pertag->dwindle_root[c1->mon->pertag->curtag], c1,
|
||||
c2);
|
||||
arrange(c1->mon, false, false);
|
||||
arrange(c2->mon, false, false);
|
||||
focusclient(c1, 0);
|
||||
} else {
|
||||
if (c1->mon &&
|
||||
c1->mon->pertag->ltidxs[c1->mon->pertag->curtag]->id == DWINDLE)
|
||||
dwindle_swap_clients(
|
||||
&c1->mon->pertag->dwindle_root[c1->mon->pertag->curtag], c1,
|
||||
c2);
|
||||
arrange(c1->mon, false, false);
|
||||
}
|
||||
|
||||
|
|
@ -6365,6 +6416,7 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
c->next_in_stack = NULL;
|
||||
c->prev_in_stack = NULL;
|
||||
|
||||
dwindle_remove_client(c);
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
printstatus();
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue