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 ffi::{self, gboolean, gpointer};
8#[cfg(all(not(unix), docsrs))]
9use libc::c_int as RawFd;
10
11#[cfg(any(unix, docsrs))]
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_gbooleanResult<(), BoolError>!(
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 identificator
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(any(unix, docsrs))]
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(val:condition)).into_glib()
165}
166
167#[cfg(any(unix, docsrs))]
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(val:condition)).into_glib()
178}
179
180#[cfg(any(unix, docsrs))]
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(any(unix, docsrs))]
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(any(unix, docsrs))]
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(any(unix, docsrs))]
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: Option = Some(func);
228 move || {
229 let func: impl FnOnce() + Send = func
230 .take()
231 .expect(msg:"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: Option = Some(func);
250 move || {
251 let func: impl FnOnce() = func
252 .take()
253 .expect(msg:"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(val:ffi::g_idle_add_full(
273 priority:ffi::G_PRIORITY_DEFAULT_IDLE,
274 function:Some(trampoline::<F>),
275 data:into_raw(func),
276 notify: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(val:ffi::g_idle_add_full(
296 priority:priority.into_glib(),
297 function:Some(trampoline::<F>),
298 data:into_raw(func),
299 notify: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(func: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 = MainContext::default();
343 let _acquire: MainContextAcquireGuard<'_> = context
344 .acquire()
345 .expect(msg:"default main context already acquired by another thread");
346 from_glib(val:ffi::g_idle_add_full(
347 priority:ffi::G_PRIORITY_DEFAULT_IDLE,
348 function:Some(trampoline_local::<F>),
349 data:into_raw_local(func),
350 notify: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 = MainContext::default();
376 let _acquire: MainContextAcquireGuard<'_> = context
377 .acquire()
378 .expect(msg:"default main context already acquired by another thread");
379 from_glib(val:ffi::g_idle_add_full(
380 priority:priority.into_glib(),
381 function:Some(trampoline_local::<F>),
382 data:into_raw_local(func),
383 notify: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(func: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(val:ffi::g_timeout_add_full(
430 priority:ffi::G_PRIORITY_DEFAULT,
431 interval:interval.as_millis() as _,
432 function:Some(trampoline::<F>),
433 data:into_raw(func),
434 notify: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(val:ffi::g_timeout_add_full(
457 priority:priority.into_glib(),
458 interval:interval.as_millis() as _,
459 function:Some(trampoline::<F>),
460 data:into_raw(func),
461 notify: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, func: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 = MainContext::default();
513 let _acquire: MainContextAcquireGuard<'_> = context
514 .acquire()
515 .expect(msg:"default main context already acquired by another thread");
516 from_glib(val:ffi::g_timeout_add_full(
517 priority:ffi::G_PRIORITY_DEFAULT,
518 interval:interval.as_millis() as _,
519 function:Some(trampoline_local::<F>),
520 data:into_raw_local(func),
521 notify: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 = MainContext::default();
550 let _acquire: MainContextAcquireGuard<'_> = context
551 .acquire()
552 .expect(msg:"default main context already acquired by another thread");
553 from_glib(val:ffi::g_timeout_add_full(
554 priority:priority.into_glib(),
555 interval:interval.as_millis() as _,
556 function:Some(trampoline_local::<F>),
557 data:into_raw_local(func),
558 notify: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, func: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(val:ffi::g_timeout_add_seconds_full(
608 priority:ffi::G_PRIORITY_DEFAULT,
609 interval,
610 function:Some(trampoline::<F>),
611 data:into_raw(func),
612 notify: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, func: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 = MainContext::default();
661 let _acquire: MainContextAcquireGuard<'_> = context
662 .acquire()
663 .expect(msg:"default main context already acquired by another thread");
664 from_glib(val:ffi::g_timeout_add_seconds_full(
665 priority:ffi::G_PRIORITY_DEFAULT,
666 interval,
667 function:Some(trampoline_local::<F>),
668 data:into_raw_local(func),
669 notify: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, func: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(val:ffi::g_child_watch_add_full(
713 priority:ffi::G_PRIORITY_DEFAULT,
714 pid:pid.0,
715 function:Some(trampoline_child_watch::<F>),
716 data:into_raw_child_watch(func),
717 notify: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 = MainContext::default();
740 let _acquire: MainContextAcquireGuard<'_> = context
741 .acquire()
742 .expect(msg:"default main context already acquired by another thread");
743 from_glib(val:ffi::g_child_watch_add_full(
744 priority:ffi::G_PRIORITY_DEFAULT,
745 pid:pid.0,
746 function:Some(trampoline_child_watch_local::<F>),
747 data:into_raw_child_watch_local(func),
748 notify:Some(destroy_closure_child_watch_local::<F>),
749 ))
750 }
751}
752
753#[cfg(any(unix, docsrs))]
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(val:ffi::g_unix_signal_add_full(
770 priority:ffi::G_PRIORITY_DEFAULT,
771 signum,
772 handler:Some(trampoline::<F>),
773 user_data:into_raw(func),
774 notify:Some(destroy_closure::<F>),
775 ))
776 }
777}
778
779#[cfg(any(unix, docsrs))]
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, func:fnmut_callback_wrapper(func))
798}
799
800#[cfg(any(unix, docsrs))]
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 = MainContext::default();
823 let _acquire: MainContextAcquireGuard<'_> = context
824 .acquire()
825 .expect(msg:"default main context already acquired by another thread");
826 from_glib(val:ffi::g_unix_signal_add_full(
827 priority:ffi::G_PRIORITY_DEFAULT,
828 signum,
829 handler:Some(trampoline_local::<F>),
830 user_data:into_raw_local(func),
831 notify:Some(destroy_closure_local::<F>),
832 ))
833 }
834}
835
836#[cfg(any(unix, docsrs))]
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, func:fnmut_callback_wrapper_local(func))
861}
862
863#[cfg(any(unix, docsrs))]
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(val:ffi::g_unix_fd_add_full(
881 priority:ffi::G_PRIORITY_DEFAULT,
882 fd,
883 condition:condition.into_glib(),
884 function:Some(trampoline_unix_fd::<F>),
885 user_data:into_raw_unix_fd(func),
886 notify:Some(destroy_closure_unix_fd::<F>),
887 ))
888 }
889}
890
891#[cfg(any(unix, docsrs))]
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 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///
903/// Different to `unix_fd_add()`, this does not require `func` to be
904/// `Send` but can only be called from the thread that owns the main context.
905///
906/// This function panics if called from a different thread than the one that
907/// owns the main context.
908#[doc(alias = "g_unix_fd_add_full")]
909pub fn unix_fd_add_local<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
910where
911 F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static,
912{
913 unsafe {
914 let context: MainContext = MainContext::default();
915 let _acquire: MainContextAcquireGuard<'_> = context
916 .acquire()
917 .expect(msg:"default main context already acquired by another thread");
918 from_glib(val:ffi::g_unix_fd_add_full(
919 priority:ffi::G_PRIORITY_DEFAULT,
920 fd,
921 condition:condition.into_glib(),
922 function:Some(trampoline_unix_fd_local::<F>),
923 user_data:into_raw_unix_fd_local(func),
924 notify:Some(destroy_closure_unix_fd_local::<F>),
925 ))
926 }
927}
928
929// rustdoc-stripper-ignore-next
930/// The priority of sources
931#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
932pub struct Priority(i32);
933
934impl Priority {
935 #[doc(alias = "G_PRIORITY_HIGH")]
936 pub const HIGH: Self = Self(ffi::G_PRIORITY_HIGH);
937 #[doc(alias = "G_PRIORITY_DEFAULT")]
938 pub const DEFAULT: Self = Self(ffi::G_PRIORITY_DEFAULT);
939 #[doc(alias = "G_PRIORITY_HIGH_IDLE")]
940 pub const HIGH_IDLE: Self = Self(ffi::G_PRIORITY_HIGH_IDLE);
941 #[doc(alias = "G_PRIORITY_DEFAULT_IDLE")]
942 pub const DEFAULT_IDLE: Self = Self(ffi::G_PRIORITY_DEFAULT_IDLE);
943 #[doc(alias = "G_PRIORITY_LOW")]
944 pub const LOW: Self = Self(ffi::G_PRIORITY_LOW);
945}
946
947impl Default for Priority {
948 fn default() -> Self {
949 Self::DEFAULT
950 }
951}
952
953#[doc(hidden)]
954impl IntoGlib for Priority {
955 type GlibType = i32;
956
957 #[inline]
958 fn into_glib(self) -> i32 {
959 self.0
960 }
961}
962
963#[doc(hidden)]
964impl FromGlib<i32> for Priority {
965 #[inline]
966 unsafe fn from_glib(val: i32) -> Self {
967 Self::from(val)
968 }
969}
970
971impl From<i32> for Priority {
972 fn from(value: i32) -> Self {
973 Self(value)
974 }
975}
976
977// rustdoc-stripper-ignore-next
978/// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle.
979///
980/// `func` will be called repeatedly until it returns `ControlFlow::Break`.
981#[doc(alias = "g_idle_source_new")]
982pub fn idle_source_new<F>(name: Option<&str>, priority: Priority, func: F) -> Source
983where
984 F: FnMut() -> ControlFlow + Send + 'static,
985{
986 unsafe {
987 let source: *mut GSource = ffi::g_idle_source_new();
988 ffi::g_source_set_callback(
989 source,
990 func:Some(trampoline::<F>),
991 data:into_raw(func),
992 notify:Some(destroy_closure::<F>),
993 );
994 ffi::g_source_set_priority(source, priority:priority.into_glib());
995
996 if let Some(name: &str) = name {
997 ffi::g_source_set_name(source, name:name.to_glib_none().0);
998 }
999
1000 from_glib_full(ptr:source)
1001 }
1002}
1003
1004// rustdoc-stripper-ignore-next
1005/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
1006/// intervals with millisecond granularity.
1007///
1008/// `func` will be called repeatedly every `interval` milliseconds until it
1009/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
1010/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
1011/// precision is not necessary.
1012#[doc(alias = "g_timeout_source_new")]
1013pub fn timeout_source_new<F>(
1014 interval: Duration,
1015 name: Option<&str>,
1016 priority: Priority,
1017 func: F,
1018) -> Source
1019where
1020 F: FnMut() -> ControlFlow + Send + 'static,
1021{
1022 unsafe {
1023 let source: *mut GSource = ffi::g_timeout_source_new(interval:interval.as_millis() as _);
1024 ffi::g_source_set_callback(
1025 source,
1026 func:Some(trampoline::<F>),
1027 data:into_raw(func),
1028 notify:Some(destroy_closure::<F>),
1029 );
1030 ffi::g_source_set_priority(source, priority:priority.into_glib());
1031
1032 if let Some(name: &str) = name {
1033 ffi::g_source_set_name(source, name:name.to_glib_none().0);
1034 }
1035
1036 from_glib_full(ptr:source)
1037 }
1038}
1039
1040// rustdoc-stripper-ignore-next
1041/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
1042/// intervals with second granularity.
1043///
1044/// `func` will be called repeatedly every `interval` seconds until it
1045/// returns `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may
1046/// be delayed by other events.
1047#[doc(alias = "g_timeout_source_new_seconds")]
1048pub fn timeout_source_new_seconds<F>(
1049 interval: u32,
1050 name: Option<&str>,
1051 priority: Priority,
1052 func: F,
1053) -> Source
1054where
1055 F: FnMut() -> ControlFlow + Send + 'static,
1056{
1057 unsafe {
1058 let source: *mut GSource = ffi::g_timeout_source_new_seconds(interval);
1059 ffi::g_source_set_callback(
1060 source,
1061 func:Some(trampoline::<F>),
1062 data:into_raw(func),
1063 notify:Some(destroy_closure::<F>),
1064 );
1065 ffi::g_source_set_priority(source, priority:priority.into_glib());
1066
1067 if let Some(name: &str) = name {
1068 ffi::g_source_set_name(source, name:name.to_glib_none().0);
1069 }
1070
1071 from_glib_full(ptr:source)
1072 }
1073}
1074
1075// rustdoc-stripper-ignore-next
1076/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
1077/// process exits.
1078///
1079/// `func` will be called when `pid` exits
1080#[doc(alias = "g_child_watch_source_new")]
1081pub fn child_watch_source_new<F>(
1082 pid: Pid,
1083 name: Option<&str>,
1084 priority: Priority,
1085 func: F,
1086) -> Source
1087where
1088 F: FnMut(Pid, i32) + Send + 'static,
1089{
1090 unsafe {
1091 let source: *mut GSource = ffi::g_child_watch_source_new(pid:pid.0);
1092 ffi::g_source_set_callback(
1093 source,
1094 func:Some(transmute::<
1095 _,
1096 unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
1097 >(trampoline_child_watch::<F> as *const ())),
1098 data:into_raw_child_watch(func),
1099 notify:Some(destroy_closure_child_watch::<F>),
1100 );
1101 ffi::g_source_set_priority(source, priority:priority.into_glib());
1102
1103 if let Some(name: &str) = name {
1104 ffi::g_source_set_name(source, name:name.to_glib_none().0);
1105 }
1106
1107 from_glib_full(ptr:source)
1108 }
1109}
1110
1111#[cfg(any(unix, docsrs))]
1112#[cfg_attr(docsrs, doc(cfg(unix)))]
1113// rustdoc-stripper-ignore-next
1114/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
1115/// UNIX signal is raised.
1116///
1117/// `func` will be called repeatedly every time `signum` is raised until it
1118/// returns `ControlFlow::Break`.
1119#[doc(alias = "g_unix_signal_source_new")]
1120pub fn unix_signal_source_new<F>(
1121 signum: i32,
1122 name: Option<&str>,
1123 priority: Priority,
1124 func: F,
1125) -> Source
1126where
1127 F: FnMut() -> ControlFlow + Send + 'static,
1128{
1129 unsafe {
1130 let source: *mut GSource = ffi::g_unix_signal_source_new(signum);
1131 ffi::g_source_set_callback(
1132 source,
1133 func:Some(trampoline::<F>),
1134 data:into_raw(func),
1135 notify:Some(destroy_closure::<F>),
1136 );
1137 ffi::g_source_set_priority(source, priority:priority.into_glib());
1138
1139 if let Some(name: &str) = name {
1140 ffi::g_source_set_name(source, name:name.to_glib_none().0);
1141 }
1142
1143 from_glib_full(ptr:source)
1144 }
1145}
1146
1147#[cfg(any(unix, docsrs))]
1148#[cfg_attr(docsrs, doc(cfg(unix)))]
1149// rustdoc-stripper-ignore-next
1150/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
1151/// UNIX file descriptor reaches the given IO condition.
1152///
1153/// `func` will be called repeatedly while the file descriptor matches the given IO condition
1154/// until it returns `ControlFlow::Break`.
1155#[doc(alias = "g_unix_fd_source_new")]
1156pub fn unix_fd_source_new<F>(
1157 fd: RawFd,
1158 condition: IOCondition,
1159 name: Option<&str>,
1160 priority: Priority,
1161 func: F,
1162) -> Source
1163where
1164 F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static,
1165{
1166 unsafe {
1167 let source: *mut GSource = ffi::g_unix_fd_source_new(fd, condition:condition.into_glib());
1168 ffi::g_source_set_callback(
1169 source,
1170 func:Some(transmute::<
1171 _,
1172 unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
1173 >(trampoline_unix_fd::<F> as *const ())),
1174 data:into_raw_unix_fd(func),
1175 notify:Some(destroy_closure_unix_fd::<F>),
1176 );
1177 ffi::g_source_set_priority(source, priority:priority.into_glib());
1178
1179 if let Some(name: &str) = name {
1180 ffi::g_source_set_name(source, name:name.to_glib_none().0);
1181 }
1182
1183 from_glib_full(ptr:source)
1184 }
1185}
1186
1187impl Source {
1188 #[doc(alias = "g_source_attach")]
1189 pub fn attach(&self, context: Option<&MainContext>) -> SourceId {
1190 unsafe {
1191 from_glib(val:ffi::g_source_attach(
1192 self.to_glib_none().0,
1193 context:context.to_glib_none().0,
1194 ))
1195 }
1196 }
1197}
1198