use std::ops::Deref; use std::rc::Rc; use objc2::rc::{autoreleasepool, Id}; use objc2::runtime::ProtocolObject; use objc2::{declare_class, msg_send, msg_send_id, mutability, ClassType, DeclaredClass}; use objc2_foundation::{CGSize, MainThreadMarker, NSObject}; use objc2_ui_kit::{UIResponder, UIView, UIViewController, UIViewControllerTransitionCoordinator, UIWindow}; use super::{Factor, Platform, Vars, WinRef, XLoopView}; use crate::app::AppHandle; use crate::win::ViewVars; declare_class!( #[derive(Debug)] pub struct XLoopWindow; unsafe impl ClassType for XLoopWindow { #[inherits(UIView, UIResponder, NSObject)] type Super = UIWindow; type Mutability = mutability::MainThreadOnly; const NAME: &'static str = "XLoopWindow"; } impl DeclaredClass for XLoopWindow { type Ivars = Rc; } unsafe impl XLoopWindow { #[method(updateProxy:)] fn update_proxy(&self,value:i64){ self.update_proxy_(value) } } ); impl XLoopWindow { pub fn new(_key: impl AsRef, delegate: impl types::WinDelegate + 'static) -> Option> { use types::AppHandle as _; let delegate = Rc::new(delegate); autoreleasepool(|_| { let mtm = MainThreadMarker::new().unwrap(); let vars = Rc::new(Vars { delegate: delegate.clone(), window: Default::default(), controller: Default::default(), view: Default::default(), touches: Default::default(), }); let controller = mtm.alloc().set_ivars(vars.clone()); let controller: Id = unsafe { msg_send_id![super(controller), init] }; *vars.controller.borrow_mut() = Some(controller.retain()); let app = AppHandle::singleton()?; let scenes = unsafe { app.0.connectedScenes() }; let scene = scenes.iter().next()?; let window: Id = unsafe { msg_send_id![ super(mtm.alloc().set_ivars(vars.clone())), initWithWindowScene: scene, ] }; *vars.window.borrow_mut() = Some(window.retain()); let view = mtm.alloc().set_ivars(ViewVars::new(vars.clone())); let view: Id = unsafe { msg_send_id![super(view), init] }; *vars.view.borrow_mut() = Some(view.retain()); unsafe { view.setPaused(true) }; unsafe { view.setEnableSetNeedsDisplay(true) }; controller.setView(Some(&view)); window.setRootViewController(Some(&controller)); delegate.on_create(WinRef(&window, &view)); Some(window) }) } fn update_proxy_(&self, value: i64) { if let Some(view) = self.ivars().view.borrow().deref() { self.ivars().delegate.on_proxy(WinRef(&self, &view), value); } } } declare_class!( #[derive(Debug)] pub struct XLoopController; unsafe impl ClassType for XLoopController { #[inherits(UIResponder, NSObject)] type Super = UIViewController; type Mutability = mutability::MainThreadOnly; const NAME: &'static str = "XLoopController"; } impl DeclaredClass for XLoopController { type Ivars = Rc; } unsafe impl XLoopController { #[method(viewWillTransitionToSize:withTransitionCoordinator:)] unsafe fn view_will_transition_to_size_with_transition_coordinator( &self, size: CGSize, coordinator: &ProtocolObject, ){ unsafe { msg_send![super(self), viewWillTransitionToSize:size withTransitionCoordinator:coordinator] } self.view_will_transition_to_size(size); } } ); impl XLoopController { fn view_will_transition_to_size(&self, size: CGSize) { let vars = self.ivars(); let (window, view) = (vars.window.borrow(), vars.view.borrow()); if let (Some(window), Some(view)) = (window.as_ref(), view.as_ref()) { let factor = Factor::from(view.deref()); let win = WinRef(&window, &view); self.ivars() .delegate .on_resize(win, (factor.to_u32(size.width), factor.to_u32(size.height))); use types::WinRef as _; win.fresh("view_will_transition_to_size"); } } }