1use std::{
4 cell::{Cell, RefCell},
5 future::Future,
6 pin::Pin,
7 ptr,
8 rc::Rc,
9};
10
11use glib::translate::*;
12
13use crate::{ffi, prelude::*, Dialog, DialogFlags, ResponseType, Widget, Window};
14
15impl Dialog {
16 #[doc(alias = "gtk_dialog_new_with_buttons")]
17 #[doc(alias = "new_with_buttons")]
18 #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
19 #[allow(deprecated)]
20 pub fn with_buttons<T: IsA<Window>>(
21 title: impl IntoOptionalGStr,
22 parent: Option<&T>,
23 flags: DialogFlags,
24 buttons: &[(&str, ResponseType)],
25 ) -> Self {
26 assert_initialized_main_thread!();
27 let ret: Self = unsafe {
28 title.run_with_gstr(|title| {
29 Widget::from_glib_none(ffi::gtk_dialog_new_with_buttons(
30 title.to_glib_none().0,
31 parent.map(|p| p.as_ref()).to_glib_none().0,
32 flags.into_glib(),
33 ptr::null_mut(),
34 ))
35 .unsafe_cast()
36 })
37 };
38
39 ret.add_buttons(buttons);
40 ret
41 }
42}
43
44#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
47#[allow(deprecated)]
48pub trait DialogExtManual: IsA<Dialog> + 'static {
49 #[doc(alias = "gtk_dialog_add_buttons")]
50 fn add_buttons(&self, buttons: &[(&str, ResponseType)]) {
51 for &(text, id) in buttons {
52 Self::add_button(self, text, id);
53 }
54 }
55
56 #[doc(alias = "gtk_dialog_get_response_for_widget")]
57 #[doc(alias = "get_response_for_widget")]
58 fn response_for_widget<P: IsA<Widget>>(&self, widget: &P) -> ResponseType {
59 unsafe {
60 from_glib(ffi::gtk_dialog_get_response_for_widget(
61 AsRef::<Dialog>::as_ref(self).to_glib_none().0,
62 widget.as_ref().to_glib_none().0,
63 ))
64 }
65 }
66
67 fn run_future<'a>(&'a self) -> Pin<Box<dyn Future<Output = ResponseType> + 'a>> {
86 Box::pin(async move {
87 let (sender, receiver) = futures_channel::oneshot::channel();
88
89 let sender = Cell::new(Some(sender));
90
91 let response_handler = self.connect_response(move |_, response_type| {
92 if let Some(m) = sender.replace(None) {
93 let _result = m.send(response_type);
94 }
95 });
96
97 self.as_ref().present();
98
99 if let Ok(response) = receiver.await {
100 self.disconnect(response_handler);
101 response
102 } else {
103 ResponseType::None
104 }
105 })
106 }
107
108 fn run_async<F: FnOnce(&Self, ResponseType) + 'static>(&self, f: F) {
128 let response_handler = Rc::new(RefCell::new(None));
129 let response_handler_clone = response_handler.clone();
130 let f = RefCell::new(Some(f));
131 *response_handler.borrow_mut() = Some(self.connect_response(move |s, response_type| {
132 if let Some(handler) = response_handler_clone.borrow_mut().take() {
133 s.disconnect(handler);
134 }
135 (*f.borrow_mut()).take().expect("cannot get callback")(s, response_type);
136 }));
137 self.as_ref().present();
138 }
139}
140
141impl<O: IsA<Dialog>> DialogExtManual for O {}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate as gtk4;
147
148 #[test]
149 async fn dialog_future() {
150 let dialog = Dialog::new();
151 glib::idle_add_local_once(glib::clone!(
152 #[strong]
153 dialog,
154 move || {
155 dialog.response(ResponseType::Ok);
156 }
157 ));
158 let response = dialog.run_future().await;
159 assert_eq!(response, ResponseType::Ok);
160 }
161}