浏览代码

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
Lucas Fernandes Nogueira 1 年之前
父节点
当前提交
0d0501cb7b

+ 5 - 0
.changes/arboard.md

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

+ 2 - 1
core/tauri-runtime-wry/Cargo.toml

@@ -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" ]

+ 20 - 43
core/tauri-runtime-wry/src/clipboard.rs

@@ -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)))
   }
 }

+ 4 - 46
core/tauri-runtime-wry/src/lib.rs

@@ -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,

+ 3 - 0
core/tauri-runtime/src/lib.rs

@@ -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}")]

+ 117 - 4
examples/api/src-tauri/Cargo.lock

@@ -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"