feat(host/session-watch): default Gaming↔Desktop follow on for Bazzite/SteamOS
apple / swift (push) Successful in 1m2s
android / android (push) Successful in 4m52s
ci / rust (push) Successful in 5m3s
ci / web (push) Successful in 55s
ci / docs-site (push) Successful in 54s
decky / build-publish (push) Successful in 22s
windows-host / package (push) Successful in 9m7s
ci / bench (push) Successful in 4m40s
apple / screenshots (push) Successful in 5m20s
deb / build-publish (push) Successful in 2m31s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 32s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m40s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m39s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m24s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 47s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m19s
docker / deploy-docs (push) Successful in 22s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 9m29s

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) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 08:43:27 +00:00
parent 3915a82780
commit 32c1929948
2 changed files with 44 additions and 4 deletions
+41 -2
View File
@@ -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<SessionSwitch>, stop: Arc<AtomicBool>) {
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::<SessionSwitch>();
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())
+3 -2
View File
@@ -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