1password / arboard Goto Github PK
View Code? Open in Web Editor NEWA clipboard for Rust
License: Apache License 2.0
A clipboard for Rust
License: Apache License 2.0
The README mentions
The Linux implementation uses the X protocol by default for managing the clipboard but fear not because Wayland works with the X11 protocoll [!] just as well.
which is a lie, because there's no guarantee that Xwayland may be running. But on the code side, there does seem to be an implementation for native Wayland:
arboard/src/wayland_data_control_clipboard.rs
Lines 88 to 102 in 23fc006
This confuses me a bit. Is there Wayland support now or not? (I'm seeing if Neovide could migrate from clipboard
to arboard
, but relying on Xwayland is... well, dangerous)
Hi, I'm a Rust beginner and I'm having different behaviors across X11 and Windows 10, so I'm wondering if I'm doing something stupid or if there's something that could be improved in this crate 🤔
Take this program:
use arboard::Clipboard;
use std::thread;
fn main() {
for n in 0..5 {
thread::spawn(move || {
let mut clipboard = Clipboard::new().unwrap();
let text = format!("thread #{}", n);
println!("Copying to clipboard: {}", text);
clipboard.set_text(text).unwrap();
})
.join()
.unwrap();
}
let mut clipboard = Clipboard::new().unwrap();
println!("Final clipboard text: {}", clipboard.get_text().unwrap());
}
It synchronously spawns 5 threads and creates a new clipboard context in each one of them (I think doing this is probably bad? but anyway...); Then, it copies the text thread #N
to the clipboard and exits the thread. And at the end it, it creates another clipboard context and displays its final content.
On my tests on a Windows 10 virtual machine, this is always the output I get when I run the program:
Copying to clipboard: thread #0
Copying to clipboard: thread #1
Copying to clipboard: thread #2
Copying to clipboard: thread #3
Copying to clipboard: thread #4
Final clipboard text: thread #4
Which is the behavior I expect... However, on my Linux machine (X11 session), I get this instead:
Copying to clipboard: thread #0
Copying to clipboard: thread #1
Copying to clipboard: thread #2
Copying to clipboard: thread #3
Copying to clipboard: thread #4
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ContentNotAvailable - "The clipboard contents were not available in the requested format or the clipboard is empty."', src/main.rs:17:63
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I was able to work around this issue on Linux by using a mutex to share a single clipboard context across threads:
use arboard::Clipboard;
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let clipboard = Arc::new(Mutex::new(Clipboard::new().unwrap()));
for n in 0..5 {
let clipboard = Arc::clone(&clipboard);
thread::spawn(move || {
let mut clipboard = clipboard.lock().unwrap();
let text = format!("thread #{}", n);
println!("Copying to clipboard: {}", text);
(*clipboard).set_text(text).unwrap();
})
.join()
.unwrap();
}
let mut clipboard = Clipboard::new().unwrap();
println!("Final clipboard text: {}", clipboard.get_text().unwrap());
}
Which now works perfectly, but in the end I wonder if I really have to do this... 🤔
Thanks for this crate.
running the following:
use arboard::Clipboard;
fn main() {
let mut clipboard = Clipboard::new().unwrap();
let the_string = "Hello, world!";
clipboard.set_text(the_string).unwrap();
println!("But now the clipboard text should be: \"{}\"", the_string);
}
nothing new seems to be copied to the clipboard. the previous thing in the clipboard is still there.
output of cargo run
:
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/exers`
But now the clipboard text should be: "Hello, world!"
my neofetch
:
OS: Arch Linux x86_64
Host: Inspiron 14 5420
Kernel: 6.8.2-arch2-1
Uptime: 16 hours, 11 mins
Packages: 1131 (pacman)
Shell: bash 5.2.26
Resolution: 2240x1400
DE: Plasma 6.0.3
WM: KWin
Theme: Breeze-Dark [GTK2], Breeze [GTK3]
Icons: breeze-dark [GTK2/3]
Terminal: tmux
CPU: 12th Gen Intel i7-1255U (12) @ 4.700GHz
GPU: Intel Alder Lake-UP3 GT2 [Iris Xe Graphics]
GPU: NVIDIA GeForce MX570
Memory: 4411MiB / 15682MiB
Currently the Windows implementation uses the image
crate to generate a bmp which may or may not be compressed depending on the underlying implementation of image
.
Forcing compression with bmp or using a different format, like compressed png could be good alternatives. One thing to factor in is how wide-spread is the support for these formats as it wouldn't make much sense to generate both the compressed and the uncompressed format for compatibility sake (assuming that every program supports uncompressed bmp)
when i use function of get_text(),it makes error: Err(Unknown { .. } - "Unknown error while interacting with the clipboard: failed to read clipboard string")
. this error offen happen. could you resolve it?
my code:
`
pub fn get_selected_text_by_clipboard() -> Result<String, Box> {
use arboard::Clipboard;
use std::{thread, time::Duration};
let old_clipboard = (Clipboard::new()?.get_text(), Clipboard::new()?.get_image());
let mut write_clipboard = Clipboard::new()?;
let not_selected_placeholder = "";
write_clipboard.set_text(not_selected_placeholder)?;
thread::sleep(Duration::from_millis(50));
copy();
thread::sleep(Duration::from_millis(100));
let new_text = Clipboard::new()?.get_text();
println!("new_text: {:?}", new_text);
match old_clipboard {
(Ok(old_text), _) => {
// Old Content is Text
write_clipboard.set_text(old_text.clone())?;
if let Ok(new) = new_text {
if new.trim() == not_selected_placeholder.trim() {
Ok(String::new())
} else {
Ok(new)
}
} else {
Ok(String::new())
}
}
(_, Ok(image)) => {
// Old Content is Image
write_clipboard.set_image(image)?;
if let Ok(new) = new_text {
if new.trim() == not_selected_placeholder.trim() {
Ok(String::new())
} else {
Ok(new)
}
} else {
Ok(String::new())
}
}
_ => {
// Old Content is Empty
write_clipboard.clear()?;
if let Ok(new) = new_text {
if new.trim() == not_selected_placeholder.trim() {
Ok(String::new())
} else {
Ok(new)
}
} else {
Ok(String::new())
}
}
}
}
`
Hey,
I try to use this crate to copy gifs into my clipboard looking like "<img src=\"data:image/gif;base64,$base64\" >"
.
This works fine when done in Java and put into the DataFormat.HTML
slot of the ClipboardContent
but I cannot get this working in rust :( Is it maybe not possible with this crate, because it uses somewhere internally something like "text/plain"
?
I use it like the following, not providing a gif because unsure about permssions.
use arboard::Clipboard;
extern crate image_base64;
fn main() {
let mut clipboard = Clipboard::new().unwrap();
let image_base64 = image_base64::to_base64("src/pleaseWork.gif");
// Used meta-tag in hope of content negotiation at some higher level
let once_more_html = format!(r#"<meta http-equiv="content-type" content="text/html; charset=utf-8"><img alt="" src="{image_base64}">"#);
clipboard.set_text(once_more_html.to_string()).unwrap()
}
KDE Plasma uses their own clipboard manager (klipper) and as a result, the string passed into set_text is not accessible via CTRL+V/Super+V.
This issue is related to emilk/egui#2425 where the problem is documented.
egui 0.20.0 (which I wanted to update from 0.19.0 which works without this problem) does not work in Windows 11 WSLg anymore.
Issue is an error from arboard during startup in the WSLg environment.
This is teh version diff between using egui 0.19.0 and 0.20.0 for arboard from Cargo.lock. So it seems version 3 has this problem while 2 does not.
[[package]]
name = "arboard"
-version = "2.1.1"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc120354d1b5ec6d7aaf4876b602def75595937b5e15d356eb554ab5177e08bb"
+checksum = "d6041616acea41d67c4a984709ddab1587fd0b10efe5cc563fee954d2f011854"
I am using the bitwarden desktop app on Linux/KDE, which uses arboard to manage the clipboard and noticed that passwords are stored in the KDE Klipper clipboard manager history.
This can be circumvented by adding x-kde-passwordManagerHint
MIME data hint to the clipboard entry and setting it to secret
, see:
https://bugs.kde.org/show_bug.cgi?id=458063
This is implemented in keepassxreboot in this PR:
https://github.com/keepassxreboot/keepassxc/pull/1969/commits
BTW the current source code of keepassxreboot also contains an implementation that prevents macosx to put secrets into the clipboard manager: https://github.com/keepassxreboot/keepassxc/blob/7bfe9065cf3a7b9e32094d965eb13a8c7fc0cc82/src/gui/Clipboard.cpp#L56 So maybe this should be part of the generic interface.
failed to download from https://crates.io/api/v1/crates/adler/1.0.2/download
I believe this line is the culprit
arboard/src/platform/linux/wayland.rs
Line 139 in c6102b1
I'm getting image data that is completely wrong in size (and presumably in format) when I copy random internet images to the clipboard and then call get_image()
.
I am assuming that, given something like let x = clipboard.get_image()?
, then we should have x.bytes.len() == 4 * x.width * x.height
. But I am not getting that at all.
Please advise.
This is hanging up Bevy_egui(and presumable Egui itself) on Android.
This actually looks like it doesn't line up with the github repo, so this might be fixed already?
OS: MacOS 13.5
Rust version: rustc 1.71.1 (eb26296b5 2023-08-03)
arboard version: tried with both 3.2.0 and master(f409d08)
code:
use arboard::Clipboard;
fn main() {
let mut clipboard = Clipboard::new().unwrap();
let image = clipboard.get_image().unwrap();
println!("{}", image.width);
}
stderr:
fish: Job 1, 'cargo run' terminated by signal SIGBUS (Misaligned address error)
Under Windows, if I write the empty string on the clipboard (clear it), I expect that if I read it back, I get again the empty string. But in this case, clipboard.get_text()
panics. The error message is the following:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ContentNotAvailable - "The clipboard contents were not available in the requested format or the clipboard is empty."'
The clipboard is empty, true, but shouldn't it return the empty string in this case?
error[E0432]: unresolved import `crate::common::ScopeGuard`
--> src/x11_clipboard.rs:45:13
|
45 | use crate::{common::ScopeGuard, common_linux::into_unknown, Error, LinuxClipboardKind};
| ^^^^^^^^^^^^^^^^^^ no `ScopeGuard` in `common`
For more information about this error, try `rustc --explain E0432`.
error: could not compile `arboard` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
…and maybe other dependencies 🙏
What is the minimum supported Rust version for this crate?
If possible, setting rust-version
metadata is helpful for checking MSRV.
Considering that xcb
has been marked by cargo-audit
as problematic: https://rustsec.org/advisories/RUSTSEC-2021-0019.html
Would a PR to replace it with x11rb
be accepted, or at least use it as an alternative with the help of a crate feature?
Cannot compile on windows with latest version v3.3.1
error[E0446]: private type `platform::windows::OpenClipboard<'_>` in public interface
--> C:\Users\gitlab_runner\.cargo\registry\src\index.crates.io-6f17d22bba15001f\arboard-3.3.1\src\platform\windows.rs:40:2
|
40 | pub fn add_cf_dibv5(_open_clipboard: OpenClipboard, image: ImageData) -> Result<(), Error> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
...
422 | struct OpenClipboard<'clipboard> {
| -------------------------------- `platform::windows::OpenClipboard<'_>` declared as private
For more information about this error, try `rustc --explain E0446`.
Platform: Arch linux with KDE Plasma 5.23.3, commit: 7b5d849 (latest master at time of issue creation)
Text setting works if app exit is delayed, image setting never works. Here's the output of the set_image example after adding a logger:
2021-11-22 23:16:32,100 TRACE [arboard::x11_clipboard] Started serve reqests thread.
2021-11-22 23:16:32,102 TRACE [arboard::x11_clipboard] Sending the data to the clipboard manager
2021-11-22 23:16:32,102 TRACE [arboard::x11_clipboard] The clipboard manager indicated that it's done requesting the contents from us.
2021-11-22 23:16:32,102 TRACE [arboard::x11_clipboard] SelectionRequest - selection is: CLIPBOARD, target is TARGETS
2021-11-22 23:16:32,102 TRACE [arboard::x11_clipboard] Handling TARGETS, dst property is _QT_SELECTION
2021-11-22 23:16:35,081 TRACE [arboard::x11_clipboard] SelectionRequest - selection is: CLIPBOARD, target is TARGETS
2021-11-22 23:16:35,081 WARN [arboard::x11_clipboard] Could not hand the clipboard contents over to the clipboard manager. The request timed out.
2021-11-22 23:16:35,081 TRACE [arboard::x11_clipboard] Handling TARGETS, dst property is _QT_SELECTION
2021-11-22 23:16:35,082 TRACE [arboard::x11_clipboard] SelectionRequest - selection is: CLIPBOARD, target is TARGETS
2021-11-22 23:16:35,082 TRACE [arboard::x11_clipboard] Handling TARGETS, dst property is _QT_SELECTION
2021-11-22 23:16:35,082 TRACE [arboard::x11_clipboard] Clipboard server window is being destroyed x_x
How to avoid getting stuck when the picture is very large, when the bytes is very long, and when using tauri to transmit?
Since version 3, arboard can't paste on other apps with text edior including vscode.
If this crate is used in a non-X11 Linux context, Cliboard::get_text()
double panics. Instead, I think an error should be returned from Clipboard::new()
if it's not possible to connect to a X11 server.
I'd be happy to implement this change, but since it will move the initialization to an earlier time, I thought it would be wise to first ask if you have any concerns or objections.
First panic:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ClosedParseErr', src/x11_clipboard.rs:98:57
stack backtrace:
0: rust_begin_unwind
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:475
1: core::panicking::panic_fmt
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/panicking.rs:85
2: core::option::expect_none_failed
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/option.rs:1221
3: core::result::Result<T,E>::unwrap
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:973
4: arboard::x11_clipboard::LockedObjects::new
at ./src/x11_clipboard.rs:98
5: arboard::x11_clipboard::ensure_lo_initialized
at ./src/x11_clipboard.rs:1173
6: arboard::x11_clipboard::X11ClipboardContext::get_text
at ./src/x11_clipboard.rs:1218
7: arboard::Clipboard::get_text
at ./src/lib.rs:65
8: hello_world::main
at ./examples/hello_world.rs:5
9: core::ops::function::FnOnce::call_once
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Second panic:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "PoisonError { inner: .. }"', src/x11_clipboard.rs:501:51
stack backtrace:
0: 0x560ad3feeb00 - std::backtrace_rs::backtrace::libunwind::trace::h577ea05e9ca4629a
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/../../backtrace/src/backtrace/libunwind.rs:96
1: 0x560ad3feeb00 - std::backtrace_rs::backtrace::trace_unsynchronized::h50b9b72b84c7dd56
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/../../backtrace/src/backtrace/mod.rs:66
2: 0x560ad3feeb00 - std::sys_common::backtrace::_print_fmt::h6541cf9823837fac
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/sys_common/backtrace.rs:79
3: 0x560ad3feeb00 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hf64fbff071026df5
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/sys_common/backtrace.rs:58
4: 0x560ad4008f7c - core::fmt::write::h9ddafa4860d8adff
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/fmt/mod.rs:1082
5: 0x560ad3fed017 - std::io::Write::write_fmt::h1d2ee292d2b65481
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/io/mod.rs:1514
6: 0x560ad3ff0de0 - std::sys_common::backtrace::_print::ha25f9ff5080d886d
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/sys_common/backtrace.rs:61
7: 0x560ad3ff0de0 - std::sys_common::backtrace::print::h213e8aa8dc5405c0
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/sys_common/backtrace.rs:48
8: 0x560ad3ff0de0 - std::panicking::default_hook::{{closure}}::h6482fae49ef9d963
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:200
9: 0x560ad3ff0b2c - std::panicking::default_hook::he30ad7589e0970f9
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:219
10: 0x560ad3ff1443 - std::panicking::rust_panic_with_hook::haa1ed36ada4ffb03
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:569
11: 0x560ad3ff1019 - std::panicking::begin_panic_handler::{{closure}}::h7001af1bb21aeaeb
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:476
12: 0x560ad3feef8c - std::sys_common::backtrace::__rust_end_short_backtrace::h39910f557f5f2367
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/sys_common/backtrace.rs:153
13: 0x560ad3ff0fd9 - rust_begin_unwind
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:475
14: 0x560ad40082a1 - core::panicking::panic_fmt::h4e2659771ebc78eb
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/panicking.rs:85
15: 0x560ad40080c3 - core::option::expect_none_failed::h448b58a024c2c33a
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/option.rs:1221
16: 0x560ad3f6e040 - core::result::Result<T,E>::unwrap::h687c87c3f313b615
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:973
17: 0x560ad3f5d7fe - arboard::x11_clipboard::Manager::destruct::hd0e565fd5595762c
at /home/jonas/Code/experiments/rust/clipboard/arboard/src/x11_clipboard.rs:501
18: 0x560ad3f521ef - <arboard::x11_clipboard::X11ClipboardContext as core::ops::drop::Drop>::drop::h307ccff1f5befb5d
at /home/jonas/Code/experiments/rust/clipboard/arboard/src/x11_clipboard.rs:1205
19: 0x560ad3f4e526 - core::ptr::drop_in_place::hf42d2093737883dc
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:184
20: 0x560ad3f4e4fe - core::ptr::drop_in_place::hab210301fc93f3d4
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:184
21: 0x560ad3f4e1fb - hello_world::main::h844a495b302b237f
at /home/jonas/Code/experiments/rust/clipboard/arboard/examples/hello_world.rs:10
22: 0x560ad3f4e49b - core::ops::function::FnOnce::call_once::h13d94cf6f0dabc3e
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
23: 0x560ad3f4e43e - std::sys_common::backtrace::__rust_begin_short_backtrace::hce407c5b19206a5a
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:137
24: 0x560ad3f4e981 - std::rt::lang_start::{{closure}}::h2d710c588bfdbe82
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:66
25: 0x560ad3ff1841 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h6a3209f124be2235
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/ops/function.rs:259
26: 0x560ad3ff1841 - std::panicking::try::do_call::h88ce358792b64df0
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:373
27: 0x560ad3ff1841 - std::panicking::try::h6311c259678e50fc
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:337
28: 0x560ad3ff1841 - std::panic::catch_unwind::h56c5716807d659a1
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panic.rs:379
29: 0x560ad3ff1841 - std::rt::lang_start_internal::h73711f37ecfcb277
at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/rt.rs:51
30: 0x560ad3f4e957 - std::rt::lang_start::hee4923ac0b96e659
at /home/jonas/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:65
31: 0x560ad3f4e42a - main
32: 0x7f5d6a551152 - __libc_start_main
33: 0x560ad3f4e09e - _start
34: 0x0 - <unknown>
thread panicked while panicking. aborting.
As was described at #37 (comment)
Arboard 3.2.0
Arch Linux/X11
Arboard works as intended in an empty project.
However, in a Bevy project Arboard outputs the following when trying to set text or image:
TRACE arboard::platform::linux::x11: Sending the data to the clipboard manager
TRACE arboard::platform::linux::x11: Started serve requests thread.
TRACE arboard::platform::linux::x11: The clipboard manager indicated that it's done requesting the contents from us.
WARN arboard::platform::linux::x11: Could not hand the clipboard contents over to the clipboard manager. The request timed out.
TRACE arboard::platform::linux::x11: Clipboard server window is being destroyed x_x
Simply put, this works:
fn main() {
let subscriber = tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::TRACE)
.finish();
tracing::subscriber::set_global_default(subscriber).unwrap();
let mut clipboard = arboard::Clipboard::new().unwrap();
clipboard.set_text("hello world").unwrap();
}
This doesn't:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, system)
.run();
}
fn system(input: Res<Input<KeyCode>>) {
if input.just_pressed(KeyCode::F12) {
let mut clipboard = arboard::Clipboard::new().unwrap();
clipboard.set_text("hello world").unwrap();
}
}
When I use the set_text method, the text isn't set to the clipboard. But when I add a little delay before the program exists it works. Here is the code
let clipboard = Clipboard::new();
match clipboard {
Ok(mut clipboard) => {
let text = clipboard.set_text("hello world 2".to_string());
match text {
Ok(_) => {
println!("OK");
//std::thread::sleep(std::time::Duration::from_millis(10));
}
Err(_) => {
println!("Error");
}
}
},
Err(_) => {
}
}
When I uncomment the std::thread::sleep(std::time::Duration::from_millis(10));
it works. But I guess this isn't the intended behaviour
JFYI you can get image by using high level format type https://docs.rs/clipboard-win/4.0.2/clipboard_win/formats/struct.Bitmap.html
It is to be used within context of opened clipboard.
See Getter/Setter traits.
If you want you can add CF_DIB to code by making PR
There are also shortcut functions that open/close clipboard and get data to owned data structure if you don't need to efficiently re-use buffers https://docs.rs/clipboard-win/4.0.2/clipboard_win/fn.get_clipboard.html
Hey there! Would you be open to supporting browsers behind a feature flag that uses wasm-bindgen
?
Hey y'all, Rust newbie here. For context, I am building a desktop app with Tauri and using arboard
to read/write images from/to the clipboard. The writing part works fine but the part I am struggling with is taking the image I read from the clipboard and rendering it on the client so the user can view and edit the image.
Things I've tried in JS:
image.bytes
into a blob/base64 string.image.bytes
into a canvas.Things I've tried in Rust:
image.bytes
to a file using this approach.In Rust, the file gets saved by when I open it, I just see this.
I think the issue is probably with my understanding of what image.bytes
returns and how to use it to actually convert it into a PNG or any other format that I can use to display the image. I know the image itself is in the form of this ImageData
struct but I don't really understand much beyond that.
Could someone help walk me through this or give me some pointers so I can further experiment with implementing this feature within my app?
Additional context: My dev environment is MacOS 12.4 and my frontend is written in React.
As it stands ImageData requires an alpha channel. I think to new users it would be intuitive that you specify some kind of depth for the Image data you're trying to set, for example Rgb8, Rgba8, La8
.
As it stands trying to set a simple .jpg to the clipboard with return an slice out of range error:
let mut ctx = arboard::Clipboard::new().unwrap();
let img = ImageReader::open("imgs/glitch_1.jpg").unwrap().decode().unwrap();
let (w,h) = img.clone().into_rgb8().dimensions();
let bytes = img.as_bytes();
let img_data = arboard::ImageData{ width: w as usize, height: h as usize, bytes: bytes.into()};
ctx.set_image(img_data).unwrap();
///for a 400x400 JPEG
thread 'main' panicked at 'range start index 638400 out of range for slice of length 480000',
If providing an alpha channel is a requirement of the OS, then maybe the readme/examples/docs could mention this, and provide some strategies for working around it, given that many people would assume support for common compression formats.
Pasted image in Word can’t be displayed,but mspaint can
Steps to reproduce
extern crate arboard;
use arboard::{Clipboard, ImageData};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut clipboard = Clipboard::new()?;
let image: ImageData = clipboard.get_image()?.to_owned_img();
println!(
"Found image, width: {}px, height: {}px, size: {}bytes",
image.width,
image.height,
image.bytes.len()
);
clipboard.set_image(image)?;
return Ok(());
}
I'm interested in getting the paths of files & directories copied from explorer/finder/etc. Is this a use case that will be supported?
I just tried on MacOS, and through the get_text()
API I got the names of the files/dirs separated by \r
, but not the full paths, nor a way to distinguish between regular text and file paths.
Thanks for creating and maintaining this library!
With examples/hello_world.rs
and initial "some old contents" clipboard contents:
$ target/debug/examples/hello_world
Clipboard text was: some old content
But now the clipboard text should be: "Hello, world!"
$ target/debug/examples/hello_world
Clipboard text was: some old content
But now the clipboard text should be: "Hello, world!"
$ target/debug/examples/hello_world
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ContentNotAvailable - "The clipboard contents were not available in the requested format or the clipboard is empty."', examples/hello_world.rs:5:61
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
The first run appears to have no effect on the X11 clipboard; the second one does have some effect, but only to clear it.
Note that the panic in the third run is only a side effect: the example in question doesn't handle the case where the clipboard is empty.
After some debugging, it seems that x11_clipboard_manager
is 0 during the destruct
call, preventing the handing off of the data.
I'm not sure why the x11_clipboard_manager != 0
condition is necessary, and if fact it seems that a xcb_window_t
value of 0 (or XCB_NONE
) is valid for other XCB calls; for example, in xcb_set_selection_owner
it means that the selection will have no owner.
I experimented with removing this condition entirely (and the previous calls that only serve to fill in x11_clipboard_manager
) and everything worked just fine, but I'm well aware that this doesn't mean anything, particularly when dealing with Xorg. : )
P.S. I first noticed the problem in 1.0.1, but I've been since working on top of the current HEAD.
Is there any way to handle clipboard change event?
Hi there,
While looking at migrating from x11-clipboard
to arboard
, I noticed that some of the more "advanced" configuration options are gone, such as being able to control the atoms used in get and store operations.
It would be nice if arboard
exposed functionality in some way that would allow users to, optionally, change which X11 clipboard operations are performed on.
A rough non-breaking change could be something like this:
pub enum X11ClipboardChoice {
Clipboard
Primary,
Secondary,
}
impl X11ClipboardContext {
pub fn get_text(&self) -> Result<String, Error> { ... }
pub fn get_text_with_clipboard(&self, clipboard: X11ClipboardChoice) -> Result<String, Error> { ... }
}
Is this a feature you would consider adding or accepting work for?
Heya! Rust noob here. I was trying to make a basic CLI app, and came across an issue while using arboard for copying the image to clipboard.
For some reason, every time I try to copy an image, it throws me this error:
thread 'main' panicked at 'assertion failed: !result.is_null()
I don't know what I'm doing wrong, but here's the code for it:
use arboard::{Clipboard, ImageData};
use imagesize::size;
use std::fs;
fn main() {
let mut ctx = Clipboard::new().unwrap();
let file_path = "./temp/Q0w4OleUkPoTRS7KGCZIJP1LV7fZPT.jpg";
let contents = fs::read(file_path).expect("Should have been able to read the file");
let (width, height) = match size(file_path) {
Ok(dim) => (dim.width, dim.height),
Err(_why) => (19, 19),
};
let img_data = ImageData {
height,
width,
bytes: std::borrow::Cow::Borrowed(contents.as_ref()),
};
ctx.set_image(img_data).unwrap();
println!("Done!")
}
Help towards the right direction would be appreciated! Thanks!
Hey, is the maintainer able to make a new release, updating the wl-clipboard-rs 2243d0d removed a dependency on failure
which is unmaintained and has security issues, see https://rustsec.org/packages/failure.html
When an image is copied, than pasted using a different software, it seems that the color channels are mixed up relative to the original.
I believe this only affects AMD CPUs as they might have a different endianness from Intel ones.
I noticed in the readme that you plan to deprecate the project. I don't know how many users it has or if there are alternatives but i'd like to suggest to you that you should instead attempt to find new maintainers. The best places for that are probably r/rust and This week in Rust's Call for Participation section, maybe also https://users.rust-lang.org/.
You can create a GitHub organization and add interested people into it. You could also attempt to transfer ownership to an organization that already depends on it like https://github.com/alacritty. As a last resort, you can use Rust Bus so the crate can find new owners and save people the maintenance burden of looking for a new fork and switching to it.
Since 3.0, we should now create a new Clipboard
, use it, then drop it right away on Windows.
However, I'm getting reports that that same code doesn't work on Linux X11, and that we there instead need to create a Clipboard
once and then keep it around for the life of the program: emilk/egui#2138
If true, this makes using arboard
suddenly very annoying as I need different paths depending on what platform I am compiling for (which is exactly what I want arboard
to help me abstract).
From a users point of view, I just want access to functions to copy and paste text and images. I don't want to think about the lifetime of the Clipboard
resource.
Environment: Linux with X11, the application is being run as root because it also uses evdev
.
For images copied from Chrome, everything works fine, but when I try to read a screenshot produced by Spectacle, this happens:
2023-05-08T12:26:31.282Z TRACE [arboard::platform::linux::x11] Started serve requests thread.
2023-05-08T12:26:31.282Z TRACE [arboard::platform::linux::x11] Trying to get the clipboard data.
2023-05-08T12:26:31.283Z TRACE [arboard::platform::linux::x11] Finished `convert_selection`
2023-05-08T12:26:31.283Z TRACE [arboard::platform::linux::x11] Read SelectionNotify
2023-05-08T12:26:31.283Z TRACE [arboard::platform::linux::x11] Clipboard server window is being destroyed x_x
get_clipboard_content() = Err(
Unknown { .. } - "Unknown error while interacting with the clipboard: incorrect type received from clipboard",
)
xclip -selection clipboard -t TARGETS -o
TIMESTAMP
TARGETS
SAVE_TARGETS
MULTIPLE
image/png
text/html
application/x-qt-image
x-kde-force-image-copy
image/png
image/avif
image/bmp
image/bw
image/cur
image/eps
image/epsf
image/epsi
image/heic
image/heif
image/icns
image/ico
image/jp2
image/jpeg
image/jpg
image/jxl
image/pbm
BITMAP
image/pcx
image/pgm
image/pic
image/ppm
PIXMAP
image/rgb
image/rgba
image/sgi
image/tga
image/tif
image/tiff
image/wbmp
image/webp
image/xbm
image/xpm
TARGETS
MULTIPLE
TIMESTAMP
SAVE_TARGETS
As shown here, both cases do provide image/png
, I wonder why this is not working, as the code in this library says that this should never happen.
BTW, since we already uses the image
crate, why not provide a function that reads a PNG from the clipboard (this can be behind a feature flag, since we don't need to decode images on Windows)? We might be able to skip some decompression and compression for folks who actually need a PNG or other compressed format to work on.
Is there any way to compare ImageData?
Hi, nice crate! I'm looking into implementing Web Clipboard API for Deno and this crate seems perfect for that. Though, there has to be a method to directly read/write bytes to implement that. Will it be added?
Hello!
I'm authoring copykitten
, a Python library that provides clipboard operations utilizing arboard
under the hood. I have an issue report from a user, who has a problem pasting transparent images into PowerPoint on Windows: Klavionik/copykitten#5. I was able to confirm this issue and now looking for a solution.
There's one way, which is to make arboard
put images into the clipboard not only in bitmap and DIB formats but also as a PNG file. This is a trick used by Google Chrome, for example. I believe this would be useful for many Windows applications, not only PowerPoint.
I have a working draft of code that does that and as far as I can see it works fine. If you are interested in this I could work on a pull request implementing this feature.
I'm trying to run the example in the readme on an ArchLinux/Wayland/Sway desktop environment, but I get the error: error while interacting with the clipboard: Display parsing error
.
I see in the readme it says: There's also an optional wayland data control backend through the wl-clipboard-rs crate. This can be enabled using the wayland-data-control feature.
, but it's not clear how to do that or if it would let me build the example without an error.
I'm trying to fix a build fail in a GUI application called MFEKglif with this issue.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.