FabianLars 7 months ago
parent 6112867735
commit edbb8234be
No known key found for this signature in database

@ -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>> { ) -> crate::Result<Clipboard<R>> {
Ok(Clipboard { Ok(Clipboard {
app: app.clone(), 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> { pub struct Clipboard<R: Runtime> {
#[allow(dead_code)] #[allow(dead_code)]
app: AppHandle<R>, 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> { impl<R: Runtime> Clipboard<R> {
pub fn write_text<'a, T: Into<Cow<'a, str>>>(&self, text: T) -> crate::Result<()> { pub fn write_text<'a, T: Into<Cow<'a, str>>>(&self, text: T) -> crate::Result<()> {
match &self.clipboard { 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())), Err(e) => Err(crate::Error::Clipboard(e.to_string())),
} }
} }
@ -38,6 +46,8 @@ impl<R: Runtime> Clipboard<R> {
Ok(clipboard) => clipboard Ok(clipboard) => clipboard
.lock() .lock()
.unwrap() .unwrap()
.as_mut()
.unwrap()
.set_image(ImageData { .set_image(ImageData {
bytes: Cow::Borrowed(image.rgba()), bytes: Cow::Borrowed(image.rgba()),
width: image.width() as usize, 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.
pub fn read_text(&self) -> crate::Result<String> { pub fn read_text(&self) -> crate::Result<String> {
match &self.clipboard { match &self.clipboard {
Ok(clipboard) => { Ok(clipboard) => {
let text = clipboard.lock().unwrap().get_text()?; let text = clipboard.lock().unwrap().as_mut().unwrap().get_text()?;
Ok(text) Ok(text)
} }
Err(e) => Err(crate::Error::Clipboard(e.to_string())), Err(e) => Err(crate::Error::Clipboard(e.to_string())),
@ -67,6 +78,8 @@ impl<R: Runtime> Clipboard<R> {
Ok(clipboard) => clipboard Ok(clipboard) => clipboard
.lock() .lock()
.unwrap() .unwrap()
.as_mut()
.unwrap()
.set_html(html, alt_text) .set_html(html, alt_text)
.map_err(Into::into), .map_err(Into::into),
Err(e) => Err(crate::Error::Clipboard(e.to_string())), Err(e) => Err(crate::Error::Clipboard(e.to_string())),
@ -75,15 +88,22 @@ impl<R: Runtime> Clipboard<R> {
pub fn clear(&self) -> crate::Result<()> { pub fn clear(&self) -> crate::Result<()> {
match &self.clipboard { 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())), 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<Image<'_>> { pub fn read_image(&self) -> crate::Result<Image<'_>> {
match &self.clipboard { match &self.clipboard {
Ok(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( let image = Image::new_owned(
image.bytes.to_vec(), image.bytes.to_vec(),
image.width as u32, image.width as u32,
@ -94,4 +114,10 @@ impl<R: Runtime> Clipboard<R> {
Err(e) => Err(crate::Error::Clipboard(e.to_string())), 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::{ use tauri::{
plugin::{Builder, TauriPlugin}, plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, RunEvent, Runtime,
}; };
#[cfg(desktop)] #[cfg(desktop)]
@ -59,5 +59,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
app.manage(clipboard); app.manage(clipboard);
Ok(()) Ok(())
}) })
.on_event(|_app, _event| {
#[cfg(desktop)]
if let RunEvent::Exit = _event {
_app.clipboard().cleanup();
}
})
.build() .build()
} }

Loading…
Cancel
Save