Skip to main content

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::{GString, translate::*};
6
7use crate::{Clipboard, ffi, prelude::*};
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            unsafe {
51                let mut error = ptr::null_mut();
52                let mut out_mime_type = ptr::null();
53                let ret = ffi::gdk_clipboard_read_finish(
54                    _source_object as *mut _,
55                    res,
56                    &mut out_mime_type,
57                    &mut error,
58                );
59                let result = if error.is_null() {
60                    Ok((from_glib_full(ret), from_glib_none(out_mime_type)))
61                } else {
62                    Err(from_glib_full(error))
63                };
64                let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
65                    Box::from_raw(user_data as *mut _);
66                let callback = callback.into_inner();
67                callback(result);
68            }
69        }
70        let callback = read_async_trampoline::<Q>;
71        unsafe {
72            ffi::gdk_clipboard_read_async(
73                self.to_glib_none().0,
74                mime_types.to_glib_none().0,
75                io_priority.into_glib(),
76                cancellable.map(|p| p.as_ref()).to_glib_none().0,
77                Some(callback),
78                Box::into_raw(user_data) as *mut _,
79            );
80        }
81    }
82
83    #[allow(clippy::type_complexity)]
84    pub fn read_future(
85        &self,
86        mime_types: &[&str],
87        io_priority: glib::Priority,
88    ) -> Pin<
89        Box<
90            dyn future::Future<Output = Result<(gio::InputStream, GString), glib::Error>> + 'static,
91        >,
92    > {
93        let mime_types = mime_types
94            .iter()
95            .copied()
96            .map(String::from)
97            .collect::<Vec<_>>();
98        Box::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
99            let mime_types = mime_types.iter().map(|s| s.as_str()).collect::<Vec<_>>();
100            obj.read_async(&mime_types, io_priority, Some(cancellable), move |res| {
101                send.resolve(res);
102            });
103        }))
104    }
105
106    /// Sets the clipboard to contain the value collected from the given varargs.
107    ///
108    /// Values should be passed the same way they are passed to other value
109    /// collecting APIs, such as `GObject::Object::set()` or
110    /// `signal_emit()`.
111    ///
112    /// **⚠️ The following code is in c ⚠️**
113    ///
114    /// ```c
115    /// gdk_clipboard_set (clipboard, G_TYPE_STRING, "Hello World");
116    ///
117    /// gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, some_texture);
118    /// ```
119    /// ## `type_`
120    /// type of value to set
121    #[doc(alias = "gdk_clipboard_set")]
122    #[doc(alias = "gdk_clipboard_set_value")]
123    #[doc(alias = "gdk_clipboard_set_valist")]
124    #[doc(alias = "set_value")]
125    #[doc(alias = "set_valist")]
126    pub fn set(&self, value: &impl ToValue) {
127        unsafe {
128            ffi::gdk_clipboard_set_value(self.to_glib_none().0, value.to_value().to_glib_none().0);
129        }
130    }
131}