iced_winit: drop Clipboard before Window

Fixes #2482, avoids nasal daemons
This commit is contained in:
Maja Kądziołka 2024-08-11 22:33:17 +02:00
parent 1c8850023f
commit f92e01e913
No known key found for this signature in database
2 changed files with 24 additions and 9 deletions

View file

@ -1,6 +1,8 @@
//! Access the clipboard. //! Access the clipboard.
use crate::core::clipboard::Kind; use crate::core::clipboard::Kind;
use winit::window::Window;
use std::sync::Arc;
/// A buffer for short-term storage and transfer within and between /// A buffer for short-term storage and transfer within and between
/// applications. /// applications.
@ -10,18 +12,31 @@ pub struct Clipboard {
} }
enum State { enum State {
Connected(window_clipboard::Clipboard), Connected {
clipboard: window_clipboard::Clipboard,
// Held until drop to satisfy the safety invariants of
// `window_clipboard::Clipboard`.
//
// Note that the field ordering is load-bearing.
#[allow(dead_code)]
window: Arc<Window>,
},
Unavailable, Unavailable,
} }
impl Clipboard { impl Clipboard {
/// Creates a new [`Clipboard`] for the given window. /// Creates a new [`Clipboard`] for the given window.
pub fn connect(window: &winit::window::Window) -> Clipboard { pub fn connect(window: Arc<Window>) -> Clipboard {
#[allow(unsafe_code)] #[allow(unsafe_code)]
let state = unsafe { window_clipboard::Clipboard::connect(window) } // SAFETY: The window handle will stay alive throughout the entire
.ok() // lifetime of the `window_clipboard::Clipboard` because we hold
.map(State::Connected) // the `Arc<Window>` together with `State`, and enum variant fields
.unwrap_or(State::Unavailable); // get dropped in declaration order.
let clipboard = unsafe { window_clipboard::Clipboard::connect(&window) };
let state = match clipboard {
Ok(clipboard) => State::Connected { clipboard, window },
Err(_) => State::Unavailable,
};
Clipboard { state } Clipboard { state }
} }
@ -37,7 +52,7 @@ impl Clipboard {
/// Reads the current content of the [`Clipboard`] as text. /// Reads the current content of the [`Clipboard`] as text.
pub fn read(&self, kind: Kind) -> Option<String> { pub fn read(&self, kind: Kind) -> Option<String> {
match &self.state { match &self.state {
State::Connected(clipboard) => match kind { State::Connected { clipboard, .. } => match kind {
Kind::Standard => clipboard.read().ok(), Kind::Standard => clipboard.read().ok(),
Kind::Primary => clipboard.read_primary().and_then(Result::ok), Kind::Primary => clipboard.read_primary().and_then(Result::ok),
}, },
@ -48,7 +63,7 @@ impl Clipboard {
/// Writes the given text contents to the [`Clipboard`]. /// Writes the given text contents to the [`Clipboard`].
pub fn write(&mut self, kind: Kind, contents: String) { pub fn write(&mut self, kind: Kind, contents: String) {
match &mut self.state { match &mut self.state {
State::Connected(clipboard) => { State::Connected { clipboard, .. } => {
let result = match kind { let result = match kind {
Kind::Standard => clipboard.write(contents), Kind::Standard => clipboard.write(contents),
Kind::Primary => { Kind::Primary => {

View file

@ -307,7 +307,7 @@ where
} }
}; };
let clipboard = Clipboard::connect(&window); let clipboard = Clipboard::connect(window.clone());
let finish_boot = async move { let finish_boot = async move {
let mut compositor = let mut compositor =