refactor(clipboard): use arboard instead of tao closes #8177 (#8394)

* refactor(clipboard): use arboard instead of tao closes #8177

* update api lock

* add change file
This commit is contained in:
Lucas Fernandes Nogueira 2023-12-14 13:41:20 -03:00 committed by GitHub
parent 1c582a942e
commit 0d0501cb7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 151 additions and 94 deletions

5
.changes/arboard.md Normal file
View File

@ -0,0 +1,5 @@
---
"tauri-runtime-wry": patch:bug
---
Use `arboard` instead of `tao` clipboard implementation to prevent a crash.

View File

@ -20,6 +20,7 @@ uuid = { version = "1", features = [ "v4" ] }
rand = "0.8"
raw-window-handle = "0.5"
tracing = { version = "0.1", optional = true }
arboard = { version = "3", optional = true }
[target."cfg(windows)".dependencies]
webview2-com = "0.19.1"
@ -47,6 +48,6 @@ macos-private-api = [
]
objc-exception = [ "wry/objc-exception" ]
global-shortcut = [ "tauri-runtime/global-shortcut" ]
clipboard = [ "tauri-runtime/clipboard" ]
clipboard = [ "tauri-runtime/clipboard", "arboard" ]
linux-headers = [ "wry/linux-headers", "webkit2gtk/v2_36" ]
tracing = [ "dep:tracing", "wry/tracing" ]

View File

