From 06086de3288df6545204225665192e99634741b2 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sun, 9 Aug 2026 00:24:15 +0200 Subject: [PATCH] =?UTF-8?q?fix(windows/cursor):=20do=20the=20clean=20on=20?= =?UTF-8?q?the=20ADD=20path=20=E2=80=94=20the=20handshake=20call=20site=20?= =?UTF-8?q?was=20never=20reached?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third and last placement bug in this chain. clean_cursor_for_next_session was called from the handshake, inside the '#[cfg(windows)] let prep = match (source, compositor) { (Virtual, Some(comp)) => ...' arm — which is not the path taken on this host, so the function never ran. The logs said so by omission: no 'skipping' line, no 'recycled' line, and cursor_excluded stayed true across the reconnect. Move it next to where the declare is recorded: the ADD request. Every session that creates a monitor goes through it, with hw_cursor in hand, before the monitor exists — which is also the moment the recycle is safe. --- crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs | 8 ++++++++ crates/punktfunk-host/src/native/handshake.rs | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs b/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs index d765be73..fb27471c 100644 --- a/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs +++ b/crates/pf-vdisplay/src/vdisplay/windows/pf_vdisplay.rs @@ -894,6 +894,14 @@ impl VdisplayDriver for PfVdisplayDriver { client_hdr: Option, hw_cursor: bool, ) -> Result { + // Give a capture-mode session the LOSSLESS pointer back: if an earlier session declared a + // hardware cursor and this one does not want it, recycle the driver's host process BEFORE + // this monitor is added. The ADD path is the only place guaranteed to see every session + // (the handshake call site this replaced sat in a `match (source, compositor)` arm that is + // not taken on this host, so it never ran). + if !hw_cursor { + clean_cursor_for_next_session(false); + } let session_id = next_session_id(); // The client display's volume rides into the monitor's EDID CTA HDR block; all-zero = // unknown → the driver keeps its built-in defaults (also what an un-upgraded driver, which diff --git a/crates/punktfunk-host/src/native/handshake.rs b/crates/punktfunk-host/src/native/handshake.rs index 601eee6d..18a76d5d 100644 --- a/crates/punktfunk-host/src/native/handshake.rs +++ b/crates/punktfunk-host/src/native/handshake.rs @@ -686,13 +686,6 @@ pub(super) async fn negotiate( // The bit the Welcome just advertised — read back rather than recomputed, so the // prepared display and the session wiring cannot disagree with it. let cursor_fw = welcome.host_caps & punktfunk_core::quic::HOST_CAP_CURSOR != 0; - // Give a capture-mode session back the LOSSLESS pointer: if an earlier session on this - // host declared the hardware cursor (desktop mouse model) and this one did not ask for - // it, clear the sticky declare now — BEFORE this session's display is created, which is - // the only safe moment, and exactly the "desktop session, disconnect, reconnect in - // capture mode" case the start-up clean cannot reach. No-op when nothing declared, when - // this session wants the channel, or when any display is still held. - pf_vdisplay::driver::clean_cursor_for_next_session(cursor_fw); // Same bit the data plane's SessionContext reads — the prepared plan and the // session wiring must agree on the slicing ceiling (an encoder rebuilt from the // prepared plan with a DIFFERENT max_slices would change the wire shape mid-flow).