1use 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 #[doc(alias = "GtkFileDialog")]
96 pub struct FileDialog(Object<ffi::GtkFileDialog, ffi::GtkFileDialogClass>);
97
98 match fn {
99 type_ => || ffi::gtk_file_dialog_get_type(),
100 }
101}
102
103impl FileDialog {
104 #[doc(alias = "gtk_file_dialog_new")]
110 pub fn new() -> FileDialog {
111 assert_initialized_main_thread!();
112 unsafe { from_glib_full(ffi::gtk_file_dialog_new()) }
113 }
114
115 pub fn builder() -> FileDialogBuilder {
120 FileDialogBuilder::new()
121 }
122
123 #[doc(alias = "gtk_file_dialog_get_accept_label")]
129 #[doc(alias = "get_accept_label")]
130 #[doc(alias = "accept-label")]
131 pub fn accept_label(&self) -> Option<glib::GString> {
132 unsafe { from_glib_none(ffi::gtk_file_dialog_get_accept_label(self.to_glib_none().0)) }
133 }
134
135 #[doc(alias = "gtk_file_dialog_get_default_filter")]
142 #[doc(alias = "get_default_filter")]
143 #[doc(alias = "default-filter")]
144 pub fn default_filter(&self) -> Option<FileFilter> {
145 unsafe {
146 from_glib_none(ffi::gtk_file_dialog_get_default_filter(
147 self.to_glib_none().0,
148 ))
149 }
150 }
151
152 #[doc(alias = "gtk_file_dialog_get_filters")]
160 #[doc(alias = "get_filters")]
161 pub fn filters(&self) -> Option<gio::ListModel> {
162 unsafe { from_glib_none(ffi::gtk_file_dialog_get_filters(self.to_glib_none().0)) }
163 }
164
165 #[doc(alias = "gtk_file_dialog_get_initial_file")]
172 #[doc(alias = "get_initial_file")]
173 #[doc(alias = "initial-file")]
174 pub fn initial_file(&self) -> Option<gio::File> {
175 unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_file(self.to_glib_none().0)) }
176 }
177
178 #[doc(alias = "gtk_file_dialog_get_initial_folder")]
185 #[doc(alias = "get_initial_folder")]
186 #[doc(alias = "initial-folder")]
187 pub fn initial_folder(&self) -> Option<gio::File> {
188 unsafe {
189 from_glib_none(ffi::gtk_file_dialog_get_initial_folder(
190 self.to_glib_none().0,
191 ))
192 }
193 }
194
195 #[doc(alias = "gtk_file_dialog_get_initial_name")]
201 #[doc(alias = "get_initial_name")]
202 #[doc(alias = "initial-name")]
203 pub fn initial_name(&self) -> Option<glib::GString> {
204 unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_name(self.to_glib_none().0)) }
205 }
206
207 #[doc(alias = "gtk_file_dialog_get_modal")]
214 #[doc(alias = "get_modal")]
215 #[doc(alias = "modal")]
216 pub fn is_modal(&self) -> bool {
217 unsafe { from_glib(ffi::gtk_file_dialog_get_modal(self.to_glib_none().0)) }
218 }
219
220 #[doc(alias = "gtk_file_dialog_get_title")]
226 #[doc(alias = "get_title")]
227 pub fn title(&self) -> glib::GString {
228 unsafe { from_glib_none(ffi::gtk_file_dialog_get_title(self.to_glib_none().0)) }
229 }
230
231 #[doc(alias = "gtk_file_dialog_open")]
244 pub fn open<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
245 &self,
246 parent: Option<&impl IsA<Window>>,
247 cancellable: Option<&impl IsA<gio::Cancellable>>,
248 callback: P,
249 ) {
250 let main_context = glib::MainContext::ref_thread_default();
251 let is_main_context_owner = main_context.is_owner();
252 let has_acquired_main_context = (!is_main_context_owner)
253 .then(|| main_context.acquire().ok())
254 .flatten();
255 assert!(
256 is_main_context_owner || has_acquired_main_context.is_some(),
257 "Async operations only allowed if the thread is owning the MainContext"
258 );
259
260 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
261 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
262 unsafe extern "C" fn open_trampoline<
263 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
264 >(
265 _source_object: *mut glib::gobject_ffi::GObject,
266 res: *mut gio::ffi::GAsyncResult,
267 user_data: glib::ffi::gpointer,
268 ) {
269 let mut error = std::ptr::null_mut();
270 let ret = ffi::gtk_file_dialog_open_finish(_source_object as *mut _, res, &mut error);
271 let result = if error.is_null() {
272 Ok(from_glib_full(ret))
273 } else {
274 Err(from_glib_full(error))
275 };
276 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
277 Box_::from_raw(user_data as *mut _);
278 let callback: P = callback.into_inner();
279 callback(result);
280 }
281 let callback = open_trampoline::<P>;
282 unsafe {
283 ffi::gtk_file_dialog_open(
284 self.to_glib_none().0,
285 parent.map(|p| p.as_ref()).to_glib_none().0,
286 cancellable.map(|p| p.as_ref()).to_glib_none().0,
287 Some(callback),
288 Box_::into_raw(user_data) as *mut _,
289 );
290 }
291 }
292
293 pub fn open_future(
294 &self,
295 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
296 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
297 let parent = parent.map(ToOwned::to_owned);
298 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
299 obj.open(
300 parent.as_ref().map(::std::borrow::Borrow::borrow),
301 Some(cancellable),
302 move |res| {
303 send.resolve(res);
304 },
305 );
306 }))
307 }
308
309 #[doc(alias = "gtk_file_dialog_open_multiple")]
325 pub fn open_multiple<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
326 &self,
327 parent: Option<&impl IsA<Window>>,
328 cancellable: Option<&impl IsA<gio::Cancellable>>,
329 callback: P,
330 ) {
331 let main_context = glib::MainContext::ref_thread_default();
332 let is_main_context_owner = main_context.is_owner();
333 let has_acquired_main_context = (!is_main_context_owner)
334 .then(|| main_context.acquire().ok())
335 .flatten();
336 assert!(
337 is_main_context_owner || has_acquired_main_context.is_some(),
338 "Async operations only allowed if the thread is owning the MainContext"
339 );
340
341 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
342 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
343 unsafe extern "C" fn open_multiple_trampoline<
344 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
345 >(
346 _source_object: *mut glib::gobject_ffi::GObject,
347 res: *mut gio::ffi::GAsyncResult,
348 user_data: glib::ffi::gpointer,
349 ) {
350 let mut error = std::ptr::null_mut();
351 let ret = ffi::gtk_file_dialog_open_multiple_finish(
352 _source_object as *mut _,
353 res,
354 &mut error,
355 );
356 let result = if error.is_null() {
357 Ok(from_glib_full(ret))
358 } else {
359 Err(from_glib_full(error))
360 };
361 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
362 Box_::from_raw(user_data as *mut _);
363 let callback: P = callback.into_inner();
364 callback(result);
365 }
366 let callback = open_multiple_trampoline::<P>;
367 unsafe {
368 ffi::gtk_file_dialog_open_multiple(
369 self.to_glib_none().0,
370 parent.map(|p| p.as_ref()).to_glib_none().0,
371 cancellable.map(|p| p.as_ref()).to_glib_none().0,
372 Some(callback),
373 Box_::into_raw(user_data) as *mut _,
374 );
375 }
376 }
377
378 pub fn open_multiple_future(
379 &self,
380 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
381 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
382 {
383 let parent = parent.map(ToOwned::to_owned);
384 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
385 obj.open_multiple(
386 parent.as_ref().map(::std::borrow::Borrow::borrow),
387 Some(cancellable),
388 move |res| {
389 send.resolve(res);
390 },
391 );
392 }))
393 }
394
395 #[cfg(feature = "v4_18")]
414 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
415 #[doc(alias = "gtk_file_dialog_open_multiple_text_files")]
416 pub fn open_multiple_text_files<
417 P: FnOnce(Result<(Option<gio::ListModel>, glib::GString), glib::Error>) + 'static,
418 >(
419 &self,
420 parent: Option<&impl IsA<Window>>,
421 cancellable: Option<&impl IsA<gio::Cancellable>>,
422 callback: P,
423 ) {
424 let main_context = glib::MainContext::ref_thread_default();
425 let is_main_context_owner = main_context.is_owner();
426 let has_acquired_main_context = (!is_main_context_owner)
427 .then(|| main_context.acquire().ok())
428 .flatten();
429 assert!(
430 is_main_context_owner || has_acquired_main_context.is_some(),
431 "Async operations only allowed if the thread is owning the MainContext"
432 );
433
434 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
435 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
436 unsafe extern "C" fn open_multiple_text_files_trampoline<
437 P: FnOnce(Result<(Option<gio::ListModel>, glib::GString), glib::Error>) + 'static,
438 >(
439 _source_object: *mut glib::gobject_ffi::GObject,
440 res: *mut gio::ffi::GAsyncResult,
441 user_data: glib::ffi::gpointer,
442 ) {
443 let mut error = std::ptr::null_mut();
444 let mut encoding = std::ptr::null();
445 let ret = ffi::gtk_file_dialog_open_multiple_text_files_finish(
446 _source_object as *mut _,
447 res,
448 &mut encoding,
449 &mut error,
450 );
451 let result = if error.is_null() {
452 Ok((from_glib_full(ret), from_glib_none(encoding)))
453 } else {
454 Err(from_glib_full(error))
455 };
456 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
457 Box_::from_raw(user_data as *mut _);
458 let callback: P = callback.into_inner();
459 callback(result);
460 }
461 let callback = open_multiple_text_files_trampoline::<P>;
462 unsafe {
463 ffi::gtk_file_dialog_open_multiple_text_files(
464 self.to_glib_none().0,
465 parent.map(|p| p.as_ref()).to_glib_none().0,
466 cancellable.map(|p| p.as_ref()).to_glib_none().0,
467 Some(callback),
468 Box_::into_raw(user_data) as *mut _,
469 );
470 }
471 }
472
473 #[cfg(feature = "v4_18")]
474 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
475 pub fn open_multiple_text_files_future(
476 &self,
477 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
478 ) -> Pin<
479 Box_<
480 dyn std::future::Future<
481 Output = Result<(Option<gio::ListModel>, glib::GString), glib::Error>,
482 > + 'static,
483 >,
484 > {
485 let parent = parent.map(ToOwned::to_owned);
486 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
487 obj.open_multiple_text_files(
488 parent.as_ref().map(::std::borrow::Borrow::borrow),
489 Some(cancellable),
490 move |res| {
491 send.resolve(res);
492 },
493 );
494 }))
495 }
496
497 #[cfg(feature = "v4_18")]
512 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
513 #[doc(alias = "gtk_file_dialog_open_text_file")]
514 pub fn open_text_file<
515 P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
516 >(
517 &self,
518 parent: Option<&impl IsA<Window>>,
519 cancellable: Option<&impl IsA<gio::Cancellable>>,
520 callback: P,
521 ) {
522 let main_context = glib::MainContext::ref_thread_default();
523 let is_main_context_owner = main_context.is_owner();
524 let has_acquired_main_context = (!is_main_context_owner)
525 .then(|| main_context.acquire().ok())
526 .flatten();
527 assert!(
528 is_main_context_owner || has_acquired_main_context.is_some(),
529 "Async operations only allowed if the thread is owning the MainContext"
530 );
531
532 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
533 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
534 unsafe extern "C" fn open_text_file_trampoline<
535 P: FnOnce(Result<(Option<gio::File>, glib::GString), glib::Error>) + 'static,
536 >(
537 _source_object: *mut glib::gobject_ffi::GObject,
538 res: *mut gio::ffi::GAsyncResult,
539 user_data: glib::ffi::gpointer,
540 ) {
541 let mut error = std::ptr::null_mut();
542 let mut encoding = std::ptr::null();
543 let ret = ffi::gtk_file_dialog_open_text_file_finish(
544 _source_object as *mut _,
545 res,
546 &mut encoding,
547 &mut error,
548 );
549 let result = if error.is_null() {
550 Ok((from_glib_full(ret), from_glib_none(encoding)))
551 } else {
552 Err(from_glib_full(error))
553 };
554 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
555 Box_::from_raw(user_data as *mut _);
556 let callback: P = callback.into_inner();
557 callback(result);
558 }
559 let callback = open_text_file_trampoline::<P>;
560 unsafe {
561 ffi::gtk_file_dialog_open_text_file(
562 self.to_glib_none().0,
563 parent.map(|p| p.as_ref()).to_glib_none().0,
564 cancellable.map(|p| p.as_ref()).to_glib_none().0,
565 Some(callback),
566 Box_::into_raw(user_data) as *mut _,
567 );
568 }
569 }
570
571 #[cfg(feature = "v4_18")]
572 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
573 pub fn open_text_file_future(
574 &self,
575 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
576 ) -> Pin<
577 Box_<
578 dyn std::future::Future<
579 Output = Result<(Option<gio::File>, glib::GString), glib::Error>,
580 > + 'static,
581 >,
582 > {
583 let parent = parent.map(ToOwned::to_owned);
584 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
585 obj.open_text_file(
586 parent.as_ref().map(::std::borrow::Borrow::borrow),
587 Some(cancellable),
588 move |res| {
589 send.resolve(res);
590 },
591 );
592 }))
593 }
594
595 #[doc(alias = "gtk_file_dialog_save")]
608 pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
609 &self,
610 parent: Option<&impl IsA<Window>>,
611 cancellable: Option<&impl IsA<gio::Cancellable>>,
612 callback: P,
613 ) {
614 let main_context = glib::MainContext::ref_thread_default();
615 let is_main_context_owner = main_context.is_owner();
616 let has_acquired_main_context = (!is_main_context_owner)
617 .then(|| main_context.acquire().ok())
618 .flatten();
619 assert!(
620 is_main_context_owner || has_acquired_main_context.is_some(),
621 "Async operations only allowed if the thread is owning the MainContext"
622 );
623
624 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
625 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
626 unsafe extern "C" fn save_trampoline<
627 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
628 >(
629 _source_object: *mut glib::gobject_ffi::GObject,
630 res: *mut gio::ffi::GAsyncResult,
631 user_data: glib::ffi::gpointer,
632 ) {
633 let mut error = std::ptr::null_mut();
634 let ret = ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
635 let result = if error.is_null() {
636 Ok(from_glib_full(ret))
637 } else {
638 Err(from_glib_full(error))
639 };
640 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
641 Box_::from_raw(user_data as *mut _);
642 let callback: P = callback.into_inner();
643 callback(result);
644 }
645 let callback = save_trampoline::<P>;
646 unsafe {
647 ffi::gtk_file_dialog_save(
648 self.to_glib_none().0,
649 parent.map(|p| p.as_ref()).to_glib_none().0,
650 cancellable.map(|p| p.as_ref()).to_glib_none().0,
651 Some(callback),
652 Box_::into_raw(user_data) as *mut _,
653 );
654 }
655 }
656
657 pub fn save_future(
658 &self,
659 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
660 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
661 let parent = parent.map(ToOwned::to_owned);
662 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
663 obj.save(
664 parent.as_ref().map(::std::borrow::Borrow::borrow),
665 Some(cancellable),
666 move |res| {
667 send.resolve(res);
668 },
669 );
670 }))
671 }
672
673 #[cfg(feature = "v4_18")]
689 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
690 #[doc(alias = "gtk_file_dialog_save_text_file")]
691 pub fn save_text_file<
692 P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>) + 'static,
693 >(
694 &self,
695 parent: Option<&impl IsA<Window>>,
696 cancellable: Option<&impl IsA<gio::Cancellable>>,
697 callback: P,
698 ) {
699 let main_context = glib::MainContext::ref_thread_default();
700 let is_main_context_owner = main_context.is_owner();
701 let has_acquired_main_context = (!is_main_context_owner)
702 .then(|| main_context.acquire().ok())
703 .flatten();
704 assert!(
705 is_main_context_owner || has_acquired_main_context.is_some(),
706 "Async operations only allowed if the thread is owning the MainContext"
707 );
708
709 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
710 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
711 unsafe extern "C" fn save_text_file_trampoline<
712 P: FnOnce(Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>)
713 + 'static,
714 >(
715 _source_object: *mut glib::gobject_ffi::GObject,
716 res: *mut gio::ffi::GAsyncResult,
717 user_data: glib::ffi::gpointer,
718 ) {
719 let mut error = std::ptr::null_mut();
720 let mut encoding = std::ptr::null();
721 let mut line_ending = std::ptr::null();
722 let ret = ffi::gtk_file_dialog_save_text_file_finish(
723 _source_object as *mut _,
724 res,
725 &mut encoding,
726 &mut line_ending,
727 &mut error,
728 );
729 let result = if error.is_null() {
730 Ok((
731 from_glib_full(ret),
732 from_glib_none(encoding),
733 from_glib_none(line_ending),
734 ))
735 } else {
736 Err(from_glib_full(error))
737 };
738 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
739 Box_::from_raw(user_data as *mut _);
740 let callback: P = callback.into_inner();
741 callback(result);
742 }
743 let callback = save_text_file_trampoline::<P>;
744 unsafe {
745 ffi::gtk_file_dialog_save_text_file(
746 self.to_glib_none().0,
747 parent.map(|p| p.as_ref()).to_glib_none().0,
748 cancellable.map(|p| p.as_ref()).to_glib_none().0,
749 Some(callback),
750 Box_::into_raw(user_data) as *mut _,
751 );
752 }
753 }
754
755 #[cfg(feature = "v4_18")]
756 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
757 pub fn save_text_file_future(
758 &self,
759 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
760 ) -> Pin<
761 Box_<
762 dyn std::future::Future<
763 Output = Result<(Option<gio::File>, glib::GString, glib::GString), glib::Error>,
764 > + 'static,
765 >,
766 > {
767 let parent = parent.map(ToOwned::to_owned);
768 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
769 obj.save_text_file(
770 parent.as_ref().map(::std::borrow::Borrow::borrow),
771 Some(cancellable),
772 move |res| {
773 send.resolve(res);
774 },
775 );
776 }))
777 }
778
779 #[doc(alias = "gtk_file_dialog_select_folder")]
796 pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
797 &self,
798 parent: Option<&impl IsA<Window>>,
799 cancellable: Option<&impl IsA<gio::Cancellable>>,
800 callback: P,
801 ) {
802 let main_context = glib::MainContext::ref_thread_default();
803 let is_main_context_owner = main_context.is_owner();
804 let has_acquired_main_context = (!is_main_context_owner)
805 .then(|| main_context.acquire().ok())
806 .flatten();
807 assert!(
808 is_main_context_owner || has_acquired_main_context.is_some(),
809 "Async operations only allowed if the thread is owning the MainContext"
810 );
811
812 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
813 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
814 unsafe extern "C" fn select_folder_trampoline<
815 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
816 >(
817 _source_object: *mut glib::gobject_ffi::GObject,
818 res: *mut gio::ffi::GAsyncResult,
819 user_data: glib::ffi::gpointer,
820 ) {
821 let mut error = std::ptr::null_mut();
822 let ret = ffi::gtk_file_dialog_select_folder_finish(
823 _source_object as *mut _,
824 res,
825 &mut error,
826 );
827 let result = if error.is_null() {
828 Ok(from_glib_full(ret))
829 } else {
830 Err(from_glib_full(error))
831 };
832 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
833 Box_::from_raw(user_data as *mut _);
834 let callback: P = callback.into_inner();
835 callback(result);
836 }
837 let callback = select_folder_trampoline::<P>;
838 unsafe {
839 ffi::gtk_file_dialog_select_folder(
840 self.to_glib_none().0,
841 parent.map(|p| p.as_ref()).to_glib_none().0,
842 cancellable.map(|p| p.as_ref()).to_glib_none().0,
843 Some(callback),
844 Box_::into_raw(user_data) as *mut _,
845 );
846 }
847 }
848
849 pub fn select_folder_future(
850 &self,
851 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
852 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
853 let parent = parent.map(ToOwned::to_owned);
854 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
855 obj.select_folder(
856 parent.as_ref().map(::std::borrow::Borrow::borrow),
857 Some(cancellable),
858 move |res| {
859 send.resolve(res);
860 },
861 );
862 }))
863 }
864
865 #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
882 pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
883 &self,
884 parent: Option<&impl IsA<Window>>,
885 cancellable: Option<&impl IsA<gio::Cancellable>>,
886 callback: P,
887 ) {
888 let main_context = glib::MainContext::ref_thread_default();
889 let is_main_context_owner = main_context.is_owner();
890 let has_acquired_main_context = (!is_main_context_owner)
891 .then(|| main_context.acquire().ok())
892 .flatten();
893 assert!(
894 is_main_context_owner || has_acquired_main_context.is_some(),
895 "Async operations only allowed if the thread is owning the MainContext"
896 );
897
898 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
899 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
900 unsafe extern "C" fn select_multiple_folders_trampoline<
901 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
902 >(
903 _source_object: *mut glib::gobject_ffi::GObject,
904 res: *mut gio::ffi::GAsyncResult,
905 user_data: glib::ffi::gpointer,
906 ) {
907 let mut error = std::ptr::null_mut();
908 let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
909 _source_object as *mut _,
910 res,
911 &mut error,
912 );
913 let result = if error.is_null() {
914 Ok(from_glib_full(ret))
915 } else {
916 Err(from_glib_full(error))
917 };
918 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
919 Box_::from_raw(user_data as *mut _);
920 let callback: P = callback.into_inner();
921 callback(result);
922 }
923 let callback = select_multiple_folders_trampoline::<P>;
924 unsafe {
925 ffi::gtk_file_dialog_select_multiple_folders(
926 self.to_glib_none().0,
927 parent.map(|p| p.as_ref()).to_glib_none().0,
928 cancellable.map(|p| p.as_ref()).to_glib_none().0,
929 Some(callback),
930 Box_::into_raw(user_data) as *mut _,
931 );
932 }
933 }
934
935 pub fn select_multiple_folders_future(
936 &self,
937 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
938 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
939 {
940 let parent = parent.map(ToOwned::to_owned);
941 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
942 obj.select_multiple_folders(
943 parent.as_ref().map(::std::borrow::Borrow::borrow),
944 Some(cancellable),
945 move |res| {
946 send.resolve(res);
947 },
948 );
949 }))
950 }
951
952 #[doc(alias = "gtk_file_dialog_set_accept_label")]
960 #[doc(alias = "accept-label")]
961 pub fn set_accept_label(&self, accept_label: Option<&str>) {
962 unsafe {
963 ffi::gtk_file_dialog_set_accept_label(
964 self.to_glib_none().0,
965 accept_label.to_glib_none().0,
966 );
967 }
968 }
969
970 #[doc(alias = "gtk_file_dialog_set_default_filter")]
979 #[doc(alias = "default-filter")]
980 pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
981 unsafe {
982 ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
983 }
984 }
985
986 #[doc(alias = "gtk_file_dialog_set_filters")]
991 #[doc(alias = "filters")]
992 pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
993 unsafe {
994 ffi::gtk_file_dialog_set_filters(
995 self.to_glib_none().0,
996 filters.map(|p| p.as_ref()).to_glib_none().0,
997 );
998 }
999 }
1000
1001 #[doc(alias = "gtk_file_dialog_set_initial_file")]
1011 #[doc(alias = "initial-file")]
1012 pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
1013 unsafe {
1014 ffi::gtk_file_dialog_set_initial_file(
1015 self.to_glib_none().0,
1016 file.map(|p| p.as_ref()).to_glib_none().0,
1017 );
1018 }
1019 }
1020
1021 #[doc(alias = "gtk_file_dialog_set_initial_folder")]
1026 #[doc(alias = "initial-folder")]
1027 pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
1028 unsafe {
1029 ffi::gtk_file_dialog_set_initial_folder(
1030 self.to_glib_none().0,
1031 folder.map(|p| p.as_ref()).to_glib_none().0,
1032 );
1033 }
1034 }
1035
1036 #[doc(alias = "gtk_file_dialog_set_initial_name")]
1047 #[doc(alias = "initial-name")]
1048 pub fn set_initial_name(&self, name: Option<&str>) {
1049 unsafe {
1050 ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
1051 }
1052 }
1053
1054 #[doc(alias = "gtk_file_dialog_set_modal")]
1059 #[doc(alias = "modal")]
1060 pub fn set_modal(&self, modal: bool) {
1061 unsafe {
1062 ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
1063 }
1064 }
1065
1066 #[doc(alias = "gtk_file_dialog_set_title")]
1070 #[doc(alias = "title")]
1071 pub fn set_title(&self, title: &str) {
1072 unsafe {
1073 ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
1074 }
1075 }
1076
1077 #[cfg(feature = "v4_10")]
1078 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1079 #[doc(alias = "accept-label")]
1080 pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1081 unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
1082 this: *mut ffi::GtkFileDialog,
1083 _param_spec: glib::ffi::gpointer,
1084 f: glib::ffi::gpointer,
1085 ) {
1086 let f: &F = &*(f as *const F);
1087 f(&from_glib_borrow(this))
1088 }
1089 unsafe {
1090 let f: Box_<F> = Box_::new(f);
1091 connect_raw(
1092 self.as_ptr() as *mut _,
1093 b"notify::accept-label\0".as_ptr() as *const _,
1094 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1095 notify_accept_label_trampoline::<F> as *const (),
1096 )),
1097 Box_::into_raw(f),
1098 )
1099 }
1100 }
1101
1102 #[cfg(feature = "v4_10")]
1103 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1104 #[doc(alias = "default-filter")]
1105 pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1106 unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
1107 this: *mut ffi::GtkFileDialog,
1108 _param_spec: glib::ffi::gpointer,
1109 f: glib::ffi::gpointer,
1110 ) {
1111 let f: &F = &*(f as *const F);
1112 f(&from_glib_borrow(this))
1113 }
1114 unsafe {
1115 let f: Box_<F> = Box_::new(f);
1116 connect_raw(
1117 self.as_ptr() as *mut _,
1118 b"notify::default-filter\0".as_ptr() as *const _,
1119 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1120 notify_default_filter_trampoline::<F> as *const (),
1121 )),
1122 Box_::into_raw(f),
1123 )
1124 }
1125 }
1126
1127 #[cfg(feature = "v4_10")]
1128 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1129 #[doc(alias = "filters")]
1130 pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1131 unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
1132 this: *mut ffi::GtkFileDialog,
1133 _param_spec: glib::ffi::gpointer,
1134 f: glib::ffi::gpointer,
1135 ) {
1136 let f: &F = &*(f as *const F);
1137 f(&from_glib_borrow(this))
1138 }
1139 unsafe {
1140 let f: Box_<F> = Box_::new(f);
1141 connect_raw(
1142 self.as_ptr() as *mut _,
1143 b"notify::filters\0".as_ptr() as *const _,
1144 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1145 notify_filters_trampoline::<F> as *const (),
1146 )),
1147 Box_::into_raw(f),
1148 )
1149 }
1150 }
1151
1152 #[cfg(feature = "v4_10")]
1153 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1154 #[doc(alias = "initial-file")]
1155 pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1156 unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
1157 this: *mut ffi::GtkFileDialog,
1158 _param_spec: glib::ffi::gpointer,
1159 f: glib::ffi::gpointer,
1160 ) {
1161 let f: &F = &*(f as *const F);
1162 f(&from_glib_borrow(this))
1163 }
1164 unsafe {
1165 let f: Box_<F> = Box_::new(f);
1166 connect_raw(
1167 self.as_ptr() as *mut _,
1168 b"notify::initial-file\0".as_ptr() as *const _,
1169 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1170 notify_initial_file_trampoline::<F> as *const (),
1171 )),
1172 Box_::into_raw(f),
1173 )
1174 }
1175 }
1176
1177 #[cfg(feature = "v4_10")]
1178 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1179 #[doc(alias = "initial-folder")]
1180 pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1181 unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
1182 this: *mut ffi::GtkFileDialog,
1183 _param_spec: glib::ffi::gpointer,
1184 f: glib::ffi::gpointer,
1185 ) {
1186 let f: &F = &*(f as *const F);
1187 f(&from_glib_borrow(this))
1188 }
1189 unsafe {
1190 let f: Box_<F> = Box_::new(f);
1191 connect_raw(
1192 self.as_ptr() as *mut _,
1193 b"notify::initial-folder\0".as_ptr() as *const _,
1194 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1195 notify_initial_folder_trampoline::<F> as *const (),
1196 )),
1197 Box_::into_raw(f),
1198 )
1199 }
1200 }
1201
1202 #[cfg(feature = "v4_10")]
1203 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1204 #[doc(alias = "initial-name")]
1205 pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1206 unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
1207 this: *mut ffi::GtkFileDialog,
1208 _param_spec: glib::ffi::gpointer,
1209 f: glib::ffi::gpointer,
1210 ) {
1211 let f: &F = &*(f as *const F);
1212 f(&from_glib_borrow(this))
1213 }
1214 unsafe {
1215 let f: Box_<F> = Box_::new(f);
1216 connect_raw(
1217 self.as_ptr() as *mut _,
1218 b"notify::initial-name\0".as_ptr() as *const _,
1219 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1220 notify_initial_name_trampoline::<F> as *const (),
1221 )),
1222 Box_::into_raw(f),
1223 )
1224 }
1225 }
1226
1227 #[cfg(feature = "v4_10")]
1228 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1229 #[doc(alias = "modal")]
1230 pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1231 unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
1232 this: *mut ffi::GtkFileDialog,
1233 _param_spec: glib::ffi::gpointer,
1234 f: glib::ffi::gpointer,
1235 ) {
1236 let f: &F = &*(f as *const F);
1237 f(&from_glib_borrow(this))
1238 }
1239 unsafe {
1240 let f: Box_<F> = Box_::new(f);
1241 connect_raw(
1242 self.as_ptr() as *mut _,
1243 b"notify::modal\0".as_ptr() as *const _,
1244 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1245 notify_modal_trampoline::<F> as *const (),
1246 )),
1247 Box_::into_raw(f),
1248 )
1249 }
1250 }
1251
1252 #[cfg(feature = "v4_10")]
1253 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1254 #[doc(alias = "title")]
1255 pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1256 unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
1257 this: *mut ffi::GtkFileDialog,
1258 _param_spec: glib::ffi::gpointer,
1259 f: glib::ffi::gpointer,
1260 ) {
1261 let f: &F = &*(f as *const F);
1262 f(&from_glib_borrow(this))
1263 }
1264 unsafe {
1265 let f: Box_<F> = Box_::new(f);
1266 connect_raw(
1267 self.as_ptr() as *mut _,
1268 b"notify::title\0".as_ptr() as *const _,
1269 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1270 notify_title_trampoline::<F> as *const (),
1271 )),
1272 Box_::into_raw(f),
1273 )
1274 }
1275 }
1276}
1277
1278#[cfg(feature = "v4_10")]
1279#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1280impl Default for FileDialog {
1281 fn default() -> Self {
1282 Self::new()
1283 }
1284}
1285
1286#[must_use = "The builder must be built to be used"]
1291pub struct FileDialogBuilder {
1292 builder: glib::object::ObjectBuilder<'static, FileDialog>,
1293}
1294
1295impl FileDialogBuilder {
1296 fn new() -> Self {
1297 Self {
1298 builder: glib::object::Object::builder(),
1299 }
1300 }
1301
1302 #[cfg(feature = "v4_10")]
1304 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1305 pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1306 Self {
1307 builder: self.builder.property("accept-label", accept_label.into()),
1308 }
1309 }
1310
1311 #[cfg(feature = "v4_10")]
1322 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1323 pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1324 Self {
1325 builder: self
1326 .builder
1327 .property("default-filter", default_filter.clone()),
1328 }
1329 }
1330
1331 #[cfg(feature = "v4_10")]
1336 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1337 pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1338 Self {
1339 builder: self.builder.property("filters", filters.clone().upcast()),
1340 }
1341 }
1342
1343 #[cfg(feature = "v4_10")]
1350 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1351 pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1352 Self {
1353 builder: self
1354 .builder
1355 .property("initial-file", initial_file.clone().upcast()),
1356 }
1357 }
1358
1359 #[cfg(feature = "v4_10")]
1363 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1364 pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1365 Self {
1366 builder: self
1367 .builder
1368 .property("initial-folder", initial_folder.clone().upcast()),
1369 }
1370 }
1371
1372 #[cfg(feature = "v4_10")]
1376 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1377 pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1378 Self {
1379 builder: self.builder.property("initial-name", initial_name.into()),
1380 }
1381 }
1382
1383 #[cfg(feature = "v4_10")]
1385 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1386 pub fn modal(self, modal: bool) -> Self {
1387 Self {
1388 builder: self.builder.property("modal", modal),
1389 }
1390 }
1391
1392 #[cfg(feature = "v4_10")]
1394 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1395 pub fn title(self, title: impl Into<glib::GString>) -> Self {
1396 Self {
1397 builder: self.builder.property("title", title.into()),
1398 }
1399 }
1400
1401 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1404 pub fn build(self) -> FileDialog {
1405 assert_initialized_main_thread!();
1406 self.builder.build()
1407 }
1408}