Merge origin/main (shared clipboard Phase 1) into the local W6.2 + rumble-D line

Reconciles the two diverged mains: the local stack (W6.1/W6.2 crate decomposition,
lid-closed fixes, ABR climb gating, rumble root-fix A-D incl. the W7 core module
splits) x origin/main (clipboard wire ABI v8 + pf-clipboard + the macOS client).

Textual conflicts were trivial (host Cargo.toml dep union; Cargo.lock + the
cbindgen header regenerate). The real work was structural: the local line's W7
splits dissolved the two files the clipboard's Phase 0 landed in, so the merge
left both layouts side by side. Resolved by re-homing the clipboard delta into
the split layout and deleting the stale flat files:

- quic/msgs.rs -> quic/clip.rs (the 0x40-0x44 messages, CLIP_* vocabulary,
  codecs) + HOST_CAP_CLIPBOARD into quic/caps.rs beside GAMEPAD_STATE; mod.rs
  declares clip and fixes the split-by-concern doc.
- client.rs -> the client/ split: CtrlRequest clip variants + Negotiated.host_caps
  (control.rs), CLIP_EVENT_QUEUE (planes.rs), clip channel ends (worker.rs),
  NativeClient clip surface + channels (mod.rs), control-task encode/decode arms +
  the clipboard task spawn (pump.rs).

Verified on macOS: core 174/174 (merged rumble + clipboard suites), pf-clipboard
clippy -D warnings clean, fmt applied, header regenerated. Host-side compile
rides the Linux/Windows legs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 14:19:46 +02:00
41 changed files with 5878 additions and 55 deletions
@@ -1397,9 +1397,7 @@ fn spawn(w: u32, h: u32, hz: u32, cmd: Option<&str>, log: &std::path::Path) -> R
.filter(|s| !s.trim().is_empty())
// Read the env fallback under the shared env lock so it can't race a concurrent session's
// `set_var` of the same key (security-review 2026-06-28 #7).
.or_else(|| {
crate::with_env_lock(|| std::env::var("PUNKTFUNK_GAMESCOPE_APP").ok())
})
.or_else(|| crate::with_env_lock(|| std::env::var("PUNKTFUNK_GAMESCOPE_APP").ok()))
.filter(|s| !s.trim().is_empty())
.unwrap_or_else(|| "sleep infinity".to_string());
// Dedicated-launch command shaping (Part B): a Steam URI runs with `-silent` so the game is the
@@ -133,10 +133,7 @@ impl VirtualDisplay for MutterDisplay {
(mode.width, mode.height),
crate::policy::Identity::Shared,
);
let remembered_scale = crate::identity::scales()
.lock()
.unwrap()
.get(&scale_key);
let remembered_scale = crate::identity::scales().lock().unwrap().get(&scale_key);
if let Some(scale) = remembered_scale {
tracing::info!(scale, "mutter: reapplying the client's saved display scale");
}
@@ -532,10 +532,7 @@ impl VirtualDisplayManager {
// (`max_displays` across Active+Lingering+Pinned slots; the identity-slot ceiling of 15 is
// the hard limit behind it) — this is the fail-closed backstop for a session that got past
// admission anyway. One live slot can never trip it (max_displays >= 1).
let max = crate::policy::prefs()
.get()
.effective()
.max_displays;
let max = crate::policy::prefs().get().effective().max_displays;
if inner.slots.len() as u32 >= max {
anyhow::bail!(
"display budget exhausted: {} display(s) live/kept, max_displays = {max} — freeing \
@@ -1450,12 +1447,7 @@ impl Drop for MonitorLease {
/// no identity to find any other slot by). Shared by `acquire` and the session setup's
/// [`VirtualDisplayManager::begin_idd_setup`], so both address the same slot.
pub fn slot_id_for(client_fp: Option<[u8; 32]>, mode: (u32, u32)) -> u32 {
super::identity::resolve_slot(
client_fp,
mode,
crate::policy::Identity::PerClient,
)
.unwrap_or(0)
super::identity::resolve_slot(client_fp, mode, crate::policy::Identity::PerClient).unwrap_or(0)
}
/// The render-GPU pin (backend-neutral): IDD-push — the sole Windows capture path — runs NVENC on the
@@ -41,10 +41,7 @@ pub(super) fn keep_alive_forever() -> bool {
/// physical(s) so the IDD is the sole composited desktop.
pub(super) fn topology_action() -> crate::policy::Topology {
use crate::policy::Topology;
if crate::policy::prefs()
.configured_effective()
.is_some()
{
if crate::policy::prefs().configured_effective().is_some() {
return crate::effective_topology();
}
if std::env::var("PUNKTFUNK_NO_ISOLATE").is_ok() {
@@ -217,10 +217,7 @@ unsafe fn set_render_adapter(h: HANDLE, luid: LUID) -> Result<()> {
///
/// # Safety
/// `dev` must be a live pf-vdisplay control handle (see [`super::manager::control_device_handle`]).
pub unsafe fn send_frame_channel(
dev: HANDLE,
req: &control::SetFrameChannelRequest,
) -> Result<()> {
pub unsafe fn send_frame_channel(dev: HANDLE, req: &control::SetFrameChannelRequest) -> Result<()> {
let mut none: [u8; 0] = [];
// SAFETY: per this fn's contract `dev` is the live control handle. `bytes_of(req)` borrows the
// caller's request for the duration of this synchronous call as the input bytes; `none` is empty,