Skip to main content

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::{AsFd, AsRawFd};
11#[cfg(not(windows))]
12use std::os::unix::io::{FromRawFd, OwnedFd};
13use std::ptr;
14
15// #[cfg(windows)]
16// #[cfg(feature = "v2_58")]
17// use std::os::windows::io::AsRawHandle;
18use crate::{ChecksumType, GStr, ffi, translate::*};
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>>(
28    working_directory: P,
29    argv: &[&str],
30    envp: &[&str],
31    flags: SpawnFlags,
32    child_setup: Option<Box_<dyn FnOnce() + 'static>>,
33    stdin_fd: Option<impl AsFd>,
34    stdout_fd: Option<impl AsFd>,
35    stderr_fd: Option<impl AsFd>,
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        unsafe {
40            let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
41                Box_::from_raw(user_data as *mut _);
42            let callback = (*callback).expect("cannot get closure...");
43            callback()
44        }
45    }
46    let child_setup = if child_setup_data.is_some() {
47        Some(child_setup_func as _)
48    } else {
49        None
50    };
51    let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
52    let stdin_raw_fd = stdin_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd());
53    let stdout_raw_fd = stdout_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd());
54    let stderr_raw_fd = stderr_fd.map_or(-1, |fd| fd.as_fd().as_raw_fd());
55    unsafe {
56        let mut child_pid = mem::MaybeUninit::uninit();
57        let mut error = ptr::null_mut();
58        let _ = ffi::g_spawn_async_with_fds(
59            working_directory.as_ref().to_glib_none().0,
60            argv.to_glib_none().0,
61            envp.to_glib_none().0,
62            flags.into_glib(),
63            child_setup,
64            Box_::into_raw(super_callback0) as *mut _,
65            child_pid.as_mut_ptr(),
66            stdin_raw_fd,
67            stdout_raw_fd,
68            stderr_raw_fd,
69            &mut error,
70        );
71        let child_pid = from_glib(child_pid.assume_init());
72        if error.is_null() {
73            Ok(child_pid)
74        } else {
75            Err(from_glib_full(error))
76        }
77    }
78}
79
80// #[cfg(feature = "v2_58")]
81// #[cfg(windows)]
82// pub fn spawn_async_with_fds<
83//     P: AsRef<std::path::Path>,
84//     T: AsRawHandle,
85//     U: AsRawHandle,
86//     V: AsRawHandle,
87// >(
88//     working_directory: P,
89//     argv: &[&str],
90//     envp: &[&str],
91//     flags: SpawnFlags,
92//     child_setup: Option<Box_<dyn FnOnce() + 'static>>,
93//     stdin_fd: T,
94//     stdout_fd: U,
95//     stderr_fd: V,
96// ) -> Result<Pid, Error> {
97//     let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
98//     unsafe extern "C" fn child_setup_func<P: AsRef<std::path::Path>>(
99//         user_data: ffi::gpointer,
100//     ) {
101//         let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
102//             Box_::from_raw(user_data as *mut _);
103//         let callback = (*callback).expect("cannot get closure...");
104//         callback()
105//     }
106//     let child_setup = if child_setup_data.is_some() {
107//         Some(child_setup_func::<P> as _)
108//     } else {
109//         None
110//     };
111//     let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
112//     unsafe {
113//         let mut child_pid = mem::MaybeUninit::uninit();
114//         let mut error = ptr::null_mut();
115//         let _ = ffi::g_spawn_async_with_fds(
116//             working_directory.as_ref().to_glib_none().0,
117//             argv.to_glib_none().0,
118//             envp.to_glib_none().0,
119//             flags.into_glib(),
120//             child_setup,
121//             Box_::into_raw(super_callback0) as *mut _,
122//             child_pid.as_mut_ptr(),
123//             stdin_fd.as_raw_handle() as usize as _,
124//             stdout_fd.as_raw_handle() as usize as _,
125//             stderr_fd.as_raw_handle() as usize as _,
126//             &mut error,
127//         );
128//         let child_pid = from_glib(child_pid.assume_init());
129//         if error.is_null() {
130//             Ok(child_pid)
131//         } else {
132//             Err(from_glib_full(error))
133//         }
134//     }
135// }
136
137#[cfg(not(windows))]
138#[cfg_attr(docsrs, doc(cfg(not(windows))))]
139#[doc(alias = "g_spawn_async_with_pipes")]
140pub fn spawn_async_with_pipes<
141    P: AsRef<std::path::Path>,
142    T: FromRawFd,
143    U: FromRawFd,
144    V: FromRawFd,
145>(
146    working_directory: P,
147    argv: &[&std::path::Path],
148    envp: &[&std::path::Path],
149    flags: SpawnFlags,
150    child_setup: Option<Box_<dyn FnOnce() + 'static>>,
151) -> Result<(Pid, T, U, V), Error> {
152    let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
153    unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
154        unsafe {
155            let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
156                Box_::from_raw(user_data as *mut _);
157            let callback = (*callback).expect("cannot get closure...");
158            callback()
159        }
160    }
161    let child_setup = if child_setup_data.is_some() {
162        Some(child_setup_func as _)
163    } else {
164        None
165    };
166    let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
167    unsafe {
168        let mut child_pid = mem::MaybeUninit::uninit();
169        let mut standard_input = mem::MaybeUninit::uninit();
170        let mut standard_output = mem::MaybeUninit::uninit();
171        let mut standard_error = mem::MaybeUninit::uninit();
172        let mut error = ptr::null_mut();
173        let _ = ffi::g_spawn_async_with_pipes(
174            working_directory.as_ref().to_glib_none().0,
175            argv.to_glib_none().0,
176            envp.to_glib_none().0,
177            flags.into_glib(),
178            child_setup,
179            Box_::into_raw(super_callback0) as *mut _,
180            child_pid.as_mut_ptr(),
181            standard_input.as_mut_ptr(),
182            standard_output.as_mut_ptr(),
183            standard_error.as_mut_ptr(),
184            &mut error,
185        );
186        if error.is_null() {
187            let child_pid = from_glib(child_pid.assume_init());
188            let standard_input = standard_input.assume_init();
189            let standard_output = standard_output.assume_init();
190            let standard_error = standard_error.assume_init();
191            #[cfg(not(windows))]
192            {
193                Ok((
194                    child_pid,
195                    FromRawFd::from_raw_fd(standard_input),
196                    FromRawFd::from_raw_fd(standard_output),
197                    FromRawFd::from_raw_fd(standard_error),
198                ))
199            }
200        // #[cfg(windows)]
201        // {
202        //     use std::os::windows::io::{FromRawHandle, RawHandle};
203        //     Ok((
204        //         child_pid,
205        //         File::from_raw_handle(standard_input as usize as RawHandle),
206        //         File::from_raw_handle(standard_output as usize as RawHandle),
207        //         File::from_raw_handle(standard_error as usize as RawHandle),
208        //     ))
209        // }
210        } else {
211            Err(from_glib_full(error))
212        }
213    }
214}
215
216// rustdoc-stripper-ignore-next
217/// Obtain the character set for the current locale.
218///
219/// This returns whether the locale's encoding is UTF-8, and the current
220/// charset if available.
221#[doc(alias = "g_get_charset")]
222#[doc(alias = "get_charset")]
223pub fn charset() -> (bool, Option<&'static GStr>) {
224    unsafe {
225        let mut out_charset = ptr::null();
226        let is_utf8 = from_glib(ffi::g_get_charset(&mut out_charset));
227        let charset = from_glib_none(out_charset);
228        (is_utf8, charset)
229    }
230}
231
232#[doc(alias = "g_compute_checksum_for_string")]
233pub fn compute_checksum_for_string(
234    checksum_type: ChecksumType,
235    str: impl IntoGStr,
236) -> Option<crate::GString> {
237    str.run_with_gstr(|str| unsafe {
238        from_glib_full(ffi::g_compute_checksum_for_string(
239            checksum_type.into_glib(),
240            str.as_ptr(),
241            str.len() as _,
242        ))
243    })
244}
245
246/// Opens a file for writing in the preferred directory for temporary
247/// files (as returned by g_get_tmp_dir()).
248///
249/// @tmpl should be a string in the GLib file name encoding containing
250/// a sequence of six 'X' characters, as the parameter to g_mkstemp().
251/// However, unlike these functions, the template should only be a
252/// basename, no directory components are allowed. If template is
253/// [`None`], a default template is used.
254///
255/// Note that in contrast to g_mkstemp() (and mkstemp()) @tmpl is not
256/// modified, and might thus be a read-only literal string.
257///
258/// Upon success, and if @name_used is non-[`None`], the actual name used
259/// is returned in @name_used. This string should be freed with g_free()
260/// when not needed any longer. The returned name is in the GLib file
261/// name encoding.
262/// ## `tmpl`
263/// Template for file name, as in
264///   g_mkstemp(), basename only, or [`None`] for a default template
265///
266/// # Returns
267///
268/// A file handle (as from open()) to the file opened for
269///   reading and writing. The file is opened in binary mode on platforms
270///   where there is a difference. The file handle should be closed with
271///   close(). In case of errors, -1 is returned and @error will be set.
272///
273/// ## `name_used`
274/// location to store actual name used,
275///   or [`None`]
276#[cfg(unix)]
277#[doc(alias = "g_file_open_tmp")]
278pub fn file_open_tmp(
279    tmpl: Option<impl AsRef<std::path::Path>>,
280) -> Result<(OwnedFd, std::path::PathBuf), crate::Error> {
281    unsafe {
282        let mut name_used = ptr::null_mut();
283        let mut error = ptr::null_mut();
284        let ret = ffi::g_file_open_tmp(
285            tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
286            &mut name_used,
287            &mut error,
288        );
289        if error.is_null() {
290            Ok((OwnedFd::from_raw_fd(ret), from_glib_full(name_used)))
291        } else {
292            Err(from_glib_full(error))
293        }
294    }
295}
296
297// rustdoc-stripper-ignore-next
298/// Spawn a new infallible `Future` on the thread-default main context.
299///
300/// This can be called from any thread and will execute the future from the thread
301/// where main context is running, e.g. via a `MainLoop`.
302#[cfg(feature = "futures")]
303pub fn spawn_future<R: Send + 'static, F: std::future::Future<Output = R> + Send + 'static>(
304    f: F,
305) -> crate::JoinHandle<R> {
306    let ctx = crate::MainContext::ref_thread_default();
307    ctx.spawn(f)
308}
309
310// rustdoc-stripper-ignore-next
311/// Spawn a new infallible `Future` on the thread-default main context.
312///
313/// The given `Future` does not have to be `Send`.
314///
315/// This can be called only from the thread where the main context is running, e.g.
316/// from any other `Future` that is executed on this main context, or after calling
317/// `with_thread_default` or `acquire` on the main context.
318#[cfg(feature = "futures")]
319pub fn spawn_future_local<R: 'static, F: std::future::Future<Output = R> + 'static>(
320    f: F,
321) -> crate::JoinHandle<R> {
322    let ctx = crate::MainContext::ref_thread_default();
323    ctx.spawn_local(f)
324}