mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-05-26 21:37:31 -04:00
feat: manual split
This commit is contained in:
parent
2723e50a90
commit
d9b906d276
7 changed files with 382 additions and 54 deletions
|
|
@ -100,6 +100,7 @@ borderpx=4
|
||||||
rootcolor=0x201b14ff
|
rootcolor=0x201b14ff
|
||||||
bordercolor=0x444444ff
|
bordercolor=0x444444ff
|
||||||
dropcolor=0x8FBA7C55
|
dropcolor=0x8FBA7C55
|
||||||
|
splitcolor=0xEB441EFF
|
||||||
focuscolor=0xc9b890ff
|
focuscolor=0xc9b890ff
|
||||||
maximizescreencolor=0x89aa61ff
|
maximizescreencolor=0x89aa61ff
|
||||||
urgentcolor=0xad401fff
|
urgentcolor=0xad401fff
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "wlr/util/log.h"
|
||||||
void client_actual_size(Client *c, int32_t *width, int32_t *height) {
|
void client_actual_size(Client *c, int32_t *width, int32_t *height) {
|
||||||
*width = c->animation.current.width - 2 * (int32_t)c->bw;
|
*width = c->animation.current.width - 2 * (int32_t)c->bw;
|
||||||
|
|
||||||
|
|
@ -245,6 +246,94 @@ void apply_shield(Client *c, struct wlr_box clip_box) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply_split_border(Client *c, bool hit_no_border) {
|
||||||
|
|
||||||
|
if (c->iskilling || !client_surface(c)->mapped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Layout *layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag];
|
||||||
|
|
||||||
|
if (hit_no_border || layout->id != DWINDLE ||
|
||||||
|
!config.dwindle_manual_split) {
|
||||||
|
if (c->splitindicator[0]->node.enabled) {
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
|
||||||
|
}
|
||||||
|
if (c->splitindicator[1]->node.enabled) {
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
DwindleNode **root =
|
||||||
|
&c->mon->pertag->dwindle_root[c->mon->pertag->curtag];
|
||||||
|
DwindleNode *dnode = dwindle_find_leaf(*root, c);
|
||||||
|
|
||||||
|
if (!dnode) {
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (dnode->custom_leaf_split_h) {
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[1]->node, true);
|
||||||
|
} else {
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, true);
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box fullgeom = c->animation.current;
|
||||||
|
// 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错
|
||||||
|
int32_t bw = (int32_t)c->bw;
|
||||||
|
|
||||||
|
int32_t right_offset, bottom_offset, left_offset, top_offset;
|
||||||
|
|
||||||
|
if (c == grabc) {
|
||||||
|
right_offset = 0;
|
||||||
|
bottom_offset = 0;
|
||||||
|
left_offset = 0;
|
||||||
|
top_offset = 0;
|
||||||
|
} else {
|
||||||
|
right_offset =
|
||||||
|
GEZERO(c->animation.current.x + c->animation.current.width -
|
||||||
|
c->mon->m.x - c->mon->m.width);
|
||||||
|
bottom_offset =
|
||||||
|
GEZERO(c->animation.current.y + c->animation.current.height -
|
||||||
|
c->mon->m.y - c->mon->m.height);
|
||||||
|
|
||||||
|
left_offset = GEZERO(c->mon->m.x - c->animation.current.x);
|
||||||
|
top_offset = GEZERO(c->mon->m.y - c->animation.current.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t border_down_width = GEZERO(fullgeom.width - left_offset -
|
||||||
|
right_offset - 2 * config.border_radius);
|
||||||
|
int32_t border_down_height =
|
||||||
|
GEZERO(bw - bottom_offset - GEZERO(top_offset + bw - fullgeom.height));
|
||||||
|
|
||||||
|
int32_t border_right_width =
|
||||||
|
GEZERO(bw - right_offset - GEZERO(left_offset + bw - fullgeom.width));
|
||||||
|
int32_t border_right_height =
|
||||||
|
GEZERO(fullgeom.height - top_offset - bottom_offset -
|
||||||
|
2 * config.border_radius);
|
||||||
|
|
||||||
|
int32_t border_down_x = GEZERO(config.border_radius - left_offset);
|
||||||
|
int32_t border_down_y = GEZERO(fullgeom.height - bw) +
|
||||||
|
GEZERO(top_offset + bw - fullgeom.height);
|
||||||
|
|
||||||
|
int32_t border_right_x =
|
||||||
|
GEZERO(fullgeom.width - bw) + GEZERO(left_offset + bw - fullgeom.width);
|
||||||
|
int32_t border_right_y = GEZERO(config.border_radius - top_offset);
|
||||||
|
|
||||||
|
set_rect_size(c->splitindicator[0], border_down_width, border_down_height);
|
||||||
|
set_rect_size(c->splitindicator[1], border_right_width,
|
||||||
|
border_right_height);
|
||||||
|
wlr_scene_node_set_position(&c->splitindicator[0]->node, border_down_x,
|
||||||
|
border_down_y);
|
||||||
|
wlr_scene_node_set_position(&c->splitindicator[1]->node, border_right_x,
|
||||||
|
border_right_y);
|
||||||
|
}
|
||||||
|
|
||||||
void apply_border(Client *c) {
|
void apply_border(Client *c) {
|
||||||
bool hit_no_border = false;
|
bool hit_no_border = false;
|
||||||
|
|
||||||
|
|
@ -253,6 +342,8 @@ void apply_border(Client *c) {
|
||||||
|
|
||||||
hit_no_border = check_hit_no_border(c);
|
hit_no_border = check_hit_no_border(c);
|
||||||
|
|
||||||
|
apply_split_border(c, hit_no_border);
|
||||||
|
|
||||||
if (hit_no_border && config.smartgaps) {
|
if (hit_no_border && config.smartgaps) {
|
||||||
c->bw = 0;
|
c->bw = 0;
|
||||||
c->fake_no_border = true;
|
c->fake_no_border = true;
|
||||||
|
|
@ -1100,6 +1191,7 @@ bool client_draw_fadeout_frame(Client *c) {
|
||||||
|
|
||||||
void client_set_focused_opacity_animation(Client *c) {
|
void client_set_focused_opacity_animation(Client *c) {
|
||||||
float *border_color = get_border_color(c);
|
float *border_color = get_border_color(c);
|
||||||
|
wlr_scene_node_lower_to_bottom(&c->border->node);
|
||||||
|
|
||||||
if (!config.animations) {
|
if (!config.animations) {
|
||||||
setborder_color(c);
|
setborder_color(c);
|
||||||
|
|
@ -1121,7 +1213,7 @@ void client_set_focused_opacity_animation(Client *c) {
|
||||||
|
|
||||||
void client_set_unfocused_opacity_animation(Client *c) {
|
void client_set_unfocused_opacity_animation(Client *c) {
|
||||||
float *border_color = get_border_color(c);
|
float *border_color = get_border_color(c);
|
||||||
|
wlr_scene_node_raise_to_top(&c->border->node);
|
||||||
if (!config.animations) {
|
if (!config.animations) {
|
||||||
setborder_color(c);
|
setborder_color(c);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ typedef struct {
|
||||||
int32_t dwindle_smart_split;
|
int32_t dwindle_smart_split;
|
||||||
int32_t dwindle_smart_resize;
|
int32_t dwindle_smart_resize;
|
||||||
int32_t dwindle_drop_simple_split;
|
int32_t dwindle_drop_simple_split;
|
||||||
|
int32_t dwindle_manual_split;
|
||||||
float dwindle_split_ratio;
|
float dwindle_split_ratio;
|
||||||
|
|
||||||
uint32_t hotarea_size;
|
uint32_t hotarea_size;
|
||||||
|
|
@ -305,6 +306,7 @@ typedef struct {
|
||||||
float rootcolor[4];
|
float rootcolor[4];
|
||||||
float bordercolor[4];
|
float bordercolor[4];
|
||||||
float dropcolor[4];
|
float dropcolor[4];
|
||||||
|
float splitcolor[4];
|
||||||
float focuscolor[4];
|
float focuscolor[4];
|
||||||
float maximizescreencolor[4];
|
float maximizescreencolor[4];
|
||||||
float urgentcolor[4];
|
float urgentcolor[4];
|
||||||
|
|
@ -1201,6 +1203,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
|
||||||
(*arg).i = parse_direction(arg_value);
|
(*arg).i = parse_direction(arg_value);
|
||||||
} else if (strcmp(func_name, "toggle_all_floating") == 0) {
|
} else if (strcmp(func_name, "toggle_all_floating") == 0) {
|
||||||
func = toggle_all_floating;
|
func = toggle_all_floating;
|
||||||
|
} else if (strcmp(func_name, "dwindle_toggle_split_direction") == 0) {
|
||||||
|
func = dwindle_toggle_split_direction;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1578,6 +1582,8 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
config->dwindle_smart_resize = atoi(value);
|
config->dwindle_smart_resize = atoi(value);
|
||||||
} else if (strcmp(key, "dwindle_drop_simple_split") == 0) {
|
} else if (strcmp(key, "dwindle_drop_simple_split") == 0) {
|
||||||
config->dwindle_drop_simple_split = atoi(value);
|
config->dwindle_drop_simple_split = atoi(value);
|
||||||
|
} else if (strcmp(key, "dwindle_manual_split") == 0) {
|
||||||
|
config->dwindle_manual_split = atoi(value);
|
||||||
} else if (strcmp(key, "dwindle_split_ratio") == 0) {
|
} else if (strcmp(key, "dwindle_split_ratio") == 0) {
|
||||||
config->dwindle_split_ratio = atof(value);
|
config->dwindle_split_ratio = atof(value);
|
||||||
} else if (strcmp(key, "hotarea_size") == 0) {
|
} else if (strcmp(key, "hotarea_size") == 0) {
|
||||||
|
|
@ -1709,6 +1715,17 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
} else {
|
} else {
|
||||||
convert_hex_to_rgba(config->dropcolor, color);
|
convert_hex_to_rgba(config->dropcolor, color);
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(key, "splitcolor") == 0) {
|
||||||
|
int64_t color = parse_color(value);
|
||||||
|
if (color == -1) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"\033[1m\033[31m[ERROR]:\033[33m Invalid splitcolor "
|
||||||
|
"format: %s\n",
|
||||||
|
value);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
convert_hex_to_rgba(config->splitcolor, color);
|
||||||
|
}
|
||||||
} else if (strcmp(key, "focuscolor") == 0) {
|
} else if (strcmp(key, "focuscolor") == 0) {
|
||||||
int64_t color = parse_color(value);
|
int64_t color = parse_color(value);
|
||||||
if (color == -1) {
|
if (color == -1) {
|
||||||
|
|
@ -3122,6 +3139,7 @@ void override_config(void) {
|
||||||
config.dwindle_smart_resize = CLAMP_INT(config.dwindle_smart_resize, 0, 1);
|
config.dwindle_smart_resize = CLAMP_INT(config.dwindle_smart_resize, 0, 1);
|
||||||
config.dwindle_drop_simple_split =
|
config.dwindle_drop_simple_split =
|
||||||
CLAMP_INT(config.dwindle_drop_simple_split, 0, 1);
|
CLAMP_INT(config.dwindle_drop_simple_split, 0, 1);
|
||||||
|
config.dwindle_manual_split = CLAMP_INT(config.dwindle_manual_split, 0, 1);
|
||||||
config.dwindle_split_ratio =
|
config.dwindle_split_ratio =
|
||||||
CLAMP_FLOAT(config.dwindle_split_ratio, 0.05f, 0.95f);
|
CLAMP_FLOAT(config.dwindle_split_ratio, 0.05f, 0.95f);
|
||||||
config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
|
config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
|
||||||
|
|
@ -3244,6 +3262,7 @@ void set_value_default() {
|
||||||
config.dwindle_smart_split = 0;
|
config.dwindle_smart_split = 0;
|
||||||
config.dwindle_smart_resize = 0;
|
config.dwindle_smart_resize = 0;
|
||||||
config.dwindle_drop_simple_split = 1;
|
config.dwindle_drop_simple_split = 1;
|
||||||
|
config.dwindle_manual_split = 0;
|
||||||
config.dwindle_split_ratio = 0.5f;
|
config.dwindle_split_ratio = 0.5f;
|
||||||
|
|
||||||
config.log_level = WLR_ERROR;
|
config.log_level = WLR_ERROR;
|
||||||
|
|
@ -3367,10 +3386,14 @@ void set_value_default() {
|
||||||
config.bordercolor[1] = 0x44 / 255.0f;
|
config.bordercolor[1] = 0x44 / 255.0f;
|
||||||
config.bordercolor[2] = 0x44 / 255.0f;
|
config.bordercolor[2] = 0x44 / 255.0f;
|
||||||
config.bordercolor[3] = 1.0f;
|
config.bordercolor[3] = 1.0f;
|
||||||
config.dropcolor[0] = 0x8f / 255.0f;
|
config.dropcolor[0] = 0xd5 / 255.0f;
|
||||||
config.dropcolor[1] = 0xba / 255.0f;
|
config.dropcolor[1] = 0x89 / 255.0f;
|
||||||
config.dropcolor[2] = 0x7c / 255.0f;
|
config.dropcolor[2] = 0x9d / 255.0f;
|
||||||
config.dropcolor[3] = 0.5f;
|
config.dropcolor[3] = 0.5f;
|
||||||
|
config.splitcolor[0] = 0xeb / 255.0f;
|
||||||
|
config.splitcolor[1] = 0x44 / 255.0f;
|
||||||
|
config.splitcolor[2] = 0x1e / 255.0f;
|
||||||
|
config.splitcolor[3] = 1.0f;
|
||||||
config.focuscolor[0] = 0xc6 / 255.0f;
|
config.focuscolor[0] = 0xc6 / 255.0f;
|
||||||
config.focuscolor[1] = 0x6b / 255.0f;
|
config.focuscolor[1] = 0x6b / 255.0f;
|
||||||
config.focuscolor[2] = 0x25 / 255.0f;
|
config.focuscolor[2] = 0x25 / 255.0f;
|
||||||
|
|
@ -3604,6 +3627,8 @@ void reapply_property(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_scene_rect_set_color(c->droparea, config.dropcolor);
|
wlr_scene_rect_set_color(c->droparea, config.dropcolor);
|
||||||
|
wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor);
|
||||||
|
wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,3 +71,4 @@ int32_t enable_monitor(const Arg *arg);
|
||||||
int32_t toggle_monitor(const Arg *arg);
|
int32_t toggle_monitor(const Arg *arg);
|
||||||
int32_t scroller_stack(const Arg *arg);
|
int32_t scroller_stack(const Arg *arg);
|
||||||
int32_t toggle_all_floating(const Arg *arg);
|
int32_t toggle_all_floating(const Arg *arg);
|
||||||
|
int32_t dwindle_toggle_split_direction(const Arg *arg);
|
||||||
|
|
@ -1918,3 +1918,28 @@ int32_t toggle_all_floating(const Arg *arg) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t dwindle_toggle_split_direction(const Arg *arg) {
|
||||||
|
if (!selmon || !selmon->sel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Client *c = selmon->sel;
|
||||||
|
if (!c || !c->mon || c->isfloating)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const Layout *layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag];
|
||||||
|
|
||||||
|
if (layout->id != DWINDLE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DwindleNode **root = &selmon->pertag->dwindle_root[selmon->pertag->curtag];
|
||||||
|
DwindleNode *leaf = dwindle_find_leaf(*root, c);
|
||||||
|
|
||||||
|
if (!leaf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
leaf->custom_leaf_split_h = !leaf->custom_leaf_split_h;
|
||||||
|
bool hit_no_border = check_hit_no_border(c);
|
||||||
|
apply_split_border(c, hit_no_border);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,3 @@
|
||||||
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_h_node = NULL;
|
||||||
static DwindleNode *dwindle_locked_v_node = NULL;
|
static DwindleNode *dwindle_locked_v_node = NULL;
|
||||||
|
|
||||||
|
|
@ -24,6 +7,39 @@ static DwindleNode *dwindle_new_leaf(Client *c) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统计同方向上的节点总和 (N_old)
|
||||||
|
static int count_block_items(DwindleNode *node, bool split_h) {
|
||||||
|
if (!node)
|
||||||
|
return 0;
|
||||||
|
if (!node->is_split || node->split_h != split_h)
|
||||||
|
return 1;
|
||||||
|
return count_block_items(node->first, split_h) +
|
||||||
|
count_block_items(node->second, split_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向上查找方向块路径,并计算每个祖先节点的绝对占比
|
||||||
|
static int get_block_path_and_ratios(DwindleNode *target, bool split_h,
|
||||||
|
DwindleNode **path, float *p) {
|
||||||
|
int path_len = 0;
|
||||||
|
path[path_len++] = target;
|
||||||
|
DwindleNode *curr = target->parent;
|
||||||
|
while (curr && curr->split_h == split_h) {
|
||||||
|
path[path_len++] = curr;
|
||||||
|
curr = curr->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
p[path_len - 1] = 1.0f; // 方向块根节点占比为 100%
|
||||||
|
for (int i = path_len - 1; i > 0; i--) {
|
||||||
|
DwindleNode *S = path[i];
|
||||||
|
DwindleNode *child = path[i - 1];
|
||||||
|
if (S->first == child)
|
||||||
|
p[i - 1] = p[i] * S->ratio;
|
||||||
|
else
|
||||||
|
p[i - 1] = p[i] * (1.0f - S->ratio);
|
||||||
|
}
|
||||||
|
return path_len;
|
||||||
|
}
|
||||||
|
|
||||||
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c) {
|
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c) {
|
||||||
if (!node)
|
if (!node)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -55,6 +71,7 @@ static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
|
||||||
DwindleNode *new_leaf = dwindle_new_leaf(new_c);
|
DwindleNode *new_leaf = dwindle_new_leaf(new_c);
|
||||||
|
|
||||||
if (!*root) {
|
if (!*root) {
|
||||||
|
new_leaf->custom_leaf_split_h = true;
|
||||||
*root = new_leaf;
|
*root = new_leaf;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -63,11 +80,45 @@ static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
|
||||||
if (!target)
|
if (!target)
|
||||||
target = dwindle_first_leaf(*root);
|
target = dwindle_first_leaf(*root);
|
||||||
|
|
||||||
|
// ================= 保持其他窗口比例缩减逻辑 =================
|
||||||
|
DwindleNode *path[128];
|
||||||
|
float p[128];
|
||||||
|
int path_len = get_block_path_and_ratios(target, split_h, path, p);
|
||||||
|
|
||||||
|
int n_old = 1;
|
||||||
|
if (path_len > 1) {
|
||||||
|
n_old = count_block_items(path[path_len - 1], split_h);
|
||||||
|
}
|
||||||
|
float N = (float)(n_old + 1);
|
||||||
|
|
||||||
|
for (int i = path_len - 1; i > 0; i--) {
|
||||||
|
DwindleNode *S = path[i];
|
||||||
|
DwindleNode *child = path[i - 1];
|
||||||
|
float p_S = p[i];
|
||||||
|
float p_first = p_S * S->ratio;
|
||||||
|
|
||||||
|
if (S->first == child) {
|
||||||
|
float p_first_new = p_first * (N - 1.0f) / N + 1.0f / N;
|
||||||
|
float p_S_new = p_S * (N - 1.0f) / N + 1.0f / N;
|
||||||
|
S->ratio = p_first_new / p_S_new;
|
||||||
|
} else {
|
||||||
|
float p_first_new = p_first * (N - 1.0f) / N;
|
||||||
|
float p_S_new = p_S * (N - 1.0f) / N + 1.0f / N;
|
||||||
|
S->ratio = p_first_new / p_S_new;
|
||||||
|
}
|
||||||
|
if (S->ratio < 0.001f)
|
||||||
|
S->ratio = 0.001f;
|
||||||
|
if (S->ratio > 0.999f)
|
||||||
|
S->ratio = 0.999f;
|
||||||
|
}
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
DwindleNode *split = calloc(1, sizeof(DwindleNode));
|
DwindleNode *split = calloc(1, sizeof(DwindleNode));
|
||||||
split->is_split = true;
|
split->is_split = true;
|
||||||
split->ratio = ratio;
|
|
||||||
split->split_h = split_h;
|
split->split_h = split_h;
|
||||||
split->split_locked = lock;
|
split->split_locked = lock;
|
||||||
|
split->custom_leaf_split_h = target->custom_leaf_split_h;
|
||||||
|
new_leaf->custom_leaf_split_h = target->custom_leaf_split_h;
|
||||||
|
|
||||||
if (as_first) {
|
if (as_first) {
|
||||||
split->first = new_leaf;
|
split->first = new_leaf;
|
||||||
|
|
@ -76,6 +127,10 @@ static void dwindle_insert(DwindleNode **root, Client *new_c, Client *focused,
|
||||||
split->first = target;
|
split->first = target;
|
||||||
split->second = new_leaf;
|
split->second = new_leaf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通用逻辑
|
||||||
|
split->ratio = ratio;
|
||||||
|
|
||||||
split->parent = target->parent;
|
split->parent = target->parent;
|
||||||
target->parent = split;
|
target->parent = split;
|
||||||
new_leaf->parent = split;
|
new_leaf->parent = split;
|
||||||
|
|
@ -102,12 +157,69 @@ static void dwindle_remove(DwindleNode **root, Client *c) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开始删除空间的比例回退逻辑
|
||||||
|
|
||||||
|
// 查找连续的同方向块路径
|
||||||
|
bool split_h = parent->split_h;
|
||||||
|
DwindleNode *path[128];
|
||||||
|
int path_len = 0;
|
||||||
|
path[path_len++] = parent;
|
||||||
|
DwindleNode *curr = parent->parent;
|
||||||
|
while (curr && curr->split_h == split_h) {
|
||||||
|
path[path_len++] = curr;
|
||||||
|
curr = curr->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算各祖先的旧绝对占比
|
||||||
|
float p[128];
|
||||||
|
p[path_len - 1] = 1.0f;
|
||||||
|
for (int i = path_len - 1; i > 0; i--) {
|
||||||
|
DwindleNode *S = path[i];
|
||||||
|
DwindleNode *child = path[i - 1];
|
||||||
|
if (S->first == child)
|
||||||
|
p[i - 1] = p[i] * S->ratio;
|
||||||
|
else
|
||||||
|
p[i - 1] = p[i] * (1.0f - S->ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算即将被删除的叶子节点,在该方向块中所占的绝对面积比例 (P_del)
|
||||||
|
float p_del =
|
||||||
|
p[0] * (parent->first == leaf ? parent->ratio : (1.0f - parent->ratio));
|
||||||
|
if (p_del > 0.999f)
|
||||||
|
p_del = 0.999f; // 兜底
|
||||||
|
|
||||||
|
// 重算祖先比例:将 P_del 空出来的空间,按原定比例无缝分配给其他窗口
|
||||||
|
for (int i = path_len - 1; i > 0; i--) {
|
||||||
|
DwindleNode *S = path[i];
|
||||||
|
DwindleNode *child = path[i - 1];
|
||||||
|
float p_S = p[i];
|
||||||
|
float p_first = p_S * S->ratio;
|
||||||
|
|
||||||
|
float denom = p_S - p_del;
|
||||||
|
if (denom < 0.0001f)
|
||||||
|
denom = 0.0001f;
|
||||||
|
|
||||||
|
if (S->first == child) {
|
||||||
|
S->ratio = (p_first - p_del) / denom;
|
||||||
|
} else {
|
||||||
|
S->ratio = p_first / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S->ratio < 0.001f)
|
||||||
|
S->ratio = 0.001f;
|
||||||
|
if (S->ratio > 0.999f)
|
||||||
|
S->ratio = 0.999f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比例重算结束
|
||||||
|
|
||||||
|
// 基础的二叉树摘除节点逻辑
|
||||||
DwindleNode *sibling =
|
DwindleNode *sibling =
|
||||||
(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;
|
||||||
|
|
||||||
/* Preserve split direction on sibling split-nodes when requested. */
|
|
||||||
if (!sibling->is_split ||
|
if (!sibling->is_split ||
|
||||||
(!config.dwindle_preserve_split && !config.dwindle_smart_split)) {
|
(!config.dwindle_preserve_split && !config.dwindle_smart_split)) {
|
||||||
sibling->container_w = 0;
|
sibling->container_w = 0;
|
||||||
|
|
@ -319,11 +431,14 @@ static void dwindle_remove_client(Client *c) {
|
||||||
* dwindle_smart_split config options. */
|
* dwindle_smart_split config options. */
|
||||||
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) {
|
||||||
|
|
||||||
|
if (!new_c || !focused)
|
||||||
|
return;
|
||||||
|
|
||||||
bool as_first = false;
|
bool as_first = false;
|
||||||
bool split_h = false;
|
bool split_h = false;
|
||||||
bool lock = false;
|
bool lock = false;
|
||||||
|
|
||||||
if (focused) {
|
|
||||||
struct wlr_box *fg = &focused->geom;
|
struct wlr_box *fg = &focused->geom;
|
||||||
double fcx = fg->x + fg->width * 0.5;
|
double fcx = fg->x + fg->width * 0.5;
|
||||||
double fcy = fg->y + fg->height * 0.5;
|
double fcy = fg->y + fg->height * 0.5;
|
||||||
|
|
@ -333,15 +448,14 @@ static void dwindle_insert_with_config(DwindleNode **root, Client *new_c,
|
||||||
double ny = (cursor->y - fcy) / (fg->height * 0.5);
|
double ny = (cursor->y - fcy) / (fg->height * 0.5);
|
||||||
|
|
||||||
if (fabs(ny) > fabs(nx)) {
|
if (fabs(ny) > fabs(nx)) {
|
||||||
split_h = false; // vertical split
|
split_h = false;
|
||||||
as_first = (ny < 0); // top → new window on top
|
as_first = (ny < 0);
|
||||||
} else {
|
} else {
|
||||||
split_h = true; // horizontal split
|
split_h = true;
|
||||||
as_first = (nx < 0); // left → new window on left
|
as_first = (nx < 0);
|
||||||
}
|
}
|
||||||
lock = true; // lock split direction
|
lock = true;
|
||||||
} else {
|
} else {
|
||||||
// normal mode, auto split
|
|
||||||
bool likely_h = (fg->width >= fg->height);
|
bool likely_h = (fg->width >= fg->height);
|
||||||
if (likely_h) {
|
if (likely_h) {
|
||||||
if (config.dwindle_hsplit == 0)
|
if (config.dwindle_hsplit == 0)
|
||||||
|
|
@ -354,10 +468,50 @@ static void dwindle_insert_with_config(DwindleNode **root, Client *new_c,
|
||||||
else
|
else
|
||||||
as_first = (config.dwindle_vsplit == 2);
|
as_first = (config.dwindle_vsplit == 2);
|
||||||
}
|
}
|
||||||
// split_h and lock are false, decided by width/height ratio
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DwindleNode *target = focused ? dwindle_find_leaf(*root, focused) : NULL;
|
||||||
|
// 防止极端情况下找不到 target
|
||||||
|
if (!target && *root)
|
||||||
|
target = dwindle_first_leaf(*root);
|
||||||
|
|
||||||
|
// 计算 1/N 比例
|
||||||
|
if (config.dwindle_manual_split && target) {
|
||||||
|
split_h = target->custom_leaf_split_h;
|
||||||
|
lock = true;
|
||||||
|
as_first = false;
|
||||||
|
|
||||||
|
// ================= 计算新节点的 1/N 比例 =================
|
||||||
|
DwindleNode *path[128];
|
||||||
|
float p[128];
|
||||||
|
int path_len = get_block_path_and_ratios(target, split_h, path, p);
|
||||||
|
|
||||||
|
int n_old = 1;
|
||||||
|
if (path_len > 1) {
|
||||||
|
n_old = count_block_items(path[path_len - 1], split_h);
|
||||||
|
}
|
||||||
|
float N = (float)(n_old + 1);
|
||||||
|
|
||||||
|
float p_target_old = p[0];
|
||||||
|
// 算出 split 节点在方向块里总共能分到的绝对面积比例
|
||||||
|
float p_split_new = p_target_old * (N - 1.0f) / N + 1.0f / N;
|
||||||
|
|
||||||
|
// 逆推传给 dwindle_insert 的局部 ratio
|
||||||
|
if (as_first) {
|
||||||
|
ratio = (1.0f / N) / p_split_new;
|
||||||
|
} else {
|
||||||
|
ratio = (p_target_old * (N - 1.0f) / N) / p_split_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安全兜底
|
||||||
|
if (ratio < 0.001f)
|
||||||
|
ratio = 0.001f;
|
||||||
|
if (ratio > 0.999f)
|
||||||
|
ratio = 0.999f;
|
||||||
|
// =========================================================
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用通用插入函数
|
||||||
dwindle_insert(root, new_c, focused, ratio, as_first, split_h, lock);
|
dwindle_insert(root, new_c, focused, ratio, as_first, split_h, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
32
src/mango.c
32
src/mango.c
|
|
@ -314,6 +314,8 @@ struct Client {
|
||||||
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
||||||
struct wlr_scene_rect *shield;
|
struct wlr_scene_rect *shield;
|
||||||
struct wlr_scene_rect *droparea;
|
struct wlr_scene_rect *droparea;
|
||||||
|
struct wlr_scene_rect *splitindicator[4];
|
||||||
|
|
||||||
struct wlr_scene_tree *scene_surface;
|
struct wlr_scene_tree *scene_surface;
|
||||||
|
|
||||||
struct wlr_scene_tree *image_capture_tree;
|
struct wlr_scene_tree *image_capture_tree;
|
||||||
|
|
@ -571,6 +573,23 @@ struct capture_session_tracker {
|
||||||
struct wlr_ext_image_copy_capture_session_v1 *session;
|
struct wlr_ext_image_copy_capture_session_v1 *session;
|
||||||
};
|
};
|
||||||
typedef struct DwindleNode DwindleNode;
|
typedef struct DwindleNode DwindleNode;
|
||||||
|
struct DwindleNode {
|
||||||
|
bool is_split;
|
||||||
|
bool split_h;
|
||||||
|
bool split_locked;
|
||||||
|
bool custom_leaf_split_h;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
struct ScrollerStackNode {
|
struct ScrollerStackNode {
|
||||||
Client *client;
|
Client *client;
|
||||||
float scroller_proportion;
|
float scroller_proportion;
|
||||||
|
|
@ -859,6 +878,7 @@ static struct ScrollerStackNode *
|
||||||
scroller_node_create(struct TagScrollerState *st, Client *c);
|
scroller_node_create(struct TagScrollerState *st, Client *c);
|
||||||
static void update_scroller_state(Monitor *m);
|
static void update_scroller_state(Monitor *m);
|
||||||
Client *scroll_get_stack_tail_client(Client *c);
|
Client *scroll_get_stack_tail_client(Client *c);
|
||||||
|
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c);
|
||||||
|
|
||||||
#include "data/static_keymap.h"
|
#include "data/static_keymap.h"
|
||||||
#include "dispatch/bind_declare.h"
|
#include "dispatch/bind_declare.h"
|
||||||
|
|
@ -4255,7 +4275,8 @@ mapnotify(struct wl_listener *listener, void *data) {
|
||||||
/* Called when the surface is mapped, or ready to display on-screen. */
|
/* Called when the surface is mapped, or ready to display on-screen. */
|
||||||
Client *at_client = NULL;
|
Client *at_client = NULL;
|
||||||
Client *c = wl_container_of(listener, c, map);
|
Client *c = wl_container_of(listener, c, map);
|
||||||
int32_t i;
|
int32_t i = 0;
|
||||||
|
|
||||||
/* Create scene tree for this client and its border */
|
/* Create scene tree for this client and its border */
|
||||||
c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
|
c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
|
||||||
wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
|
wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
|
||||||
|
|
@ -4331,6 +4352,15 @@ mapnotify(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
// extra node
|
// extra node
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
c->splitindicator[i] = wlr_scene_rect_create(
|
||||||
|
c->scene, 0, 0,
|
||||||
|
c->isurgent ? config.urgentcolor : config.splitcolor);
|
||||||
|
c->splitindicator[i]->node.data = c;
|
||||||
|
wlr_scene_node_lower_to_bottom(&c->splitindicator[i]->node);
|
||||||
|
wlr_scene_node_set_enabled(&c->splitindicator[i]->node, false);
|
||||||
|
}
|
||||||
|
|
||||||
c->droparea = wlr_scene_rect_create(c->scene, 0, 0, config.dropcolor);
|
c->droparea = wlr_scene_rect_create(c->scene, 0, 0, config.dropcolor);
|
||||||
wlr_scene_node_lower_to_bottom(&c->droparea->node);
|
wlr_scene_node_lower_to_bottom(&c->droparea->node);
|
||||||
wlr_scene_node_set_position(&c->droparea->node, 0, 0);
|
wlr_scene_node_set_position(&c->droparea->node, 0, 0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue