1use std::boxed::Box as Box_;
4use std::pin::Pin;
5use std::ptr;
6
7use glib::prelude::*;
8use glib::translate::*;
9
10use crate::{ffi, AppInfo, AppLaunchContext, Cancellable};
11
12mod sealed {
13 pub trait Sealed {}
14 impl<T: super::IsA<super::AppInfo>> Sealed for T {}
15}
16
17pub trait AppInfoExtManual: sealed::Sealed + IsA<AppInfo> + 'static {
18 #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
34 #[doc(alias = "g_app_info_launch_uris_async")]
35 fn launch_uris_async<
36 P: IsA<AppLaunchContext>,
37 Q: IsA<Cancellable>,
38 R: FnOnce(Result<(), glib::Error>) + 'static,
39 >(
40 &self,
41 uris: &[&str],
42 context: Option<&P>,
43 cancellable: Option<&Q>,
44 callback: R,
45 ) {
46 let main_context = glib::MainContext::ref_thread_default();
47 let is_main_context_owner = main_context.is_owner();
48 let has_acquired_main_context = (!is_main_context_owner)
49 .then(|| main_context.acquire().ok())
50 .flatten();
51 assert!(
52 is_main_context_owner || has_acquired_main_context.is_some(),
53 "Async operations only allowed if the thread is owning the MainContext"
54 );
55
56 let user_data: Box_<(glib::thread_guard::ThreadGuard<R>, *mut *mut libc::c_char)> =
57 Box_::new((
58 glib::thread_guard::ThreadGuard::new(callback),
59 uris.to_glib_full(),
60 ));
61 unsafe extern "C" fn launch_uris_async_trampoline<
62 R: FnOnce(Result<(), glib::Error>) + 'static,
63 >(
64 _source_object: *mut glib::gobject_ffi::GObject,
65 res: *mut ffi::GAsyncResult,
66 user_data: glib::ffi::gpointer,
67 ) {
68 let mut error = ptr::null_mut();
69 let _ = ffi::g_app_info_launch_uris_finish(_source_object as *mut _, res, &mut error);
70 let result = if error.is_null() {
71 Ok(())
72 } else {
73 Err(from_glib_full(error))
74 };
75 let callback: Box_<(glib::thread_guard::ThreadGuard<R>, *mut *mut libc::c_char)> =
76 Box_::from_raw(user_data as *mut _);
77 let (callback, uris) = *callback;
78 let callback = callback.into_inner();
79 callback(result);
80 glib::ffi::g_strfreev(uris);
81 }
82 let callback = launch_uris_async_trampoline::<R>;
83 unsafe {
84 ffi::g_app_info_launch_uris_async(
85 self.as_ref().to_glib_none().0,
86 uris.to_glib_none().0,
87 context.map(|p| p.as_ref()).to_glib_none().0,
88 cancellable.map(|p| p.as_ref()).to_glib_none().0,
89 Some(callback),
90 Box_::into_raw(user_data) as *mut _,
91 );
92 }
93 }
94
95 #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
96 fn launch_uris_future<P: IsA<AppLaunchContext> + Clone + 'static>(
97 &self,
98 uris: &[&str],
99 context: Option<&P>,
100 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
101 let uris = uris.iter().copied().map(String::from).collect::<Vec<_>>();
102 let context = context.map(ToOwned::to_owned);
103 Box_::pin(crate::GioFuture::new(
104 self,
105 move |obj, cancellable, send| {
106 let uris = uris
107 .iter()
108 .map(::std::borrow::Borrow::borrow)
109 .collect::<Vec<_>>();
110 obj.launch_uris_async(
111 uris.as_ref(),
112 context.as_ref().map(::std::borrow::Borrow::borrow),
113 Some(cancellable),
114 move |res| {
115 send.resolve(res);
116 },
117 );
118 },
119 ))
120 }
121}
122
123impl<O: IsA<AppInfo>> AppInfoExtManual for O {}