Skip to content

feat(linux): add opt-in text clipboard sync - #5782

Draft
Wouze wants to merge 16 commits into
LizardByte:masterfrom
Wouze:clipboard-sync
Draft

Wouze wants to merge 16 commits into
LizardByte:masterfrom
Wouze:clipboard-sync

Conversation

@Wouze

@Wouze Wouze commented Sep 23, 2026 •

Copy link
Copy Markdown

Description

Add opt-in text clipboard sync for a Linux X11 host.

The client sends clipboard text with input packet 0x55000008. A zero-length packet subscribes and does not clear the host clipboard. Sunshine sends host clipboard text back on control message 0x5505 only after that subscribe. The host watcher uses the X11 CLIPBOARD selection and does not echo text it just applied. Text is capped at 32,755 bytes.

Mac, Windows, and Linux builds without X11 still link. Their clipboard functions do nothing.

The submodule third-party/moonlight-common-c points at moonlight-stream/moonlight-common-c#155 (cfd661028220a2c1bb8536cb49b2573f1a317f90). That commit is on the fork until the protocol pull request is merged.

Tested on Ubuntu 24.04, Xorg, with a Moonlight Qt build that has Sync clipboard enabled. Copy works both ways. A stock Moonlight client still connects.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

See our AI usage policy.

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@ReenigneArcher
ReenigneArcher marked this pull request as draft September 23, 2026 14:46
@Wouze

Wouze commented Sep 23, 2026

Copy link
Copy Markdown
Author

Hi
I saw this pr being moved to draft
should i change something or do more tests?

i really feel this feature is must, as many clients (like remmina and others) support it by default, and many people are doing workarounds it

Thanks
mohammad

@ReenigneArcher

Copy link
Copy Markdown
Member

The submodule third-party/moonlight-common-c points at moonlight-stream/moonlight-common-c#155 (d22d24c94b6786f56c855a610b2f4fcc5a03d44b). That commit is on the fork until the protocol pull request is merged.

It's draft because of this.

@Wouze

Wouze commented Oct 3, 2026

Copy link
Copy Markdown
Author

Hello @ReenigneArcher

um it have been more than a week but the moonlight lib c and qt didnt get merged nor reviewed, can you help me get some attention since you are a contributor there?

Thanks

@ReenigneArcher ReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packet framing and bounded clipboard callback parsing agree with moonlight-common-c #155, but the X11 backend has the four reproducible problems noted inline. Please fix these and add automated regression tests, including empty/maximum/truncated clipboard packets and subscription lifecycle behavior, as required by AGENTS.md. The new X11 implementation helpers and state members also need the required Doxygen documentation.

Validation: both complete PR diffs passed git diff --check; moonlight-common-c #155 built with UCRT64 in Debug, and focused sender/parser harnesses passed. A harness using this PR's exact clipboard.cpp with mocked X11 calls reproduced each inline finding. A full Sunshine build and real Xorg session were not run. Both PR heads are mergeable against their targets. CI awaits maintainer approval; the failing GH-Pages Read the Docs log ends with 'Timeout waiting for check runs', so that status is a verification limit rather than a contributor code finding.

Comment thread src/platform/linux/clipboard.cpp Outdated
Comment thread src/platform/linux/clipboard.cpp Outdated
Comment thread src/platform/linux/clipboard.cpp Outdated
Comment thread src/platform/linux/clipboard.cpp Outdated
@Wouze

Wouze commented Oct 3, 2026

Copy link
Copy Markdown
Author

The four X11 notes are fixed, and this branch is updated onto current master.

  • Each opted-in client keeps its own subscription. Stopping the session removes it.
  • A client that subscribes later still receives the current clipboard when the text has not changed.
  • An INCR property is assembled from its chunks and is not published as text. Other property types are ignored.
  • A selection request with property None is answered on the target atom.

Tests cover empty, maximum, and truncated clipboard packets, plus subscription lifecycle, the None property, and INCR transfers.

@ReenigneArcher ReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The per-client subscriber tracking, unchanged initial snapshot, and property=None fixes now pass the focused checks, and small INCR transfers work through the actual watcher. The remaining INCR handshake defect below still prevents large host copies from reaching clients.

Validation: all 11 added clipboard helper tests passed in a focused UCRT64 gtest build using the exact PR helper code and real mailbox queues. Additional tests using the exact clipboard.cpp with mocked X11 calls passed the small-transfer and None-property cases, and reproduced the oversized-chunk stall and unsupported-type issue. The unchanged pinned moonlight-common-c sender/parser boundary harness passed again, and the complete PR diff passed git diff --check.

Verification limits: a full Sunshine build and real Xorg session were not run. Hosted CI, CodeQL, lint, and GH-Pages builds await maintainer approval; the current failed GH-Pages Read the Docs log ends with 'Timeout waiting for check runs'. These are separate from the code findings. The current head is mergeable against master.

Comment thread src/platform/linux/clipboard.cpp Outdated
Comment thread src/platform/clipboard_sync.h Outdated
Wouze added 2 commits October 8, 2026 00:40
A chunk larger than one X read stayed on the window, so the owner never sent the rest of a large copy. Unsupported INCR data was also published when the terminator arrived.
The quality gate failed on the declaration scope, the long test lambda, and an explicit vector type.

@ReenigneArcher ReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both findings from the previous review are fixed: oversized INCR properties are drained and acknowledged, and unsupported types during INCR are rejected without publishing their bytes. The earlier failing watcher regressions now pass. No additional runtime defect was found in the complete PR diff. The remaining requested change is the repository's required formatting cleanup noted inline.

Validation: the focused UCRT64 gtest build passed all 21 tests (17 PR clipboard tests and four additional watcher/helper regressions), including a 64 KiB INCR chunk, unsupported-type rejection, and the actual None-property responder. The pinned moonlight-common-c sender/parser boundary harness passed again. Both the follow-up diff and complete PR diff passed git diff --check. The pinned clang-format 23.1.0 --dry-run --Werror check fails in clipboard_sync.h and linux/clipboard.cpp; test_clipboard.cpp passes.

Verification limits: a full Sunshine build and real Xorg session were not run. Hosted CI, CodeQL, common lint, and GH-Pages builds still await maintainer approval; the current failed GH-Pages Read the Docs log ends with 'Timeout waiting for check runs'. Those pending checks are separate from the reproduced local formatting failure. The current head is mergeable against master.

Comment thread src/platform/clipboard_sync.h Outdated
The pinned clang-format check failed on the template keyword and the property read call.
ReenigneArcher
ReenigneArcher previously approved these changes Oct 8, 2026
The protocol no longer carries a token. Echoes are already ignored by comparing the text.
@Wouze

Wouze commented Oct 23, 2026

Copy link
Copy Markdown
Author

@ReenigneArcher the protocol review dropped the unused echo token, so this branch follows that in 40f4b83. The submodule points at moonlight-common-c f197f1d5. This stays a draft until that protocol pull request merges.

Wouze added 3 commits October 23, 2026 21:56
Master already cleared these Sonar findings. The input constructor keeps the clipboard queue.
The watcher is split into smaller functions, and its thread stays joinable for the life of the process.
The selection targets are copied into the X buffer, and the event handler takes the watcher state in one argument.
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants