1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Take a look at the license at the top of the repository in the LICENSE file.

use std::{future, pin::Pin, ptr};

use glib::{translate::*, GString};

use crate::{prelude::*, Clipboard};

impl Clipboard {
    /// Asynchronously requests an input stream to read the @self's
    /// contents from.
    ///
    /// When the operation is finished @callback will be called. You must then
    /// call `Gdk::Clipboard::read_finish()` to get the result of the operation.
    ///
    /// The clipboard will choose the most suitable mime type from the given list
    /// to fulfill the request, preferring the ones listed first.
    /// ## `mime_types`
    /// a [`None`]-terminated array of mime types to choose from
    /// ## `io_priority`
    /// the I/O priority of the request
    /// ## `cancellable`
    /// optional `GCancellable` object
    /// ## `callback`
    /// callback to call when the request is satisfied
    #[doc(alias = "gdk_clipboard_read_async")]
    pub fn read_async<Q: FnOnce(Result<(gio::InputStream, GString), glib::Error>) + 'static>(
        &self,
        mime_types: &[&str],
        io_priority: glib::Priority,
        cancellable: Option<&impl IsA<gio::Cancellable>>,
        callback: Q,
    ) {
        let main_context = glib::MainContext::ref_thread_default();
        let is_main_context_owner = main_context.is_owner();
        let has_acquired_main_context = (!is_main_context_owner)
            .then(|| main_context.acquire().ok())
            .flatten();
        assert!(
            is_main_context_owner || has_acquired_main_context.is_some(),
            "Async operations only allowed if the thread is owning the MainContext"
        );

        let user_data: Box<glib::thread_guard::ThreadGuard<Q>> =
            Box::new(glib::thread_guard::ThreadGuard::new(callback));
        unsafe extern "C" fn read_async_trampoline<
            Q: FnOnce(Result<(gio::InputStream, GString), glib::Error>) + 'static,
        >(
            _source_object: *mut glib::gobject_ffi::GObject,
            res: *mut gio::ffi::GAsyncResult,
            user_data: glib::ffi::gpointer,
        ) {
            let mut error = ptr::null_mut();
            let mut out_mime_type = ptr::null();
            let ret = ffi::gdk_clipboard_read_finish(
                _source_object as *mut _,
                res,
                &mut out_mime_type,
                &mut error,
            );
            let result = if error.is_null() {
                Ok((from_glib_full(ret), from_glib_none(out_mime_type)))
            } else {
                Err(from_glib_full(error))
            };
            let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
                Box::from_raw(user_data as *mut _);
            let callback = callback.into_inner();
            callback(result);
        }
        let callback = read_async_trampoline::<Q>;
        unsafe {
            ffi::gdk_clipboard_read_async(
                self.to_glib_none().0,
                mime_types.to_glib_none().0,
                io_priority.into_glib(),
                cancellable.map(|p| p.as_ref()).to_glib_none().0,
                Some(callback),
                Box::into_raw(user_data) as *mut _,
            );
        }
    }

    #[allow(clippy::type_complexity)]
    pub fn read_future(
        &self,
        mime_types: &[&str],
        io_priority: glib::Priority,
    ) -> Pin<
        Box<
            dyn future::Future<Output = Result<(gio::InputStream, GString), glib::Error>> + 'static,
        >,
    > {
        let mime_types = mime_types
            .iter()
            .copied()
            .map(String::from)
            .collect::<Vec<_>>();
        Box::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
            let mime_types = mime_types.iter().map(|s| s.as_str()).collect::<Vec<_>>();
            obj.read_async(&mime_types, io_priority, Some(cancellable), move |res| {
                send.resolve(res);
            });
        }))
    }

    /// Sets the clipboard to contain the value collected from the given varargs.
    ///
    /// Values should be passed the same way they are passed to other value
    /// collecting APIs, such as `GObject::Object::set()` or
    /// `signal_emit()`.
    ///
    /// **⚠️ The following code is in c ⚠️**
    ///
    /// ```c
    /// gdk_clipboard_set (clipboard, GTK_TYPE_STRING, "Hello World");
    ///
    /// gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, some_texture);
    /// ```
    /// ## `type_`
    /// type of value to set
    #[doc(alias = "gdk_clipboard_set")]
    #[doc(alias = "gdk_clipboard_set_value")]
    #[doc(alias = "gdk_clipboard_set_valist")]
    #[doc(alias = "set_value")]
    #[doc(alias = "set_valist")]
    pub fn set(&self, value: &impl ToValue) {
        unsafe {
            ffi::gdk_clipboard_set_value(self.to_glib_none().0, value.to_value().to_glib_none().0);
        }
    }
}