Skip to content

Commit ce11079

Browse files
authored
fix(clipboard-manager): Drop on exit (#2280)
* fix(clipboard-manager): Drop on exit ref https://docs.rs/arboard/latest/arboard/struct.Clipboard.html ref #2267 * more specific
1 parent 784a54a commit ce11079

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

.changes/clipboard-drop.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
clipboard-manager: patch
3+
clipboard-manager-js: patch
4+
---
5+
6+
Explicitly drop `arboard::Clipboard` on exit. Add recommendation to not use read methods on the mainthread.

plugins/clipboard-manager/src/desktop.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,29 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
1414
) -> crate::Result<Clipboard<R>> {
1515
Ok(Clipboard {
1616
app: app.clone(),
17-
clipboard: arboard::Clipboard::new().map(Mutex::new),
17+
clipboard: arboard::Clipboard::new().map(|c| Mutex::new(Some(c))),
1818
})
1919
}
2020

2121
/// Access to the clipboard APIs.
2222
pub struct Clipboard<R: Runtime> {
2323
#[allow(dead_code)]
2424
app: AppHandle<R>,
25-
clipboard: Result<Mutex<arboard::Clipboard>, arboard::Error>,
25+
// According to arboard docs the clipboard must be dropped before exit.
26+
// Since tauri doesn't call drop on exit we'll use an Option to take() on RunEvent::Exit.
27+
clipboard: Result<Mutex<Option<arboard::Clipboard>>, arboard::Error>,
2628
}
2729

2830
impl<R: Runtime> Clipboard<R> {
2931
pub fn write_text<'a, T: Into<Cow<'a, str>>>(&self, text: T) -> crate::Result<()> {
3032
match &self.clipboard {
31-
Ok(clipboard) => clipboard.lock().unwrap().set_text(text).map_err(Into::into),
33+
Ok(clipboard) => clipboard
34+
.lock()
35+
.unwrap()
36+
.as_mut()
37+
.unwrap()
38+
.set_text(text)
39+
.map_err(Into::into),
3240
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
3341
}
3442
}
@@ -38,6 +46,8 @@ impl<R: Runtime> Clipboard<R> {
3846
Ok(clipboard) => clipboard
3947
.lock()
4048
.unwrap()
49+
.as_mut()
50+
.unwrap()
4151
.set_image(ImageData {
4252
bytes: Cow::Borrowed(image.rgba()),
4353
width: image.width() as usize,
@@ -48,10 +58,11 @@ impl<R: Runtime> Clipboard<R> {
4858
}
4959
}
5060

61+
/// 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.
5162
pub fn read_text(&self) -> crate::Result<String> {
5263
match &self.clipboard {
5364
Ok(clipboard) => {
54-
let text = clipboard.lock().unwrap().get_text()?;
65+
let text = clipboard.lock().unwrap().as_mut().unwrap().get_text()?;
5566
Ok(text)
5667
}
5768
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
@@ -67,6 +78,8 @@ impl<R: Runtime> Clipboard<R> {
6778
Ok(clipboard) => clipboard
6879
.lock()
6980
.unwrap()
81+
.as_mut()
82+
.unwrap()
7083
.set_html(html, alt_text)
7184
.map_err(Into::into),
7285
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
@@ -75,15 +88,22 @@ impl<R: Runtime> Clipboard<R> {
7588

7689
pub fn clear(&self) -> crate::Result<()> {
7790
match &self.clipboard {
78-
Ok(clipboard) => clipboard.lock().unwrap().clear().map_err(Into::into),
91+
Ok(clipboard) => clipboard
92+
.lock()
93+
.unwrap()
94+
.as_mut()
95+
.unwrap()
96+
.clear()
97+
.map_err(Into::into),
7998
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
8099
}
81100
}
82101

102+
/// 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.
83103
pub fn read_image(&self) -> crate::Result<Image<'_>> {
84104
match &self.clipboard {
85105
Ok(clipboard) => {
86-
let image = clipboard.lock().unwrap().get_image()?;
106+
let image = clipboard.lock().unwrap().as_mut().unwrap().get_image()?;
87107
let image = Image::new_owned(
88108
image.bytes.to_vec(),
89109
image.width as u32,
@@ -94,4 +114,10 @@ impl<R: Runtime> Clipboard<R> {
94114
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
95115
}
96116
}
117+
118+
pub(crate) fn cleanup(&self) {
119+
if let Ok(clipboard) = &self.clipboard {
120+
clipboard.lock().unwrap().take();
121+
}
122+
}
97123
}

plugins/clipboard-manager/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
use tauri::{
1313
plugin::{Builder, TauriPlugin},
14-
Manager, Runtime,
14+
Manager, RunEvent, Runtime,
1515
};
1616

1717
#[cfg(desktop)]
@@ -59,5 +59,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
5959
app.manage(clipboard);
6060
Ok(())
6161
})
62+
.on_event(|_app, _event| {
63+
#[cfg(desktop)]
64+
if let RunEvent::Exit = _event {
65+
_app.clipboard().cleanup();
66+
}
67+
})
6268
.build()
6369
}

0 commit comments

Comments
 (0)