gio/auto/subprocess.rs
1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{AsyncResult, Cancellable, Initable, InputStream, OutputStream, SubprocessFlags, ffi};
6use glib::{prelude::*, translate::*};
7use std::{boxed::Box as Box_, pin::Pin};
8
9glib::wrapper! {
10 /// remaining around for long periods of
11 /// time. [`wait()`][Self::wait()] can be used to wait for this to happen,
12 /// but it will happen even without the call being explicitly made.
13 ///
14 /// As a matter of principle, `GSubprocess` has no API that accepts
15 /// shell-style space-separated strings. It will, however, match the
16 /// typical shell behaviour of searching the `PATH` for executables that do
17 /// not contain a directory separator in their name. By default, the `PATH`
18 /// of the current process is used. You can specify
19 /// `G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP` to use the `PATH` of the
20 /// launcher environment instead.
21 ///
22 /// `GSubprocess` attempts to have a very simple API for most uses (ie:
23 /// spawning a subprocess with arguments and support for most typical
24 /// kinds of input and output redirection). See `Gio::Subprocess::new()`. The
25 /// [`SubprocessLauncher`][crate::SubprocessLauncher] API is provided for more complicated cases
26 /// (advanced types of redirection, environment variable manipulation,
27 /// change of working directory, child setup functions, etc).
28 ///
29 /// A typical use of `GSubprocess` will involve calling
30 /// `Gio::Subprocess::new()`, followed by [`wait_async()`][Self::wait_async()] or
31 /// [`wait()`][Self::wait()]. After the process exits, the status can be
32 /// checked using functions such as [`has_exited()`][Self::has_exited()] (which
33 /// are similar to the familiar `WIFEXITED`-style POSIX macros).
34 ///
35 /// Note that as of GLib 2.82, creating a `GSubprocess` causes the signal
36 /// `SIGPIPE` to be ignored for the remainder of the program. If you are writing
37 /// a command-line utility that uses `GSubprocess`, you may need to take into
38 /// account the fact that your program will not automatically be killed
39 /// if it tries to write to `stdout` after it has been closed.
40 ///
41 /// ## Properties
42 ///
43 ///
44 /// #### `argv`
45 /// Argument vector.
46 ///
47 /// Writable | Construct Only
48 ///
49 ///
50 /// #### `flags`
51 /// Subprocess flags.
52 ///
53 /// Writable | Construct Only
54 ///
55 /// # Implements
56 ///
57 /// [`trait@glib::ObjectExt`], [`InitableExt`][trait@crate::prelude::InitableExt]
58 #[doc(alias = "GSubprocess")]
59 pub struct Subprocess(Object<ffi::GSubprocess>) @implements Initable;
60
61 match fn {
62 type_ => || ffi::g_subprocess_get_type(),
63 }
64}
65
66impl Subprocess {
67 //#[doc(alias = "g_subprocess_new")]
68 //pub fn new(flags: SubprocessFlags, error: Option<&mut glib::Error>, argv0: &str, : /*Unknown conversion*//*Unimplemented*/Basic: VarArgs) -> Subprocess {
69 // unsafe { TODO: call ffi:g_subprocess_new() }
70 //}
71
72 /// Create a new process with the given flags and argument list.
73 ///
74 /// The argument list is expected to be [`None`]-terminated.
75 /// ## `argv`
76 /// commandline arguments for the subprocess
77 /// ## `flags`
78 /// flags that define the behaviour of the subprocess
79 ///
80 /// # Returns
81 ///
82 /// A newly created #GSubprocess, or [`None`] on error (and @error
83 /// will be set)
84 #[doc(alias = "g_subprocess_newv")]
85 pub fn newv(
86 argv: &[&std::ffi::OsStr],
87 flags: SubprocessFlags,
88 ) -> Result<Subprocess, glib::Error> {
89 unsafe {
90 let mut error = std::ptr::null_mut();
91 let ret = ffi::g_subprocess_newv(argv.to_glib_none().0, flags.into_glib(), &mut error);
92 if error.is_null() {
93 Ok(from_glib_full(ret))
94 } else {
95 Err(from_glib_full(error))
96 }
97 }
98 }
99
100 /// Communicate with the subprocess until it terminates, and all input
101 /// and output has been completed.
102 ///
103 /// If @stdin_buf is given, the subprocess must have been created with
104 /// [`SubprocessFlags::STDIN_PIPE`][crate::SubprocessFlags::STDIN_PIPE]. The given data is fed to the
105 /// stdin of the subprocess and the pipe is closed (ie: EOF).
106 ///
107 /// At the same time (as not to cause blocking when dealing with large
108 /// amounts of data), if [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE] or
109 /// [`SubprocessFlags::STDERR_PIPE`][crate::SubprocessFlags::STDERR_PIPE] were used, reads from those
110 /// streams. The data that was read is returned in @stdout and/or
111 /// the @stderr.
112 ///
113 /// If the subprocess was created with [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE],
114 /// @stdout_buf will contain the data read from stdout. Otherwise, for
115 /// subprocesses not created with [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE],
116 /// @stdout_buf will be set to [`None`]. Similar provisions apply to
117 /// @stderr_buf and [`SubprocessFlags::STDERR_PIPE`][crate::SubprocessFlags::STDERR_PIPE].
118 ///
119 /// As usual, any output variable may be given as [`None`] to ignore it.
120 ///
121 /// If you desire the stdout and stderr data to be interleaved, create
122 /// the subprocess with [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE] and
123 /// [`SubprocessFlags::STDERR_MERGE`][crate::SubprocessFlags::STDERR_MERGE]. The merged result will be returned
124 /// in @stdout_buf and @stderr_buf will be set to [`None`].
125 ///
126 /// In case of any error (including cancellation), [`false`] will be
127 /// returned with @error set. Some or all of the stdin data may have
128 /// been written. Any stdout or stderr data that has been read will be
129 /// discarded. None of the out variables (aside from @error) will have
130 /// been set to anything in particular and should not be inspected.
131 ///
132 /// In the case that [`true`] is returned, the subprocess has exited and the
133 /// exit status inspection APIs (eg: g_subprocess_get_if_exited(),
134 /// g_subprocess_get_exit_status()) may be used.
135 ///
136 /// You should not attempt to use any of the subprocess pipes after
137 /// starting this function, since they may be left in strange states,
138 /// even if the operation was cancelled. You should especially not
139 /// attempt to interact with the pipes while the operation is in progress
140 /// (either from another thread or if using the asynchronous version).
141 /// ## `stdin_buf`
142 /// data to send to the stdin of the subprocess, or [`None`]
143 /// ## `cancellable`
144 /// a #GCancellable
145 ///
146 /// # Returns
147 ///
148 /// [`true`] if successful
149 ///
150 /// ## `stdout_buf`
151 /// data read from the subprocess stdout
152 ///
153 /// ## `stderr_buf`
154 /// data read from the subprocess stderr
155 #[doc(alias = "g_subprocess_communicate")]
156 pub fn communicate(
157 &self,
158 stdin_buf: Option<&glib::Bytes>,
159 cancellable: Option<&impl IsA<Cancellable>>,
160 ) -> Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error> {
161 unsafe {
162 let mut stdout_buf = std::ptr::null_mut();
163 let mut stderr_buf = std::ptr::null_mut();
164 let mut error = std::ptr::null_mut();
165 let is_ok = ffi::g_subprocess_communicate(
166 self.to_glib_none().0,
167 stdin_buf.to_glib_none().0,
168 cancellable.map(|p| p.as_ref()).to_glib_none().0,
169 &mut stdout_buf,
170 &mut stderr_buf,
171 &mut error,
172 );
173 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
174 if error.is_null() {
175 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
176 } else {
177 Err(from_glib_full(error))
178 }
179 }
180 }
181
182 /// Asynchronous version of g_subprocess_communicate(). Complete
183 /// invocation with g_subprocess_communicate_finish().
184 /// ## `stdin_buf`
185 /// Input data, or [`None`]
186 /// ## `cancellable`
187 /// Cancellable
188 /// ## `callback`
189 /// Callback
190 #[doc(alias = "g_subprocess_communicate_async")]
191 pub fn communicate_async<
192 P: FnOnce(Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>) + 'static,
193 >(
194 &self,
195 stdin_buf: Option<&glib::Bytes>,
196 cancellable: Option<&impl IsA<Cancellable>>,
197 callback: P,
198 ) {
199 let main_context = glib::MainContext::ref_thread_default();
200 let is_main_context_owner = main_context.is_owner();
201 let has_acquired_main_context = (!is_main_context_owner)
202 .then(|| main_context.acquire().ok())
203 .flatten();
204 assert!(
205 is_main_context_owner || has_acquired_main_context.is_some(),
206 "Async operations only allowed if the thread is owning the MainContext"
207 );
208
209 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
210 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
211 unsafe extern "C" fn communicate_async_trampoline<
212 P: FnOnce(Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>) + 'static,
213 >(
214 _source_object: *mut glib::gobject_ffi::GObject,
215 res: *mut crate::ffi::GAsyncResult,
216 user_data: glib::ffi::gpointer,
217 ) {
218 unsafe {
219 let mut error = std::ptr::null_mut();
220 let mut stdout_buf = std::ptr::null_mut();
221 let mut stderr_buf = std::ptr::null_mut();
222 ffi::g_subprocess_communicate_finish(
223 _source_object as *mut _,
224 res,
225 &mut stdout_buf,
226 &mut stderr_buf,
227 &mut error,
228 );
229 let result = if error.is_null() {
230 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
231 } else {
232 Err(from_glib_full(error))
233 };
234 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
235 Box_::from_raw(user_data as *mut _);
236 let callback: P = callback.into_inner();
237 callback(result);
238 }
239 }
240 let callback = communicate_async_trampoline::<P>;
241 unsafe {
242 ffi::g_subprocess_communicate_async(
243 self.to_glib_none().0,
244 stdin_buf.to_glib_none().0,
245 cancellable.map(|p| p.as_ref()).to_glib_none().0,
246 Some(callback),
247 Box_::into_raw(user_data) as *mut _,
248 );
249 }
250 }
251
252 pub fn communicate_future(
253 &self,
254 stdin_buf: Option<&glib::Bytes>,
255 ) -> Pin<
256 Box_<
257 dyn std::future::Future<
258 Output = Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>,
259 > + 'static,
260 >,
261 > {
262 let stdin_buf = stdin_buf.map(ToOwned::to_owned);
263 Box_::pin(crate::GioFuture::new(
264 self,
265 move |obj, cancellable, send| {
266 obj.communicate_async(
267 stdin_buf.as_ref().map(::std::borrow::Borrow::borrow),
268 Some(cancellable),
269 move |res| {
270 send.resolve(res);
271 },
272 );
273 },
274 ))
275 }
276
277 /// Like g_subprocess_communicate(), but validates the output of the
278 /// process as UTF-8, and returns it as a regular NUL terminated string.
279 ///
280 /// On error, @stdout_buf and @stderr_buf will be set to undefined values and
281 /// should not be used.
282 /// ## `stdin_buf`
283 /// data to send to the stdin of the subprocess, or [`None`]
284 /// ## `cancellable`
285 /// a #GCancellable
286 ///
287 /// # Returns
288 ///
289 ///
290 /// ## `stdout_buf`
291 /// data read from the subprocess stdout
292 ///
293 /// ## `stderr_buf`
294 /// data read from the subprocess stderr
295 #[doc(alias = "g_subprocess_communicate_utf8")]
296 pub fn communicate_utf8(
297 &self,
298 stdin_buf: Option<&str>,
299 cancellable: Option<&impl IsA<Cancellable>>,
300 ) -> Result<(Option<glib::GString>, Option<glib::GString>), glib::Error> {
301 unsafe {
302 let mut stdout_buf = std::ptr::null_mut();
303 let mut stderr_buf = std::ptr::null_mut();
304 let mut error = std::ptr::null_mut();
305 let is_ok = ffi::g_subprocess_communicate_utf8(
306 self.to_glib_none().0,
307 stdin_buf.to_glib_none().0,
308 cancellable.map(|p| p.as_ref()).to_glib_none().0,
309 &mut stdout_buf,
310 &mut stderr_buf,
311 &mut error,
312 );
313 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
314 if error.is_null() {
315 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
316 } else {
317 Err(from_glib_full(error))
318 }
319 }
320 }
321
322 /// Use an operating-system specific method to attempt an immediate,
323 /// forceful termination of the process. There is no mechanism to
324 /// determine whether or not the request itself was successful;
325 /// however, you can use g_subprocess_wait() to monitor the status of
326 /// the process after calling this function.
327 ///
328 /// On Unix, this function sends `SIGKILL`.
329 #[doc(alias = "g_subprocess_force_exit")]
330 pub fn force_exit(&self) {
331 unsafe {
332 ffi::g_subprocess_force_exit(self.to_glib_none().0);
333 }
334 }
335
336 /// Check the exit status of the subprocess, given that it exited
337 /// normally. This is the value passed to the exit() system call or the
338 /// return value from main.
339 ///
340 /// This is equivalent to the system WEXITSTATUS macro.
341 ///
342 /// It is an error to call this function before g_subprocess_wait() and
343 /// unless g_subprocess_get_if_exited() returned [`true`].
344 ///
345 /// # Returns
346 ///
347 /// the exit status
348 #[doc(alias = "g_subprocess_get_exit_status")]
349 #[doc(alias = "get_exit_status")]
350 pub fn exit_status(&self) -> i32 {
351 unsafe { ffi::g_subprocess_get_exit_status(self.to_glib_none().0) }
352 }
353
354 /// On UNIX, returns the process ID as a decimal string.
355 /// On Windows, returns the result of GetProcessId() also as a string.
356 /// If the subprocess has terminated, this will return [`None`].
357 ///
358 /// # Returns
359 ///
360 /// the subprocess identifier, or [`None`] if the subprocess
361 /// has terminated
362 #[doc(alias = "g_subprocess_get_identifier")]
363 #[doc(alias = "get_identifier")]
364 pub fn identifier(&self) -> Option<glib::GString> {
365 unsafe { from_glib_none(ffi::g_subprocess_get_identifier(self.to_glib_none().0)) }
366 }
367
368 /// Check if the given subprocess exited normally (ie: by way of exit()
369 /// or return from main()).
370 ///
371 /// This is equivalent to the system WIFEXITED macro.
372 ///
373 /// It is an error to call this function before g_subprocess_wait() has
374 /// returned.
375 ///
376 /// # Returns
377 ///
378 /// [`true`] if the case of a normal exit
379 #[doc(alias = "g_subprocess_get_if_exited")]
380 #[doc(alias = "get_if_exited")]
381 pub fn has_exited(&self) -> bool {
382 unsafe { from_glib(ffi::g_subprocess_get_if_exited(self.to_glib_none().0)) }
383 }
384
385 /// Check if the given subprocess terminated in response to a signal.
386 ///
387 /// This is equivalent to the system WIFSIGNALED macro.
388 ///
389 /// It is an error to call this function before g_subprocess_wait() has
390 /// returned.
391 ///
392 /// # Returns
393 ///
394 /// [`true`] if the case of termination due to a signal
395 #[doc(alias = "g_subprocess_get_if_signaled")]
396 #[doc(alias = "get_if_signaled")]
397 pub fn has_signaled(&self) -> bool {
398 unsafe { from_glib(ffi::g_subprocess_get_if_signaled(self.to_glib_none().0)) }
399 }
400
401 /// Gets the raw status code of the process, as from waitpid().
402 ///
403 /// This value has no particular meaning, but it can be used with the
404 /// macros defined by the system headers such as WIFEXITED. It can also
405 /// be used with g_spawn_check_wait_status().
406 ///
407 /// It is more likely that you want to use g_subprocess_get_if_exited()
408 /// followed by g_subprocess_get_exit_status().
409 ///
410 /// It is an error to call this function before g_subprocess_wait() has
411 /// returned.
412 ///
413 /// # Returns
414 ///
415 /// the (meaningless) waitpid() exit status from the kernel
416 #[doc(alias = "g_subprocess_get_status")]
417 #[doc(alias = "get_status")]
418 pub fn status(&self) -> i32 {
419 unsafe { ffi::g_subprocess_get_status(self.to_glib_none().0) }
420 }
421
422 /// Gets the #GInputStream from which to read the stderr output of
423 /// @self.
424 ///
425 /// The process must have been created with [`SubprocessFlags::STDERR_PIPE`][crate::SubprocessFlags::STDERR_PIPE],
426 /// otherwise [`None`] will be returned.
427 ///
428 /// # Returns
429 ///
430 /// the stderr pipe
431 #[doc(alias = "g_subprocess_get_stderr_pipe")]
432 #[doc(alias = "get_stderr_pipe")]
433 pub fn stderr_pipe(&self) -> Option<InputStream> {
434 unsafe { from_glib_none(ffi::g_subprocess_get_stderr_pipe(self.to_glib_none().0)) }
435 }
436
437 /// Gets the #GOutputStream that you can write to in order to give data
438 /// to the stdin of @self.
439 ///
440 /// The process must have been created with [`SubprocessFlags::STDIN_PIPE`][crate::SubprocessFlags::STDIN_PIPE] and
441 /// not [`SubprocessFlags::STDIN_INHERIT`][crate::SubprocessFlags::STDIN_INHERIT], otherwise [`None`] will be returned.
442 ///
443 /// # Returns
444 ///
445 /// the stdout pipe
446 #[doc(alias = "g_subprocess_get_stdin_pipe")]
447 #[doc(alias = "get_stdin_pipe")]
448 pub fn stdin_pipe(&self) -> Option<OutputStream> {
449 unsafe { from_glib_none(ffi::g_subprocess_get_stdin_pipe(self.to_glib_none().0)) }
450 }
451
452 /// Gets the #GInputStream from which to read the stdout output of
453 /// @self.
454 ///
455 /// The process must have been created with [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE],
456 /// otherwise [`None`] will be returned.
457 ///
458 /// # Returns
459 ///
460 /// the stdout pipe
461 #[doc(alias = "g_subprocess_get_stdout_pipe")]
462 #[doc(alias = "get_stdout_pipe")]
463 pub fn stdout_pipe(&self) -> Option<InputStream> {
464 unsafe { from_glib_none(ffi::g_subprocess_get_stdout_pipe(self.to_glib_none().0)) }
465 }
466
467 /// Checks if the process was "successful". A process is considered
468 /// successful if it exited cleanly with an exit status of 0, either by
469 /// way of the exit() system call or return from main().
470 ///
471 /// It is an error to call this function before g_subprocess_wait() has
472 /// returned.
473 ///
474 /// # Returns
475 ///
476 /// [`true`] if the process exited cleanly with a exit status of 0
477 #[doc(alias = "g_subprocess_get_successful")]
478 #[doc(alias = "get_successful")]
479 pub fn is_successful(&self) -> bool {
480 unsafe { from_glib(ffi::g_subprocess_get_successful(self.to_glib_none().0)) }
481 }
482
483 /// Get the signal number that caused the subprocess to terminate, given
484 /// that it terminated due to a signal.
485 ///
486 /// This is equivalent to the system WTERMSIG macro.
487 ///
488 /// It is an error to call this function before g_subprocess_wait() and
489 /// unless g_subprocess_get_if_signaled() returned [`true`].
490 ///
491 /// # Returns
492 ///
493 /// the signal causing termination
494 #[doc(alias = "g_subprocess_get_term_sig")]
495 #[doc(alias = "get_term_sig")]
496 pub fn term_sig(&self) -> i32 {
497 unsafe { ffi::g_subprocess_get_term_sig(self.to_glib_none().0) }
498 }
499
500 /// Sends the UNIX signal @signal_num to the subprocess, if it is still
501 /// running.
502 ///
503 /// This API is race-free. If the subprocess has terminated, it will not
504 /// be signalled.
505 ///
506 /// This API is not available on Windows.
507 /// ## `signal_num`
508 /// the signal number to send
509 #[cfg(not(windows))]
510 #[cfg_attr(docsrs, doc(cfg(not(windows))))]
511 #[doc(alias = "g_subprocess_send_signal")]
512 pub fn send_signal(&self, signal_num: i32) {
513 unsafe {
514 ffi::g_subprocess_send_signal(self.to_glib_none().0, signal_num);
515 }
516 }
517
518 /// Synchronously wait for the subprocess to terminate.
519 ///
520 /// After the process terminates you can query its exit status with
521 /// functions such as g_subprocess_get_if_exited() and
522 /// g_subprocess_get_exit_status().
523 ///
524 /// This function does not fail in the case of the subprocess having
525 /// abnormal termination. See g_subprocess_wait_check() for that.
526 ///
527 /// Cancelling @cancellable doesn't kill the subprocess. Call
528 /// g_subprocess_force_exit() if it is desirable.
529 /// ## `cancellable`
530 /// a #GCancellable
531 ///
532 /// # Returns
533 ///
534 /// [`true`] on success, [`false`] if @cancellable was cancelled
535 #[doc(alias = "g_subprocess_wait")]
536 pub fn wait(&self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<(), glib::Error> {
537 unsafe {
538 let mut error = std::ptr::null_mut();
539 let is_ok = ffi::g_subprocess_wait(
540 self.to_glib_none().0,
541 cancellable.map(|p| p.as_ref()).to_glib_none().0,
542 &mut error,
543 );
544 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
545 if error.is_null() {
546 Ok(())
547 } else {
548 Err(from_glib_full(error))
549 }
550 }
551 }
552
553 /// Wait for the subprocess to terminate.
554 ///
555 /// This is the asynchronous version of g_subprocess_wait().
556 /// ## `cancellable`
557 /// a #GCancellable, or [`None`]
558 /// ## `callback`
559 /// a #GAsyncReadyCallback to call when the operation is complete
560 #[doc(alias = "g_subprocess_wait_async")]
561 pub fn wait_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
562 &self,
563 cancellable: Option<&impl IsA<Cancellable>>,
564 callback: P,
565 ) {
566 let main_context = glib::MainContext::ref_thread_default();
567 let is_main_context_owner = main_context.is_owner();
568 let has_acquired_main_context = (!is_main_context_owner)
569 .then(|| main_context.acquire().ok())
570 .flatten();
571 assert!(
572 is_main_context_owner || has_acquired_main_context.is_some(),
573 "Async operations only allowed if the thread is owning the MainContext"
574 );
575
576 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
577 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
578 unsafe extern "C" fn wait_async_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
579 _source_object: *mut glib::gobject_ffi::GObject,
580 res: *mut crate::ffi::GAsyncResult,
581 user_data: glib::ffi::gpointer,
582 ) {
583 unsafe {
584 let mut error = std::ptr::null_mut();
585 ffi::g_subprocess_wait_finish(_source_object as *mut _, res, &mut error);
586 let result = if error.is_null() {
587 Ok(())
588 } else {
589 Err(from_glib_full(error))
590 };
591 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
592 Box_::from_raw(user_data as *mut _);
593 let callback: P = callback.into_inner();
594 callback(result);
595 }
596 }
597 let callback = wait_async_trampoline::<P>;
598 unsafe {
599 ffi::g_subprocess_wait_async(
600 self.to_glib_none().0,
601 cancellable.map(|p| p.as_ref()).to_glib_none().0,
602 Some(callback),
603 Box_::into_raw(user_data) as *mut _,
604 );
605 }
606 }
607
608 pub fn wait_future(
609 &self,
610 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
611 Box_::pin(crate::GioFuture::new(
612 self,
613 move |obj, cancellable, send| {
614 obj.wait_async(Some(cancellable), move |res| {
615 send.resolve(res);
616 });
617 },
618 ))
619 }
620
621 /// Combines g_subprocess_wait() with g_spawn_check_wait_status().
622 /// ## `cancellable`
623 /// a #GCancellable
624 ///
625 /// # Returns
626 ///
627 /// [`true`] on success, [`false`] if process exited abnormally, or
628 /// @cancellable was cancelled
629 #[doc(alias = "g_subprocess_wait_check")]
630 pub fn wait_check(
631 &self,
632 cancellable: Option<&impl IsA<Cancellable>>,
633 ) -> Result<(), glib::Error> {
634 unsafe {
635 let mut error = std::ptr::null_mut();
636 let is_ok = ffi::g_subprocess_wait_check(
637 self.to_glib_none().0,
638 cancellable.map(|p| p.as_ref()).to_glib_none().0,
639 &mut error,
640 );
641 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
642 if error.is_null() {
643 Ok(())
644 } else {
645 Err(from_glib_full(error))
646 }
647 }
648 }
649
650 /// Combines g_subprocess_wait_async() with g_spawn_check_wait_status().
651 ///
652 /// This is the asynchronous version of g_subprocess_wait_check().
653 /// ## `cancellable`
654 /// a #GCancellable, or [`None`]
655 /// ## `callback`
656 /// a #GAsyncReadyCallback to call when the operation is complete
657 #[doc(alias = "g_subprocess_wait_check_async")]
658 pub fn wait_check_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
659 &self,
660 cancellable: Option<&impl IsA<Cancellable>>,
661 callback: P,
662 ) {
663 let main_context = glib::MainContext::ref_thread_default();
664 let is_main_context_owner = main_context.is_owner();
665 let has_acquired_main_context = (!is_main_context_owner)
666 .then(|| main_context.acquire().ok())
667 .flatten();
668 assert!(
669 is_main_context_owner || has_acquired_main_context.is_some(),
670 "Async operations only allowed if the thread is owning the MainContext"
671 );
672
673 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
674 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
675 unsafe extern "C" fn wait_check_async_trampoline<
676 P: FnOnce(Result<(), glib::Error>) + 'static,
677 >(
678 _source_object: *mut glib::gobject_ffi::GObject,
679 res: *mut crate::ffi::GAsyncResult,
680 user_data: glib::ffi::gpointer,
681 ) {
682 unsafe {
683 let mut error = std::ptr::null_mut();
684 ffi::g_subprocess_wait_check_finish(_source_object as *mut _, res, &mut error);
685 let result = if error.is_null() {
686 Ok(())
687 } else {
688 Err(from_glib_full(error))
689 };
690 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
691 Box_::from_raw(user_data as *mut _);
692 let callback: P = callback.into_inner();
693 callback(result);
694 }
695 }
696 let callback = wait_check_async_trampoline::<P>;
697 unsafe {
698 ffi::g_subprocess_wait_check_async(
699 self.to_glib_none().0,
700 cancellable.map(|p| p.as_ref()).to_glib_none().0,
701 Some(callback),
702 Box_::into_raw(user_data) as *mut _,
703 );
704 }
705 }
706
707 pub fn wait_check_future(
708 &self,
709 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
710 Box_::pin(crate::GioFuture::new(
711 self,
712 move |obj, cancellable, send| {
713 obj.wait_check_async(Some(cancellable), move |res| {
714 send.resolve(res);
715 });
716 },
717 ))
718 }
719}