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#[cfg(unix)]
247#[doc(alias = "g_file_open_tmp")]
248pub fn file_open_tmp(
249    tmpl: Option<impl AsRef<std::path::Path>>,
250) -> Result<(OwnedFd, std::path::PathBuf), crate::Error> {
251    unsafe {
252        let mut name_used = ptr::null_mut();
253        let mut error = ptr::null_mut();
254        let ret = ffi::g_file_open_tmp(
255            tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
256            &mut name_used,
257            &mut error,
258        );
259        if error.is_null() {
260            Ok((OwnedFd::from_raw_fd(ret), from_glib_full(name_used)))
261        } else {
262            Err(from_glib_full(error))
263        }
264    }
265}
266
267// rustdoc-stripper-ignore-next
268/// Spawn a new infallible `Future` on the thread-default main context.
269///
270/// This can be called from any thread and will execute the future from the thread
271/// where main context is running, e.g. via a `MainLoop`.
272#[cfg(feature = "futures")]
273pub fn spawn_future<R: Send + 'static, F: std::future::Future<Output = R> + Send + 'static>(
274    f: F,
275) -> crate::JoinHandle<R> {
276    let ctx = crate::MainContext::ref_thread_default();
277    ctx.spawn(f)
278}
279
280// rustdoc-stripper-ignore-next
281/// Spawn a new infallible `Future` on the thread-default main context.
282///
283/// The given `Future` does not have to be `Send`.
284///
285/// This can be called only from the thread where the main context is running, e.g.
286/// from any other `Future` that is executed on this main context, or after calling
287/// `with_thread_default` or `acquire` on the main context.
288#[cfg(feature = "futures")]
289pub fn spawn_future_local<R: 'static, F: std::future::Future<Output = R> + 'static>(
290    f: F,
291) -> crate::JoinHandle<R> {
292    let ctx = crate::MainContext::ref_thread_default();
293    ctx.spawn_local(f)
294}