fix(desktop): support Wayland image clipboard paste

This commit is contained in:
Kayshen-X 2026-07-27 21:08:15 +08:00
parent 3064554ff4
commit dcf8c3b1b3
3 changed files with 104 additions and 6 deletions

70
Cargo.lock generated
View file

@ -251,6 +251,7 @@ dependencies = [
"parking_lot",
"percent-encoding",
"windows-sys 0.60.2",
"wl-clipboard-rs",
"x11rb",
]
@ -810,7 +811,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
"nom 7.1.3",
]
[[package]]
@ -1369,7 +1370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab"
dependencies = [
"futures-core",
"nom",
"nom 7.1.3",
"pin-project-lite",
]
@ -1411,6 +1412,12 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "flate2"
version = "1.1.9"
@ -2770,6 +2777,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]]
name = "ntapi"
version = "0.4.3"
@ -3664,6 +3680,16 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_pipe"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "owned_ttf_parser"
version = "0.25.1"
@ -3718,6 +3744,17 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "petgraph"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap 2.14.0",
]
[[package]]
name = "phf"
version = "0.11.3"
@ -5501,6 +5538,17 @@ dependencies = [
"syn",
]
[[package]]
name = "tree_magic_mini"
version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
dependencies = [
"memchr",
"nom 8.0.0",
"petgraph",
]
[[package]]
name = "try-lock"
version = "0.2.5"
@ -6559,6 +6607,24 @@ dependencies = [
"wasmparser",
]
[[package]]
name = "wl-clipboard-rs"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3"
dependencies = [
"libc",
"log",
"os_pipe",
"rustix 1.1.4",
"thiserror 2.0.18",
"tree_magic_mini",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-protocols-wlr",
]
[[package]]
name = "writeable"
version = "0.6.3"

View file

@ -183,10 +183,11 @@ serde = { workspace = true }
serde_json = { workspace = true }
toml_edit = "0.25"
rfd = "0.14"
# OS clipboard for the AI chat input's Cmd+C / Cmd+V / Cmd+X.
# arboard wraps NSPasteboard (macOS), the Win32 clipboard, and
# X11 / Wayland on Linux — one cross-platform text-clipboard API.
arboard = "3"
# OS clipboard for Cmd+C / Cmd+V / Cmd+X, including canvas images.
# Native Wayland access is opt-in in arboard; without this feature a
# Wayland session still probes X11/XWayland and misses clipboard offers
# made directly by apps such as KDE Spectacle.
arboard = { version = "3", features = ["wayland-data-control"] }
# Base64-encodes chat image attachments for providers that take
# inline image content blocks (Claude SDK) or a base64 body field
# (HTTP-server transport). Same pure-Rust crate op-figma uses.

View file

@ -93,3 +93,34 @@ pub fn set_text(text: &str) {
let _ = clipboard.set_text(text.to_owned());
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::borrow::Cow;
#[test]
fn native_clipboard_rgba_is_encoded_as_png() {
let image = arboard::ImageData {
width: 2,
height: 1,
bytes: Cow::Owned(vec![255, 0, 0, 255, 0, 255, 0, 128]),
};
let encoded = encode_image(image).expect("valid clipboard RGBA should encode");
assert_eq!((encoded.width, encoded.height), (2, 1));
assert!(encoded.png.starts_with(b"\x89PNG\r\n\x1a\n"));
}
#[test]
fn native_clipboard_rgba_rejects_truncated_rows() {
let image = arboard::ImageData {
width: 2,
height: 1,
bytes: Cow::Owned(vec![255, 0, 0, 255]),
};
assert!(encode_image(image).is_none());
}
}