Skip to main content

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}