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