On the server, while the cursor is on a client, every physical mouse move
warped the local cursor back to screen center and the tap callback returned
the mouse-move event instead of consuming it. That leaked continuous motion
to whatever local app sat under the centered cursor (e.g. a fullscreen game
or a centered video reacting to the phantom movement).
Capture the mouse the way macOS games do instead: dissociate the hardware
mouse from the cursor in leave() so the cursor freezes and hides, read raw
deltas from the event in onMouseMove(), consume off-screen moves in the tap
callback, and re-associate in enter() (disable() already does via
showCursor()). This retires the center-warp and the "bogus motion" edge
heuristic that only existed to paper over the warp.
fixes: #5871
updateShape() unconditionally recentered the cursor and notified the
server on every call, even mid-churn when no device reports a region
yet. Only touch tracked state once a real region is found, and only
notify the server when the shape actually changed.
On a multi-monitor server the portal reports one input-capture zone per
output. handleZonesChanged added a pointer barrier on every active side of
every zone, including edges that sit on an internal seam between two adjacent
monitors. The portal rejects such a barrier ("adjacent to multiple monitor
edges"), and because a single rejected barrier fails the whole
set_pointer_barriers request, input capture never engaged on multi-monitor
Wayland servers.
Compute the union (bounding box) of all zones first, then add a barrier for a
given side only when that zone edge lies on the outer boundary of the union,
skipping internal seams.
Server aborted with "pure virtual method called" when the bind address
was in use: EiScreen's PortalInputCapture glib thread outlived Arch and
hit its freed vtable. ~EiScreen never deleted m_portalInputCapture, and
a fatal startup threw past cleanupServer(). Fix both.
Add libportal clipboard handling to the remote desktop.
Supports both directions (server to Wayland client paste,
and copy from the Wayland client back to the server)
for UTF-8 text, plain text, and PNG/BMP images.
The shared mime-type table, BMP/DIB and PNG encode/decode helpers, and
portal selection read/write live in a new PortalClipboard
helper used by both PortalInputCapture and PortalRemoteDesktop.
If the portal returns a restored RemoteDesktop session without clipboard
enabled (a token persisted before clipboard support existed), discard
the restore token and reconnect so the user gets a fresh permission
dialog. Otherwise the session would loop with a clipboard-less token
forever.
Send the clipboard over the libportal InputCapture portal. Only built
if the installed libportal has clipboard support.
AI disclosure: Claude was used on both sides of this work.
- Peter Hutterer: "The second commit was purely written by Claude
after I stared at this for too long without seeing any hope of
getting started. Turns out Claude wrote something that at least
looks correct and it does work. It needs review but also needs
knowledge of deskflow's internals that I don't have..."
- Nick Bolton: Claude also assisted with the follow-up work listed
below (image copy/paste, session re-request, race fixes, size/mime
validation, and CMake detection).
Server side (Wayland host, Peter Hutterer):
- Initial scaffolding for inputcapture clipboard support, guarded so it
only builds when the portal exposes the clipboard API.
- Integrate clipboard data into the inputcapture session so the host
clipboard can be offered to the remote (the Claude-written commit
referenced above).
Client side (Wayland receiver, KoljaFrahm):
- Receive clipboard data from the server and feed it into the local
clipboard through libportal. Built on the reference code by Peter:
https://github.com/whot/libportal-clipboard-test/tree/main
Build integration and rebase (Chris Rizzitello, sithlord48):
- Add the original CMake check for libportal/clipboard.h to define
HAVE_LIBPORTAL_CLIPBOARD, and guard the libportal clipboard use on
it.
- Update the code style and rebase onto the updated input capture
session persistence: https://github.com/deskflow/deskflow/pull/9415
Image support and reliability fixes (Nick Bolton):
- Support image copy/paste in addition to text, so screenshots and
other image clipboard contents work both ways through inputcapture.
- Re-request the input capture session when it comes up without a
clipboard, so new testers with existing sessions can get clipboard
functionality without needing to clear the session.
- Defer clipboard reads until the input capture session is active,
avoiding races where reads happen before the portal is ready.
- Fix assorted style issues in original commit to match conventions.
- Check the configured clipboard size limit and validate incoming
mime types before forwarding inputcapture clipboard data.
- Switch the CMake clipboard probe to check_symbol_exists so detection
matches what the compiler actually sees in the headers.
Co-authored-by: Nick Bolton <nick@symless.com>
Co-authored-by: KoljaFrahm <GitHub.Kolja@dfgh.net>
Co-authored-by: Chris Rizzitello <sithlord48@gmail.com>
Avoid stale server enter coordinates in relative mouse mode by saving and reusing the client's local cursor position around leave and enter.
Store Windows restore positions per desktop so UAC and secure desktop transitions do not reuse normal desktop coordinates. This affects relative mouse movement restore behavior while preserving the existing center-on-leave path.
Track InputCapture pointer barrier metadata so activation callbacks can identify the fired edge. Portal activations may report cursor positions on zone boundaries, while Deskflow switches using aggregate screen coordinates. Clamp the activation position to the portal zone, then project the fired edge onto Deskflow's aggregate screen before dispatching primary motion.
Keep barrier metadata in sync when zones are rebuilt or when the compositor rejects a requested barrier.
Move repeated InputCapture pointer barrier construction into a helper and add a small side-to-name utility for logging. This keeps the existing barrier geometry and activation handling unchanged while making later barrier metadata changes easier to review.
When macOS is the primary screen, hotkey switching to a secondary screen can leave the local cursor baseline away from the hidden-cursor center. The first physical mouse movement is then interpreted as a large secondary-screen delta.
Align macOS primary leave behavior with the Windows and X11 implementations by logging and warping the cursor to the primary-screen center before marking the screen off screen. OSXScreen::warpCursor also updates m_xCursor and m_yCursor, so the next motion delta starts from the expected center baseline.
Impact is limited to macOS primary/server leave handling; macOS secondary/client leave behavior and non-macOS builds are unchanged.
Use the new libportal API to start a CreateSession2, then set the
session persistence and read/write the tokens as required. This allows
us to start a server without a permission dialog - provided the portal
supports it and the user is ok with that.
OpenClipboard() can fail transiently when another process holds the
clipboard mutex. Add a retry loop (5 attempts, 5ms delay) so that
Deskflow handles brief contention gracefully instead of immediately
failing.