gdk4/
clipboard.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{future, pin::Pin, ptr};
4
5use glib::{translate::*, GString};
6
7use crate::{ffi, prelude::*, Clipboard};
8
9impl Clipboard {
10    /// Asynchronously requests an input stream to read the @self's
11    /// contents from.
12    ///
13    /// The clipboard will choose the most suitable mime type from the given list
14    /// to fulfill the request, preferring the ones listed first.
15    /// ## `mime_types`
16    /// a [`None`]-terminated array of mime types to choose from
17    /// ## `io_priority`
18    /// the I/O priority of the request
19    /// ## `cancellable`
20    /// optional `GCancellable` object
21    /// ## `callback`
22    /// callback to call when the request is satisfied
23    #[doc(alias = "gdk_clipboard_read_async")]
24    pub fn read_async<Q: FnOnce(Result<(gio::InputStream, GString), glib::Error>) + 'static>(
25        &self,
26        mime_types: &[&str],
27        io_priority: glib::Priority,
28        cancellable: Option<&impl IsA<gio::Cancellable>>,
29        callback: Q,
30    ) {
31        let main_context = glib::MainContext::ref_thread_default();
32        let is_main_context_owner = main_context.is_owner();
33        let has_acquired_main_context = (!is_main_context_owner)
34            .then(|| main_context.acquire().ok())
35            .flatten();
36        assert!(
37            is_main_context_owner || has_acquired_main_context.is_some(),
38            "Async operations only allowed if the thread is owning the MainContext"
39        );
40
41        let user_data: Box<glib::thread_guard::ThreadGuard<Q>> =
42            Box::new(glib::thread_guard::ThreadGuard::new(callback));
43        unsafe extern "C" fn read_async_trampoline<
44            Q: FnOnce(Result<(gio::InputStream, GString), glib::Error>) + 'static,
45        >(
46            _source_object: *mut glib::gobject_ffi::GObject,
47            res: *mut gio::ffi::GAsyncResult,
48            user_data: glib::ffi::gpointer,
49        ) {
50            let mut error = ptr::null_mut();
51            let mut out_mime_type = ptr::null();
52            let ret = ffi::gdk_clipboard_read_finish(
53                _source_object as *mut _,
54                res,
55                &mut out_mime_type,
56                &mut error,
57            );
58            let result = if error.is_null() {
59                Ok((from_glib_full(ret), from_glib_none(out_mime_type)))
60            } else {
61                Err(from_glib_full(error))
62            };
63            let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
64                Box::from_raw(user_data as *mut _);
65            let callback = callback.into_inner();
66            callback(result);
67        }
68        let callback = read_async_trampoline::<Q>;
69        unsafe {
70            ffi::gdk_clipboard_read_async(
71                self.to_glib_none().0,
72                mime_types.to_glib_none().0,
73                io_priority.into_glib(),
74                cancellable.map(|p| p.as_ref()).to_glib_none().0,
75                Some(callback),
76                Box::into_raw(user_data) as *mut _,
77            );
78        }
79    }
80
81    #[allow(clippy::type_complexity)]
82    pub fn read_future(
83        &self,
84        mime_types: &[&str],
85        io_priority: glib::Priority,
86    ) -> Pin<
87        Box<
88            dyn future::Future<Output = Result<(gio::InputStream, GString), glib::Error>> + 'static,
89        >,
90    > {
91        let mime_types = mime_types
92            .iter()
93            .copied()
94            .map(String::from)
95            .collect::<Vec<_>>();
96        Box::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
97            let mime_types = mime_types.iter().map(|s| s.as_str()).collect::<Vec<_>>();
98            obj.read_async(&mime_types, io_priority, Some(cancellable), move |res| {
99                send.resolve(res);
100            });
101        }))
102    }
103
104    /// Sets the clipboard to contain the value collected from the given varargs.
105    ///
106    /// Values should be passed the same way they are passed to other value
107    /// collecting APIs, such as `GObject::Object::set()` or
108    /// `signal_emit()`.
109    ///
110    /// **⚠️ The following code is in c ⚠️**
111    ///
112    /// ```c
113    /// gdk_clipboard_set (clipboard, GTK_TYPE_STRING, "Hello World");
114    ///
115    /// gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, some_texture);
116    /// ```
117    /// ## `type_`
118    /// type of value to set
119    #[doc(alias = "gdk_clipboard_set")]
120    #[doc(alias = "gdk_clipboard_set_value")]
121    #[doc(alias = "gdk_clipboard_set_valist")]
122    #[doc(alias = "set_value")]
123    #[doc(alias = "set_valist")]
124    pub fn set(&self, value: &impl ToValue) {
125        unsafe {
126            ffi::gdk_clipboard_set_value(self.to_glib_none().0, value.to_value().to_glib_none().0);
127        }
128    }
129}