The flatpak's gamescope env stops faking Gaming Mode #464

Merged
enricobuehler merged 1 commits from worktree-gamescope-env-fullscreen into main 2026-08-30 23:38:19 +00:00
Owner

A field report on 2026-08-30: "the GTK client is just launching in fullscreen." Reproduced on
.21 — a plain GNOME desktop, launched from the .desktop entry, with no Deck and no gamescope
anywhere on the box.

What causes it

The shell fullscreens itself when cli::fullscreen_mode() is true, and that read
GAMESCOPE_WAYLAND_DISPLAY as proof of Gaming Mode. Our own flatpak sets it unconditionally.
packaging/flatpak/io.unom.Punktfunk.yml exports --env=GAMESCOPE_WAYLAND_DISPLAY=gamescope-0
because the vendored gamescope WSI layer reads that one variable and nothing else to decide
whether to negotiate HDR10 — the manifest's own comment calls it "the layer's ONLY 'am I under
gamescope?' signal"
. So inside the sandbox it is set on every launch, on every desktop.

Verified rather than reasoned: on .21, flatpak run --command=env io.unom.Punktfunk prints
GAMESCOPE_WAYLAND_DISPLAY=gamescope-0 while the host has neither a gamescope process nor a
/run/user/1000/gamescope-* socket.

The manifest line landed in e1adc5d6 (2026-08-05) and shipped from v0.25.0, which dates the
regression. The flatpak is the main Linux channel, so this has hit every flatpak user on every
desktop for six releases.

Fullscreen was the visible quarter of it

The same misreading also meant:

  • a stream ignored fullscreen_on_stream = false — the env ORed straight past the flag the client
    resolves that setting into;
  • the settings dialog swapped every dropdown for a subpage, the workaround meant for gamescope's
    unmapped popovers;
  • the system-button "auto" policy picked Deck rules, handing Steam and QAM to a local Steam UI
    that is not running;
  • the overlay-focus watcher took the gamescope path.

The fix

The variable has to keep being exported — the WSI layer needs it — so the fix is in what we
accept as proof. pf_client_core::gamescope::under_gamescope() is now the one answer, and all six
readers route through it:

  • WAYLAND_DISPLAY settles it whenever we have one. A desktop session inside the sandbox still
    gets --socket=wayland, so it names the desktop compositor. That mismatch is exactly what the
    WSI layer itself bails on.
  • Gaming Mode leaves nothing to compare — it runs apps as X11 clients (DISPLAY=:1, no
    WAYLAND_DISPLAY) — so there the fallback is the named socket actually existing. The flatpak
    binds it (--filesystem=xdg-run/gamescope-0) for HDR anyway, so this is the same reachability
    the layer depends on.

Also dropped the SteamDeck leg from the Gaming-Mode tests while here, because it names the
machine rather than the session, so a Deck in desktop mode was fullscreening too.
is_steam_deck() genuinely wants machine identity and keeps its check, but now compares the value:
Valve documents SteamDeck=1, and desktop Steam exports SteamDeck=0 into everything it launches,
so a presence check called every PC with Steam a Deck.

Verification

Run on .21 (CachyOS, GNOME), because cargo test -p pf-client-core on macOS is pre-existing red
from target-gated dependencies:

  • cargo fmt --all --check clean, before and after the rebase onto 37bb8948.
  • The new only_a_real_gamescope_counts test passes. It covers the flatpak-on-desktop shape (both
    with and without some other gamescope running on the box), a real nested gamescope, and Game Mode
    with and without a live socket.
  • cargo clippy -D warnings --all-targets green across pf-client-core, pf-presenter,
    punktfunk-client-linux and punktfunk-client-session. All four were confirmed really built in
    the log rather than skipped as fresh — the warm shared target dir prints Finished without
    checking otherwise.

Not verified on glass. Nobody has yet watched a rebuilt flatpak launch windowed on a desktop,
and no Deck in Game Mode has confirmed it still fullscreens. Both need a flatpak build.

