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