glib/
source.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{cell::RefCell, mem::transmute, num::NonZeroU32, time::Duration};
4
5use crate::ffi::{self, gboolean, gpointer};
6
7use crate::{ControlFlow, MainContext, Source, thread_guard::ThreadGuard, translate::*};
8
9// rustdoc-stripper-ignore-next
10/// The id of a source that is returned by `idle_add` and `timeout_add`.
11///
12/// This type does not implement `Clone` to prevent calling [`SourceId::remove`]
13/// multiple times on the same source.
14#[derive(Debug, Eq, PartialEq)]
15pub struct SourceId(NonZeroU32);
16
17impl SourceId {
18    // rustdoc-stripper-ignore-next
19    /// Returns the internal source ID.
20    pub fn as_raw(&self) -> u32 {
21        self.0.get()
22    }
23
24    // rustdoc-stripper-ignore-next
25    /// Removes the source with the given id `source_id` from the default main context.
26    ///
27    /// It is a programmer error to attempt to remove a non-existent source.
28    #[doc(alias = "g_source_remove")]
29    pub fn remove(self) {
30        unsafe {
31            result_from_gboolean!(
32                ffi::g_source_remove(self.as_raw()),
33                "Failed to remove source"
34            )
35            .unwrap()
36        }
37    }
38}
39
40#[doc(hidden)]
41impl FromGlib<u32> for SourceId {
42    #[inline]
43    unsafe fn from_glib(val: u32) -> Self {
44        unsafe {
45            debug_assert_ne!(val, 0);
46            Self(NonZeroU32::new_unchecked(val))
47        }
48    }
49}
50
51// rustdoc-stripper-ignore-next
52/// Process identifier
53#[derive(Copy, Clone, Debug, Eq, PartialEq)]
54#[doc(alias = "GPid")]
55pub struct Pid(pub ffi::GPid);
56
57unsafe impl Send for Pid {}
58unsafe impl Sync for Pid {}
59
60#[doc(hidden)]
61impl IntoGlib for Pid {
62    type GlibType = ffi::GPid;
63
64    #[inline]
65    fn into_glib(self) -> ffi::GPid {
66        self.0
67    }
68}
69
70#[doc(hidden)]
71impl FromGlib<ffi::GPid> for Pid {
72    #[inline]
73    unsafe fn from_glib(val: ffi::GPid) -> Self {
74        Self(val)
75    }
76}
77
78unsafe extern "C" fn trampoline<F: FnMut() -> ControlFlow + Send + 'static>(
79    func: gpointer,
80) -> gboolean {
81    unsafe {
82        let func: &RefCell<F> = &*(func as *const RefCell<F>);
83        (*func.borrow_mut())().into_glib()
84    }
85}
86
87unsafe extern "C" fn trampoline_local<F: FnMut() -> ControlFlow + 'static>(
88    func: gpointer,
89) -> gboolean {
90    unsafe {
91        let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
92        (*func.get_ref().borrow_mut())().into_glib()
93    }
94}
95
96unsafe extern "C" fn destroy_closure<F: FnMut() -> ControlFlow + Send + 'static>(ptr: gpointer) {
97    unsafe {
98        let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
99    }
100}
101
102unsafe extern "C" fn destroy_closure_local<F: FnMut() -> ControlFlow + 'static>(ptr: gpointer) {
103    unsafe {
104        let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
105    }
106}
107
108fn into_raw<F: FnMut() -> ControlFlow + Send + 'static>(func: F) -> gpointer {
109    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
110    Box::into_raw(func) as gpointer
111}
112
113fn into_raw_local<F: FnMut() -> ControlFlow + 'static>(func: F) -> gpointer {
114    let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
115    Box::into_raw(func) as gpointer
116}
117
118unsafe extern "C" fn trampoline_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
119    pid: ffi::GPid,
120    status: i32,
121    func: gpointer,
122) {
123    unsafe {
124        let func: &RefCell<F> = &*(func as *const RefCell<F>);
125        (*func.borrow_mut())(Pid(pid), status)
126    }
127}
128
129unsafe extern "C" fn trampoline_child_watch_local<F: FnMut(Pid, i32) + 'static>(
130    pid: ffi::GPid,
131    status: i32,
132    func: gpointer,
133) {
134    unsafe {
135        let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
136        (*func.get_ref().borrow_mut())(Pid(pid), status)
137    }
138}
139
140unsafe extern "C" fn destroy_closure_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
141    ptr: gpointer,
142) {
143    unsafe {
144        let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
145    }
146}
147
148unsafe extern "C" fn destroy_closure_child_watch_local<F: FnMut(Pid, i32) + 'static>(
149    ptr: gpointer,
150) {
151    unsafe {
152        let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
153    }
154}
155
156fn into_raw_child_watch<F: FnMut(Pid, i32) + Send + 'static>(func: F) -> gpointer {
157    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
158    Box::into_raw(func) as gpointer
159}
160
161fn into_raw_child_watch_local<F: FnMut(Pid, i32) + 'static>(func: F) -> gpointer {
162    let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
163    Box::into_raw(func) as gpointer
164}
165
166// rustdoc-stripper-ignore-next
167/// Transform a generic FnOnce into a closure that can be used as callback in various glib methods
168///
169/// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break`
170/// in order to prevent being called twice.
171#[inline(always)]
172fn fnmut_callback_wrapper(
173    func: impl FnOnce() + Send + 'static,
174) -> impl FnMut() -> ControlFlow + Send + 'static {
175    let mut func = Some(func);
176    move || {
177        let func = func
178            .take()
179            .expect("GSource closure called after returning ControlFlow::Break");
180        func();
181        ControlFlow::Break
182    }
183}
184
185// rustdoc-stripper-ignore-next
186/// Transform a generic FnOnce into a closure that can be used as callback in various glib methods
187///
188/// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break`
189/// in order to prevent being called twice.
190///
191/// Different to `fnmut_callback_wrapper()`, this does not require `func` to be
192/// `Send` but can only be called from the thread that owns the main context.
193#[inline(always)]
194fn fnmut_callback_wrapper_local(
195    func: impl FnOnce() + 'static,
196) -> impl FnMut() -> ControlFlow + 'static {
197    let mut func = Some(func);
198    move || {
199        let func = func
200            .take()
201            .expect("GSource closure called after returning glib::ControlFlow::Break");
202        func();
203        ControlFlow::Break
204    }
205}
206
207// rustdoc-stripper-ignore-next
208/// Adds a closure to be called by the default main loop when it's idle.
209///
210/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
211///
212/// The default main loop almost always is the main loop of the main thread.
213/// Thus, the closure is called on the main thread.
214#[doc(alias = "g_idle_add_full")]
215pub fn idle_add<F>(func: F) -> SourceId
216where
217    F: FnMut() -> ControlFlow + Send + 'static,
218{
219    unsafe {
220        from_glib(ffi::g_idle_add_full(
221            ffi::G_PRIORITY_DEFAULT_IDLE,
222            Some(trampoline::<F>),
223            into_raw(func),
224            Some(destroy_closure::<F>),
225        ))
226    }
227}
228
229// rustdoc-stripper-ignore-next
230/// Adds a closure to be called by the default main loop when it's idle.
231///
232/// `func` will be called repeatedly with `priority` until it returns
233/// `ControlFlow::Break`.
234///
235/// The default main loop almost always is the main loop of the main thread.
236/// Thus, the closure is called on the main thread.
237#[doc(alias = "g_idle_add_full")]
238pub fn idle_add_full<F>(priority: Priority, func: F) -> SourceId
239where
240    F: FnMut() -> ControlFlow + Send + 'static,
241{
242    unsafe {
243        from_glib(ffi::g_idle_add_full(
244            priority.into_glib(),
245            Some(trampoline::<F>),
246            into_raw(func),
247            Some(destroy_closure::<F>),
248        ))
249    }
250}
251
252// rustdoc-stripper-ignore-next
253/// Adds a closure to be called by the default main loop when it's idle.
254///
255/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
256///
257/// The default main loop almost always is the main loop of the main thread.
258/// Thus, the closure is called on the main thread.
259///
260/// In comparison to `idle_add()`, this only requires `func` to be
261/// `FnOnce`, and will automatically return `ControlFlow::Break`.
262#[doc(alias = "g_idle_add_full")]
263#[doc(alias = "g_idle_add_once")]
264pub fn idle_add_once<F>(func: F) -> SourceId
265where
266    F: FnOnce() + Send + 'static,
267{
268    idle_add(fnmut_callback_wrapper(func))
269}
270
271// rustdoc-stripper-ignore-next
272/// Adds a closure to be called by the default main loop when it's idle.
273///
274/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
275///
276/// The default main loop almost always is the main loop of the main thread.
277/// Thus, the closure is called on the main thread.
278///
279/// Different to `idle_add()`, this does not require `func` to be
280/// `Send` but can only be called from the thread that owns the main context.
281///
282/// This function panics if called from a different thread than the one that
283/// owns the default main context.
284#[doc(alias = "g_idle_add_full")]
285pub fn idle_add_local<F>(func: F) -> SourceId
286where
287    F: FnMut() -> ControlFlow + 'static,
288{
289    unsafe {
290        let context = MainContext::default();
291        let _acquire = context
292            .acquire()
293            .expect("default main context already acquired by another thread");
294        from_glib(ffi::g_idle_add_full(
295            ffi::G_PRIORITY_DEFAULT_IDLE,
296            Some(trampoline_local::<F>),
297            into_raw_local(func),
298            Some(destroy_closure_local::<F>),
299        ))
300    }
301}
302
303// rustdoc-stripper-ignore-next
304/// Adds a closure to be called by the default main loop when it's idle.
305///
306/// `func` will be called repeatedly with `priority` until it returns
307/// `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/// Different to `idle_add()`, this does not require `func` to be
313/// `Send` but can only be called from the thread that owns the main context.
314///
315/// This function panics if called from a different thread than the one that
316/// owns the default main context.
317#[doc(alias = "g_idle_add_full")]
318pub fn idle_add_local_full<F>(priority: Priority, func: F) -> SourceId
319where
320    F: FnMut() -> ControlFlow + 'static,
321{
322    unsafe {
323        let context = MainContext::default();
324        let _acquire = context
325            .acquire()
326            .expect("default main context already acquired by another thread");
327        from_glib(ffi::g_idle_add_full(
328            priority.into_glib(),
329            Some(trampoline_local::<F>),
330            into_raw_local(func),
331            Some(destroy_closure_local::<F>),
332        ))
333    }
334}
335
336// rustdoc-stripper-ignore-next
337/// Adds a closure to be called by the default main loop when it's idle.
338///
339/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
340///
341/// The default main loop almost always is the main loop of the main thread.
342/// Thus, the closure is called on the main thread.
343///
344/// Different to `idle_add()`, this does not require `func` to be
345/// `Send` but can only be called from the thread that owns the main context.
346///
347/// This function panics if called from a different thread than the one that
348/// owns the main context.
349///
350/// In comparison to `idle_add_local()`, this only requires `func` to be
351/// `FnOnce`, and will automatically return `ControlFlow::Break`.
352#[doc(alias = "g_idle_add_full")]
353pub fn idle_add_local_once<F>(func: F) -> SourceId
354where
355    F: FnOnce() + 'static,
356{
357    idle_add_local(fnmut_callback_wrapper_local(func))
358}
359
360// rustdoc-stripper-ignore-next
361/// Adds a closure to be called by the default main loop at regular intervals
362/// with millisecond granularity.
363///
364/// `func` will be called repeatedly every `interval` milliseconds until it
365/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
366/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
367/// precision is not necessary.
368///
369/// The default main loop almost always is the main loop of the main thread.
370/// Thus, the closure is called on the main thread.
371#[doc(alias = "g_timeout_add_full")]
372pub fn timeout_add<F>(interval: Duration, func: F) -> SourceId
373where
374    F: FnMut() -> ControlFlow + Send + 'static,
375{
376    unsafe {
377        from_glib(ffi::g_timeout_add_full(
378            ffi::G_PRIORITY_DEFAULT,
379            interval.as_millis() as _,
380            Some(trampoline::<F>),
381            into_raw(func),
382            Some(destroy_closure::<F>),
383        ))
384    }
385}
386
387// rustdoc-stripper-ignore-next
388/// Adds a closure to be called by the default main loop at regular intervals
389/// with millisecond granularity.
390///
391/// `func` will be called repeatedly every `interval` milliseconds with `priority`
392/// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the
393/// timeout may be delayed by other events. Prefer `timeout_add_seconds` when
394/// millisecond precision is not necessary.
395///
396/// The default main loop almost always is the main loop of the main thread.
397/// Thus, the closure is called on the main thread.
398#[doc(alias = "g_timeout_add_full")]
399pub fn timeout_add_full<F>(interval: Duration, priority: Priority, func: F) -> SourceId
400where
401    F: FnMut() -> ControlFlow + Send + 'static,
402{
403    unsafe {
404        from_glib(ffi::g_timeout_add_full(
405            priority.into_glib(),
406            interval.as_millis() as _,
407            Some(trampoline::<F>),
408            into_raw(func),
409            Some(destroy_closure::<F>),
410        ))
411    }
412}
413
414// rustdoc-stripper-ignore-next
415/// Adds a closure to be called by the default main loop at regular intervals
416/// with millisecond granularity.
417///
418/// `func` will be called repeatedly every `interval` milliseconds until it
419/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
420/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
421/// precision is not necessary.
422///
423/// The default main loop almost always is the main loop of the main thread.
424/// Thus, the closure is called on the main thread.
425///
426/// In comparison to `timeout_add()`, this only requires `func` to be
427/// `FnOnce`, and will automatically return `ControlFlow::Break`.
428#[doc(alias = "g_timeout_add_full")]
429#[doc(alias = "g_timeout_add_once")]
430pub fn timeout_add_once<F>(interval: Duration, func: F) -> SourceId
431where
432    F: FnOnce() + Send + 'static,
433{
434    timeout_add(interval, fnmut_callback_wrapper(func))
435}
436
437// rustdoc-stripper-ignore-next
438/// Adds a closure to be called by the default main loop at regular intervals
439/// with millisecond granularity.
440///
441/// `func` will be called repeatedly every `interval` milliseconds until it
442/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
443/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
444/// precision is not necessary.
445///
446/// The default main loop almost always is the main loop of the main thread.
447/// Thus, the closure is called on the main thread.
448///
449/// Different to `timeout_add()`, this does not require `func` to be
450/// `Send` but can only be called from the thread that owns the main context.
451///
452/// This function panics if called from a different thread than the one that
453/// owns the main context.
454#[doc(alias = "g_timeout_add_full")]
455pub fn timeout_add_local<F>(interval: Duration, func: F) -> SourceId
456where
457    F: FnMut() -> ControlFlow + 'static,
458{
459    unsafe {
460        let context = MainContext::default();
461        let _acquire = context
462            .acquire()
463            .expect("default main context already acquired by another thread");
464        from_glib(ffi::g_timeout_add_full(
465            ffi::G_PRIORITY_DEFAULT,
466            interval.as_millis() as _,
467            Some(trampoline_local::<F>),
468            into_raw_local(func),
469            Some(destroy_closure_local::<F>),
470        ))
471    }
472}
473
474// rustdoc-stripper-ignore-next
475/// Adds a closure to be called by the default main loop at regular intervals
476/// with millisecond granularity.
477///
478/// `func` will be called repeatedly every `interval` milliseconds with `priority`
479/// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the
480/// timeout may be delayed by other events. Prefer `timeout_add_seconds` when
481/// millisecond precision is not necessary.
482///
483/// The default main loop almost always is the main loop of the main thread.
484/// Thus, the closure is called on the main thread.
485///
486/// Different to `timeout_add()`, this does not require `func` to be
487/// `Send` but can only be called from the thread that owns the main context.
488///
489/// This function panics if called from a different thread than the one that
490/// owns the main context.
491#[doc(alias = "g_timeout_add_full")]
492pub fn timeout_add_local_full<F>(interval: Duration, priority: Priority, func: F) -> SourceId
493where
494    F: FnMut() -> ControlFlow + 'static,
495{
496    unsafe {
497        let context = MainContext::default();
498        let _acquire = context
499            .acquire()
500            .expect("default main context already acquired by another thread");
501        from_glib(ffi::g_timeout_add_full(
502            priority.into_glib(),
503            interval.as_millis() as _,
504            Some(trampoline_local::<F>),
505            into_raw_local(func),
506            Some(destroy_closure_local::<F>),
507        ))
508    }
509}
510
511// rustdoc-stripper-ignore-next
512/// Adds a closure to be called by the default main loop at regular intervals
513/// with millisecond granularity.
514///
515/// `func` will be called repeatedly every `interval` milliseconds until it
516/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
517/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
518/// precision is not necessary.
519///
520/// The default main loop almost always is the main loop of the main thread.
521/// Thus, the closure is called on the main thread.
522///
523/// Different to `timeout_add()`, this does not require `func` to be
524/// `Send` but can only be called from the thread that owns the main context.
525///
526/// This function panics if called from a different thread than the one that
527/// owns the main context.
528///
529/// In comparison to `timeout_add_local()`, this only requires `func` to be
530/// `FnOnce`, and will automatically return `ControlFlow::Break`.
531#[doc(alias = "g_timeout_add_full")]
532pub fn timeout_add_local_once<F>(interval: Duration, func: F) -> SourceId
533where
534    F: FnOnce() + 'static,
535{
536    timeout_add_local(interval, fnmut_callback_wrapper_local(func))
537}
538
539// rustdoc-stripper-ignore-next
540/// Adds a closure to be called by the default main loop at regular intervals
541/// with second granularity.
542///
543/// `func` will be called repeatedly every `interval` seconds until it
544/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
545/// be delayed by other events.
546///
547/// The default main loop almost always is the main loop of the main thread.
548/// Thus, the closure is called on the main thread.
549#[doc(alias = "g_timeout_add_seconds_full")]
550pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
551where
552    F: FnMut() -> ControlFlow + Send + 'static,
553{
554    unsafe {
555        from_glib(ffi::g_timeout_add_seconds_full(
556            ffi::G_PRIORITY_DEFAULT,
557            interval,
558            Some(trampoline::<F>),
559            into_raw(func),
560            Some(destroy_closure::<F>),
561        ))
562    }
563}
564
565// rustdoc-stripper-ignore-next
566/// Adds a closure to be called by the default main loop at regular intervals
567/// with second granularity.
568///
569/// `func` will be called repeatedly every `interval` seconds until it
570/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
571/// be delayed by other events.
572///
573/// The default main loop almost always is the main loop of the main thread.
574/// Thus, the closure is called on the main thread.
575///
576/// In comparison to `timeout_add_seconds()`, this only requires `func` to be
577/// `FnOnce`, and will automatically return `ControlFlow::Break`.
578#[doc(alias = "g_timeout_add_seconds_full")]
579pub fn timeout_add_seconds_once<F>(interval: u32, func: F) -> SourceId
580where
581    F: FnOnce() + Send + 'static,
582{
583    timeout_add_seconds(interval, fnmut_callback_wrapper(func))
584}
585
586// rustdoc-stripper-ignore-next
587/// Adds a closure to be called by the default main loop at regular intervals
588/// with second granularity.
589///
590/// `func` will be called repeatedly every `interval` seconds until it
591/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
592/// be delayed by other events.
593///
594/// The default main loop almost always is the main loop of the main thread.
595/// Thus, the closure is called on the main thread.
596///
597/// Different to `timeout_add_seconds()`, this does not require `func` to be
598/// `Send` but can only be called from the thread that owns the main context.
599///
600/// This function panics if called from a different thread than the one that
601/// owns the main context.
602#[doc(alias = "g_timeout_add_seconds_full")]
603pub fn timeout_add_seconds_local<F>(interval: u32, func: F) -> SourceId
604where
605    F: FnMut() -> ControlFlow + 'static,
606{
607    unsafe {
608        let context = MainContext::default();
609        let _acquire = context
610            .acquire()
611            .expect("default main context already acquired by another thread");
612        from_glib(ffi::g_timeout_add_seconds_full(
613            ffi::G_PRIORITY_DEFAULT,
614            interval,
615            Some(trampoline_local::<F>),
616            into_raw_local(func),
617            Some(destroy_closure_local::<F>),
618        ))
619    }
620}
621
622// rustdoc-stripper-ignore-next
623/// Adds a closure to be called by the default main loop at regular intervals
624/// with second granularity.
625///
626/// `func` will be called repeatedly every `interval` seconds until it
627/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
628/// be delayed by other events.
629///
630/// The default main loop almost always is the main loop of the main thread.
631/// Thus, the closure is called on the main thread.
632///
633/// Different to `timeout_add_seconds()`, this does not require `func` to be
634/// `Send` but can only be called from the thread that owns the main context.
635///
636/// This function panics if called from a different thread than the one that
637/// owns the main context.
638///
639/// In comparison to `timeout_add_seconds_local()`, this only requires `func` to be
640/// `FnOnce`, and will automatically return `ControlFlow::Break`.
641#[doc(alias = "g_timeout_add_seconds_full")]
642pub fn timeout_add_seconds_local_once<F>(interval: u32, func: F) -> SourceId
643where
644    F: FnOnce() + 'static,
645{
646    timeout_add_seconds_local(interval, fnmut_callback_wrapper_local(func))
647}
648
649// rustdoc-stripper-ignore-next
650/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
651/// process exits.
652///
653/// `func` will be called when `pid` exits
654#[doc(alias = "g_child_watch_add_full")]
655pub fn child_watch_add<F>(pid: Pid, func: F) -> SourceId
656where
657    F: FnMut(Pid, i32) + Send + 'static,
658{
659    unsafe {
660        from_glib(ffi::g_child_watch_add_full(
661            ffi::G_PRIORITY_DEFAULT,
662            pid.0,
663            Some(trampoline_child_watch::<F>),
664            into_raw_child_watch(func),
665            Some(destroy_closure_child_watch::<F>),
666        ))
667    }
668}
669
670// rustdoc-stripper-ignore-next
671/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
672/// process exits.
673///
674/// `func` will be called when `pid` exits
675///
676/// Different to `child_watch_add()`, this does not require `func` to be
677/// `Send` but can only be called from the thread that owns the main context.
678///
679/// This function panics if called from a different thread than the one that
680/// owns the main context.
681#[doc(alias = "g_child_watch_add_full")]
682pub fn child_watch_add_local<F>(pid: Pid, func: F) -> SourceId
683where
684    F: FnMut(Pid, i32) + 'static,
685{
686    unsafe {
687        let context = MainContext::default();
688        let _acquire = context
689            .acquire()
690            .expect("default main context already acquired by another thread");
691        from_glib(ffi::g_child_watch_add_full(
692            ffi::G_PRIORITY_DEFAULT,
693            pid.0,
694            Some(trampoline_child_watch_local::<F>),
695            into_raw_child_watch_local(func),
696            Some(destroy_closure_child_watch_local::<F>),
697        ))
698    }
699}
700
701// rustdoc-stripper-ignore-next
702/// The priority of sources
703#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
704pub struct Priority(i32);
705
706impl Priority {
707    #[doc(alias = "G_PRIORITY_HIGH")]
708    pub const HIGH: Self = Self(ffi::G_PRIORITY_HIGH);
709    #[doc(alias = "G_PRIORITY_DEFAULT")]
710    pub const DEFAULT: Self = Self(ffi::G_PRIORITY_DEFAULT);
711    #[doc(alias = "G_PRIORITY_HIGH_IDLE")]
712    pub const HIGH_IDLE: Self = Self(ffi::G_PRIORITY_HIGH_IDLE);
713    #[doc(alias = "G_PRIORITY_DEFAULT_IDLE")]
714    pub const DEFAULT_IDLE: Self = Self(ffi::G_PRIORITY_DEFAULT_IDLE);
715    #[doc(alias = "G_PRIORITY_LOW")]
716    pub const LOW: Self = Self(ffi::G_PRIORITY_LOW);
717}
718
719impl Default for Priority {
720    fn default() -> Self {
721        Self::DEFAULT
722    }
723}
724
725#[doc(hidden)]
726impl IntoGlib for Priority {
727    type GlibType = i32;
728
729    #[inline]
730    fn into_glib(self) -> i32 {
731        self.0
732    }
733}
734
735#[doc(hidden)]
736impl FromGlib<i32> for Priority {
737    #[inline]
738    unsafe fn from_glib(val: i32) -> Self {
739        Self::from(val)
740    }
741}
742
743impl From<i32> for Priority {
744    fn from(value: i32) -> Self {
745        Self(value)
746    }
747}
748
749// rustdoc-stripper-ignore-next
750/// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle.
751///
752/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
753#[doc(alias = "g_idle_source_new")]
754pub fn idle_source_new<F>(name: Option<&str>, priority: Priority, func: F) -> Source
755where
756    F: FnMut() -> ControlFlow + Send + 'static,
757{
758    unsafe {
759        let source = ffi::g_idle_source_new();
760        ffi::g_source_set_callback(
761            source,
762            Some(trampoline::<F>),
763            into_raw(func),
764            Some(destroy_closure::<F>),
765        );
766        ffi::g_source_set_priority(source, priority.into_glib());
767
768        if let Some(name) = name {
769            ffi::g_source_set_name(source, name.to_glib_none().0);
770        }
771
772        from_glib_full(source)
773    }
774}
775
776// rustdoc-stripper-ignore-next
777/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
778/// intervals with millisecond granularity.
779///
780/// `func` will be called repeatedly every `interval` milliseconds until it
781/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
782/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
783/// precision is not necessary.
784#[doc(alias = "g_timeout_source_new")]
785pub fn timeout_source_new<F>(
786    interval: Duration,
787    name: Option<&str>,
788    priority: Priority,
789    func: F,
790) -> Source
791where
792    F: FnMut() -> ControlFlow + Send + 'static,
793{
794    unsafe {
795        let source = ffi::g_timeout_source_new(interval.as_millis() as _);
796        ffi::g_source_set_callback(
797            source,
798            Some(trampoline::<F>),
799            into_raw(func),
800            Some(destroy_closure::<F>),
801        );
802        ffi::g_source_set_priority(source, priority.into_glib());
803
804        if let Some(name) = name {
805            ffi::g_source_set_name(source, name.to_glib_none().0);
806        }
807
808        from_glib_full(source)
809    }
810}
811
812// rustdoc-stripper-ignore-next
813/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
814/// intervals with second granularity.
815///
816/// `func` will be called repeatedly every `interval` seconds until it
817/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
818/// be delayed by other events.
819#[doc(alias = "g_timeout_source_new_seconds")]
820pub fn timeout_source_new_seconds<F>(
821    interval: u32,
822    name: Option<&str>,
823    priority: Priority,
824    func: F,
825) -> Source
826where
827    F: FnMut() -> ControlFlow + Send + 'static,
828{
829    unsafe {
830        let source = ffi::g_timeout_source_new_seconds(interval);
831        ffi::g_source_set_callback(
832            source,
833            Some(trampoline::<F>),
834            into_raw(func),
835            Some(destroy_closure::<F>),
836        );
837        ffi::g_source_set_priority(source, priority.into_glib());
838
839        if let Some(name) = name {
840            ffi::g_source_set_name(source, name.to_glib_none().0);
841        }
842
843        from_glib_full(source)
844    }
845}
846
847// rustdoc-stripper-ignore-next
848/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
849/// process exits.
850///
851/// `func` will be called when `pid` exits
852#[doc(alias = "g_child_watch_source_new")]
853pub fn child_watch_source_new<F>(
854    pid: Pid,
855    name: Option<&str>,
856    priority: Priority,
857    func: F,
858) -> Source
859where
860    F: FnMut(Pid, i32) + Send + 'static,
861{
862    unsafe {
863        let source = ffi::g_child_watch_source_new(pid.0);
864        ffi::g_source_set_callback(
865            source,
866            Some(transmute::<
867                *mut (),
868                unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
869            >(trampoline_child_watch::<F> as *mut ())),
870            into_raw_child_watch(func),
871            Some(destroy_closure_child_watch::<F>),
872        );
873        ffi::g_source_set_priority(source, priority.into_glib());
874
875        if let Some(name) = name {
876            ffi::g_source_set_name(source, name.to_glib_none().0);
877        }
878
879        from_glib_full(source)
880    }
881}
882
883impl Source {
884    #[doc(alias = "g_source_attach")]
885    pub fn attach(&self, context: Option<&MainContext>) -> SourceId {
886        unsafe {
887            from_glib(ffi::g_source_attach(
888                self.to_glib_none().0,
889                context.to_glib_none().0,
890            ))
891        }
892    }
893
894    /// Gets the [`MainContext`][crate::MainContext] with which the source is associated.
895    ///
896    /// You can call this on a source that has been destroyed, provided
897    /// that the [`MainContext`][crate::MainContext] it was attached to still exists (in which
898    /// case it will return that [`MainContext`][crate::MainContext]). In particular, you can
899    /// always call this function on the source returned from
900    /// [`main_current_source()`][crate::main_current_source()]. But calling this function on a source
901    /// whose [`MainContext`][crate::MainContext] has been destroyed is an error.
902    ///
903    /// If the associated [`MainContext`][crate::MainContext] could be destroy concurrently from
904    /// a different thread, then this function is not safe to call and
905    /// [`dup_context()`][Self::dup_context()] should be used instead.
906    ///
907    /// # Returns
908    ///
909    /// the main context with which the
910    ///   source is associated, or `NULL` if the context has not yet been added to a
911    ///   source
912    #[doc(alias = "g_source_get_context")]
913    #[doc(alias = "get_context")]
914    #[doc(alias = "g_source_dup_context")]
915    pub fn context(&self) -> Option<MainContext> {
916        #[cfg(feature = "v2_86")]
917        unsafe {
918            from_glib_full(ffi::g_source_dup_context(self.to_glib_none().0))
919        }
920        #[cfg(not(feature = "v2_86"))]
921        unsafe {
922            from_glib_none(ffi::g_source_get_context(self.to_glib_none().0))
923        }
924    }
925}