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<(gio::ListModel, glib::GString), glib::Error>) + 'static,
420 >(
421 &self,
422 parent: Option<&impl IsA<Window>>,
423 cancellable: Option<&impl IsA<gio::Cancellable>>,
424 callback: P,
425 ) {
426 let main_context = glib::MainContext::ref_thread_default();
427 let is_main_context_owner = main_context.is_owner();
428 let has_acquired_main_context = (!is_main_context_owner)
429 .then(|| main_context.acquire().ok())
430 .flatten();
431 assert!(
432 is_main_context_owner || has_acquired_main_context.is_some(),
433 "Async operations only allowed if the thread is owning the MainContext"
434 );
435
436 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
437 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
438 unsafe extern "C" fn open_multiple_text_files_trampoline<
439 P: FnOnce(Result<(gio::ListModel, glib::GString), glib::Error>) + 'static,
440 >(
441 _source_object: *mut glib::gobject_ffi::GObject,
442 res: *mut gio::ffi::GAsyncResult,
443 user_data: glib::ffi::gpointer,
444 ) {
445 let mut error = std::ptr::null_mut();
446 let mut encoding = std::ptr::null();
447 let ret = ffi::gtk_file_dialog_open_multiple_text_files_finish(
448 _source_object as *mut _,
449 res,
450 &mut encoding,
451 &mut error,
452 );
453 let result = if error.is_null() {
454 Ok((from_glib_full(ret), from_glib_none(encoding)))
455 } else {
456 Err(from_glib_full(error))
457 };
458 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
459 Box_::from_raw(user_data as *mut _);
460 let callback: P = callback.into_inner();
461 callback(result);
462 }
463 let callback = open_multiple_text_files_trampoline::<P>;
464 unsafe {
465 ffi::gtk_file_dialog_open_multiple_text_files(
466 self.to_glib_none().0,
467 parent.map(|p| p.as_ref()).to_glib_none().0,
468 cancellable.map(|p| p.as_ref()).to_glib_none().0,
469 Some(callback),
470 Box_::into_raw(user_data) as *mut _,
471 );
472 }
473 }
474
475 #[cfg(feature = "v4_18")]
476 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
477 pub fn open_multiple_text_files_future(
478 &self,
479 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
480 ) -> Pin<
481 Box_<
482 dyn std::future::Future<Output = Result<(gio::ListModel, glib::GString), glib::Error>>
483 + 'static,
484 >,
485 > {
486 let parent = parent.map(ToOwned::to_owned);
487 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
488 obj.open_multiple_text_files(
489 parent.as_ref().map(::std::borrow::Borrow::borrow),
490 Some(cancellable),
491 move |res| {
492 send.resolve(res);
493 },
494 );
495 }))
496 }
497
498 #[cfg(feature = "v4_18")]
513 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
514 #[doc(alias = "gtk_file_dialog_open_text_file")]
515 pub fn open_text_file<P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static>(
516 &self,
517 parent: Option<&impl IsA<Window>>,
518 cancellable: Option<&impl IsA<gio::Cancellable>>,
519 callback: P,
520 ) {
521 let main_context = glib::MainContext::ref_thread_default();
522 let is_main_context_owner = main_context.is_owner();
523 let has_acquired_main_context = (!is_main_context_owner)
524 .then(|| main_context.acquire().ok())
525 .flatten();
526 assert!(
527 is_main_context_owner || has_acquired_main_context.is_some(),
528 "Async operations only allowed if the thread is owning the MainContext"
529 );
530
531 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
532 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
533 unsafe extern "C" fn open_text_file_trampoline<
534 P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static,
535 >(
536 _source_object: *mut glib::gobject_ffi::GObject,
537 res: *mut gio::ffi::GAsyncResult,
538 user_data: glib::ffi::gpointer,
539 ) {
540 let mut error = std::ptr::null_mut();
541 let mut encoding = std::ptr::null();
542 let ret = ffi::gtk_file_dialog_open_text_file_finish(
543 _source_object as *mut _,
544 res,
545 &mut encoding,
546 &mut error,
547 );
548 let result = if error.is_null() {
549 Ok((from_glib_full(ret), from_glib_none(encoding)))
550 } else {
551 Err(from_glib_full(error))
552 };
553 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
554 Box_::from_raw(user_data as *mut _);
555 let callback: P = callback.into_inner();
556 callback(result);
557 }
558 let callback = open_text_file_trampoline::<P>;
559 unsafe {
560 ffi::gtk_file_dialog_open_text_file(
561 self.to_glib_none().0,
562 parent.map(|p| p.as_ref()).to_glib_none().0,
563 cancellable.map(|p| p.as_ref()).to_glib_none().0,
564 Some(callback),
565 Box_::into_raw(user_data) as *mut _,
566 );
567 }
568 }
569
570 #[cfg(feature = "v4_18")]
571 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
572 pub fn open_text_file_future(
573 &self,
574 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
575 ) -> Pin<
576 Box_<
577 dyn std::future::Future<Output = Result<(gio::File, glib::GString), glib::Error>>
578 + 'static,
579 >,
580 > {
581 let parent = parent.map(ToOwned::to_owned);
582 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
583 obj.open_text_file(
584 parent.as_ref().map(::std::borrow::Borrow::borrow),
585 Some(cancellable),
586 move |res| {
587 send.resolve(res);
588 },
589 );
590 }))
591 }
592
593 #[doc(alias = "gtk_file_dialog_save")]
606 pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
607 &self,
608 parent: Option<&impl IsA<Window>>,
609 cancellable: Option<&impl IsA<gio::Cancellable>>,
610 callback: P,
611 ) {
612 let main_context = glib::MainContext::ref_thread_default();
613 let is_main_context_owner = main_context.is_owner();
614 let has_acquired_main_context = (!is_main_context_owner)
615 .then(|| main_context.acquire().ok())
616 .flatten();
617 assert!(
618 is_main_context_owner || has_acquired_main_context.is_some(),
619 "Async operations only allowed if the thread is owning the MainContext"
620 );
621
622 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
623 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
624 unsafe extern "C" fn save_trampoline<
625 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
626 >(
627 _source_object: *mut glib::gobject_ffi::GObject,
628 res: *mut gio::ffi::GAsyncResult,
629 user_data: glib::ffi::gpointer,
630 ) {
631 let mut error = std::ptr::null_mut();
632 let ret = ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
633 let result = if error.is_null() {
634 Ok(from_glib_full(ret))
635 } else {
636 Err(from_glib_full(error))
637 };
638 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
639 Box_::from_raw(user_data as *mut _);
640 let callback: P = callback.into_inner();
641 callback(result);
642 }
643 let callback = save_trampoline::<P>;
644 unsafe {
645 ffi::gtk_file_dialog_save(
646 self.to_glib_none().0,
647 parent.map(|p| p.as_ref()).to_glib_none().0,
648 cancellable.map(|p| p.as_ref()).to_glib_none().0,
649 Some(callback),
650 Box_::into_raw(user_data) as *mut _,
651 );
652 }
653 }
654
655 pub fn save_future(
656 &self,
657 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
658 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
659 let parent = parent.map(ToOwned::to_owned);
660 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
661 obj.save(
662 parent.as_ref().map(::std::borrow::Borrow::borrow),
663 Some(cancellable),
664 move |res| {
665 send.resolve(res);
666 },
667 );
668 }))
669 }
670
671 #[cfg(feature = "v4_18")]
687 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
688 #[doc(alias = "gtk_file_dialog_save_text_file")]
689 pub fn save_text_file<
690 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
691 >(
692 &self,
693 parent: Option<&impl IsA<Window>>,
694 cancellable: Option<&impl IsA<gio::Cancellable>>,
695 callback: P,
696 ) {
697 let main_context = glib::MainContext::ref_thread_default();
698 let is_main_context_owner = main_context.is_owner();
699 let has_acquired_main_context = (!is_main_context_owner)
700 .then(|| main_context.acquire().ok())
701 .flatten();
702 assert!(
703 is_main_context_owner || has_acquired_main_context.is_some(),
704 "Async operations only allowed if the thread is owning the MainContext"
705 );
706
707 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
708 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
709 unsafe extern "C" fn save_text_file_trampoline<
710 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
711 >(
712 _source_object: *mut glib::gobject_ffi::GObject,
713 res: *mut gio::ffi::GAsyncResult,
714 user_data: glib::ffi::gpointer,
715 ) {
716 let mut error = std::ptr::null_mut();
717 let mut encoding = std::ptr::null();
718 let mut line_ending = std::ptr::null();
719 let ret = ffi::gtk_file_dialog_save_text_file_finish(
720 _source_object as *mut _,
721 res,
722 &mut encoding,
723 &mut line_ending,
724 &mut error,
725 );
726 let result = if error.is_null() {
727 Ok((
728 from_glib_full(ret),
729 from_glib_none(encoding),
730 from_glib_none(line_ending),
731 ))
732 } else {
733 Err(from_glib_full(error))
734 };
735 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
736 Box_::from_raw(user_data as *mut _);
737 let callback: P = callback.into_inner();
738 callback(result);
739 }
740 let callback = save_text_file_trampoline::<P>;
741 unsafe {
742 ffi::gtk_file_dialog_save_text_file(
743 self.to_glib_none().0,
744 parent.map(|p| p.as_ref()).to_glib_none().0,
745 cancellable.map(|p| p.as_ref()).to_glib_none().0,
746 Some(callback),
747 Box_::into_raw(user_data) as *mut _,
748 );
749 }
750 }
751
752 #[cfg(feature = "v4_18")]
753 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
754 pub fn save_text_file_future(
755 &self,
756 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
757 ) -> Pin<
758 Box_<
759 dyn std::future::Future<
760 Output = Result<(gio::File, glib::GString, glib::GString), glib::Error>,
761 > + 'static,
762 >,
763 > {
764 let parent = parent.map(ToOwned::to_owned);
765 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
766 obj.save_text_file(
767 parent.as_ref().map(::std::borrow::Borrow::borrow),
768 Some(cancellable),
769 move |res| {
770 send.resolve(res);
771 },
772 );
773 }))
774 }
775
776 #[doc(alias = "gtk_file_dialog_select_folder")]
793 pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
794 &self,
795 parent: Option<&impl IsA<Window>>,
796 cancellable: Option<&impl IsA<gio::Cancellable>>,
797 callback: P,
798 ) {
799 let main_context = glib::MainContext::ref_thread_default();
800 let is_main_context_owner = main_context.is_owner();
801 let has_acquired_main_context = (!is_main_context_owner)
802 .then(|| main_context.acquire().ok())
803 .flatten();
804 assert!(
805 is_main_context_owner || has_acquired_main_context.is_some(),
806 "Async operations only allowed if the thread is owning the MainContext"
807 );
808
809 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
810 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
811 unsafe extern "C" fn select_folder_trampoline<
812 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
813 >(
814 _source_object: *mut glib::gobject_ffi::GObject,
815 res: *mut gio::ffi::GAsyncResult,
816 user_data: glib::ffi::gpointer,
817 ) {
818 let mut error = std::ptr::null_mut();
819 let ret = ffi::gtk_file_dialog_select_folder_finish(
820 _source_object as *mut _,
821 res,
822 &mut error,
823 );
824 let result = if error.is_null() {
825 Ok(from_glib_full(ret))
826 } else {
827 Err(from_glib_full(error))
828 };
829 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
830 Box_::from_raw(user_data as *mut _);
831 let callback: P = callback.into_inner();
832 callback(result);
833 }
834 let callback = select_folder_trampoline::<P>;
835 unsafe {
836 ffi::gtk_file_dialog_select_folder(
837 self.to_glib_none().0,
838 parent.map(|p| p.as_ref()).to_glib_none().0,
839 cancellable.map(|p| p.as_ref()).to_glib_none().0,
840 Some(callback),
841 Box_::into_raw(user_data) as *mut _,
842 );
843 }
844 }
845
846 pub fn select_folder_future(
847 &self,
848 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
849 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
850 let parent = parent.map(ToOwned::to_owned);
851 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
852 obj.select_folder(
853 parent.as_ref().map(::std::borrow::Borrow::borrow),
854 Some(cancellable),
855 move |res| {
856 send.resolve(res);
857 },
858 );
859 }))
860 }
861
862 #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
879 pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
880 &self,
881 parent: Option<&impl IsA<Window>>,
882 cancellable: Option<&impl IsA<gio::Cancellable>>,
883 callback: P,
884 ) {
885 let main_context = glib::MainContext::ref_thread_default();
886 let is_main_context_owner = main_context.is_owner();
887 let has_acquired_main_context = (!is_main_context_owner)
888 .then(|| main_context.acquire().ok())
889 .flatten();
890 assert!(
891 is_main_context_owner || has_acquired_main_context.is_some(),
892 "Async operations only allowed if the thread is owning the MainContext"
893 );
894
895 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
896 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
897 unsafe extern "C" fn select_multiple_folders_trampoline<
898 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
899 >(
900 _source_object: *mut glib::gobject_ffi::GObject,
901 res: *mut gio::ffi::GAsyncResult,
902 user_data: glib::ffi::gpointer,
903 ) {
904 let mut error = std::ptr::null_mut();
905 let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
906 _source_object as *mut _,
907 res,
908 &mut error,
909 );
910 let result = if error.is_null() {
911 Ok(from_glib_full(ret))
912 } else {
913 Err(from_glib_full(error))
914 };
915 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
916 Box_::from_raw(user_data as *mut _);
917 let callback: P = callback.into_inner();
918 callback(result);
919 }
920 let callback = select_multiple_folders_trampoline::<P>;
921 unsafe {
922 ffi::gtk_file_dialog_select_multiple_folders(
923 self.to_glib_none().0,
924 parent.map(|p| p.as_ref()).to_glib_none().0,
925 cancellable.map(|p| p.as_ref()).to_glib_none().0,
926 Some(callback),
927 Box_::into_raw(user_data) as *mut _,
928 );
929 }
930 }
931
932 pub fn select_multiple_folders_future(
933 &self,
934 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
935 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
936 {
937 let parent = parent.map(ToOwned::to_owned);
938 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
939 obj.select_multiple_folders(
940 parent.as_ref().map(::std::borrow::Borrow::borrow),
941 Some(cancellable),
942 move |res| {
943 send.resolve(res);
944 },
945 );
946 }))
947 }
948
949 #[doc(alias = "gtk_file_dialog_set_accept_label")]
957 #[doc(alias = "accept-label")]
958 pub fn set_accept_label(&self, accept_label: Option<&str>) {
959 unsafe {
960 ffi::gtk_file_dialog_set_accept_label(
961 self.to_glib_none().0,
962 accept_label.to_glib_none().0,
963 );
964 }
965 }
966
967 #[doc(alias = "gtk_file_dialog_set_default_filter")]
976 #[doc(alias = "default-filter")]
977 pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
978 unsafe {
979 ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
980 }
981 }
982
983 #[doc(alias = "gtk_file_dialog_set_filters")]
988 #[doc(alias = "filters")]
989 pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
990 unsafe {
991 ffi::gtk_file_dialog_set_filters(
992 self.to_glib_none().0,
993 filters.map(|p| p.as_ref()).to_glib_none().0,
994 );
995 }
996 }
997
998 #[doc(alias = "gtk_file_dialog_set_initial_file")]
1008 #[doc(alias = "initial-file")]
1009 pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
1010 unsafe {
1011 ffi::gtk_file_dialog_set_initial_file(
1012 self.to_glib_none().0,
1013 file.map(|p| p.as_ref()).to_glib_none().0,
1014 );
1015 }
1016 }
1017
1018 #[doc(alias = "gtk_file_dialog_set_initial_folder")]
1023 #[doc(alias = "initial-folder")]
1024 pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
1025 unsafe {
1026 ffi::gtk_file_dialog_set_initial_folder(
1027 self.to_glib_none().0,
1028 folder.map(|p| p.as_ref()).to_glib_none().0,
1029 );
1030 }
1031 }
1032
1033 #[doc(alias = "gtk_file_dialog_set_initial_name")]
1044 #[doc(alias = "initial-name")]
1045 pub fn set_initial_name(&self, name: Option<&str>) {
1046 unsafe {
1047 ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
1048 }
1049 }
1050
1051 #[doc(alias = "gtk_file_dialog_set_modal")]
1056 #[doc(alias = "modal")]
1057 pub fn set_modal(&self, modal: bool) {
1058 unsafe {
1059 ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
1060 }
1061 }
1062
1063 #[doc(alias = "gtk_file_dialog_set_title")]
1067 #[doc(alias = "title")]
1068 pub fn set_title(&self, title: &str) {
1069 unsafe {
1070 ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
1071 }
1072 }
1073
1074 #[cfg(feature = "v4_10")]
1075 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1076 #[doc(alias = "accept-label")]
1077 pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1078 unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
1079 this: *mut ffi::GtkFileDialog,
1080 _param_spec: glib::ffi::gpointer,
1081 f: glib::ffi::gpointer,
1082 ) {
1083 let f: &F = &*(f as *const F);
1084 f(&from_glib_borrow(this))
1085 }
1086 unsafe {
1087 let f: Box_<F> = Box_::new(f);
1088 connect_raw(
1089 self.as_ptr() as *mut _,
1090 c"notify::accept-label".as_ptr() as *const _,
1091 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1092 notify_accept_label_trampoline::<F> as *const (),
1093 )),
1094 Box_::into_raw(f),
1095 )
1096 }
1097 }
1098
1099 #[cfg(feature = "v4_10")]
1100 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1101 #[doc(alias = "default-filter")]
1102 pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1103 unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
1104 this: *mut ffi::GtkFileDialog,
1105 _param_spec: glib::ffi::gpointer,
1106 f: glib::ffi::gpointer,
1107 ) {
1108 let f: &F = &*(f as *const F);
1109 f(&from_glib_borrow(this))
1110 }
1111 unsafe {
1112 let f: Box_<F> = Box_::new(f);
1113 connect_raw(
1114 self.as_ptr() as *mut _,
1115 c"notify::default-filter".as_ptr() as *const _,
1116 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1117 notify_default_filter_trampoline::<F> as *const (),
1118 )),
1119 Box_::into_raw(f),
1120 )
1121 }
1122 }
1123
1124 #[cfg(feature = "v4_10")]
1125 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1126 #[doc(alias = "filters")]
1127 pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1128 unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
1129 this: *mut ffi::GtkFileDialog,
1130 _param_spec: glib::ffi::gpointer,
1131 f: glib::ffi::gpointer,
1132 ) {
1133 let f: &F = &*(f as *const F);
1134 f(&from_glib_borrow(this))
1135 }
1136 unsafe {
1137 let f: Box_<F> = Box_::new(f);
1138 connect_raw(
1139 self.as_ptr() as *mut _,
1140 c"notify::filters".as_ptr() as *const _,
1141 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1142 notify_filters_trampoline::<F> as *const (),
1143 )),
1144 Box_::into_raw(f),
1145 )
1146 }
1147 }
1148
1149 #[cfg(feature = "v4_10")]
1150 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1151 #[doc(alias = "initial-file")]
1152 pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1153 unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
1154 this: *mut ffi::GtkFileDialog,
1155 _param_spec: glib::ffi::gpointer,
1156 f: glib::ffi::gpointer,
1157 ) {
1158 let f: &F = &*(f as *const F);
1159 f(&from_glib_borrow(this))
1160 }
1161 unsafe {
1162 let f: Box_<F> = Box_::new(f);
1163 connect_raw(
1164 self.as_ptr() as *mut _,
1165 c"notify::initial-file".as_ptr() as *const _,
1166 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1167 notify_initial_file_trampoline::<F> as *const (),
1168 )),
1169 Box_::into_raw(f),
1170 )
1171 }
1172 }
1173
1174 #[cfg(feature = "v4_10")]
1175 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1176 #[doc(alias = "initial-folder")]
1177 pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1178 unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
1179 this: *mut ffi::GtkFileDialog,
1180 _param_spec: glib::ffi::gpointer,
1181 f: glib::ffi::gpointer,
1182 ) {
1183 let f: &F = &*(f as *const F);
1184 f(&from_glib_borrow(this))
1185 }
1186 unsafe {
1187 let f: Box_<F> = Box_::new(f);
1188 connect_raw(
1189 self.as_ptr() as *mut _,
1190 c"notify::initial-folder".as_ptr() as *const _,
1191 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1192 notify_initial_folder_trampoline::<F> as *const (),
1193 )),
1194 Box_::into_raw(f),
1195 )
1196 }
1197 }
1198
1199 #[cfg(feature = "v4_10")]
1200 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1201 #[doc(alias = "initial-name")]
1202 pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1203 unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
1204 this: *mut ffi::GtkFileDialog,
1205 _param_spec: glib::ffi::gpointer,
1206 f: glib::ffi::gpointer,
1207 ) {
1208 let f: &F = &*(f as *const F);
1209 f(&from_glib_borrow(this))
1210 }
1211 unsafe {
1212 let f: Box_<F> = Box_::new(f);
1213 connect_raw(
1214 self.as_ptr() as *mut _,
1215 c"notify::initial-name".as_ptr() as *const _,
1216 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1217 notify_initial_name_trampoline::<F> as *const (),
1218 )),
1219 Box_::into_raw(f),
1220 )
1221 }
1222 }
1223
1224 #[cfg(feature = "v4_10")]
1225 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1226 #[doc(alias = "modal")]
1227 pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1228 unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
1229 this: *mut ffi::GtkFileDialog,
1230 _param_spec: glib::ffi::gpointer,
1231 f: glib::ffi::gpointer,
1232 ) {
1233 let f: &F = &*(f as *const F);
1234 f(&from_glib_borrow(this))
1235 }
1236 unsafe {
1237 let f: Box_<F> = Box_::new(f);
1238 connect_raw(
1239 self.as_ptr() as *mut _,
1240 c"notify::modal".as_ptr() as *const _,
1241 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1242 notify_modal_trampoline::<F> as *const (),
1243 )),
1244 Box_::into_raw(f),
1245 )
1246 }
1247 }
1248
1249 #[cfg(feature = "v4_10")]
1250 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1251 #[doc(alias = "title")]
1252 pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1253 unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
1254 this: *mut ffi::GtkFileDialog,
1255 _param_spec: glib::ffi::gpointer,
1256 f: glib::ffi::gpointer,
1257 ) {
1258 let f: &F = &*(f as *const F);
1259 f(&from_glib_borrow(this))
1260 }
1261 unsafe {
1262 let f: Box_<F> = Box_::new(f);
1263 connect_raw(
1264 self.as_ptr() as *mut _,
1265 c"notify::title".as_ptr() as *const _,
1266 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1267 notify_title_trampoline::<F> as *const (),
1268 )),
1269 Box_::into_raw(f),
1270 )
1271 }
1272 }
1273}
1274
1275#[cfg(feature = "v4_10")]
1276#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1277impl Default for FileDialog {
1278 fn default() -> Self {
1279 Self::new()
1280 }
1281}
1282
1283#[must_use = "The builder must be built to be used"]
1288pub struct FileDialogBuilder {
1289 builder: glib::object::ObjectBuilder<'static, FileDialog>,
1290}
1291
1292impl FileDialogBuilder {
1293 fn new() -> Self {
1294 Self {
1295 builder: glib::object::Object::builder(),
1296 }
1297 }
1298
1299 #[cfg(feature = "v4_10")]
1301 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1302 pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1303 Self {
1304 builder: self.builder.property("accept-label", accept_label.into()),
1305 }
1306 }
1307
1308 #[cfg(feature = "v4_10")]
1319 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1320 pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1321 Self {
1322 builder: self
1323 .builder
1324 .property("default-filter", default_filter.clone()),
1325 }
1326 }
1327
1328 #[cfg(feature = "v4_10")]
1333 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1334 pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1335 Self {
1336 builder: self.builder.property("filters", filters.clone().upcast()),
1337 }
1338 }
1339
1340 #[cfg(feature = "v4_10")]
1347 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1348 pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1349 Self {
1350 builder: self
1351 .builder
1352 .property("initial-file", initial_file.clone().upcast()),
1353 }
1354 }
1355
1356 #[cfg(feature = "v4_10")]
1360 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1361 pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1362 Self {
1363 builder: self
1364 .builder
1365 .property("initial-folder", initial_folder.clone().upcast()),
1366 }
1367 }
1368
1369 #[cfg(feature = "v4_10")]
1373 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1374 pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1375 Self {
1376 builder: self.builder.property("initial-name", initial_name.into()),
1377 }
1378 }
1379
1380 #[cfg(feature = "v4_10")]
1382 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1383 pub fn modal(self, modal: bool) -> Self {
1384 Self {
1385 builder: self.builder.property("modal", modal),
1386 }
1387 }
1388
1389 #[cfg(feature = "v4_10")]
1391 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1392 pub fn title(self, title: impl Into<glib::GString>) -> Self {
1393 Self {
1394 builder: self.builder.property("title", title.into()),
1395 }
1396 }
1397
1398 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1401 pub fn build(self) -> FileDialog {
1402 assert_initialized_main_thread!();
1403 self.builder.build()
1404 }
1405}