iced_winit/
clipboard.rs

1//! Access the clipboard.
2
3use crate::core::clipboard::Kind;
4use std::sync::Arc;
5use winit::window::{Window, WindowId};
6
7/// A buffer for short-term storage and transfer within and between
8/// applications.
9pub struct Clipboard {
10    state: State,
11}
12
13enum State {
14    Connected {
15        clipboard: window_clipboard::Clipboard,
16        // Held until drop to satisfy the safety invariants of
17        // `window_clipboard::Clipboard`.
18        //
19        // Note that the field ordering is load-bearing.
20        #[allow(dead_code)]
21        window: Arc<Window>,
22    },
23    Unavailable,
24}
25
26impl Clipboard {
27    /// Creates a new [`Clipboard`] for the given window.
28    pub fn connect(window: Arc<Window>) -> Clipboard {
29        // SAFETY: The window handle will stay alive throughout the entire
30        // lifetime of the `window_clipboard::Clipboard` because we hold
31        // the `Arc<Window>` together with `State`, and enum variant fields
32        // get dropped in declaration order.
33        #[allow(unsafe_code)]
34        let clipboard =
35            unsafe { window_clipboard::Clipboard::connect(&window) };
36
37        let state = match clipboard {
38            Ok(clipboard) => State::Connected { clipboard, window },
39            Err(_) => State::Unavailable,
40        };
41
42        Clipboard { state }
43    }
44
45    /// Creates a new [`Clipboard`] that isn't associated with a window.
46    /// This clipboard will never contain a copied value.
47    pub fn unconnected() -> Clipboard {
48        Clipboard {
49            state: State::Unavailable,
50        }
51    }
52
53    /// Reads the current content of the [`Clipboard`] as text.
54    pub fn read(&self, kind: Kind) -> Option<String> {
55        match &self.state {
56            State::Connected { clipboard, .. } => match kind {
57                Kind::Standard => clipboard.read().ok(),
58                Kind::Primary => clipboard.read_primary().and_then(Result::ok),
59            },
60            State::Unavailable => None,
61        }
62    }
63
64    /// Writes the given text contents to the [`Clipboard`].
65    pub fn write(&mut self, kind: Kind, contents: String) {
66        match &mut self.state {
67            State::Connected { clipboard, .. } => {
68                let result = match kind {
69                    Kind::Standard => clipboard.write(contents),
70                    Kind::Primary => {
71                        clipboard.write_primary(contents).unwrap_or(Ok(()))
72                    }
73                };
74
75                match result {
76                    Ok(()) => {}
77                    Err(error) => {
78                        log::warn!("error writing to clipboard: {error}");
79                    }
80                }
81            }
82            State::Unavailable => {}
83        }
84    }
85
86    /// Returns the identifier of the window used to create the [`Clipboard`], if any.
87    pub fn window_id(&self) -> Option<WindowId> {
88        match &self.state {
89            State::Connected { window, .. } => Some(window.id()),
90            State::Unavailable => None,
91        }
92    }
93}
94
95impl crate::core::Clipboard for Clipboard {
96    fn read(&self, kind: Kind) -> Option<String> {
97        self.read(kind)
98    }
99
100    fn write(&mut self, kind: Kind, contents: String) {
101        self.write(kind, contents);
102    }
103}