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    /// `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            unsafe {
252                let mut error = std::ptr::null_mut();
253                let mut stdout_buf = std::ptr::null_mut();
254                let mut stderr_buf = std::ptr::null_mut();
255                ffi::g_subprocess_communicate_finish(
256                    _source_object as *mut _,
257                    res,
258                    &mut stdout_buf,
259                    &mut stderr_buf,
260                    &mut error,
261                );
262                let result = if error.is_null() {
263                    Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
264                } else {
265                    Err(from_glib_full(error))
266                };
267                let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
268                    Box_::from_raw(user_data as *mut _);
269                let callback: P = callback.into_inner();
270                callback(result);
271            }
272        }
273        let callback = communicate_async_trampoline::<P>;
274        unsafe {
275            ffi::g_subprocess_communicate_async(
276                self.to_glib_none().0,
277                stdin_buf.to_glib_none().0,
278                cancellable.map(|p| p.as_ref()).to_glib_none().0,
279                Some(callback),
280                Box_::into_raw(user_data) as *mut _,
281            );
282        }
283    }
284
285    pub fn communicate_future(
286        &self,
287        stdin_buf: Option<&glib::Bytes>,
288    ) -> Pin<
289        Box_<
290            dyn std::future::Future<
291                    Output = Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>,
292                > + 'static,
293        >,
294    > {
295        let stdin_buf = stdin_buf.map(ToOwned::to_owned);
296        Box_::pin(crate::GioFuture::new(
297            self,
298            move |obj, cancellable, send| {
299                obj.communicate_async(
300                    stdin_buf.as_ref().map(::std::borrow::Borrow::borrow),
301                    Some(cancellable),
302                    move |res| {
303                        send.resolve(res);
304                    },
305                );
306            },
307        ))
308    }
309
310    /// Like g_subprocess_communicate(), but validates the output of the
311    /// process as UTF-8, and returns it as a regular NUL terminated string.
312    ///
313    /// On error, @stdout_buf and @stderr_buf will be set to undefined values and
314    /// should not be used.
315    /// ## `stdin_buf`
316    /// data to send to the stdin of the subprocess, or [`None`]
317    /// ## `cancellable`
318    /// a #GCancellable
319    ///
320    /// # Returns
321    ///
322    ///
323    /// ## `stdout_buf`
324    /// data read from the subprocess stdout
325    ///
326    /// ## `stderr_buf`
327    /// data read from the subprocess stderr
328    #[doc(alias = "g_subprocess_communicate_utf8")]
329    pub fn communicate_utf8(
330        &self,
331        stdin_buf: Option<&str>,
332        cancellable: Option<&impl IsA<Cancellable>>,
333    ) -> Result<(Option<glib::GString>, Option<glib::GString>), glib::Error> {
334        unsafe {
335            let mut stdout_buf = std::ptr::null_mut();
336            let mut stderr_buf = std::ptr::null_mut();
337            let mut error = std::ptr::null_mut();
338            let is_ok = ffi::g_subprocess_communicate_utf8(
339                self.to_glib_none().0,
340                stdin_buf.to_glib_none().0,
341                cancellable.map(|p| p.as_ref()).to_glib_none().0,
342                &mut stdout_buf,
343                &mut stderr_buf,
344                &mut error,
345            );
346            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
347            if error.is_null() {
348                Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
349            } else {
350                Err(from_glib_full(error))
351            }
352        }
353    }
354
355    /// Use an operating-system specific method to attempt an immediate,
356    /// forceful termination of the process.  There is no mechanism to
357    /// determine whether or not the request itself was successful;
358    /// however, you can use g_subprocess_wait() to monitor the status of
359    /// the process after calling this function.
360    ///
361    /// On Unix, this function sends `SIGKILL`.
362    #[doc(alias = "g_subprocess_force_exit")]
363    pub fn force_exit(&self) {
364        unsafe {
365            ffi::g_subprocess_force_exit(self.to_glib_none().0);
366        }
367    }
368
369    /// Check the exit status of the subprocess, given that it exited
370    /// normally.  This is the value passed to the exit() system call or the
371    /// return value from main.
372    ///
373    /// This is equivalent to the system WEXITSTATUS macro.
374    ///
375    /// It is an error to call this function before g_subprocess_wait() and
376    /// unless g_subprocess_get_if_exited() returned [`true`].
377    ///
378    /// # Returns
379    ///
380    /// the exit status
381    #[doc(alias = "g_subprocess_get_exit_status")]
382    #[doc(alias = "get_exit_status")]
383    pub fn exit_status(&self) -> i32 {
384        unsafe { ffi::g_subprocess_get_exit_status(self.to_glib_none().0) }
385    }
386
387    /// On UNIX, returns the process ID as a decimal string.
388    /// On Windows, returns the result of GetProcessId() also as a string.
389    /// If the subprocess has terminated, this will return [`None`].
390    ///
391    /// # Returns
392    ///
393    /// the subprocess identifier, or [`None`] if the subprocess
394    ///    has terminated
395    #[doc(alias = "g_subprocess_get_identifier")]
396    #[doc(alias = "get_identifier")]
397    pub fn identifier(&self) -> Option<glib::GString> {
398        unsafe { from_glib_none(ffi::g_subprocess_get_identifier(self.to_glib_none().0)) }
399    }
400
401    /// Check if the given subprocess exited normally (ie: by way of exit()
402    /// or return from main()).
403    ///
404    /// This is equivalent to the system WIFEXITED macro.
405    ///
406    /// It is an error to call this function before g_subprocess_wait() has
407    /// returned.
408    ///
409    /// # Returns
410    ///
411    /// [`true`] if the case of a normal exit
412    #[doc(alias = "g_subprocess_get_if_exited")]
413    #[doc(alias = "get_if_exited")]
414    pub fn has_exited(&self) -> bool {
415        unsafe { from_glib(ffi::g_subprocess_get_if_exited(self.to_glib_none().0)) }
416    }
417
418    /// Check if the given subprocess terminated in response to a signal.
419    ///
420    /// This is equivalent to the system WIFSIGNALED macro.
421    ///
422    /// It is an error to call this function before g_subprocess_wait() has
423    /// returned.
424    ///
425    /// # Returns
426    ///
427    /// [`true`] if the case of termination due to a signal
428    #[doc(alias = "g_subprocess_get_if_signaled")]
429    #[doc(alias = "get_if_signaled")]
430    pub fn has_signaled(&self) -> bool {
431        unsafe { from_glib(ffi::g_subprocess_get_if_signaled(self.to_glib_none().0)) }
432    }
433
434    /// Gets the raw status code of the process, as from waitpid().
435    ///
436    /// This value has no particular meaning, but it can be used with the
437    /// macros defined by the system headers such as WIFEXITED.  It can also
438    /// be used with g_spawn_check_wait_status().
439    ///
440    /// It is more likely that you want to use g_subprocess_get_if_exited()
441    /// followed by g_subprocess_get_exit_status().
442    ///
443    /// It is an error to call this function before g_subprocess_wait() has
444    /// returned.
445    ///
446    /// # Returns
447    ///
448    /// the (meaningless) waitpid() exit status from the kernel
449    #[doc(alias = "g_subprocess_get_status")]
450    #[doc(alias = "get_status")]
451    pub fn status(&self) -> i32 {
452        unsafe { ffi::g_subprocess_get_status(self.to_glib_none().0) }
453    }
454
455    /// Gets the #GInputStream from which to read the stderr output of
456    /// @self.
457    ///
458    /// The process must have been created with [`SubprocessFlags::STDERR_PIPE`][crate::SubprocessFlags::STDERR_PIPE],
459    /// otherwise [`None`] will be returned.
460    ///
461    /// # Returns
462    ///
463    /// the stderr pipe
464    #[doc(alias = "g_subprocess_get_stderr_pipe")]
465    #[doc(alias = "get_stderr_pipe")]
466    pub fn stderr_pipe(&self) -> Option<InputStream> {
467        unsafe { from_glib_none(ffi::g_subprocess_get_stderr_pipe(self.to_glib_none().0)) }
468    }
469
470    /// Gets the #GOutputStream that you can write to in order to give data
471    /// to the stdin of @self.
472    ///
473    /// The process must have been created with [`SubprocessFlags::STDIN_PIPE`][crate::SubprocessFlags::STDIN_PIPE] and
474    /// not [`SubprocessFlags::STDIN_INHERIT`][crate::SubprocessFlags::STDIN_INHERIT], otherwise [`None`] will be returned.
475    ///
476    /// # Returns
477    ///
478    /// the stdout pipe
479    #[doc(alias = "g_subprocess_get_stdin_pipe")]
480    #[doc(alias = "get_stdin_pipe")]
481    pub fn stdin_pipe(&self) -> Option<OutputStream> {
482        unsafe { from_glib_none(ffi::g_subprocess_get_stdin_pipe(self.to_glib_none().0)) }
483    }
484
485    /// Gets the #GInputStream from which to read the stdout output of
486    /// @self.
487    ///
488    /// The process must have been created with [`SubprocessFlags::STDOUT_PIPE`][crate::SubprocessFlags::STDOUT_PIPE],
489    /// otherwise [`None`] will be returned.
490    ///
491    /// # Returns
492    ///
493    /// the stdout pipe
494    #[doc(alias = "g_subprocess_get_stdout_pipe")]
495    #[doc(alias = "get_stdout_pipe")]
496    pub fn stdout_pipe(&self) -> Option<InputStream> {
497        unsafe { from_glib_none(ffi::g_subprocess_get_stdout_pipe(self.to_glib_none().0)) }
498    }
499
500    /// Checks if the process was "successful".  A process is considered
501    /// successful if it exited cleanly with an exit status of 0, either by
502    /// way of the exit() system call or return from main().
503    ///
504    /// It is an error to call this function before g_subprocess_wait() has
505    /// returned.
506    ///
507    /// # Returns
508    ///
509    /// [`true`] if the process exited cleanly with a exit status of 0
510    #[doc(alias = "g_subprocess_get_successful")]
511    #[doc(alias = "get_successful")]
512    pub fn is_successful(&self) -> bool {
513        unsafe { from_glib(ffi::g_subprocess_get_successful(self.to_glib_none().0)) }
514    }
515
516    /// Get the signal number that caused the subprocess to terminate, given
517    /// that it terminated due to a signal.
518    ///
519    /// This is equivalent to the system WTERMSIG macro.
520    ///
521    /// It is an error to call this function before g_subprocess_wait() and
522    /// unless g_subprocess_get_if_signaled() returned [`true`].
523    ///
524    /// # Returns
525    ///
526    /// the signal causing termination
527    #[doc(alias = "g_subprocess_get_term_sig")]
528    #[doc(alias = "get_term_sig")]
529    pub fn term_sig(&self) -> i32 {
530        unsafe { ffi::g_subprocess_get_term_sig(self.to_glib_none().0) }
531    }
532
533    /// Sends the UNIX signal @signal_num to the subprocess, if it is still
534    /// running.
535    ///
536    /// This API is race-free.  If the subprocess has terminated, it will not
537    /// be signalled.
538    ///
539    /// This API is not available on Windows.
540    /// ## `signal_num`
541    /// the signal number to send
542    #[cfg(not(windows))]
543    #[cfg_attr(docsrs, doc(cfg(not(windows))))]
544    #[doc(alias = "g_subprocess_send_signal")]
545    pub fn send_signal(&self, signal_num: i32) {
546        unsafe {
547            ffi::g_subprocess_send_signal(self.to_glib_none().0, signal_num);
548        }
549    }
550
551    /// Synchronously wait for the subprocess to terminate.
552    ///
553    /// After the process terminates you can query its exit status with
554    /// functions such as g_subprocess_get_if_exited() and
555    /// g_subprocess_get_exit_status().
556    ///
557    /// This function does not fail in the case of the subprocess having
558    /// abnormal termination.  See g_subprocess_wait_check() for that.
559    ///
560    /// Cancelling @cancellable doesn't kill the subprocess.  Call
561    /// g_subprocess_force_exit() if it is desirable.
562    /// ## `cancellable`
563    /// a #GCancellable
564    ///
565    /// # Returns
566    ///
567    /// [`true`] on success, [`false`] if @cancellable was cancelled
568    #[doc(alias = "g_subprocess_wait")]
569    pub fn wait(&self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<(), glib::Error> {
570        unsafe {
571            let mut error = std::ptr::null_mut();
572            let is_ok = ffi::g_subprocess_wait(
573                self.to_glib_none().0,
574                cancellable.map(|p| p.as_ref()).to_glib_none().0,
575                &mut error,
576            );
577            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
578            if error.is_null() {
579                Ok(())
580            } else {
581                Err(from_glib_full(error))
582            }
583        }
584    }
585
586    /// Wait for the subprocess to terminate.
587    ///
588    /// This is the asynchronous version of g_subprocess_wait().
589    /// ## `cancellable`
590    /// a #GCancellable, or [`None`]
591    /// ## `callback`
592    /// a #GAsyncReadyCallback to call when the operation is complete
593    #[doc(alias = "g_subprocess_wait_async")]
594    pub fn wait_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
595        &self,
596        cancellable: Option<&impl IsA<Cancellable>>,
597        callback: P,
598    ) {
599        let main_context = glib::MainContext::ref_thread_default();
600        let is_main_context_owner = main_context.is_owner();
601        let has_acquired_main_context = (!is_main_context_owner)
602            .then(|| main_context.acquire().ok())
603            .flatten();
604        assert!(
605            is_main_context_owner || has_acquired_main_context.is_some(),
606            "Async operations only allowed if the thread is owning the MainContext"
607        );
608
609        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
610            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
611        unsafe extern "C" fn wait_async_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
612            _source_object: *mut glib::gobject_ffi::GObject,
613            res: *mut crate::ffi::GAsyncResult,
614            user_data: glib::ffi::gpointer,
615        ) {
616            unsafe {
617                let mut error = std::ptr::null_mut();
618                ffi::g_subprocess_wait_finish(_source_object as *mut _, res, &mut error);
619                let result = if error.is_null() {
620                    Ok(())
621                } else {
622                    Err(from_glib_full(error))
623                };
624                let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
625                    Box_::from_raw(user_data as *mut _);
626                let callback: P = callback.into_inner();
627                callback(result);
628            }
629        }
630        let callback = wait_async_trampoline::<P>;
631        unsafe {
632            ffi::g_subprocess_wait_async(
633                self.to_glib_none().0,
634                cancellable.map(|p| p.as_ref()).to_glib_none().0,
635                Some(callback),
636                Box_::into_raw(user_data) as *mut _,
637            );
638        }
639    }
640
641    pub fn wait_future(
642        &self,
643    ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
644        Box_::pin(crate::GioFuture::new(
645            self,
646            move |obj, cancellable, send| {
647                obj.wait_async(Some(cancellable), move |res| {
648                    send.resolve(res);
649                });
650            },
651        ))
652    }
653
654    /// Combines g_subprocess_wait() with g_spawn_check_wait_status().
655    /// ## `cancellable`
656    /// a #GCancellable
657    ///
658    /// # Returns
659    ///
660    /// [`true`] on success, [`false`] if process exited abnormally, or
661    /// @cancellable was cancelled
662    #[doc(alias = "g_subprocess_wait_check")]
663    pub fn wait_check(
664        &self,
665        cancellable: Option<&impl IsA<Cancellable>>,
666    ) -> Result<(), glib::Error> {
667        unsafe {
668            let mut error = std::ptr::null_mut();
669            let is_ok = ffi::g_subprocess_wait_check(
670                self.to_glib_none().0,
671                cancellable.map(|p| p.as_ref()).to_glib_none().0,
672                &mut error,
673            );
674            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
675            if error.is_null() {
676                Ok(())
677            } else {
678                Err(from_glib_full(error))
679            }
680        }
681    }
682
683    /// Combines g_subprocess_wait_async() with g_spawn_check_wait_status().
684    ///
685    /// This is the asynchronous version of g_subprocess_wait_check().
686    /// ## `cancellable`
687    /// a #GCancellable, or [`None`]
688    /// ## `callback`
689    /// a #GAsyncReadyCallback to call when the operation is complete
690    #[doc(alias = "g_subprocess_wait_check_async")]
691    pub fn wait_check_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
692        &self,
693        cancellable: Option<&impl IsA<Cancellable>>,
694        callback: P,
695    ) {
696        let main_context = glib::MainContext::ref_thread_default();
697        let is_main_context_owner = main_context.is_owner();
698        let has_acquired_main_context = (!is_main_context_owner)
699            .then(|| main_context.acquire().ok())
700            .flatten();
701        assert!(
702            is_main_context_owner || has_acquired_main_context.is_some(),
703            "Async operations only allowed if the thread is owning the MainContext"
704        );
705
706        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
707            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
708        unsafe extern "C" fn wait_check_async_trampoline<
709            P: FnOnce(Result<(), glib::Error>) + 'static,
710        >(
711            _source_object: *mut glib::gobject_ffi::GObject,
712            res: *mut crate::ffi::GAsyncResult,
713            user_data: glib::ffi::gpointer,
714        ) {
715            unsafe {
716                let mut error = std::ptr::null_mut();
717                ffi::g_subprocess_wait_check_finish(_source_object as *mut _, res, &mut error);
718                let result = if error.is_null() {
719                    Ok(())
720                } else {
721                    Err(from_glib_full(error))
722                };
723                let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
724                    Box_::from_raw(user_data as *mut _);
725                let callback: P = callback.into_inner();
726                callback(result);
727            }
728        }
729        let callback = wait_check_async_trampoline::<P>;
730        unsafe {
731            ffi::g_subprocess_wait_check_async(
732                self.to_glib_none().0,
733                cancellable.map(|p| p.as_ref()).to_glib_none().0,
734                Some(callback),
735                Box_::into_raw(user_data) as *mut _,
736            );
737        }
738    }
739
740    pub fn wait_check_future(
741        &self,
742    ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
743        Box_::pin(crate::GioFuture::new(
744            self,
745            move |obj, cancellable, send| {
746                obj.wait_check_async(Some(cancellable), move |res| {
747                    send.resolve(res);
748                });
749            },
750        ))
751    }
752}