A field report on 2026-08-30: *"the GTK client is just launching in fullscreen."* Reproduced on .21 — a plain GNOME desktop, launched from the `.desktop` entry, with no Deck and no gamescope anywhere on the box. ## What causes it The shell fullscreens itself when `cli::fullscreen_mode()` is true, and that read `GAMESCOPE_WAYLAND_DISPLAY` as proof of Gaming Mode. **Our own flatpak sets it unconditionally.** `packaging/flatpak/io.unom.Punktfunk.yml` exports `--env=GAMESCOPE_WAYLAND_DISPLAY=gamescope-0` because the vendored gamescope WSI layer reads that one variable and nothing else to decide whether to negotiate HDR10 — the manifest's own comment calls it *"the layer's ONLY 'am I under gamescope?' signal"*. So inside the sandbox it is set on every launch, on every desktop. Verified rather than reasoned: on .21, `flatpak run --command=env io.unom.Punktfunk` prints `GAMESCOPE_WAYLAND_DISPLAY=gamescope-0` while the host has neither a gamescope process nor a `/run/user/1000/gamescope-*` socket. The manifest line landed in `e1adc5d6` (2026-08-05) and shipped from **v0.25.0**, which dates the regression. The flatpak is the main Linux channel, so this has hit every flatpak user on every desktop for six releases. ## Fullscreen was the visible quarter of it The same misreading also meant: - a stream ignored `fullscreen_on_stream = false` — the env ORed straight past the flag the client resolves that setting into; - the settings dialog swapped every dropdown for a subpage, the workaround meant for gamescope's unmapped popovers; - the system-button "auto" policy picked Deck rules, handing Steam and QAM to a local Steam UI that is not running; - the overlay-focus watcher took the gamescope path. ## The fix The variable has to keep being exported — the WSI layer needs it — so the fix is in what *we* accept as proof. `pf_client_core::gamescope::under_gamescope()` is now the one answer, and all six readers route through it: - **`WAYLAND_DISPLAY` settles it whenever we have one.** A desktop session inside the sandbox still gets `--socket=wayland`, so it names the *desktop* compositor. That mismatch is exactly what the WSI layer itself bails on. - **Gaming Mode leaves nothing to compare** — it runs apps as X11 clients (`DISPLAY=:1`, no `WAYLAND_DISPLAY`) — so there the fallback is the named socket actually existing. The flatpak binds it (`--filesystem=xdg-run/gamescope-0`) for HDR anyway, so this is the same reachability the layer depends on. Also dropped the `SteamDeck` leg from the Gaming-Mode tests while here, because it names the *machine* rather than the session, so a Deck in **desktop** mode was fullscreening too. `is_steam_deck()` genuinely wants machine identity and keeps its check, but now compares the value: Valve documents `SteamDeck=1`, and desktop Steam exports `SteamDeck=0` into everything it launches, so a presence check called every PC with Steam a Deck. ## Verification Run on .21 (CachyOS, GNOME), because `cargo test -p pf-client-core` on macOS is pre-existing red from target-gated dependencies: - `cargo fmt --all --check` clean, before and after the rebase onto `37bb8948`. - The new `only_a_real_gamescope_counts` test passes. It covers the flatpak-on-desktop shape (both with and without some other gamescope running on the box), a real nested gamescope, and Game Mode with and without a live socket. - `cargo clippy -D warnings --all-targets` green across `pf-client-core`, `pf-presenter`, `punktfunk-client-linux` and `punktfunk-client-session`. All four were confirmed really built in the log rather than skipped as fresh — the warm shared target dir prints `Finished` without checking otherwise. **Not verified on glass.** Nobody has yet watched a rebuilt flatpak launch windowed on a desktop, and no Deck in Game Mode has confirmed it still fullscreens. Both need a flatpak build.
enricobuehler added 1 commit 2026-08-30 23:13:13 +00:00
fix(clients): the flatpak's gamescope env stops faking Gaming Mode
ci / web (pull_request) Successful in 1m5s
ci / docs-site (pull_request) Successful in 1m7s
ci / bun-nix (pull_request) Successful in 27s
ci / rust-arm64 (pull_request) Successful in 3m50s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 3m9s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 6m55s
android / android (pull_request) Successful in 12m58s
ci / docs-drift (pull_request) Failing after 14m41s
ci / rust (pull_request) Successful in 18m26s
7580bd70fd
A field report on 2026-08-30: "the GTK client is just launching in
fullscreen". Reproduced on a plain GNOME desktop (.21), launched from
the .desktop entry, with no Deck and no gamescope anywhere on the box.

The shell fullscreens itself when `cli::fullscreen_mode()` is true, and
that read `GAMESCOPE_WAYLAND_DISPLAY` as proof of Gaming Mode. Our own
flatpak sets it unconditionally: `packaging/flatpak/io.unom.Punktfunk.yml`
exports `GAMESCOPE_WAYLAND_DISPLAY=gamescope-0` because the vendored
gamescope WSI layer reads that variable and nothing else to decide
whether to negotiate HDR10 (e1adc5d6, 2026-08-05, shipped in v0.25.0).
So inside the sandbox it is set on every launch, on every desktop —
verified in the sandbox on .21, where the host has neither a gamescope
process nor a socket. The flatpak is the main Linux channel, so this hit
every flatpak user on every desktop since v0.25.0.

Fullscreen was only the visible half. The same reading also meant:

- a stream ignored `fullscreen_on_stream = false` (the env ORed straight
  past the flag the client resolves the setting into);
- the settings dialog swapped every dropdown for a subpage, the
  workaround meant for gamescope's unmapped popovers;
- the system-button "auto" policy picked Deck rules, handing Steam/QAM
  to a local Steam UI that is not there;
- the overlay-focus watcher took the gamescope path.

The variable has to keep being exported, so the fix is in what we accept
as proof. `pf_client_core::gamescope::under_gamescope()` is now the one
answer, and all six readers route through it: `WAYLAND_DISPLAY` settles
it whenever we have one (a desktop session in the sandbox still gets
`--socket=wayland`, so it names the desktop compositor — the same
mismatch the WSI layer bails on), and Gaming Mode, which runs apps as
X11 clients with no `WAYLAND_DISPLAY`, falls back to the named socket
actually existing.

Dropped the `SteamDeck` leg from the Gaming-Mode tests while here: it
says which MACHINE this is, so a Deck in DESKTOP mode was fullscreening
too. `is_steam_deck()` still wants machine identity and keeps it, but
now compares the value — Valve documents `SteamDeck=1`, and desktop
Steam exports `SteamDeck=0` into everything it launches, so the presence
check called every PC with Steam a Deck.

Verified on .21 (CachyOS, GNOME): `cargo fmt --all --check` clean; the
new `only_a_real_gamescope_counts` test passes; `cargo clippy -D
warnings --all-targets` green over pf-client-core, pf-presenter,
punktfunk-client-linux and punktfunk-client-session, with all four
confirmed really built in the log rather than skipped as fresh.
enricobuehler merged commit 3b8a8230cd into main 2026-08-30 23:38:19 +00:00
enricobuehler deleted branch worktree-gamescope-env-fullscreen 2026-08-30 23:38:25 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#464