use std::cell::RefCell; use std::ops::Deref; use std::rc::Rc; use objc2::rc::Id; use objc2::{declare_class, mutability, ClassType, DeclaredClass}; use objc2_foundation::{MainThreadMarker, NSObject, NSObjectProtocol}; use objc2_ui_kit::{UIApplication, UIApplicationDelegate}; use super::Platform; mod proxy; pub use proxy::*; #[derive(Clone, Copy)] pub struct AppRef<'a>(pub &'a UIApplication); impl<'a> Deref for AppRef<'a> { type Target = UIApplication; fn deref(&self) -> &Self::Target { self.0 } } impl<'a> types::AppRef for AppRef<'a> { fn terminate(&self) { // not surport } fn proxy(&self) -> Option { Some(AppProxy(with_app_vars(None, |vars| vars.proxy.clone()))) } } pub struct AppHandle(pub Id); impl types::AppHandle for AppHandle { fn singleton() -> Option { let mtm = MainThreadMarker::new().unwrap(); let app = UIApplication::sharedApplication(mtm); Some(AppHandle(app)) } fn with(&self, mut fun: impl FnMut(::AppRef<'_>)) { fun(AppRef(&self.0)); } } pub type RcDynDelegate = Rc>; pub struct AppVars { delegate: RefCell>, proxy: Id, } thread_local! { static CACHE:RefCell = RefCell::new(AppVars { delegate: RefCell::new(None), proxy: AppProxyObj::new(), }); } pub fn with_app_vars(v: Option, fun: impl Fn(&AppVars) -> T) -> T { let _ = MainThreadMarker::new().unwrap(); if let Some(new) = v { CACHE.with_borrow_mut(|old| { *old.delegate.borrow_mut() = Some(new); }) } CACHE.with_borrow(|v| fun(v)) } declare_class!( pub(crate) struct AppDelegate; unsafe impl ClassType for AppDelegate { type Super = NSObject; type Mutability = mutability::MainThreadOnly; const NAME: &'static str = "XLoopAppDelegate"; } impl DeclaredClass for AppDelegate {} unsafe impl NSObjectProtocol for AppDelegate {} unsafe impl UIApplicationDelegate for AppDelegate { #[method(applicationDidFinishLaunching:)] unsafe fn application_did_finish_launching(&self, application: &UIApplication){ self.did_finish_launching_(application) } #[method(applicationWillTerminate:)] unsafe fn application_will_terminate(&self, application: &UIApplication){ self.application_will_terminate_(application); } } ); impl AppDelegate { fn did_finish_launching_(&self, application: &UIApplication) { with_app_vars(None, |vars| { let delegate = vars.delegate.borrow(); delegate.as_deref()?.on_launch(AppRef(application)); Some(()) }); } fn application_will_terminate_(&self, application: &UIApplication) { with_app_vars(None, |vars| { let delegate = vars.delegate.borrow(); delegate.as_deref()?.on_terminate(AppRef(application)); Some(()) }); } }