Files
enricobuehler 77834be4e4 feat(clients)!: retire the "Show game library" toggle — the library is simply there now
The console's Interface tab still offered an enable/disable switch for the game
library, left over from when the feature was experimental. Removing it turned out
to be the opposite of a one-line deletion.

The console never read the setting. Its row rendered a value and flipped a bool,
and every library affordance in the console — the home Y hint, the Y press, the
`--browse <host>` deep link — is gated on PAIRING and nothing else. So the row
showed "Game library · Off" while the same shell handed you the library on Y. The
docs already said as much.

What the flag actually gated was the other two desktop shells, GTK and WinUI,
which hide "Browse library…" unless it is on — and its stored default is `false`.
So deleting only the console row would have left every user who never found this
switch with a hidden library in the desktop apps, while removing the last place in
Gaming Mode where it could be turned on. The letter of the request, and the exact
opposite of its intent.

So the field goes, not just the row: `trust::Settings::library_enabled` and all
four reads of it. No migration code and no serde alias is needed, and that is by
construction rather than by luck — `Settings` is `#[serde(default)]` with a
`#[serde(flatten)] extra` map, so a stored `"library_enabled": false` parses into
`extra`, round-trips untouched, and is ignored. Everyone who had it off now has
the library, and a downgraded binary still finds its old value under the same key.
A test pins that contract, since it is the whole reason this is safe.

At the two GTK and two WinUI menu sites the flag is replaced by the PAIRING
predicate rather than dropped for an unconditional item. The library fetch
authenticates with the paired identity, and GTK's saved cards include trusted-but-
unpaired hosts, so an unconditional menu entry would promote a documented latent
bug — a fetch that cannot authenticate — into the default experience on every
install.

Apple and Android keep their own independent toggles for now, deliberately: both
already default TRUE, so nobody there loses anything by our not touching them, and
their removal is a follow-up rather than a rushed edit across two more UI
frameworks in this change.

VERIFICATION. The console and GTK legs are gate-green in the Linux container
(clippy `-D warnings`, a plain non-test build, and the test suites), and the GTK
leg needed that plain build: deleting the read orphaned the struct field that held
the settings store, which `--all-targets` hides and a shipping build raises.
The WinUI edits are READ-VERIFIED ONLY — `punktfunk-client-windows` is
`cfg(windows)` and compiles on neither the Mac nor the Linux container, so they
are unproven until a Windows runner sees them.
2026-08-16 19:03:53 +02:00
..

punktfunk — Windows client

The native Windows app for streaming a punktfunk host to your PC. A modern WinUI 3 app that discovers hosts on your network, pairs with a PIN, and streams at your display's own resolution and refresh rate — with hardware-accelerated video decode and HDR.

It's pure Rust: the UI is WinUI 3 driven through windows-reactor (a declarative, React-like framework), and it links the shared punktfunk-core directly to speak the fast punktfunk/1 protocol.

Features

  • Hardware decode, GPU present — Punktfunk's own decoders, no FFmpeg anywhere in the client: Vulkan Video (pf-vkdecode) leads on NVIDIA and AMD, D3D11VA (pf-dxvadec driving ID3D11VideoDecoder) leads on Intel, whichever isn't first is the fallback, and an OpenH264/rav1d CPU rung is last. Either hardware rung hands its surface to the Vulkan presenter without a CPU copy.
  • HDR10 — advertise 10-bit/HDR, detect PQ in-band, and flip the swapchain to R10G10B10A2 + ST.2084 with HDR10 metadata.
  • Your display's native mode — the host builds a virtual display at exactly your WxH@Hz.
  • Audio both ways — WASAPI render + mic capture.
  • Full controller support — SDL3 gamepads with rumble, lightbar, and DualSense feedback.
  • Your display's native mode, really — "Native display" resolves the actual size + refresh of the monitor the window is on at connect time.
  • Find hosts automatically — mDNS discovery lists hosts on your LAN, alongside saved and manual entries. First connect does a one-time SPAKE2 PIN pairing (or TOFU on trusted LANs), then reconnects on a pinned identity. Saved hosts carry per-host actions: a network speed test (probe burst over the real data plane → recommended bitrate, applied in one tap) and forget.
  • Polished shell — host cards, settings (resolution / refresh / host compositor / decoder / codec / bitrate / HDR / forwarded controller / gamepad type / system shortcuts / audio channels / mic / stats-overlay level), the tiered stats overlay (Off / Compact / Normal / Detailed — Ctrl+Alt+Shift+S cycles it live in the session window), and the full trust surface. Stream input uses Win32 low-level hooks with Moonlight-style capture: Ctrl+Alt+Shift+Q releases the pointer, a click on the stream re-captures it, and system shortcuts (Alt+Tab, Win, …) can act locally or forward to the host.

