From b472fa11d19a612157c8a75cdba8b7fb349af54a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 23 Jun 2026 14:45:06 +0800 Subject: [PATCH] feat: add windowrule option vrr_only_fullscreen --- docs/window-management/rules.md | 1 + src/config/parse_config.h | 4 ++++ src/mango.c | 42 +++++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md index 5c97961c..27ff8ab0 100644 --- a/docs/window-management/rules.md +++ b/docs/window-management/rules.md @@ -35,6 +35,7 @@ windowrule=Parameter:Values,Parameter:Values,appid:Values,title:Values | `single_scratchpad` | integer | `0` / `1` (default 1) | Only show one out of named scratchpads or the normal scratchpad | | `allow_shortcuts_inhibit` | integer | `0` / `1` (default 1) | Allow shortcuts to be inhibited by clients | | `idleinhibit_when_focus` | integer | `0` / `1` (default 0) | Automatically keep idle inhibit active when this window is focused | +| `vrr_only_fullscreen` | integer | `0` / `1` (default 0) | VRR only fullscreen,you need to turn `vrr` to `0` in monitor rule first | | `shield_when_capture` | integer | `0` / `1` | Shield window when captured | diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 875ce081..0103e8d3 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -80,6 +80,7 @@ typedef struct { int32_t ignore_minimize; int32_t isnosizehint; int32_t idleinhibit_when_focus; + int32_t vrr_only_fullscreen; char *monitor; int32_t offsetx; int32_t offsety; @@ -2364,6 +2365,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_minimize = -1; rule->isnosizehint = -1; rule->idleinhibit_when_focus = -1; + rule->vrr_only_fullscreen = -1; rule->isterm = -1; rule->allow_csd = -1; rule->force_fakemaximize = -1; @@ -2478,6 +2480,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->isnosizehint = atoi(val); } else if (strcmp(key, "idleinhibit_when_focus") == 0) { rule->idleinhibit_when_focus = atoi(val); + } else if (strcmp(key, "vrr_only_fullscreen") == 0) { + rule->vrr_only_fullscreen = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "allow_csd") == 0) { diff --git a/src/mango.c b/src/mango.c index 52ecdfbc..b90c06b2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -379,7 +379,8 @@ 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, idleinhibit_when_focus; + ignore_maximize, ignore_minimize, idleinhibit_when_focus, + vrr_only_fullscreen; int32_t ismaximizescreen; int32_t overview_backup_bw; int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -595,6 +596,8 @@ struct Monitor { struct wlr_ext_workspace_group_handle_v1 *ext_group; bool iscleanuping; int8_t carousel_anim_dir; + bool vrr_global_enable; + bool is_vrr_opening; }; typedef struct { @@ -1653,6 +1656,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); APPLY_INT_PROP(c, r, idleinhibit_when_focus); + APPLY_INT_PROP(c, r, vrr_only_fullscreen); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); @@ -3353,17 +3357,24 @@ struct wlr_output_mode *get_nearest_output_mode(struct wlr_output *output, } void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { + wlr_output_state_set_adaptive_sync_enabled(state, true); if (!wlr_output_test_state(m->wlr_output, state)) { wlr_output_state_set_adaptive_sync_enabled(state, false); wlr_log(WLR_DEBUG, "failed to enable adaptive sync for output %s", m->wlr_output->name); } else { + m->is_vrr_opening = true; wlr_log(WLR_INFO, "adaptive sync enabled for output %s", m->wlr_output->name); } } +void disable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { + wlr_output_state_set_adaptive_sync_enabled(state, false); + m->is_vrr_opening = false; +} + bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { if (rule->name != NULL && !regex_match(rule->name, m->wlr_output->name)) return false; @@ -3384,6 +3395,8 @@ bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, struct wlr_output_state *state, int vrr, int custom) { bool mode_set = false; + m->vrr_global_enable = vrr; + 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); @@ -3400,7 +3413,7 @@ bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, if (vrr) { enable_adaptive_sync(m, state); } else { - wlr_output_state_set_adaptive_sync_enabled(state, false); + disable_adaptive_sync(m, state); } wlr_output_state_set_scale(state, rule->scale); wlr_output_state_set_transform(state, rule->rr); @@ -3439,6 +3452,8 @@ void createmon(struct wl_listener *listener, void *data) { m->resizing_count_pending = 0; m->resizing_count_current = 0; m->carousel_anim_dir = 0; + m->vrr_global_enable = false; + m->is_vrr_opening = false; m->wlr_output = wlr_output; m->wlr_output->data = m; @@ -4603,6 +4618,7 @@ void init_client_properties(Client *c) { c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->idleinhibit_when_focus = 0; + c->vrr_only_fullscreen = 0; c->scroller_proportion_single = 0.0f; c->float_geom.width = 0; c->float_geom.height = 0; @@ -5140,8 +5156,12 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { wlr_output_state_set_transform(&state, config_head->state.transform); wlr_output_state_set_scale(&state, config_head->state.scale); - wlr_output_state_set_adaptive_sync_enabled( - &state, config_head->state.adaptive_sync_enabled); + + if (config_head->state.adaptive_sync_enabled) { + enable_adaptive_sync(m, &state); + } else { + disable_adaptive_sync(m, &state); + } apply_or_test: ok &= test ? wlr_output_test_state(wlr_output, &state) @@ -6637,6 +6657,20 @@ void check_keep_idle_inhibit(Client *c) { if (c && c->idleinhibit_when_focus && keep_idle_inhibit_source) { wl_event_source_timer_update(keep_idle_inhibit_source, 1000); } + + if (c && c->mon && c->vrr_only_fullscreen && c->isfullscreen && + !c->mon->is_vrr_opening) { + struct wlr_output_state state = {0}; + enable_adaptive_sync(c->mon, &state); + } else if (c && c->mon && (!c->vrr_only_fullscreen || !c->isfullscreen)) { + if (!c->mon->is_vrr_opening && c->mon->vrr_global_enable) { + struct wlr_output_state state = {0}; + enable_adaptive_sync(c->mon, &state); + } else if (c->mon->is_vrr_opening && !c->mon->vrr_global_enable) { + struct wlr_output_state state = {0}; + disable_adaptive_sync(c->mon, &state); + } + } } int32_t keep_idle_inhibit(void *data) {