glib/
source.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(unix)]
4use std::os::unix::io::RawFd;
5use std::{cell::RefCell, mem::transmute, num::NonZeroU32, time::Duration};
6
7use crate::ffi::{self, gboolean, gpointer};
8#[cfg(all(not(unix), docsrs))]
9use libc::c_int as RawFd;
10
11#[cfg(unix)]
12use crate::IOCondition;
13use crate::{thread_guard::ThreadGuard, translate::*, ControlFlow, MainContext, Source};
14
15// rustdoc-stripper-ignore-next
16/// The id of a source that is returned by `idle_add` and `timeout_add`.
17///
18/// This type does not implement `Clone` to prevent calling [`SourceId::remove`]
19/// multiple times on the same source.
20#[derive(Debug, Eq, PartialEq)]
21pub struct SourceId(NonZeroU32);
22
23impl SourceId {
24    // rustdoc-stripper-ignore-next
25    /// Returns the internal source ID.
26    pub fn as_raw(&self) -> u32 {
27        self.0.get()
28    }
29
30    // rustdoc-stripper-ignore-next
31    /// Removes the source with the given id `source_id` from the default main context.
32    ///
33    /// It is a programmer error to attempt to remove a non-existent source.
34    #[doc(alias = "g_source_remove")]
35    pub fn remove(self) {
36        unsafe {
37            result_from_gboolean!(
38                ffi::g_source_remove(self.as_raw()),
39                "Failed to remove source"
40            )
41            .unwrap()
42        }
43    }
44}
45
46#[doc(hidden)]
47impl FromGlib<u32> for SourceId {
48    #[inline]
49    unsafe fn from_glib(val: u32) -> Self {
50        debug_assert_ne!(val, 0);
51        Self(NonZeroU32::new_unchecked(val))
52    }
53}
54
55// rustdoc-stripper-ignore-next
56/// Process identifier
57#[derive(Copy, Clone, Debug, Eq, PartialEq)]
58#[doc(alias = "GPid")]
59pub struct Pid(pub ffi::GPid);
60
61unsafe impl Send for Pid {}
62unsafe impl Sync for Pid {}
63
64#[doc(hidden)]
65impl IntoGlib for Pid {
66    type GlibType = ffi::GPid;
67
68    #[inline]
69    fn into_glib(self) -> ffi::GPid {
70        self.0
71    }
72}
73
74#[doc(hidden)]
75impl FromGlib<ffi::GPid> for Pid {
76    #[inline]
77    unsafe fn from_glib(val: ffi::GPid) -> Self {
78        Self(val)
79    }
80}
81
82unsafe extern "C" fn trampoline<F: FnMut() -> ControlFlow + Send + 'static>(
83    func: gpointer,
84) -> gboolean {
85    let func: &RefCell<F> = &*(func as *const RefCell<F>);
86    (*func.borrow_mut())().into_glib()
87}
88
89unsafe extern "C" fn trampoline_local<F: FnMut() -> ControlFlow + 'static>(
90    func: gpointer,
91) -> gboolean {
92    let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
93    (*func.get_ref().borrow_mut())().into_glib()
94}
95
96unsafe extern "C" fn destroy_closure<F: FnMut() -> ControlFlow + Send + 'static>(ptr: gpointer) {
97    let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
98}
99
100unsafe extern "C" fn destroy_closure_local<F: FnMut() -> ControlFlow + 'static>(ptr: gpointer) {
101    let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
102}
103
104fn into_raw<F: FnMut() -> ControlFlow + Send + 'static>(func: F) -> gpointer {
105    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
106    Box::into_raw(func) as gpointer
107}
108
109fn into_raw_local<F: FnMut() -> ControlFlow + 'static>(func: F) -> gpointer {
110    let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
111    Box::into_raw(func) as gpointer
112}
113
114unsafe extern "C" fn trampoline_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
115    pid: ffi::GPid,
116    status: i32,
117    func: gpointer,
118) {
119    let func: &RefCell<F> = &*(func as *const RefCell<F>);
120    (*func.borrow_mut())(Pid(pid), status)
121}
122
123unsafe extern "C" fn trampoline_child_watch_local<F: FnMut(Pid, i32) + 'static>(
124    pid: ffi::GPid,
125    status: i32,
126    func: gpointer,
127) {
128    let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
129    (*func.get_ref().borrow_mut())(Pid(pid), status)
130}
131
132unsafe extern "C" fn destroy_closure_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
133    ptr: gpointer,
134) {
135    let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
136}
137
138unsafe extern "C" fn destroy_closure_child_watch_local<F: FnMut(Pid, i32) + 'static>(
139    ptr: gpointer,
140) {
141    let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
142}
143
144fn into_raw_child_watch<F: FnMut(Pid, i32) + Send + 'static>(func: F) -> gpointer {
145    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
146    Box::into_raw(func) as gpointer
147}
148
149fn into_raw_child_watch_local<F: FnMut(Pid, i32) + 'static>(func: F) -> gpointer {
150    let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
151    Box::into_raw(func) as gpointer
152}
153
154#[cfg(unix)]
155#[cfg_attr(docsrs, doc(cfg(unix)))]
156unsafe extern "C" fn trampoline_unix_fd<
157    F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
158>(
159    fd: i32,
160    condition: ffi::GIOCondition,
161    func: gpointer,
162) -> gboolean {
163    let func: &RefCell<F> = &*(func as *const RefCell<F>);
164    (*func.borrow_mut())(fd, from_glib(condition)).into_glib()
165}
166
167#[cfg(unix)]
168#[cfg_attr(docsrs, doc(cfg(unix)))]
169unsafe extern "C" fn trampoline_unix_fd_local<
170    F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static,
171>(
172    fd: i32,
173    condition: ffi::GIOCondition,
174    func: gpointer,
175) -> gboolean {
176    let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
177    (*func.get_ref().borrow_mut())(fd, from_glib(condition)).into_glib()
178}
179
180#[cfg(unix)]
181#[cfg_attr(docsrs, doc(cfg(unix)))]
182unsafe extern "C" fn destroy_closure_unix_fd<
183    F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
184>(
185    ptr: gpointer,
186) {
187    let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
188}
189
190#[cfg(unix)]
191#[cfg_attr(docsrs, doc(cfg(unix)))]
192unsafe extern "C" fn destroy_closure_unix_fd_local<
193    F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static,
194>(
195    ptr: gpointer,
196) {
197    let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
198}
199
200#[cfg(unix)]
201#[cfg_attr(docsrs, doc(cfg(unix)))]
202fn into_raw_unix_fd<F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static>(
203    func: F,
204) -> gpointer {
205    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
206    Box::into_raw(func) as gpointer
207}
208
209#[cfg(unix)]
210#[cfg_attr(docsrs, doc(cfg(unix)))]
211fn into_raw_unix_fd_local<F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static>(
212    func: F,
213) -> gpointer {
214    let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
215    Box::into_raw(func) as gpointer
216}
217
218// rustdoc-stripper-ignore-next
219/// Transform a generic FnOnce into a closure that can be used as callback in various glib methods
220///
221/// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break`
222/// in order to prevent being called twice.
223#[inline(always)]
224fn fnmut_callback_wrapper(
225    func: impl FnOnce() + Send + 'static,
226) -> impl FnMut() -> ControlFlow + Send + 'static {
227    let mut func = Some(func);
228    move || {
229        let func = func
230            .take()
231            .expect("GSource closure called after returning ControlFlow::Break");
232        func();
233        ControlFlow::Break
234    }
235}
236
237// rustdoc-stripper-ignore-next
238/// Transform a generic FnOnce into a closure that can be used as callback in various glib methods
239///
240/// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break`
241/// in order to prevent being called twice.
242///
243/// Different to `fnmut_callback_wrapper()`, this does not require `func` to be
244/// `Send` but can only be called from the thread that owns the main context.
245#[inline(always)]
246fn fnmut_callback_wrapper_local(
247    func: impl FnOnce() + 'static,
248) -> impl FnMut() -> ControlFlow + 'static {
249    let mut func = Some(func);
250    move || {
251        let func = func
252            .take()
253            .expect("GSource closure called after returning glib::ControlFlow::Break");
254        func();
255        ControlFlow::Break
256    }
257}
258
259// rustdoc-stripper-ignore-next
260/// Adds a closure to be called by the default main loop when it's idle.
261///
262/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
263///
264/// The default main loop almost always is the main loop of the main thread.
265/// Thus, the closure is called on the main thread.
266#[doc(alias = "g_idle_add_full")]
267pub fn idle_add<F>(func: F) -> SourceId
268where
269    F: FnMut() -> ControlFlow + Send + 'static,
270{
271    unsafe {
272        from_glib(ffi::g_idle_add_full(
273            ffi::G_PRIORITY_DEFAULT_IDLE,
274            Some(trampoline::<F>),
275            into_raw(func),
276            Some(destroy_closure::<F>),
277        ))
278    }
279}
280
281// rustdoc-stripper-ignore-next
282/// Adds a closure to be called by the default main loop when it's idle.
283///
284/// `func` will be called repeatedly with `priority` until it returns
285/// `ControlFlow::Break`.
286///
287/// The default main loop almost always is the main loop of the main thread.
288/// Thus, the closure is called on the main thread.
289#[doc(alias = "g_idle_add_full")]
290pub fn idle_add_full<F>(priority: Priority, func: F) -> SourceId
291where
292    F: FnMut() -> ControlFlow + Send + 'static,
293{
294    unsafe {
295        from_glib(ffi::g_idle_add_full(
296            priority.into_glib(),
297            Some(trampoline::<F>),
298            into_raw(func),
299            Some(destroy_closure::<F>),
300        ))
301    }
302}
303
304// rustdoc-stripper-ignore-next
305/// Adds a closure to be called by the default main loop when it's idle.
306///
307/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
308///
309/// The default main loop almost always is the main loop of the main thread.
310/// Thus, the closure is called on the main thread.
311///
312/// In comparison to `idle_add()`, this only requires `func` to be
313/// `FnOnce`, and will automatically return `ControlFlow::Break`.
314#[doc(alias = "g_idle_add_full")]
315#[doc(alias = "g_idle_add_once")]
316pub fn idle_add_once<F>(func: F) -> SourceId
317where
318    F: FnOnce() + Send + 'static,
319{
320    idle_add(fnmut_callback_wrapper(func))
321}
322
323// rustdoc-stripper-ignore-next
324/// Adds a closure to be called by the default main loop when it's idle.
325///
326/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
327///
328/// The default main loop almost always is the main loop of the main thread.
329/// Thus, the closure is called on the main thread.
330///
331/// Different to `idle_add()`, this does not require `func` to be
332/// `Send` but can only be called from the thread that owns the main context.
333///
334/// This function panics if called from a different thread than the one that
335/// owns the default main context.
336#[doc(alias = "g_idle_add_full")]
337pub fn idle_add_local<F>(func: F) -> SourceId
338where
339    F: FnMut() -> ControlFlow + 'static,
340{
341    unsafe {
342        let context = MainContext::default();
343        let _acquire = context
344            .acquire()
345            .expect("default main context already acquired by another thread");
346        from_glib(ffi::g_idle_add_full(
347            ffi::G_PRIORITY_DEFAULT_IDLE,
348            Some(trampoline_local::<F>),
349            into_raw_local(func),
350            Some(destroy_closure_local::<F>),
351        ))
352    }
353}
354
355// rustdoc-stripper-ignore-next
356/// Adds a closure to be called by the default main loop when it's idle.
357///
358/// `func` will be called repeatedly with `priority` until it returns
359/// `ControlFlow::Break`.
360///
361/// The default main loop almost always is the main loop of the main thread.
362/// Thus, the closure is called on the main thread.
363///
364/// Different to `idle_add()`, this does not require `func` to be
365/// `Send` but can only be called from the thread that owns the main context.
366///
367/// This function panics if called from a different thread than the one that
368/// owns the default main context.
369#[doc(alias = "g_idle_add_full")]
370pub fn idle_add_local_full<F>(priority: Priority, func: F) -> SourceId
371where
372    F: FnMut() -> ControlFlow + 'static,
373{
374    unsafe {
375        let context = MainContext::default();
376        let _acquire = context
377            .acquire()
378            .expect("default main context already acquired by another thread");
379        from_glib(ffi::g_idle_add_full(
380            priority.into_glib(),
381            Some(trampoline_local::<F>),
382            into_raw_local(func),
383            Some(destroy_closure_local::<F>),
384        ))
385    }
386}
387
388// rustdoc-stripper-ignore-next
389/// Adds a closure to be called by the default main loop when it's idle.
390///
391/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
392///
393/// The default main loop almost always is the main loop of the main thread.
394/// Thus, the closure is called on the main thread.
395///
396/// Different to `idle_add()`, this does not require `func` to be
397/// `Send` but can only be called from the thread that owns the main context.
398///
399/// This function panics if called from a different thread than the one that
400/// owns the main context.
401///
402/// In comparison to `idle_add_local()`, this only requires `func` to be
403/// `FnOnce`, and will automatically return `ControlFlow::Break`.
404#[doc(alias = "g_idle_add_full")]
405pub fn idle_add_local_once<F>(func: F) -> SourceId
406where
407    F: FnOnce() + 'static,
408{
409    idle_add_local(fnmut_callback_wrapper_local(func))
410}
411
412// rustdoc-stripper-ignore-next
413/// Adds a closure to be called by the default main loop at regular intervals
414/// with millisecond granularity.
415///
416/// `func` will be called repeatedly every `interval` milliseconds until it
417/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
418/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
419/// precision is not necessary.
420///
421/// The default main loop almost always is the main loop of the main thread.
422/// Thus, the closure is called on the main thread.
423#[doc(alias = "g_timeout_add_full")]
424pub fn timeout_add<F>(interval: Duration, func: F) -> SourceId
425where
426    F: FnMut() -> ControlFlow + Send + 'static,
427{
428    unsafe {
429        from_glib(ffi::g_timeout_add_full(
430            ffi::G_PRIORITY_DEFAULT,
431            interval.as_millis() as _,
432            Some(trampoline::<F>),
433            into_raw(func),
434            Some(destroy_closure::<F>),
435        ))
436    }
437}
438
439// rustdoc-stripper-ignore-next
440/// Adds a closure to be called by the default main loop at regular intervals
441/// with millisecond granularity.
442///
443/// `func` will be called repeatedly every `interval` milliseconds with `priority`
444/// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the
445/// timeout may be delayed by other events. Prefer `timeout_add_seconds` when
446/// millisecond precision is not necessary.
447///
448/// The default main loop almost always is the main loop of the main thread.
449/// Thus, the closure is called on the main thread.
450#[doc(alias = "g_timeout_add_full")]
451pub fn timeout_add_full<F>(interval: Duration, priority: Priority, func: F) -> SourceId
452where
453    F: FnMut() -> ControlFlow + Send + 'static,
454{
455    unsafe {
456        from_glib(ffi::g_timeout_add_full(
457            priority.into_glib(),
458            interval.as_millis() as _,
459            Some(trampoline::<F>),
460            into_raw(func),
461            Some(destroy_closure::<F>),
462        ))
463    }
464}
465
466// rustdoc-stripper-ignore-next
467/// Adds a closure to be called by the default main loop at regular intervals
468/// with millisecond granularity.
469///
470/// `func` will be called repeatedly every `interval` milliseconds until it
471/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
472/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
473/// precision is not necessary.
474///
475/// The default main loop almost always is the main loop of the main thread.
476/// Thus, the closure is called on the main thread.
477///
478/// In comparison to `timeout_add()`, this only requires `func` to be
479/// `FnOnce`, and will automatically return `ControlFlow::Break`.
480#[doc(alias = "g_timeout_add_full")]
481#[doc(alias = "g_timeout_add_once")]
482pub fn timeout_add_once<F>(interval: Duration, func: F) -> SourceId
483where
484    F: FnOnce() + Send + 'static,
485{
486    timeout_add(interval, fnmut_callback_wrapper(func))
487}
488
489// rustdoc-stripper-ignore-next
490/// Adds a closure to be called by the default main loop at regular intervals
491/// with millisecond granularity.
492///
493/// `func` will be called repeatedly every `interval` milliseconds until it
494/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
495/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
496/// precision is not necessary.
497///
498/// The default main loop almost always is the main loop of the main thread.
499/// Thus, the closure is called on the main thread.
500///
501/// Different to `timeout_add()`, this does not require `func` to be
502/// `Send` but can only be called from the thread that owns the main context.
503///
504/// This function panics if called from a different thread than the one that
505/// owns the main context.
506#[doc(alias = "g_timeout_add_full")]
507pub fn timeout_add_local<F>(interval: Duration, func: F) -> SourceId
508where
509    F: FnMut() -> ControlFlow + 'static,
510{
511    unsafe {
512        let context = MainContext::default();
513        let _acquire = context
514            .acquire()
515            .expect("default main context already acquired by another thread");
516        from_glib(ffi::g_timeout_add_full(
517            ffi::G_PRIORITY_DEFAULT,
518            interval.as_millis() as _,
519            Some(trampoline_local::<F>),
520            into_raw_local(func),
521            Some(destroy_closure_local::<F>),
522        ))
523    }
524}
525
526// rustdoc-stripper-ignore-next
527/// Adds a closure to be called by the default main loop at regular intervals
528/// with millisecond granularity.
529///
530/// `func` will be called repeatedly every `interval` milliseconds with `priority`
531/// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the
532/// timeout may be delayed by other events. Prefer `timeout_add_seconds` when
533/// millisecond precision is not necessary.
534///
535/// The default main loop almost always is the main loop of the main thread.
536/// Thus, the closure is called on the main thread.
537///
538/// Different to `timeout_add()`, this does not require `func` to be
539/// `Send` but can only be called from the thread that owns the main context.
540///
541/// This function panics if called from a different thread than the one that
542/// owns the main context.
543#[doc(alias = "g_timeout_add_full")]
544pub fn timeout_add_local_full<F>(interval: Duration, priority: Priority, func: F) -> SourceId
545where
546    F: FnMut() -> ControlFlow + 'static,
547{
548    unsafe {
549        let context = MainContext::default();
550        let _acquire = context
551            .acquire()
552            .expect("default main context already acquired by another thread");
553        from_glib(ffi::g_timeout_add_full(
554            priority.into_glib(),
555            interval.as_millis() as _,
556            Some(trampoline_local::<F>),
557            into_raw_local(func),
558            Some(destroy_closure_local::<F>),
559        ))
560    }
561}
562
563// rustdoc-stripper-ignore-next
564/// Adds a closure to be called by the default main loop at regular intervals
565/// with millisecond granularity.
566///
567/// `func` will be called repeatedly every `interval` milliseconds until it
568/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
569/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
570/// precision is not necessary.
571///
572/// The default main loop almost always is the main loop of the main thread.
573/// Thus, the closure is called on the main thread.
574///
575/// Different to `timeout_add()`, this does not require `func` to be
576/// `Send` but can only be called from the thread that owns the main context.
577///
578/// This function panics if called from a different thread than the one that
579/// owns the main context.
580///
581/// In comparison to `timeout_add_local()`, this only requires `func` to be
582/// `FnOnce`, and will automatically return `ControlFlow::Break`.
583#[doc(alias = "g_timeout_add_full")]
584pub fn timeout_add_local_once<F>(interval: Duration, func: F) -> SourceId
585where
586    F: FnOnce() + 'static,
587{
588    timeout_add_local(interval, fnmut_callback_wrapper_local(func))
589}
590
591// rustdoc-stripper-ignore-next
592/// Adds a closure to be called by the default main loop at regular intervals
593/// with second granularity.
594///
595/// `func` will be called repeatedly every `interval` seconds until it
596/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
597/// be delayed by other events.
598///
599/// The default main loop almost always is the main loop of the main thread.
600/// Thus, the closure is called on the main thread.
601#[doc(alias = "g_timeout_add_seconds_full")]
602pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
603where
604    F: FnMut() -> ControlFlow + Send + 'static,
605{
606    unsafe {
607        from_glib(ffi::g_timeout_add_seconds_full(
608            ffi::G_PRIORITY_DEFAULT,
609            interval,
610            Some(trampoline::<F>),
611            into_raw(func),
612            Some(destroy_closure::<F>),
613        ))
614    }
615}
616
617// rustdoc-stripper-ignore-next
618/// Adds a closure to be called by the default main loop at regular intervals
619/// with second granularity.
620///
621/// `func` will be called repeatedly every `interval` seconds until it
622/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
623/// be delayed by other events.
624///
625/// The default main loop almost always is the main loop of the main thread.
626/// Thus, the closure is called on the main thread.
627///
628/// In comparison to `timeout_add_seconds()`, this only requires `func` to be
629/// `FnOnce`, and will automatically return `ControlFlow::Break`.
630#[doc(alias = "g_timeout_add_seconds_full")]
631pub fn timeout_add_seconds_once<F>(interval: u32, func: F) -> SourceId
632where
633    F: FnOnce() + Send + 'static,
634{
635    timeout_add_seconds(interval, fnmut_callback_wrapper(func))
636}
637
638// rustdoc-stripper-ignore-next
639/// Adds a closure to be called by the default main loop at regular intervals
640/// with second granularity.
641///
642/// `func` will be called repeatedly every `interval` seconds until it
643/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
644/// be delayed by other events.
645///
646/// The default main loop almost always is the main loop of the main thread.
647/// Thus, the closure is called on the main thread.
648///
649/// Different to `timeout_add_seconds()`, this does not require `func` to be
650/// `Send` but can only be called from the thread that owns the main context.
651///
652/// This function panics if called from a different thread than the one that
653/// owns the main context.
654#[doc(alias = "g_timeout_add_seconds_full")]
655pub fn timeout_add_seconds_local<F>(interval: u32, func: F) -> SourceId
656where
657    F: FnMut() -> ControlFlow + 'static,
658{
659    unsafe {
660        let context = MainContext::default();
661        let _acquire = context
662            .acquire()
663            .expect("default main context already acquired by another thread");
664        from_glib(ffi::g_timeout_add_seconds_full(
665            ffi::G_PRIORITY_DEFAULT,
666            interval,
667            Some(trampoline_local::<F>),
668            into_raw_local(func),
669            Some(destroy_closure_local::<F>),
670        ))
671    }
672}
673
674// rustdoc-stripper-ignore-next
675/// Adds a closure to be called by the default main loop at regular intervals
676/// with second granularity.
677///
678/// `func` will be called repeatedly every `interval` seconds until it
679/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
680/// be delayed by other events.
681///
682/// The default main loop almost always is the main loop of the main thread.
683/// Thus, the closure is called on the main thread.
684///
685/// Different to `timeout_add_seconds()`, this does not require `func` to be
686/// `Send` but can only be called from the thread that owns the main context.
687///
688/// This function panics if called from a different thread than the one that
689/// owns the main context.
690///
691/// In comparison to `timeout_add_seconds_local()`, this only requires `func` to be
692/// `FnOnce`, and will automatically return `ControlFlow::Break`.
693#[doc(alias = "g_timeout_add_seconds_full")]
694pub fn timeout_add_seconds_local_once<F>(interval: u32, func: F) -> SourceId
695where
696    F: FnOnce() + 'static,
697{
698    timeout_add_seconds_local(interval, fnmut_callback_wrapper_local(func))
699}
700
701// rustdoc-stripper-ignore-next
702/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
703/// process exits.
704///
705/// `func` will be called when `pid` exits
706#[doc(alias = "g_child_watch_add_full")]
707pub fn child_watch_add<F>(pid: Pid, func: F) -> SourceId
708where
709    F: FnMut(Pid, i32) + Send + 'static,
710{
711    unsafe {
712        from_glib(ffi::g_child_watch_add_full(
713            ffi::G_PRIORITY_DEFAULT,
714            pid.0,
715            Some(trampoline_child_watch::<F>),
716            into_raw_child_watch(func),
717            Some(destroy_closure_child_watch::<F>),
718        ))
719    }
720}
721
722// rustdoc-stripper-ignore-next
723/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
724/// process exits.
725///
726/// `func` will be called when `pid` exits
727///
728/// Different to `child_watch_add()`, this does not require `func` to be
729/// `Send` but can only be called from the thread that owns the main context.
730///
731/// This function panics if called from a different thread than the one that
732/// owns the main context.
733#[doc(alias = "g_child_watch_add_full")]
734pub fn child_watch_add_local<F>(pid: Pid, func: F) -> SourceId
735where
736    F: FnMut(Pid, i32) + 'static,
737{
738    unsafe {
739        let context = MainContext::default();
740        let _acquire = context
741            .acquire()
742            .expect("default main context already acquired by another thread");
743        from_glib(ffi::g_child_watch_add_full(
744            ffi::G_PRIORITY_DEFAULT,
745            pid.0,
746            Some(trampoline_child_watch_local::<F>),
747            into_raw_child_watch_local(func),
748            Some(destroy_closure_child_watch_local::<F>),
749        ))
750    }
751}
752
753#[cfg(unix)]
754#[cfg_attr(docsrs, doc(cfg(unix)))]
755// rustdoc-stripper-ignore-next
756/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
757///
758/// `func` will be called repeatedly every time `signum` is raised until it
759/// returns `ControlFlow::Break`.
760///
761/// The default main loop almost always is the main loop of the main thread.
762/// Thus, the closure is called on the main thread.
763#[doc(alias = "g_unix_signal_add_full")]
764pub fn unix_signal_add<F>(signum: i32, func: F) -> SourceId
765where
766    F: FnMut() -> ControlFlow + Send + 'static,
767{
768    unsafe {
769        from_glib(ffi::g_unix_signal_add_full(
770            ffi::G_PRIORITY_DEFAULT,
771            signum,
772            Some(trampoline::<F>),
773            into_raw(func),
774            Some(destroy_closure::<F>),
775        ))
776    }
777}
778
779#[cfg(unix)]
780#[cfg_attr(docsrs, doc(cfg(unix)))]
781// rustdoc-stripper-ignore-next
782/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
783///
784/// `func` will be called repeatedly every time `signum` is raised until it
785/// returns `ControlFlow::Break`.
786///
787/// The default main loop almost always is the main loop of the main thread.
788/// Thus, the closure is called on the main thread.
789///
790/// In comparison to `unix_signal_add()`, this only requires `func` to be
791/// `FnOnce`, and will automatically return `ControlFlow::Break`.
792#[doc(alias = "g_unix_signal_add_full")]
793pub fn unix_signal_add_once<F>(signum: i32, func: F) -> SourceId
794where
795    F: FnOnce() + Send + 'static,
796{
797    unix_signal_add(signum, fnmut_callback_wrapper(func))
798}
799
800#[cfg(unix)]
801#[cfg_attr(docsrs, doc(cfg(unix)))]
802// rustdoc-stripper-ignore-next
803/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
804///
805/// `func` will be called repeatedly every time `signum` is raised until it
806/// returns `ControlFlow::Break`.
807///
808/// The default main loop almost always is the main loop of the main thread.
809/// Thus, the closure is called on the main thread.
810///
811/// Different to `unix_signal_add()`, this does not require `func` to be
812/// `Send` but can only be called from the thread that owns the main context.
813///
814/// This function panics if called from a different thread than the one that
815/// owns the main context.
816#[doc(alias = "g_unix_signal_add_full")]
817pub fn unix_signal_add_local<F>(signum: i32, func: F) -> SourceId
818where
819    F: FnMut() -> ControlFlow + 'static,
820{
821    unsafe {
822        let context = MainContext::default();
823        let _acquire = context
824            .acquire()
825            .expect("default main context already acquired by another thread");
826        from_glib(ffi::g_unix_signal_add_full(
827            ffi::G_PRIORITY_DEFAULT,
828            signum,
829            Some(trampoline_local::<F>),
830            into_raw_local(func),
831            Some(destroy_closure_local::<F>),
832        ))
833    }
834}
835
836#[cfg(unix)]
837#[cfg_attr(docsrs, doc(cfg(unix)))]
838// rustdoc-stripper-ignore-next
839/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
840///
841/// `func` will be called repeatedly every time `signum` is raised until it
842/// returns `ControlFlow::Break`.
843///
844/// The default main loop almost always is the main loop of the main thread.
845/// Thus, the closure is called on the main thread.
846///
847/// Different to `unix_signal_add()`, this does not require `func` to be
848/// `Send` but can only be called from the thread that owns the main context.
849///
850/// This function panics if called from a different thread than the one that
851/// owns the main context.
852///
853/// In comparison to `unix_signal_add_local()`, this only requires `func` to be
854/// `FnOnce`, and will automatically return `ControlFlow::Break`.
855#[doc(alias = "g_unix_signal_add_full")]
856pub fn unix_signal_add_local_once<F>(signum: i32, func: F) -> SourceId
857where
858    F: FnOnce() + 'static,
859{
860    unix_signal_add_local(signum, fnmut_callback_wrapper_local(func))
861}
862
863#[cfg(unix)]
864#[cfg_attr(docsrs, doc(cfg(unix)))]
865// rustdoc-stripper-ignore-next
866/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
867/// UNIX file descriptor reaches the given IO condition.
868///
869/// `func` will be called repeatedly while the file descriptor matches the given IO condition
870/// until it returns `ControlFlow::Break`.
871///
872/// The default main loop almost always is the main loop of the main thread.
873/// Thus, the closure is called on the main thread.
874#[doc(alias = "g_unix_fd_add_full")]
875pub fn unix_fd_add<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
876where
877    F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
878{
879    unsafe {
880        from_glib(ffi::g_unix_fd_add_full(
881            ffi::G_PRIORITY_DEFAULT,
882            fd,
883            condition.into_glib(),
884            Some(trampoline_unix_fd::<F>),
885            into_raw_unix_fd(func),
886            Some(destroy_closure_unix_fd::<F>),
887        ))
888    }
889}
890
891#[cfg(unix)]
892#[cfg_attr(docsrs, doc(cfg(unix)))]
893// rustdoc-stripper-ignore-next
894/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
895/// UNIX file descriptor reaches the given IO condition.
896///
897/// `func` will be called repeatedly with `priority` while the file descriptor matches the given IO condition
898/// until it returns `ControlFlow::Break`.
899///
900/// The default main loop almost always is the main loop of the main thread.
901/// Thus, the closure is called on the main thread.
902#[doc(alias = "g_unix_fd_add_full")]
903pub fn unix_fd_add_full<F>(
904    fd: RawFd,
905    priority: Priority,
906    condition: IOCondition,
907    func: F,
908) -> SourceId
909where
910    F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
911{
912    unsafe {
913        from_glib(ffi::g_unix_fd_add_full(
914            priority.into_glib(),
915            fd,
916            condition.into_glib(),
917            Some(trampoline_unix_fd::<F>),
918            into_raw_unix_fd(func),
919            Some(destroy_closure_unix_fd::<F>),
920        ))
921    }
922}
923
924#[cfg(unix)]
925#[cfg_attr(docsrs, doc(cfg(unix)))]
926// rustdoc-stripper-ignore-next
927/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
928/// UNIX file descriptor reaches the given IO condition.
929///
930/// `func` will be called repeatedly while the file descriptor matches the given IO condition
931/// until it returns `ControlFlow::Break`.
932///
933/// The default main loop almost always is the main loop of the main thread.
934/// Thus, the closure is called on the main thread.
935///
936/// Different to `unix_fd_add()`, this does not require `func` to be
937/// `Send` but can only be called from the thread that owns the main context.
938///
939/// This function panics if called from a different thread than the one that
940/// owns the main context.
941#[doc(alias = "g_unix_fd_add_full")]
942pub fn unix_fd_add_local<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
943where
944    F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static,
945{
946    unsafe {
947        let context = MainContext::default();
948        let _acquire = context
949            .acquire()
950            .expect("default main context already acquired by another thread");
951        from_glib(ffi::g_unix_fd_add_full(
952            ffi::G_PRIORITY_DEFAULT,
953            fd,
954            condition.into_glib(),
955            Some(trampoline_unix_fd_local::<F>),
956            into_raw_unix_fd_local(func),
957            Some(destroy_closure_unix_fd_local::<F>),
958        ))
959    }
960}
961
962#[cfg(unix)]
963#[cfg_attr(docsrs, doc(cfg(unix)))]
964// rustdoc-stripper-ignore-next
965/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
966/// UNIX file descriptor reaches the given IO condition.
967///
968/// `func` will be called repeatedly with `priority` while the file descriptor matches the given IO condition
969/// until it returns `ControlFlow::Break`.
970///
971/// The default main loop almost always is the main loop of the main thread.
972/// Thus, the closure is called on the main thread.
973///
974/// Different to `unix_fd_add()`, this does not require `func` to be
975/// `Send` but can only be called from the thread that owns the main context.
976///
977/// This function panics if called from a different thread than the one that
978/// owns the main context.
979#[doc(alias = "g_unix_fd_add_full")]
980pub fn unix_fd_add_local_full<F>(
981    fd: RawFd,
982    priority: Priority,
983    condition: IOCondition,
984    func: F,
985) -> SourceId
986where
987    F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static,
988{
989    unsafe {
990        let context = MainContext::default();
991        let _acquire = context
992            .acquire()
993            .expect("default main context already acquired by another thread");
994        from_glib(ffi::g_unix_fd_add_full(
995            priority.into_glib(),
996            fd,
997            condition.into_glib(),
998            Some(trampoline_unix_fd_local::<F>),
999            into_raw_unix_fd_local(func),
1000            Some(destroy_closure_unix_fd_local::<F>),
1001        ))
1002    }
1003}
1004
1005// rustdoc-stripper-ignore-next
1006/// The priority of sources
1007#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
1008pub struct Priority(i32);
1009
1010impl Priority {
1011    #[doc(alias = "G_PRIORITY_HIGH")]
1012    pub const HIGH: Self = Self(ffi::G_PRIORITY_HIGH);
1013    #[doc(alias = "G_PRIORITY_DEFAULT")]
1014    pub const DEFAULT: Self = Self(ffi::G_PRIORITY_DEFAULT);
1015    #[doc(alias = "G_PRIORITY_HIGH_IDLE")]
1016    pub const HIGH_IDLE: Self = Self(ffi::G_PRIORITY_HIGH_IDLE);
1017    #[doc(alias = "G_PRIORITY_DEFAULT_IDLE")]
1018    pub const DEFAULT_IDLE: Self = Self(ffi::G_PRIORITY_DEFAULT_IDLE);
1019    #[doc(alias = "G_PRIORITY_LOW")]
1020    pub const LOW: Self = Self(ffi::G_PRIORITY_LOW);
1021}
1022
1023impl Default for Priority {
1024    fn default() -> Self {
1025        Self::DEFAULT
1026    }
1027}
1028
1029#[doc(hidden)]
1030impl IntoGlib for Priority {
1031    type GlibType = i32;
1032
1033    #[inline]
1034    fn into_glib(self) -> i32 {
1035        self.0
1036    }
1037}
1038
1039#[doc(hidden)]
1040impl FromGlib<i32> for Priority {
1041    #[inline]
1042    unsafe fn from_glib(val: i32) -> Self {
1043        Self::from(val)
1044    }
1045}
1046
1047impl From<i32> for Priority {
1048    fn from(value: i32) -> Self {
1049        Self(value)
1050    }
1051}
1052
1053// rustdoc-stripper-ignore-next
1054/// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle.
1055///
1056/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
1057#[doc(alias = "g_idle_source_new")]
1058pub fn idle_source_new<F>(name: Option<&str>, priority: Priority, func: F) -> Source
1059where
1060    F: FnMut() -> ControlFlow + Send + 'static,
1061{
1062    unsafe {
1063        let source = ffi::g_idle_source_new();
1064        ffi::g_source_set_callback(
1065            source,
1066            Some(trampoline::<F>),
1067            into_raw(func),
1068            Some(destroy_closure::<F>),
1069        );
1070        ffi::g_source_set_priority(source, priority.into_glib());
1071
1072        if let Some(name) = name {
1073            ffi::g_source_set_name(source, name.to_glib_none().0);
1074        }
1075
1076        from_glib_full(source)
1077    }
1078}
1079
1080// rustdoc-stripper-ignore-next
1081/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
1082/// intervals with millisecond granularity.
1083///
1084/// `func` will be called repeatedly every `interval` milliseconds until it
1085/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
1086/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
1087/// precision is not necessary.
1088#[doc(alias = "g_timeout_source_new")]
1089pub fn timeout_source_new<F>(
1090    interval: Duration,
1091    name: Option<&str>,
1092    priority: Priority,
1093    func: F,
1094) -> Source
1095where
1096    F: FnMut() -> ControlFlow + Send + 'static,
1097{
1098    unsafe {
1099        let source = ffi::g_timeout_source_new(interval.as_millis() as _);
1100        ffi::g_source_set_callback(
1101            source,
1102            Some(trampoline::<F>),
1103            into_raw(func),
1104            Some(destroy_closure::<F>),
1105        );
1106        ffi::g_source_set_priority(source, priority.into_glib());
1107
1108        if let Some(name) = name {
1109            ffi::g_source_set_name(source, name.to_glib_none().0);
1110        }
1111
1112        from_glib_full(source)
1113    }
1114}
1115
1116// rustdoc-stripper-ignore-next
1117/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
1118/// intervals with second granularity.
1119///
1120/// `func` will be called repeatedly every `interval` seconds until it
1121/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
1122/// be delayed by other events.
1123#[doc(alias = "g_timeout_source_new_seconds")]
1124pub fn timeout_source_new_seconds<F>(
1125    interval: u32,
1126    name: Option<&str>,
1127    priority: Priority,
1128    func: F,
1129) -> Source
1130where
1131    F: FnMut() -> ControlFlow + Send + 'static,
1132{
1133    unsafe {
1134        let source = ffi::g_timeout_source_new_seconds(interval);
1135        ffi::g_source_set_callback(
1136            source,
1137            Some(trampoline::<F>),
1138            into_raw(func),
1139            Some(destroy_closure::<F>),
1140        );
1141        ffi::g_source_set_priority(source, priority.into_glib());
1142
1143        if let Some(name) = name {
1144            ffi::g_source_set_name(source, name.to_glib_none().0);
1145        }
1146
1147        from_glib_full(source)
1148    }
1149}
1150
1151// rustdoc-stripper-ignore-next
1152/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
1153/// process exits.
1154///
1155/// `func` will be called when `pid` exits
1156#[doc(alias = "g_child_watch_source_new")]
1157pub fn child_watch_source_new<F>(
1158    pid: Pid,
1159    name: Option<&str>,
1160    priority: Priority,
1161    func: F,
1162) -> Source
1163where
1164    F: FnMut(Pid, i32) + Send + 'static,
1165{
1166    unsafe {
1167        let source = ffi::g_child_watch_source_new(pid.0);
1168        ffi::g_source_set_callback(
1169            source,
1170            Some(transmute::<
1171                *mut (),
1172                unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
1173            >(trampoline_child_watch::<F> as *mut ())),
1174            into_raw_child_watch(func),
1175            Some(destroy_closure_child_watch::<F>),
1176        );
1177        ffi::g_source_set_priority(source, priority.into_glib());
1178
1179        if let Some(name) = name {
1180            ffi::g_source_set_name(source, name.to_glib_none().0);
1181        }
1182
1183        from_glib_full(source)
1184    }
1185}
1186
1187#[cfg(unix)]
1188#[cfg_attr(docsrs, doc(cfg(unix)))]
1189// rustdoc-stripper-ignore-next
1190/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
1191/// UNIX signal is raised.
1192///
1193/// `func` will be called repeatedly every time `signum` is raised until it
1194/// returns `ControlFlow::Break`.
1195#[doc(alias = "g_unix_signal_source_new")]
1196pub fn unix_signal_source_new<F>(
1197    signum: i32,
1198    name: Option<&str>,
1199    priority: Priority,
1200    func: F,
1201) -> Source
1202where
1203    F: FnMut() -> ControlFlow + Send + 'static,
1204{
1205    unsafe {
1206        let source = ffi::g_unix_signal_source_new(signum);
1207        ffi::g_source_set_callback(
1208            source,
1209            Some(trampoline::<F>),
1210            into_raw(func),
1211            Some(destroy_closure::<F>),
1212        );
1213        ffi::g_source_set_priority(source, priority.into_glib());
1214
1215        if let Some(name) = name {
1216            ffi::g_source_set_name(source, name.to_glib_none().0);
1217        }
1218
1219        from_glib_full(source)
1220    }
1221}
1222
1223#[cfg(unix)]
1224#[cfg_attr(docsrs, doc(cfg(unix)))]
1225// rustdoc-stripper-ignore-next
1226/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
1227/// UNIX file descriptor reaches the given IO condition.
1228///
1229/// `func` will be called repeatedly while the file descriptor matches the given IO condition
1230/// until it returns `ControlFlow::Break`.
1231#[doc(alias = "g_unix_fd_source_new")]
1232pub fn unix_fd_source_new<F>(
1233    fd: RawFd,
1234    condition: IOCondition,
1235    name: Option<&str>,
1236    priority: Priority,
1237    func: F,
1238) -> Source
1239where
1240    F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
1241{
1242    unsafe {
1243        let source = ffi::g_unix_fd_source_new(fd, condition.into_glib());
1244        ffi::g_source_set_callback(
1245            source,
1246            Some(transmute::<
1247                *const (),
1248                unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
1249            >(trampoline_unix_fd::<F> as *const ())),
1250            into_raw_unix_fd(func),
1251            Some(destroy_closure_unix_fd::<F>),
1252        );
1253        ffi::g_source_set_priority(source, priority.into_glib());
1254
1255        if let Some(name) = name {
1256            ffi::g_source_set_name(source, name.to_glib_none().0);
1257        }
1258
1259        from_glib_full(source)
1260    }
1261}
1262
1263impl Source {
1264    #[doc(alias = "g_source_attach")]
1265    pub fn attach(&self, context: Option<&MainContext>) -> SourceId {
1266        unsafe {
1267            from_glib(ffi::g_source_attach(
1268                self.to_glib_none().0,
1269                context.to_glib_none().0,
1270            ))
1271        }
1272    }
1273}