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}