use core::ptr;
use core::sync::atomic::{AtomicBool, Ordering};
use super::ffi::{self, Id, NSInteger, NSPoint, NSUInteger, ObjcBool, Pool, Sel, value};
use crate::waker::WakeSignal;
pub(super) const WAKE_MARKER: NSInteger = 0x6372_6362;
#[derive(Debug, Default)]
pub(super) struct AppKitWake {
pending: AtomicBool,
}
impl AppKitWake {
pub(super) fn taken(&self) {
self.pending.store(false, Ordering::Release);
}
}
pub(super) unsafe fn is_wake(event: Id) -> bool {
unsafe {
ffi::msg_usize(event, ffi::sel(c"type")) == value::EVENT_TYPE_APPLICATION_DEFINED
&& ffi::msg_usize(event, ffi::sel(c"data1")) as NSInteger == WAKE_MARKER
}
}
impl WakeSignal for AppKitWake {
fn wake(&self) {
if self.pending.swap(true, Ordering::AcqRel) {
return;
}
let _pool = Pool::push();
let (Some(app_class), Some(event_class)) =
(ffi::class(c"NSApplication"), ffi::class(c"NSEvent"))
else {
return;
};
unsafe {
let app = ffi::msg(app_class, ffi::sel(c"sharedApplication"));
let make: unsafe extern "C" fn(
Id,
Sel,
NSUInteger,
NSPoint,
NSUInteger,
f64,
NSInteger,
Id,
i16,
NSInteger,
NSInteger,
) -> Id = ffi::msg_send();
let event = make(
event_class,
ffi::sel(c"otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
value::EVENT_TYPE_APPLICATION_DEFINED,
NSPoint::default(),
0,
0.0,
0,
ptr::null_mut(),
0,
WAKE_MARKER,
0,
);
if app.is_null() || event.is_null() {
self.taken();
return;
}
let post: unsafe extern "C" fn(Id, Sel, Id, ObjcBool) = ffi::msg_send();
post(app, ffi::sel(c"postEvent:atStart:"), event, ffi::YES);
}
}
}