fix(clipboard-manager): Drop on exit (#2280)

* 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

* more specific
pull/2346/head
Fabian-Lars 4 months ago committed by GitHub
parent 784a54a390
commit ce11079f19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

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

@ -14,7 +14,7 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
) -> crate::Result<Clipboard<R>> {
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<R: Runtime, C: DeserializeOwned>(
pub struct Clipboard<R: Runtime> {
#[allow(dead_code)]
app: AppHandle<R>,
clipboard: Result<Mutex<arboard::Clipboard>, 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<Mutex<Option<arboard::Clipboard>>, arboard::Error>,
}
impl<R: Runtime> Clipboard<R> {
pub fn write_text<'a, T: Into<Cow<'a, str>>>(&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<R: Runtime> Clipboard<R> {
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<R: Runtime> Clipboard<R> {
}
}
/// Warning: This method should not be used on the main thread! Otherwise the underlying libraries may deadlock on Linux, freezing the whole app, when trying to copy data copied from this app, for example if the user copies text from the WebView.
pub fn read_text(&self) -> crate::Result<String> {
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<R: Runtime> Clipboard<R> {
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<R: Runtime> Clipboard<R> {
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, when trying to copy data copied from this app, for example if the user copies text from the WebView.
pub fn read_image(&self) -> crate::Result<Image<'_>> {
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<R: Runtime> Clipboard<R> {
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
}
}
pub(crate) fn cleanup(&self) {
if let Ok(clipboard) = &self.clipboard {
clipboard.lock().unwrap().take();
}
}
}

@ -11,7 +11,7 @@
use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime,
Manager, RunEvent, Runtime,
};
#[cfg(desktop)]
@ -59,5 +59,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
app.manage(clipboard);
Ok(())
})
.on_event(|_app, _event| {
#[cfg(desktop)]
if let RunEvent::Exit = _event {
_app.clipboard().cleanup();
}
})
.build()
}

Loading…
Cancel
Save