gtk4/auto/
file_dialog.rs

1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{ffi, FileFilter, Window};
6use glib::{
7    prelude::*,
8    signal::{connect_raw, SignalHandlerId},
9    translate::*,
10};
11use std::{boxed::Box as Box_, pin::Pin};
12
13glib::wrapper! {
14    /// Collects the arguments that are needed to present a file chooser
15    /// dialog to the user, such as a title for the dialog and whether it
16    /// should be modal.
17    ///
18    /// The dialog is shown with [`open()`][Self::open()],
19    /// [`save()`][Self::save()], etc.
20    ///
21    /// ## Properties
22    ///
23    ///
24    /// #### `accept-label`
25    ///  Label for the file chooser's accept button.
26    ///
27    /// Readable | Writeable
28    ///
29    ///
30    /// #### `default-filter`
31    ///  The default filter.
32    ///
33    /// This filter is initially active in the file chooser dialog.
34    ///
35    /// If the default filter is `NULL`, the first filter of [`filters`][struct@crate::FileDialog#filters]
36    /// is used as the default filter. If that property contains no filter, the dialog will
37    /// be unfiltered.
38    ///
39    /// If [`filters`][struct@crate::FileDialog#filters] is not `NULL`, the default filter should be
40    /// part of the list. If it is not, the dialog may choose to not make it available.
41    ///
42    /// Readable | Writeable
43    ///
44    ///
45    /// #### `filters`
46    ///  The list of filters.
47    ///
48    /// See [`default-filter`][struct@crate::FileDialog#default-filter] about how these
49    /// two properties interact.
50    ///
51    /// Readable | Writeable
52    ///
53    ///
54    /// #### `initial-file`
55    ///  The initial file.
56    ///
57    /// This file is initially selected in the file chooser dialog
58    ///
59    /// This is a utility property that sets both [`initial-folder`][struct@crate::FileDialog#initial-folder]
60    /// and [`initial-name`][struct@crate::FileDialog#initial-name].
61    ///
62    /// Readable | Writeable
63    ///
64    ///
65    /// #### `initial-folder`
66    ///  The initial folder.
67    ///
68    /// This is the directory that is initially opened in the file chooser dialog.
69    ///
70    /// Readable | Writeable
71    ///
72    ///
73    /// #### `initial-name`
74    ///  The initial name.
75    ///
76    /// This is the name of the file that is initially selected in the file chooser dialog.
77    ///
78    /// Readable | Writeable
79    ///
80    ///
81    /// #### `modal`
82    ///  Whether the file chooser dialog is modal.
83    ///
84    /// Readable | Writeable
85    ///
86    ///
87    /// #### `title`
88    ///  A title that may be shown on the file chooser dialog.
89    ///
90    /// Readable | Writeable
91    ///
92    /// # Implements
93    ///
94    /// [`trait@glib::ObjectExt`]
95    #[doc(alias = "GtkFileDialog")]
96    pub struct FileDialog(Object<ffi::GtkFileDialog, ffi::GtkFileDialogClass>);
97
98    match fn {
99        type_ => || ffi::gtk_file_dialog_get_type(),
100    }
101}
102
103impl FileDialog {
104    /// Creates a new [`FileDialog`][crate::FileDialog] object.
105    ///
106    /// # Returns
107    ///
108    /// the new [`FileDialog`][crate::FileDialog]
109    #[doc(alias = "gtk_file_dialog_new")]
110    pub fn new() -> FileDialog {
111        assert_initialized_main_thread!();
112        unsafe { from_glib_full(ffi::gtk_file_dialog_new()) }
113    }
114
115    // rustdoc-stripper-ignore-next
116    /// Creates a new builder-pattern struct instance to construct [`FileDialog`] objects.
117    ///
118    /// This method returns an instance of [`FileDialogBuilder`](crate::builders::FileDialogBuilder) which can be used to create [`FileDialog`] objects.
119    pub fn builder() -> FileDialogBuilder {
120        FileDialogBuilder::new()
121    }
122
123    /// Retrieves the text used by the dialog on its accept button.
124    ///
125    /// # Returns
126    ///
127    /// the label shown on the file chooser's accept button
128    #[doc(alias = "gtk_file_dialog_get_accept_label")]
129    #[doc(alias = "get_accept_label")]
130    #[doc(alias = "accept-label")]
131    pub fn accept_label(&self) -> Option<glib::GString> {
132        unsafe { from_glib_none(ffi::gtk_file_dialog_get_accept_label(self.to_glib_none().0)) }
133    }
134
135    /// Gets the filter that will be selected by default
136    /// in the file chooser dialog.
137    ///
138    /// # Returns
139    ///
140    /// the default filter
141    #[doc(alias = "gtk_file_dialog_get_default_filter")]
142    #[doc(alias = "get_default_filter")]
143    #[doc(alias = "default-filter")]
144    pub fn default_filter(&self) -> Option<FileFilter> {
145        unsafe {
146            from_glib_none(ffi::gtk_file_dialog_get_default_filter(
147                self.to_glib_none().0,
148            ))
149        }
150    }
151
152    /// Gets the filters that will be offered to the user
153    /// in the file chooser dialog.
154    ///
155    /// # Returns
156    ///
157    /// the filters,
158    ///   as a list model of [`FileFilter`][crate::FileFilter]
159    #[doc(alias = "gtk_file_dialog_get_filters")]
160    #[doc(alias = "get_filters")]
161    pub fn filters(&self) -> Option<gio::ListModel> {
162        unsafe { from_glib_none(ffi::gtk_file_dialog_get_filters(self.to_glib_none().0)) }
163    }
164
165    /// Gets the file that will be initially selected in
166    /// the file chooser dialog.
167    ///
168    /// # Returns
169    ///
170    /// the file
171    #[doc(alias = "gtk_file_dialog_get_initial_file")]
172    #[doc(alias = "get_initial_file")]
173    #[doc(alias = "initial-file")]
174    pub fn initial_file(&self) -> Option<gio::File> {
175        unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_file(self.to_glib_none().0)) }
176    }
177
178    /// Gets the folder that will be set as the
179    /// initial folder in the file chooser dialog.
180    ///
181    /// # Returns
182    ///
183    /// the folder
184    #[doc(alias = "gtk_file_dialog_get_initial_folder")]
185    #[doc(alias = "get_initial_folder")]
186    #[doc(alias = "initial-folder")]
187    pub fn initial_folder(&self) -> Option<gio::File> {
188        unsafe {
189            from_glib_none(ffi::gtk_file_dialog_get_initial_folder(
190                self.to_glib_none().0,
191            ))
192        }
193    }
194
195    /// Gets the filename that will be initially selected.
196    ///
197    /// # Returns
198    ///
199    /// the name
200    #[doc(alias = "gtk_file_dialog_get_initial_name")]
201    #[doc(alias = "get_initial_name")]
202    #[doc(alias = "initial-name")]
203    pub fn initial_name(&self) -> Option<glib::GString> {
204        unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_name(self.to_glib_none().0)) }
205    }
206
207    /// Returns whether the file chooser dialog blocks interaction
208    /// with the parent window while it is presented.
209    ///
210    /// # Returns
211    ///
212    /// true if the file chooser dialog is modal
213    #[doc(alias = "gtk_file_dialog_get_modal")]
214    #[doc(alias = "get_modal")]
215    #[doc(alias = "modal")]
216    pub fn is_modal(&self) -> bool {
217        unsafe { from_glib(ffi::gtk_file_dialog_get_modal(self.to_glib_none().0)) }
218    }
219
220    /// Returns the title that will be shown on the file chooser dialog.
221    ///
222    /// # Returns
223    ///
224    /// the title
225    #[doc(alias = "gtk_file_dialog_get_title")]
226    #[doc(alias = "get_title")]
227    pub fn title(&self) -> glib::GString {
228        unsafe { from_glib_none(ffi::gtk_file_dialog_get_title(self.to_glib_none().0)) }
229    }
230
231    /// Presents a file chooser dialog to the user.
232    ///
233    /// The file chooser dialog will be set up to select a single file.
234    ///
235    /// The @callback will be called when the dialog is dismissed.
236    /// ## `parent`
237    /// the parent window
238    /// ## `cancellable`
239    /// a cancellable to cancel the operation
240    /// ## `callback`
241    /// a callback to call when the
242    ///   operation is complete
243    #[doc(alias = "gtk_file_dialog_open")]
244    pub fn open<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
245        &self,
246        parent: Option<&impl IsA<Window>>,
247        cancellable: Option<&impl IsA<gio::Cancellable>>,
248        callback: P,
249    ) {
250        let main_context = glib::MainContext::ref_thread_default();
251        let is_main_context_owner = main_context.is_owner();
252        let has_acquired_main_context = (!is_main_context_owner)
253            .then(|| main_context.acquire().ok())
254            .flatten();
255        assert!(
256            is_main_context_owner || has_acquired_main_context.is_some(),
257            "Async operations only allowed if the thread is owning the MainContext"
258        );
259
260        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
261            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
262        unsafe extern "C" fn open_trampoline<
263            P: FnOnce(Result<gio::File, glib::Error>) + 'static,
264        >(
265            _source_object: *mut glib::gobject_ffi::GObject,
266            res: *mut gio::ffi::GAsyncResult,
267            user_data: glib::ffi::gpointer,
268        ) {
269            let mut error = std::ptr::null_mut();
270            let ret = ffi::gtk_file_dialog_open_finish(_source_object as *mut _, res, &mut error);
271            let result = if error.is_null() {
272                Ok(from_glib_full(ret))
273            } else {
274                Err(from_glib_full(error))
275            };
276            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
277                Box_::from_raw(user_data as *mut _);
278            let callback: P = callback.into_inner();
279            callback(result);
280        }
281        let callback = open_trampoline::<P>;
282        unsafe {
283            ffi::gtk_file_dialog_open(
284                self.to_glib_none().0,
285                parent.map(|p| p.as_ref()).to_glib_none().0,
286                cancellable.map(|p| p.as_ref()).to_glib_none().0,
287                Some(callback),
288                Box_::into_raw(user_data) as *mut _,
289            );
290        }
291    }
292
293    pub fn open_future(
294        &self,
295        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
296    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
297        let parent = parent.map(ToOwned::to_owned);
298        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
299            obj.open(
300                parent.as_ref().map(::std::borrow::Borrow::borrow),
301                Some(cancellable),
302                move |res| {
303                    send.resolve(res);
304                },
305            );
306        }))
307    }
308
309    /// Presents a file chooser dialog to the user.
310    ///
311    /// The file chooser dialog will be set up to select multiple files.
312    ///
313    /// The file chooser dialog will initially be opened in the directory
314    /// [`initial-folder`][struct@crate::FileDialog#initial-folder].
315    ///
316    /// The @callback will be called when the dialog is dismissed.
317    /// ## `parent`
318    /// the parent window
319    /// ## `cancellable`
320    /// a cancellable to cancel the operation
321    /// ## `callback`
322    /// a callback to call when the
323    ///   operation is complete
324    #[doc(alias = "gtk_file_dialog_open_multiple")]
325    pub fn open_multiple<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
326        &self,
327        parent: Option<&impl IsA<Window>>,
328        cancellable: Option<&impl IsA<gio::Cancellable>>,
329        callback: P,
330    ) {
331        let main_context = glib::MainContext::ref_thread_default();
332        let is_main_context_owner = main_context.is_owner();
333        let has_acquired_main_context = (!is_main_context_owner)
334            .then(|| main_context.acquire().ok())
335            .flatten();
336        assert!(
337            is_main_context_owner || has_acquired_main_context.is_some(),
338            "Async operations only allowed if the thread is owning the MainContext"
339        );
340
341        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
342            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
343        unsafe extern "C" fn open_multiple_trampoline<
344            P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
345        >(
346            _source_object: *mut glib::gobject_ffi::GObject,
347            res: *mut gio::ffi::GAsyncResult,
348            user_data: glib::ffi::gpointer,
349        ) {
350            let mut error = std::ptr::null_mut();
351            let ret = ffi::gtk_file_dialog_open_multiple_finish(
352                _source_object as *mut _,
353                res,
354                &mut error,
355            );
356            let result = if error.is_null() {
357                Ok(from_glib_full(ret))
358            } else {
359                Err(from_glib_full(error))
360            };
361            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
362                Box_::from_raw(user_data as *mut _);
363            let callback: P = callback.into_inner();
364            callback(result);
365        }
366        let callback = open_multiple_trampoline::<P>;
367        unsafe {
368            ffi::gtk_file_dialog_open_multiple(
369                self.to_glib_none().0,
370                parent.map(|p| p.as_ref()).to_glib_none().0,
371                cancellable.map(|p| p.as_ref()).to_glib_none().0,
372                Some(callback),
373                Box_::into_raw(user_data) as *mut _,
374            );
375        }
376    }
377
378    pub fn open_multiple_future(
379        &self,
380        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
381    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
382    {
383        let parent = parent.map(ToOwned::to_owned);
384        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
385            obj.open_multiple(
386                parent.as_ref().map(::std::borrow::Borrow::borrow),
387                Some(cancellable),
388                move |res| {
389                    send.resolve(res);
390                },
391            );
392        }))
393    }
394
395    /// Presents a file chooser dialog to the user.
396    ///
397    /// The file chooser dialog will be set up to select multiple files.
398    ///
399    /// The file chooser dialog will initially be opened in the directory
400    /// [`initial-folder`][struct@crate::FileDialog#initial-folder].
401    ///
402    /// In contrast to [`open()`][Self::open()], this function
403    /// lets the user select the text encoding for the files, if possible.
404    ///
405    /// The @callback will be called when the dialog is dismissed.
406    /// ## `parent`
407    /// the parent window
408    /// ## `cancellable`
409    /// a cancellable to cancel the operation
410    /// ## `callback`
411    /// a callback to call when the
412    ///   operation is complete
413    #[cfg(feature = "v4_18")]
414    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
415    #[doc(alias = "gtk_file_dialog_open_multiple_text_files")]
416    pub fn open_multiple_text_files<
417        P: FnOnce(Result<(Option<gio::ListModel>, glib::GString), glib::Error>) + 'static,
418    >(
419        &self,
420        parent: Option<&impl IsA<Window>>,
421        cancellable: Option<&impl IsA<gio::Cancellable>>,
422        callback: P,
423    ) {
424        let main_context = glib::MainContext::ref_thread_default();
425        let is_main_context_owner = main_context.is_owner();
426        let has_acquired_main_context = (!is_main_context_owner)
427            .then(|| main_context.acquire().ok())
428            .flatten();
429        assert!(
430            is_main_context_owner || has_acquired_main_context.is_some(),
431            "Async operations only allowed if the thread is owning the MainContext"
432        );
433
434        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
435            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
436        unsafe extern "C" fn open_multiple_text_files_trampoline<
437            P: FnOnce(Result<(Option<gio::ListModel>, glib::GString), glib::Error>) + 'static,
438        >(
439            _source_object: *mut glib::gobject_ffi::GObject,
440            res: *mut gio::ffi::GAsyncResult,
441            user_data: glib::ffi::gpointer,
442        ) {
443            let mut error = std::ptr::null_mut();
444            let mut encoding = std::ptr::null();
445            let ret = ffi::gtk_file_dialog_open_multiple_text_files_finish(
446                _source_object as *mut _,
447                res,
448                &mut encoding,
449                &mut error,
450            );
451            let result = if error.is_null() {
452                Ok((from_glib_full(ret), from_glib_none(encoding)))
453            } else {
454                Err(from_glib_full(error))
455            };
456            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
457                Box_::from_raw(user_data as *mut _);
458            let callback: P = callback.into_inner();
459            callback(result);
460        }
461        let callback = open_multiple_text_files_trampoline::<P>;
462        unsafe {
463            ffi::gtk_file_dialog_open_multiple_text_files(
464                self.to_glib_none().0,
465                parent.map(|p| p.as_ref()).to_glib_none().0,
466                cancellable.map(|p| p.as_ref()).to_glib_none().0,
467                Some(callback),
468                Box_::into_raw(user_data) as *mut _,
469            );
470        }
471    }
472
473    #[cfg(feature = "v4_18")]
474    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
475    pub fn open_multiple_text_files_future(
476        &self,
477        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
478    ) -> Pin<
479        Box_<
480            dyn std::future::Future<
481                    Output = Result<(Option<gio::ListModel>, glib::GString), glib::Error>,
482                > + 'static,
483        >,
484    > {
485        let parent = parent.map(ToOwned::to_owned);
486        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
487            obj.open_multiple_text_files(
488                parent.as_ref().map(::std::borrow::Borrow::borrow),
489                Some(cancellable),
490                move |res| {
491                    send.resolve(res);
492                },
493            );
494        }))
495    }
496
497    /// Initiates a file selection operation by presenting a file chooser
498    /// dialog to the user.
499    ///
500    /// In contrast to [`open()`][Self::open()], this function
501    /// lets the user select the text encoding for the file, if possible.
502    ///
503    /// The @callback will be called when the dialog is dismissed.
504    /// ## `parent`
505    /// the parent [`Window`][crate::Window]
506    /// ## `cancellable`
507    /// a `GCancellable` to cancel the operation
508    /// ## `callback`
509    /// a callback to call when the
510    ///   operation is complete
511    #[cfg(feature = "v4_18")]
512    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
513    #[doc(alias = "gtk_file_dialog_open_text_file")]
514    pub fn open_text_file<
515        P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
516    >(
517        &self,
518        parent: Option<&impl IsA<Window>>,
519        cancellable: Option<&impl IsA<gio::Cancellable>>,
520        callback: P,
521    ) {
522        let main_context = glib::MainContext::ref_thread_default();
523        let is_main_context_owner = main_context.is_owner();
524        let has_acquired_main_context = (!is_main_context_owner)
525            .then(|| main_context.acquire().ok())
526            .flatten();
527        assert!(
528            is_main_context_owner || has_acquired_main_context.is_some(),
529            "Async operations only allowed if the thread is owning the MainContext"
530        );
531
532        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
533            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
534        unsafe extern "C" fn open_text_file_trampoline<
535            P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
536        >(
537            _source_object: *mut glib::gobject_ffi::GObject,
538            res: *mut gio::ffi::GAsyncResult,
539            user_data: glib::ffi::gpointer,
540        ) {
541            let mut error = std::ptr::null_mut();
542            let mut encoding = std::ptr::null();
543            let ret = ffi::gtk_file_dialog_open_text_file_finish(
544                _source_object as *mut _,
545                res,
546                &mut encoding,
547                &mut error,
548            );
549            let result = if error.is_null() {
550                Ok((from_glib_full(ret), from_glib_none(encoding)))
551            } else {
552                Err(from_glib_full(error))
553            };
554            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
555                Box_::from_raw(user_data as *mut _);
556            let callback: P = callback.into_inner();
557            callback(result);
558        }
559        let callback = open_text_file_trampoline::<P>;
560        unsafe {
561            ffi::gtk_file_dialog_open_text_file(
562                self.to_glib_none().0,
563                parent.map(|p| p.as_ref()).to_glib_none().0,
564                cancellable.map(|p| p.as_ref()).to_glib_none().0,
565                Some(callback),
566                Box_::into_raw(user_data) as *mut _,
567            );
568        }
569    }
570
571    #[cfg(feature = "v4_18")]
572    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
573    pub fn open_text_file_future(
574        &self,
575        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
576    ) -> Pin<
577        Box_<
578            dyn std::future::Future<
579                    Output = Result<(Option<gio::File>, glib::GString), glib::Error>,
580                > + 'static,
581        >,
582    > {
583        let parent = parent.map(ToOwned::to_owned);
584        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
585            obj.open_text_file(
586                parent.as_ref().map(::std::borrow::Borrow::borrow),
587                Some(cancellable),
588                move |res| {
589                    send.resolve(res);
590                },
591            );
592        }))
593    }
594
595    /// Presents a file chooser dialog to the user.
596    ///
597    /// The file chooser dialog will be save mode.
598    ///
599    /// The @callback will be called when the dialog is dismissed.
600    /// ## `parent`
601    /// the parent window
602    /// ## `cancellable`
603    /// a cancellable to cancel the operation
604    /// ## `callback`
605    /// a callback to call when the
606    ///   operation is complete
607    #[doc(alias = "gtk_file_dialog_save")]
608    pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
609        &self,
610        parent: Option<&impl IsA<Window>>,
611        cancellable: Option<&impl IsA<gio::Cancellable>>,
612        callback: P,
613    ) {
614        let main_context = glib::MainContext::ref_thread_default();
615        let is_main_context_owner = main_context.is_owner();
616        let has_acquired_main_context = (!is_main_context_owner)
617            .then(|| main_context.acquire().ok())
618            .flatten();
619        assert!(
620            is_main_context_owner || has_acquired_main_context.is_some(),
621            "Async operations only allowed if the thread is owning the MainContext"
622        );
623
624        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
625            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
626        unsafe extern "C" fn save_trampoline<
627            P: FnOnce(Result<gio::File, glib::Error>) + 'static,
628        >(
629            _source_object: *mut glib::gobject_ffi::GObject,
630            res: *mut gio::ffi::GAsyncResult,
631            user_data: glib::ffi::gpointer,
632        ) {
633            let mut error = std::ptr::null_mut();
634            let ret = ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
635            let result = if error.is_null() {
636                Ok(from_glib_full(ret))
637            } else {
638                Err(from_glib_full(error))
639            };
640            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
641                Box_::from_raw(user_data as *mut _);
642            let callback: P = callback.into_inner();
643            callback(result);
644        }
645        let callback = save_trampoline::<P>;
646        unsafe {
647            ffi::gtk_file_dialog_save(
648                self.to_glib_none().0,
649                parent.map(|p| p.as_ref()).to_glib_none().0,
650                cancellable.map(|p| p.as_ref()).to_glib_none().0,
651                Some(callback),
652                Box_::into_raw(user_data) as *mut _,
653            );
654        }
655    }
656
657    pub fn save_future(
658        &self,
659        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
660    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
661        let parent = parent.map(ToOwned::to_owned);
662        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
663            obj.save(
664                parent.as_ref().map(::std::borrow::Borrow::borrow),
665                Some(cancellable),
666                move |res| {
667                    send.resolve(res);
668                },
669            );
670        }))
671    }
672
673    /// Initiates a file save operation by presenting a file chooser
674    /// dialog to the user.
675    ///
676    /// In contrast to [`save()`][Self::save()], this function
677    /// lets the user select the text encoding and line endings for
678    /// the text file, if possible.
679    ///
680    /// The @callback will be called when the dialog is dismissed.
681    /// ## `parent`
682    /// the parent [`Window`][crate::Window]
683    /// ## `cancellable`
684    /// a `GCancellable` to cancel the operation
685    /// ## `callback`
686    /// a callback to call when the
687    ///   operation is complete
688    #[cfg(feature = "v4_18")]
689    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
690    #[doc(alias = "gtk_file_dialog_save_text_file")]
691    pub fn save_text_file<
692        P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>) + 'static,
693    >(
694        &self,
695        parent: Option<&impl IsA<Window>>,
696        cancellable: Option<&impl IsA<gio::Cancellable>>,
697        callback: P,
698    ) {
699        let main_context = glib::MainContext::ref_thread_default();
700        let is_main_context_owner = main_context.is_owner();
701        let has_acquired_main_context = (!is_main_context_owner)
702            .then(|| main_context.acquire().ok())
703            .flatten();
704        assert!(
705            is_main_context_owner || has_acquired_main_context.is_some(),
706            "Async operations only allowed if the thread is owning the MainContext"
707        );
708
709        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
710            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
711        unsafe extern "C" fn save_text_file_trampoline<
712            P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>)
713                + 'static,
714        >(
715            _source_object: *mut glib::gobject_ffi::GObject,
716            res: *mut gio::ffi::GAsyncResult,
717            user_data: glib::ffi::gpointer,
718        ) {
719            let mut error = std::ptr::null_mut();
720            let mut encoding = std::ptr::null();
721            let mut line_ending = std::ptr::null();
722            let ret = ffi::gtk_file_dialog_save_text_file_finish(
723                _source_object as *mut _,
724                res,
725                &mut encoding,
726                &mut line_ending,
727                &mut error,
728            );
729            let result = if error.is_null() {
730                Ok((
731                    from_glib_full(ret),
732                    from_glib_none(encoding),
733                    from_glib_none(line_ending),
734                ))
735            } else {
736                Err(from_glib_full(error))
737            };
738            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
739                Box_::from_raw(user_data as *mut _);
740            let callback: P = callback.into_inner();
741            callback(result);
742        }
743        let callback = save_text_file_trampoline::<P>;
744        unsafe {
745            ffi::gtk_file_dialog_save_text_file(
746                self.to_glib_none().0,
747                parent.map(|p| p.as_ref()).to_glib_none().0,
748                cancellable.map(|p| p.as_ref()).to_glib_none().0,
749                Some(callback),
750                Box_::into_raw(user_data) as *mut _,
751            );
752        }
753    }
754
755    #[cfg(feature = "v4_18")]
756    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
757    pub fn save_text_file_future(
758        &self,
759        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
760    ) -> Pin<
761        Box_<
762            dyn std::future::Future<
763                    Output = Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>,
764                > + 'static,
765        >,
766    > {
767        let parent = parent.map(ToOwned::to_owned);
768        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
769            obj.save_text_file(
770                parent.as_ref().map(::std::borrow::Borrow::borrow),
771                Some(cancellable),
772                move |res| {
773                    send.resolve(res);
774                },
775            );
776        }))
777    }
778
779    /// Presents a file chooser dialog to the user.
780    ///
781    /// The file chooser dialog will be set up to select a single folder.
782    ///
783    /// If you pass @initial_folder, the file chooser dialog will initially
784    /// be opened in the parent directory of that folder, otherwise, it
785    /// will be in the directory [`initial-folder`][struct@crate::FileDialog#initial-folder].
786    ///
787    /// The @callback will be called when the dialog is dismissed.
788    /// ## `parent`
789    /// the parent window
790    /// ## `cancellable`
791    /// a cancellable to cancel the operation
792    /// ## `callback`
793    /// a callback to call when the
794    ///   operation is complete
795    #[doc(alias = "gtk_file_dialog_select_folder")]
796    pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
797        &self,
798        parent: Option<&impl IsA<Window>>,
799        cancellable: Option<&impl IsA<gio::Cancellable>>,
800        callback: P,
801    ) {
802        let main_context = glib::MainContext::ref_thread_default();
803        let is_main_context_owner = main_context.is_owner();
804        let has_acquired_main_context = (!is_main_context_owner)
805            .then(|| main_context.acquire().ok())
806            .flatten();
807        assert!(
808            is_main_context_owner || has_acquired_main_context.is_some(),
809            "Async operations only allowed if the thread is owning the MainContext"
810        );
811
812        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
813            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
814        unsafe extern "C" fn select_folder_trampoline<
815            P: FnOnce(Result<gio::File, glib::Error>) + 'static,
816        >(
817            _source_object: *mut glib::gobject_ffi::GObject,
818            res: *mut gio::ffi::GAsyncResult,
819            user_data: glib::ffi::gpointer,
820        ) {
821            let mut error = std::ptr::null_mut();
822            let ret = ffi::gtk_file_dialog_select_folder_finish(
823                _source_object as *mut _,
824                res,
825                &mut error,
826            );
827            let result = if error.is_null() {
828                Ok(from_glib_full(ret))
829            } else {
830                Err(from_glib_full(error))
831            };
832            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
833                Box_::from_raw(user_data as *mut _);
834            let callback: P = callback.into_inner();
835            callback(result);
836        }
837        let callback = select_folder_trampoline::<P>;
838        unsafe {
839            ffi::gtk_file_dialog_select_folder(
840                self.to_glib_none().0,
841                parent.map(|p| p.as_ref()).to_glib_none().0,
842                cancellable.map(|p| p.as_ref()).to_glib_none().0,
843                Some(callback),
844                Box_::into_raw(user_data) as *mut _,
845            );
846        }
847    }
848
849    pub fn select_folder_future(
850        &self,
851        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
852    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
853        let parent = parent.map(ToOwned::to_owned);
854        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
855            obj.select_folder(
856                parent.as_ref().map(::std::borrow::Borrow::borrow),
857                Some(cancellable),
858                move |res| {
859                    send.resolve(res);
860                },
861            );
862        }))
863    }
864
865    /// Presents a file chooser dialog to the user.
866    ///
867    /// The file chooser dialog will be set up to allow selecting
868    /// multiple folders.
869    ///
870    /// The file chooser dialog will initially be opened in the
871    /// directory [`initial-folder`][struct@crate::FileDialog#initial-folder].
872    ///
873    /// The @callback will be called when the dialog is dismissed.
874    /// ## `parent`
875    /// the parent window
876    /// ## `cancellable`
877    /// a cancellable to cancel the operation
878    /// ## `callback`
879    /// a callback to call when the
880    ///   operation is complete
881    #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
882    pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
883        &self,
884        parent: Option<&impl IsA<Window>>,
885        cancellable: Option<&impl IsA<gio::Cancellable>>,
886        callback: P,
887    ) {
888        let main_context = glib::MainContext::ref_thread_default();
889        let is_main_context_owner = main_context.is_owner();
890        let has_acquired_main_context = (!is_main_context_owner)
891            .then(|| main_context.acquire().ok())
892            .flatten();
893        assert!(
894            is_main_context_owner || has_acquired_main_context.is_some(),
895            "Async operations only allowed if the thread is owning the MainContext"
896        );
897
898        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
899            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
900        unsafe extern "C" fn select_multiple_folders_trampoline<
901            P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
902        >(
903            _source_object: *mut glib::gobject_ffi::GObject,
904            res: *mut gio::ffi::GAsyncResult,
905            user_data: glib::ffi::gpointer,
906        ) {
907            let mut error = std::ptr::null_mut();
908            let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
909                _source_object as *mut _,
910                res,
911                &mut error,
912            );
913            let result = if error.is_null() {
914                Ok(from_glib_full(ret))
915            } else {
916                Err(from_glib_full(error))
917            };
918            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
919                Box_::from_raw(user_data as *mut _);
920            let callback: P = callback.into_inner();
921            callback(result);
922        }
923        let callback = select_multiple_folders_trampoline::<P>;
924        unsafe {
925            ffi::gtk_file_dialog_select_multiple_folders(
926                self.to_glib_none().0,
927                parent.map(|p| p.as_ref()).to_glib_none().0,
928                cancellable.map(|p| p.as_ref()).to_glib_none().0,
929                Some(callback),
930                Box_::into_raw(user_data) as *mut _,
931            );
932        }
933    }
934
935    pub fn select_multiple_folders_future(
936        &self,
937        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
938    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
939    {
940        let parent = parent.map(ToOwned::to_owned);
941        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
942            obj.select_multiple_folders(
943                parent.as_ref().map(::std::borrow::Borrow::borrow),
944                Some(cancellable),
945                move |res| {
946                    send.resolve(res);
947                },
948            );
949        }))
950    }
951
952    /// Sets the label shown on the file chooser's accept button.
953    ///
954    /// Leaving the accept label unset or setting it as `NULL` will
955    /// fall back to a default label, depending on what API is used
956    /// to launch the file dialog.
957    /// ## `accept_label`
958    /// the new accept label
959    #[doc(alias = "gtk_file_dialog_set_accept_label")]
960    #[doc(alias = "accept-label")]
961    pub fn set_accept_label(&self, accept_label: Option<&str>) {
962        unsafe {
963            ffi::gtk_file_dialog_set_accept_label(
964                self.to_glib_none().0,
965                accept_label.to_glib_none().0,
966            );
967        }
968    }
969
970    /// Sets the filter that will be selected by default
971    /// in the file chooser dialog.
972    ///
973    /// If set to `NULL`, the first item in [`filters`][struct@crate::FileDialog#filters]
974    /// will be used as the default filter. If that list is empty, the dialog
975    /// will be unfiltered.
976    /// ## `filter`
977    /// the file filter
978    #[doc(alias = "gtk_file_dialog_set_default_filter")]
979    #[doc(alias = "default-filter")]
980    pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
981        unsafe {
982            ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
983        }
984    }
985
986    /// Sets the filters that will be offered to the user
987    /// in the file chooser dialog.
988    /// ## `filters`
989    /// a list model of [`FileFilter`][crate::FileFilter]
990    #[doc(alias = "gtk_file_dialog_set_filters")]
991    #[doc(alias = "filters")]
992    pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
993        unsafe {
994            ffi::gtk_file_dialog_set_filters(
995                self.to_glib_none().0,
996                filters.map(|p| p.as_ref()).to_glib_none().0,
997            );
998        }
999    }
1000
1001    /// Sets the file that will be initially selected in
1002    /// the file chooser dialog.
1003    ///
1004    /// This function is a shortcut for calling both
1005    /// [`set_initial_folder()`][Self::set_initial_folder()] and
1006    /// [`set_initial_name()`][Self::set_initial_name()] with the
1007    /// directory and name of @file, respectively.
1008    /// ## `file`
1009    /// a file
1010    #[doc(alias = "gtk_file_dialog_set_initial_file")]
1011    #[doc(alias = "initial-file")]
1012    pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
1013        unsafe {
1014            ffi::gtk_file_dialog_set_initial_file(
1015                self.to_glib_none().0,
1016                file.map(|p| p.as_ref()).to_glib_none().0,
1017            );
1018        }
1019    }
1020
1021    /// Sets the folder that will be set as the
1022    /// initial folder in the file chooser dialog.
1023    /// ## `folder`
1024    /// a file
1025    #[doc(alias = "gtk_file_dialog_set_initial_folder")]
1026    #[doc(alias = "initial-folder")]
1027    pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
1028        unsafe {
1029            ffi::gtk_file_dialog_set_initial_folder(
1030                self.to_glib_none().0,
1031                folder.map(|p| p.as_ref()).to_glib_none().0,
1032            );
1033        }
1034    }
1035
1036    /// Sets the filename that will be initially selected.
1037    ///
1038    /// For save dialogs, @name will usually be pre-entered into the
1039    /// name field.
1040    ///
1041    /// If a file with this name already exists in the directory set
1042    /// via [`initial-folder`][struct@crate::FileDialog#initial-folder], the dialog will
1043    /// preselect it.
1044    /// ## `name`
1045    /// a string
1046    #[doc(alias = "gtk_file_dialog_set_initial_name")]
1047    #[doc(alias = "initial-name")]
1048    pub fn set_initial_name(&self, name: Option<&str>) {
1049        unsafe {
1050            ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
1051        }
1052    }
1053
1054    /// Sets whether the file chooser dialog blocks interaction
1055    /// with the parent window while it is presented.
1056    /// ## `modal`
1057    /// the new value
1058    #[doc(alias = "gtk_file_dialog_set_modal")]
1059    #[doc(alias = "modal")]
1060    pub fn set_modal(&self, modal: bool) {
1061        unsafe {
1062            ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
1063        }
1064    }
1065
1066    /// Sets the title that will be shown on the file chooser dialog.
1067    /// ## `title`
1068    /// the new title
1069    #[doc(alias = "gtk_file_dialog_set_title")]
1070    #[doc(alias = "title")]
1071    pub fn set_title(&self, title: &str) {
1072        unsafe {
1073            ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
1074        }
1075    }
1076
1077    #[cfg(feature = "v4_10")]
1078    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1079    #[doc(alias = "accept-label")]
1080    pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1081        unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
1082            this: *mut ffi::GtkFileDialog,
1083            _param_spec: glib::ffi::gpointer,
1084            f: glib::ffi::gpointer,
1085        ) {
1086            let f: &F = &*(f as *const F);
1087            f(&from_glib_borrow(this))
1088        }
1089        unsafe {
1090            let f: Box_<F> = Box_::new(f);
1091            connect_raw(
1092                self.as_ptr() as *mut _,
1093                b"notify::accept-label\0".as_ptr() as *const _,
1094                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1095                    notify_accept_label_trampoline::<F> as *const (),
1096                )),
1097                Box_::into_raw(f),
1098            )
1099        }
1100    }
1101
1102    #[cfg(feature = "v4_10")]
1103    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1104    #[doc(alias = "default-filter")]
1105    pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1106        unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
1107            this: *mut ffi::GtkFileDialog,
1108            _param_spec: glib::ffi::gpointer,
1109            f: glib::ffi::gpointer,
1110        ) {
1111            let f: &F = &*(f as *const F);
1112            f(&from_glib_borrow(this))
1113        }
1114        unsafe {
1115            let f: Box_<F> = Box_::new(f);
1116            connect_raw(
1117                self.as_ptr() as *mut _,
1118                b"notify::default-filter\0".as_ptr() as *const _,
1119                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1120                    notify_default_filter_trampoline::<F> as *const (),
1121                )),
1122                Box_::into_raw(f),
1123            )
1124        }
1125    }
1126
1127    #[cfg(feature = "v4_10")]
1128    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1129    #[doc(alias = "filters")]
1130    pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1131        unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
1132            this: *mut ffi::GtkFileDialog,
1133            _param_spec: glib::ffi::gpointer,
1134            f: glib::ffi::gpointer,
1135        ) {
1136            let f: &F = &*(f as *const F);
1137            f(&from_glib_borrow(this))
1138        }
1139        unsafe {
1140            let f: Box_<F> = Box_::new(f);
1141            connect_raw(
1142                self.as_ptr() as *mut _,
1143                b"notify::filters\0".as_ptr() as *const _,
1144                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1145                    notify_filters_trampoline::<F> as *const (),
1146                )),
1147                Box_::into_raw(f),
1148            )
1149        }
1150    }
1151
1152    #[cfg(feature = "v4_10")]
1153    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1154    #[doc(alias = "initial-file")]
1155    pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1156        unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
1157            this: *mut ffi::GtkFileDialog,
1158            _param_spec: glib::ffi::gpointer,
1159            f: glib::ffi::gpointer,
1160        ) {
1161            let f: &F = &*(f as *const F);
1162            f(&from_glib_borrow(this))
1163        }
1164        unsafe {
1165            let f: Box_<F> = Box_::new(f);
1166            connect_raw(
1167                self.as_ptr() as *mut _,
1168                b"notify::initial-file\0".as_ptr() as *const _,
1169                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1170                    notify_initial_file_trampoline::<F> as *const (),
1171                )),
1172                Box_::into_raw(f),
1173            )
1174        }
1175    }
1176
1177    #[cfg(feature = "v4_10")]
1178    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1179    #[doc(alias = "initial-folder")]
1180    pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1181        unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
1182            this: *mut ffi::GtkFileDialog,
1183            _param_spec: glib::ffi::gpointer,
1184            f: glib::ffi::gpointer,
1185        ) {
1186            let f: &F = &*(f as *const F);
1187            f(&from_glib_borrow(this))
1188        }
1189        unsafe {
1190            let f: Box_<F> = Box_::new(f);
1191            connect_raw(
1192                self.as_ptr() as *mut _,
1193                b"notify::initial-folder\0".as_ptr() as *const _,
1194                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1195                    notify_initial_folder_trampoline::<F> as *const (),
1196                )),
1197                Box_::into_raw(f),
1198            )
1199        }
1200    }
1201
1202    #[cfg(feature = "v4_10")]
1203    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1204    #[doc(alias = "initial-name")]
1205    pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1206        unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
1207            this: *mut ffi::GtkFileDialog,
1208            _param_spec: glib::ffi::gpointer,
1209            f: glib::ffi::gpointer,
1210        ) {
1211            let f: &F = &*(f as *const F);
1212            f(&from_glib_borrow(this))
1213        }
1214        unsafe {
1215            let f: Box_<F> = Box_::new(f);
1216            connect_raw(
1217                self.as_ptr() as *mut _,
1218                b"notify::initial-name\0".as_ptr() as *const _,
1219                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1220                    notify_initial_name_trampoline::<F> as *const (),
1221                )),
1222                Box_::into_raw(f),
1223            )
1224        }
1225    }
1226
1227    #[cfg(feature = "v4_10")]
1228    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1229    #[doc(alias = "modal")]
1230    pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1231        unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
1232            this: *mut ffi::GtkFileDialog,
1233            _param_spec: glib::ffi::gpointer,
1234            f: glib::ffi::gpointer,
1235        ) {
1236            let f: &F = &*(f as *const F);
1237            f(&from_glib_borrow(this))
1238        }
1239        unsafe {
1240            let f: Box_<F> = Box_::new(f);
1241            connect_raw(
1242                self.as_ptr() as *mut _,
1243                b"notify::modal\0".as_ptr() as *const _,
1244                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1245                    notify_modal_trampoline::<F> as *const (),
1246                )),
1247                Box_::into_raw(f),
1248            )
1249        }
1250    }
1251
1252    #[cfg(feature = "v4_10")]
1253    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1254    #[doc(alias = "title")]
1255    pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1256        unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
1257            this: *mut ffi::GtkFileDialog,
1258            _param_spec: glib::ffi::gpointer,
1259            f: glib::ffi::gpointer,
1260        ) {
1261            let f: &F = &*(f as *const F);
1262            f(&from_glib_borrow(this))
1263        }
1264        unsafe {
1265            let f: Box_<F> = Box_::new(f);
1266            connect_raw(
1267                self.as_ptr() as *mut _,
1268                b"notify::title\0".as_ptr() as *const _,
1269                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1270                    notify_title_trampoline::<F> as *const (),
1271                )),
1272                Box_::into_raw(f),
1273            )
1274        }
1275    }
1276}
1277
1278#[cfg(feature = "v4_10")]
1279#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1280impl Default for FileDialog {
1281    fn default() -> Self {
1282        Self::new()
1283    }
1284}
1285
1286// rustdoc-stripper-ignore-next
1287/// A [builder-pattern] type to construct [`FileDialog`] objects.
1288///
1289/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
1290#[must_use = "The builder must be built to be used"]
1291pub struct FileDialogBuilder {
1292    builder: glib::object::ObjectBuilder<'static, FileDialog>,
1293}
1294
1295impl FileDialogBuilder {
1296    fn new() -> Self {
1297        Self {
1298            builder: glib::object::Object::builder(),
1299        }
1300    }
1301
1302    /// Label for the file chooser's accept button.
1303    #[cfg(feature = "v4_10")]
1304    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1305    pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1306        Self {
1307            builder: self.builder.property("accept-label", accept_label.into()),
1308        }
1309    }
1310
1311    /// The default filter.
1312    ///
1313    /// This filter is initially active in the file chooser dialog.
1314    ///
1315    /// If the default filter is `NULL`, the first filter of [`filters`][struct@crate::FileDialog#filters]
1316    /// is used as the default filter. If that property contains no filter, the dialog will
1317    /// be unfiltered.
1318    ///
1319    /// If [`filters`][struct@crate::FileDialog#filters] is not `NULL`, the default filter should be
1320    /// part of the list. If it is not, the dialog may choose to not make it available.
1321    #[cfg(feature = "v4_10")]
1322    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1323    pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1324        Self {
1325            builder: self
1326                .builder
1327                .property("default-filter", default_filter.clone()),
1328        }
1329    }
1330
1331    /// The list of filters.
1332    ///
1333    /// See [`default-filter`][struct@crate::FileDialog#default-filter] about how these
1334    /// two properties interact.
1335    #[cfg(feature = "v4_10")]
1336    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1337    pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1338        Self {
1339            builder: self.builder.property("filters", filters.clone().upcast()),
1340        }
1341    }
1342
1343    /// The initial file.
1344    ///
1345    /// This file is initially selected in the file chooser dialog
1346    ///
1347    /// This is a utility property that sets both [`initial-folder`][struct@crate::FileDialog#initial-folder]
1348    /// and [`initial-name`][struct@crate::FileDialog#initial-name].
1349    #[cfg(feature = "v4_10")]
1350    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1351    pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1352        Self {
1353            builder: self
1354                .builder
1355                .property("initial-file", initial_file.clone().upcast()),
1356        }
1357    }
1358
1359    /// The initial folder.
1360    ///
1361    /// This is the directory that is initially opened in the file chooser dialog.
1362    #[cfg(feature = "v4_10")]
1363    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1364    pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1365        Self {
1366            builder: self
1367                .builder
1368                .property("initial-folder", initial_folder.clone().upcast()),
1369        }
1370    }
1371
1372    /// The initial name.
1373    ///
1374    /// This is the name of the file that is initially selected in the file chooser dialog.
1375    #[cfg(feature = "v4_10")]
1376    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1377    pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1378        Self {
1379            builder: self.builder.property("initial-name", initial_name.into()),
1380        }
1381    }
1382
1383    /// Whether the file chooser dialog is modal.
1384    #[cfg(feature = "v4_10")]
1385    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1386    pub fn modal(self, modal: bool) -> Self {
1387        Self {
1388            builder: self.builder.property("modal", modal),
1389        }
1390    }
1391
1392    /// A title that may be shown on the file chooser dialog.
1393    #[cfg(feature = "v4_10")]
1394    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1395    pub fn title(self, title: impl Into<glib::GString>) -> Self {
1396        Self {
1397            builder: self.builder.property("title", title.into()),
1398        }
1399    }
1400
1401    // rustdoc-stripper-ignore-next
1402    /// Build the [`FileDialog`].
1403    #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1404    pub fn build(self) -> FileDialog {
1405        assert_initialized_main_thread!();
1406        self.builder.build()
1407    }
1408}