1use raw_window_handle::RawDisplayHandle;
2
3pub struct Clipboard {
8 #[cfg(all(feature = "arboard", not(target_os = "android")))]
9 arboard: Option<arboard::Clipboard>,
10
11 #[cfg(all(
12 any(
13 target_os = "linux",
14 target_os = "dragonfly",
15 target_os = "freebsd",
16 target_os = "netbsd",
17 target_os = "openbsd"
18 ),
19 feature = "smithay-clipboard"
20 ))]
21 smithay: Option<smithay_clipboard::Clipboard>,
22
23 clipboard: String,
25}
26
27impl Clipboard {
28 pub fn new(_raw_display_handle: Option<RawDisplayHandle>) -> Self {
30 Self {
31 #[cfg(all(feature = "arboard", not(target_os = "android")))]
32 arboard: init_arboard(),
33
34 #[cfg(all(
35 any(
36 target_os = "linux",
37 target_os = "dragonfly",
38 target_os = "freebsd",
39 target_os = "netbsd",
40 target_os = "openbsd"
41 ),
42 feature = "smithay-clipboard"
43 ))]
44 smithay: init_smithay_clipboard(_raw_display_handle),
45
46 clipboard: Default::default(),
47 }
48 }
49
50 pub fn get(&mut self) -> Option<String> {
51 #[cfg(all(
52 any(
53 target_os = "linux",
54 target_os = "dragonfly",
55 target_os = "freebsd",
56 target_os = "netbsd",
57 target_os = "openbsd"
58 ),
59 feature = "smithay-clipboard"
60 ))]
61 if let Some(clipboard) = &mut self.smithay {
62 return match clipboard.load() {
63 Ok(text) => Some(text),
64 Err(err) => {
65 log::error!("smithay paste error: {err}");
66 None
67 }
68 };
69 }
70
71 #[cfg(all(feature = "arboard", not(target_os = "android")))]
72 if let Some(clipboard) = &mut self.arboard {
73 return match clipboard.get_text() {
74 Ok(text) => Some(text),
75 Err(err) => {
76 log::error!("arboard paste error: {err}");
77 None
78 }
79 };
80 }
81
82 Some(self.clipboard.clone())
83 }
84
85 pub fn set_text(&mut self, text: String) {
86 #[cfg(all(
87 any(
88 target_os = "linux",
89 target_os = "dragonfly",
90 target_os = "freebsd",
91 target_os = "netbsd",
92 target_os = "openbsd"
93 ),
94 feature = "smithay-clipboard"
95 ))]
96 if let Some(clipboard) = &mut self.smithay {
97 clipboard.store(text);
98 return;
99 }
100
101 #[cfg(all(feature = "arboard", not(target_os = "android")))]
102 if let Some(clipboard) = &mut self.arboard {
103 if let Err(err) = clipboard.set_text(text) {
104 log::error!("arboard copy/cut error: {err}");
105 }
106 return;
107 }
108
109 self.clipboard = text;
110 }
111
112 pub fn set_image(&mut self, image: &egui::ColorImage) {
113 #[cfg(all(feature = "arboard", not(target_os = "android")))]
114 if let Some(clipboard) = &mut self.arboard {
115 if let Err(err) = clipboard.set_image(arboard::ImageData {
116 width: image.width(),
117 height: image.height(),
118 bytes: std::borrow::Cow::Borrowed(bytemuck::cast_slice(&image.pixels)),
119 }) {
120 log::error!("arboard copy/cut error: {err}");
121 }
122 log::debug!("Copied image to clipboard");
123 return;
124 }
125
126 log::error!("Copying images is not supported. Enable the 'clipboard' feature of `egui-winit` to enable it.");
127 _ = image;
128 }
129}
130
131#[cfg(all(feature = "arboard", not(target_os = "android")))]
132fn init_arboard() -> Option<arboard::Clipboard> {
133 profiling::function_scope!();
134
135 log::trace!("Initializing arboard clipboard…");
136 match arboard::Clipboard::new() {
137 Ok(clipboard) => Some(clipboard),
138 Err(err) => {
139 log::warn!("Failed to initialize arboard clipboard: {err}");
140 None
141 }
142 }
143}
144
145#[cfg(all(
146 any(
147 target_os = "linux",
148 target_os = "dragonfly",
149 target_os = "freebsd",
150 target_os = "netbsd",
151 target_os = "openbsd"
152 ),
153 feature = "smithay-clipboard"
154))]
155fn init_smithay_clipboard(
156 raw_display_handle: Option<RawDisplayHandle>,
157) -> Option<smithay_clipboard::Clipboard> {
158 #![allow(clippy::undocumented_unsafe_blocks)]
159
160 profiling::function_scope!();
161
162 if let Some(RawDisplayHandle::Wayland(display)) = raw_display_handle {
163 log::trace!("Initializing smithay clipboard…");
164 #[allow(unsafe_code)]
165 Some(unsafe { smithay_clipboard::Clipboard::new(display.display.as_ptr()) })
166 } else {
167 #[cfg(feature = "wayland")]
168 log::debug!("Cannot init smithay clipboard without a Wayland display handle");
169 #[cfg(not(feature = "wayland"))]
170 log::debug!(
171 "Cannot init smithay clipboard: the 'wayland' feature of 'egui-winit' is not enabled"
172 );
173 None
174 }
175}