Builds and ships for both x64 and ARM64 as a signed MSIX.

Get it

Install the signed MSIX from the package registry — see docs.punktfunk.unom.io/docs/install-client. A stock Moonlight client also works over GameStream if you prefer.

Build from source

Windows-only (the crate builds as a stub on other platforms so the workspace stays green). You need the MSVC toolchain and CMake (SDL3 builds from source) — nothing else: decode is native since M10, so there is no FFMPEG_DIR to point anywhere, and the Windows App SDK runtime bootstrap is staged next to the exe by windows-reactor-setup from this crate's own build.rs.

cargo build -p punktfunk-client-windows --target x86_64-pc-windows-msvc

# CLI paths for testing (no window):
punktfunk-client --discover                                   # list hosts on the LAN
punktfunk-client --headless --connect host[:port] [--pin HEX] # connect, count frames, print stats
punktfunk-client --headless --speed-test --connect host[:port]  # probe burst → recommended bitrate

CARGO_HOME must be an ASCII path — non-ASCII characters break SDL3's MSVC precompiled-header build. Packaging (MSIX manifest, signing) lives in packaging/.

Layout

Decode/present/input live in the spawned punktfunk-session binary (clients/session), not here — this crate is the shell that discovers, pairs, and launches it.

src/
  main.rs                 entry point + CLI paths (--discover · --headless · --speed-test)
  bin/punktfunk-console.rs  the couch/HTPC Start-menu entry (re-execs with --console)
  app/                    WinUI 3 shell (windows-reactor), one module per screen:
                          mod (root/router) · hosts · connect · pair · speed · settings ·
                          library · help · licenses · stream · style (shared cards/pills)
  deeplink.rs             punktfunk:// activation, single-instance hand-off, shortcut writer
  spawn.rs                punktfunk-session child process + its stdout event contract
  shell_window.rs         hide/restore the shell HWND around a session
  gpu.rs                  DXGI adapter enumeration for the GPU picker
  trust.rs · discovery.rs persistent identity, TOFU/PIN pairing, mDNS browse
  probe.rs · wol.rs       speed probe · Wake-on-LAN
  logfile.rs              log tee to %LOCALAPPDATA%
packaging/                MSIX manifest, signing, pack script

Manual smoke checklist

The windows-reactor pin is a moving target and WinUI regressions rarely show up in cargo check — walk this after a reactor bump or a change to the render/state architecture:

  • Hosts — discovery populates tiles; tile hover fill; "…" menu → Forget and Rename; add-host modal connects; WOL wait screen cancels.
  • Settings — every section renders; combos still show their selection after a section switch AND a scope switch (the historic blank-combo reconciler bug); profile create / rename / delete (with confirm); colour swatches repaint; the Overridden marker appears on edit and clears on Reset; GPU combo lists adapters.
  • Pair — PIN entry pairs (the typed PIN must reach the Connect click — use_ref mirror path).
  • Session — connect → session spawns → HUD stats tick; Ctrl+Alt+Shift+Q releases the pointer; shell window restores on exit.
  • Shell — speed test completes; library grid loads; punktfunk:// deep link routes (second instance hands off and exits); window icon appears; screen-entrance animations play.