1use glib_sys::{self, gboolean, gpointer};
6#[cfg(all(not(unix), feature = "dox"))]
7use libc::c_int as RawFd;
8use std::cell::RefCell;
9use std::mem::transmute;
10#[cfg(unix)]
11use std::os::unix::io::RawFd;
12use std::process;
13use std::thread;
14use translate::{from_glib, from_glib_full, FromGlib, ToGlib, ToGlibPtr};
15#[cfg(any(unix, feature = "dox"))]
16use IOCondition;
17
18use MainContext;
19use Source;
20
21#[derive(Debug, Eq, PartialEq)]
23pub struct SourceId(u32);
24
25#[doc(hidden)]
26impl ToGlib for SourceId {
27 type GlibType = u32;
28
29 #[inline]
30 fn to_glib(&self) -> u32 {
31 self.0
32 }
33}
34
35#[doc(hidden)]
36impl FromGlib<u32> for SourceId {
37 #[inline]
38 fn from_glib(val: u32) -> SourceId {
39 assert_ne!(val, 0);
40 SourceId(val)
41 }
42}
43
44#[derive(Copy, Clone, Debug, Eq, PartialEq)]
46pub struct Pid(pub glib_sys::GPid);
47
48unsafe impl Send for Pid {}
49unsafe impl Sync for Pid {}
50
51#[derive(Copy, Clone, Debug, PartialEq, Eq)]
59pub struct Continue(pub bool);
60
61#[doc(hidden)]
62impl ToGlib for Continue {
63 type GlibType = gboolean;
64
65 #[inline]
66 fn to_glib(&self) -> gboolean {
67 self.0.to_glib()
68 }
69}
70
71#[deprecated(note = "Rustc has this functionality built-in since 1.26.0")]
74pub struct CallbackGuard(());
75
76#[allow(deprecated)]
77impl CallbackGuard {
78 pub fn new() -> CallbackGuard {
79 CallbackGuard(())
80 }
81}
82
83#[allow(deprecated)]
84impl Default for CallbackGuard {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[allow(deprecated)]
91impl Drop for CallbackGuard {
92 fn drop(&mut self) {
93 use std::io::stderr;
94 use std::io::Write;
95
96 if thread::panicking() {
97 let _ = stderr().write(b"Uncaught panic, exiting\n");
98 process::abort();
99 }
100 }
101}
102
103unsafe extern "C" fn trampoline<F: FnMut() -> Continue + 'static>(func: gpointer) -> gboolean {
104 let func: &RefCell<F> = &*(func as *const RefCell<F>);
105 (&mut *func.borrow_mut())().to_glib()
106}
107
108unsafe extern "C" fn destroy_closure<F: FnMut() -> Continue + 'static>(ptr: gpointer) {
109 Box::<RefCell<F>>::from_raw(ptr as *mut _);
110}
111
112fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
113 let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
114 Box::into_raw(func) as gpointer
115}
116
117unsafe extern "C" fn trampoline_child_watch<F: FnMut(Pid, i32) + 'static>(
118 pid: glib_sys::GPid,
119 status: i32,
120 func: gpointer,
121) {
122 let func: &RefCell<F> = &*(func as *const RefCell<F>);
123 (&mut *func.borrow_mut())(Pid(pid), status)
124}
125
126unsafe extern "C" fn destroy_closure_child_watch<F: FnMut(Pid, i32) + 'static>(ptr: gpointer) {
127 Box::<RefCell<F>>::from_raw(ptr as *mut _);
128}
129
130fn into_raw_child_watch<F: FnMut(Pid, i32) + 'static>(func: F) -> gpointer {
131 let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
132 Box::into_raw(func) as gpointer
133}
134
135#[cfg(any(unix, feature = "dox"))]
136unsafe extern "C" fn trampoline_unix_fd<F: FnMut(RawFd, IOCondition) -> Continue + 'static>(
137 fd: i32,
138 condition: glib_sys::GIOCondition,
139 func: gpointer,
140) -> gboolean {
141 let func: &RefCell<F> = &*(func as *const RefCell<F>);
142 (&mut *func.borrow_mut())(fd, from_glib(condition)).to_glib()
143}
144
145#[cfg(any(unix, feature = "dox"))]
146unsafe extern "C" fn destroy_closure_unix_fd<F: FnMut(RawFd, IOCondition) -> Continue + 'static>(
147 ptr: gpointer,
148) {
149 Box::<RefCell<F>>::from_raw(ptr as *mut _);
150}
151
152#[cfg(any(unix, feature = "dox"))]
153fn into_raw_unix_fd<F: FnMut(RawFd, IOCondition) -> Continue + 'static>(func: F) -> gpointer {
154 let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
155 Box::into_raw(func) as gpointer
156}
157
158pub fn idle_add<F>(func: F) -> SourceId
165where
166 F: FnMut() -> Continue + Send + 'static,
167{
168 unsafe {
169 from_glib(glib_sys::g_idle_add_full(
170 glib_sys::G_PRIORITY_DEFAULT_IDLE,
171 Some(trampoline::<F>),
172 into_raw(func),
173 Some(destroy_closure::<F>),
174 ))
175 }
176}
177
178pub fn idle_add_local<F>(func: F) -> SourceId
191where
192 F: FnMut() -> Continue + 'static,
193{
194 unsafe {
195 assert!(MainContext::default().is_owner());
196 from_glib(glib_sys::g_idle_add_full(
197 glib_sys::G_PRIORITY_DEFAULT_IDLE,
198 Some(trampoline::<F>),
199 into_raw(func),
200 Some(destroy_closure::<F>),
201 ))
202 }
203}
204
205pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
216where
217 F: FnMut() -> Continue + Send + 'static,
218{
219 unsafe {
220 from_glib(glib_sys::g_timeout_add_full(
221 glib_sys::G_PRIORITY_DEFAULT,
222 interval,
223 Some(trampoline::<F>),
224 into_raw(func),
225 Some(destroy_closure::<F>),
226 ))
227 }
228}
229
230pub fn timeout_add_local<F>(interval: u32, func: F) -> SourceId
247where
248 F: FnMut() -> Continue + 'static,
249{
250 unsafe {
251 assert!(MainContext::default().is_owner());
252 from_glib(glib_sys::g_timeout_add_full(
253 glib_sys::G_PRIORITY_DEFAULT,
254 interval,
255 Some(trampoline::<F>),
256 into_raw(func),
257 Some(destroy_closure::<F>),
258 ))
259 }
260}
261
262pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
272where
273 F: FnMut() -> Continue + Send + 'static,
274{
275 unsafe {
276 from_glib(glib_sys::g_timeout_add_seconds_full(
277 glib_sys::G_PRIORITY_DEFAULT,
278 interval,
279 Some(trampoline::<F>),
280 into_raw(func),
281 Some(destroy_closure::<F>),
282 ))
283 }
284}
285
286pub fn timeout_add_seconds_local<F>(interval: u32, func: F) -> SourceId
302where
303 F: FnMut() -> Continue + 'static,
304{
305 unsafe {
306 assert!(MainContext::default().is_owner());
307 from_glib(glib_sys::g_timeout_add_seconds_full(
308 glib_sys::G_PRIORITY_DEFAULT,
309 interval,
310 Some(trampoline::<F>),
311 into_raw(func),
312 Some(destroy_closure::<F>),
313 ))
314 }
315}
316
317pub fn child_watch_add<F>(pid: Pid, func: F) -> SourceId
322where
323 F: FnMut(Pid, i32) + Send + 'static,
324{
325 unsafe {
326 from_glib(glib_sys::g_child_watch_add_full(
327 glib_sys::G_PRIORITY_DEFAULT,
328 pid.0,
329 Some(transmute(trampoline_child_watch::<F> as usize)),
330 into_raw_child_watch(func),
331 Some(destroy_closure_child_watch::<F>),
332 ))
333 }
334}
335
336pub fn child_watch_add_local<F>(pid: Pid, func: F) -> SourceId
347where
348 F: FnMut(Pid, i32) + 'static,
349{
350 unsafe {
351 assert!(MainContext::default().is_owner());
352 from_glib(glib_sys::g_child_watch_add_full(
353 glib_sys::G_PRIORITY_DEFAULT,
354 pid.0,
355 Some(transmute(trampoline_child_watch::<F> as usize)),
356 into_raw_child_watch(func),
357 Some(destroy_closure_child_watch::<F>),
358 ))
359 }
360}
361
362#[cfg(any(unix, feature = "dox"))]
363pub fn unix_signal_add<F>(signum: i32, func: F) -> SourceId
371where
372 F: FnMut() -> Continue + Send + 'static,
373{
374 unsafe {
375 from_glib(glib_sys::g_unix_signal_add_full(
376 glib_sys::G_PRIORITY_DEFAULT,
377 signum,
378 Some(trampoline::<F>),
379 into_raw(func),
380 Some(destroy_closure::<F>),
381 ))
382 }
383}
384
385#[cfg(any(unix, feature = "dox"))]
386pub fn unix_signal_add_local<F>(signum: i32, func: F) -> SourceId
400where
401 F: FnMut() -> Continue + 'static,
402{
403 unsafe {
404 assert!(MainContext::default().is_owner());
405 from_glib(glib_sys::g_unix_signal_add_full(
406 glib_sys::G_PRIORITY_DEFAULT,
407 signum,
408 Some(trampoline::<F>),
409 into_raw(func),
410 Some(destroy_closure::<F>),
411 ))
412 }
413}
414
415#[cfg(any(unix, feature = "dox"))]
416pub fn unix_fd_add<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
425where
426 F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static,
427{
428 unsafe {
429 from_glib(glib_sys::g_unix_fd_add_full(
430 glib_sys::G_PRIORITY_DEFAULT,
431 fd,
432 condition.to_glib(),
433 Some(transmute(trampoline_unix_fd::<F> as usize)),
434 into_raw_unix_fd(func),
435 Some(destroy_closure_unix_fd::<F>),
436 ))
437 }
438}
439
440#[cfg(any(unix, feature = "dox"))]
441pub fn unix_fd_add_local<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
456where
457 F: FnMut(RawFd, IOCondition) -> Continue + 'static,
458{
459 unsafe {
460 assert!(MainContext::default().is_owner());
461 from_glib(glib_sys::g_unix_fd_add_full(
462 glib_sys::G_PRIORITY_DEFAULT,
463 fd,
464 condition.to_glib(),
465 Some(transmute(trampoline_unix_fd::<F> as usize)),
466 into_raw_unix_fd(func),
467 Some(destroy_closure_unix_fd::<F>),
468 ))
469 }
470}
471
472#[allow(clippy::needless_pass_by_value)]
480pub fn source_remove(source_id: SourceId) {
481 unsafe {
482 glib_sys::g_source_remove(source_id.to_glib());
483 }
484}
485
486#[derive(Clone, Copy, Debug, Eq, PartialEq)]
489pub struct Priority(i32);
490
491#[doc(hidden)]
492impl ToGlib for Priority {
493 type GlibType = i32;
494
495 #[inline]
496 fn to_glib(&self) -> i32 {
497 self.0
498 }
499}
500
501#[doc(hidden)]
502impl FromGlib<i32> for Priority {
503 #[inline]
504 fn from_glib(val: i32) -> Priority {
505 Priority(val)
506 }
507}
508
509impl Default for Priority {
510 fn default() -> Priority {
511 PRIORITY_DEFAULT
512 }
513}
514
515pub const PRIORITY_HIGH: Priority = Priority(glib_sys::G_PRIORITY_HIGH);
516pub const PRIORITY_DEFAULT: Priority = Priority(glib_sys::G_PRIORITY_DEFAULT);
517pub const PRIORITY_HIGH_IDLE: Priority = Priority(glib_sys::G_PRIORITY_HIGH_IDLE);
518pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(glib_sys::G_PRIORITY_DEFAULT_IDLE);
519pub const PRIORITY_LOW: Priority = Priority(glib_sys::G_PRIORITY_LOW);
520
521pub fn idle_source_new<F>(name: Option<&str>, priority: Priority, func: F) -> Source
525where
526 F: FnMut() -> Continue + Send + 'static,
527{
528 unsafe {
529 let source = glib_sys::g_idle_source_new();
530 glib_sys::g_source_set_callback(
531 source,
532 Some(trampoline::<F>),
533 into_raw(func),
534 Some(destroy_closure::<F>),
535 );
536 glib_sys::g_source_set_priority(source, priority.to_glib());
537
538 if let Some(name) = name {
539 glib_sys::g_source_set_name(source, name.to_glib_none().0);
540 }
541
542 from_glib_full(source)
543 }
544}
545
546pub fn timeout_source_new<F>(
554 interval: u32,
555 name: Option<&str>,
556 priority: Priority,
557 func: F,
558) -> Source
559where
560 F: FnMut() -> Continue + Send + 'static,
561{
562 unsafe {
563 let source = glib_sys::g_timeout_source_new(interval);
564 glib_sys::g_source_set_callback(
565 source,
566 Some(trampoline::<F>),
567 into_raw(func),
568 Some(destroy_closure::<F>),
569 );
570 glib_sys::g_source_set_priority(source, priority.to_glib());
571
572 if let Some(name) = name {
573 glib_sys::g_source_set_name(source, name.to_glib_none().0);
574 }
575
576 from_glib_full(source)
577 }
578}
579
580pub fn timeout_source_new_seconds<F>(
587 interval: u32,
588 name: Option<&str>,
589 priority: Priority,
590 func: F,
591) -> Source
592where
593 F: FnMut() -> Continue + Send + 'static,
594{
595 unsafe {
596 let source = glib_sys::g_timeout_source_new_seconds(interval);
597 glib_sys::g_source_set_callback(
598 source,
599 Some(trampoline::<F>),
600 into_raw(func),
601 Some(destroy_closure::<F>),
602 );
603 glib_sys::g_source_set_priority(source, priority.to_glib());
604
605 if let Some(name) = name {
606 glib_sys::g_source_set_name(source, name.to_glib_none().0);
607 }
608
609 from_glib_full(source)
610 }
611}
612
613pub fn child_watch_source_new<F>(
618 pid: Pid,
619 name: Option<&str>,
620 priority: Priority,
621 func: F,
622) -> Source
623where
624 F: FnMut(Pid, i32) + Send + 'static,
625{
626 unsafe {
627 let source = glib_sys::g_child_watch_source_new(pid.0);
628 glib_sys::g_source_set_callback(
629 source,
630 Some(transmute(trampoline_child_watch::<F> as usize)),
631 into_raw_child_watch(func),
632 Some(destroy_closure_child_watch::<F>),
633 );
634 glib_sys::g_source_set_priority(source, priority.to_glib());
635
636 if let Some(name) = name {
637 glib_sys::g_source_set_name(source, name.to_glib_none().0);
638 }
639
640 from_glib_full(source)
641 }
642}
643
644#[cfg(any(unix, feature = "dox"))]
645pub fn unix_signal_source_new<F>(
651 signum: i32,
652 name: Option<&str>,
653 priority: Priority,
654 func: F,
655) -> Source
656where
657 F: FnMut() -> Continue + Send + 'static,
658{
659 unsafe {
660 let source = glib_sys::g_unix_signal_source_new(signum);
661 glib_sys::g_source_set_callback(
662 source,
663 Some(trampoline::<F>),
664 into_raw(func),
665 Some(destroy_closure::<F>),
666 );
667 glib_sys::g_source_set_priority(source, priority.to_glib());
668
669 if let Some(name) = name {
670 glib_sys::g_source_set_name(source, name.to_glib_none().0);
671 }
672
673 from_glib_full(source)
674 }
675}
676
677#[cfg(any(unix, feature = "dox"))]
678pub fn unix_fd_source_new<F>(
684 fd: RawFd,
685 condition: IOCondition,
686 name: Option<&str>,
687 priority: Priority,
688 func: F,
689) -> Source
690where
691 F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static,
692{
693 unsafe {
694 let source = glib_sys::g_unix_fd_source_new(fd, condition.to_glib());
695 glib_sys::g_source_set_callback(
696 source,
697 Some(transmute(trampoline_unix_fd::<F> as usize)),
698 into_raw_unix_fd(func),
699 Some(destroy_closure_unix_fd::<F>),
700 );
701 glib_sys::g_source_set_priority(source, priority.to_glib());
702
703 if let Some(name) = name {
704 glib_sys::g_source_set_name(source, name.to_glib_none().0);
705 }
706
707 from_glib_full(source)
708 }
709}
710
711impl Source {
712 pub fn attach(&self, context: Option<&MainContext>) -> SourceId {
713 unsafe {
714 from_glib(glib_sys::g_source_attach(
715 self.to_glib_none().0,
716 context.to_glib_none().0,
717 ))
718 }
719 }
720
721 pub fn remove(tag: SourceId) -> Result<(), ::BoolError> {
722 unsafe {
723 glib_result_from_gboolean!(
724 glib_sys::g_source_remove(tag.to_glib()),
725 "Failed to remove source"
726 )
727 }
728 }
729}