1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | #[cfg (not(windows))] |
4 | use std::boxed::Box as Box_; |
5 | #[cfg (not(windows))] |
6 | use std::mem; |
7 | #[cfg (not(windows))] |
8 | #[cfg (feature = "v2_58" )] |
9 | use std::os::unix::io::AsRawFd; |
10 | #[cfg (not(windows))] |
11 | use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; |
12 | use std::ptr; |
13 | |
14 | // #[cfg(windows)] |
15 | // #[cfg(feature = "v2_58")] |
16 | // use std::os::windows::io::AsRawHandle; |
17 | use crate::{translate::*, GStr}; |
18 | #[cfg (not(windows))] |
19 | use 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" )] |
26 | pub 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" )] |
134 | pub 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" )] |
215 | pub 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" )] |
226 | pub 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" )] |
244 | pub 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`. |
268 | pub 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. |
283 | pub 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 | |