From 32c19299485cce1a8359e606bcacce17f4ac9795 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 28 Jun 2026 08:43:27 +0000 Subject: [PATCH] =?UTF-8?q?feat(host/session-watch):=20default=20Gaming?= =?UTF-8?q?=E2=86=94Desktop=20follow=20on=20for=20Bazzite/SteamOS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mid-stream session watcher (rebuild the backend in place when the box flips Gaming↔Desktop) was opt-in via PUNKTFUNK_SESSION_WATCH, so it never ran on a stock Bazzite/SteamOS box — switching modes froze the stream on the now-dead compositor. Default it ON when os-release ID/ID_LIKE is bazzite/steamos (the platforms that flip sessions); still off on plain desktops. Also parse the env properly so PUNKTFUNK_SESSION_WATCH=0 actually disables it (was: any value, including "0", enabled it). Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/punktfunk-host/src/punktfunk1.rs | 43 +++++++++++++++++++++++-- packaging/bazzite/host.env | 5 +-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/crates/punktfunk-host/src/punktfunk1.rs b/crates/punktfunk-host/src/punktfunk1.rs index 5dcf8a9..4870a91 100644 --- a/crates/punktfunk-host/src/punktfunk1.rs +++ b/crates/punktfunk-host/src/punktfunk1.rs @@ -2256,6 +2256,45 @@ struct SessionSwitch { /// read (so no handshake plumbing). Opt-in via `PUNKTFUNK_SESSION_WATCH`; readiness of the new /// backend is left to the encode thread's `build_pipeline_with_retry` (the watcher never writes /// env). Exits when `stop` is set or the channel closes. +/// Whether to run the mid-stream session-switch watcher. An explicit `PUNKTFUNK_SESSION_WATCH` wins +/// (truthy → on; `0`/`false`/`no`/`off`/empty → off). When unset it defaults **on** for Steam HTPC +/// platforms (Bazzite / SteamOS) — which flip Gaming↔Desktop and need the host to follow the switch +/// mid-stream — and **off** elsewhere, preserving the opt-in default for plain desktop hosts. +fn session_watch_enabled() -> bool { + match std::env::var("PUNKTFUNK_SESSION_WATCH") { + Ok(v) => { + let v = v.trim(); + !(v.is_empty() + || v == "0" + || v.eq_ignore_ascii_case("false") + || v.eq_ignore_ascii_case("no") + || v.eq_ignore_ascii_case("off")) + } + Err(_) => is_steam_htpc_platform(), + } +} + +/// True on Bazzite or SteamOS (matched against os-release `ID`/`ID_LIKE`) — the platforms that flip +/// between Steam Gaming Mode and a Desktop session, where following a mid-stream switch is the +/// sensible default. Anything else (incl. non-Linux, where the file is absent) → false. +fn is_steam_htpc_platform() -> bool { + let Ok(os) = std::fs::read_to_string("/etc/os-release") else { + return false; + }; + os.lines().any(|line| { + let line = line.trim(); + let Some(val) = line + .strip_prefix("ID=") + .or_else(|| line.strip_prefix("ID_LIKE=")) + else { + return false; + }; + val.trim_matches('"') + .split_whitespace() + .any(|tok| tok.eq_ignore_ascii_case("bazzite") || tok.eq_ignore_ascii_case("steamos")) + }) +} + fn session_watcher_loop(tx: std::sync::mpsc::Sender, stop: Arc) { use crate::vdisplay; const DEBOUNCE: std::time::Duration = std::time::Duration::from_secs(3); @@ -2491,9 +2530,9 @@ fn virtual_stream(ctx: SessionContext) -> Result<()> { // place when the box flips Gaming↔Desktop. When not spawned, session_rx just stays empty. let mut compositor = compositor; let (session_tx, session_rx) = std::sync::mpsc::channel::(); - let watch = std::env::var_os("PUNKTFUNK_SESSION_WATCH").is_some() - && crate::config::config().compositor.is_none(); + let watch = session_watch_enabled() && crate::config::config().compositor.is_none(); let _watcher = if watch { + tracing::info!("session watcher on — following a mid-stream Gaming↔Desktop switch"); let stop = stop.clone(); std::thread::Builder::new() .name("punktfunk1-watcher".into()) diff --git a/packaging/bazzite/host.env b/packaging/bazzite/host.env index 2fbbbd6..21855c6 100644 --- a/packaging/bazzite/host.env +++ b/packaging/bazzite/host.env @@ -27,5 +27,6 @@ PUNKTFUNK_ZEROCOPY=1 # PUNKTFUNK_GAMESCOPE_ATTACH=1 # PUNKTFUNK_GAMESCOPE_APP=steam -gamepadui # only for an ad-hoc bare-spawn fallback # -# Follow a Gaming<->Desktop switch MID-STREAM (rebuild the backend in place, no reconnect): -# PUNKTFUNK_SESSION_WATCH=1 +# Follow a Gaming<->Desktop switch MID-STREAM (rebuild the backend in place, no reconnect). This is +# ON BY DEFAULT on Bazzite/SteamOS (the host detects the platform); set =0 to disable it: +# PUNKTFUNK_SESSION_WATCH=0