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 = unsafe { window_clipboard::Clipboard::connect(&window) };
35
36        let state = match clipboard {
37            Ok(clipboard) => State::Connected { clipboard, window },
38            Err(_) => State::Unavailable,
39        };
40
41        Clipboard { state }
42    }
43
44    /// Creates a new [`Clipboard`] that isn't associated with a window.
45    /// This clipboard will never contain a copied value.
46    pub fn unconnected() -> Clipboard {
47        Clipboard {
48            state: State::Unavailable,
49        }
50    }
51
52    /// Reads the current content of the [`Clipboard`] as text.
53    pub fn read(&self, kind: Kind) -> Option<String> {
54        match &self.state {
55            State::Connected { clipboard, .. } => match kind {
56                Kind::Standard => clipboard.read().ok(),
57                Kind::Primary => clipboard.read_primary().and_then(Result::ok),
58            },
59            State::Unavailable => None,
60        }
61    }
62
63    /// Writes the given text contents to the [`Clipboard`].
64    pub fn write(&mut self, kind: Kind, contents: String) {
65        match &mut self.state {
66            State::Connected { clipboard, .. } => {
67                let result = match kind {
68                    Kind::Standard => clipboard.write(contents),
69                    Kind::Primary => clipboard.write_primary(contents).unwrap_or(Ok(())),
70                };
71
72                match result {
73                    Ok(()) => {}
74                    Err(error) => {
75                        log::warn!("error writing to clipboard: {error}");
76                    }
77                }
78            }
79            State::Unavailable => {}
80        }
81    }
82
83    /// Returns the identifier of the window used to create the [`Clipboard`], if any.
84    pub fn window_id(&self) -> Option<WindowId> {
85        match &self.state {
86            State::Connected { window, .. } => Some(window.id()),
87            State::Unavailable => None,
88        }
89    }
90}
91
92impl crate::core::Clipboard for Clipboard {
93    fn read(&self, kind: Kind) -> Option<String> {
94        self.read(kind)
95    }
96
97    fn write(&mut self, kind: Kind, contents: String) {
98        self.write(kind, contents);
99    }
100}