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:
@@ -145,6 +145,10 @@ pub fn run(target: Option<&str>) -> u8 {
|
||||
trust::touch_last_used(&trust::hex(&fingerprint));
|
||||
})),
|
||||
overlay: Some(Box::new(overlay)),
|
||||
window_size: crate::session_main::window_size(&settings_at_start),
|
||||
// Latched at console start (like the stats tier above): toggling Match window in
|
||||
// the console's settings screen applies from the next console launch.
|
||||
match_window: crate::session_main::match_window(&settings_at_start),
|
||||
};
|
||||
|
||||
let result =
|
||||
|
||||
@@ -164,6 +164,34 @@ mod session_main {
|
||||
}
|
||||
}
|
||||
|
||||
/// The window's starting size under Match-window: the persisted last size, so the
|
||||
/// first connect's mode already matches the glass; `None` (policy off / never
|
||||
/// stored) = the 1280×720 default.
|
||||
pub(crate) fn window_size(settings: &trust::Settings) -> Option<(u32, u32)> {
|
||||
(settings.match_window && settings.last_window_w > 0 && settings.last_window_h > 0)
|
||||
.then_some((settings.last_window_w, settings.last_window_h))
|
||||
}
|
||||
|
||||
/// The Match-window policy hook for the presenter loop
|
||||
/// (design/midstream-resolution-resize.md D1/D2): `Some(persist)` turns the
|
||||
/// debounced resize→`Reconfigure` machinery on; the callback stores each resize-end's
|
||||
/// logical window size (load-modify-save, like the console settings screen) so the
|
||||
/// next launch opens at it.
|
||||
pub(crate) fn match_window(
|
||||
settings: &trust::Settings,
|
||||
) -> Option<Box<dyn FnMut(u32, u32)>> {
|
||||
settings.match_window.then(|| {
|
||||
Box::new(|w: u32, h: u32| {
|
||||
let mut s = trust::Settings::load();
|
||||
if (s.last_window_w, s.last_window_h) != (w, h) {
|
||||
s.last_window_w = w;
|
||||
s.last_window_h = h;
|
||||
s.save();
|
||||
}
|
||||
}) as Box<dyn FnMut(u32, u32)>
|
||||
})
|
||||
}
|
||||
|
||||
/// One JSON status line on stdout (the shell parses these; strings hand-escaped via
|
||||
/// the minimal rules a reason string can need). `pub(crate)`: browse mode emits its
|
||||
/// failure through the same contract when spawned with `--json-status`.
|
||||
@@ -343,6 +371,8 @@ mod session_main {
|
||||
overlay: Some(Box::new(pf_console_ui::SkiaOverlay::new())),
|
||||
#[cfg(not(feature = "ui"))]
|
||||
overlay: None,
|
||||
window_size: window_size(&settings),
|
||||
match_window: match_window(&settings),
|
||||
};
|
||||
|
||||
let outcome =
|
||||
|
||||
Reference in New Issue
Block a user