Files
punktfunk/crates/pf-client-core/src/lib.rs
T
enricobuehler cab6350723 feat(client): shared clipboard on Windows
The protocol half has been in punktfunk-core since the clipboard work
landed -- the per-session fetch task, plus clip_control/clip_offer/
clip_fetch/clip_serve/next_clip on NativeClient -- but only the Apple
client ever drove it, through the C ABI. The Windows and Linux clients link
the core directly and simply never wired it, so copy-paste between host and
client worked on a Mac and nowhere else.

This adds the missing half: the OS-clipboard bridge, on its own session
thread beside the audio one.

Local -> remote stays lazy by construction, as the design asks: a
GetClipboardSequenceNumber poll spots a local copy and we announce only the
FORMAT LIST; bytes are read when (and only when) the host actually pastes
and sends a FetchRequest.

Remote -> local is EAGER in this first cut, which is a deliberate deviation
worth naming. macOS gets laziness free from NSPasteboardItemDataProvider;
the Windows equivalent is delayed rendering, which needs a clipboard-owning
window running its own message pump. So we fetch on the offer and place real
bytes under a 4 MB cap -- text always crosses, a large image is skipped
rather than pulled for a paste that may never come. Delayed rendering lifts
the cap later.

Echo suppression is the design's Windows rule verbatim (capture the
sequence number right after our own SetClipboardData); without it every
copy ping-pongs between the machines forever. Content marked
ExcludeClipboardContentFromMonitorProcessing -- what password managers set
-- is never announced and never served.

Text and PNG for now. Apps that publish only CF_DIB need the conversion the
host already has. Linux keeps a stub: the bridge itself is
platform-neutral and will drive a data-control seam unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:06:06 +02:00

60 lines
2.5 KiB
Rust

//! Shared, UI-agnostic client plumbing, extracted verbatim from the GTK client
//! (design: punktfunk-planning `linux-client-rearchitecture.md`, Phase 0) so the desktop
//! shells and the Vulkan session binary build on one implementation — on Linux AND
//! Windows (the session binary runs on both; macOS stays `wol`-only, clients/apple is
//! the client there).
//!
//! Nothing here may depend on a UI toolkit: the presenter contract is `session`'s
//! channels (`SessionHandle`) and `video`'s `DecodedImage` (RGBA bytes, dmabuf fds +
//! plane layout, or a decoded VkImage) — how frames reach the screen is the consumer's
//! business.
//!
//! Audio is the one per-OS module swap: `audio.rs` (PipeWire) on Linux,
//! `audio_wasapi.rs` (WASAPI) on Windows — same public surface, picked here by `#[path]`
//! so `crate::audio` is the only name the session pump ever sees. `keymap` (evdev-keyed)
//! stays Linux: the session path uses pf-presenter's SDL-scancode table instead.
#[cfg(target_os = "linux")]
pub mod audio;
#[cfg(windows)]
#[path = "audio_wasapi.rs"]
pub mod audio;
#[cfg(any(target_os = "linux", windows))]
pub mod discovery;
#[cfg(any(target_os = "linux", windows))]
pub mod gamepad;
#[cfg(target_os = "linux")]
pub mod keymap;
#[cfg(any(target_os = "linux", windows))]
pub mod library;
#[cfg(any(target_os = "linux", windows))]
pub mod session;
#[cfg(any(target_os = "linux", windows))]
pub mod trust;
#[cfg(any(target_os = "linux", windows))]
pub mod video;
#[cfg(any(target_os = "linux", windows))]
mod video_color;
#[cfg(any(target_os = "linux", windows))]
mod video_software;
#[cfg(target_os = "linux")]
mod video_vaapi;
#[cfg(any(target_os = "linux", windows))]
mod video_vulkan;
// The OS-clipboard bridge for the shared clipboard (design/clipboard-and-file-transfer.md §5).
// Built everywhere the session client is; the platform seam inside is Windows-real,
// stub elsewhere.
#[cfg(any(target_os = "linux", windows))]
pub mod clipboard;
// PyroWave decode — Linux + Windows (plan §4.5; the Apple Metal port is its own phase).
// Windows joined once its client moved to the SAME spawned Vulkan session presenter as
// Linux's: the decoder is plain Vulkan compute on the presenter's device (no fds, no
// dmabuf, no D3D11 interop), so the old "Windows present-path decision" that gated it
// resolved itself — the present path is now literally the same code.
#[cfg(windows)]
pub mod video_d3d11;
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
pub mod video_pyrowave;
pub mod wol;