From 6522e18d0839858711974f351a54fa20d3e05b68 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 13:25:24 +0800 Subject: [PATCH 01/19] opt: fix potential issues caused by uninitialization --- src/layout/arrange.h | 20 +++++++++++++++++--- src/mango.c | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 69d221d1..d674068e 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -5,6 +5,16 @@ void save_old_size_per(Monitor *m) { if (VISIBLEON(c, m) && ISTILED(c)) { c->old_master_inner_per = c->master_inner_per; c->old_stack_inner_per = c->stack_inner_per; + } else { + if (c->old_master_inner_per <= 0.0f || + c->old_master_inner_per > 1.0f) { + c->old_master_inner_per = 1.0f; + } + + if (c->old_stack_inner_per <= 0.0f || + c->old_stack_inner_per > 1.0f) { + c->old_stack_inner_per = 1.0f; + } } } } @@ -45,14 +55,16 @@ void restore_size_per(Monitor *m, Client *c) { } if (!c->ismaster && c->old_stack_inner_per < 1.0 && - c->stack_inner_per < 1.0) { + c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 && + c->stack_inner_per > 0.0f) { c->stack_inner_per = (1.0 - c->stack_inner_per) * c->old_stack_inner_per / (1.0 - c->old_stack_inner_per); } if (c->ismaster && c->old_master_inner_per < 1.0 && - c->master_inner_per < 1.0) { + c->old_master_inner_per > 0.0f && c->master_inner_per < 1.0 && + c->master_inner_per > 0.0f) { c->master_inner_per = (1.0 - c->master_inner_per) * c->old_master_inner_per / (1.0 - c->old_master_inner_per); @@ -61,10 +73,12 @@ void restore_size_per(Monitor *m, Client *c) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c && !fc->ismaster && fc->old_ismaster && fc->old_stack_inner_per < 1.0 && - fc->stack_inner_per < 1.0) { + fc->old_stack_inner_per > 0.0f && fc->stack_inner_per < 1.0 && + fc->stack_inner_per > 0.0f) { fc->stack_inner_per = (1.0 - fc->stack_inner_per) * fc->old_stack_inner_per / (1.0 - fc->old_stack_inner_per); + fc->old_ismaster = false; } } } diff --git a/src/mango.c b/src/mango.c index 3ae5ccc9..4c063cf4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4025,6 +4025,9 @@ void init_client_properties(Client *c) { c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; + c->old_stack_inner_per = 0.0f; + c->old_master_inner_per = 0.0f; + c->old_master_mfact_per = 0.0f; c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; From 11b4bb03bfea2e914fc7b208f724d89f7a446060 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 14:17:26 +0800 Subject: [PATCH 02/19] feat: support the repeated exchange of the same two clients --- src/dispatch/bind_define.h | 4 +++- src/mango.c | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 5cf41d6c..ac1f6022 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -110,7 +110,9 @@ int32_t exchange_client(const Arg *arg) { if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) return 0; - exchange_two_client(c, direction_select(arg)); + Client *tc = direction_select(arg); + tc = get_focused_stack_client(tc); + exchange_two_client(c, tc); return 0; } diff --git a/src/mango.c b/src/mango.c index 4c063cf4..c28844fe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4830,6 +4830,11 @@ void exchange_two_client(Client *c1, Client *c2) { } else { arrange(c1->mon, false, false); } + + // In order to facilitate repeated exchanges for get_focused_stack_client + // set c2 focus order behind c1 + wl_list_remove(&c2->flink); + wl_list_insert(&c1->flink, &c2->flink); } void set_activation_env() { From 9a17a0279c39b330d155d50282d1d2641d519dc3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 18:21:49 +0800 Subject: [PATCH 03/19] feat: add custom option to monitorrule --- src/config/parse_config.h | 10 ++++++++-- src/mango.c | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ce5db532..59debcf2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -112,6 +112,7 @@ typedef struct { int32_t width, height; // Monitor resolution float refresh; // Refresh rate int32_t vrr; // variable refresh rate + int32_t custom; // enable custom mode } ConfigMonitorRule; // 修改后的宏定义 @@ -1796,6 +1797,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->height = -1; rule->refresh = 0.0f; rule->vrr = 0; + rule->custom = 0; bool parse_error = false; char *token = strtok(value, ","); @@ -1833,6 +1835,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); } else if (strcmp(key, "vrr") == 0) { rule->vrr = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "custom") == 0) { + rule->custom = CLAMP_INT(atoi(val), 0, 1); } else { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown " @@ -3555,7 +3559,7 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int32_t ji, vrr; + int32_t ji, vrr, custom; int32_t mx, my; struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; @@ -3609,13 +3613,15 @@ void reapply_monitor_rules(void) { mx = mr->x == INT32_MAX ? m->m.x : mr->x; my = mr->y == INT32_MAX ? m->m.y : mr->y; vrr = mr->vrr >= 0 ? mr->vrr : 0; + custom = mr->custom >= 0 ? mr->custom : 0; if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { internal_mode = get_nearest_output_mode( m->wlr_output, mr->width, mr->height, mr->refresh); if (internal_mode) { wlr_output_state_set_mode(&state, internal_mode); - } else if (wlr_output_is_headless(m->wlr_output)) { + } else if (custom || + wlr_output_is_headless(m->wlr_output)) { wlr_output_state_set_custom_mode( &state, mr->width, mr->height, (int32_t)roundf(mr->refresh * 1000)); diff --git a/src/mango.c b/src/mango.c index c28844fe..94bddb6b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2884,7 +2884,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int32_t ji, vrr; + int32_t ji, vrr, custom; struct wlr_output_state state; Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; @@ -2976,6 +2976,7 @@ void createmon(struct wl_listener *listener, void *data) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; vrr = r->vrr >= 0 ? r->vrr : 0; + custom = r->custom >= 0 ? r->custom : 0; scale = r->scale; rr = r->rr; @@ -2985,7 +2986,7 @@ void createmon(struct wl_listener *listener, void *data) { if (internal_mode) { custom_monitor_mode = true; wlr_output_state_set_mode(&state, internal_mode); - } else if (wlr_output_is_headless(m->wlr_output)) { + } else if (custom || wlr_output_is_headless(m->wlr_output)) { custom_monitor_mode = true; wlr_output_state_set_custom_mode( &state, r->width, r->height, From 10d7e5c6e3817d36ae8dbe5747ad23fe26944a45 Mon Sep 17 00:00:00 2001 From: kanvolu Date: Fri, 6 Mar 2026 22:23:59 -0500 Subject: [PATCH 04/19] Added cycling both ways for switch_proportion_preset Now switch_proportion_preset requires an argument "prev" or "next" to determine cycle direction --- src/config/parse_config.h | 1 + src/dispatch/bind_declare.h | 2 +- src/dispatch/bind_define.h | 29 ++++++++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 59debcf2..47d086a7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -947,6 +947,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).f = atof(arg_value); } else if (strcmp(func_name, "switch_proportion_preset") == 0) { func = switch_proportion_preset; + (*arg).i = parse_circle_direction(arg_value); } else if (strcmp(func_name, "viewtoleft") == 0) { func = viewtoleft; (*arg).i = atoi(arg_value); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 22ef6123..7dced532 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,4 +69,4 @@ int32_t setoption(const Arg *arg); int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); -int32_t scroller_stack(const Arg *arg); \ No newline at end of file +int32_t scroller_stack(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index ac1f6022..676be515 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1056,13 +1056,28 @@ int32_t switch_proportion_preset(const Arg *arg) { for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == tc->scroller_proportion) { - if (i == config.scroller_proportion_preset_count - 1) { - target_proportion = config.scroller_proportion_preset[0]; - break; + + if (arg->i == NEXT) { + if (i == config.scroller_proportion_preset_count - 1) { + target_proportion = + config.scroller_proportion_preset[0]; + break; + } else { + target_proportion = + config.scroller_proportion_preset[i + 1]; + break; + } } else { - target_proportion = - config.scroller_proportion_preset[i + 1]; - break; + if (i == 0) { + target_proportion = + config.scroller_proportion_preset + [config.scroller_proportion_preset_count - 1]; + break; + } else { + target_proportion = + config.scroller_proportion_preset[i - 1]; + break; + } } } } @@ -1847,4 +1862,4 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; -} \ No newline at end of file +} From 63b9ffb1a422e34b8d2ce4121cf1aee6fd0e5dad Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 12:54:37 +0800 Subject: [PATCH 05/19] opt: opt the old size per init --- src/layout/arrange.h | 10 ---------- src/mango.c | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index d674068e..058198bf 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -5,16 +5,6 @@ void save_old_size_per(Monitor *m) { if (VISIBLEON(c, m) && ISTILED(c)) { c->old_master_inner_per = c->master_inner_per; c->old_stack_inner_per = c->stack_inner_per; - } else { - if (c->old_master_inner_per <= 0.0f || - c->old_master_inner_per > 1.0f) { - c->old_master_inner_per = 1.0f; - } - - if (c->old_stack_inner_per <= 0.0f || - c->old_stack_inner_per > 1.0f) { - c->old_stack_inner_per = 1.0f; - } } } } diff --git a/src/mango.c b/src/mango.c index 94bddb6b..a256d8f0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4026,9 +4026,9 @@ void init_client_properties(Client *c) { c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; - c->old_stack_inner_per = 0.0f; - c->old_master_inner_per = 0.0f; - c->old_master_mfact_per = 0.0f; + c->old_stack_inner_per = 1.0f; + c->old_master_inner_per = 1.0f; + c->old_master_mfact_per = 1.0f; c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; From fd68f188c63e7595f55bbb326bcb7c7ad4ec7c1f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 13:24:46 +0800 Subject: [PATCH 06/19] opt: add some comment --- src/layout/arrange.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 058198bf..36f6396a 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -44,6 +44,10 @@ void restore_size_per(Monitor *m, Client *c) { return; } + // it is possible that the current floating window is moved to another tag, + // but the tag has not executed save_old_size_per + // so it must be judged whether their old size values are initial values + if (!c->ismaster && c->old_stack_inner_per < 1.0 && c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 && c->stack_inner_per > 0.0f) { From 89a4ec83a0d24887d182209feca488f32fe3c071 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 13:46:18 +0800 Subject: [PATCH 07/19] fix: avoid mutual influence of monitor rules --- src/config/parse_config.h | 72 ++++--------------------- src/mango.c | 111 +++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 123 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 47d086a7..d10bf0c2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -372,6 +372,9 @@ typedef int32_t (*FuncType)(const Arg *); Config config; bool parse_config_file(Config *config, const char *file_path, bool must_exist); +bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, + struct wlr_output_state *state, int vrr, int custom); +bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule); // Helper function to trim whitespace from start and end of a string void trim_whitespace(char *str) { @@ -3563,14 +3566,12 @@ void reapply_monitor_rules(void) { int32_t ji, vrr, custom; int32_t mx, my; struct wlr_output_state state; - struct wlr_output_mode *internal_mode = NULL; - wlr_output_state_init(&state); - bool match_rule = false; wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { + if (!m->wlr_output->enabled) continue; - } + + wlr_output_state_init(&state); for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) @@ -3578,73 +3579,22 @@ void reapply_monitor_rules(void) { mr = &config.monitor_rules[ji]; - // 检查是否匹配的变量 - match_rule = true; - - // 检查四个标识字段的匹配 - if (mr->name != NULL) { - if (!regex_match(mr->name, m->wlr_output->name)) { - match_rule = false; - } - } - - if (mr->make != NULL) { - if (m->wlr_output->make == NULL || - strcmp(mr->make, m->wlr_output->make) != 0) { - match_rule = false; - } - } - - if (mr->model != NULL) { - if (m->wlr_output->model == NULL || - strcmp(mr->model, m->wlr_output->model) != 0) { - match_rule = false; - } - } - - if (mr->serial != NULL) { - if (m->wlr_output->serial == NULL || - strcmp(mr->serial, m->wlr_output->serial) != 0) { - match_rule = false; - } - } - - // 只有当所有指定的标识都匹配时才应用规则 - if (match_rule) { + if (monitor_matches_rule(m, mr)) { mx = mr->x == INT32_MAX ? m->m.x : mr->x; my = mr->y == INT32_MAX ? m->m.y : mr->y; vrr = mr->vrr >= 0 ? mr->vrr : 0; custom = mr->custom >= 0 ? mr->custom : 0; - if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { - internal_mode = get_nearest_output_mode( - m->wlr_output, mr->width, mr->height, mr->refresh); - if (internal_mode) { - wlr_output_state_set_mode(&state, internal_mode); - } else if (custom || - wlr_output_is_headless(m->wlr_output)) { - wlr_output_state_set_custom_mode( - &state, mr->width, mr->height, - (int32_t)roundf(mr->refresh * 1000)); - } - } - - if (vrr) { - enable_adaptive_sync(m, &state); - } else { - wlr_output_state_set_adaptive_sync_enabled(&state, false); - } - - wlr_output_state_set_scale(&state, mr->scale); - wlr_output_state_set_transform(&state, mr->rr); + (void)apply_rule_to_state(m, mr, &state, vrr, custom); wlr_output_layout_add(output_layout, m->wlr_output, mx, my); + wlr_output_commit_state(m->wlr_output, &state); + break; } } - wlr_output_commit_state(m->wlr_output, &state); wlr_output_state_finish(&state); - updatemons(NULL, NULL); } + updatemons(NULL, NULL); } void reapply_cursor_style(void) { diff --git a/src/mango.c b/src/mango.c index a256d8f0..2af2720f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -806,7 +806,6 @@ static int32_t keep_idle_inhibit(void *data); static void check_keep_idle_inhibit(Client *c); static void pre_caculate_before_arrange(Monitor *m, bool want_animation, bool from_view, bool only_caculate); - #include "data/static_keymap.h" #include "dispatch/bind_declare.h" #include "layout/layout.h" @@ -2878,6 +2877,49 @@ void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { } } +bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { + if (rule->name != NULL && !regex_match(rule->name, m->wlr_output->name)) + return false; + if (rule->make != NULL && (m->wlr_output->make == NULL || + strcmp(rule->make, m->wlr_output->make) != 0)) + return false; + if (rule->model != NULL && (m->wlr_output->model == NULL || + strcmp(rule->model, m->wlr_output->model) != 0)) + return false; + if (rule->serial != NULL && + (m->wlr_output->serial == NULL || + strcmp(rule->serial, m->wlr_output->serial) != 0)) + return false; + return true; +} + +/* 将规则中的显示参数应用到 wlr_output_state 中,返回是否设置了自定义模式 */ +bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, + struct wlr_output_state *state, int vrr, int custom) { + bool mode_set = false; + if (rule->width > 0 && rule->height > 0 && rule->refresh > 0) { + struct wlr_output_mode *internal_mode = get_nearest_output_mode( + m->wlr_output, rule->width, rule->height, rule->refresh); + if (internal_mode) { + wlr_output_state_set_mode(state, internal_mode); + mode_set = true; + } else if (custom || wlr_output_is_headless(m->wlr_output)) { + wlr_output_state_set_custom_mode( + state, rule->width, rule->height, + (int32_t)roundf(rule->refresh * 1000)); + mode_set = true; + } + } + if (vrr) { + enable_adaptive_sync(m, state); + } else { + wlr_output_state_set_adaptive_sync_enabled(state, false); + } + wlr_output_state_set_scale(state, rule->scale); + wlr_output_state_set_transform(state, rule->rr); + return mode_set; +} + void createmon(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ @@ -2887,9 +2929,7 @@ void createmon(struct wl_listener *listener, void *data) { int32_t ji, vrr, custom; struct wlr_output_state state; Monitor *m = NULL; - struct wlr_output_mode *internal_mode = NULL; bool custom_monitor_mode = false; - bool match_rule = false; if (!wlr_output_init_render(wlr_output, alloc, drw)) return; @@ -2919,7 +2959,6 @@ void createmon(struct wl_listener *listener, void *data) { for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); - wlr_output_state_init(&state); /* Initialize monitor state using configured rules */ m->gappih = gappih; m->gappiv = gappiv; @@ -2932,6 +2971,8 @@ void createmon(struct wl_listener *listener, void *data) { m->m.y = INT32_MAX; float scale = 1; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; + + wlr_output_state_init(&state); wlr_output_state_set_scale(&state, scale); wlr_output_state_set_transform(&state, rr); @@ -2941,38 +2982,7 @@ void createmon(struct wl_listener *listener, void *data) { r = &config.monitor_rules[ji]; - // 检查是否匹配的变量 - match_rule = true; - - // 检查四个标识字段的匹配 - if (r->name != NULL) { - if (!regex_match(r->name, m->wlr_output->name)) { - match_rule = false; - } - } - - if (r->make != NULL) { - if (m->wlr_output->make == NULL || - strcmp(r->make, m->wlr_output->make) != 0) { - match_rule = false; - } - } - - if (r->model != NULL) { - if (m->wlr_output->model == NULL || - strcmp(r->model, m->wlr_output->model) != 0) { - match_rule = false; - } - } - - if (r->serial != NULL) { - if (m->wlr_output->serial == NULL || - strcmp(r->serial, m->wlr_output->serial) != 0) { - match_rule = false; - } - } - - if (match_rule) { + if (monitor_matches_rule(m, r)) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; vrr = r->vrr >= 0 ? r->vrr : 0; @@ -2980,36 +2990,13 @@ void createmon(struct wl_listener *listener, void *data) { scale = r->scale; rr = r->rr; - if (r->width > 0 && r->height > 0 && r->refresh > 0) { - internal_mode = get_nearest_output_mode(m->wlr_output, r->width, - r->height, r->refresh); - if (internal_mode) { - custom_monitor_mode = true; - wlr_output_state_set_mode(&state, internal_mode); - } else if (custom || wlr_output_is_headless(m->wlr_output)) { - custom_monitor_mode = true; - wlr_output_state_set_custom_mode( - &state, r->width, r->height, - (int32_t)roundf(r->refresh * 1000)); - } + if (apply_rule_to_state(m, r, &state, vrr, custom)) { + custom_monitor_mode = true; } - - if (vrr) { - enable_adaptive_sync(m, &state); - } else { - wlr_output_state_set_adaptive_sync_enabled(&state, false); - } - - wlr_output_state_set_scale(&state, r->scale); - wlr_output_state_set_transform(&state, r->rr); - break; + break; // 只应用第一个匹配规则 } } - /* The mode is a tuple of (width, height, refresh rate), and each - * monitor supports only a specific set of modes. We just pick the - * monitor's preferred mode; a more sophisticated compositor would let - * the user configure it. */ if (!custom_monitor_mode) wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); From 75c888bbe4bc7efda789bbe1d8872a36b0b2a964 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 15:31:05 +0800 Subject: [PATCH 08/19] opt: optimize resizewin setp with keyboard --- src/layout/arrange.h | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 36f6396a..853e4692 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -276,6 +276,18 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); + if (!isdrag) { + new_stack_inner_per = + new_stack_inner_per + + (new_stack_inner_per - grabc->old_stack_inner_per) / + ((1 / new_stack_inner_per) - 1); + + new_master_inner_per = + new_master_inner_per + + (new_master_inner_per - grabc->old_master_inner_per) / + ((1 / new_master_inner_per) - 1); + } + // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { @@ -431,6 +443,18 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); + if (!isdrag) { + new_stack_inner_per = + new_stack_inner_per + + (new_stack_inner_per - grabc->old_stack_inner_per) / + ((1 / new_stack_inner_per) - 1); + + new_master_inner_per = + new_master_inner_per + + (new_master_inner_per - grabc->old_master_inner_per) / + ((1 / new_master_inner_per) - 1); + } + // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { @@ -616,7 +640,14 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, // 应用限制,确保比例在合理范围内 new_scroller_proportion = fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); - new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion)); + new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion)); + + if (!isdrag) { + new_stack_proportion = + new_stack_proportion + + (new_stack_proportion - grabc->old_stack_proportion) / + ((1 / new_stack_proportion) - 1); + } grabc->stack_proportion = new_stack_proportion; From b1d744ad1f493cba26fb31a87db5346ac9361c6b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:21:50 +0800 Subject: [PATCH 09/19] feat: export drag interval to able configure --- assets/config.conf | 2 ++ src/config/parse_config.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/assets/config.conf b/assets/config.conf index 15b654c1..77786649 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,6 +74,8 @@ overviewgappi=5 overviewgappo=30 # Misc +drag_tile_refresh_interval=16.0 +drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 focus_on_activate=1 diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d10bf0c2..3220b713 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -356,6 +356,8 @@ typedef struct { int32_t single_scratchpad; int32_t xwayland_persistence; int32_t syncobj_enable; + float drag_tile_refresh_interval; + float drag_floating_refresh_interval; int32_t allow_tearing; int32_t allow_shortcuts_inhibit; int32_t allow_lock_transparent; @@ -1399,6 +1401,10 @@ bool parse_option(Config *config, char *key, char *value) { config->xwayland_persistence = atoi(value); } else if (strcmp(key, "syncobj_enable") == 0) { config->syncobj_enable = atoi(value); + } else if (strcmp(key, "drag_tile_refresh_interval") == 0) { + config->drag_tile_refresh_interval = atof(value); + } else if (strcmp(key, "drag_floating_refresh_interval") == 0) { + config->drag_floating_refresh_interval = atof(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { @@ -3149,6 +3155,13 @@ void override_config(void) { // 杂项设置 xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); + drag_tile_refresh_interval = + CLAMP_FLOAT(config.drag_tile_refresh_interval, 1.0f, 16.0f); + drag_floating_refresh_interval = + CLAMP_FLOAT(config.drag_floating_refresh_interval, 1.0f, 16.0f); + drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1); + drag_floating_refresh_interval = + CLAMP_FLOAT(config.drag_floating_refresh_interval, 0.0f, 1000.0f); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1); @@ -3337,6 +3350,8 @@ void set_value_default() { config.single_scratchpad = single_scratchpad; config.xwayland_persistence = xwayland_persistence; config.syncobj_enable = syncobj_enable; + config.drag_tile_refresh_interval = drag_tile_refresh_interval; + config.drag_floating_refresh_interval = drag_floating_refresh_interval; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; config.allow_lock_transparent = allow_lock_transparent; From 636060972dc42c18a7abb1f533fc23be338ceb23 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:29:37 +0800 Subject: [PATCH 10/19] opt: change some default config --- assets/config.conf | 2 +- src/config/preset.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/config.conf b/assets/config.conf index 77786649..d2587165 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,7 +74,7 @@ overviewgappi=5 overviewgappo=30 # Misc -drag_tile_refresh_interval=16.0 +drag_tile_refresh_interval=8.0 drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 diff --git a/src/config/preset.h b/src/config/preset.h index d9824588..f91da11a 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -109,7 +109,7 @@ int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; int32_t allow_lock_transparent = 0; -double drag_tile_refresh_interval = 16.0; +double drag_tile_refresh_interval = 8.0; double drag_floating_refresh_interval = 8.0; int32_t allow_tearing = TEARING_DISABLED; int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; From d0eb7d7114705877529045e6315de1c271a8e2a3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:40:22 +0800 Subject: [PATCH 11/19] opt: remove some config in default config file --- assets/config.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/assets/config.conf b/assets/config.conf index d2587165..15b654c1 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,8 +74,6 @@ overviewgappi=5 overviewgappo=30 # Misc -drag_tile_refresh_interval=8.0 -drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 focus_on_activate=1 From 09c170793177dcbdb4e0a7881260f4243caf2d59 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 18:51:12 +0800 Subject: [PATCH 12/19] opt: optimize size per caculate when resizewin --- src/layout/arrange.h | 93 ++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 853e4692..bbe735f7 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -276,21 +276,24 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); - if (!isdrag) { - new_stack_inner_per = - new_stack_inner_per + - (new_stack_inner_per - grabc->old_stack_inner_per) / - ((1 / new_stack_inner_per) - 1); - - new_master_inner_per = - new_master_inner_per + - (new_master_inner_per - grabc->old_master_inner_per) / - ((1 / new_master_inner_per) - 1); - } - // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + + if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!tc->ismaster && new_stack_inner_per != 1.0f && + grabc->old_stack_inner_per != 1.0f) + tc->stack_inner_per = (1 - new_stack_inner_per) / + (1 - grabc->old_stack_inner_per) * + tc->stack_inner_per; + if (tc->ismaster && new_master_inner_per != 1.0f && + grabc->old_master_inner_per != 1.0f) + tc->master_inner_per = + (1.0f - new_master_inner_per) / + (1.0f - grabc->old_master_inner_per) * + tc->master_inner_per; + } + tc->master_mfact_per = new_master_mfact_per; } } @@ -443,21 +446,23 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); - if (!isdrag) { - new_stack_inner_per = - new_stack_inner_per + - (new_stack_inner_per - grabc->old_stack_inner_per) / - ((1 / new_stack_inner_per) - 1); - - new_master_inner_per = - new_master_inner_per + - (new_master_inner_per - grabc->old_master_inner_per) / - ((1 / new_master_inner_per) - 1); - } - // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!tc->ismaster && new_stack_inner_per != 1.0f && + grabc->old_stack_inner_per != 1.0f) + tc->stack_inner_per = (1 - new_stack_inner_per) / + (1 - grabc->old_stack_inner_per) * + tc->stack_inner_per; + if (tc->ismaster && new_master_inner_per != 1.0f && + grabc->old_master_inner_per != 1.0f) + tc->master_inner_per = + (1.0f - new_master_inner_per) / + (1.0f - grabc->old_master_inner_per) * + tc->master_inner_per; + } + tc->master_mfact_per = new_master_mfact_per; } } @@ -480,6 +485,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, bool isvertical) { + Client *tc = NULL; float delta_x, delta_y; float new_scroller_proportion; float new_stack_proportion; @@ -642,17 +648,20 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion)); - if (!isdrag) { - new_stack_proportion = - new_stack_proportion + - (new_stack_proportion - grabc->old_stack_proportion) / - ((1 / new_stack_proportion) - 1); - } - grabc->stack_proportion = new_stack_proportion; stack_head->scroller_proportion = new_scroller_proportion; + wl_list_for_each(tc, &clients, link) { + if (new_stack_proportion != 1.0f && + grabc->old_stack_proportion != 1.0f && tc != grabc && + ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) { + tc->stack_proportion = (1.0f - new_stack_proportion) / + (1.0f - grabc->old_stack_proportion) * + tc->stack_proportion; + } + } + if (!isdrag) { arrange(grabc->mon, false, false); return; @@ -695,6 +704,18 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, } } +/* If there are no calculation omissions, +these two functions will never be triggered. +Just in case to facilitate the final investigation*/ + +void check_size_per_valid(Client *c) { + if (c->ismaster) { + assert(c->master_inner_per > 0.0f && c->master_inner_per <= 1.0f); + } else { + assert(c->stack_inner_per > 0.0f && c->stack_inner_per <= 1.0f); + } +} + void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, double total_left_stack_hight_percent, double total_right_stack_hight_percent, @@ -710,6 +731,7 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f; @@ -725,17 +747,20 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, : 1.0f; } i++; + + check_size_per_valid(c); } } } else { wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { c->stack_inner_per = - stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f; - + stack_num > 1 ? 1.0f / ((stack_num - 1) / 2.0f) + : 1.0f; } else { c->stack_inner_per = stack_num > 1 ? 2.0f / stack_num : 1.0f; @@ -764,6 +789,8 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, } } i++; + + check_size_per_valid(c); } } } From 31284b4b5db8785004cdb345c778f31424684a6f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 22:54:13 +0800 Subject: [PATCH 13/19] opt: optimize center tile layout resizewin --- src/layout/arrange.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index bbe735f7..33db8ec0 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -280,9 +280,11 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { - if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!isdrag && tc != grabc) { if (!tc->ismaster && new_stack_inner_per != 1.0f && - grabc->old_stack_inner_per != 1.0f) + grabc->old_stack_inner_per != 1.0f && + (type != CENTER_TILE || + !(grabc->isleftstack ^ tc->isleftstack))) tc->stack_inner_per = (1 - new_stack_inner_per) / (1 - grabc->old_stack_inner_per) * tc->stack_inner_per; From cfe492fbc4af1b9518d1102680c3452e0e52d7b8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 23:14:17 +0800 Subject: [PATCH 14/19] opt: fix a minor judgment error --- src/layout/arrange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 33db8ec0..0284f8ca 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -89,7 +89,7 @@ void set_size_per(Monitor *m, Client *c) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { if (current_layout->id == CENTER_TILE && - !(fc->isleftstack ^ c->isleftstack)) + (fc->isleftstack ^ c->isleftstack)) continue; c->master_mfact_per = fc->master_mfact_per; c->master_inner_per = fc->master_inner_per; From 89a0f7e3155a9b4489a56302153a92e4a5f1f339 Mon Sep 17 00:00:00 2001 From: Nikita Mitasov Date: Sat, 7 Mar 2026 22:18:46 +0300 Subject: [PATCH 15/19] fix(guix): add deprecated package variable with old naming. --- mangowm.scm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangowm.scm b/mangowm.scm index 33d95045..7d94166d 100644 --- a/mangowm.scm +++ b/mangowm.scm @@ -61,4 +61,7 @@ inspired by dwl but aiming to be more feature-rich.") (license gpl3))) +(define-deprecated-package mangowc + mangowm-git) + mangowm-git From a4ad8d0d1945fa37063ac3d112926e061f158c73 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Mar 2026 08:45:56 +0800 Subject: [PATCH 16/19] fix: miss judge isdrag when resize stack in scroller --- src/layout/arrange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 0284f8ca..e164a0f6 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -655,7 +655,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, stack_head->scroller_proportion = new_scroller_proportion; wl_list_for_each(tc, &clients, link) { - if (new_stack_proportion != 1.0f && + if (!isdrag && new_stack_proportion != 1.0f && grabc->old_stack_proportion != 1.0f && tc != grabc && ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) { tc->stack_proportion = (1.0f - new_stack_proportion) / From a607d63ae7c8965655562ed310991e9dc164d4e0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Mar 2026 20:00:44 +0800 Subject: [PATCH 17/19] opt: reset size per when toggleview --- src/dispatch/bind_define.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 676be515..228e92e3 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1436,6 +1436,7 @@ int32_t toggleview(const Arg *arg) { uint32_t newtagset; uint32_t target; + Client *c = NULL; target = arg->ui == 0 ? ~0 & TAGMASK : arg->ui; @@ -1444,6 +1445,11 @@ int32_t toggleview(const Arg *arg) { if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focusclient(focustop(selmon), 1); + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon) && ISTILED(c)) { + set_size_per(selmon, c); + } + } arrange(selmon, false, false); } printstatus(); From d441ca22f4bd7554f04defdd36f13bedc38610e7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Mar 2026 20:20:13 +0800 Subject: [PATCH 18/19] opt: set scroller stack to same first tag --- src/dispatch/bind_define.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 228e92e3..4f808bdf 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1774,28 +1774,19 @@ int32_t scroller_stack(const Arg *arg) { if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; - if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal)) - return 0; - bool is_horizontal_layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER ? true : false; Client *target_client = find_client_by_direction(c, arg, false, true); - if (target_client && (!client_only_in_one_tag(target_client) || - target_client->isglobal || target_client->isunglobal)) - return 0; - if (target_client) { stack_head = get_scroll_stack_head(target_client); } - if (c) { - source_stack_head = get_scroll_stack_head(c); - } + source_stack_head = get_scroll_stack_head(c); - if (stack_head == source_stack_head) { + if (source_stack_head == stack_head) { return 0; } @@ -1843,6 +1834,10 @@ int32_t scroller_stack(const Arg *arg) { if (!target_client || target_client->mon != c->mon) { return 0; + } else { + c->isglobal = target_client->isglobal = 0; + c->isunglobal = target_client->isglobal = 0; + c->tags = target_client->tags = get_tags_first_tag(target_client->tags); } exit_scroller_stack(c); From db30977196b91cfe2e5db8e9829faafe13417bd9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 9 Mar 2026 11:15:13 +0800 Subject: [PATCH 19/19] opt: optimize popup unconstrain --- src/mango.c | 55 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/mango.c b/src/mango.c index 2af2720f..bdafcc58 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2590,41 +2590,49 @@ void destroydecoration(struct wl_listener *listener, void *data) { wl_list_remove(&c->set_decoration_mode.link); } -static void popup_unconstrain(Popup *popup) { +static bool popup_unconstrain(Popup *popup) { struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; Client *c = NULL; LayerSurface *l = NULL; int32_t type = -1; if (!wlr_popup || !wlr_popup->parent) { - return; + return false; } struct wlr_scene_node *parent_node = wlr_popup->parent->data; if (!parent_node) { wlr_log(WLR_ERROR, "Popup parent has no scene node"); - return; + return false; } type = toplevel_from_wlr_surface(wlr_popup->base->surface, &c, &l); if ((l && !l->mon) || (c && !c->mon)) { - wlr_xdg_popup_destroy(wlr_popup); - return; + return true; } - int parent_lx, parent_ly; - wlr_scene_node_coords(parent_node, &parent_lx, &parent_ly); - struct wlr_box usable = type == LayerShell ? l->mon->m : c->mon->w; - struct wlr_box constraint_box = { - .x = usable.x - parent_lx, - .y = usable.y - parent_ly, - .width = usable.width, - .height = usable.height, - }; + int lx, ly; + struct wlr_box constraint_box; + + if (type == LayerShell) { + wlr_scene_node_coords(&l->scene_layer->tree->node, &lx, &ly); + constraint_box.x = usable.x - lx; + constraint_box.y = usable.y - ly; + constraint_box.width = usable.width; + constraint_box.height = usable.height; + } else { + constraint_box.x = + usable.x - (c->geom.x + c->bw - c->surface.xdg->current.geometry.x); + constraint_box.y = + usable.y - (c->geom.y + c->bw - c->surface.xdg->current.geometry.y); + constraint_box.width = usable.width; + constraint_box.height = usable.height; + } wlr_xdg_popup_unconstrain_from_box(wlr_popup, &constraint_box); + return false; } static void destroypopup(struct wl_listener *listener, void *data) { @@ -2638,14 +2646,16 @@ static void commitpopup(struct wl_listener *listener, void *data) { Popup *popup = wl_container_of(listener, popup, commit); struct wlr_surface *surface = data; + bool should_destroy = false; struct wlr_xdg_popup *wlr_popup = wlr_xdg_popup_try_from_wlr_surface(surface); - if (!wlr_popup || !wlr_popup->base->initial_commit) - goto commitpopup_listen_free; + if (!wlr_popup->base->initial_commit) + return; if (!wlr_popup->parent || !wlr_popup->parent->data) { - goto commitpopup_listen_free; + should_destroy = true; + goto cleanup_popup_commit; } wlr_scene_node_raise_to_top(wlr_popup->parent->data); @@ -2655,16 +2665,21 @@ static void commitpopup(struct wl_listener *listener, void *data) { popup->wlr_popup = wlr_popup; - popup_unconstrain(popup); + should_destroy = popup_unconstrain(popup); + +cleanup_popup_commit: -commitpopup_listen_free: wl_list_remove(&popup->commit.link); popup->commit.notify = NULL; + + if (should_destroy) { + wlr_xdg_popup_destroy(wlr_popup); + } } static void repositionpopup(struct wl_listener *listener, void *data) { Popup *popup = wl_container_of(listener, popup, reposition); - popup_unconstrain(popup); + (void)popup_unconstrain(popup); } static void createpopup(struct wl_listener *listener, void *data) {