fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard - #2904
Conversation
There was a problem hiding this comment.
🤖 Agent-authored review.
IMPORTANT — Correctness: the sole commit is missing its Signed-off-by trailer, so the repository-required DCO check fails. Please amend it with git commit --amend --no-edit --signoff and force-push the updated commit.
The implementation itself is appropriately minimal: wayland-data-control activates wl-clipboard-rs only on supported Unix targets, arboard selects that backend when WAYLAND_DISPLAY is present and retains its X11 fallback, and the lockfile matches the feature graph. I found no code defect.
At 0d1203e340adbb0b009501fb7ef9706a1a93bd3f, just desktop-tauri-fmt-check, just desktop-tauri-check, just desktop-tauri-clippy, and just desktop-tauri-test pass (1,629 passed, 14 ignored, plus 3 diagnostic tests). Rust Lint, Semgrep, zizmor, and Desktop E2E Relay also pass in CI; the remaining CI jobs are still running. Requesting changes solely for the required DCO sign-off.
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 Agent-authored review.
Verified the root-cause claim and the mechanism at source, not just from the description. The diagnosis is right and the fix is the minimal correct one.
What I confirmed in arboard 3.6.1 (vendored at ~/.cargo/registry/src/index.crates.io-*/arboard-3.6.1):
wayland-data-control = ["wl-clipboard-rs"]exists, andmod waylandinsrc/platform/linux/mod.rsis gated on it — so without the feature the Linux build genuinely has no Wayland backend andClipboard::new()unconditionally returnsSelf::X11(..). The bug report's diagnosis holds.- Backend selection (
linux/mod.rs,Clipboard::new) does exactly what the description says: ifWAYLAND_DISPLAYis set it trieswayland::Clipboard::new(), and on error falls back to X11 with awarn!. X11-only sessions are unaffected. wl-clipboard-rsis declared under[target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten"))))'.dependencies], so the "macOS and Windows unaffected" claim is accurate at the manifest level.
No new system build deps — I checked this specifically because wayland-sys uses pkg-config and wayland-backend uses cc. Neither triggers here: cargo tree --target x86_64-unknown-linux-gnu -e features -p wayland-sys resolves wayland-sys with no features, and its build.rs only probes pkg-config under client/server/cursor/egl. wayland-backend likewise doesn't enable client_system, so libwayland-dev is not required. Empirically confirmed: Desktop Core is green at 0d1203e, and that job compiles the Tauri crate on ubuntu-latest (desktop-tauri-clippy / -check / -test) with the existing apt list.
CI status at 0d1203e: Rust Lint, Desktop Core, Windows Rust, Desktop Build (macOS), Semgrep, zizmor all green.
- DCO Check = FAILURE ("All commits are missing DCO sign-off").
git log -1on0d1203ehas noSigned-off-by:trailer. This is the only thing gating merge — needs an amend + force-push. - Desktop Smoke E2E (4) = FAILURE, and it is unrelated to this change. It's
tests/e2e/thread-focus-mode.spec.ts:206toBeInViewport()→ "viewport ratio 0" (174 passed, 1 failed after 2 retries). That job never compiles Rust — its steps arepnpm -C desktop build:e2e+ Playwright against the mock bridge — so aCargo.toml/Cargo.lock-only diff cannot influence it. Matches the known scroll-anchor flake bucket.
Non-blocking notes
MINOR — the fix narrows the silent-failure class, it doesn't close it. Clipboard::new() falls back to X11 whenever wayland::Clipboard::new() errors, and wayland::Clipboard::new() requires ext-data-control or wlr-data-control from the compositor. Hyprland (the reporter's) is wlroots and exposes zwlr_data_control_manager_v1, so #2896 is genuinely fixed for them. KWin also qualifies — it implements ext_data_control_manager_v1 (KDE/kwin src/wayland/datacontroldevicemanager_v1.cpp). GNOME/Mutter implements neither: GNOME/mutter src/wayland/ has no data-control source file at all. On GNOME Wayland this PR changes nothing, and the original symptom — set_text returns Ok over an empty clipboard — persists. Worth a follow-up issue rather than scope creep here.
MINOR — the fallback is currently invisible. arboard logs that fallback via the log crate (warn! in Clipboard::new), but the Tauri crate installs no log implementation — no log, env_logger, tracing-subscriber, or tauri-plugin-log in desktop/src-tauri/Cargo.toml, and no log::/tracing:: call sites in desktop/src-tauri/src. So when the Wayland handshake fails we get the X11 fallback with zero diagnostic trail, which is precisely the debugging difficulty that made #2896 hard to pin down. Cheap follow-up: wire a log sink, or surface the selected backend once at startup.
MINOR — ClipboardState's app-lifetime caching is inert on the Wayland path. wayland::Clipboard is struct Clipboard {} — a ZST holding no connection; each set_text opens a fresh Wayland connection and copy_multi spawns its own serving thread. The doc comment on ClipboardState ("App-lifetime clipboard ownership keeps copied data available on Linux") describes the X11 backend's semantics and is now only half-true for Linux. Harmless, but the comment will mislead the next reader. Same for release() on RunEvent::Exit.
MINOR — supply-chain surface, and it isn't scanned. The lockfile gains 10 crates (wl-clipboard-rs, wayland-{backend,client,protocols,protocols-wlr,scanner,sys}, tree_magic_mini, downcast-rs, os_pipe) plus a second major nom (8.0.0 alongside 7.1.3). Licenses are all fine — every one is MIT or MIT/Apache-2.0, all inside deny.toml's allow list. But note that nothing enforces that: root Cargo.toml has exclude = ["desktop/src-tauri"], so cargo-deny check never sees these crates, and the Security job was SKIPPED on this PR anyway since desktop/src-tauri/** isn't in the rust paths filter. Pre-existing gap, not this PR's to fix — flagging because this PR is the kind of change that gap is blind to.
Verdict: approve on the code. The change is minimal, the mechanism is verified at source rather than assumed, and it's the right fix for the reported platform. Add the DCO sign-off and it's mergeable; the E2E red is an unrelated known flake.
…e Wayland clipboard Without arboard's wayland-data-control feature the Linux build is X11-only: in a Wayland session every copy lands on the XWayland clipboard, which Wayland-native apps never see because the compositor only mirrors X11 selections while an XWayland window holds focus -- and arboard's clipboard client is windowless. set_text still returns Ok, so the UI reports "Copied" over an empty clipboard. Enabling the feature lets arboard use the zwlr-data-control protocol under Wayland compositors and fall back to X11 when WAYLAND_DISPLAY is absent. The wl-clipboard-rs dependency is target-gated inside arboard, so macOS and Windows builds are unaffected. Fixes block#2896 Signed-off-by: Shawn Yeager <shawn@shawnyeager.com>
0d1203e to
7bd9ea6
Compare
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 Agent-authored review.
The blocking feedback is addressed. The amended commit includes Signed-off-by: Shawn Yeager <shawn@shawnyeager.com>, and DCO now passes.
I also verified that 7bd9ea6a0dcec51dba3aa20f15bfc4c9bb36de34 has the exact same tree as the previously reviewed 0d1203e340adbb0b009501fb7ef9706a1a93bd3f, so the prior code assessment and passing local Tauri gates still apply. Approving the current head; the newly triggered CI run is still in progress.
…unity-policy-fetch * origin/main: Fix formatting in README.md diagram (block#2284) fix(desktop): make Linux AppImage GStreamer work on non-Debian distros (block#2176) refactor(desktop): remove Agent directory section from Agents page (block#2290) fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard (block#2904) fix(desktop): supervise and re-arm relay-mesh runtime (block#2823) fix(agents): run live Databricks discovery instead of the fallback list (block#2890) fix(desktop): retire prepend mode on every reader wheel (block#2913) fix(desktop): consolidate prepend scroll correction (block#2855) docs(buzz-acp): correct agent key generation instructions (block#2875) fix(desktop): track concurrent agent turns up to the harness maximum (block#2882) docs(contributing): trim to goose-scale minimal intake surface (block#2780) fix(relay): preserve reconnect backoff (block#2759)
…ding-harnesses * origin/main: (47 commits) fix(desktop): remove bundled libsystemd from AppImage (#2353) docs: document required DCO sign-off and add commit-msg sign-off hook (#2993) fix(desktop): make agent definition authoritative for model/provider/prompt (#1968) chore(desktop): delete dead persona catalog UI cluster (#2886) fix(desktop): surface install failures hidden by curl-pipe exit codes (#2892) fix(mobile): validate invite relay destinations (#2986) Refactor managed-agent runtime into cohesive modules (#2974) Refine mobile settings and themes (#2844) Fix formatting in README.md diagram (#2284) fix(desktop): make Linux AppImage GStreamer work on non-Debian distros (#2176) refactor(desktop): remove Agent directory section from Agents page (#2290) fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard (#2904) fix(desktop): supervise and re-arm relay-mesh runtime (#2823) fix(agents): run live Databricks discovery instead of the fallback list (#2890) fix(desktop): retire prepend mode on every reader wheel (#2913) fix(desktop): consolidate prepend scroll correction (#2855) docs(buzz-acp): correct agent key generation instructions (#2875) fix(desktop): track concurrent agent turns up to the harness maximum (#2882) docs(contributing): trim to goose-scale minimal intake surface (#2780) fix(relay): preserve reconnect backoff (#2759) ... Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com> # Conflicts: # desktop/src/features/onboarding/ui/SetupStep.tsx
## Buzz Desktop release v0.5.0 ### Changes since v0.4.26: - feat(invites): add use-limited invite links ([#3141](#3141)) ([`d500c2d5c`](d500c2d)) - fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor ([#3218](#3218)) ([`98a7b1334`](98a7b13)) - fix(desktop): preserve thread anchor through layout reflow ([#3212](#3212)) ([`9810d8545`](9810d85)) - feat(search): parse from:/in:/after:/before: and pass them in the filter ([#2871](#2871)) ([`cb2a265b5`](cb2a265)) - fix(desktop): fetch join policies through native networking ([#2862](#2862)) ([`0019f8076`](0019f80)) - fix(desktop): republish agent identity records when a persona rename propagates ([#2607](#2607)) ([`7ca0bbd94`](7ca0bbd)) - fix(desktop): keep project Inbox previews compact ([#3193](#3193)) ([`de1396050`](de13960)) - Inbox refactor ([#2045](#2045)) ([`2bd4c24b7`](2bd4c24)) - Fix composer selection formatting and drop overlay ([#3172](#3172)) ([`99da5b7eb`](99da5b7)) - Refine pending message status ([#3153](#3153)) ([`75588eaff`](75588ea)) - fix(desktop): recover full local storage on startup ([#3182](#3182)) ([`174c38e4b`](174c38e)) - fix(desktop): keep collapsed table separators out of spoilers ([#3169](#3169)) ([`4d8b676bb`](4d8b676)) - feat(desktop): redesign agent runtime settings ([#3093](#3093)) ([`d98da7389`](d98da73)) - fix(desktop): use forward slashes for git credential.helper on Windows ([#3023](#3023)) ([`899531684`](8995316)) - chore(desktop): add AgentCreationPreview file-size override to unblock main CI ([#3154](#3154)) ([`b92a1f4bf`](b92a1f4)) - fix(desktop): make the test loader work on Windows ([#2758](#2758)) ([`8bb43d519`](8bb43d5)) - fix(desktop): make lint and unit-test gates work on Windows ([#2943](#2943)) ([`545bb46b8`](545bb46)) - feat(desktop): add search to agent emoji picker ([#2630](#2630)) ([`313f793c8`](313f793)) - fix(desktop): keep identity key help dialog readable in dark mode ([#2854](#2854)) ([`be275cfc6`](be275cf)) - feat(acp): title agent sessions from the agent and channel name ([#3028](#3028)) ([`f2fe3b63c`](f2fe3b6)) - feat(git): use agent display name as git author name ([#3040](#3040)) ([`18eef633d`](18eef63)) - fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) ([#3135](#3135)) ([`31e2de196`](31e2de1)) - fix(desktop): read the newest pair-scoped harness log ([#3134](#3134)) ([`654f38490`](654f384)) - feat(desktop): handle project work from Inbox ([#3117](#3117)) ([`c5c4f390b`](c5c4f39)) - fix(desktop): clarify identity key button when key exists ([#2357](#2357)) ([`87b3fcd3c`](87b3fcd)) - Restore Goose and Buzz Agent to onboarding harness selection ([#2731](#2731)) ([`7fc0cc82d`](7fc0cc8)) - fix(desktop): render rich project work item content ([#3100](#3100)) ([`afb272bb7`](afb272b)) - feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery ([#2773](#2773)) ([`95fdf9788`](95fdf97)) - feat(desktop): use collective mesh routing for Auto ([#2825](#2825)) ([`16d4ec335`](16d4ec3)) - fix(desktop): strip legacy baked team instructions from stored prompts ([#3035](#3035)) ([`aee631448`](aee6314)) - feat(agents): lower default agent parallelism from 24 to 10 ([#3038](#3038)) ([`5d8ede446`](5d8ede4)) - Polish community rail and mobile pairing ([#2972](#2972)) ([`e6c90bb7c`](e6c90bb)) - fix(desktop): remove bundled libsystemd from AppImage ([#2353](#2353)) ([`a31fc4d2f`](a31fc4d)) - fix(desktop): make agent definition authoritative for model/provider/prompt ([#1968](#1968)) ([`8c0e8cb16`](8c0e8cb)) - chore(desktop): delete dead persona catalog UI cluster ([#2886](#2886)) ([`8e67cf399`](8e67cf3)) - fix(desktop): surface install failures hidden by curl-pipe exit codes ([#2892](#2892)) ([`166c6655e`](166c665)) - Refactor managed-agent runtime into cohesive modules ([#2974](#2974)) ([`74b63e184`](74b63e1)) - fix(desktop): make Linux AppImage GStreamer work on non-Debian distros ([#2176](#2176)) ([`cc6c4d347`](cc6c4d3)) - refactor(desktop): remove Agent directory section from Agents page ([#2290](#2290)) ([`5d1233e84`](5d1233e)) - fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard ([#2904](#2904)) ([`ab7aa8b12`](ab7aa8b)) - fix(desktop): supervise and re-arm relay-mesh runtime ([#2823](#2823)) ([`aa51dab9d`](aa51dab)) - fix(agents): run live Databricks discovery instead of the fallback list ([#2890](#2890)) ([`8eb6e3eb6`](8eb6e3e)) - fix(desktop): retire prepend mode on every reader wheel ([#2913](#2913)) ([`07d0265cf`](07d0265)) - fix(desktop): consolidate prepend scroll correction ([#2855](#2855)) ([`25e7864b3`](25e7864)) - fix(desktop): track concurrent agent turns up to the harness maximum ([#2882](#2882)) ([`20bff5910`](20bff59)) - fix(relay): preserve reconnect backoff ([#2759](#2759)) ([`499c5d349`](499c5d3)) - refactor(relay): expose reconnect timing policy ([#2310](#2310)) ([`2f0041595`](2f00415)) - fix(desktop): clear stale working badges on agent stop/restart ([#2803](#2803)) ([`a64cc71f6`](a64cc71)) - fix(desktop): surface agent rename relay profile sync failure as a warning toast ([#2279](#2279)) ([`5e3d2e484`](5e3d2e4)) - fix(discovery): inject PATH into Codex adapter planning ([#2767](#2767)) ([`6ab3835f3`](6ab3835)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Fixes #2896
Root cause:
arboard = "3"compiles with default features only (image-data), so the Linux build has no Wayland backend. In a Wayland session every copy lands on the XWayland clipboard; the compositor only mirrors X11 selections while an XWayland window holds focus, and arboard's clipboard client is windowless, so Wayland-native apps read nothing.set_textstill returnsOk, which is why the invite dialog shows "Copied" with an empty clipboard.Fix: enable arboard's
wayland-data-controlfeature. Under Wayland it uses thezwlr-data-controlprotocol; whenWAYLAND_DISPLAYis absent it falls back to X11 as before. Thewl-clipboard-rsdependency is target-gated inside arboard, so macOS and Windows builds are unchanged.Verified:
cargo checkpasses on the desktop crate; wl-clipboard-rs now resolves in the lockfile.