1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(not(windows))]
4use std::boxed::Box as Box_;
5#[cfg(not(windows))]
6use std::mem;
7#[cfg(not(windows))]
8#[cfg(feature = "v2_58")]
9use std::os::unix::io::AsRawFd;
10#[cfg(not(windows))]
11use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
12use std::ptr;
13
14// #[cfg(windows)]
15// #[cfg(feature = "v2_58")]
16// use std::os::windows::io::AsRawHandle;
17use crate::{translate::*, GStr};
18#[cfg(not(windows))]
19use crate::{Error, Pid, SpawnFlags};
20
21#[cfg(feature = "v2_58")]
22#[cfg(not(windows))]
23#[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", not(windows)))))]
24#[allow(clippy::too_many_arguments)]
25#[doc(alias = "g_spawn_async_with_fds")]
26pub fn spawn_async_with_fds<P: AsRef<std::path::Path>, T: AsRawFd, U: AsRawFd, V: AsRawFd>(
27 working_directory: P,
28 argv: &[&str],
29 envp: &[&str],
30 flags: SpawnFlags,
31 child_setup: Option<Box_<dyn FnOnce() + 'static>>,
32 stdin_fd: T,
33 stdout_fd: U,
34 stderr_fd: V,
35) -> Result<Pid, Error> {
36 let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
37 unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
38 let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
39 Box_::from_raw(user_data as *mut _);
40 let callback = (*callback).expect("cannot get closure...");
41 callback()
42 }
43 let child_setup = if child_setup_data.is_some() {
44 Some(child_setup_func as _)
45 } else {
46 None
47 };
48 let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
49 unsafe {
50 let mut child_pid = mem::MaybeUninit::uninit();
51 let mut error = ptr::null_mut();
52 let _ = ffi::g_spawn_async_with_fds(
53 working_directory.as_ref().to_glib_none().0,
54 argv.to_glib_none().0,
55 envp.to_glib_none().0,
56 flags.into_glib(),
57 child_setup,
58 Box_::into_raw(super_callback0) as *mut _,
59 child_pid.as_mut_ptr(),
60 stdin_fd.as_raw_fd(),
61 stdout_fd.as_raw_fd(),
62 stderr_fd.as_raw_fd(),
63 &mut error,
64 );
65 let child_pid = from_glib(child_pid.assume_init());
66 if error.is_null() {
67 Ok(child_pid)
68 } else {
69 Err(from_glib_full(error))
70 }
71 }
72}
73
74// #[cfg(feature = "v2_58")]
75// #[cfg(windows)]
76// pub fn spawn_async_with_fds<
77// P: AsRef<std::path::Path>,
78// T: AsRawHandle,
79// U: AsRawHandle,
80// V: AsRawHandle,
81// >(
82// working_directory: P,
83// argv: &[&str],
84// envp: &[&str],
85// flags: SpawnFlags,
86// child_setup: Option<Box_<dyn FnOnce() + 'static>>,
87// stdin_fd: T,
88// stdout_fd: U,
89// stderr_fd: V,
90// ) -> Result<Pid, Error> {
91// let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
92// unsafe extern "C" fn child_setup_func<P: AsRef<std::path::Path>>(
93// user_data: ffi::gpointer,
94// ) {
95// let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
96// Box_::from_raw(user_data as *mut _);
97// let callback = (*callback).expect("cannot get closure...");
98// callback()
99// }
100// let child_setup = if child_setup_data.is_some() {
101// Some(child_setup_func::<P> as _)
102// } else {
103// None
104// };
105// let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
106// unsafe {
107// let mut child_pid = mem::MaybeUninit::uninit();
108// let mut error = ptr::null_mut();
109// let _ = ffi::g_spawn_async_with_fds(
110// working_directory.as_ref().to_glib_none().0,
111// argv.to_glib_none().0,
112// envp.to_glib_none().0,
113// flags.into_glib(),
114// child_setup,
115// Box_::into_raw(super_callback0) as *mut _,
116// child_pid.as_mut_ptr(),
117// stdin_fd.as_raw_handle() as usize as _,
118// stdout_fd.as_raw_handle() as usize as _,
119// stderr_fd.as_raw_handle() as usize as _,
120// &mut error,
121// );
122// let child_pid = from_glib(child_pid.assume_init());
123// if error.is_null() {
124// Ok(child_pid)
125// } else {
126// Err(from_glib_full(error))
127// }
128// }
129// }
130
131#[cfg(not(windows))]
132#[cfg_attr(docsrs, doc(cfg(not(windows))))]
133#[doc(alias = "g_spawn_async_with_pipes")]
134pub fn spawn_async_with_pipes<
135 P: AsRef<std::path::Path>,
136 T: FromRawFd,
137 U: FromRawFd,
138 V: FromRawFd,
139>(
140 working_directory: P,
141 argv: &[&std::path::Path],
142 envp: &[&std::path::Path],
143 flags: SpawnFlags,
144 child_setup: Option<Box_<dyn FnOnce() + 'static>>,
145) -> Result<(Pid, T, U, V), Error> {
146 let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
147 unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
148 let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
149 Box_::from_raw(user_data as *mut _);
150 let callback = (*callback).expect("cannot get closure...");
151 callback()
152 }
153 let child_setup = if child_setup_data.is_some() {
154 Some(child_setup_func as _)
155 } else {
156 None
157 };
158 let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
159 unsafe {
160 let mut child_pid = mem::MaybeUninit::uninit();
161 let mut standard_input = mem::MaybeUninit::uninit();
162 let mut standard_output = mem::MaybeUninit::uninit();
163 let mut standard_error = mem::MaybeUninit::uninit();
164 let mut error = ptr::null_mut();
165 let _ = ffi::g_spawn_async_with_pipes(
166 working_directory.as_ref().to_glib_none().0,
167 argv.to_glib_none().0,
168 envp.to_glib_none().0,
169 flags.into_glib(),
170 child_setup,
171 Box_::into_raw(super_callback0) as *mut _,
172 child_pid.as_mut_ptr(),
173 standard_input.as_mut_ptr(),
174 standard_output.as_mut_ptr(),
175 standard_error.as_mut_ptr(),
176 &mut error,
177 );
178 let child_pid = from_glib(child_pid.assume_init());
179 let standard_input = standard_input.assume_init();
180 let standard_output = standard_output.assume_init();
181 let standard_error = standard_error.assume_init();
182 if error.is_null() {
183 #[cfg(not(windows))]
184 {
185 Ok((
186 child_pid,
187 FromRawFd::from_raw_fd(standard_input),
188 FromRawFd::from_raw_fd(standard_output),
189 FromRawFd::from_raw_fd(standard_error),
190 ))
191 }
192 // #[cfg(windows)]
193 // {
194 // use std::os::windows::io::{FromRawHandle, RawHandle};
195 // Ok((
196 // child_pid,
197 // File::from_raw_handle(standard_input as usize as RawHandle),
198 // File::from_raw_handle(standard_output as usize as RawHandle),
199 // File::from_raw_handle(standard_error as usize as RawHandle),
200 // ))
201 // }
202 } else {
203 Err(from_glib_full(error))
204 }
205 }
206}
207
208// rustdoc-stripper-ignore-next
209/// Obtain the character set for the current locale.
210///
211/// This returns whether the locale's encoding is UTF-8, and the current
212/// charset if available.
213#[doc(alias = "g_get_charset")]
214#[doc(alias = "get_charset")]
215pub fn charset() -> (bool, Option<&'static GStr>) {
216 unsafe {
217 let mut out_charset: *const i8 = ptr::null();
218 let is_utf8: bool = from_glib(val:ffi::g_get_charset(&mut out_charset));
219 let charset: Option<&GStr> = from_glib_none(ptr:out_charset);
220 (is_utf8, charset)
221 }
222}
223
224#[cfg(unix)]
225#[doc(alias = "g_unix_open_pipe")]
226pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> {
227 unsafe {
228 let mut fds: [i32; 2] = [0, 2];
229 let mut error: *mut GError = ptr::null_mut();
230 let _ = ffi::g_unix_open_pipe(&mut fds, flags, &mut error);
231 if error.is_null() {
232 Ok((
233 FromRawFd::from_raw_fd(fds[0]),
234 FromRawFd::from_raw_fd(fds[1]),
235 ))
236 } else {
237 Err(from_glib_full(ptr:error))
238 }
239 }
240}
241
242#[cfg(unix)]
243#[doc(alias = "g_file_open_tmp")]
244pub fn file_open_tmp(
245 tmpl: Option<impl AsRef<std::path::Path>>,
246) -> Result<(RawFd, std::path::PathBuf), crate::Error> {
247 unsafe {
248 let mut name_used: *mut i8 = ptr::null_mut();
249 let mut error: *mut GError = ptr::null_mut();
250 let ret: i32 = ffi::g_file_open_tmp(
251 tmpl:tmpl.as_ref().map(|p: &impl AsRef| p.as_ref()).to_glib_none().0,
252 &mut name_used,
253 &mut error,
254 );
255 if error.is_null() {
256 Ok((ret.into_raw_fd(), from_glib_full(ptr:name_used)))
257 } else {
258 Err(from_glib_full(ptr:error))
259 }
260 }
261}
262
263// rustdoc-stripper-ignore-next
264/// Spawn a new infallible `Future` on the thread-default main context.
265///
266/// This can be called from any thread and will execute the future from the thread
267/// where main context is running, e.g. via a `MainLoop`.
268pub fn spawn_future<R: Send + 'static, F: std::future::Future<Output = R> + Send + 'static>(
269 f: F,
270) -> crate::JoinHandle<R> {
271 let ctx: MainContext = crate::MainContext::ref_thread_default();
272 ctx.spawn(f)
273}
274
275// rustdoc-stripper-ignore-next
276/// Spawn a new infallible `Future` on the thread-default main context.
277///
278/// The given `Future` does not have to be `Send`.
279///
280/// This can be called only from the thread where the main context is running, e.g.
281/// from any other `Future` that is executed on this main context, or after calling
282/// `with_thread_default` or `acquire` on the main context.
283pub fn spawn_future_local<R: 'static, F: std::future::Future<Output = R> + 'static>(
284 f: F,
285) -> crate::JoinHandle<R> {
286 let ctx: MainContext = crate::MainContext::ref_thread_default();
287 ctx.spawn_local(f)
288}
289