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