refactor(windows-host): §2.5 step 2 — unify both backends behind VirtualDisplayManager (OnceLock)

The two Windows virtual-display backends (sudovda + pf_vdisplay) carried VERBATIM-DUPLICATED
~250-line Idle/Active/Lingering refcount state machines in two `MGR: Mutex<Mgr>` globals, each
smuggling the control HANDLE across the pinger/linger threads as a raw `isize` (HANDLE is !Send).

New `vdisplay/windows/manager.rs`: one host-lifetime `VirtualDisplayManager` (OnceLock singleton,
user-approved) owns the earned state machine + the linger timer + a TYPED `Arc<OwnedHandle>`
control device (the raw-isize smuggle is gone — OwnedHandle is Send+Sync and also CloseHandle's
the device on drop, fixing a latent leak). The only backend-specific code left is the IOCTL
surface behind a small `VdisplayDriver` trait (open/add_monitor/remove_monitor/ping) + the
per-monitor REMOVE key (`MonitorKey::Guid` for sudovda, `::Session(u64)` for pf-vdisplay). The
render-adapter pin decision, the GDI/CCD glue (crate::win_display), and the gen-stamped
MonitorLease are backend-neutral and live once in the manager.

  * sudovda.rs / pf_vdisplay.rs: shrink to a `VdisplayDriver` impl + a thin `VirtualDisplay`
    wrapper (new() -> manager::init(driver); create() -> manager::vdm().acquire(mode)). Their
    IOCTL ops + structs + open_device stay in place (no transcription).
  * MON_GEN -> a manager field; the preempt's wait_for_monitor_released moves onto the manager
    (punktfunk1 calls vdm().wait_for_monitor_released). MonitorLease.drop -> vdm().release(gen),
    with the stale-lease no-op preserved verbatim.

Behaviour-preserving: the state machine (acquire/release/reconfigure/teardown/linger/preempt) is
the canonical sudovda copy with the IOCTLs routed through the driver seam. Box build to follow
(Windows-only; Linux check is a no-op for these files).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 19:50:34 +00:00
parent 15202011c1
commit d9b8b88a42
5 changed files with 672 additions and 981 deletions
+2 -1
View File
@@ -2255,7 +2255,8 @@ fn virtual_stream(ctx: SessionContext) -> Result<()> {
let prev = IDD_SESSION_STOP.lock().unwrap().replace(stop.clone());
if let Some(prev_stop) = prev {
prev_stop.store(true, Ordering::SeqCst);
crate::vdisplay::sudovda::wait_for_monitor_released(std::time::Duration::from_secs(3));
crate::vdisplay::manager::vdm()
.wait_for_monitor_released(std::time::Duration::from_secs(3));
}
}
let mut vd = crate::vdisplay::open(compositor)?;