macro_rules! callback (
(
args -> ($($args:ty),*),
glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
convert_args -> ($($convert_args:expr),*)
) => (
thread_local!(static CALLBACK_KEY: RefCell<Option<Box<dyn FnMut($($args),*)>>> = RefCell::new(None));
pub fn set<T>(f: T)
where T: FnMut($($args),*) + 'static
{
let boxed_cb = Some(Box::new(f) as Box<dyn FnMut($($args),*)>);
CALLBACK_KEY.with(|cb| {
*cb.borrow_mut() = boxed_cb;
});
unsafe {
crate::ffi::$glfw(Some(callback));
}
}
pub fn unset() {
CALLBACK_KEY.with(|cb| {
*cb.borrow_mut() = None;
});
unsafe {
crate::ffi::$glfw(None);
}
}
extern "C" fn callback($($glfw_arg_names: $glfw_args),*) {
CALLBACK_KEY.with(|cb| {
match *cb.borrow_mut() {
Some(ref mut cb) => unsafe { cb($($convert_args),*) },
_ => {}
}
})
}
)
);
pub mod error {
use std::cell::RefCell;
use std::mem;
use std::os::raw::{c_char, c_int};
callback!(
args -> (crate::Error, String),
glfw -> glfwSetErrorCallback(error: c_int, description: *const c_char),
convert_args -> (mem::transmute(error), crate::string_from_c_str(description))
);
}
pub mod monitor {
use std::cell::RefCell;
use std::mem;
use std::os::raw::c_int;
callback!(
args -> (crate::Monitor, crate::MonitorEvent),
glfw -> glfwSetMonitorCallback(monitor: *mut crate::ffi::GLFWmonitor, event: c_int),
convert_args -> (
crate::Monitor { ptr: monitor },
mem::transmute(event)
)
);
}
pub mod joystick {
use std::cell::RefCell;
use std::mem;
use std::os::raw::c_int;
callback!(
args -> (crate::JoystickId, crate::JoystickEvent),
glfw -> glfwSetJoystickCallback(joystick_id: c_int, event: c_int),
convert_args -> (mem::transmute(joystick_id), mem::transmute(event))
);
}
pub mod unbuffered {
use crate::{WindowEvent, WindowId};
use std::cell::RefCell;
type CallbackPtr = *mut std::ffi::c_void;
type HandlerFn = fn(
window_id: WindowId,
event: (f64, WindowEvent),
callback_ptr: CallbackPtr,
) -> Option<(f64, WindowEvent)>;
thread_local! {
static HANDLER: RefCell<Option<(HandlerFn, CallbackPtr)>> = RefCell::new(None);
}
pub struct UnsetHandlerGuard {
_private: (),
}
impl Drop for UnsetHandlerGuard {
fn drop(&mut self) {
HANDLER.with(|ref_cell| {
*ref_cell.borrow_mut() = None;
})
}
}
pub unsafe fn handle(
window_id: WindowId,
event: (f64, WindowEvent),
) -> Option<(f64, WindowEvent)> {
HANDLER.with(|ref_cell| {
if let Some((handler, callback_ptr)) = *ref_cell.borrow() {
handler(window_id, event, callback_ptr)
} else {
Some(event)
}
})
}
pub unsafe fn set_handler<F>(callback: &mut F) -> UnsetHandlerGuard
where
F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
{
fn handler<F>(
window_id: WindowId,
event: (f64, WindowEvent),
callback_ptr: CallbackPtr,
) -> Option<(f64, WindowEvent)>
where
F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
{
unsafe {
let callback: &mut F = &mut *(callback_ptr as *mut F);
callback(window_id, event)
}
}
HANDLER.with(|ref_cell| {
let callback_ptr = callback as *mut F as CallbackPtr;
*ref_cell.borrow_mut() = Some((handler::<F>, callback_ptr));
});
UnsetHandlerGuard { _private: () }
}
}