Skip to main content

gtk/
native_dialog.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::prelude::*;
4use crate::NativeDialog;
5use crate::ResponseType;
6use std::cell::Cell;
7use std::future::Future;
8use std::pin::Pin;
9
10pub trait NativeDialogExtManual: IsA<NativeDialog> {
11    // rustdoc-stripper-ignore-next
12    /// Shows the dialog and returns a `Future` that resolves to the
13    /// `ResponseType` on response.
14    ///
15    /// ```no_run
16    /// use gtk::prelude::*;
17    ///
18    /// # async fn run() {
19    /// let dialog = gtk::FileChooserNative::builder()
20    ///    .title("Select a File")
21    ///    .build();
22    ///
23    /// dialog.run_future().await;
24    /// println!("Selected file: {:?}", dialog.file());
25    /// dialog.destroy();
26    /// # }
27    /// ```
28    fn run_future<'a>(&'a self) -> Pin<Box<dyn Future<Output = ResponseType> + 'a>> {
29        Box::pin(async move {
30            let (sender, receiver) = futures_channel::oneshot::channel();
31
32            let sender = Cell::new(Some(sender));
33
34            let response_handler = self.connect_response(move |_, response_type| {
35                if let Some(m) = sender.replace(None) {
36                    let _result = m.send(response_type);
37                }
38            });
39
40            self.show();
41
42            if let Ok(response) = receiver.await {
43                if response != ResponseType::DeleteEvent {
44                    self.disconnect(response_handler);
45                }
46                response
47            } else {
48                ResponseType::None
49            }
50        })
51    }
52}
53
54impl<O: IsA<NativeDialog>> NativeDialogExtManual for O {}