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")]
15 pub struct FileDialog(Object<ffi::GtkFileDialog, ffi::GtkFileDialogClass>);
16
17 match fn {
18 type_ => || ffi::gtk_file_dialog_get_type(),
19 }
20}
21
22impl FileDialog {
23 #[doc(alias = "gtk_file_dialog_new")]
24 pub fn new() -> FileDialog {
25 assert_initialized_main_thread!();
26 unsafe { from_glib_full(ffi::gtk_file_dialog_new()) }
27 }
28
29 pub fn builder() -> FileDialogBuilder {
34 FileDialogBuilder::new()
35 }
36
37 #[doc(alias = "gtk_file_dialog_get_accept_label")]
38 #[doc(alias = "get_accept_label")]
39 #[doc(alias = "accept-label")]
40 pub fn accept_label(&self) -> Option<glib::GString> {
41 unsafe { from_glib_none(ffi::gtk_file_dialog_get_accept_label(self.to_glib_none().0)) }
42 }
43
44 #[doc(alias = "gtk_file_dialog_get_default_filter")]
45 #[doc(alias = "get_default_filter")]
46 #[doc(alias = "default-filter")]
47 pub fn default_filter(&self) -> Option<FileFilter> {
48 unsafe {
49 from_glib_none(ffi::gtk_file_dialog_get_default_filter(
50 self.to_glib_none().0,
51 ))
52 }
53 }
54
55 #[doc(alias = "gtk_file_dialog_get_filters")]
56 #[doc(alias = "get_filters")]
57 pub fn filters(&self) -> Option<gio::ListModel> {
58 unsafe { from_glib_none(ffi::gtk_file_dialog_get_filters(self.to_glib_none().0)) }
59 }
60
61 #[doc(alias = "gtk_file_dialog_get_initial_file")]
62 #[doc(alias = "get_initial_file")]
63 #[doc(alias = "initial-file")]
64 pub fn initial_file(&self) -> Option<gio::File> {
65 unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_file(self.to_glib_none().0)) }
66 }
67
68 #[doc(alias = "gtk_file_dialog_get_initial_folder")]
69 #[doc(alias = "get_initial_folder")]
70 #[doc(alias = "initial-folder")]
71 pub fn initial_folder(&self) -> Option<gio::File> {
72 unsafe {
73 from_glib_none(ffi::gtk_file_dialog_get_initial_folder(
74 self.to_glib_none().0,
75 ))
76 }
77 }
78
79 #[doc(alias = "gtk_file_dialog_get_initial_name")]
80 #[doc(alias = "get_initial_name")]
81 #[doc(alias = "initial-name")]
82 pub fn initial_name(&self) -> Option<glib::GString> {
83 unsafe { from_glib_none(ffi::gtk_file_dialog_get_initial_name(self.to_glib_none().0)) }
84 }
85
86 #[doc(alias = "gtk_file_dialog_get_modal")]
87 #[doc(alias = "get_modal")]
88 #[doc(alias = "modal")]
89 pub fn is_modal(&self) -> bool {
90 unsafe { from_glib(ffi::gtk_file_dialog_get_modal(self.to_glib_none().0)) }
91 }
92
93 #[doc(alias = "gtk_file_dialog_get_title")]
94 #[doc(alias = "get_title")]
95 pub fn title(&self) -> glib::GString {
96 unsafe { from_glib_none(ffi::gtk_file_dialog_get_title(self.to_glib_none().0)) }
97 }
98
99 #[doc(alias = "gtk_file_dialog_open")]
100 pub fn open<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
101 &self,
102 parent: Option<&impl IsA<Window>>,
103 cancellable: Option<&impl IsA<gio::Cancellable>>,
104 callback: P,
105 ) {
106 let main_context = glib::MainContext::ref_thread_default();
107 let is_main_context_owner = main_context.is_owner();
108 let has_acquired_main_context = (!is_main_context_owner)
109 .then(|| main_context.acquire().ok())
110 .flatten();
111 assert!(
112 is_main_context_owner || has_acquired_main_context.is_some(),
113 "Async operations only allowed if the thread is owning the MainContext"
114 );
115
116 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
117 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
118 unsafe extern "C" fn open_trampoline<
119 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
120 >(
121 _source_object: *mut glib::gobject_ffi::GObject,
122 res: *mut gio::ffi::GAsyncResult,
123 user_data: glib::ffi::gpointer,
124 ) {
125 let mut error = std::ptr::null_mut();
126 let ret = ffi::gtk_file_dialog_open_finish(_source_object as *mut _, res, &mut error);
127 let result = if error.is_null() {
128 Ok(from_glib_full(ret))
129 } else {
130 Err(from_glib_full(error))
131 };
132 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
133 Box_::from_raw(user_data as *mut _);
134 let callback: P = callback.into_inner();
135 callback(result);
136 }
137 let callback = open_trampoline::<P>;
138 unsafe {
139 ffi::gtk_file_dialog_open(
140 self.to_glib_none().0,
141 parent.map(|p| p.as_ref()).to_glib_none().0,
142 cancellable.map(|p| p.as_ref()).to_glib_none().0,
143 Some(callback),
144 Box_::into_raw(user_data) as *mut _,
145 );
146 }
147 }
148
149 pub fn open_future(
150 &self,
151 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
152 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
153 let parent = parent.map(ToOwned::to_owned);
154 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
155 obj.open(
156 parent.as_ref().map(::std::borrow::Borrow::borrow),
157 Some(cancellable),
158 move |res| {
159 send.resolve(res);
160 },
161 );
162 }))
163 }
164
165 #[doc(alias = "gtk_file_dialog_open_multiple")]
166 pub fn open_multiple<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
167 &self,
168 parent: Option<&impl IsA<Window>>,
169 cancellable: Option<&impl IsA<gio::Cancellable>>,
170 callback: P,
171 ) {
172 let main_context = glib::MainContext::ref_thread_default();
173 let is_main_context_owner = main_context.is_owner();
174 let has_acquired_main_context = (!is_main_context_owner)
175 .then(|| main_context.acquire().ok())
176 .flatten();
177 assert!(
178 is_main_context_owner || has_acquired_main_context.is_some(),
179 "Async operations only allowed if the thread is owning the MainContext"
180 );
181
182 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
183 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
184 unsafe extern "C" fn open_multiple_trampoline<
185 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
186 >(
187 _source_object: *mut glib::gobject_ffi::GObject,
188 res: *mut gio::ffi::GAsyncResult,
189 user_data: glib::ffi::gpointer,
190 ) {
191 let mut error = std::ptr::null_mut();
192 let ret = ffi::gtk_file_dialog_open_multiple_finish(
193 _source_object as *mut _,
194 res,
195 &mut error,
196 );
197 let result = if error.is_null() {
198 Ok(from_glib_full(ret))
199 } else {
200 Err(from_glib_full(error))
201 };
202 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
203 Box_::from_raw(user_data as *mut _);
204 let callback: P = callback.into_inner();
205 callback(result);
206 }
207 let callback = open_multiple_trampoline::<P>;
208 unsafe {
209 ffi::gtk_file_dialog_open_multiple(
210 self.to_glib_none().0,
211 parent.map(|p| p.as_ref()).to_glib_none().0,
212 cancellable.map(|p| p.as_ref()).to_glib_none().0,
213 Some(callback),
214 Box_::into_raw(user_data) as *mut _,
215 );
216 }
217 }
218
219 pub fn open_multiple_future(
220 &self,
221 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
222 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
223 {
224 let parent = parent.map(ToOwned::to_owned);
225 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
226 obj.open_multiple(
227 parent.as_ref().map(::std::borrow::Borrow::borrow),
228 Some(cancellable),
229 move |res| {
230 send.resolve(res);
231 },
232 );
233 }))
234 }
235
236 #[cfg(feature = "v4_18")]
237 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
238 #[doc(alias = "gtk_file_dialog_open_multiple_text_files")]
239 pub fn open_multiple_text_files<
240 P: FnOnce(Result<(gio::ListModel, glib::GString), glib::Error>) + 'static,
241 >(
242 &self,
243 parent: Option<&impl IsA<Window>>,
244 cancellable: Option<&impl IsA<gio::Cancellable>>,
245 callback: P,
246 ) {
247 let main_context = glib::MainContext::ref_thread_default();
248 let is_main_context_owner = main_context.is_owner();
249 let has_acquired_main_context = (!is_main_context_owner)
250 .then(|| main_context.acquire().ok())
251 .flatten();
252 assert!(
253 is_main_context_owner || has_acquired_main_context.is_some(),
254 "Async operations only allowed if the thread is owning the MainContext"
255 );
256
257 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
258 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
259 unsafe extern "C" fn open_multiple_text_files_trampoline<
260 P: FnOnce(Result<(gio::ListModel, glib::GString), glib::Error>) + 'static,
261 >(
262 _source_object: *mut glib::gobject_ffi::GObject,
263 res: *mut gio::ffi::GAsyncResult,
264 user_data: glib::ffi::gpointer,
265 ) {
266 let mut error = std::ptr::null_mut();
267 let mut encoding = std::ptr::null();
268 let ret = ffi::gtk_file_dialog_open_multiple_text_files_finish(
269 _source_object as *mut _,
270 res,
271 &mut encoding,
272 &mut error,
273 );
274 let result = if error.is_null() {
275 Ok((from_glib_full(ret), from_glib_none(encoding)))
276 } else {
277 Err(from_glib_full(error))
278 };
279 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
280 Box_::from_raw(user_data as *mut _);
281 let callback: P = callback.into_inner();
282 callback(result);
283 }
284 let callback = open_multiple_text_files_trampoline::<P>;
285 unsafe {
286 ffi::gtk_file_dialog_open_multiple_text_files(
287 self.to_glib_none().0,
288 parent.map(|p| p.as_ref()).to_glib_none().0,
289 cancellable.map(|p| p.as_ref()).to_glib_none().0,
290 Some(callback),
291 Box_::into_raw(user_data) as *mut _,
292 );
293 }
294 }
295
296 #[cfg(feature = "v4_18")]
297 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
298 pub fn open_multiple_text_files_future(
299 &self,
300 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
301 ) -> Pin<
302 Box_<
303 dyn std::future::Future<Output = Result<(gio::ListModel, glib::GString), glib::Error>>
304 + 'static,
305 >,
306 > {
307 let parent = parent.map(ToOwned::to_owned);
308 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
309 obj.open_multiple_text_files(
310 parent.as_ref().map(::std::borrow::Borrow::borrow),
311 Some(cancellable),
312 move |res| {
313 send.resolve(res);
314 },
315 );
316 }))
317 }
318
319 #[cfg(feature = "v4_18")]
320 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
321 #[doc(alias = "gtk_file_dialog_open_text_file")]
322 pub fn open_text_file<P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static>(
323 &self,
324 parent: Option<&impl IsA<Window>>,
325 cancellable: Option<&impl IsA<gio::Cancellable>>,
326 callback: P,
327 ) {
328 let main_context = glib::MainContext::ref_thread_default();
329 let is_main_context_owner = main_context.is_owner();
330 let has_acquired_main_context = (!is_main_context_owner)
331 .then(|| main_context.acquire().ok())
332 .flatten();
333 assert!(
334 is_main_context_owner || has_acquired_main_context.is_some(),
335 "Async operations only allowed if the thread is owning the MainContext"
336 );
337
338 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
339 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
340 unsafe extern "C" fn open_text_file_trampoline<
341 P: FnOnce(Result<(gio::File, glib::GString), glib::Error>) + 'static,
342 >(
343 _source_object: *mut glib::gobject_ffi::GObject,
344 res: *mut gio::ffi::GAsyncResult,
345 user_data: glib::ffi::gpointer,
346 ) {
347 let mut error = std::ptr::null_mut();
348 let mut encoding = std::ptr::null();
349 let ret = ffi::gtk_file_dialog_open_text_file_finish(
350 _source_object as *mut _,
351 res,
352 &mut encoding,
353 &mut error,
354 );
355 let result = if error.is_null() {
356 Ok((from_glib_full(ret), from_glib_none(encoding)))
357 } else {
358 Err(from_glib_full(error))
359 };
360 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
361 Box_::from_raw(user_data as *mut _);
362 let callback: P = callback.into_inner();
363 callback(result);
364 }
365 let callback = open_text_file_trampoline::<P>;
366 unsafe {
367 ffi::gtk_file_dialog_open_text_file(
368 self.to_glib_none().0,
369 parent.map(|p| p.as_ref()).to_glib_none().0,
370 cancellable.map(|p| p.as_ref()).to_glib_none().0,
371 Some(callback),
372 Box_::into_raw(user_data) as *mut _,
373 );
374 }
375 }
376
377 #[cfg(feature = "v4_18")]
378 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
379 pub fn open_text_file_future(
380 &self,
381 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
382 ) -> Pin<
383 Box_<
384 dyn std::future::Future<Output = Result<(gio::File, glib::GString), glib::Error>>
385 + 'static,
386 >,
387 > {
388 let parent = parent.map(ToOwned::to_owned);
389 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
390 obj.open_text_file(
391 parent.as_ref().map(::std::borrow::Borrow::borrow),
392 Some(cancellable),
393 move |res| {
394 send.resolve(res);
395 },
396 );
397 }))
398 }
399
400 #[doc(alias = "gtk_file_dialog_save")]
401 pub fn save<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
402 &self,
403 parent: Option<&impl IsA<Window>>,
404 cancellable: Option<&impl IsA<gio::Cancellable>>,
405 callback: P,
406 ) {
407 let main_context = glib::MainContext::ref_thread_default();
408 let is_main_context_owner = main_context.is_owner();
409 let has_acquired_main_context = (!is_main_context_owner)
410 .then(|| main_context.acquire().ok())
411 .flatten();
412 assert!(
413 is_main_context_owner || has_acquired_main_context.is_some(),
414 "Async operations only allowed if the thread is owning the MainContext"
415 );
416
417 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
418 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
419 unsafe extern "C" fn save_trampoline<
420 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
421 >(
422 _source_object: *mut glib::gobject_ffi::GObject,
423 res: *mut gio::ffi::GAsyncResult,
424 user_data: glib::ffi::gpointer,
425 ) {
426 let mut error = std::ptr::null_mut();
427 let ret = ffi::gtk_file_dialog_save_finish(_source_object as *mut _, res, &mut error);
428 let result = if error.is_null() {
429 Ok(from_glib_full(ret))
430 } else {
431 Err(from_glib_full(error))
432 };
433 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
434 Box_::from_raw(user_data as *mut _);
435 let callback: P = callback.into_inner();
436 callback(result);
437 }
438 let callback = save_trampoline::<P>;
439 unsafe {
440 ffi::gtk_file_dialog_save(
441 self.to_glib_none().0,
442 parent.map(|p| p.as_ref()).to_glib_none().0,
443 cancellable.map(|p| p.as_ref()).to_glib_none().0,
444 Some(callback),
445 Box_::into_raw(user_data) as *mut _,
446 );
447 }
448 }
449
450 pub fn save_future(
451 &self,
452 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
453 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
454 let parent = parent.map(ToOwned::to_owned);
455 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
456 obj.save(
457 parent.as_ref().map(::std::borrow::Borrow::borrow),
458 Some(cancellable),
459 move |res| {
460 send.resolve(res);
461 },
462 );
463 }))
464 }
465
466 #[cfg(feature = "v4_18")]
467 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
468 #[doc(alias = "gtk_file_dialog_save_text_file")]
469 pub fn save_text_file<
470 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
471 >(
472 &self,
473 parent: Option<&impl IsA<Window>>,
474 cancellable: Option<&impl IsA<gio::Cancellable>>,
475 callback: P,
476 ) {
477 let main_context = glib::MainContext::ref_thread_default();
478 let is_main_context_owner = main_context.is_owner();
479 let has_acquired_main_context = (!is_main_context_owner)
480 .then(|| main_context.acquire().ok())
481 .flatten();
482 assert!(
483 is_main_context_owner || has_acquired_main_context.is_some(),
484 "Async operations only allowed if the thread is owning the MainContext"
485 );
486
487 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
488 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
489 unsafe extern "C" fn save_text_file_trampoline<
490 P: FnOnce(Result<(gio::File, glib::GString, glib::GString), glib::Error>) + 'static,
491 >(
492 _source_object: *mut glib::gobject_ffi::GObject,
493 res: *mut gio::ffi::GAsyncResult,
494 user_data: glib::ffi::gpointer,
495 ) {
496 let mut error = std::ptr::null_mut();
497 let mut encoding = std::ptr::null();
498 let mut line_ending = std::ptr::null();
499 let ret = ffi::gtk_file_dialog_save_text_file_finish(
500 _source_object as *mut _,
501 res,
502 &mut encoding,
503 &mut line_ending,
504 &mut error,
505 );
506 let result = if error.is_null() {
507 Ok((
508 from_glib_full(ret),
509 from_glib_none(encoding),
510 from_glib_none(line_ending),
511 ))
512 } else {
513 Err(from_glib_full(error))
514 };
515 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
516 Box_::from_raw(user_data as *mut _);
517 let callback: P = callback.into_inner();
518 callback(result);
519 }
520 let callback = save_text_file_trampoline::<P>;
521 unsafe {
522 ffi::gtk_file_dialog_save_text_file(
523 self.to_glib_none().0,
524 parent.map(|p| p.as_ref()).to_glib_none().0,
525 cancellable.map(|p| p.as_ref()).to_glib_none().0,
526 Some(callback),
527 Box_::into_raw(user_data) as *mut _,
528 );
529 }
530 }
531
532 #[cfg(feature = "v4_18")]
533 #[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
534 pub fn save_text_file_future(
535 &self,
536 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
537 ) -> Pin<
538 Box_<
539 dyn std::future::Future<
540 Output = Result<(gio::File, glib::GString, glib::GString), glib::Error>,
541 > + 'static,
542 >,
543 > {
544 let parent = parent.map(ToOwned::to_owned);
545 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
546 obj.save_text_file(
547 parent.as_ref().map(::std::borrow::Borrow::borrow),
548 Some(cancellable),
549 move |res| {
550 send.resolve(res);
551 },
552 );
553 }))
554 }
555
556 #[doc(alias = "gtk_file_dialog_select_folder")]
557 pub fn select_folder<P: FnOnce(Result<gio::File, glib::Error>) + 'static>(
558 &self,
559 parent: Option<&impl IsA<Window>>,
560 cancellable: Option<&impl IsA<gio::Cancellable>>,
561 callback: P,
562 ) {
563 let main_context = glib::MainContext::ref_thread_default();
564 let is_main_context_owner = main_context.is_owner();
565 let has_acquired_main_context = (!is_main_context_owner)
566 .then(|| main_context.acquire().ok())
567 .flatten();
568 assert!(
569 is_main_context_owner || has_acquired_main_context.is_some(),
570 "Async operations only allowed if the thread is owning the MainContext"
571 );
572
573 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
574 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
575 unsafe extern "C" fn select_folder_trampoline<
576 P: FnOnce(Result<gio::File, glib::Error>) + 'static,
577 >(
578 _source_object: *mut glib::gobject_ffi::GObject,
579 res: *mut gio::ffi::GAsyncResult,
580 user_data: glib::ffi::gpointer,
581 ) {
582 let mut error = std::ptr::null_mut();
583 let ret = ffi::gtk_file_dialog_select_folder_finish(
584 _source_object as *mut _,
585 res,
586 &mut error,
587 );
588 let result = if error.is_null() {
589 Ok(from_glib_full(ret))
590 } else {
591 Err(from_glib_full(error))
592 };
593 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
594 Box_::from_raw(user_data as *mut _);
595 let callback: P = callback.into_inner();
596 callback(result);
597 }
598 let callback = select_folder_trampoline::<P>;
599 unsafe {
600 ffi::gtk_file_dialog_select_folder(
601 self.to_glib_none().0,
602 parent.map(|p| p.as_ref()).to_glib_none().0,
603 cancellable.map(|p| p.as_ref()).to_glib_none().0,
604 Some(callback),
605 Box_::into_raw(user_data) as *mut _,
606 );
607 }
608 }
609
610 pub fn select_folder_future(
611 &self,
612 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
613 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::File, glib::Error>> + 'static>> {
614 let parent = parent.map(ToOwned::to_owned);
615 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
616 obj.select_folder(
617 parent.as_ref().map(::std::borrow::Borrow::borrow),
618 Some(cancellable),
619 move |res| {
620 send.resolve(res);
621 },
622 );
623 }))
624 }
625
626 #[doc(alias = "gtk_file_dialog_select_multiple_folders")]
627 pub fn select_multiple_folders<P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static>(
628 &self,
629 parent: Option<&impl IsA<Window>>,
630 cancellable: Option<&impl IsA<gio::Cancellable>>,
631 callback: P,
632 ) {
633 let main_context = glib::MainContext::ref_thread_default();
634 let is_main_context_owner = main_context.is_owner();
635 let has_acquired_main_context = (!is_main_context_owner)
636 .then(|| main_context.acquire().ok())
637 .flatten();
638 assert!(
639 is_main_context_owner || has_acquired_main_context.is_some(),
640 "Async operations only allowed if the thread is owning the MainContext"
641 );
642
643 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
644 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
645 unsafe extern "C" fn select_multiple_folders_trampoline<
646 P: FnOnce(Result<gio::ListModel, glib::Error>) + 'static,
647 >(
648 _source_object: *mut glib::gobject_ffi::GObject,
649 res: *mut gio::ffi::GAsyncResult,
650 user_data: glib::ffi::gpointer,
651 ) {
652 let mut error = std::ptr::null_mut();
653 let ret = ffi::gtk_file_dialog_select_multiple_folders_finish(
654 _source_object as *mut _,
655 res,
656 &mut error,
657 );
658 let result = if error.is_null() {
659 Ok(from_glib_full(ret))
660 } else {
661 Err(from_glib_full(error))
662 };
663 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
664 Box_::from_raw(user_data as *mut _);
665 let callback: P = callback.into_inner();
666 callback(result);
667 }
668 let callback = select_multiple_folders_trampoline::<P>;
669 unsafe {
670 ffi::gtk_file_dialog_select_multiple_folders(
671 self.to_glib_none().0,
672 parent.map(|p| p.as_ref()).to_glib_none().0,
673 cancellable.map(|p| p.as_ref()).to_glib_none().0,
674 Some(callback),
675 Box_::into_raw(user_data) as *mut _,
676 );
677 }
678 }
679
680 pub fn select_multiple_folders_future(
681 &self,
682 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
683 ) -> Pin<Box_<dyn std::future::Future<Output = Result<gio::ListModel, glib::Error>> + 'static>>
684 {
685 let parent = parent.map(ToOwned::to_owned);
686 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
687 obj.select_multiple_folders(
688 parent.as_ref().map(::std::borrow::Borrow::borrow),
689 Some(cancellable),
690 move |res| {
691 send.resolve(res);
692 },
693 );
694 }))
695 }
696
697 #[doc(alias = "gtk_file_dialog_set_accept_label")]
698 #[doc(alias = "accept-label")]
699 pub fn set_accept_label(&self, accept_label: Option<&str>) {
700 unsafe {
701 ffi::gtk_file_dialog_set_accept_label(
702 self.to_glib_none().0,
703 accept_label.to_glib_none().0,
704 );
705 }
706 }
707
708 #[doc(alias = "gtk_file_dialog_set_default_filter")]
709 #[doc(alias = "default-filter")]
710 pub fn set_default_filter(&self, filter: Option<&FileFilter>) {
711 unsafe {
712 ffi::gtk_file_dialog_set_default_filter(self.to_glib_none().0, filter.to_glib_none().0);
713 }
714 }
715
716 #[doc(alias = "gtk_file_dialog_set_filters")]
717 #[doc(alias = "filters")]
718 pub fn set_filters(&self, filters: Option<&impl IsA<gio::ListModel>>) {
719 unsafe {
720 ffi::gtk_file_dialog_set_filters(
721 self.to_glib_none().0,
722 filters.map(|p| p.as_ref()).to_glib_none().0,
723 );
724 }
725 }
726
727 #[doc(alias = "gtk_file_dialog_set_initial_file")]
728 #[doc(alias = "initial-file")]
729 pub fn set_initial_file(&self, file: Option<&impl IsA<gio::File>>) {
730 unsafe {
731 ffi::gtk_file_dialog_set_initial_file(
732 self.to_glib_none().0,
733 file.map(|p| p.as_ref()).to_glib_none().0,
734 );
735 }
736 }
737
738 #[doc(alias = "gtk_file_dialog_set_initial_folder")]
739 #[doc(alias = "initial-folder")]
740 pub fn set_initial_folder(&self, folder: Option<&impl IsA<gio::File>>) {
741 unsafe {
742 ffi::gtk_file_dialog_set_initial_folder(
743 self.to_glib_none().0,
744 folder.map(|p| p.as_ref()).to_glib_none().0,
745 );
746 }
747 }
748
749 #[doc(alias = "gtk_file_dialog_set_initial_name")]
750 #[doc(alias = "initial-name")]
751 pub fn set_initial_name(&self, name: Option<&str>) {
752 unsafe {
753 ffi::gtk_file_dialog_set_initial_name(self.to_glib_none().0, name.to_glib_none().0);
754 }
755 }
756
757 #[doc(alias = "gtk_file_dialog_set_modal")]
758 #[doc(alias = "modal")]
759 pub fn set_modal(&self, modal: bool) {
760 unsafe {
761 ffi::gtk_file_dialog_set_modal(self.to_glib_none().0, modal.into_glib());
762 }
763 }
764
765 #[doc(alias = "gtk_file_dialog_set_title")]
766 #[doc(alias = "title")]
767 pub fn set_title(&self, title: &str) {
768 unsafe {
769 ffi::gtk_file_dialog_set_title(self.to_glib_none().0, title.to_glib_none().0);
770 }
771 }
772
773 #[cfg(feature = "v4_10")]
774 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
775 #[doc(alias = "accept-label")]
776 pub fn connect_accept_label_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
777 unsafe extern "C" fn notify_accept_label_trampoline<F: Fn(&FileDialog) + 'static>(
778 this: *mut ffi::GtkFileDialog,
779 _param_spec: glib::ffi::gpointer,
780 f: glib::ffi::gpointer,
781 ) {
782 let f: &F = &*(f as *const F);
783 f(&from_glib_borrow(this))
784 }
785 unsafe {
786 let f: Box_<F> = Box_::new(f);
787 connect_raw(
788 self.as_ptr() as *mut _,
789 c"notify::accept-label".as_ptr() as *const _,
790 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
791 notify_accept_label_trampoline::<F> as *const (),
792 )),
793 Box_::into_raw(f),
794 )
795 }
796 }
797
798 #[cfg(feature = "v4_10")]
799 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
800 #[doc(alias = "default-filter")]
801 pub fn connect_default_filter_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
802 unsafe extern "C" fn notify_default_filter_trampoline<F: Fn(&FileDialog) + 'static>(
803 this: *mut ffi::GtkFileDialog,
804 _param_spec: glib::ffi::gpointer,
805 f: glib::ffi::gpointer,
806 ) {
807 let f: &F = &*(f as *const F);
808 f(&from_glib_borrow(this))
809 }
810 unsafe {
811 let f: Box_<F> = Box_::new(f);
812 connect_raw(
813 self.as_ptr() as *mut _,
814 c"notify::default-filter".as_ptr() as *const _,
815 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
816 notify_default_filter_trampoline::<F> as *const (),
817 )),
818 Box_::into_raw(f),
819 )
820 }
821 }
822
823 #[cfg(feature = "v4_10")]
824 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
825 #[doc(alias = "filters")]
826 pub fn connect_filters_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
827 unsafe extern "C" fn notify_filters_trampoline<F: Fn(&FileDialog) + 'static>(
828 this: *mut ffi::GtkFileDialog,
829 _param_spec: glib::ffi::gpointer,
830 f: glib::ffi::gpointer,
831 ) {
832 let f: &F = &*(f as *const F);
833 f(&from_glib_borrow(this))
834 }
835 unsafe {
836 let f: Box_<F> = Box_::new(f);
837 connect_raw(
838 self.as_ptr() as *mut _,
839 c"notify::filters".as_ptr() as *const _,
840 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
841 notify_filters_trampoline::<F> as *const (),
842 )),
843 Box_::into_raw(f),
844 )
845 }
846 }
847
848 #[cfg(feature = "v4_10")]
849 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
850 #[doc(alias = "initial-file")]
851 pub fn connect_initial_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
852 unsafe extern "C" fn notify_initial_file_trampoline<F: Fn(&FileDialog) + 'static>(
853 this: *mut ffi::GtkFileDialog,
854 _param_spec: glib::ffi::gpointer,
855 f: glib::ffi::gpointer,
856 ) {
857 let f: &F = &*(f as *const F);
858 f(&from_glib_borrow(this))
859 }
860 unsafe {
861 let f: Box_<F> = Box_::new(f);
862 connect_raw(
863 self.as_ptr() as *mut _,
864 c"notify::initial-file".as_ptr() as *const _,
865 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
866 notify_initial_file_trampoline::<F> as *const (),
867 )),
868 Box_::into_raw(f),
869 )
870 }
871 }
872
873 #[cfg(feature = "v4_10")]
874 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
875 #[doc(alias = "initial-folder")]
876 pub fn connect_initial_folder_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
877 unsafe extern "C" fn notify_initial_folder_trampoline<F: Fn(&FileDialog) + 'static>(
878 this: *mut ffi::GtkFileDialog,
879 _param_spec: glib::ffi::gpointer,
880 f: glib::ffi::gpointer,
881 ) {
882 let f: &F = &*(f as *const F);
883 f(&from_glib_borrow(this))
884 }
885 unsafe {
886 let f: Box_<F> = Box_::new(f);
887 connect_raw(
888 self.as_ptr() as *mut _,
889 c"notify::initial-folder".as_ptr() as *const _,
890 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
891 notify_initial_folder_trampoline::<F> as *const (),
892 )),
893 Box_::into_raw(f),
894 )
895 }
896 }
897
898 #[cfg(feature = "v4_10")]
899 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
900 #[doc(alias = "initial-name")]
901 pub fn connect_initial_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
902 unsafe extern "C" fn notify_initial_name_trampoline<F: Fn(&FileDialog) + 'static>(
903 this: *mut ffi::GtkFileDialog,
904 _param_spec: glib::ffi::gpointer,
905 f: glib::ffi::gpointer,
906 ) {
907 let f: &F = &*(f as *const F);
908 f(&from_glib_borrow(this))
909 }
910 unsafe {
911 let f: Box_<F> = Box_::new(f);
912 connect_raw(
913 self.as_ptr() as *mut _,
914 c"notify::initial-name".as_ptr() as *const _,
915 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
916 notify_initial_name_trampoline::<F> as *const (),
917 )),
918 Box_::into_raw(f),
919 )
920 }
921 }
922
923 #[cfg(feature = "v4_10")]
924 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
925 #[doc(alias = "modal")]
926 pub fn connect_modal_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
927 unsafe extern "C" fn notify_modal_trampoline<F: Fn(&FileDialog) + 'static>(
928 this: *mut ffi::GtkFileDialog,
929 _param_spec: glib::ffi::gpointer,
930 f: glib::ffi::gpointer,
931 ) {
932 let f: &F = &*(f as *const F);
933 f(&from_glib_borrow(this))
934 }
935 unsafe {
936 let f: Box_<F> = Box_::new(f);
937 connect_raw(
938 self.as_ptr() as *mut _,
939 c"notify::modal".as_ptr() as *const _,
940 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
941 notify_modal_trampoline::<F> as *const (),
942 )),
943 Box_::into_raw(f),
944 )
945 }
946 }
947
948 #[cfg(feature = "v4_10")]
949 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
950 #[doc(alias = "title")]
951 pub fn connect_title_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
952 unsafe extern "C" fn notify_title_trampoline<F: Fn(&FileDialog) + 'static>(
953 this: *mut ffi::GtkFileDialog,
954 _param_spec: glib::ffi::gpointer,
955 f: glib::ffi::gpointer,
956 ) {
957 let f: &F = &*(f as *const F);
958 f(&from_glib_borrow(this))
959 }
960 unsafe {
961 let f: Box_<F> = Box_::new(f);
962 connect_raw(
963 self.as_ptr() as *mut _,
964 c"notify::title".as_ptr() as *const _,
965 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
966 notify_title_trampoline::<F> as *const (),
967 )),
968 Box_::into_raw(f),
969 )
970 }
971 }
972}
973
974#[cfg(feature = "v4_10")]
975#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
976impl Default for FileDialog {
977 fn default() -> Self {
978 Self::new()
979 }
980}
981
982#[must_use = "The builder must be built to be used"]
987pub struct FileDialogBuilder {
988 builder: glib::object::ObjectBuilder<'static, FileDialog>,
989}
990
991impl FileDialogBuilder {
992 fn new() -> Self {
993 Self {
994 builder: glib::object::Object::builder(),
995 }
996 }
997
998 #[cfg(feature = "v4_10")]
999 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1000 pub fn accept_label(self, accept_label: impl Into<glib::GString>) -> Self {
1001 Self {
1002 builder: self.builder.property("accept-label", accept_label.into()),
1003 }
1004 }
1005
1006 #[cfg(feature = "v4_10")]
1007 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1008 pub fn default_filter(self, default_filter: &FileFilter) -> Self {
1009 Self {
1010 builder: self
1011 .builder
1012 .property("default-filter", default_filter.clone()),
1013 }
1014 }
1015
1016 #[cfg(feature = "v4_10")]
1017 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1018 pub fn filters(self, filters: &impl IsA<gio::ListModel>) -> Self {
1019 Self {
1020 builder: self.builder.property("filters", filters.clone().upcast()),
1021 }
1022 }
1023
1024 #[cfg(feature = "v4_10")]
1025 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1026 pub fn initial_file(self, initial_file: &impl IsA<gio::File>) -> Self {
1027 Self {
1028 builder: self
1029 .builder
1030 .property("initial-file", initial_file.clone().upcast()),
1031 }
1032 }
1033
1034 #[cfg(feature = "v4_10")]
1035 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1036 pub fn initial_folder(self, initial_folder: &impl IsA<gio::File>) -> Self {
1037 Self {
1038 builder: self
1039 .builder
1040 .property("initial-folder", initial_folder.clone().upcast()),
1041 }
1042 }
1043
1044 #[cfg(feature = "v4_10")]
1045 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1046 pub fn initial_name(self, initial_name: impl Into<glib::GString>) -> Self {
1047 Self {
1048 builder: self.builder.property("initial-name", initial_name.into()),
1049 }
1050 }
1051
1052 #[cfg(feature = "v4_10")]
1053 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1054 pub fn modal(self, modal: bool) -> Self {
1055 Self {
1056 builder: self.builder.property("modal", modal),
1057 }
1058 }
1059
1060 #[cfg(feature = "v4_10")]
1061 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
1062 pub fn title(self, title: impl Into<glib::GString>) -> Self {
1063 Self {
1064 builder: self.builder.property("title", title.into()),
1065 }
1066 }
1067
1068 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
1071 pub fn build(self) -> FileDialog {
1072 assert_initialized_main_thread!();
1073 self.builder.build()
1074 }
1075}