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>
11 KiB
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, notkscreen-doctor.kscreen-doctordrives 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 tohandled = falseand the oldkscreen-doctorpath still runs. - >60 Hz custom modes install in-process too, so the whole KWin path is kscreen-free on modern KWin.
set_custom_modebuilds a one-entrykde_mode_list_v2and applies it viakde_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_modesreplaces 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 withoutset_custom_modesfalls back toset_custom_refresh. - The gamescope managed takeover is display-manager-flavor-aware. Masking the box's
gamescope-session-plusunit made plasmalogin'sRelogin=truefail 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; onlyreset-failed+restartrecovers. 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 withreset-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 onensure_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 aPUNKTFUNK_COMPOSITORpin 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-selectsentinel'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 ownos-session-select(its internal pkexec is authorizedallow_anyby 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_screenand sendinput'sMouseMoveAbsmapped 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 the0x57keep-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. Newpf-inject::stream_targetpublishes the streamed output's CCD target id at capture bring-up (one central site —capture_virtual_outputcovers the native and GameStream planes); mapping sites resolve its current desktop rect throughpf-win-display'ssource_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_ccdalso 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.