1use crate::{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 = "GtkFileLauncher")]
51 pub struct FileLauncher(Object<ffi::GtkFileLauncher, ffi::GtkFileLauncherClass>);
52
53 match fn {
54 type_ => || ffi::gtk_file_launcher_get_type(),
55 }
56}
57
58impl FileLauncher {
59 #[doc(alias = "gtk_file_launcher_new")]
67 pub fn new(file: Option<&impl IsA<gio::File>>) -> FileLauncher {
68 assert_initialized_main_thread!();
69 unsafe {
70 from_glib_full(ffi::gtk_file_launcher_new(
71 file.map(|p| p.as_ref()).to_glib_none().0,
72 ))
73 }
74 }
75
76 #[cfg(feature = "v4_12")]
82 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
83 #[doc(alias = "gtk_file_launcher_get_always_ask")]
84 #[doc(alias = "get_always_ask")]
85 #[doc(alias = "always-ask")]
86 pub fn must_always_ask(&self) -> bool {
87 unsafe { from_glib(ffi::gtk_file_launcher_get_always_ask(self.to_glib_none().0)) }
88 }
89
90 #[doc(alias = "gtk_file_launcher_get_file")]
96 #[doc(alias = "get_file")]
97 pub fn file(&self) -> Option<gio::File> {
98 unsafe { from_glib_none(ffi::gtk_file_launcher_get_file(self.to_glib_none().0)) }
99 }
100
101 #[cfg(feature = "v4_14")]
107 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
108 #[doc(alias = "gtk_file_launcher_get_writable")]
109 #[doc(alias = "get_writable")]
110 #[doc(alias = "writable")]
111 pub fn is_writable(&self) -> bool {
112 unsafe { from_glib(ffi::gtk_file_launcher_get_writable(self.to_glib_none().0)) }
113 }
114
115 #[doc(alias = "gtk_file_launcher_launch")]
126 pub fn launch<P: FnOnce(Result<(), glib::Error>) + 'static>(
127 &self,
128 parent: Option<&impl IsA<Window>>,
129 cancellable: Option<&impl IsA<gio::Cancellable>>,
130 callback: P,
131 ) {
132 let main_context = glib::MainContext::ref_thread_default();
133 let is_main_context_owner = main_context.is_owner();
134 let has_acquired_main_context = (!is_main_context_owner)
135 .then(|| main_context.acquire().ok())
136 .flatten();
137 assert!(
138 is_main_context_owner || has_acquired_main_context.is_some(),
139 "Async operations only allowed if the thread is owning the MainContext"
140 );
141
142 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
143 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
144 unsafe extern "C" fn launch_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
145 _source_object: *mut glib::gobject_ffi::GObject,
146 res: *mut gio::ffi::GAsyncResult,
147 user_data: glib::ffi::gpointer,
148 ) {
149 unsafe {
150 let mut error = std::ptr::null_mut();
151 ffi::gtk_file_launcher_launch_finish(_source_object as *mut _, res, &mut error);
152 let result = if error.is_null() {
153 Ok(())
154 } else {
155 Err(from_glib_full(error))
156 };
157 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
158 Box_::from_raw(user_data as *mut _);
159 let callback: P = callback.into_inner();
160 callback(result);
161 }
162 }
163 let callback = launch_trampoline::<P>;
164 unsafe {
165 ffi::gtk_file_launcher_launch(
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 launch_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.launch(
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 #[doc(alias = "gtk_file_launcher_open_containing_folder")]
203 pub fn open_containing_folder<P: FnOnce(Result<(), glib::Error>) + 'static>(
204 &self,
205 parent: Option<&impl IsA<Window>>,
206 cancellable: Option<&impl IsA<gio::Cancellable>>,
207 callback: P,
208 ) {
209 let main_context = glib::MainContext::ref_thread_default();
210 let is_main_context_owner = main_context.is_owner();
211 let has_acquired_main_context = (!is_main_context_owner)
212 .then(|| main_context.acquire().ok())
213 .flatten();
214 assert!(
215 is_main_context_owner || has_acquired_main_context.is_some(),
216 "Async operations only allowed if the thread is owning the MainContext"
217 );
218
219 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
220 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
221 unsafe extern "C" fn open_containing_folder_trampoline<
222 P: FnOnce(Result<(), glib::Error>) + 'static,
223 >(
224 _source_object: *mut glib::gobject_ffi::GObject,
225 res: *mut gio::ffi::GAsyncResult,
226 user_data: glib::ffi::gpointer,
227 ) {
228 unsafe {
229 let mut error = std::ptr::null_mut();
230 ffi::gtk_file_launcher_open_containing_folder_finish(
231 _source_object as *mut _,
232 res,
233 &mut error,
234 );
235 let result = if error.is_null() {
236 Ok(())
237 } else {
238 Err(from_glib_full(error))
239 };
240 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
241 Box_::from_raw(user_data as *mut _);
242 let callback: P = callback.into_inner();
243 callback(result);
244 }
245 }
246 let callback = open_containing_folder_trampoline::<P>;
247 unsafe {
248 ffi::gtk_file_launcher_open_containing_folder(
249 self.to_glib_none().0,
250 parent.map(|p| p.as_ref()).to_glib_none().0,
251 cancellable.map(|p| p.as_ref()).to_glib_none().0,
252 Some(callback),
253 Box_::into_raw(user_data) as *mut _,
254 );
255 }
256 }
257
258 pub fn open_containing_folder_future(
259 &self,
260 parent: Option<&(impl IsA<Window> + Clone + 'static)>,
261 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
262 let parent = parent.map(ToOwned::to_owned);
263 Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
264 obj.open_containing_folder(
265 parent.as_ref().map(::std::borrow::Borrow::borrow),
266 Some(cancellable),
267 move |res| {
268 send.resolve(res);
269 },
270 );
271 }))
272 }
273
274 #[cfg(feature = "v4_12")]
281 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
282 #[doc(alias = "gtk_file_launcher_set_always_ask")]
283 #[doc(alias = "always-ask")]
284 pub fn set_always_ask(&self, always_ask: bool) {
285 unsafe {
286 ffi::gtk_file_launcher_set_always_ask(self.to_glib_none().0, always_ask.into_glib());
287 }
288 }
289
290 #[doc(alias = "gtk_file_launcher_set_file")]
294 #[doc(alias = "file")]
295 pub fn set_file(&self, file: Option<&impl IsA<gio::File>>) {
296 unsafe {
297 ffi::gtk_file_launcher_set_file(
298 self.to_glib_none().0,
299 file.map(|p| p.as_ref()).to_glib_none().0,
300 );
301 }
302 }
303
304 #[cfg(feature = "v4_14")]
308 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
309 #[doc(alias = "gtk_file_launcher_set_writable")]
310 #[doc(alias = "writable")]
311 pub fn set_writable(&self, writable: bool) {
312 unsafe {
313 ffi::gtk_file_launcher_set_writable(self.to_glib_none().0, writable.into_glib());
314 }
315 }
316
317 #[cfg(feature = "v4_12")]
318 #[cfg_attr(docsrs, doc(cfg(feature = "v4_12")))]
319 #[doc(alias = "always-ask")]
320 pub fn connect_always_ask_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
321 unsafe extern "C" fn notify_always_ask_trampoline<F: Fn(&FileLauncher) + 'static>(
322 this: *mut ffi::GtkFileLauncher,
323 _param_spec: glib::ffi::gpointer,
324 f: glib::ffi::gpointer,
325 ) {
326 unsafe {
327 let f: &F = &*(f as *const F);
328 f(&from_glib_borrow(this))
329 }
330 }
331 unsafe {
332 let f: Box_<F> = Box_::new(f);
333 connect_raw(
334 self.as_ptr() as *mut _,
335 c"notify::always-ask".as_ptr() as *const _,
336 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
337 notify_always_ask_trampoline::<F> as *const (),
338 )),
339 Box_::into_raw(f),
340 )
341 }
342 }
343
344 #[cfg(feature = "v4_10")]
345 #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
346 #[doc(alias = "file")]
347 pub fn connect_file_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
348 unsafe extern "C" fn notify_file_trampoline<F: Fn(&FileLauncher) + 'static>(
349 this: *mut ffi::GtkFileLauncher,
350 _param_spec: glib::ffi::gpointer,
351 f: glib::ffi::gpointer,
352 ) {
353 unsafe {
354 let f: &F = &*(f as *const F);
355 f(&from_glib_borrow(this))
356 }
357 }
358 unsafe {
359 let f: Box_<F> = Box_::new(f);
360 connect_raw(
361 self.as_ptr() as *mut _,
362 c"notify::file".as_ptr() as *const _,
363 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
364 notify_file_trampoline::<F> as *const (),
365 )),
366 Box_::into_raw(f),
367 )
368 }
369 }
370
371 #[cfg(feature = "v4_14")]
372 #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
373 #[doc(alias = "writable")]
374 pub fn connect_writable_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
375 unsafe extern "C" fn notify_writable_trampoline<F: Fn(&FileLauncher) + 'static>(
376 this: *mut ffi::GtkFileLauncher,
377 _param_spec: glib::ffi::gpointer,
378 f: glib::ffi::gpointer,
379 ) {
380 unsafe {
381 let f: &F = &*(f as *const F);
382 f(&from_glib_borrow(this))
383 }
384 }
385 unsafe {
386 let f: Box_<F> = Box_::new(f);
387 connect_raw(
388 self.as_ptr() as *mut _,
389 c"notify::writable".as_ptr() as *const _,
390 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
391 notify_writable_trampoline::<F> as *const (),
392 )),
393 Box_::into_raw(f),
394 )
395 }
396 }
397}