feat(apple): cursor channel on the Mac client — ABI v11 + NSCursor rendering
The Mac client now exercises the full cursor channel against capable hosts: desktop-mode sessions advertise CLIENT_CAP_CURSOR, the host stops compositing the pointer, and StreamView draws the forwarded shapes as the real NSCursor — plus the M3 host-driven model flip. - ABI v11: punktfunk_connect_ex9 (adds client_caps; ex7/ex8 pass 0 — Android untouched), PunktfunkCursorShape/State + the two next_cursor_* poll fns (audio-style borrow contract), and PUNKTFUNK_CLIENT_CAP_CURSOR. Fixed in passing: the first insertion split next_host_timing's cfg/no_mangle attributes off the fn, which silently dropped the symbol from the header AND dylib — caught by the Swift build, reattached with its docs. - PunktfunkConnection: clientCaps connect param, hostSupportsCursor, CursorShapeEvent/CursorStateEvent + nextCursorShape/nextCursorState (one cursor thread drains both planes; cursorLock joins the close() ladder). - SessionModel: desktop-mode sessions (DefaultsKey.mouseMode) connect with the cursor cap on macOS. - StreamView: shape cache (serial → NSCursor, straight-alpha RGBA via CGImage), resetCursorRects wears the HOST shape while the desktop model is engaged (hidden host pointer ⇒ invisible), latest-wins state pump, and the M3 auto-flip — edge-triggered on relative_hint, ⌃⌥⇧M sets an override latch cleared by the next host edge, leaving relative warps the pointer to the host position via the inverse letterbox mapping (CGWarpMouseCursorPosition, CursorCapture's coordinate convention). Verified: swift build + full test suites green (xcframework rebuilt at ABI v11, signed); core 218 tests + clippy -D warnings on Linux (.21). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -302,13 +302,26 @@ final class SessionModel: ObservableObject {
|
||||
if preferredCodec == PunktfunkConnection.codecPyroWave, MetalWaveletDecoder.supported {
|
||||
videoCodecs |= PunktfunkConnection.codecPyroWave
|
||||
}
|
||||
// Cursor channel (remote-desktop-sweep M2, macOS): sessions STARTING in the desktop
|
||||
// mouse model advertise local cursor rendering — the host then stops compositing
|
||||
// the pointer and forwards shape/state, which StreamView draws as the real
|
||||
// NSCursor. Capture-mode sessions keep today's composited pointer.
|
||||
#if os(macOS)
|
||||
let clientCaps: UInt8 =
|
||||
(MouseInputMode(
|
||||
rawValue: UserDefaults.standard.string(forKey: DefaultsKey.mouseMode) ?? "")
|
||||
?? .capture) == .desktop ? 0x01 : 0
|
||||
#else
|
||||
let clientCaps: UInt8 = 0
|
||||
#endif
|
||||
let result = Result { try PunktfunkConnection(
|
||||
host: host.address, port: host.port,
|
||||
width: width, height: height, refreshHz: hz,
|
||||
pinSHA256: pin, identity: identity, compositor: compositor,
|
||||
gamepad: gamepad, bitrateKbps: bitrateKbps, videoCaps: videoCaps,
|
||||
audioChannels: audioChannels,
|
||||
videoCodecs: videoCodecs, preferredCodec: preferredCodec, launchID: launchID,
|
||||
videoCodecs: videoCodecs, preferredCodec: preferredCodec,
|
||||
clientCaps: clientCaps, launchID: launchID,
|
||||
// Delegated approval: the host holds this connect open until the operator approves
|
||||
// it (~180 s) — outwait that window so a slow approval still lands here. Normal
|
||||
// connects keep the snappy default.
|
||||
|
||||
Reference in New Issue
Block a user