glib/functions.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3pub use crate::auto::functions::*;
4#[cfg(not(windows))]
5use std::boxed::Box as Box_;
6#[cfg(not(windows))]
7use std::mem;
8#[cfg(not(windows))]
9#[cfg(feature = "v2_58")]
10use std::os::unix::io::AsRawFd;
11#[cfg(not(windows))]
12use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
13use std::ptr;
14
15// #[cfg(windows)]
16// #[cfg(feature = "v2_58")]
17// use std::os::windows::io::AsRawHandle;
18use crate::{ffi, translate::*, ChecksumType, GStr};
19#[cfg(not(windows))]
20use crate::{Error, Pid, SpawnFlags};
21
22#[cfg(feature = "v2_58")]
23#[cfg(not(windows))]
24#[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", not(windows)))))]
25#[allow(clippy::too_many_arguments)]
26#[doc(alias = "g_spawn_async_with_fds")]
27pub fn spawn_async_with_fds<P: AsRef<std::path::Path>, T: AsRawFd, U: AsRawFd, V: AsRawFd>(
28 working_directory: P,
29 argv: &[&str],
30 envp: &[&str],
31 flags: SpawnFlags,
32 child_setup: Option<Box_<dyn FnOnce() + 'static>>,
33 stdin_fd: T,
34 stdout_fd: U,
35 stderr_fd: V,
36) -> Result<Pid, Error> {
37 let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
38 unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
39 let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
40 Box_::from_raw(user_data as *mut _);
41 let callback = (*callback).expect("cannot get closure...");
42 callback()
43 }
44 let child_setup = if child_setup_data.is_some() {
45 Some(child_setup_func as _)
46 } else {
47 None
48 };
49 let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
50 unsafe {
51 let mut child_pid = mem::MaybeUninit::uninit();
52 let mut error = ptr::null_mut();
53 let _ = ffi::g_spawn_async_with_fds(
54 working_directory.as_ref().to_glib_none().0,
55 argv.to_glib_none().0,
56 envp.to_glib_none().0,
57 flags.into_glib(),
58 child_setup,
59 Box_::into_raw(super_callback0) as *mut _,
60 child_pid.as_mut_ptr(),
61 stdin_fd.as_raw_fd(),
62 stdout_fd.as_raw_fd(),
63 stderr_fd.as_raw_fd(),
64 &mut error,
65 );
66 let child_pid = from_glib(child_pid.assume_init());
67 if error.is_null() {
68 Ok(child_pid)
69 } else {
70 Err(from_glib_full(error))
71 }
72 }
73}
74
75// #[cfg(feature = "v2_58")]
76// #[cfg(windows)]
77// pub fn spawn_async_with_fds<
78// P: AsRef<std::path::Path>,
79// T: AsRawHandle,
80// U: AsRawHandle,
81// V: AsRawHandle,
82// >(
83// working_directory: P,
84// argv: &[&str],
85// envp: &[&str],
86// flags: SpawnFlags,
87// child_setup: Option<Box_<dyn FnOnce() + 'static>>,
88// stdin_fd: T,
89// stdout_fd: U,
90// stderr_fd: V,
91// ) -> Result<Pid, Error> {
92// let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
93// unsafe extern "C" fn child_setup_func<P: AsRef<std::path::Path>>(
94// user_data: ffi::gpointer,
95// ) {
96// let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
97// Box_::from_raw(user_data as *mut _);
98// let callback = (*callback).expect("cannot get closure...");
99// callback()
100// }
101// let child_setup = if child_setup_data.is_some() {
102// Some(child_setup_func::<P> as _)
103// } else {
104// None
105// };
106// let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
107// unsafe {
108// let mut child_pid = mem::MaybeUninit::uninit();
109// let mut error = ptr::null_mut();
110// let _ = ffi::g_spawn_async_with_fds(
111// working_directory.as_ref().to_glib_none().0,
112// argv.to_glib_none().0,
113// envp.to_glib_none().0,
114// flags.into_glib(),
115// child_setup,
116// Box_::into_raw(super_callback0) as *mut _,
117// child_pid.as_mut_ptr(),
118// stdin_fd.as_raw_handle() as usize as _,
119// stdout_fd.as_raw_handle() as usize as _,
120// stderr_fd.as_raw_handle() as usize as _,
121// &mut error,
122// );
123// let child_pid = from_glib(child_pid.assume_init());
124// if error.is_null() {
125// Ok(child_pid)
126// } else {
127// Err(from_glib_full(error))
128// }
129// }
130// }
131
132#[cfg(not(windows))]
133#[cfg_attr(docsrs, doc(cfg(not(windows))))]
134#[doc(alias = "g_spawn_async_with_pipes")]
135pub fn spawn_async_with_pipes<
136 P: AsRef<std::path::Path>,
137 T: FromRawFd,
138 U: FromRawFd,
139 V: FromRawFd,
140>(
141 working_directory: P,
142 argv: &[&std::path::Path],
143 envp: &[&std::path::Path],
144 flags: SpawnFlags,
145 child_setup: Option<Box_<dyn FnOnce() + 'static>>,
146) -> Result<(Pid, T, U, V), Error> {
147 let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
148 unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
149 let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
150 Box_::from_raw(user_data as *mut _);
151 let callback = (*callback).expect("cannot get closure...");
152 callback()
153 }
154 let child_setup = if child_setup_data.is_some() {
155 Some(child_setup_func as _)
156 } else {
157 None
158 };
159 let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
160 unsafe {
161 let mut child_pid = mem::MaybeUninit::uninit();
162 let mut standard_input = mem::MaybeUninit::uninit();
163 let mut standard_output = mem::MaybeUninit::uninit();
164 let mut standard_error = mem::MaybeUninit::uninit();
165 let mut error = ptr::null_mut();
166 let _ = ffi::g_spawn_async_with_pipes(
167 working_directory.as_ref().to_glib_none().0,
168 argv.to_glib_none().0,
169 envp.to_glib_none().0,
170 flags.into_glib(),
171 child_setup,
172 Box_::into_raw(super_callback0) as *mut _,
173 child_pid.as_mut_ptr(),
174 standard_input.as_mut_ptr(),
175 standard_output.as_mut_ptr(),
176 standard_error.as_mut_ptr(),
177 &mut error,
178 );
179 let child_pid = from_glib(child_pid.assume_init());
180 let standard_input = standard_input.assume_init();
181 let standard_output = standard_output.assume_init();
182 let standard_error = standard_error.assume_init();
183 if error.is_null() {
184 #[cfg(not(windows))]
185 {
186 Ok((
187 child_pid,
188 FromRawFd::from_raw_fd(standard_input),
189 FromRawFd::from_raw_fd(standard_output),
190 FromRawFd::from_raw_fd(standard_error),
191 ))
192 }
193 // #[cfg(windows)]
194 // {
195 // use std::os::windows::io::{FromRawHandle, RawHandle};
196 // Ok((
197 // child_pid,
198 // File::from_raw_handle(standard_input as usize as RawHandle),
199 // File::from_raw_handle(standard_output as usize as RawHandle),
200 // File::from_raw_handle(standard_error as usize as RawHandle),
201 // ))
202 // }
203 } else {
204 Err(from_glib_full(error))
205 }
206 }
207}
208
209// rustdoc-stripper-ignore-next
210/// Obtain the character set for the current locale.
211///
212/// This returns whether the locale's encoding is UTF-8, and the current
213/// charset if available.
214#[doc(alias = "g_get_charset")]
215#[doc(alias = "get_charset")]
216pub fn charset() -> (bool, Option<&'static GStr>) {
217 unsafe {
218 let mut out_charset = ptr::null();
219 let is_utf8 = from_glib(ffi::g_get_charset(&mut out_charset));
220 let charset = from_glib_none(out_charset);
221 (is_utf8, charset)
222 }
223}
224
225#[doc(alias = "g_compute_checksum_for_string")]
226pub fn compute_checksum_for_string(
227 checksum_type: ChecksumType,
228 str: impl IntoGStr,
229) -> Option<crate::GString> {
230 str.run_with_gstr(|str| unsafe {
231 from_glib_full(ffi::g_compute_checksum_for_string(
232 checksum_type.into_glib(),
233 str.as_ptr(),
234 str.len() as _,
235 ))
236 })
237}
238
239/// Similar to the UNIX pipe() call, but on modern systems like Linux
240/// uses the pipe2() system call, which atomically creates a pipe with
241/// the configured flags.
242///
243/// As of GLib 2.78, the supported flags are `O_CLOEXEC`/`FD_CLOEXEC` (see below)
244/// and `O_NONBLOCK`. Prior to GLib 2.78, only `FD_CLOEXEC` was supported — if
245/// you wanted to configure `O_NONBLOCK` then that had to be done separately with
246/// `fcntl()`.
247///
248/// Since GLib 2.80, the constants `G_UNIX_PIPE_END_READ` and
249/// `G_UNIX_PIPE_END_WRITE` can be used as mnemonic indexes in @fds.
250///
251/// It is a programmer error to call this function with unsupported flags, and a
252/// critical warning will be raised.
253///
254/// As of GLib 2.78, it is preferred to pass `O_CLOEXEC` in, rather than
255/// `FD_CLOEXEC`, as that matches the underlying `pipe()` API more closely. Prior
256/// to 2.78, only `FD_CLOEXEC` was supported. Support for `FD_CLOEXEC` may be
257/// deprecated and removed in future.
258/// ## `fds`
259/// Array of two integers
260/// ## `flags`
261/// Bitfield of file descriptor flags, as for fcntl()
262///
263/// # Returns
264///
265/// [`true`] on success, [`false`] if not (and errno will be set).
266#[cfg(unix)]
267#[doc(alias = "g_unix_open_pipe")]
268pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> {
269 unsafe {
270 let mut fds = [0, 2];
271 let mut error = ptr::null_mut();
272 let _ = ffi::g_unix_open_pipe(&mut fds, flags, &mut error);
273 if error.is_null() {
274 Ok((
275 FromRawFd::from_raw_fd(fds[0]),
276 FromRawFd::from_raw_fd(fds[1]),
277 ))
278 } else {
279 Err(from_glib_full(error))
280 }
281 }
282}
283
284/// Opens a file for writing in the preferred directory for temporary
285/// files (as returned by g_get_tmp_dir()).
286///
287/// @tmpl should be a string in the GLib file name encoding containing
288/// a sequence of six 'X' characters, as the parameter to g_mkstemp().
289/// However, unlike these functions, the template should only be a
290/// basename, no directory components are allowed. If template is
291/// [`None`], a default template is used.
292///
293/// Note that in contrast to g_mkstemp() (and mkstemp()) @tmpl is not
294/// modified, and might thus be a read-only literal string.
295///
296/// Upon success, and if @name_used is non-[`None`], the actual name used
297/// is returned in @name_used. This string should be freed with g_free()
298/// when not needed any longer. The returned name is in the GLib file
299/// name encoding.
300/// ## `tmpl`
301/// Template for file name, as in
302/// g_mkstemp(), basename only, or [`None`] for a default template
303///
304/// # Returns
305///
306/// A file handle (as from open()) to the file opened for
307/// reading and writing. The file is opened in binary mode on platforms
308/// where there is a difference. The file handle should be closed with
309/// close(). In case of errors, -1 is returned and @error will be set.
310///
311/// ## `name_used`
312/// location to store actual name used,
313/// or [`None`]
314#[cfg(unix)]
315#[doc(alias = "g_file_open_tmp")]
316pub fn file_open_tmp(
317 tmpl: Option<impl AsRef<std::path::Path>>,
318) -> Result<(RawFd, std::path::PathBuf), crate::Error> {
319 unsafe {
320 let mut name_used = ptr::null_mut();
321 let mut error = ptr::null_mut();
322 let ret = ffi::g_file_open_tmp(
323 tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
324 &mut name_used,
325 &mut error,
326 );
327 if error.is_null() {
328 Ok((ret.into_raw_fd(), from_glib_full(name_used)))
329 } else {
330 Err(from_glib_full(error))
331 }
332 }
333}
334
335// rustdoc-stripper-ignore-next
336/// Spawn a new infallible `Future` on the thread-default main context.
337///
338/// This can be called from any thread and will execute the future from the thread
339/// where main context is running, e.g. via a `MainLoop`.
340pub fn spawn_future<R: Send + 'static, F: std::future::Future<Output = R> + Send + 'static>(
341 f: F,
342) -> crate::JoinHandle<R> {
343 let ctx = crate::MainContext::ref_thread_default();
344 ctx.spawn(f)
345}
346
347// rustdoc-stripper-ignore-next
348/// Spawn a new infallible `Future` on the thread-default main context.
349///
350/// The given `Future` does not have to be `Send`.
351///
352/// This can be called only from the thread where the main context is running, e.g.
353/// from any other `Future` that is executed on this main context, or after calling
354/// `with_thread_default` or `acquire` on the main context.
355pub fn spawn_future_local<R: 'static, F: std::future::Future<Output = R> + 'static>(
356 f: F,
357) -> crate::JoinHandle<R> {
358 let ctx = crate::MainContext::ref_thread_default();
359 ctx.spawn_local(f)
360}