i_slint_backend_winit/
clipboard.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use copypasta::ClipboardProvider;
5
6/// The Default, and the selection clippoard
7pub type ClipboardPair = (Box<dyn ClipboardProvider>, Box<dyn ClipboardProvider>);
8
9pub fn select_clipboard(
10    pair: &mut ClipboardPair,
11    clipboard: i_slint_core::platform::Clipboard,
12) -> Option<&mut dyn ClipboardProvider> {
13    match clipboard {
14        i_slint_core::platform::Clipboard::DefaultClipboard => Some(pair.0.as_mut()),
15        i_slint_core::platform::Clipboard::SelectionClipboard => Some(pair.1.as_mut()),
16        _ => None,
17    }
18}
19
20pub fn create_clipboard(
21    _display_handle: &winit::raw_window_handle::DisplayHandle<'_>,
22) -> ClipboardPair {
23    // Provide a truly silent no-op clipboard context, as copypasta's NoopClipboard spams stdout with
24    // println.
25    struct SilentClipboardContext;
26    impl ClipboardProvider for SilentClipboardContext {
27        fn get_contents(
28            &mut self,
29        ) -> Result<String, Box<dyn std::error::Error + Send + Sync + 'static>> {
30            Ok(Default::default())
31        }
32
33        fn set_contents(
34            &mut self,
35            _: String,
36        ) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
37            Ok(())
38        }
39    }
40
41    cfg_if::cfg_if! {
42        if #[cfg(all(
43            unix,
44            not(any(
45                target_vendor = "apple",
46                target_os = "android",
47                target_os = "emscripten"
48            ))
49        ))]
50        {
51
52            #[cfg(feature = "wayland")]
53            if let raw_window_handle::RawDisplayHandle::Wayland(wayland) = _display_handle.as_raw() {
54                let clipboard = unsafe { copypasta::wayland_clipboard::create_clipboards_from_external(wayland.display.as_ptr()) };
55                return (Box::new(clipboard.1), Box::new(clipboard.0));
56            };
57            #[cfg(feature = "x11")]
58            {
59                use copypasta::x11_clipboard::{X11ClipboardContext, Primary, Clipboard};
60                let prim = X11ClipboardContext::<Primary>::new()
61                    .map_or(
62                        Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,
63                        |x| Box::new(x) as Box<dyn ClipboardProvider>,
64                    );
65                let sec = X11ClipboardContext::<Clipboard>::new()
66                    .map_or(
67                        Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,
68                        |x| Box::new(x) as Box<dyn ClipboardProvider>,
69                    );
70                (sec, prim)
71            }
72            #[cfg(not(feature = "x11"))]
73            (Box::new(SilentClipboardContext), Box::new(SilentClipboardContext))
74        } else {
75            (
76                copypasta::ClipboardContext::new().map_or(
77                    Box::new(SilentClipboardContext) as Box<dyn ClipboardProvider>,
78                    |x| Box::new(x) as Box<dyn ClipboardProvider>,
79                ),
80                Box::new(SilentClipboardContext),
81            )
82        }
83    }
84}