diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 43e8badc..d0b19c1e 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: days-before-issue-stale: -1 # 手动标记后,14 天后关闭 days-before-issue-close: 7 - # 使用的标签(必须和你手动添加的标签一致) + # 使用的标签 stale-issue-label: "stale" # 自动关闭时自动加上的标签 close-issue-label: "automatic-closing" 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 diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b4fb37e9..3220b713 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -78,7 +78,8 @@ typedef struct { int32_t ignore_maximize; int32_t ignore_minimize; int32_t isnosizehint; - const char *monitor; + int32_t indleinhibit_when_focus; + char *monitor; int32_t offsetx; int32_t offsety; int32_t width; @@ -111,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; // 修改后的宏定义 @@ -354,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; @@ -370,6 +374,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) { @@ -945,6 +952,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); @@ -1393,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) { @@ -1795,6 +1807,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, ","); @@ -1832,6 +1845,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 " @@ -2022,6 +2037,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_maximize = -1; rule->ignore_minimize = -1; rule->isnosizehint = -1; + rule->indleinhibit_when_focus = -1; rule->isterm = -1; rule->allow_csd = -1; rule->force_maximize = -1; @@ -2132,6 +2148,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_minimize = atoi(val); } else if (strcmp(key, "isnosizehint") == 0) { rule->isnosizehint = atoi(val); + } else if (strcmp(key, "indleinhibit_when_focus") == 0) { + rule->indleinhibit_when_focus = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "allow_csd") == 0) { @@ -3137,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); @@ -3325,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; @@ -3551,17 +3578,15 @@ 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; - 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) @@ -3569,78 +3594,29 @@ 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 (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) { - if (hide_source) { - wl_event_source_timer_update(hide_source, 0); - wl_event_source_remove(hide_source); - hide_source = NULL; + if (hide_cursor_source) { + wl_event_source_timer_update(hide_cursor_source, 0); + wl_event_source_remove(hide_cursor_source); + hide_cursor_source = NULL; } wlr_cursor_unset_image(cursor); @@ -3671,12 +3647,13 @@ void reapply_cursor_style(void) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); - hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hidecursor, cursor); if (cursor_hidden) { wlr_cursor_unset_image(cursor); } else { - wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, + cursor_hide_timeout * 1000); } } 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; 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 5cf41d6c..4f808bdf 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; } @@ -1054,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; + } } } } @@ -1419,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; @@ -1427,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(); @@ -1751,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; } @@ -1820,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); @@ -1845,4 +1863,4 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; -} \ No newline at end of file +} diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 1ef89c3a..e164a0f6 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,11 +1,31 @@ +void save_old_size_per(Monitor *m) { + Client *c = NULL; + + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, m) && ISTILED(c)) { + c->old_master_inner_per = c->master_inner_per; + c->old_stack_inner_per = c->stack_inner_per; + } + } +} + void restore_size_per(Monitor *m, Client *c) { Client *fc = NULL; - double total_master_inner_per = 0; - double total_stack_inner_per = 0; if (!m || !c) return; + wl_list_for_each(fc, &clients, link) { + if (VISIBLEON(fc, m) && ISTILED(fc)) { + fc->old_ismaster = fc->ismaster; + } + } + + c->old_master_inner_per = c->master_inner_per; + c->old_stack_inner_per = c->stack_inner_per; + + pre_caculate_before_arrange(m, false, false, true); + const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; if (current_layout->id == SCROLLER || @@ -15,7 +35,7 @@ void restore_size_per(Monitor *m, Client *c) { return; } - if (current_layout->id == CENTER_TILE || c->ismaster) { + if (current_layout->id == CENTER_TILE) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) { set_size_per(m, fc); @@ -24,19 +44,36 @@ void restore_size_per(Monitor *m, Client *c) { return; } - wl_list_for_each(fc, &clients, link) { - if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { - if (fc->ismaster) { - total_master_inner_per += fc->master_inner_per; - } else { - total_stack_inner_per += fc->stack_inner_per; - } - } + // 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) { + 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 && total_stack_inner_per) { - c->stack_inner_per = total_stack_inner_per * c->stack_inner_per / - (1 - c->stack_inner_per); + if (c->ismaster && c->old_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); + } + + 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->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; + } } } @@ -52,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; @@ -90,8 +127,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { next = tc; begin_find_nextnext = true; continue; @@ -107,8 +143,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { prev = tc; begin_find_prevprev = true; continue; @@ -244,6 +279,23 @@ 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) { + if (!tc->ismaster && new_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; + 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; } } @@ -276,8 +328,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.next; node != &clients; node = node->next) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { next = tc; break; } @@ -287,8 +338,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.prev; node != &clients; node = node->prev) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { prev = tc; break; } @@ -401,6 +451,20 @@ void resize_tile_master_vertical(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 (!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; } } @@ -423,6 +487,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; @@ -583,12 +648,22 @@ 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)); grabc->stack_proportion = new_stack_proportion; stack_head->scroller_proportion = new_scroller_proportion; + wl_list_for_each(tc, &clients, link) { + 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) / + (1.0f - grabc->old_stack_proportion) * + tc->stack_proportion; + } + } + if (!isdrag) { arrange(grabc->mon, false, false); return; @@ -631,6 +706,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, @@ -646,6 +733,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; @@ -661,17 +749,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; @@ -700,13 +791,15 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, } } i++; + + check_size_per_valid(c); } } } } -void // 17 -arrange(Monitor *m, bool want_animation, bool from_view) { +void pre_caculate_before_arrange(Monitor *m, bool want_animation, + bool from_view, bool only_caculate) { Client *c = NULL; double total_stack_inner_percent = 0; double total_master_inner_percent = 0; @@ -795,14 +888,17 @@ arrange(Monitor *m, bool want_animation, bool from_view) { i++; } - set_arrange_visible(m, c, want_animation); + if (!only_caculate) + set_arrange_visible(m, c, want_animation); } else { - set_arrange_hidden(m, c, want_animation); + if (!only_caculate) + set_arrange_hidden(m, c, want_animation); } } - if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted && - !c->animation.tagouting && VISIBLEON(c, m)) { + if (!only_caculate && c->mon == m && c->ismaximizescreen && + !c->animation.tagouted && !c->animation.tagouting && + VISIBLEON(c, m)) { reset_maximizescreen_size(c); } } @@ -811,6 +907,12 @@ arrange(Monitor *m, bool want_animation, bool from_view) { m, m->visible_tiling_clients, total_left_stack_hight_percent, total_right_stack_hight_percent, total_stack_inner_percent, total_master_inner_percent, master_num, stack_num); +} + +void // 17 +arrange(Monitor *m, bool want_animation, bool from_view) { + + pre_caculate_before_arrange(m, want_animation, from_view, false); if (m->isoverview) { overviewlayout.arrange(m); diff --git a/src/mango.c b/src/mango.c index 0864a982..bdafcc58 100644 --- a/src/mango.c +++ b/src/mango.c @@ -347,7 +347,7 @@ struct Client { struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, - ignore_maximize, ignore_minimize; + ignore_maximize, ignore_minimize, indleinhibit_when_focus; int32_t ismaximizescreen; int32_t overview_backup_bw; int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -412,6 +412,7 @@ struct Client { double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; + bool old_ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; int32_t tearing_hint; @@ -488,7 +489,6 @@ typedef struct { typedef struct { struct wlr_xdg_popup *wlr_popup; - uint32_t type; struct wl_listener destroy; struct wl_listener commit; struct wl_listener reposition; @@ -800,7 +800,12 @@ static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); static bool match_monitor_spec(char *spec, Monitor *m); - +static void last_cursor_surface_destroy(struct wl_listener *listener, + void *data); +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" @@ -896,7 +901,8 @@ struct dvec2 *baked_points_focus; struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; -static struct wl_event_source *hide_source; +static struct wl_event_source *hide_cursor_source; +static struct wl_event_source *keep_idle_inhibit_source; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; @@ -964,6 +970,8 @@ static struct wl_listener new_session_lock = {.notify = locksession}; static struct wl_listener drm_lease_request = {.notify = requestdrmlease}; static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; +static struct wl_listener last_cursor_surface_destroy_listener = { + .notify = last_cursor_surface_destroy}; #ifdef XWAYLAND static void fix_xwayland_unmanaged_coordinate(Client *c); @@ -1331,6 +1339,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); + APPLY_INT_PROP(c, r, indleinhibit_when_focus); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); @@ -1435,7 +1444,7 @@ void applyrules(Client *c) { // set monitor of client wl_list_for_each(m, &mons, link) { - if (regex_match(r->monitor, m->wlr_output->name)) { + if (match_monitor_spec(r->monitor, m)) { mon = m; } } @@ -1690,9 +1699,10 @@ void focuslayer(LayerSurface *l) { client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); } -void reset_exclusive_layer(Monitor *m) { +void reset_exclusive_layers_focus(Monitor *m) { LayerSurface *l = NULL; int32_t i; + bool neet_change_focus_to_client = false; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -1703,28 +1713,47 @@ void reset_exclusive_layer(Monitor *m) { return; for (i = 0; i < (int32_t)LENGTH(layers_above_shell); i++) { - wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + wl_list_for_each(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { + exclusive_focus = NULL; + + neet_change_focus_to_client = true; + } + + if (l->layer_surface->surface == + seat->keyboard_state.focused_surface && + l->being_unmapped) { + neet_change_focus_to_client = true; + } + if (l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && l->layer_surface->surface == - seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); + seat->keyboard_state.focused_surface) { + neet_change_focus_to_client = true; + } if (locked || l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE || - !l->mapped || l == exclusive_focus) + l->being_unmapped) continue; /* Deactivate the focused client. */ exclusive_focus = l; - focuslayer(l); + neet_change_focus_to_client = false; + if (l->layer_surface->surface != + seat->keyboard_state.focused_surface) + focuslayer(l); return; } } + + if (neet_change_focus_to_client) { + focusclient(focustop(selmon), 1); + } } void arrangelayers(Monitor *m) { @@ -1746,9 +1775,6 @@ void arrangelayers(Monitor *m) { /* Arrange non-exlusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) arrangelayer(m, &m->layers[i], &usable_area, 0); - - /* Find topmost keyboard interactive layer, if such a layer exists */ - reset_exclusive_layer(m); } void // 鼠标滚轮事件 @@ -2133,6 +2159,11 @@ void checkidleinhibitor(struct wlr_surface *exclude) { wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } +void last_cursor_surface_destroy(struct wl_listener *listener, void *data) { + last_cursor.surface = NULL; + wl_list_remove(&listener->link); +} + void setcursorshape(struct wl_listener *listener, void *data) { struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; if (cursor_mode != CurNormal && cursor_mode != CurPressed) @@ -2141,6 +2172,11 @@ void setcursorshape(struct wl_listener *listener, void *data) { * actually has pointer focus first. If so, we can tell the cursor to * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) { + /* Remove surface destroy listener if active */ + if (last_cursor.surface && + last_cursor_surface_destroy_listener.link.prev != NULL) + wl_list_remove(&last_cursor_surface_destroy_listener.link); + last_cursor.shape = event->shape; last_cursor.surface = NULL; if (!cursor_hidden) @@ -2384,13 +2420,7 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); - - // 按需交互layer需要像正常窗口一样抢占非独占layer的焦点 - if (!exclusive_focus && - l->layer_surface->current.keyboard_interactive == - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { - focuslayer(l); - } + reset_exclusive_layers_focus(l->mon); } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { @@ -2410,7 +2440,12 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { l->layer_surface->current = l->layer_surface->pending; arrangelayers(l->mon); l->layer_surface->current = old_state; - + // 按需交互layer只在map之前设置焦点 + if (!exclusive_focus && + l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + focuslayer(l); + } return; } @@ -2455,28 +2490,31 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { layer_flush_blur_background(l); - if (layer_surface == exclusive_focus && - layer_surface->current.keyboard_interactive != - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) - exclusive_focus = NULL; - if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; l->mapped = layer_surface->surface->mapped; - if (scene_layer != l->scene->node.parent) { - wlr_scene_node_reparent(&l->scene->node, scene_layer); - wl_list_remove(&l->link); - wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); - wlr_scene_node_reparent( - &l->popups->node, - (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP - ? layers[LyrTop] - : scene_layer)); + if (layer_surface->current.committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], + &l->link); + wlr_scene_node_reparent( + &l->popups->node, + (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP + ? layers[LyrTop] + : scene_layer)); + } } arrangelayers(l->mon); + + if (layer_surface->current.committed & + WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) { + reset_exclusive_layers_focus(l->mon); + } } void commitnotify(struct wl_listener *listener, void *data) { @@ -2552,37 +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; } - int parent_lx, parent_ly; - wlr_scene_node_coords(parent_node, &parent_lx, &parent_ly); - struct wlr_box *scheduled = &wlr_popup->scheduled.geometry; - int popup_lx = parent_lx + scheduled->x; - int popup_ly = parent_ly + scheduled->y; + type = toplevel_from_wlr_surface(wlr_popup->base->surface, &c, &l); + if ((l && !l->mon) || (c && !c->mon)) { + return true; + } - Monitor *mon = get_monitor_nearest_to(popup_lx, popup_ly); + struct wlr_box usable = type == LayerShell ? l->mon->m : c->mon->w; - struct wlr_box usable = popup->type == LayerShell ? mon->m : mon->w; + int lx, ly; + struct wlr_box constraint_box; - struct wlr_box constraint_box = { - .x = usable.x - parent_lx, - .y = usable.y - parent_ly, - .width = usable.width, - .height = usable.height, - }; + 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) { @@ -2596,44 +2646,40 @@ static void commitpopup(struct wl_listener *listener, void *data) { Popup *popup = wl_container_of(listener, popup, commit); struct wlr_surface *surface = data; - struct wlr_xdg_popup *wkr_popup = + bool should_destroy = false; + struct wlr_xdg_popup *wlr_popup = wlr_xdg_popup_try_from_wlr_surface(surface); - Client *c = NULL; - LayerSurface *l = NULL; - int32_t type = -1; + if (!wlr_popup->base->initial_commit) + return; - if (!wkr_popup || !wkr_popup->base->initial_commit) - goto commitpopup_listen_free; - - type = toplevel_from_wlr_surface(wkr_popup->base->surface, &c, &l); - if (!wkr_popup->parent || !wkr_popup->parent->data || type < 0) { - wlr_xdg_popup_destroy(wkr_popup); - goto commitpopup_listen_free; + if (!wlr_popup->parent || !wlr_popup->parent->data) { + should_destroy = true; + goto cleanup_popup_commit; } - wlr_scene_node_raise_to_top(wkr_popup->parent->data); + wlr_scene_node_raise_to_top(wlr_popup->parent->data); - wkr_popup->base->surface->data = - wlr_scene_xdg_surface_create(wkr_popup->parent->data, wkr_popup->base); - if ((l && !l->mon) || (c && !c->mon)) { - wlr_xdg_popup_destroy(wkr_popup); - goto commitpopup_listen_free; - } + wlr_popup->base->surface->data = + wlr_scene_xdg_surface_create(wlr_popup->parent->data, wlr_popup->base); - popup->type = type; - popup->wlr_popup = wkr_popup; + 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) { @@ -2846,18 +2892,59 @@ 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. */ 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; bool custom_monitor_mode = false; - bool match_rule = false; if (!wlr_output_init_render(wlr_output, alloc, drw)) return; @@ -2887,7 +2974,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; @@ -2900,6 +2986,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); @@ -2909,74 +2997,21 @@ 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; + custom = r->custom >= 0 ? r->custom : 0; 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 (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)); @@ -3335,8 +3370,7 @@ void destroylocksurface(struct wl_listener *listener, void *data) { if (lock_surface->surface != seat->keyboard_state.focused_surface) { if (exclusive_focus && !locked) { - exclusive_focus = NULL; - reset_exclusive_layer(m); + reset_exclusive_layers_focus(m); } return; } @@ -3345,9 +3379,7 @@ void destroylocksurface(struct wl_listener *listener, void *data) { surface = wl_container_of(cur_lock->surfaces.next, surface, link); client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); } else if (!locked) { - exclusive_focus = NULL; - reset_exclusive_layer(selmon); - focusclient(focustop(selmon), 1); + reset_exclusive_layers_focus(selmon); } else { wlr_seat_keyboard_clear_focus(seat); } @@ -3452,6 +3484,8 @@ void focusclient(Client *c, int32_t lift) { selmon->sel = c; c->isfocusing = true; + check_keep_idle_inhibit(c); + if (last_focus_client && !last_focus_client->iskilling && last_focus_client != c) { last_focus_client->isfocusing = false; @@ -3953,6 +3987,7 @@ void init_client_properties(Client *c) { c->swallowing = NULL; c->swallowedby = NULL; c->ismaster = 0; + c->old_ismaster = 0; c->isleftstack = 0; c->ismaximizescreen = 0; c->isfullscreen = 0; @@ -3993,12 +4028,16 @@ 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 = 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; c->force_tiled_state = 1; c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; + c->indleinhibit_when_focus = 0; c->scroller_proportion_single = 0.0f; c->float_geom.width = 0; c->float_geom.height = 0; @@ -4794,6 +4833,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() { @@ -4918,10 +4962,21 @@ void setcursor(struct wl_listener *listener, void *data) { * hardware cursor on the output that it's currently on and continue to * do so as the cursor moves between outputs. */ if (event->seat_client == seat->pointer_state.focused_client) { + /* Clear previous surface destroy listener if any */ + if (last_cursor.surface && + last_cursor_surface_destroy_listener.link.prev != NULL) + wl_list_remove(&last_cursor_surface_destroy_listener.link); + last_cursor.shape = 0; last_cursor.surface = event->surface; last_cursor.hotspot_x = event->hotspot_x; last_cursor.hotspot_y = event->hotspot_y; + + /* Track surface destruction to avoid dangling pointer */ + if (event->surface) + wl_signal_add(&event->surface->events.destroy, + &last_cursor_surface_destroy_listener); + if (!cursor_hidden) wlr_cursor_set_surface(cursor, event->surface, event->hotspot_x, event->hotspot_y); @@ -5007,6 +5062,10 @@ setfloating(Client *c, int32_t floating) { restore_size_per(c->mon, c); } + if (c->isfloating && !old_floating_state) { + save_old_size_per(c->mon); + } + if (!c->force_maximize) client_set_maximized(c, false); @@ -5093,6 +5152,10 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { restore_size_per(c->mon, c); } + if (c->ismaximizescreen && !old_maximizescreen_state) { + save_old_size_per(c->mon); + } + if (!c->force_maximize && !c->ismaximizescreen) { client_set_maximized(c, false); } else if (!c->force_maximize && c->ismaximizescreen) { @@ -5164,6 +5227,10 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 restore_size_per(c->mon, c); } + if (c->isfullscreen && !old_fullscreen_state) { + save_old_size_per(c->mon); + } + arrange(c->mon, false, false); } @@ -5523,6 +5590,9 @@ void setup(void) { idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor); + keep_idle_inhibit_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keep_idle_inhibit, NULL); + layer_shell = wlr_layer_shell_v1_create(dpy, 4); wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface); @@ -5590,8 +5660,8 @@ void setup(void) { cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); - hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hidecursor, cursor); /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, @@ -5619,6 +5689,8 @@ void setup(void) { LISTEN_STATIC(&cursor->events.hold_end, hold_end); seat = wlr_seat_create(dpy, "seat0"); + + wl_list_init(&last_cursor_surface_destroy_listener.link); wl_signal_add(&seat->events.request_set_cursor, &request_cursor); wl_signal_add(&seat->events.request_set_selection, &request_set_sel); wl_signal_add(&seat->events.request_set_primary_selection, @@ -5808,7 +5880,8 @@ void overview_restore(Client *c, const Arg *arg) { } void handlecursoractivity(void) { - wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, + cursor_hide_timeout * 1000); if (!cursor_hidden) return; @@ -5818,7 +5891,7 @@ void handlecursoractivity(void) { if (last_cursor.shape) wlr_cursor_set_xcursor(cursor, cursor_mgr, wlr_cursor_shape_v1_name(last_cursor.shape)); - else + else if (last_cursor.surface) wlr_cursor_set_surface(cursor, last_cursor.surface, last_cursor.hotspot_x, last_cursor.hotspot_y); } @@ -5829,6 +5902,36 @@ int32_t hidecursor(void *data) { return 1; } +void check_keep_idle_inhibit(Client *c) { + if (c && c->indleinhibit_when_focus && keep_idle_inhibit_source) { + wl_event_source_timer_update(keep_idle_inhibit_source, 1000); + } +} + +int32_t keep_idle_inhibit(void *data) { + + if (!idle_inhibit_mgr) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (session && !session->active) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (!selmon || !selmon->sel || !selmon->sel->indleinhibit_when_focus) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (seat && idle_notifier) { + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + wl_event_source_timer_update(keep_idle_inhibit_source, 1000); + } + return 1; +} + void unlocksession(struct wl_listener *listener, void *data) { SessionLock *lock = wl_container_of(listener, lock, unlock); destroylock(lock, 1); @@ -5843,17 +5946,20 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { init_fadeout_layers(l); wlr_scene_node_set_enabled(&l->scene->node, false); + if (l == exclusive_focus) exclusive_focus = NULL; + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) arrangelayers(l->mon); - if (l->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); + + reset_exclusive_layers_focus(l->mon); + motionnotify(0, NULL, 0, 0, 0, 0); - l->being_unmapped = false; layer_flush_blur_background(l); wlr_scene_node_destroy(&l->shadow->node); l->shadow = NULL; + l->being_unmapped = false; } void unmapnotify(struct wl_listener *listener, void *data) {