1use crate::{ffi, 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 = "GtkFileLauncher")]
15 pub struct FileLauncher(Object<ffi::GtkFileLauncher, ffi::GtkFileLauncherClass>);
16
17 match fn {
18 type_ => || ffi::gtk_file_launcher_get_type(),
19 }
20}
21
22impl FileLauncher {
23 #[doc(alias = "gtk_file_launcher_new")]
24 pub fn new(file: Option<&impl IsA<gio::File>>) -> FileLauncher {
25 assert_initialized_main_thread!();
26 unsafe {
27 from_glib_full(ffi::gtk_file_launcher_new(
28 file.map(|p| p.as_ref()).to_glib_none().0,
29 ))
30 }
31 }
32
33 #[cfg(feature = "v4_12")]
34 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
35 #[doc(alias = "gtk_file_launcher_get_always_ask")]
36 #[doc(alias = "get_always_ask")]
37 #[doc(alias = "always-ask")]
38 pub fn must_always_ask(&self) -> bool {
39 unsafe { from_glib(ffi::gtk_file_launcher_get_always_ask(self.to_glib_none().0)) }
40 }
41
42 #[doc(alias = "gtk_file_launcher_get_file")]
43 #[doc(alias = "get_file")]
44 pub fn file(&self) -> Option<gio::File> {
45 unsafe { from_glib_none(ffi::gtk_file_launcher_get_file(self.to_glib_none().0)) }
46 }
47
48 #[cfg(feature = "v4_14")]
49 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
50 #[doc(alias = "gtk_file_launcher_get_writable")]
51 #[doc(alias = "get_writable")]
52 #[doc(alias = "writable")]
53 pub fn is_writable(&self) -> bool {
54 unsafe { from_glib(ffi::gtk_file_launcher_get_writable(self.to_glib_none().0)) }
55 }
56
57 #[doc(alias = "gtk_file_launcher_launch")]
58 pub fn launch<P: FnOnce(Result<(), glib::Error>) + 'static>(
59 &self,
60 parent: Option<&impl IsA<Window>>,
61 cancellable: Option<&impl IsA<gio::Cancellable>>,
62 callback: P,
63 ) {
64 let main_context = glib::MainContext::ref_thread_default();
65 let is_main_context_owner = main_context.is_owner();
66 let has_acquired_main_context = (!is_main_context_owner)
67 .then(|| main_context.acquire().ok())
68 .flatten();
69 assert!(
70 is_main_context_owner || has_acquired_main_context.is_some(),
71 "Async operations only allowed if the thread is owning the MainContext"
72 );
73
74 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
75 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
76 unsafe extern "C" fn launch_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
77 _source_object: *mut glib::gobject_ffi::GObject,
78 res: *mut gio::ffi::GAsyncResult,
79 user_data: glib::ffi::gpointer,
80 ) {
81 let mut error = std::ptr::null_mut();
82 ffi::gtk_file_launcher_launch_finish(_source_object as *mut _, res, &mut error);
83 let result = if error.is_null() {
84 Ok(())
85 } else {
86 Err(from_glib_full(error))
87 };
88 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
89 Box_::from_raw(user_data as *mut _);
90 let callback: P = callback.into_inner();
91 callback(result);
92 }
93 let callback = launch_trampoline::<P>;
94 unsafe {
95 ffi::gtk_file_launcher_launch(
96 self.to_glib_none().0,
97 parent.map(|p| p.as_ref()).to_glib_none().0,
98 cancellable.map(|p| p.as_ref()).to_glib_none().0,
99 Some(callback),
100 Box_::into_raw(user_data) as *mut _,
101 );
102 }
103 }
104
105 pub fn launch_future(
106 &self,
107 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
108 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
109 let parent = parent.map(ToOwned::to_owned);
110 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
111 obj.launch(
112 parent.as_ref().map(::std::borrow::Borrow::borrow),
113 Some(cancellable),
114 move |res| {
115 send.resolve(res);
116 },
117 );
118 }))
119 }
120
121 #[doc(alias = "gtk_file_launcher_open_containing_folder")]
122 pub fn open_containing_folder<P: FnOnce(Result<(), glib::Error>) + 'static>(
123 &self,
124 parent: Option<&impl IsA<Window>>,
125 cancellable: Option<&impl IsA<gio::Cancellable>>,
126 callback: P,
127 ) {
128 let main_context = glib::MainContext::ref_thread_default();
129 let is_main_context_owner = main_context.is_owner();
130 let has_acquired_main_context = (!is_main_context_owner)
131 .then(|| main_context.acquire().ok())
132 .flatten();
133 assert!(
134 is_main_context_owner || has_acquired_main_context.is_some(),
135 "Async operations only allowed if the thread is owning the MainContext"
136 );
137
138 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
139 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
140 unsafe extern "C" fn open_containing_folder_trampoline<
141 P: FnOnce(Result<(), glib::Error>) + 'static,
142 >(
143 _source_object: *mut glib::gobject_ffi::GObject,
144 res: *mut gio::ffi::GAsyncResult,
145 user_data: glib::ffi::gpointer,
146 ) {
147 let mut error = std::ptr::null_mut();
148 ffi::gtk_file_launcher_open_containing_folder_finish(
149 _source_object as *mut _,
150 res,
151 &mut error,
152 );
153 let result = if error.is_null() {
154 Ok(())
155 } else {
156 Err(from_glib_full(error))
157 };
158 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
159 Box_::from_raw(user_data as *mut _);
160 let callback: P = callback.into_inner();
161 callback(result);
162 }
163 let callback = open_containing_folder_trampoline::<P>;
164 unsafe {
165 ffi::gtk_file_launcher_open_containing_folder(
166 self.to_glib_none().0,
167 parent.map(|p| p.as_ref()).to_glib_none().0,
168 cancellable.map(|p| p.as_ref()).to_glib_none().0,
169 Some(callback),
170 Box_::into_raw(user_data) as *mut _,
171 );
172 }
173 }
174
175 pub fn open_containing_folder_future(
176 &self,
177 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
178 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
179 let parent = parent.map(ToOwned::to_owned);
180 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
181 obj.open_containing_folder(
182 parent.as_ref().map(::std::borrow::Borrow::borrow),
183 Some(cancellable),
184 move |res| {
185 send.resolve(res);
186 },
187 );
188 }))
189 }
190
191 #[cfg(feature = "v4_12")]
192 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
193 #[doc(alias = "gtk_file_launcher_set_always_ask")]
194 #[doc(alias = "always-ask")]
195 pub fn set_always_ask(&self, always_ask: bool) {
196 unsafe {
197 ffi::gtk_file_launcher_set_always_ask(self.to_glib_none().0, always_ask.into_glib());
198 }
199 }
200
201 #[doc(alias = "gtk_file_launcher_set_file")]
202 #[doc(alias = "file")]
203 pub fn set_file(&self, file: Option<&impl IsA<gio::File>>) {
204 unsafe {
205 ffi::gtk_file_launcher_set_file(
206 self.to_glib_none().0,
207 file.map(|p| p.as_ref()).to_glib_none().0,
208 );
209 }
210 }
211
212 #[cfg(feature = "v4_14")]
213 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
214 #[doc(alias = "gtk_file_launcher_set_writable")]
215 #[doc(alias = "writable")]
216 pub fn set_writable(&self, writable: bool) {
217 unsafe {
218 ffi::gtk_file_launcher_set_writable(self.to_glib_none().0, writable.into_glib());
219 }
220 }
221
222 #[cfg(feature = "v4_12")]
223 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
224 #[doc(alias = "always-ask")]
225 pub fn connect_always_ask_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
226 unsafe extern "C" fn notify_always_ask_trampoline<F: Fn(&FileLauncher) + 'static>(
227 this: *mut ffi::GtkFileLauncher,
228 _param_spec: glib::ffi::gpointer,
229 f: glib::ffi::gpointer,
230 ) {
231 let f: &F = &*(f as *const F);
232 f(&from_glib_borrow(this))
233 }
234 unsafe {
235 let f: Box_<F> = Box_::new(f);
236 connect_raw(
237 self.as_ptr() as *mut _,
238 c"notify::always-ask".as_ptr() as *const _,
239 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
240 notify_always_ask_trampoline::<F> as *const (),
241 )),
242 Box_::into_raw(f),
243 )
244 }
245 }
246
247 #[cfg(feature = "v4_10")]
248 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
249 #[doc(alias = "file")]
250 pub fn connect_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
251 unsafe extern "C" fn notify_file_trampoline<F: Fn(&FileLauncher) + 'static>(
252 this: *mut ffi::GtkFileLauncher,
253 _param_spec: glib::ffi::gpointer,
254 f: glib::ffi::gpointer,
255 ) {
256 let f: &F = &*(f as *const F);
257 f(&from_glib_borrow(this))
258 }
259 unsafe {
260 let f: Box_<F> = Box_::new(f);
261 connect_raw(
262 self.as_ptr() as *mut _,
263 c"notify::file".as_ptr() as *const _,
264 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
265 notify_file_trampoline::<F> as *const (),
266 )),
267 Box_::into_raw(f),
268 )
269 }
270 }
271
272 #[cfg(feature = "v4_14")]
273 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
274 #[doc(alias = "writable")]
275 pub fn connect_writable_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
276 unsafe extern "C" fn notify_writable_trampoline<F: Fn(&FileLauncher) + 'static>(
277 this: *mut ffi::GtkFileLauncher,
278 _param_spec: glib::ffi::gpointer,
279 f: glib::ffi::gpointer,
280 ) {
281 let f: &F = &*(f as *const F);
282 f(&from_glib_borrow(this))
283 }
284 unsafe {
285 let f: Box_<F> = Box_::new(f);
286 connect_raw(
287 self.as_ptr() as *mut _,
288 c"notify::writable".as_ptr() as *const _,
289 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
290 notify_writable_trampoline::<F> as *const (),
291 )),
292 Box_::into_raw(f),
293 )
294 }
295 }
296}