Skip to main content

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