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