Skip to main content

iced_runtime/
clipboard.rs

1//! Access the clipboard.
2use crate::core::clipboard::{Content, Error, Kind};
3use crate::futures::futures::channel::oneshot;
4use crate::task::{self, Task};
5
6use std::path::PathBuf;
7use std::sync::Arc;
8
9/// A clipboard action to be performed by some [`Task`].
10///
11/// [`Task`]: crate::Task
12#[derive(Debug)]
13pub enum Action {
14    /// Read the clipboard and produce `T` with the result.
15    Read {
16        /// The [`Kind`] of [`Content`] to read.
17        kind: Kind,
18        /// The channel to send the read contents.
19        channel: oneshot::Sender<Result<Content, Error>>,
20    },
21
22    /// Write the given contents to the clipboard.
23    Write {
24        /// The [`Content`] to be written.
25        content: Content,
26
27        /// The channel to send the write result.
28        channel: oneshot::Sender<Result<(), Error>>,
29    },
30
31    /// Read the primary selection and produce `T` with the result.
32    ReadPrimary {
33        /// The channel to send the read text.
34        channel: oneshot::Sender<Result<String, Error>>,
35    },
36
37    /// Publish the given text as the primary selection.
38    WritePrimary {
39        /// The text to publish.
40        text: String,
41
42        /// The channel to send the write result.
43        channel: oneshot::Sender<Result<(), Error>>,
44    },
45}
46
47/// Read the primary selection.
48///
49/// The primary selection is the X11 and Wayland convention where selecting
50/// text makes it available for a middle-click paste, without disturbing the
51/// clipboard the user last copied to deliberately. It is text-only, so unlike
52/// [`read`] there is no [`Kind`] to choose.
53///
54/// On platforms without a primary selection this yields
55/// [`Error::ContentNotAvailable`].
56pub fn read_primary() -> Task<Result<Arc<String>, Error>> {
57    task::oneshot(|channel| crate::Action::Clipboard(Action::ReadPrimary { channel }))
58        .map(|result| result.map(Arc::new))
59}
60
61/// Publish the given text as the primary selection.
62///
63/// Does not touch the clipboard: the two are separate selections, and
64/// copy-on-select must not overwrite what the user last copied.
65pub fn write_primary(text: impl Into<String>) -> Task<Result<(), Error>> {
66    let text = text.into();
67
68    task::oneshot(|channel| crate::Action::Clipboard(Action::WritePrimary { text, channel }))
69}
70
71/// Read the given [`Kind`] of [`Content`] from the clipboard.
72pub fn read(kind: Kind) -> Task<Result<Arc<Content>, Error>> {
73    task::oneshot(|channel| crate::Action::Clipboard(Action::Read { kind, channel }))
74        .map(|result| result.map(Arc::new))
75}
76
77/// Read the current text contents of the clipboard.
78pub fn read_text() -> Task<Result<Arc<String>, Error>> {
79    task::oneshot(|channel| {
80        crate::Action::Clipboard(Action::Read {
81            kind: Kind::Text,
82            channel,
83        })
84    })
85    .map(|result| {
86        let Ok(Content::Text(text)) = result else {
87            return Err(Error::ContentNotAvailable);
88        };
89
90        Ok(Arc::new(text))
91    })
92}
93
94/// Read the current HTML contents of the clipboard.
95pub fn read_html() -> Task<Result<Arc<String>, Error>> {
96    task::oneshot(|channel| {
97        crate::Action::Clipboard(Action::Read {
98            kind: Kind::Html,
99            channel,
100        })
101    })
102    .map(|result| {
103        let Ok(Content::Html(html)) = result else {
104            return Err(Error::ContentNotAvailable);
105        };
106
107        Ok(Arc::new(html))
108    })
109}
110
111/// Read the current file paths of the clipboard.
112pub fn read_files() -> Task<Result<Arc<[PathBuf]>, Error>> {
113    task::oneshot(|channel| {
114        crate::Action::Clipboard(Action::Read {
115            kind: Kind::Files,
116            channel,
117        })
118    })
119    .map(|result| {
120        let Ok(Content::Files(files)) = result else {
121            return Err(Error::ContentNotAvailable);
122        };
123
124        Ok(Arc::from(files))
125    })
126}
127
128/// Read the current [`Image`](crate::core::clipboard::Image) of the clipboard.
129#[cfg(feature = "image")]
130pub fn read_image() -> Task<Result<crate::core::clipboard::Image, Error>> {
131    task::oneshot(|channel| {
132        crate::Action::Clipboard(Action::Read {
133            kind: Kind::Image,
134            channel,
135        })
136    })
137    .map(|result| {
138        let Ok(Content::Image(image)) = result else {
139            return Err(Error::ContentNotAvailable);
140        };
141
142        Ok(image)
143    })
144}
145
146/// Write the given [`Content`] to the clipboard.
147pub fn write(content: impl Into<Content>) -> Task<Result<(), Error>> {
148    let content = content.into();
149
150    task::oneshot(|channel| crate::Action::Clipboard(Action::Write { content, channel }))
151}