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