use crate::translate::{from_glib, from_glib_full, FromGlib, IntoGlib, ToGlibPtr};
#[cfg(any(unix, feature = "dox"))]
use crate::IOCondition;
use ffi::{self, gboolean, gpointer};
#[cfg(all(not(unix), feature = "dox"))]
use libc::c_int as RawFd;
use std::cell::RefCell;
use std::mem::transmute;
use std::num::NonZeroU32;
#[cfg(unix)]
use std::os::unix::io::RawFd;
use std::time::Duration;
use crate::thread_guard::ThreadGuard;
use crate::MainContext;
use crate::Source;
#[derive(Debug, Eq, PartialEq)]
pub struct SourceId(NonZeroU32);
impl SourceId {
pub unsafe fn as_raw(&self) -> u32 {
self.0.get()
}
#[doc(alias = "g_source_remove")]
pub fn remove(self) {
unsafe {
result_from_gboolean!(
ffi::g_source_remove(self.as_raw()),
"Failed to remove source"
)
.unwrap()
}
}
}
#[doc(hidden)]
impl FromGlib<u32> for SourceId {
#[inline]
unsafe fn from_glib(val: u32) -> Self {
assert_ne!(val, 0);
Self(NonZeroU32::new_unchecked(val))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[doc(alias = "GPid")]
pub struct Pid(pub ffi::GPid);
unsafe impl Send for Pid {}
unsafe impl Sync for Pid {}
#[doc(hidden)]
impl IntoGlib for Pid {
type GlibType = ffi::GPid;
#[inline]
fn into_glib(self) -> ffi::GPid {
self.0
}
}
#[doc(hidden)]
impl FromGlib<ffi::GPid> for Pid {
#[inline]
unsafe fn from_glib(val: ffi::GPid) -> Self {
Self(val)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Continue(pub bool);
#[doc(hidden)]
impl IntoGlib for Continue {
type GlibType = gboolean;
#[inline]
fn into_glib(self) -> gboolean {
self.0.into_glib()
}
}
unsafe extern "C" fn trampoline<F: FnMut() -> Continue + Send + 'static>(
func: gpointer,
) -> gboolean {
let func: &RefCell<F> = &*(func as *const RefCell<F>);
(*func.borrow_mut())().into_glib()
}
unsafe extern "C" fn trampoline_local<F: FnMut() -> Continue + 'static>(
func: gpointer,
) -> gboolean {
let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
(*func.get_ref().borrow_mut())().into_glib()
}
unsafe extern "C" fn destroy_closure<F: FnMut() -> Continue + Send + 'static>(ptr: gpointer) {
let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
}
unsafe extern "C" fn destroy_closure_local<F: FnMut() -> Continue + 'static>(ptr: gpointer) {
let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
}
fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
Box::into_raw(func) as gpointer
}
fn into_raw_local<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
Box::into_raw(func) as gpointer
}
unsafe extern "C" fn trampoline_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
pid: ffi::GPid,
status: i32,
func: gpointer,
) {
let func: &RefCell<F> = &*(func as *const RefCell<F>);
(*func.borrow_mut())(Pid(pid), status)
}
unsafe extern "C" fn trampoline_child_watch_local<F: FnMut(Pid, i32) + 'static>(
pid: ffi::GPid,
status: i32,
func: gpointer,
) {
let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
(*func.get_ref().borrow_mut())(Pid(pid), status)
}
unsafe extern "C" fn destroy_closure_child_watch<F: FnMut(Pid, i32) + Send + 'static>(
ptr: gpointer,
) {
let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
}
unsafe extern "C" fn destroy_closure_child_watch_local<F: FnMut(Pid, i32) + 'static>(
ptr: gpointer,
) {
let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
}
fn into_raw_child_watch<F: FnMut(Pid, i32) + Send + 'static>(func: F) -> gpointer {
let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
Box::into_raw(func) as gpointer
}
fn into_raw_child_watch_local<F: FnMut(Pid, i32) + 'static>(func: F) -> gpointer {
let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
Box::into_raw(func) as gpointer
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
unsafe extern "C" fn trampoline_unix_fd<
F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static,
>(
fd: i32,
condition: ffi::GIOCondition,
func: gpointer,
) -> gboolean {
let func: &RefCell<F> = &*(func as *const RefCell<F>);
(*func.borrow_mut())(fd, from_glib(condition)).into_glib()
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
unsafe extern "C" fn trampoline_unix_fd_local<
F: FnMut(RawFd, IOCondition) -> Continue + 'static,
>(
fd: i32,
condition: ffi::GIOCondition,
func: gpointer,
) -> gboolean {
let func: &ThreadGuard<RefCell<F>> = &*(func as *const ThreadGuard<RefCell<F>>);
(*func.get_ref().borrow_mut())(fd, from_glib(condition)).into_glib()
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
unsafe extern "C" fn destroy_closure_unix_fd<
F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static,
>(
ptr: gpointer,
) {
let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
unsafe extern "C" fn destroy_closure_unix_fd_local<
F: FnMut(RawFd, IOCondition) -> Continue + 'static,
>(
ptr: gpointer,
) {
let _ = Box::<ThreadGuard<RefCell<F>>>::from_raw(ptr as *mut _);
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
fn into_raw_unix_fd<F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static>(
func: F,
) -> gpointer {
let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
Box::into_raw(func) as gpointer
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
fn into_raw_unix_fd_local<F: FnMut(RawFd, IOCondition) -> Continue + 'static>(func: F) -> gpointer {
let func: Box<ThreadGuard<RefCell<F>>> = Box::new(ThreadGuard::new(RefCell::new(func)));
Box::into_raw(func) as gpointer
}
#[inline(always)]
fn fnmut_callback_wrapper(
func: impl FnOnce() + Send + 'static,
) -> impl FnMut() -> Continue + Send + 'static {
let mut func = Some(func);
move || {
let func = func
.take()
.expect("GSource closure called after returning glib::Continue(false)");
func();
Continue(false)
}
}
#[inline(always)]
fn fnmut_callback_wrapper_local(
func: impl FnOnce() + 'static,
) -> impl FnMut() -> Continue + 'static {
let mut func = Some(func);
move || {
let func = func
.take()
.expect("GSource closure called after returning glib::Continue(false)");
func();
Continue(false)
}
}
#[doc(alias = "g_idle_add_full")]
pub fn idle_add<F>(func: F) -> SourceId
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
from_glib(ffi::g_idle_add_full(
ffi::G_PRIORITY_DEFAULT_IDLE,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
))
}
}
#[doc(alias = "g_idle_add_full")]
#[doc(alias = "g_idle_add_once")]
pub fn idle_add_once<F>(func: F) -> SourceId
where
F: FnOnce() + Send + 'static,
{
idle_add(fnmut_callback_wrapper(func))
}
#[doc(alias = "g_idle_add_full")]
pub fn idle_add_local<F>(func: F) -> SourceId
where
F: FnMut() -> Continue + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_idle_add_full(
ffi::G_PRIORITY_DEFAULT_IDLE,
Some(trampoline_local::<F>),
into_raw_local(func),
Some(destroy_closure_local::<F>),
))
}
}
#[doc(alias = "g_idle_add_full")]
pub fn idle_add_local_once<F>(func: F) -> SourceId
where
F: FnOnce() + 'static,
{
idle_add_local(fnmut_callback_wrapper_local(func))
}
#[doc(alias = "g_timeout_add_full")]
pub fn timeout_add<F>(interval: Duration, func: F) -> SourceId
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
from_glib(ffi::g_timeout_add_full(
ffi::G_PRIORITY_DEFAULT,
interval.as_millis() as _,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
))
}
}
#[doc(alias = "g_timeout_add_full")]
#[doc(alias = "g_timeout_add_once")]
pub fn timeout_add_once<F>(interval: Duration, func: F) -> SourceId
where
F: FnOnce() + Send + 'static,
{
timeout_add(interval, fnmut_callback_wrapper(func))
}
#[doc(alias = "g_timeout_add_full")]
pub fn timeout_add_local<F>(interval: Duration, func: F) -> SourceId
where
F: FnMut() -> Continue + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_timeout_add_full(
ffi::G_PRIORITY_DEFAULT,
interval.as_millis() as _,
Some(trampoline_local::<F>),
into_raw_local(func),
Some(destroy_closure_local::<F>),
))
}
}
#[doc(alias = "g_timeout_add_full")]
pub fn timeout_add_local_once<F>(interval: Duration, func: F) -> SourceId
where
F: FnOnce() + 'static,
{
timeout_add_local(interval, fnmut_callback_wrapper_local(func))
}
#[doc(alias = "g_timeout_add_seconds_full")]
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
from_glib(ffi::g_timeout_add_seconds_full(
ffi::G_PRIORITY_DEFAULT,
interval,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
))
}
}
#[doc(alias = "g_timeout_add_seconds_full")]
pub fn timeout_add_seconds_once<F>(interval: u32, func: F) -> SourceId
where
F: FnOnce() + Send + 'static,
{
timeout_add_seconds(interval, fnmut_callback_wrapper(func))
}
#[doc(alias = "g_timeout_add_seconds_full")]
pub fn timeout_add_seconds_local<F>(interval: u32, func: F) -> SourceId
where
F: FnMut() -> Continue + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_timeout_add_seconds_full(
ffi::G_PRIORITY_DEFAULT,
interval,
Some(trampoline_local::<F>),
into_raw_local(func),
Some(destroy_closure_local::<F>),
))
}
}
#[doc(alias = "g_timeout_add_seconds_full")]
pub fn timeout_add_seconds_local_once<F>(interval: u32, func: F) -> SourceId
where
F: FnOnce() + 'static,
{
timeout_add_seconds_local(interval, fnmut_callback_wrapper_local(func))
}
#[doc(alias = "g_child_watch_add_full")]
pub fn child_watch_add<F>(pid: Pid, func: F) -> SourceId
where
F: FnMut(Pid, i32) + Send + 'static,
{
unsafe {
from_glib(ffi::g_child_watch_add_full(
ffi::G_PRIORITY_DEFAULT,
pid.0,
Some(trampoline_child_watch::<F>),
into_raw_child_watch(func),
Some(destroy_closure_child_watch::<F>),
))
}
}
#[doc(alias = "g_child_watch_add_full")]
pub fn child_watch_add_local<F>(pid: Pid, func: F) -> SourceId
where
F: FnMut(Pid, i32) + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_child_watch_add_full(
ffi::G_PRIORITY_DEFAULT,
pid.0,
Some(trampoline_child_watch_local::<F>),
into_raw_child_watch_local(func),
Some(destroy_closure_child_watch_local::<F>),
))
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_signal_add_full")]
pub fn unix_signal_add<F>(signum: i32, func: F) -> SourceId
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
from_glib(ffi::g_unix_signal_add_full(
ffi::G_PRIORITY_DEFAULT,
signum,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
))
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_signal_add_full")]
pub fn unix_signal_add_once<F>(signum: i32, func: F) -> SourceId
where
F: FnOnce() + Send + 'static,
{
unix_signal_add(signum, fnmut_callback_wrapper(func))
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_signal_add_full")]
pub fn unix_signal_add_local<F>(signum: i32, func: F) -> SourceId
where
F: FnMut() -> Continue + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_unix_signal_add_full(
ffi::G_PRIORITY_DEFAULT,
signum,
Some(trampoline_local::<F>),
into_raw_local(func),
Some(destroy_closure_local::<F>),
))
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_signal_add_full")]
pub fn unix_signal_add_local_once<F>(signum: i32, func: F) -> SourceId
where
F: FnOnce() + 'static,
{
unix_signal_add_local(signum, fnmut_callback_wrapper_local(func))
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_fd_add_full")]
pub fn unix_fd_add<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
where
F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static,
{
unsafe {
from_glib(ffi::g_unix_fd_add_full(
ffi::G_PRIORITY_DEFAULT,
fd,
condition.into_glib(),
Some(trampoline_unix_fd::<F>),
into_raw_unix_fd(func),
Some(destroy_closure_unix_fd::<F>),
))
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_fd_add_full")]
pub fn unix_fd_add_local<F>(fd: RawFd, condition: IOCondition, func: F) -> SourceId
where
F: FnMut(RawFd, IOCondition) -> Continue + 'static,
{
unsafe {
let context = MainContext::default();
let _acquire = context
.acquire()
.expect("default main context already acquired by another thread");
from_glib(ffi::g_unix_fd_add_full(
ffi::G_PRIORITY_DEFAULT,
fd,
condition.into_glib(),
Some(trampoline_unix_fd_local::<F>),
into_raw_unix_fd_local(func),
Some(destroy_closure_unix_fd_local::<F>),
))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Priority(i32);
#[doc(hidden)]
impl IntoGlib for Priority {
type GlibType = i32;
#[inline]
fn into_glib(self) -> i32 {
self.0
}
}
#[doc(hidden)]
impl FromGlib<i32> for Priority {
#[inline]
unsafe fn from_glib(val: i32) -> Self {
Self(val)
}
}
impl Default for Priority {
fn default() -> Self {
PRIORITY_DEFAULT
}
}
#[doc(alias = "G_PRIORITY_HIGH")]
pub const PRIORITY_HIGH: Priority = Priority(ffi::G_PRIORITY_HIGH);
#[doc(alias = "G_PRIORITY_DEFAULT")]
pub const PRIORITY_DEFAULT: Priority = Priority(ffi::G_PRIORITY_DEFAULT);
#[doc(alias = "G_PRIORITY_HIGH_IDLE")]
pub const PRIORITY_HIGH_IDLE: Priority = Priority(ffi::G_PRIORITY_HIGH_IDLE);
#[doc(alias = "G_PRIORITY_DEFAULT_IDLE")]
pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(ffi::G_PRIORITY_DEFAULT_IDLE);
#[doc(alias = "G_PRIORITY_LOW")]
pub const PRIORITY_LOW: Priority = Priority(ffi::G_PRIORITY_LOW);
#[doc(alias = "g_idle_source_new")]
pub fn idle_source_new<F>(name: Option<&str>, priority: Priority, func: F) -> Source
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
let source = ffi::g_idle_source_new();
ffi::g_source_set_callback(
source,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
#[doc(alias = "g_timeout_source_new")]
pub fn timeout_source_new<F>(
interval: Duration,
name: Option<&str>,
priority: Priority,
func: F,
) -> Source
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
let source = ffi::g_timeout_source_new(interval.as_millis() as _);
ffi::g_source_set_callback(
source,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
#[doc(alias = "g_timeout_source_new_seconds")]
pub fn timeout_source_new_seconds<F>(
interval: u32,
name: Option<&str>,
priority: Priority,
func: F,
) -> Source
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
let source = ffi::g_timeout_source_new_seconds(interval);
ffi::g_source_set_callback(
source,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
#[doc(alias = "g_child_watch_source_new")]
pub fn child_watch_source_new<F>(
pid: Pid,
name: Option<&str>,
priority: Priority,
func: F,
) -> Source
where
F: FnMut(Pid, i32) + Send + 'static,
{
unsafe {
let source = ffi::g_child_watch_source_new(pid.0);
ffi::g_source_set_callback(
source,
Some(transmute::<
_,
unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
>(trampoline_child_watch::<F> as *const ())),
into_raw_child_watch(func),
Some(destroy_closure_child_watch::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_signal_source_new")]
pub fn unix_signal_source_new<F>(
signum: i32,
name: Option<&str>,
priority: Priority,
func: F,
) -> Source
where
F: FnMut() -> Continue + Send + 'static,
{
unsafe {
let source = ffi::g_unix_signal_source_new(signum);
ffi::g_source_set_callback(
source,
Some(trampoline::<F>),
into_raw(func),
Some(destroy_closure::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
#[cfg(any(unix, feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(unix)))]
#[doc(alias = "g_unix_fd_source_new")]
pub fn 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,
{
unsafe {
let source = ffi::g_unix_fd_source_new(fd, condition.into_glib());
ffi::g_source_set_callback(
source,
Some(transmute::<
_,
unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean,
>(trampoline_unix_fd::<F> as *const ())),
into_raw_unix_fd(func),
Some(destroy_closure_unix_fd::<F>),
);
ffi::g_source_set_priority(source, priority.into_glib());
if let Some(name) = name {
ffi::g_source_set_name(source, name.to_glib_none().0);
}
from_glib_full(source)
}
}
impl Source {
#[doc(alias = "g_source_attach")]
pub fn attach(&self, context: Option<&MainContext>) -> SourceId {
unsafe {
from_glib(ffi::g_source_attach(
self.to_glib_none().0,
context.to_glib_none().0,
))
}
}
}