Files
punktfunk/docs/releases/v0.19.2.md
T
enricobuehlerandClaude Opus 4.8 f4fe4d0792
android-screenshots / screenshots (push) Successful in 2m59s
windows-host / package (push) Successful in 9m45s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m48s
android / android (push) Successful in 12m37s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 2m20s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 1m5s
arch / build-publish (push) Successful in 12m2s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m45s
audit / cargo-audit (push) Successful in 2m10s
audit / bun-audit (push) Successful in 14s
ci / web (push) Successful in 54s
ci / docs-site (push) Successful in 1m6s
apple / swift (push) Successful in 1m57s
ci / bench (push) Successful in 5m41s
ci / rust (push) Successful in 18m52s
decky / build-publish (push) Successful in 20s
deb / build-publish (push) Successful in 8m50s
deb / build-publish-host (push) Successful in 9m24s
web-screenshots / screenshots (push) Successful in 3m7s
flatpak / build-publish (push) Successful in 6m27s
docker / deploy-docs (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 11s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 15s
release / apple (push) Successful in 1h4m50s
apple / screenshots (push) Successful in 23m21s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m40s
linux-client-screenshots / screenshots (push) Successful in 7m14s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m0s
chore(release): bump workspace version to 0.19.2
An all-fixes patch on top of 0.19.1, all host-side:

- KDE Plasma display takeover moved off kscreen-doctor to in-process
  kde_output_management_v2 (86d5d666), with the >60 Hz custom-mode install
  ported too (64511af4) — a KWin host whose kscreen-doctor wedges now disables
  its physicals and hands over the streamed output in ~2.4 ms instead of hanging
  ~26 s and never taking over.
- The gamescope managed takeover is display-manager-flavor-aware (e35dad52) so
  switching a non-SDDM Linux desktop (Nobara / plasmalogin) into Game Mode no
  longer start-limits the display manager into a permanent black screen, and
  in-stream 'Switch to Desktop' is honored under it (a3e21d92).
- Windows display isolation anchors the kept sources at the desktop origin
  (9b241d9d) so an origin-less desktop no longer fails 0x57, with restore
  guaranteed never to leave the desktop all-dark.
- Windows pen/touch/absolute-mouse map over the streamed output's rect rather
  than the whole virtual desktop (087e7d04), so absolute input lands correctly
  when a physical monitor is kept on beside the streamed display.

Nothing moved on the wire (protocol 2) or at the C ABI (13), so no embedder
rebuild and 0.18/0.19 peers keep mixing freely. The Windows virtual-display
driver protocol is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 17:56:08 +02:00

11 KiB
Raw Blame History

A small fixes update, all on the machine you stream from — your apps don't change, you can update whenever, and everything you've already paired stays paired.

This one cleans up a handful of things that went wrong on specific setups. On a KDE Plasma desktop, streaming now properly takes over the screen — switching off the real monitors and handing you the streamed display — and comes up in a couple of seconds instead of stalling, even on machines where KDE's own display tools had stopped responding. On a Linux machine you switch into Steam's Game Mode, that switch no longer risks leaving the machine stuck on a black screen, and you can now switch back to the desktop from inside the stream. And on Windows, giving the stream its own dedicated display is reliable again and can no longer leave the real desktop dark — and pen, touch and absolute-position mouse now land where you point when a second monitor is in play.

Fixed: streaming from a KDE Plasma desktop takes over the screen — and comes up fast

On some KDE Plasma machines — a Nobara media PC among them — connecting used to look like it worked but leave the real monitors on and never actually hand you the streamed display, after a long wait of around half a minute. The cause was KDE's own display tooling hanging on that machine, with Punktfunk waiting on it.

Punktfunk now sets the machine's displays up by talking to KDE directly instead of going through that tool:

  • The streamed display actually becomes the desktop. The physical monitors switch off for the session and come back when you disconnect — reliably, and typically in a couple of seconds instead of half a minute.
  • It works even when KDE's display settings tool is unresponsive — the exact case that used to break connecting entirely.
  • High refresh rates work on these machines too. The 90/120 Hz path no longer leans on that same tool. (Machines where the tool was healthy already worked; this just removes the dependency.)

Fixed: switching a Linux machine into Steam's Game Mode no longer breaks it

Switching a Linux desktop into Steam's Game Mode mid-stream could leave the whole machine on a permanent black screen — on desktops that don't use the same sign-in manager as a Steam Deck (a Nobara home-theatre PC was the report). Steam Deck-style machines were never affected.

The switch is safe now: Punktfunk hands the screen to Game Mode without taking down the machine's sign-in manager, and puts everything back when you disconnect. On a machine where it doesn't have permission to do that cleanly, it mirrors whatever Game Mode is already showing rather than risk the screen — so you always get a picture instead of a black one.

New: switch back to the desktop from inside the stream

On a Linux machine that Punktfunk put into Game Mode for you, choosing Switch to Desktop from Steam's menu used to do nothing — it just dropped you straight back into Game Mode. It now actually returns the machine to its desktop, and the stream follows it there.

Fixed: giving the stream its own display on Windows is reliable again — and never goes dark

The experimental option that isolates the stream onto its own display on Windows (switching off the physical monitors) could fail outright on some monitor layouts, and a failed attempt could leave the real desktop on a black screen.

  • It works across monitor layouts now, not only when a physical monitor happened to sit in the top-left corner of the desktop.
  • The desktop is never left dark. If restoring your original layout can't light a screen back up, Punktfunk falls back to a normal extended-desktop arrangement, so you're never stranded looking at black.

Fixed: pen, touch and absolute mouse land where you point on a multi-monitor Windows machine

When you stream from a Windows machine that keeps a physical monitor on alongside the streamed display, pen, touch, and absolute-position mouse input landed in the wrong spot — shifted across and scaled wrong, so a stylus drew where you weren't pointing. A single-display setup was never affected; the pen showed it first, because a stylus is pure point-where-you-touch with nothing to correct it.

Input now maps onto the streamed display itself, so the pen lands exactly where you touch — and it keeps up if you rearrange the machine's monitors mid-session.

Under the hood (for developers)

  • Nothing changed on the wire or at the API boundary. The streaming protocol stays at version 2 and the embeddable core library stays at C ABI 13 — no embedder rebuild is required, and 0.18/0.19 hosts and clients still mix freely. The Windows virtual-display driver protocol is unchanged.
  • KWin display topology now runs in-process over kde_output_management_v2 / kde_output_device_v2, not kscreen-doctor. kscreen-doctor drives libkscreen, which waits on the kscreen KDED module over D-Bus; when that layer wedges it blocks in its own connect and never returns, so all five topology queries hit their 5 s budget and are killed — the physicals never disable and the virtual output never becomes the desktop (also_disabled=[], ~26 s bring-up) even though the compositor's own Wayland is fully responsive. The host now resolves its output by stable device UUID (supersede-robust), takes primary, disables the physical/bootstrap outputs (capturing their modes to re-enable on teardown) and positions — all over bounded Wayland round-trips (management v19 bound + outputs enumerated in ~2.4 ms on KWin 6.6.4, ~3400× faster than the hang). Every wait is time-bounded, so a genuinely wedged compositor degrades to handled = false and the old kscreen-doctor path still runs.
  • >60 Hz custom modes install in-process too, so the whole KWin path is kscreen-free on modern KWin. set_custom_mode builds a one-entry kde_mode_list_v2 and applies it via kde_output_configuration_v2.set_custom_modes (since v18), waits for KWin to generate the mode (its CVT generator may align the width down — matched with the same height-exact / width-within-8 / refresh-within-1 Hz gate as before), then selects it, which drives the sacrificial-birth stream renegotiation. set_custom_modes replaces the custom list, so reconnects are idempotent — no more one-custom-mode-per-connect growth of the display's mode list — and a >60 Hz session no longer eats a 5 s kscreen resolve timeout on a box where the tool wedges. Pre-6.6 KWin without set_custom_modes falls back to set_custom_refresh.
  • The gamescope managed takeover is display-manager-flavor-aware. Masking the box's gamescope-session-plus unit made plasmalogin's Relogin=true fail its Exec repeatedly and trip systemd's start limit within ~1 s — the DM dies, and the restore verb (unmask + user start) cannot bring a seatless gamescope back; only reset-failed + restart recovers. SDDM (Bazzite/SteamOS) keeps the proven mask + SIGKILL path. plasmalogin / unknown DMs are never masked: with privilege (root or a scoped operator polkit rule on the DM unit — documented) the host stops the DM for the stream and restores it with reset-failed + restart (recorded in the persisted takeover state so a host crash still restores); without privilege the managed takeover degrades to attach and mirrors the live Game Mode. Companion fixes from the same triage: an attach-only rebuild-probe guard on ensure_box_gamescope_mode (which also no longer re-modes a box that drives a physical display), a 100 s capture-loss rebuild budget for gamescope (the 40 s budget expired inside Steam's first ~45 s cold-start attempt), a once-per-capture-loss WARN when a PUNKTFUNK_COMPOSITOR pin no longer matches the live session, and a managed session that took nothing over is stopped on disconnect instead of orphaned.
  • In-stream "Switch to Desktop" is honored under the managed takeover. Steam's session-select is a silent no-op while the DM is stopped (its config-write branches all require the DM running), so it merely relaunched Game Mode. The managed launch now baselines the ~/.config/steamos-session-select sentinel's mtime; a capture loss with the sentinel advanced is read as the switch request and replayed with the DM up — restore the DM, run the distro's own os-session-select (its internal pkexec is authorized allow_any by the distro policy, so it works from the host's sessionless context), then stop the autologin game-mode unit so Relogin lands in the newly selected desktop. A 120 s post-honor grace keeps the rebuild loop from racing the booting desktop back into Game Mode (superseded early if the box's own game-mode unit reappears, so the desktop→game leg stays fast). The baseline is re-recorded on crash-restore so a pre-existing sentinel never reads as a fresh request.
  • Windows absolute input maps over the streamed output's desktop rect, not the whole virtual desktop. Pen, touch and absolute mouse arrive normalized to the streamed display's frame, but pointer_windows::to_screen and sendinput's MouseMoveAbs mapped them across the entire virtual desktop — correct only when the virtual display is the sole active display (Exclusive topology). In Extend — a physical kept on beside the virtual output, or an Exclusive isolate degraded to the 0x57 keep-physicals fallback — the streamed output sits at a non-zero origin, so every sample landed shifted and mis-scaled, and the strictly-absolute pen (no closed-loop correction onto the target) exposed it first. New pf-inject::stream_target publishes the streamed output's CCD target id at capture bring-up (one central site — capture_virtual_output covers the native and GameStream planes); mapping sites resolve its current desktop rect through pf-win-display's source_desktop_rect — the same resolver the cursor-readback poller uses, so inject and readback always agree — TTL-cached at 250 ms because a group-layout re-arrange moves a live output's origin mid-session. No target resolved falls back to the whole virtual desktop (still right for Exclusive topology). The same fix closes the identical latent absolute-mouse offset.
  • Windows display isolation anchors the kept sources at the desktop origin. A committable CCD config must contain a primary pinned at exactly (0,0); deactivating the display that held the origin while the kept virtual stays at its EXTEND offset supplies an origin-less desktop, which Windows rejects wholesale (0x57) — on every shape, doomed-path-carried and keep-only escalation alike. The kept sources are now translated rigidly so the top-left-most lands on the origin (sets already covering (0,0) stay byte-identical, so plain re-commits don't churn). restore_displays_ccd also guarantees the desktop is never left all-dark: an unappliable snapshot (0x64a) or one that applies cleanly yet re-lights nothing falls back to the database EXTEND preset when no external physical is active afterwards (internal panels don't count — a closed lid isn't forced back on), and the final isolate-failure diagnostic now names the surviving targets rather than asserting a non-virtual display stayed active.