libadwaita/
alert_dialog.rs

1use glib::object::IsA;
2use glib::translate::*;
3
4use crate::prelude::*;
5use crate::AlertDialog;
6
7use std::boxed::Box as Box_;
8use std::pin::Pin;
9
10mod sealed {
11    pub trait Sealed {}
12    impl<T: super::IsA<super::AlertDialog>> Sealed for T {}
13}
14
15pub trait AlertDialogExtManual: sealed::Sealed + IsA<AlertDialog> + 'static {
16    /// Gets the label of @response.
17    ///
18    /// See [`AlertDialogExt::set_response_label()`][crate::prelude::AlertDialogExt::set_response_label()].
19    /// ## `response`
20    /// a response ID
21    ///
22    /// # Returns
23    ///
24    /// the label of @response
25    #[doc(alias = "adw_alert_dialog_get_response_label")]
26    #[doc(alias = "get_response_label")]
27    fn response_label(&self, response: &str) -> glib::GString {
28        assert!(self.as_ref().has_response(response));
29
30        unsafe {
31            from_glib_none(ffi::adw_alert_dialog_get_response_label(
32                self.as_ref().to_glib_none().0,
33                response.to_glib_none().0,
34            ))
35        }
36    }
37
38    /// Adds multiple responses to @self.
39    ///
40    /// This is the same as calling [`AlertDialogExt::add_response()`][crate::prelude::AlertDialogExt::add_response()] repeatedly. The
41    /// variable argument list should be `NULL`-terminated list of response IDs and
42    /// labels.
43    ///
44    /// Example:
45    ///
46    /// **⚠️ The following code is in c ⚠️**
47    ///
48    /// ```c
49    /// adw_alert_dialog_add_responses (dialog,
50    ///                                 "cancel",  _("_Cancel"),
51    ///                                 "discard", _("_Discard"),
52    ///                                 "save",    _("_Save"),
53    ///                                 NULL);
54    /// ```
55    /// ## `first_id`
56    /// response id
57    #[doc(alias = "adw_alert_dialog_add_responses")]
58    fn add_responses(&self, ids_and_labels: &[(&str, &str)]) {
59        ids_and_labels.iter().for_each(|(id, label)| {
60            self.add_response(id, label);
61        });
62    }
63
64    /// This function shows @self to the user.
65    ///
66    /// If the window is an [`Window`][crate::Window] or [`ApplicationWindow`][crate::ApplicationWindow], the dialog
67    /// will be shown within it. Otherwise, it will be a separate window.
68    /// ## `parent`
69    /// the parent widget
70    /// ## `cancellable`
71    /// a `GCancellable` to cancel the operation
72    /// ## `callback`
73    /// a callback to call when the operation is complete
74    #[doc(alias = "adw_alert_dialog_choose")]
75    fn choose<P: FnOnce(glib::GString) + 'static>(
76        self,
77        parent: Option<&impl IsA<gtk::Widget>>,
78        cancellable: Option<&impl IsA<gio::Cancellable>>,
79        callback: P,
80    ) {
81        let main_context = glib::MainContext::ref_thread_default();
82        let is_main_context_owner = main_context.is_owner();
83        let has_acquired_main_context = (!is_main_context_owner)
84            .then(|| main_context.acquire().ok())
85            .flatten();
86        assert!(
87            is_main_context_owner || has_acquired_main_context.is_some(),
88            "Async operations only allowed if the thread is owning the MainContext"
89        );
90
91        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
92            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
93        unsafe extern "C" fn choose_trampoline<P: FnOnce(glib::GString) + 'static>(
94            _source_object: *mut glib::gobject_ffi::GObject,
95            res: *mut gio::ffi::GAsyncResult,
96            user_data: glib::ffi::gpointer,
97        ) {
98            unsafe {
99                let result = from_glib_none(ffi::adw_alert_dialog_choose_finish(
100                    _source_object as *mut _,
101                    res,
102                ));
103                let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
104                    Box_::from_raw(user_data as *mut _);
105                let callback: P = callback.into_inner();
106                callback(result);
107            }
108        }
109        let callback = choose_trampoline::<P>;
110        unsafe {
111            ffi::adw_alert_dialog_choose(
112                self.upcast().into_glib_ptr(),
113                parent.map(|p| p.as_ref()).to_glib_none().0,
114                cancellable.map(|p| p.as_ref()).to_glib_none().0,
115                Some(callback),
116                Box_::into_raw(user_data) as *mut _,
117            );
118        }
119    }
120
121    fn choose_future(
122        self,
123        parent: Option<&impl IsA<gtk::Widget>>,
124    ) -> Pin<Box_<dyn std::future::Future<Output = glib::GString> + 'static>> {
125        let parent = parent.map(ToOwned::to_owned);
126        Box_::pin(gio::GioFuture::new(
127            &self,
128            move |obj: &Self, cancellable, send| {
129                obj.clone().choose(
130                    parent.as_ref().map(::std::borrow::Borrow::borrow),
131                    Some(cancellable),
132                    move |res| {
133                        send.resolve(res);
134                    },
135                );
136            },
137        ))
138    }
139}
140
141impl<O: IsA<AlertDialog>> AlertDialogExtManual for O {}