feat(resize): mid-stream resolution resize — host hardening (H1–H5) + session-binary Match window (C1)
design/midstream-resolution-resize.md Phase 0 + Phase 1. Host (Phase 0): - H1/H5: per-backend Reconfigure acceptance gate — reject for gamescope (all sub-modes; a resize must never relaunch the title) and under the per-client-mode identity policy (a resize would resolve a different display slot). Synthetic stays reconfigurable on purpose (the protocol test source; the C-ABI roundtrip test rides it). Plus a 500 ms host-side min-interval backstop against Reconfigure spam. - H2: rollback/corrective ack — the data plane reports the mode actually live after a failed rebuild (or a refresh the backend capped) through a reconfig_result channel; the control task forwards it as a second accepted Reconfigured so the client's mode slot self-corrects. - H3: live stats mode — SendStats reads a packed AtomicU64 (w|h|hz) updated on every switch instead of latching the session-start mode. - H4: registry::retire(gen) — a mode-switch rebuild force-releases the superseded Linux display, so linger/forever keep-alive policies don't accumulate kept monitors at stale modes. VirtualOutput carries pool_gen (fresh AND reused) and the Pipeline tuple threads it to the switch arm. Client (Phase 1, default off): - Settings: match_window policy + persisted last window size; exposed as the Resolution tri-state (Native / Match window / explicit) in the Skia console, GTK and WinUI settings pages. - pf-presenter: window opens at the persisted size; Hello mode follows the window's pixel size; D2 trigger discipline (400 ms debounce to resize-end, ≥1 s spacing, even-floor + ≥320×200 clamp, each distinct size requested at most once — covers rejects and host rollbacks) as a pure, unit-tested decision; HUD line + title refresh on a switch. - Session binary wires both --connect and --browse paths; the WinUI shell is session-always, so this covers Windows too. Verified: workspace tests + clippy green; synthetic --remode end-to-end; live session-binary run (window at persisted 1000×600 → Hello 1000×600@60). On-glass per-backend matrix (Mutter/KWin/gamescope-reject, keep-alive accumulation) still pending before any default flip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -136,29 +136,37 @@ pub(crate) fn settings_page(
|
||||
let s = ctx.settings.lock().unwrap().clone();
|
||||
|
||||
// --- Display ---------------------------------------------------------------------------
|
||||
// The D1 tri-state: Native, Match window (a virtual index 1, stored as the
|
||||
// `match_window` flag), then the explicit sizes.
|
||||
let (res_names, res_i) = {
|
||||
let names: Vec<String> = RESOLUTIONS
|
||||
.iter()
|
||||
.map(|&(w, h)| {
|
||||
if w == 0 {
|
||||
"Native display".into()
|
||||
} else {
|
||||
format!("{w} \u{00D7} {h}")
|
||||
}
|
||||
})
|
||||
let names: Vec<String> = std::iter::once("Native display".to_string())
|
||||
.chain(std::iter::once("Match window".to_string()))
|
||||
.chain(
|
||||
RESOLUTIONS
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|&(w, h)| format!("{w} \u{00D7} {h}")),
|
||||
)
|
||||
.collect();
|
||||
let i = RESOLUTIONS
|
||||
.iter()
|
||||
.position(|&(w, h)| w == s.width && h == s.height)
|
||||
.unwrap_or(0);
|
||||
let i = if s.match_window {
|
||||
1
|
||||
} else {
|
||||
RESOLUTIONS
|
||||
.iter()
|
||||
.position(|&(w, h)| w == s.width && h == s.height)
|
||||
.map(|i| if i == 0 { 0 } else { i + 1 })
|
||||
.unwrap_or(0)
|
||||
};
|
||||
(names, i)
|
||||
};
|
||||
let res_combo = setting_combo(ctx, "Resolution", res_names, res_i, |s, i| {
|
||||
(s.width, s.height) = RESOLUTIONS[i];
|
||||
s.match_window = i == 1;
|
||||
(s.width, s.height) = if i <= 1 { (0, 0) } else { RESOLUTIONS[i - 1] };
|
||||
})
|
||||
.tooltip(
|
||||
"The host creates a virtual display at exactly this size. \u{201C}Native display\u{201D} \
|
||||
resolves to the monitor this window is on at connect.",
|
||||
resolves to the monitor this window is on at connect; \u{201C}Match window\u{201D} \
|
||||
follows the stream window, including mid-stream resizes.",
|
||||
);
|
||||
let (hz_names, hz_i) = {
|
||||
let names: Vec<String> = REFRESH
|
||||
|
||||
Reference in New Issue
Block a user