use std::os::raw::c_void;
use std::sync::Arc;
use objc2::MainThreadMarker;
use objc2_core_foundation::{
CFIndex, CFRetained, CFRunLoop, CFRunLoopSource, CFRunLoopSourceContext, kCFRunLoopCommonModes,
};
use winit_core::event_loop::EventLoopProxyProvider;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EventLoopProxy {
source: CFRetained<CFRunLoopSource>,
main_loop: CFRetained<CFRunLoop>,
}
unsafe impl Send for EventLoopProxy {}
unsafe impl Sync for EventLoopProxy {}
impl EventLoopProxy {
pub fn new<F: Fn() + 'static>(mtm: MainThreadMarker, signaller: F) -> Self {
let signaller = Arc::new(signaller);
unsafe extern "C-unwind" fn retain<F>(info: *const c_void) -> *const c_void {
unsafe { Arc::increment_strong_count(info.cast::<F>()) };
info
}
unsafe extern "C-unwind" fn release<F>(info: *const c_void) {
unsafe { Arc::decrement_strong_count(info.cast::<F>()) };
}
extern "C-unwind" fn equal(info1: *const c_void, info2: *const c_void) -> u8 {
(info1 == info2) as u8
}
extern "C-unwind" fn hash(info: *const c_void) -> usize {
info as usize
}
unsafe extern "C-unwind" fn perform<F: Fn()>(info: *mut c_void) {
let signaller = unsafe { &*info.cast::<F>() };
(signaller)();
}
let order = CFIndex::MAX - 1;
let mut context = CFRunLoopSourceContext {
version: 0,
info: Arc::as_ptr(&signaller) as *mut c_void,
retain: Some(retain::<F>),
release: Some(release::<F>),
copyDescription: None,
equal: Some(equal),
hash: Some(hash),
schedule: None,
cancel: None,
perform: Some(perform::<F>),
};
let source = unsafe {
let _ = mtm;
CFRunLoopSource::new(None, order, &mut context).unwrap()
};
let main_loop = CFRunLoop::main().unwrap();
unsafe { main_loop.add_source(Some(&source), kCFRunLoopCommonModes) };
Self { source, main_loop }
}
pub fn invalidate(&self) {
self.source.invalidate();
}
}
impl EventLoopProxyProvider for EventLoopProxy {
fn wake_up(&self) {
self.source.signal();
self.main_loop.wake_up();
}
}