merge(core): reconcile the W7/W8 client refactor with origin's shared-clipboard feature

origin/main landed the shared clipboard (design/clipboard-and-file-transfer.md) while
this branch split quic/msgs.rs -> quic/{caps,control,...} and client.rs ->
client/{mod,control,worker,pump,planes,...} (W7) and deleted the two monoliths. The
feature had modified both deleted files, so its delta is re-applied onto the split
instead of resurrecting the monoliths:

  - HOST_CAP_CLIPBOARD                         -> quic/caps.rs
  - MSG_CLIP_* / CLIP_* consts, the six Clip*
    structs, and their encode/decode impls     -> quic/control.rs (beside the clock codecs)
  - CtrlRequest::{ClipControl,ClipOffer} +
    Negotiated.host_caps                        -> client/control.rs
  - WorkerArgs.{clip_event_tx,clip_cmd_rx}      -> client/worker.rs
  - CLIP_EVENT_QUEUE                            -> client/planes.rs
  - NativeClient clip fields, the 7 clip_* /
    host_caps / next_clip methods, connect()
    channel wiring                              -> client/mod.rs
  - the control-task encode/decode arms and
    the clipboard-task spawn                     -> client/pump.rs

Cargo.lock reconciled (adds pf-clipboard), punktfunk-host/Cargo.toml unions the W6
pf-* subsystem deps with pf-clipboard, and include/punktfunk_core.h is the cbindgen
union (clipboard + rumble C-ABI). punktfunk-core builds --all-features and its 174
lib tests pass, including quic::tests::clip_loopback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 15:38:11 +02:00
co-authored by Claude Opus 4.8
36 changed files with 5864 additions and 25 deletions
+11 -1
View File
@@ -1,7 +1,7 @@
//! `CtrlRequest` (the embedder's control-stream requests) and `Negotiated` (the handshake result).
use crate::config::{CompositorPref, GamepadPref, Mode};
use crate::quic::{ColorInfo, LossReport, ProbeRequest, RfiRequest};
use crate::quic::{ClipControl, ClipOffer, ColorInfo, LossReport, ProbeRequest, RfiRequest};
/// A control-stream request the embedder makes on the open handshake stream: a mode switch or a
/// speed test. One outbound channel carries both so the worker's `select!` has a single writer
@@ -22,6 +22,12 @@ pub(crate) enum CtrlRequest {
/// its report tick after the first no-op clock flush — the "the clock stepped under me"
/// signal; the control task also self-triggers one every [`CLOCK_RESYNC_INTERVAL`].
ClockResync,
/// Shared-clipboard enable/disable for this session (`design/clipboard-and-file-transfer.md`
/// §3.1). Idempotent; carries the file-permission flag.
ClipControl(ClipControl),
/// Announce that the local clipboard changed — the lazy format-list offer (bytes cross later on
/// a fetch stream). Symmetric message; the host may send one too.
ClipOffer(ClipOffer),
}
/// What the worker reports to [`NativeClient::connect`] once the handshake lands: the
@@ -55,4 +61,8 @@ pub(crate) struct Negotiated {
pub(crate) audio_channels: u8,
/// The single codec the host will emit (`quic::CODEC_*`).
pub(crate) codec: u8,
/// The host capability bitfield ([`crate::quic::Welcome::host_caps`]):
/// [`crate::quic::HOST_CAP_GAMEPAD_STATE`], [`crate::quic::HOST_CAP_CLIPBOARD`]. Exposed to the
/// embedder via [`NativeClient::host_caps`] so a native client greys out unsupported toggles.
pub(crate) host_caps: u8,
}