From edbb8234beca2ef57d59077e678f7953761817b9 Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 8 Jan 2025 13:07:21 +0100 Subject: [PATCH] fix(clipboard-manager): Drop on exit ref https://docs.rs/arboard/latest/arboard/struct.Clipboard.html ref https://github.com/tauri-apps/plugins-workspace/issues/2267 --- .changes/clipboard-drop.md | 6 ++++ plugins/clipboard-manager/src/desktop.rs | 38 ++++++++++++++++++++---- plugins/clipboard-manager/src/lib.rs | 8 ++++- 3 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 .changes/clipboard-drop.md diff --git a/.changes/clipboard-drop.md b/.changes/clipboard-drop.md new file mode 100644 index 00000000..75624c3f --- /dev/null +++ b/.changes/clipboard-drop.md @@ -0,0 +1,6 @@ +--- +clipboard-manager: patch +clipboard-manager-js: patch +--- + +Explicitly drop `arboard::Clipboard` on exit. Add recommendation to not use read methods on the mainthread. diff --git a/plugins/clipboard-manager/src/desktop.rs b/plugins/clipboard-manager/src/desktop.rs index 5edd4934..5df2df8c 100644 --- a/plugins/clipboard-manager/src/desktop.rs +++ b/plugins/clipboard-manager/src/desktop.rs @@ -14,7 +14,7 @@ pub fn init( ) -> crate::Result> { Ok(Clipboard { app: app.clone(), - clipboard: arboard::Clipboard::new().map(Mutex::new), + clipboard: arboard::Clipboard::new().map(|c| Mutex::new(Some(c))), }) } @@ -22,13 +22,21 @@ pub fn init( pub struct Clipboard { #[allow(dead_code)] app: AppHandle, - clipboard: Result, arboard::Error>, + // According to arboard docs the clipboard must be dropped before exit. + // Since tauri doesn't call drop on exit we'll use an Option to take() on RunEvent::Exit. + clipboard: Result>, arboard::Error>, } impl Clipboard { pub fn write_text<'a, T: Into>>(&self, text: T) -> crate::Result<()> { match &self.clipboard { - Ok(clipboard) => clipboard.lock().unwrap().set_text(text).map_err(Into::into), + Ok(clipboard) => clipboard + .lock() + .unwrap() + .as_mut() + .unwrap() + .set_text(text) + .map_err(Into::into), Err(e) => Err(crate::Error::Clipboard(e.to_string())), } } @@ -38,6 +46,8 @@ impl Clipboard { Ok(clipboard) => clipboard .lock() .unwrap() + .as_mut() + .unwrap() .set_image(ImageData { bytes: Cow::Borrowed(image.rgba()), width: image.width() as usize, @@ -48,10 +58,11 @@ impl Clipboard { } } + /// Warning: This method should not be used on the main thread! Otherwise the underlying libraries may deadlock on Linux, freezing the whole app. pub fn read_text(&self) -> crate::Result { match &self.clipboard { Ok(clipboard) => { - let text = clipboard.lock().unwrap().get_text()?; + let text = clipboard.lock().unwrap().as_mut().unwrap().get_text()?; Ok(text) } Err(e) => Err(crate::Error::Clipboard(e.to_string())), @@ -67,6 +78,8 @@ impl Clipboard { Ok(clipboard) => clipboard .lock() .unwrap() + .as_mut() + .unwrap() .set_html(html, alt_text) .map_err(Into::into), Err(e) => Err(crate::Error::Clipboard(e.to_string())), @@ -75,15 +88,22 @@ impl Clipboard { pub fn clear(&self) -> crate::Result<()> { match &self.clipboard { - Ok(clipboard) => clipboard.lock().unwrap().clear().map_err(Into::into), + Ok(clipboard) => clipboard + .lock() + .unwrap() + .as_mut() + .unwrap() + .clear() + .map_err(Into::into), Err(e) => Err(crate::Error::Clipboard(e.to_string())), } } + /// Warning: This method should not be used on the main thread! Otherwise the underlying libraries may deadlock on Linux, freezing the whole app. pub fn read_image(&self) -> crate::Result> { match &self.clipboard { Ok(clipboard) => { - let image = clipboard.lock().unwrap().get_image()?; + let image = clipboard.lock().unwrap().as_mut().unwrap().get_image()?; let image = Image::new_owned( image.bytes.to_vec(), image.width as u32, @@ -94,4 +114,10 @@ impl Clipboard { Err(e) => Err(crate::Error::Clipboard(e.to_string())), } } + + pub(crate) fn cleanup(&self) { + if let Ok(clipboard) = &self.clipboard { + clipboard.lock().unwrap().take(); + } + } } diff --git a/plugins/clipboard-manager/src/lib.rs b/plugins/clipboard-manager/src/lib.rs index 133020d9..0cbb4e41 100644 --- a/plugins/clipboard-manager/src/lib.rs +++ b/plugins/clipboard-manager/src/lib.rs @@ -11,7 +11,7 @@ use tauri::{ plugin::{Builder, TauriPlugin}, - Manager, Runtime, + Manager, RunEvent, Runtime, }; #[cfg(desktop)] @@ -59,5 +59,11 @@ pub fn init() -> TauriPlugin { app.manage(clipboard); Ok(()) }) + .on_event(|_app, _event| { + #[cfg(desktop)] + if let RunEvent::Exit = _event { + _app.clipboard().cleanup(); + } + }) .build() }