use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use ffi as glib_ffi;
use ffi::{gboolean, gpointer};
use translate::{from_glib, FromGlib, ToGlib};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Id(u32);
impl ToGlib for Id {
type GlibType = u32;
#[inline]
fn to_glib(&self) -> u32 {
self.0
}
}
impl FromGlib<u32> for Id {
#[inline]
fn from_glib(val: u32) -> Id {
Id(val)
}
}
pub struct Continue(pub bool);
impl ToGlib for Continue {
type GlibType = gboolean;
#[inline]
fn to_glib(&self) -> gboolean {
self.0.to_glib()
}
}
pub struct CallbackGuard(());
impl CallbackGuard {
pub fn new() -> CallbackGuard {
CallbackGuard(())
}
}
impl Drop for CallbackGuard {
fn drop(&mut self) {
if thread::panicking() {
process::exit(101);
}
}
}
unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
let _guard = CallbackGuard::new();
let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
(&mut *func.borrow_mut())().to_glib()
}
unsafe extern "C" fn destroy_closure(ptr: gpointer) {
let _guard = CallbackGuard::new();
Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}
fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
Box::new(RefCell::new(Box::new(func)));
Box::into_raw(func) as gpointer
}
pub fn idle_add<F>(func: F) -> Id
where F: FnMut() -> Continue + Send + 'static {
unsafe {
from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
into_raw(func), Some(destroy_closure)))
}
}
pub fn timeout_add<F>(interval: u32, func: F) -> Id
where F: FnMut() -> Continue + Send + 'static {
unsafe {
from_glib(glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
Some(trampoline), into_raw(func), Some(destroy_closure)))
}
}
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> Id
where F: FnMut() -> Continue + Send + 'static {
unsafe {
from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
Some(trampoline), into_raw(func), Some(destroy_closure)))
}
}
pub fn source_remove(source_id: Id) {
unsafe {
glib_ffi::g_source_remove(source_id.to_glib());
}
}