@ -4,59 +4,36 @@
//! Clipboard implementation.
use crate::{getter, Context, Message};
use std::sync::{
mpsc::{channel, Sender},
Arc, Mutex,
use std::{
fmt,
sync::{Arc, Mutex},
};
use tauri_runtime::{ClipboardManager, Result, UserEvent};
pub use wry::application::clipboard::Clipboard;
pub use arboard::Clipboard;
use tauri_runtime::{ClipboardManager, Result};
#[derive(Debug, Clone)]
pub enum ClipboardMessage {
WriteText(String, Sender<()>),
ReadText(Sender<Option<String>>),
#[derive(Clone)]
pub struct ClipboardManagerWrapper {
pub clipboard: Arc<Mutex<Clipboard>>,
}
#[derive(Debug, Clone)]
pub struct ClipboardManagerWrapper<T: UserEvent> {
pub context: Context<T>,
impl fmt::Debug for ClipboardManagerWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ClipboardManagerWrapper").finish()
}
}
// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`.
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl<T: UserEvent> Sync for ClipboardManagerWrapper<T> {}
impl<T: UserEvent> ClipboardManager for ClipboardManagerWrapper<T> {
impl ClipboardManager for ClipboardManagerWrapper {
fn read_text(&self) -> Result<Option<String>> {
let (tx, rx) = channel();
getter!(self, rx, Message::Clipboard(ClipboardMessage::ReadText(tx)))
Ok(self.clipboard.lock().unwrap().get_text().ok())
}
fn write_text<V: Into<String>>(&mut self, text: V) -> Result<()> {
let (tx, rx) = channel();
getter!(
self,
rx,
Message::Clipboard(ClipboardMessage::WriteText(text.into(), tx))
)?;
Ok(())
}
}
pub fn handle_clipboard_message(
message: ClipboardMessage,
clipboard_manager: &Arc<Mutex<Clipboard>>,
) {
match message {
ClipboardMessage::WriteText(text, tx) => {
clipboard_manager.lock().unwrap().write_text(text);
tx.send(()).unwrap();
}
ClipboardMessage::ReadText(tx) => tx
.send(clipboard_manager.lock().unwrap().read_text())
.unwrap(),
self
.clipboard
.lock()
.unwrap()
.set_text(text.into())
.map_err(|e| crate::Error::Clipboard(Box::new(e)))
}
}

View File

@ -175,8 +175,6 @@ pub(crate) fn send_user_message<T: UserEvent>(
webview_id_map: context.webview_id_map.clone(),
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager: context.main_thread.global_shortcut_manager.clone(),
#[cfg(feature = "clipboard")]
clipboard_manager: context.main_thread.clipboard_manager.clone(),
windows: context.main_thread.windows.clone(),
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: context.main_thread.system_tray_manager.clone(),
@ -276,8 +274,6 @@ pub struct DispatcherMainThreadContext<T: UserEvent> {
pub web_context: WebContextStore,
#[cfg(all(desktop, feature = "global-shortcut"))]
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
#[cfg(feature = "clipboard")]
pub clipboard_manager: Arc<Mutex<Clipboard>>,
pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: SystemTrayManager,
@ -1213,8 +1209,6 @@ pub enum Message<T: 'static> {
),
#[cfg(all(desktop, feature = "global-shortcut"))]
GlobalShortcut(GlobalShortcutMessage),
#[cfg(feature = "clipboard")]
Clipboard(ClipboardMessage),
UserEvent(T),
}
@ -1226,8 +1220,6 @@ impl<T: UserEvent> Clone for Message<T> {
Self::Tray(i, m) => Self::Tray(*i, m.clone()),
#[cfg(all(desktop, feature = "global-shortcut"))]
Self::GlobalShortcut(m) => Self::GlobalShortcut(m.clone()),
#[cfg(feature = "clipboard")]
Self::Clipboard(m) => Self::Clipboard(m.clone()),
Self::UserEvent(t) => Self::UserEvent(t.clone()),
_ => unimplemented!(),
}
@ -1829,7 +1821,7 @@ pub struct Wry<T: UserEvent> {
global_shortcut_manager_handle: GlobalShortcutManagerHandle<T>,
#[cfg(feature = "clipboard")]
clipboard_manager_handle: ClipboardManagerWrapper<T>,
clipboard_manager_handle: ClipboardManagerWrapper,
event_loop: EventLoop<Message<T>>,
}
@ -1860,11 +1852,7 @@ impl<T: UserEvent> fmt::Debug for Wry<T> {
);
#[cfg(feature = "clipboard")]
d.field(
"clipboard_manager",
&self.context.main_thread.clipboard_manager,
)
.field("clipboard_manager_handle", &self.clipboard_manager_handle);
d.field("clipboard_manager_handle", &self.clipboard_manager_handle);
d.finish()
}
@ -1985,9 +1973,6 @@ impl<T: UserEvent> Wry<T> {
#[cfg(all(desktop, feature = "global-shortcut"))]
let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop)));
#[cfg(feature = "clipboard")]
let clipboard_manager = Arc::new(Mutex::new(Clipboard::new()));
let windows = Rc::new(RefCell::new(HashMap::default()));
let webview_id_map = WebviewIdStore::default();
@ -2003,8 +1988,6 @@ impl<T: UserEvent> Wry<T> {
web_context,
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager,
#[cfg(feature = "clipboard")]
clipboard_manager,
windows,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager,
@ -2023,7 +2006,7 @@ impl<T: UserEvent> Wry<T> {
#[cfg(feature = "clipboard")]
#[allow(clippy::redundant_clone)]
let clipboard_manager_handle = ClipboardManagerWrapper {
context: context.clone(),
clipboard: Arc::new(Mutex::new(Clipboard::new().unwrap())),
};
Ok(Self {
@ -2056,7 +2039,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
type GlobalShortcutManager = GlobalShortcutManagerHandle<T>;
#[cfg(feature = "clipboard")]
type ClipboardManager = ClipboardManagerWrapper<T>;
type ClipboardManager = ClipboardManagerWrapper;
#[cfg(all(desktop, feature = "system-tray"))]
type TrayHandler = SystemTrayHandle<T>;
@ -2221,8 +2204,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
#[cfg(all(desktop, feature = "global-shortcut"))]
let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone();
#[cfg(feature = "clipboard")]
let clipboard_manager = self.context.main_thread.clipboard_manager.clone();
let mut iteration = RunIteration::default();
let proxy = self.event_loop.create_proxy();
@ -2249,8 +2230,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
global_shortcut_manager: global_shortcut_manager.clone(),
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager_handle: &global_shortcut_manager_handle,
#[cfg(feature = "clipboard")]
clipboard_manager: clipboard_manager.clone(),
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: system_tray_manager.clone(),
#[cfg(feature = "tracing")]
@ -2275,8 +2254,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
global_shortcut_manager: global_shortcut_manager.clone(),
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager_handle: &global_shortcut_manager_handle,
#[cfg(feature = "clipboard")]
clipboard_manager: clipboard_manager.clone(),
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: system_tray_manager.clone(),
#[cfg(feature = "tracing")]
@ -2306,9 +2283,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
#[cfg(all(desktop, feature = "global-shortcut"))]
let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone();
#[cfg(feature = "clipboard")]
let clipboard_manager = self.context.main_thread.clipboard_manager.clone();
let proxy = self.event_loop.create_proxy();
self.event_loop.run(move |event, event_loop, control_flow| {
@ -2326,8 +2300,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
global_shortcut_manager: global_shortcut_manager.clone(),
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager_handle: &global_shortcut_manager_handle,
#[cfg(feature = "clipboard")]
clipboard_manager: clipboard_manager.clone(),
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: system_tray_manager.clone(),
#[cfg(feature = "tracing")]
@ -2351,8 +2323,6 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
global_shortcut_manager: global_shortcut_manager.clone(),
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager_handle: &global_shortcut_manager_handle,
#[cfg(feature = "clipboard")]
clipboard_manager: clipboard_manager.clone(),
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: system_tray_manager.clone(),
#[cfg(feature = "tracing")]
@ -2372,8 +2342,6 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> {
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
#[cfg(all(desktop, feature = "global-shortcut"))]
pub global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle<T>,
#[cfg(feature = "clipboard")]
pub clipboard_manager: Arc<Mutex<Clipboard>>,
#[cfg(all(desktop, feature = "system-tray"))]
pub system_tray_manager: SystemTrayManager,
#[cfg(feature = "tracing")]
@ -2385,8 +2353,6 @@ struct UserMessageContext {
webview_id_map: WebviewIdStore,
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
#[cfg(feature = "clipboard")]
clipboard_manager: Arc<Mutex<Clipboard>>,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: SystemTrayManager,
}
@ -2401,8 +2367,6 @@ fn handle_user_message<T: UserEvent>(
webview_id_map,
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager,
#[cfg(feature = "clipboard")]
clipboard_manager,
windows,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager,
@ -2805,8 +2769,6 @@ fn handle_user_message<T: UserEvent>(
Message::GlobalShortcut(message) => {
handle_global_shortcut_message(message, &global_shortcut_manager)
}
#[cfg(feature = "clipboard")]
Message::Clipboard(message) => handle_clipboard_message(message, &clipboard_manager),
Message::UserEvent(_) => (),
}
@ -2831,8 +2793,6 @@ fn handle_event_loop<T: UserEvent>(
global_shortcut_manager,
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager_handle,
#[cfg(feature = "clipboard")]
clipboard_manager,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager,
#[cfg(feature = "tracing")]
@ -3079,8 +3039,6 @@ fn handle_event_loop<T: UserEvent>(
webview_id_map,
#[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager,
#[cfg(feature = "clipboard")]
clipboard_manager,
windows,
#[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager,

View File

@ -252,6 +252,9 @@ pub enum Error {
#[cfg(all(desktop, feature = "global-shortcut"))]
#[error(transparent)]
GlobalShortcut(Box<dyn std::error::Error + Send + Sync>),
#[cfg(all(desktop, feature = "clipboard"))]
#[error(transparent)]
Clipboard(Box<dyn std::error::Error + Send + Sync>),
#[error("Invalid header name: {0}")]
InvalidHeaderName(#[from] InvalidHeaderName),
#[error("Invalid header value: {0}")]

View File

@ -134,6 +134,25 @@ dependencies = [
"window-shadows",
]
[[package]]
name = "arboard"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aafb29b107435aa276664c1db8954ac27a6e105cdad3c88287a199eb0e313c08"
dependencies = [
"clipboard-win",
"core-graphics",
"image",
"log",
"objc",
"objc-foundation",
"objc_id",
"parking_lot",
"thiserror",
"winapi",
"x11rb",
]
[[package]]
name = "ascii"
version = "1.1.0"
@ -532,6 +551,17 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "clipboard-win"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362"
dependencies = [
"error-code",
"str-buf",
"winapi",
]
[[package]]
name = "cocoa"
version = "0.24.1"
@ -939,6 +969,16 @@ dependencies = [
"libc",
]
[[package]]
name = "error-code"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
dependencies = [
"libc",
"str-buf",
]
[[package]]
name = "event-listener"
version = "2.5.3"
@ -1240,6 +1280,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -1700,6 +1750,8 @@ dependencies = [
"color_quant",
"num-rational",
"num-traits",
"png",
"tiff",
]
[[package]]
@ -1835,6 +1887,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jpeg-decoder"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
[[package]]
name = "js-sys"
version = "0.3.64"
@ -3377,6 +3435,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "str-buf"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
[[package]]
name = "string_cache"
version = "0.8.7"
@ -3555,7 +3619,7 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
[[package]]
name = "tauri"
version = "1.5.2"
version = "1.5.3"
dependencies = [
"anyhow",
"base64 0.21.2",
@ -3660,7 +3724,7 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "1.4.1"
version = "1.4.2"
dependencies = [
"heck 0.4.1",
"proc-macro2",
@ -3691,8 +3755,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
version = "0.14.1"
version = "0.14.2"
dependencies = [
"arboard",
"cocoa",
"gtk",
"percent-encoding",
@ -3709,7 +3774,7 @@ dependencies = [
[[package]]
name = "tauri-utils"
version = "1.5.0"
version = "1.5.1"
dependencies = [
"aes-gcm",
"brotli",
@ -3834,6 +3899,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "tiff"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471"
dependencies = [
"flate2",
"jpeg-decoder",
"weezl",
]
[[package]]
name = "time"
version = "0.3.22"
@ -4405,6 +4481,12 @@ dependencies = [
"windows-metadata",
]
[[package]]
name = "weezl"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]]
name = "win7-notifications"
version = "0.4.0"
@ -4440,6 +4522,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "winapi-wsapoll"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
@ -4886,6 +4977,28 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "x11rb"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
dependencies = [
"gethostname",
"nix",
"winapi",
"winapi-wsapoll",
"x11rb-protocol",
]
[[package]]
name = "x11rb-protocol"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc"
dependencies = [
"nix",
]
[[package]]
name = "xattr"
version = "0.2.3"