gtk4/native_dialog.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4 cell::{Cell, RefCell},
5 future::Future,
6 pin::Pin,
7 rc::Rc,
8};
9
10use crate::{prelude::*, NativeDialog, ResponseType};
11
12mod sealed {
13 pub trait Sealed {}
14 impl<T: super::IsA<super::NativeDialog>> Sealed for T {}
15}
16
17// rustdoc-stripper-ignore-next
18/// Trait containing manually implemented methods of
19/// [`NativeDialog`](crate::NativeDialog).
20#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
21#[allow(deprecated)]
22pub trait NativeDialogExtManual: sealed::Sealed + IsA<NativeDialog> {
23 // rustdoc-stripper-ignore-next
24 /// Shows the dialog and returns a `Future` that resolves to the
25 /// `ResponseType` on response.
26 ///
27 /// ```no_run
28 /// # use gtk4 as gtk;
29 /// use gtk::prelude::*;
30 ///
31 /// # async fn run() {
32 /// let dialog = gtk::FileChooserNative::builder()
33 /// .title("Select a File")
34 /// .build();
35 ///
36 /// dialog.run_future().await;
37 /// println!("Selected file: {:?}", dialog.file());
38 /// dialog.destroy();
39 /// # }
40 /// ```
41 fn run_future<'a>(&'a self) -> Pin<Box<dyn Future<Output = ResponseType> + 'a>> {
42 Box::pin(async move {
43 let (sender, receiver) = futures_channel::oneshot::channel();
44
45 let sender = Cell::new(Some(sender));
46
47 let response_handler = self.connect_response(move |_, response_type| {
48 if let Some(m) = sender.replace(None) {
49 let _result = m.send(response_type);
50 }
51 });
52
53 self.show();
54
55 if let Ok(response) = receiver.await {
56 self.disconnect(response_handler);
57 response
58 } else {
59 ResponseType::None
60 }
61 })
62 }
63
64 // rustdoc-stripper-ignore-next
65 /// Shows the dialog and calls the callback when a response has been
66 /// received.
67 ///
68 /// **Important**: this function isn't blocking.
69 ///
70 /// ```no_run
71 /// # use gtk4 as gtk;
72 /// use gtk::prelude::*;
73 ///
74 /// let dialog = gtk::FileChooserNative::builder()
75 /// .title("Select a File")
76 /// .build();
77 ///
78 /// dialog.run_async(move |obj, answer| {
79 /// obj.destroy();
80 /// println!("Selected file: {:?}", obj.file());
81 /// });
82 /// ```
83 fn run_async<F: FnOnce(&Self, ResponseType) + 'static>(&self, f: F) {
84 let response_handler = Rc::new(RefCell::new(None));
85 let response_handler_clone = response_handler.clone();
86 let f = RefCell::new(Some(f));
87 *response_handler.borrow_mut() = Some(self.connect_response(move |s, response_type| {
88 if let Some(handler) = response_handler_clone.borrow_mut().take() {
89 s.disconnect(handler);
90 }
91 (*f.borrow_mut()).take().expect("cannot get callback")(s, response_type);
92 }));
93 self.show();
94 }
95}
96
97impl<O: IsA<NativeDialog>> NativeDialogExtManual for O {}