1use crate::{FileFilter, Window, ffi};
6use glib::{
7 prelude::*,
8 signal::{SignalHandlerId, connect_raw},
9 translate::*,
10};
11use std::{boxed::Box as Box_, pin::Pin};
12
13glib::wrapper! {
14 #[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 unsafe {
272 let mut error = std::ptr::null_mut();
273 let ret =
274 ffi::gtk_file_dialog_open_finish(_source_object as *mut _, res, &mut error);
275 let result = if error.is_null() {
276 Ok(from_glib_full(ret))
277 } else {
278 Err(from_glib_full(error))
279 };
280 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
281 Box_::from_raw(user_data as *mut _);
282 let callback: P = callback.into_inner();
283 callback(result);
284 }
285 }
286 let callback = open_trampoline::<P>;
287 unsafe {
288 ffi::gtk_file_dialog_open(
289 self.to_glib_none().0,
290 parent.map(|p| p.as_ref()).to_glib_none().0,
291 cancellable.map(|p| p.as_ref()).to_glib_none().0,
292 Some(callback),
293 Box_::into_raw(user_data) as *mut _,
294 );
295 }
296 }
297
298 pub fn open_future(
299 &self,
300 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
301 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
302 let parent = parent.map(ToOwned::to_owned);
303 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
304 obj.open(
305 parent.as_ref().map(::std::borrow::Borrow::borrow),
306 Some(cancellable),
307 move |res| {
308 send.resolve(res);
309 },
310 );
311 }))
312 }
313
314 #[doc(alias = "gtk_file_dialog_open_multiple")]
330 pub fn open_multiple<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
331 &self,
332 parent: Option<&impl IsA<Window>>,
333 cancellable: Option<&impl IsA<gio::Cancellable>>,
334 callback: P,
335 ) {
336 let main_context = glib::MainContext::ref_thread_default();
337 let is_main_context_owner = main_context.is_owner();
338 let has_acquired_main_context = (!is_main_context_owner)
339 .then(|| main_context.acquire().ok())
340 .flatten();
341 assert!(
342 is_main_context_owner || has_acquired_main_context.is_some(),
343 "Async operations only allowed if the thread is owning the MainContext"
344 );
345
346 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
347 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
348 unsafe extern "C" fn open_multiple_trampoline<
349 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
350 >(
351 _source_object: *mut glib::gobject_ffi::GObject,
352 res: *mut gio::ffi::GAsyncResult,
353 user_data: glib::ffi::gpointer,
354 ) {
355 unsafe {
356 let mut error = std::ptr::null_mut();
357 let ret = ffi::gtk_file_dialog_open_multiple_finish(
358 _source_object as *mut _,
359 res,
360 &mut error,
361 );
362 let result = if error.is_null() {
363 Ok(from_glib_full(ret))
364 } else {
365 Err(from_glib_full(error))
366 };
367 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
368 Box_::from_raw(user_data as *mut _);
369 let callback: P = callback.into_inner();
370 callback(result);
371 }
372 }
373 let callback = open_multiple_trampoline::<P>;
374 unsafe {
375 ffi::gtk_file_dialog_open_multiple(
376 self.to_glib_none().0,
377 parent.map(|p| p.as_ref()).to_glib_none().0,
378 cancellable.map(|p| p.as_ref()).to_glib_none().0,
379 Some(callback),
380 Box_::into_raw(user_data) as *mut _,
381 );
382 }
383 }
384
385 pub fn open_multiple_future(
386 &self,
387 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
388 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
389 {
390 let parent = parent.map(ToOwned::to_owned);
391 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
392 obj.open_multiple(
393 parent.as_ref().map(::std::borrow::Borrow::borrow),
394 Some(cancellable),
395 move |res| {
396 send.resolve(res);
397 },
398 );
399 }))
400 }
401
402 #[cfg(feature = "v4_18")]
421 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
422 #[doc(alias = "gtk_file_dialog_open_multiple_text_files")]
423 pub fn open_multiple_text_files<
424 P: FnOnce(Result<(gio::ListModel, glib::GString), glib::Error>) + 'static,
425 >(
426 &self,
427 parent: Option<&impl IsA<Window>>,
428 cancellable: Option<&impl IsA<gio::Cancellable>>,
429 callback: P,
430 ) {
431 let main_context = glib::MainContext::ref_thread_default();
432 let is_main_context_owner = main_context.is_owner();
433 let has_acquired_main_context = (!is_main_context_owner)
434 .then(|| main_context.acquire().ok())
435 .flatten();
436 assert!(
437 is_main_context_owner || has_acquired_main_context.is_some(),
438 "Async operations only allowed if the thread is owning the MainContext"
439 );
440
441 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
442 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
443 unsafe extern "C" fn open_multiple_text_files_trampoline<
444 P: FnOnce(Result<(gio::ListModel, glib::GString), glib::Error>) + 'static,
445 >(
446 _source_object: *mut glib::gobject_ffi::GObject,
447 res: *mut gio::ffi::GAsyncResult,
448 user_data: glib::ffi::gpointer,
449 ) {
450 unsafe {
451 let mut error = std::ptr::null_mut();
452 let mut encoding = std::ptr::null();
453 let ret = ffi::gtk_file_dialog_open_multiple_text_files_finish(
454 _source_object as *mut _,
455 res,
456 &mut encoding,
457 &mut error,
458 );
459 let result = if error.is_null() {
460 Ok((from_glib_full(ret), from_glib_none(encoding)))
461 } else {
462 Err(from_glib_full(error))
463 };
464 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
465 Box_::from_raw(user_data as *mut _);
466 let callback: P = callback.into_inner();
467 callback(result);
468 }
469 }
470 let callback = open_multiple_text_files_trampoline::<P>;
471 unsafe {
472 ffi::gtk_file_dialog_open_multiple_text_files(
473 self.to_glib_none().0,
474 parent.map(|p| p.as_ref()).to_glib_none().0,
475 cancellable.map(|p| p.as_ref()).to_glib_none().0,
476 Some(callback),
477 Box_::into_raw(user_data) as *mut _,
478 );
479 }
480 }
481
482 #[cfg(feature = "v4_18")]
483 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
484 pub fn open_multiple_text_files_future(
485 &self,
486 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
487 ) -> Pin<
488 Box_<
489 dyn std::future::Future<Output = Result<(gio::ListModel, glib::GString), glib::Error>>
490 + 'static,
491 >,
492 > {
493 let parent = parent.map(ToOwned::to_owned);
494 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
495 obj.open_multiple_text_files(
496 parent.as_ref().map(::std::borrow::Borrow::borrow),
497 Some(cancellable),
498 move |res| {
499 send.resolve(res);
500 },
501 );
502 }))
503 }
504
505 #[cfg(feature = "v4_18")]
520 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
521 #[doc(alias = "gtk_file_dialog_open_text_file")]
522 pub fn open_text_file<P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static>(
523 &self,
524 parent: Option<&impl IsA<Window>>,
525 cancellable: Option<&impl IsA<gio::Cancellable>>,
526 callback: P,
527 ) {
528 let main_context = glib::MainContext::ref_thread_default();
529 let is_main_context_owner = main_context.is_owner();
530 let has_acquired_main_context = (!is_main_context_owner)
531 .then(|| main_context.acquire().ok())
532 .flatten();
533 assert!(
534 is_main_context_owner || has_acquired_main_context.is_some(),
535 "Async operations only allowed if the thread is owning the MainContext"
536 );
537
538 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
539 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
540 unsafe extern "C" fn open_text_file_trampoline<
541 P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static,
542 >(
543 _source_object: *mut glib::gobject_ffi::GObject,
544 res: *mut gio::ffi::GAsyncResult,
545 user_data: glib::ffi::gpointer,
546 ) {
547 unsafe {
548 let mut error = std::ptr::null_mut();
549 let mut encoding = std::ptr::null();
550 let ret = ffi::gtk_file_dialog_open_text_file_finish(
551 _source_object as *mut _,
552 res,
553 &mut encoding,
554 &mut error,
555 );
556 let result = if error.is_null() {
557 Ok((from_glib_full(ret), from_glib_none(encoding)))
558 } else {
559 Err(from_glib_full(error))
560 };
561 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
562 Box_::from_raw(user_data as *mut _);
563 let callback: P = callback.into_inner();
564 callback(result);
565 }
566 }
567 let callback = open_text_file_trampoline::<P>;
568 unsafe {
569 ffi::gtk_file_dialog_open_text_file(
570 self.to_glib_none().0,
571 parent.map(|p| p.as_ref()).to_glib_none().0,
572 cancellable.map(|p| p.as_ref()).to_glib_none().0,
573 Some(callback),
574 Box_::into_raw(user_data) as *mut _,
575 );
576 }
577 }
578
579 #[cfg(feature = "v4_18")]
580 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
581 pub fn open_text_file_future(
582 &self,
583 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
584 ) -> Pin<
585 Box_<
586 dyn std::future::Future<Output = Result<(gio::File, glib::GString), glib::Error>>
587 + 'static,
588 >,
589 > {
590 let parent = parent.map(ToOwned::to_owned);
591 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
592 obj.open_text_file(
593 parent.as_ref().map(::std::borrow::Borrow::borrow),
594 Some(cancellable),
595 move |res| {
596 send.resolve(res);
597 },
598 );
599 }))
600 }
601
602 #[doc(alias = "gtk_file_dialog_save")]
615 pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
616 &self,
617 parent: Option<&impl IsA<Window>>,
618 cancellable: Option<&impl IsA<gio::Cancellable>>,
619 callback: P,
620 ) {
621 let main_context = glib::MainContext::ref_thread_default();
622 let is_main_context_owner = main_context.is_owner();
623 let has_acquired_main_context = (!is_main_context_owner)
624 .then(|| main_context.acquire().ok())
625 .flatten();
626 assert!(
627 is_main_context_owner || has_acquired_main_context.is_some(),
628 "Async operations only allowed if the thread is owning the MainContext"
629 );
630
631 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
632 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
633 unsafe extern "C" fn save_trampoline<
634 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
635 >(
636 _source_object: *mut glib::gobject_ffi::GObject,
637 res: *mut gio::ffi::GAsyncResult,
638 user_data: glib::ffi::gpointer,
639 ) {
640 unsafe {
641 let mut error = std::ptr::null_mut();
642 let ret =
643 ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
644 let result = if error.is_null() {
645 Ok(from_glib_full(ret))
646 } else {
647 Err(from_glib_full(error))
648 };
649 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
650 Box_::from_raw(user_data as *mut _);
651 let callback: P = callback.into_inner();
652 callback(result);
653 }
654 }
655 let callback = save_trampoline::<P>;
656 unsafe {
657 ffi::gtk_file_dialog_save(
658 self.to_glib_none().0,
659 parent.map(|p| p.as_ref()).to_glib_none().0,
660 cancellable.map(|p| p.as_ref()).to_glib_none().0,
661 Some(callback),
662 Box_::into_raw(user_data) as *mut _,
663 );
664 }
665 }
666
667 pub fn save_future(
668 &self,
669 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
670 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
671 let parent = parent.map(ToOwned::to_owned);
672 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
673 obj.save(
674 parent.as_ref().map(::std::borrow::Borrow::borrow),
675 Some(cancellable),
676 move |res| {
677 send.resolve(res);
678 },
679 );
680 }))
681 }
682
683 #[cfg(feature = "v4_18")]
699 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
700 #[doc(alias = "gtk_file_dialog_save_text_file")]
701 pub fn save_text_file<
702 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
703 >(
704 &self,
705 parent: Option<&impl IsA<Window>>,
706 cancellable: Option<&impl IsA<gio::Cancellable>>,
707 callback: P,
708 ) {
709 let main_context = glib::MainContext::ref_thread_default();
710 let is_main_context_owner = main_context.is_owner();
711 let has_acquired_main_context = (!is_main_context_owner)
712 .then(|| main_context.acquire().ok())
713 .flatten();
714 assert!(
715 is_main_context_owner || has_acquired_main_context.is_some(),
716 "Async operations only allowed if the thread is owning the MainContext"
717 );
718
719 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
720 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
721 unsafe extern "C" fn save_text_file_trampoline<
722 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
723 >(
724 _source_object: *mut glib::gobject_ffi::GObject,
725 res: *mut gio::ffi::GAsyncResult,
726 user_data: glib::ffi::gpointer,
727 ) {
728 unsafe {
729 let mut error = std::ptr::null_mut();
730 let mut encoding = std::ptr::null();
731 let mut line_ending = std::ptr::null();
732 let ret = ffi::gtk_file_dialog_save_text_file_finish(
733 _source_object as *mut _,
734 res,
735 &mut encoding,
736 &mut line_ending,
737 &mut error,
738 );
739 let result = if error.is_null() {
740 Ok((
741 from_glib_full(ret),
742 from_glib_none(encoding),
743 from_glib_none(line_ending),
744 ))
745 } else {
746 Err(from_glib_full(error))
747 };
748 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
749 Box_::from_raw(user_data as *mut _);
750 let callback: P = callback.into_inner();
751 callback(result);
752 }
753 }
754 let callback = save_text_file_trampoline::<P>;
755 unsafe {
756 ffi::gtk_file_dialog_save_text_file(
757 self.to_glib_none().0,
758 parent.map(|p| p.as_ref()).to_glib_none().0,
759 cancellable.map(|p| p.as_ref()).to_glib_none().0,
760 Some(callback),
761 Box_::into_raw(user_data) as *mut _,
762 );
763 }
764 }
765
766 #[cfg(feature = "v4_18")]
767 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
768 pub fn save_text_file_future(
769 &self,
770 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
771 ) -> Pin<
772 Box_<
773 dyn std::future::Future<
774 Output = Result<(gio::File, glib::GString, glib::GString), glib::Error>,
775 > + 'static,
776 >,
777 > {
778 let parent = parent.map(ToOwned::to_owned);
779 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
780 obj.save_text_file(
781 parent.as_ref().map(::std::borrow::Borrow::borrow),
782 Some(cancellable),
783 move |res| {
784 send.resolve(res);
785 },
786 );
787 }))
788 }
789
790 #[doc(alias = "gtk_file_dialog_select_folder")]
807 pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
808 &self,
809 parent: Option<&impl IsA<Window>>,
810 cancellable: Option<&impl IsA<gio::Cancellable>>,
811 callback: P,
812 ) {
813 let main_context = glib::MainContext::ref_thread_default();
814 let is_main_context_owner = main_context.is_owner();
815 let has_acquired_main_context = (!is_main_context_owner)
816 .then(|| main_context.acquire().ok())
817 .flatten();
818 assert!(
819 is_main_context_owner || has_acquired_main_context.is_some(),
820 "Async operations only allowed if the thread is owning the MainContext"
821 );
822
823 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
824 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
825 unsafe extern "C" fn select_folder_trampoline<
826 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
827 >(
828 _source_object: *mut glib::gobject_ffi::GObject,
829 res: *mut gio::ffi::GAsyncResult,
830 user_data: glib::ffi::gpointer,
831 ) {
832 unsafe {
833 let mut error = std::ptr::null_mut();
834 let ret = ffi::gtk_file_dialog_select_folder_finish(
835 _source_object as *mut _,
836 res,
837 &mut error,
838 );
839 let result = if error.is_null() {
840 Ok(from_glib_full(ret))
841 } else {
842 Err(from_glib_full(error))
843 };
844 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
845 Box_::from_raw(user_data as *mut _);
846 let callback: P = callback.into_inner();
847 callback(result);
848 }
849 }
850 let callback = select_folder_trampoline::<P>;
851 unsafe {
852 ffi::gtk_file_dialog_select_folder(
853 self.to_glib_none().0,
854 parent.map(|p| p.as_ref()).to_glib_none().0,
855 cancellable.map(|p| p.as_ref()).to_glib_none().0,
856 Some(callback),
857 Box_::into_raw(user_data) as *mut _,
858 );
859 }
860 }
861
862 pub fn select_folder_future(
863 &self,
864 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
865 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
866 let parent = parent.map(ToOwned::to_owned);
867 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
868 obj.select_folder(
869 parent.as_ref().map(::std::borrow::Borrow::borrow),
870 Some(cancellable),
871 move |res| {
872 send.resolve(res);
873 },
874 );
875 }))
876 }
877
878 #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
895 pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
896 &self,
897 parent: Option<&impl IsA<Window>>,
898 cancellable: Option<&impl IsA<gio::Cancellable>>,
899 callback: P,
900 ) {
901 let main_context = glib::MainContext::ref_thread_default();
902 let is_main_context_owner = main_context.is_owner();
903 let has_acquired_main_context = (!is_main_context_owner)
904 .then(|| main_context.acquire().ok())
905 .flatten();
906 assert!(
907 is_main_context_owner || has_acquired_main_context.is_some(),
908 "Async operations only allowed if the thread is owning the MainContext"
909 );
910
911 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
912 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
913 unsafe extern "C" fn select_multiple_folders_trampoline<
914 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
915 >(
916 _source_object: *mut glib::gobject_ffi::GObject,
917 res: *mut gio::ffi::GAsyncResult,
918 user_data: glib::ffi::gpointer,
919 ) {
920 unsafe {
921 let mut error = std::ptr::null_mut();
922 let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
923 _source_object as *mut _,
924 res,
925 &mut error,
926 );
927 let result = if error.is_null() {
928 Ok(from_glib_full(ret))
929 } else {
930 Err(from_glib_full(error))
931 };
932 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
933 Box_::from_raw(user_data as *mut _);
934 let callback: P = callback.into_inner();
935 callback(result);
936 }
937 }
938 let callback = select_multiple_folders_trampoline::<P>;
939 unsafe {
940 ffi::gtk_file_dialog_select_multiple_folders(
941 self.to_glib_none().0,
942 parent.map(|p| p.as_ref()).to_glib_none().0,
943 cancellable.map(|p| p.as_ref()).to_glib_none().0,
944 Some(callback),
945 Box_::into_raw(user_data) as *mut _,
946 );
947 }
948 }
949
950 pub fn select_multiple_folders_future(
951 &self,
952 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
953 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
954 {
955 let parent = parent.map(ToOwned::to_owned);
956 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
957 obj.select_multiple_folders(
958 parent.as_ref().map(::std::borrow::Borrow::borrow),
959 Some(cancellable),
960 move |res| {
961 send.resolve(res);
962 },
963 );
964 }))
965 }
966
967 #[doc(alias = "gtk_file_dialog_set_accept_label")]
975 #[doc(alias = "accept-label")]
976 pub fn set_accept_label(&self, accept_label: Option<&str>) {
977 unsafe {
978 ffi::gtk_file_dialog_set_accept_label(
979 self.to_glib_none().0,
980 accept_label.to_glib_none().0,
981 );
982 }
983 }
984
985 #[doc(alias = "gtk_file_dialog_set_default_filter")]
994 #[doc(alias = "default-filter")]
995 pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
996 unsafe {
997 ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
998 }
999 }
1000
1001 #[doc(alias = "gtk_file_dialog_set_filters")]
1006 #[doc(alias = "filters")]
1007 pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
1008 unsafe {
1009 ffi::gtk_file_dialog_set_filters(
1010 self.to_glib_none().0,
1011 filters.map(|p| p.as_ref()).to_glib_none().0,
1012 );
1013 }
1014 }
1015
1016 #[doc(alias = "gtk_file_dialog_set_initial_file")]
1026 #[doc(alias = "initial-file")]
1027 pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
1028 unsafe {
1029 ffi::gtk_file_dialog_set_initial_file(
1030 self.to_glib_none().0,
1031 file.map(|p| p.as_ref()).to_glib_none().0,
1032 );
1033 }
1034 }
1035
1036 #[doc(alias = "gtk_file_dialog_set_initial_folder")]
1041 #[doc(alias = "initial-folder")]
1042 pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
1043 unsafe {
1044 ffi::gtk_file_dialog_set_initial_folder(
1045 self.to_glib_none().0,
1046 folder.map(|p| p.as_ref()).to_glib_none().0,
1047 );
1048 }
1049 }
1050
1051 #[doc(alias = "gtk_file_dialog_set_initial_name")]
1062 #[doc(alias = "initial-name")]
1063 pub fn set_initial_name(&self, name: Option<&str>) {
1064 unsafe {
1065 ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
1066 }
1067 }
1068
1069 #[doc(alias = "gtk_file_dialog_set_modal")]
1074 #[doc(alias = "modal")]
1075 pub fn set_modal(&self, modal: bool) {
1076 unsafe {
1077 ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
1078 }
1079 }
1080
1081 #[doc(alias = "gtk_file_dialog_set_title")]
1085 #[doc(alias = "title")]
1086 pub fn set_title(&self, title: &str) {
1087 unsafe {
1088 ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
1089 }
1090 }
1091
1092 #[cfg(feature = "v4_10")]
1093 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1094 #[doc(alias = "accept-label")]
1095 pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1096 unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
1097 this: *mut ffi::GtkFileDialog,
1098 _param_spec: glib::ffi::gpointer,
1099 f: glib::ffi::gpointer,
1100 ) {
1101 unsafe {
1102 let f: &F = &*(f as *const F);
1103 f(&from_glib_borrow(this))
1104 }
1105 }
1106 unsafe {
1107 let f: Box_<F> = Box_::new(f);
1108 connect_raw(
1109 self.as_ptr() as *mut _,
1110 c"notify::accept-label".as_ptr() as *const _,
1111 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1112 notify_accept_label_trampoline::<F> as *const (),
1113 )),
1114 Box_::into_raw(f),
1115 )
1116 }
1117 }
1118
1119 #[cfg(feature = "v4_10")]
1120 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1121 #[doc(alias = "default-filter")]
1122 pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1123 unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
1124 this: *mut ffi::GtkFileDialog,
1125 _param_spec: glib::ffi::gpointer,
1126 f: glib::ffi::gpointer,
1127 ) {
1128 unsafe {
1129 let f: &F = &*(f as *const F);
1130 f(&from_glib_borrow(this))
1131 }
1132 }
1133 unsafe {
1134 let f: Box_<F> = Box_::new(f);
1135 connect_raw(
1136 self.as_ptr() as *mut _,
1137 c"notify::default-filter".as_ptr() as *const _,
1138 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1139 notify_default_filter_trampoline::<F> as *const (),
1140 )),
1141 Box_::into_raw(f),
1142 )
1143 }
1144 }
1145
1146 #[cfg(feature = "v4_10")]
1147 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1148 #[doc(alias = "filters")]
1149 pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1150 unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
1151 this: *mut ffi::GtkFileDialog,
1152 _param_spec: glib::ffi::gpointer,
1153 f: glib::ffi::gpointer,
1154 ) {
1155 unsafe {
1156 let f: &F = &*(f as *const F);
1157 f(&from_glib_borrow(this))
1158 }
1159 }
1160 unsafe {
1161 let f: Box_<F> = Box_::new(f);
1162 connect_raw(
1163 self.as_ptr() as *mut _,
1164 c"notify::filters".as_ptr() as *const _,
1165 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1166 notify_filters_trampoline::<F> as *const (),
1167 )),
1168 Box_::into_raw(f),
1169 )
1170 }
1171 }
1172
1173 #[cfg(feature = "v4_10")]
1174 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1175 #[doc(alias = "initial-file")]
1176 pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1177 unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
1178 this: *mut ffi::GtkFileDialog,
1179 _param_spec: glib::ffi::gpointer,
1180 f: glib::ffi::gpointer,
1181 ) {
1182 unsafe {
1183 let f: &F = &*(f as *const F);
1184 f(&from_glib_borrow(this))
1185 }
1186 }
1187 unsafe {
1188 let f: Box_<F> = Box_::new(f);
1189 connect_raw(
1190 self.as_ptr() as *mut _,
1191 c"notify::initial-file".as_ptr() as *const _,
1192 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1193 notify_initial_file_trampoline::<F> as *const (),
1194 )),
1195 Box_::into_raw(f),
1196 )
1197 }
1198 }
1199
1200 #[cfg(feature = "v4_10")]
1201 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1202 #[doc(alias = "initial-folder")]
1203 pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1204 unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
1205 this: *mut ffi::GtkFileDialog,
1206 _param_spec: glib::ffi::gpointer,
1207 f: glib::ffi::gpointer,
1208 ) {
1209 unsafe {
1210 let f: &F = &*(f as *const F);
1211 f(&from_glib_borrow(this))
1212 }
1213 }
1214 unsafe {
1215 let f: Box_<F> = Box_::new(f);
1216 connect_raw(
1217 self.as_ptr() as *mut _,
1218 c"notify::initial-folder".as_ptr() as *const _,
1219 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1220 notify_initial_folder_trampoline::<F> as *const (),
1221 )),
1222 Box_::into_raw(f),
1223 )
1224 }
1225 }
1226
1227 #[cfg(feature = "v4_10")]
1228 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1229 #[doc(alias = "initial-name")]
1230 pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1231 unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
1232 this: *mut ffi::GtkFileDialog,
1233 _param_spec: glib::ffi::gpointer,
1234 f: glib::ffi::gpointer,
1235 ) {
1236 unsafe {
1237 let f: &F = &*(f as *const F);
1238 f(&from_glib_borrow(this))
1239 }
1240 }
1241 unsafe {
1242 let f: Box_<F> = Box_::new(f);
1243 connect_raw(
1244 self.as_ptr() as *mut _,
1245 c"notify::initial-name".as_ptr() as *const _,
1246 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1247 notify_initial_name_trampoline::<F> as *const (),
1248 )),
1249 Box_::into_raw(f),
1250 )
1251 }
1252 }
1253
1254 #[cfg(feature = "v4_10")]
1255 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1256 #[doc(alias = "modal")]
1257 pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1258 unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
1259 this: *mut ffi::GtkFileDialog,
1260 _param_spec: glib::ffi::gpointer,
1261 f: glib::ffi::gpointer,
1262 ) {
1263 unsafe {
1264 let f: &F = &*(f as *const F);
1265 f(&from_glib_borrow(this))
1266 }
1267 }
1268 unsafe {
1269 let f: Box_<F> = Box_::new(f);
1270 connect_raw(
1271 self.as_ptr() as *mut _,
1272 c"notify::modal".as_ptr() as *const _,
1273 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1274 notify_modal_trampoline::<F> as *const (),
1275 )),
1276 Box_::into_raw(f),
1277 )
1278 }
1279 }
1280
1281 #[cfg(feature = "v4_10")]
1282 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1283 #[doc(alias = "title")]
1284 pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
1285 unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
1286 this: *mut ffi::GtkFileDialog,
1287 _param_spec: glib::ffi::gpointer,
1288 f: glib::ffi::gpointer,
1289 ) {
1290 unsafe {
1291 let f: &F = &*(f as *const F);
1292 f(&from_glib_borrow(this))
1293 }
1294 }
1295 unsafe {
1296 let f: Box_<F> = Box_::new(f);
1297 connect_raw(
1298 self.as_ptr() as *mut _,
1299 c"notify::title".as_ptr() as *const _,
1300 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
1301 notify_title_trampoline::<F> as *const (),
1302 )),
1303 Box_::into_raw(f),
1304 )
1305 }
1306 }
1307}
1308
1309#[cfg(feature = "v4_10")]
1310#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1311impl Default for FileDialog {
1312 fn default() -> Self {
1313 Self::new()
1314 }
1315}
1316
1317#[must_use = "The builder must be built to be used"]
1322pub struct FileDialogBuilder {
1323 builder: glib::object::ObjectBuilder<'static, FileDialog>,
1324}
1325
1326impl FileDialogBuilder {
1327 fn new() -> Self {
1328 Self {
1329 builder: glib::object::Object::builder(),
1330 }
1331 }
1332
1333 #[cfg(feature = "v4_10")]
1335 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1336 pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1337 Self {
1338 builder: self.builder.property("accept-label", accept_label.into()),
1339 }
1340 }
1341
1342 #[cfg(feature = "v4_10")]
1353 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1354 pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1355 Self {
1356 builder: self
1357 .builder
1358 .property("default-filter", default_filter.clone()),
1359 }
1360 }
1361
1362 #[cfg(feature = "v4_10")]
1367 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1368 pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1369 Self {
1370 builder: self.builder.property("filters", filters.clone().upcast()),
1371 }
1372 }
1373
1374 #[cfg(feature = "v4_10")]
1381 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1382 pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1383 Self {
1384 builder: self
1385 .builder
1386 .property("initial-file", initial_file.clone().upcast()),
1387 }
1388 }
1389
1390 #[cfg(feature = "v4_10")]
1394 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1395 pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1396 Self {
1397 builder: self
1398 .builder
1399 .property("initial-folder", initial_folder.clone().upcast()),
1400 }
1401 }
1402
1403 #[cfg(feature = "v4_10")]
1407 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1408 pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1409 Self {
1410 builder: self.builder.property("initial-name", initial_name.into()),
1411 }
1412 }
1413
1414 #[cfg(feature = "v4_10")]
1416 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1417 pub fn modal(self, modal: bool) -> Self {
1418 Self {
1419 builder: self.builder.property("modal", modal),
1420 }
1421 }
1422
1423 #[cfg(feature = "v4_10")]
1425 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1426 pub fn title(self, title: impl Into<glib::GString>) -> Self {
1427 Self {
1428 builder: self.builder.property("title", title.into()),
1429 }
1430 }
1431
1432 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1435 pub fn build(self) -> FileDialog {
1436 assert_initialized_main_thread!();
1437 self.builder.build()
1438 }
1439}