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 dismissed.
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 dismissed.
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 dismissed.
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<(Option<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<(Option<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<
483                    Output = Result<(Option<gio::ListModel>, glib::GString), glib::Error>,
484                > + 'static,
485        >,
486    > {
487        let parent = parent.map(ToOwned::to_owned);
488        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
489            obj.open_multiple_text_files(
490                parent.as_ref().map(::std::borrow::Borrow::borrow),
491                Some(cancellable),
492                move |res| {
493                    send.resolve(res);
494                },
495            );
496        }))
497    }
498
499    /// Initiates a file selection operation by presenting a file chooser
500    /// dialog to the user.
501    ///
502    /// In contrast to [`open()`][Self::open()], this function
503    /// lets the user select the text encoding for the file, if possible.
504    ///
505    /// The @callback will be called when the dialog is dismissed.
506    /// ## `parent`
507    /// the parent [`Window`][crate::Window]
508    /// ## `cancellable`
509    /// a `GCancellable` to cancel the operation
510    /// ## `callback`
511    /// a callback to call when the
512    ///   operation is complete
513    #[cfg(feature = "v4_18")]
514    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
515    #[doc(alias = "gtk_file_dialog_open_text_file")]
516    pub fn open_text_file<
517        P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
518    >(
519        &self,
520        parent: Option<&impl IsA<Window>>,
521        cancellable: Option<&impl IsA<gio::Cancellable>>,
522        callback: P,
523    ) {
524        let main_context = glib::MainContext::ref_thread_default();
525        let is_main_context_owner = main_context.is_owner();
526        let has_acquired_main_context = (!is_main_context_owner)
527            .then(|| main_context.acquire().ok())
528            .flatten();
529        assert!(
530            is_main_context_owner || has_acquired_main_context.is_some(),
531            "Async operations only allowed if the thread is owning the MainContext"
532        );
533
534        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
535            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
536        unsafe extern "C" fn open_text_file_trampoline<
537            P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
538        >(
539            _source_object: *mut glib::gobject_ffi::GObject,
540            res: *mut gio::ffi::GAsyncResult,
541            user_data: glib::ffi::gpointer,
542        ) {
543            let mut error = std::ptr::null_mut();
544            let mut encoding = std::ptr::null();
545            let ret = ffi::gtk_file_dialog_open_text_file_finish(
546                _source_object as *mut _,
547                res,
548                &mut encoding,
549                &mut error,
550            );
551            let result = if error.is_null() {
552                Ok((from_glib_full(ret), from_glib_none(encoding)))
553            } else {
554                Err(from_glib_full(error))
555            };
556            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
557                Box_::from_raw(user_data as *mut _);
558            let callback: P = callback.into_inner();
559            callback(result);
560        }
561        let callback = open_text_file_trampoline::<P>;
562        unsafe {
563            ffi::gtk_file_dialog_open_text_file(
564                self.to_glib_none().0,
565                parent.map(|p| p.as_ref()).to_glib_none().0,
566                cancellable.map(|p| p.as_ref()).to_glib_none().0,
567                Some(callback),
568                Box_::into_raw(user_data) as *mut _,
569            );
570        }
571    }
572
573    #[cfg(feature = "v4_18")]
574    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
575    pub fn open_text_file_future(
576        &self,
577        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
578    ) -> Pin<
579        Box_<
580            dyn std::future::Future<
581                    Output = Result<(Option<gio::File>, glib::GString), glib::Error>,
582                > + 'static,
583        >,
584    > {
585        let parent = parent.map(ToOwned::to_owned);
586        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
587            obj.open_text_file(
588                parent.as_ref().map(::std::borrow::Borrow::borrow),
589                Some(cancellable),
590                move |res| {
591                    send.resolve(res);
592                },
593            );
594        }))
595    }
596
597    /// Presents a file chooser dialog to the user.
598    ///
599    /// The file chooser dialog will be save mode.
600    ///
601    /// The @callback will be called when the dialog is dismissed.
602    /// ## `parent`
603    /// the parent window
604    /// ## `cancellable`
605    /// a cancellable to cancel the operation
606    /// ## `callback`
607    /// a callback to call when the
608    ///   operation is complete
609    #[doc(alias = "gtk_file_dialog_save")]
610    pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
611        &self,
612        parent: Option<&impl IsA<Window>>,
613        cancellable: Option<&impl IsA<gio::Cancellable>>,
614        callback: P,
615    ) {
616        let main_context = glib::MainContext::ref_thread_default();
617        let is_main_context_owner = main_context.is_owner();
618        let has_acquired_main_context = (!is_main_context_owner)
619            .then(|| main_context.acquire().ok())
620            .flatten();
621        assert!(
622            is_main_context_owner || has_acquired_main_context.is_some(),
623            "Async operations only allowed if the thread is owning the MainContext"
624        );
625
626        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
627            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
628        unsafe extern "C" fn save_trampoline<
629            P: FnOnce(Result<gio::File, glib::Error>) + 'static,
630        >(
631            _source_object: *mut glib::gobject_ffi::GObject,
632            res: *mut gio::ffi::GAsyncResult,
633            user_data: glib::ffi::gpointer,
634        ) {
635            let mut error = std::ptr::null_mut();
636            let ret = ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
637            let result = if error.is_null() {
638                Ok(from_glib_full(ret))
639            } else {
640                Err(from_glib_full(error))
641            };
642            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
643                Box_::from_raw(user_data as *mut _);
644            let callback: P = callback.into_inner();
645            callback(result);
646        }
647        let callback = save_trampoline::<P>;
648        unsafe {
649            ffi::gtk_file_dialog_save(
650                self.to_glib_none().0,
651                parent.map(|p| p.as_ref()).to_glib_none().0,
652                cancellable.map(|p| p.as_ref()).to_glib_none().0,
653                Some(callback),
654                Box_::into_raw(user_data) as *mut _,
655            );
656        }
657    }
658
659    pub fn save_future(
660        &self,
661        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
662    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
663        let parent = parent.map(ToOwned::to_owned);
664        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
665            obj.save(
666                parent.as_ref().map(::std::borrow::Borrow::borrow),
667                Some(cancellable),
668                move |res| {
669                    send.resolve(res);
670                },
671            );
672        }))
673    }
674
675    /// Initiates a file save operation by presenting a file chooser
676    /// dialog to the user.
677    ///
678    /// In contrast to [`save()`][Self::save()], this function
679    /// lets the user select the text encoding and line endings for
680    /// the text file, if possible.
681    ///
682    /// The @callback will be called when the dialog is dismissed.
683    /// ## `parent`
684    /// the parent [`Window`][crate::Window]
685    /// ## `cancellable`
686    /// a `GCancellable` to cancel the operation
687    /// ## `callback`
688    /// a callback to call when the
689    ///   operation is complete
690    #[cfg(feature = "v4_18")]
691    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
692    #[doc(alias = "gtk_file_dialog_save_text_file")]
693    pub fn save_text_file<
694        P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>) + 'static,
695    >(
696        &self,
697        parent: Option<&impl IsA<Window>>,
698        cancellable: Option<&impl IsA<gio::Cancellable>>,
699        callback: P,
700    ) {
701        let main_context = glib::MainContext::ref_thread_default();
702        let is_main_context_owner = main_context.is_owner();
703        let has_acquired_main_context = (!is_main_context_owner)
704            .then(|| main_context.acquire().ok())
705            .flatten();
706        assert!(
707            is_main_context_owner || has_acquired_main_context.is_some(),
708            "Async operations only allowed if the thread is owning the MainContext"
709        );
710
711        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
712            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
713        unsafe extern "C" fn save_text_file_trampoline<
714            P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>)
715                + 'static,
716        >(
717            _source_object: *mut glib::gobject_ffi::GObject,
718            res: *mut gio::ffi::GAsyncResult,
719            user_data: glib::ffi::gpointer,
720        ) {
721            let mut error = std::ptr::null_mut();
722            let mut encoding = std::ptr::null();
723            let mut line_ending = std::ptr::null();
724            let ret = ffi::gtk_file_dialog_save_text_file_finish(
725                _source_object as *mut _,
726                res,
727                &mut encoding,
728                &mut line_ending,
729                &mut error,
730            );
731            let result = if error.is_null() {
732                Ok((
733                    from_glib_full(ret),
734                    from_glib_none(encoding),
735                    from_glib_none(line_ending),
736                ))
737            } else {
738                Err(from_glib_full(error))
739            };
740            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
741                Box_::from_raw(user_data as *mut _);
742            let callback: P = callback.into_inner();
743            callback(result);
744        }
745        let callback = save_text_file_trampoline::<P>;
746        unsafe {
747            ffi::gtk_file_dialog_save_text_file(
748                self.to_glib_none().0,
749                parent.map(|p| p.as_ref()).to_glib_none().0,
750                cancellable.map(|p| p.as_ref()).to_glib_none().0,
751                Some(callback),
752                Box_::into_raw(user_data) as *mut _,
753            );
754        }
755    }
756
757    #[cfg(feature = "v4_18")]
758    #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
759    pub fn save_text_file_future(
760        &self,
761        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
762    ) -> Pin<
763        Box_<
764            dyn std::future::Future<
765                    Output = Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>,
766                > + 'static,
767        >,
768    > {
769        let parent = parent.map(ToOwned::to_owned);
770        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
771            obj.save_text_file(
772                parent.as_ref().map(::std::borrow::Borrow::borrow),
773                Some(cancellable),
774                move |res| {
775                    send.resolve(res);
776                },
777            );
778        }))
779    }
780
781    /// Presents a file chooser dialog to the user.
782    ///
783    /// The file chooser dialog will be set up to select a single folder.
784    ///
785    /// If you pass @initial_folder, the file chooser dialog will initially
786    /// be opened in the parent directory of that folder, otherwise, it
787    /// will be in the directory [`initial-folder`][struct@crate::FileDialog#initial-folder].
788    ///
789    /// The @callback will be called when the dialog is dismissed.
790    /// ## `parent`
791    /// the parent window
792    /// ## `cancellable`
793    /// a cancellable to cancel the operation
794    /// ## `callback`
795    /// a callback to call when the
796    ///   operation is complete
797    #[doc(alias = "gtk_file_dialog_select_folder")]
798    pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
799        &self,
800        parent: Option<&impl IsA<Window>>,
801        cancellable: Option<&impl IsA<gio::Cancellable>>,
802        callback: P,
803    ) {
804        let main_context = glib::MainContext::ref_thread_default();
805        let is_main_context_owner = main_context.is_owner();
806        let has_acquired_main_context = (!is_main_context_owner)
807            .then(|| main_context.acquire().ok())
808            .flatten();
809        assert!(
810            is_main_context_owner || has_acquired_main_context.is_some(),
811            "Async operations only allowed if the thread is owning the MainContext"
812        );
813
814        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
815            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
816        unsafe extern "C" fn select_folder_trampoline<
817            P: FnOnce(Result<gio::File, glib::Error>) + 'static,
818        >(
819            _source_object: *mut glib::gobject_ffi::GObject,
820            res: *mut gio::ffi::GAsyncResult,
821            user_data: glib::ffi::gpointer,
822        ) {
823            let mut error = std::ptr::null_mut();
824            let ret = ffi::gtk_file_dialog_select_folder_finish(
825                _source_object as *mut _,
826                res,
827                &mut error,
828            );
829            let result = if error.is_null() {
830                Ok(from_glib_full(ret))
831            } else {
832                Err(from_glib_full(error))
833            };
834            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
835                Box_::from_raw(user_data as *mut _);
836            let callback: P = callback.into_inner();
837            callback(result);
838        }
839        let callback = select_folder_trampoline::<P>;
840        unsafe {
841            ffi::gtk_file_dialog_select_folder(
842                self.to_glib_none().0,
843                parent.map(|p| p.as_ref()).to_glib_none().0,
844                cancellable.map(|p| p.as_ref()).to_glib_none().0,
845                Some(callback),
846                Box_::into_raw(user_data) as *mut _,
847            );
848        }
849    }
850
851    pub fn select_folder_future(
852        &self,
853        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
854    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
855        let parent = parent.map(ToOwned::to_owned);
856        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
857            obj.select_folder(
858                parent.as_ref().map(::std::borrow::Borrow::borrow),
859                Some(cancellable),
860                move |res| {
861                    send.resolve(res);
862                },
863            );
864        }))
865    }
866
867    /// Presents a file chooser dialog to the user.
868    ///
869    /// The file chooser dialog will be set up to allow selecting
870    /// multiple folders.
871    ///
872    /// The file chooser dialog will initially be opened in the
873    /// directory [`initial-folder`][struct@crate::FileDialog#initial-folder].
874    ///
875    /// The @callback will be called when the dialog is dismissed.
876    /// ## `parent`
877    /// the parent window
878    /// ## `cancellable`
879    /// a cancellable to cancel the operation
880    /// ## `callback`
881    /// a callback to call when the
882    ///   operation is complete
883    #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
884    pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
885        &self,
886        parent: Option<&impl IsA<Window>>,
887        cancellable: Option<&impl IsA<gio::Cancellable>>,
888        callback: P,
889    ) {
890        let main_context = glib::MainContext::ref_thread_default();
891        let is_main_context_owner = main_context.is_owner();
892        let has_acquired_main_context = (!is_main_context_owner)
893            .then(|| main_context.acquire().ok())
894            .flatten();
895        assert!(
896            is_main_context_owner || has_acquired_main_context.is_some(),
897            "Async operations only allowed if the thread is owning the MainContext"
898        );
899
900        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
901            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
902        unsafe extern "C" fn select_multiple_folders_trampoline<
903            P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
904        >(
905            _source_object: *mut glib::gobject_ffi::GObject,
906            res: *mut gio::ffi::GAsyncResult,
907            user_data: glib::ffi::gpointer,
908        ) {
909            let mut error = std::ptr::null_mut();
910            let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
911                _source_object as *mut _,
912                res,
913                &mut error,
914            );
915            let result = if error.is_null() {
916                Ok(from_glib_full(ret))
917            } else {
918                Err(from_glib_full(error))
919            };
920            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
921                Box_::from_raw(user_data as *mut _);
922            let callback: P = callback.into_inner();
923            callback(result);
924        }
925        let callback = select_multiple_folders_trampoline::<P>;
926        unsafe {
927            ffi::gtk_file_dialog_select_multiple_folders(
928                self.to_glib_none().0,
929                parent.map(|p| p.as_ref()).to_glib_none().0,
930                cancellable.map(|p| p.as_ref()).to_glib_none().0,
931                Some(callback),
932                Box_::into_raw(user_data) as *mut _,
933            );
934        }
935    }
936
937    pub fn select_multiple_folders_future(
938        &self,
939        parent: Option<&(impl IsA<Window> + Clone + 'static)>,
940    ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
941    {
942        let parent = parent.map(ToOwned::to_owned);
943        Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
944            obj.select_multiple_folders(
945                parent.as_ref().map(::std::borrow::Borrow::borrow),
946                Some(cancellable),
947                move |res| {
948                    send.resolve(res);
949                },
950            );
951        }))
952    }
953
954    /// Sets the label shown on the file chooser's accept button.
955    ///
956    /// Leaving the accept label unset or setting it as `NULL` will
957    /// fall back to a default label, depending on what API is used
958    /// to launch the file dialog.
959    /// ## `accept_label`
960    /// the new accept label
961    #[doc(alias = "gtk_file_dialog_set_accept_label")]
962    #[doc(alias = "accept-label")]
963    pub fn set_accept_label(&self, accept_label: Option<&str>) {
964        unsafe {
965            ffi::gtk_file_dialog_set_accept_label(
966                self.to_glib_none().0,
967                accept_label.to_glib_none().0,
968            );
969        }
970    }
971
972    /// Sets the filter that will be selected by default
973    /// in the file chooser dialog.
974    ///
975    /// If set to `NULL`, the first item in [`filters`][struct@crate::FileDialog#filters]
976    /// will be used as the default filter. If that list is empty, the dialog
977    /// will be unfiltered.
978    /// ## `filter`
979    /// the file filter
980    #[doc(alias = "gtk_file_dialog_set_default_filter")]
981    #[doc(alias = "default-filter")]
982    pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
983        unsafe {
984            ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
985        }
986    }
987
988    /// Sets the filters that will be offered to the user
989    /// in the file chooser dialog.
990    /// ## `filters`
991    /// a list model of [`FileFilter`][crate::FileFilter]
992    #[doc(alias = "gtk_file_dialog_set_filters")]
993    #[doc(alias = "filters")]
994    pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
995        unsafe {
996            ffi::gtk_file_dialog_set_filters(
997                self.to_glib_none().0,
998                filters.map(|p| p.as_ref()).to_glib_none().0,
999            );
1000        }
1001    }
1002
1003    /// Sets the file that will be initially selected in
1004    /// the file chooser dialog.
1005    ///
1006    /// This function is a shortcut for calling both
1007    /// [`set_initial_folder()`][Self::set_initial_folder()] and
1008    /// [`set_initial_name()`][Self::set_initial_name()] with the
1009    /// directory and name of @file, respectively.
1010    /// ## `file`
1011    /// a file
1012    #[doc(alias = "gtk_file_dialog_set_initial_file")]
1013    #[doc(alias = "initial-file")]
1014    pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
1015        unsafe {
1016            ffi::gtk_file_dialog_set_initial_file(
1017                self.to_glib_none().0,
1018                file.map(|p| p.as_ref()).to_glib_none().0,
1019            );
1020        }
1021    }
1022
1023    /// Sets the folder that will be set as the
1024    /// initial folder in the file chooser dialog.
1025    /// ## `folder`
1026    /// a file
1027    #[doc(alias = "gtk_file_dialog_set_initial_folder")]
1028    #[doc(alias = "initial-folder")]
1029    pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
1030        unsafe {
1031            ffi::gtk_file_dialog_set_initial_folder(
1032                self.to_glib_none().0,
1033                folder.map(|p| p.as_ref()).to_glib_none().0,
1034            );
1035        }
1036    }
1037
1038    /// Sets the filename that will be initially selected.
1039    ///
1040    /// For save dialogs, @name will usually be pre-entered into the
1041    /// name field.
1042    ///
1043    /// If a file with this name already exists in the directory set
1044    /// via [`initial-folder`][struct@crate::FileDialog#initial-folder], the dialog will
1045    /// preselect it.
1046    /// ## `name`
1047    /// a string
1048    #[doc(alias = "gtk_file_dialog_set_initial_name")]
1049    #[doc(alias = "initial-name")]
1050    pub fn set_initial_name(&self, name: Option<&str>) {
1051        unsafe {
1052            ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
1053        }
1054    }
1055
1056    /// Sets whether the file chooser dialog blocks interaction
1057    /// with the parent window while it is presented.
1058    /// ## `modal`
1059    /// the new value
1060    #[doc(alias = "gtk_file_dialog_set_modal")]
1061    #[doc(alias = "modal")]
1062    pub fn set_modal(&self, modal: bool) {
1063        unsafe {
1064            ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
1065        }
1066    }
1067
1068    /// Sets the title that will be shown on the file chooser dialog.
1069    /// ## `title`
1070    /// the new title
1071    #[doc(alias = "gtk_file_dialog_set_title")]
1072    #[doc(alias = "title")]
1073    pub fn set_title(&self, title: &str) {
1074        unsafe {
1075            ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
1076        }
1077    }
1078
1079    #[cfg(feature = "v4_10")]
1080    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1081    #[doc(alias = "accept-label")]
1082    pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1083        unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
1084            this: *mut ffi::GtkFileDialog,
1085            _param_spec: glib::ffi::gpointer,
1086            f: glib::ffi::gpointer,
1087        ) {
1088            let f: &F = &*(f as *const F);
1089            f(&from_glib_borrow(this))
1090        }
1091        unsafe {
1092            let f: Box_<F> = Box_::new(f);
1093            connect_raw(
1094                self.as_ptr() as *mut _,
1095                c"notify::accept-label".as_ptr() as *const _,
1096                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1097                    notify_accept_label_trampoline::<F> as *const (),
1098                )),
1099                Box_::into_raw(f),
1100            )
1101        }
1102    }
1103
1104    #[cfg(feature = "v4_10")]
1105    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1106    #[doc(alias = "default-filter")]
1107    pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1108        unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
1109            this: *mut ffi::GtkFileDialog,
1110            _param_spec: glib::ffi::gpointer,
1111            f: glib::ffi::gpointer,
1112        ) {
1113            let f: &F = &*(f as *const F);
1114            f(&from_glib_borrow(this))
1115        }
1116        unsafe {
1117            let f: Box_<F> = Box_::new(f);
1118            connect_raw(
1119                self.as_ptr() as *mut _,
1120                c"notify::default-filter".as_ptr() as *const _,
1121                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1122                    notify_default_filter_trampoline::<F> as *const (),
1123                )),
1124                Box_::into_raw(f),
1125            )
1126        }
1127    }
1128
1129    #[cfg(feature = "v4_10")]
1130    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1131    #[doc(alias = "filters")]
1132    pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1133        unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
1134            this: *mut ffi::GtkFileDialog,
1135            _param_spec: glib::ffi::gpointer,
1136            f: glib::ffi::gpointer,
1137        ) {
1138            let f: &F = &*(f as *const F);
1139            f(&from_glib_borrow(this))
1140        }
1141        unsafe {
1142            let f: Box_<F> = Box_::new(f);
1143            connect_raw(
1144                self.as_ptr() as *mut _,
1145                c"notify::filters".as_ptr() as *const _,
1146                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1147                    notify_filters_trampoline::<F> as *const (),
1148                )),
1149                Box_::into_raw(f),
1150            )
1151        }
1152    }
1153
1154    #[cfg(feature = "v4_10")]
1155    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1156    #[doc(alias = "initial-file")]
1157    pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1158        unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
1159            this: *mut ffi::GtkFileDialog,
1160            _param_spec: glib::ffi::gpointer,
1161            f: glib::ffi::gpointer,
1162        ) {
1163            let f: &F = &*(f as *const F);
1164            f(&from_glib_borrow(this))
1165        }
1166        unsafe {
1167            let f: Box_<F> = Box_::new(f);
1168            connect_raw(
1169                self.as_ptr() as *mut _,
1170                c"notify::initial-file".as_ptr() as *const _,
1171                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1172                    notify_initial_file_trampoline::<F> as *const (),
1173                )),
1174                Box_::into_raw(f),
1175            )
1176        }
1177    }
1178
1179    #[cfg(feature = "v4_10")]
1180    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1181    #[doc(alias = "initial-folder")]
1182    pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1183        unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
1184            this: *mut ffi::GtkFileDialog,
1185            _param_spec: glib::ffi::gpointer,
1186            f: glib::ffi::gpointer,
1187        ) {
1188            let f: &F = &*(f as *const F);
1189            f(&from_glib_borrow(this))
1190        }
1191        unsafe {
1192            let f: Box_<F> = Box_::new(f);
1193            connect_raw(
1194                self.as_ptr() as *mut _,
1195                c"notify::initial-folder".as_ptr() as *const _,
1196                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1197                    notify_initial_folder_trampoline::<F> as *const (),
1198                )),
1199                Box_::into_raw(f),
1200            )
1201        }
1202    }
1203
1204    #[cfg(feature = "v4_10")]
1205    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1206    #[doc(alias = "initial-name")]
1207    pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1208        unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
1209            this: *mut ffi::GtkFileDialog,
1210            _param_spec: glib::ffi::gpointer,
1211            f: glib::ffi::gpointer,
1212        ) {
1213            let f: &F = &*(f as *const F);
1214            f(&from_glib_borrow(this))
1215        }
1216        unsafe {
1217            let f: Box_<F> = Box_::new(f);
1218            connect_raw(
1219                self.as_ptr() as *mut _,
1220                c"notify::initial-name".as_ptr() as *const _,
1221                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1222                    notify_initial_name_trampoline::<F> as *const (),
1223                )),
1224                Box_::into_raw(f),
1225            )
1226        }
1227    }
1228
1229    #[cfg(feature = "v4_10")]
1230    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1231    #[doc(alias = "modal")]
1232    pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1233        unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
1234            this: *mut ffi::GtkFileDialog,
1235            _param_spec: glib::ffi::gpointer,
1236            f: glib::ffi::gpointer,
1237        ) {
1238            let f: &F = &*(f as *const F);
1239            f(&from_glib_borrow(this))
1240        }
1241        unsafe {
1242            let f: Box_<F> = Box_::new(f);
1243            connect_raw(
1244                self.as_ptr() as *mut _,
1245                c"notify::modal".as_ptr() as *const _,
1246                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1247                    notify_modal_trampoline::<F> as *const (),
1248                )),
1249                Box_::into_raw(f),
1250            )
1251        }
1252    }
1253
1254    #[cfg(feature = "v4_10")]
1255    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1256    #[doc(alias = "title")]
1257    pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1258        unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
1259            this: *mut ffi::GtkFileDialog,
1260            _param_spec: glib::ffi::gpointer,
1261            f: glib::ffi::gpointer,
1262        ) {
1263            let f: &F = &*(f as *const F);
1264            f(&from_glib_borrow(this))
1265        }
1266        unsafe {
1267            let f: Box_<F> = Box_::new(f);
1268            connect_raw(
1269                self.as_ptr() as *mut _,
1270                c"notify::title".as_ptr() as *const _,
1271                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1272                    notify_title_trampoline::<F> as *const (),
1273                )),
1274                Box_::into_raw(f),
1275            )
1276        }
1277    }
1278}
1279
1280#[cfg(feature = "v4_10")]
1281#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1282impl Default for FileDialog {
1283    fn default() -> Self {
1284        Self::new()
1285    }
1286}
1287
1288// rustdoc-stripper-ignore-next
1289/// A [builder-pattern] type to construct [`FileDialog`] objects.
1290///
1291/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
1292#[must_use = "The builder must be built to be used"]
1293pub struct FileDialogBuilder {
1294    builder: glib::object::ObjectBuilder<'static, FileDialog>,
1295}
1296
1297impl FileDialogBuilder {
1298    fn new() -> Self {
1299        Self {
1300            builder: glib::object::Object::builder(),
1301        }
1302    }
1303
1304    /// Label for the file chooser's accept button.
1305    #[cfg(feature = "v4_10")]
1306    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1307    pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1308        Self {
1309            builder: self.builder.property("accept-label", accept_label.into()),
1310        }
1311    }
1312
1313    /// The default filter.
1314    ///
1315    /// This filter is initially active in the file chooser dialog.
1316    ///
1317    /// If the default filter is `NULL`, the first filter of [`filters`][struct@crate::FileDialog#filters]
1318    /// is used as the default filter. If that property contains no filter, the dialog will
1319    /// be unfiltered.
1320    ///
1321    /// If [`filters`][struct@crate::FileDialog#filters] is not `NULL`, the default filter should be
1322    /// part of the list. If it is not, the dialog may choose to not make it available.
1323    #[cfg(feature = "v4_10")]
1324    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1325    pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1326        Self {
1327            builder: self
1328                .builder
1329                .property("default-filter", default_filter.clone()),
1330        }
1331    }
1332
1333    /// The list of filters.
1334    ///
1335    /// See [`default-filter`][struct@crate::FileDialog#default-filter] about how these
1336    /// two properties interact.
1337    #[cfg(feature = "v4_10")]
1338    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1339    pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1340        Self {
1341            builder: self.builder.property("filters", filters.clone().upcast()),
1342        }
1343    }
1344
1345    /// The initial file.
1346    ///
1347    /// This file is initially selected in the file chooser dialog
1348    ///
1349    /// This is a utility property that sets both [`initial-folder`][struct@crate::FileDialog#initial-folder]
1350    /// and [`initial-name`][struct@crate::FileDialog#initial-name].
1351    #[cfg(feature = "v4_10")]
1352    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1353    pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1354        Self {
1355            builder: self
1356                .builder
1357                .property("initial-file", initial_file.clone().upcast()),
1358        }
1359    }
1360
1361    /// The initial folder.
1362    ///
1363    /// This is the directory that is initially opened in the file chooser dialog.
1364    #[cfg(feature = "v4_10")]
1365    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1366    pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1367        Self {
1368            builder: self
1369                .builder
1370                .property("initial-folder", initial_folder.clone().upcast()),
1371        }
1372    }
1373
1374    /// The initial name.
1375    ///
1376    /// This is the name of the file that is initially selected in the file chooser dialog.
1377    #[cfg(feature = "v4_10")]
1378    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1379    pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1380        Self {
1381            builder: self.builder.property("initial-name", initial_name.into()),
1382        }
1383    }
1384
1385    /// Whether the file chooser dialog is modal.
1386    #[cfg(feature = "v4_10")]
1387    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1388    pub fn modal(self, modal: bool) -> Self {
1389        Self {
1390            builder: self.builder.property("modal", modal),
1391        }
1392    }
1393
1394    /// A title that may be shown on the file chooser dialog.
1395    #[cfg(feature = "v4_10")]
1396    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1397    pub fn title(self, title: impl Into<glib::GString>) -> Self {
1398        Self {
1399            builder: self.builder.property("title", title.into()),
1400        }
1401    }
1402
1403    // rustdoc-stripper-ignore-next
1404    /// Build the [`FileDialog`].
1405    #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1406    pub fn build(self) -> FileDialog {
1407        assert_initialized_main_thread!();
1408        self.builder.build()
1409    }
1410}