use std::{
ffi::c_void,
panic::{AssertUnwindSafe, UnwindSafe},
rc::Weak,
};
use core_foundation::{
base::CFIndex,
runloop::{
kCFRunLoopAfterWaiting,
kCFRunLoopBeforeWaiting,
kCFRunLoopExit,
CFRunLoopActivity,
CFRunLoopObserverContext,
CFRunLoopObserverRef,
},
};
use objc2_foundation::MainThreadMarker;
use super::{app_delegate::AppDelegate, panicinfo::PanicInfo, runloop::RunLoop, stop_app_on_panic};
unsafe fn control_flow_handler<F>(panic_info: *mut c_void, f: F)
where
F: FnOnce(Weak<PanicInfo>) + UnwindSafe,
{
let info_from_raw = unsafe { Weak::from_raw(panic_info as *mut PanicInfo) };
let panic_info = AssertUnwindSafe(Weak::clone(&info_from_raw));
std::mem::forget(info_from_raw);
let mtm = MainThreadMarker::new().unwrap();
stop_app_on_panic(mtm, Weak::clone(&panic_info), move || {
let _ = &panic_info;
f(panic_info.0)
});
}
extern "C" fn control_flow_begin_handler(
_: CFRunLoopObserverRef,
activity: CFRunLoopActivity,
panic_info: *mut c_void,
) {
unsafe {
control_flow_handler(panic_info, |panic_info| {
#[allow(non_upper_case_globals)]
match activity {
kCFRunLoopAfterWaiting => {
AppDelegate::get(MainThreadMarker::new().unwrap()).wakeup(panic_info);
}
_ => unreachable!(),
}
});
}
}
extern "C" fn control_flow_end_handler(
_: CFRunLoopObserverRef,
activity: CFRunLoopActivity,
panic_info: *mut c_void,
) {
unsafe {
control_flow_handler(panic_info, |panic_info| {
#[allow(non_upper_case_globals)]
match activity {
kCFRunLoopBeforeWaiting => {
AppDelegate::get(MainThreadMarker::new().unwrap()).cleared(panic_info);
}
kCFRunLoopExit => (), _ => unreachable!(),
}
});
}
}
pub fn setup_control_flow_observers(panic_info: Weak<PanicInfo>) {
unsafe {
let mut context = CFRunLoopObserverContext {
info: Weak::into_raw(panic_info) as *mut _,
version: 0,
retain: None,
release: None,
copyDescription: None,
};
let run_loop = RunLoop::get();
run_loop.add_observer(
kCFRunLoopAfterWaiting,
CFIndex::min_value(),
control_flow_begin_handler,
&mut context as *mut _,
);
run_loop.add_observer(
kCFRunLoopExit | kCFRunLoopBeforeWaiting,
CFIndex::max_value(),
control_flow_end_handler,
&mut context as *mut _,
);
}
}