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}