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")]
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 #[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 pub fn builder() -> FileDialogBuilder {
122 FileDialogBuilder::new()
123 }
124
125 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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#[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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}