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