use std::rc::Rc; use objc2::rc::{autoreleasepool, Id}; use objc2::runtime::{AnyObject, ProtocolObject}; use objc2::{declare_class, msg_send, msg_send_id, mutability, ClassType, DeclaredClass}; use objc2_app_kit::{NSBackingStoreType, NSEvent, NSEventType, NSResponder, NSWindow, NSWindowDelegate, NSWindowStyleMask}; use objc2_foundation::{CGPoint, CGRect, CGSize, MainThreadMarker, NSNotification, NSObject, NSObjectProtocol}; use super::{Factor, Platform, Vars, WinEvent, WinRef, XLoopView}; declare_class!( #[derive(Debug)] pub struct XLoopWindow; unsafe impl ClassType for XLoopWindow { #[inherits(NSResponder, NSObject)] type Super = NSWindow; type Mutability = mutability::MainThreadOnly; const NAME: &'static str = "XLoopWindow"; } impl DeclaredClass for XLoopWindow { type Ivars = (Vars,Id); } unsafe impl XLoopWindow { #[method(sendEvent:)] fn send_event(&self, event: &NSEvent) { self.send_event_(event); unsafe { msg_send![super(self), sendEvent: event] } } #[method(updateProxy:)] fn update_proxy(&self,value:i64){ self.update_proxy_(value) } #[method(canBecomeMainWindow)] fn can_become_main_window(&self) -> bool { true } #[method(canBecomeKeyWindow)] fn can_become_key_window(&self) -> bool { true } } ); impl XLoopWindow { pub fn new(delegate: impl types::WinDelegate + 'static) -> Id { let delegate = Rc::new(delegate); autoreleasepool(|_| { let mtm = MainThreadMarker::new().unwrap(); let vars = Vars { delegate, marked_text: Default::default(), }; let delegate = mtm.alloc().set_ivars(vars.clone()); let delegate: Id = unsafe { msg_send_id![super(delegate), init] }; let window: Id = unsafe { msg_send_id![ super(mtm.alloc().set_ivars((vars.clone(),delegate.clone()))), initWithContentRect: CGRect::new(CGPoint::new(0., 0.), CGSize::new(350., 700.)), styleMask: NSWindowStyleMask( NSWindowStyleMask::Closable.0 | NSWindowStyleMask::Miniaturizable.0 | NSWindowStyleMask::Resizable.0 | NSWindowStyleMask::Titled.0 | NSWindowStyleMask::UnifiedTitleAndToolbar.0, ), backing: NSBackingStoreType::NSBackingStoreBuffered, defer: false, ] }; window.setDelegate(Some(ProtocolObject::from_ref(&*delegate.clone()))); let view = mtm.alloc().set_ivars(vars.clone()); let view: Id = unsafe { msg_send_id![super(view), init] }; unsafe { view.as_super().setPaused(true) }; unsafe { view.setEnableSetNeedsDisplay(true) }; window.setContentView(Some(&view)); window.setInitialFirstResponder(Some(&view)); window.center(); delegate.ivars().delegate.on_create(WinRef(&window, &view)); window }) } fn send_event_(&self, event: &NSEvent) { let event_type = unsafe { event.r#type() }; if event_type == NSEventType::MouseMoved { if let Some(view) = self.contentView() { self.ivars().0.delegate.on_mouse(WinRef(&self, &view), WinEvent(event)); } } } fn update_proxy_(&self, value: i64) { if let Some(view) = self.contentView() { self.ivars().0.delegate.on_proxy(WinRef(&self, &view), value); } } } declare_class!( #[derive(Debug)] pub struct WinDelegate; unsafe impl ClassType for WinDelegate { type Super = NSObject; type Mutability = mutability::MainThreadOnly; const NAME: &'static str = "XLoopWindowDelegate"; } impl DeclaredClass for WinDelegate { type Ivars = Vars; } unsafe impl NSObjectProtocol for WinDelegate {} unsafe impl NSWindowDelegate for WinDelegate { #[method(windowShouldClose:)] unsafe fn window_should_close(&self, window: &NSWindow) -> bool{ self.should_close(window) } #[method(windowDidResize:)] unsafe fn window_did_resize(&self, notification: &NSNotification){ self.did_resize(notification) } } ); impl WinDelegate { fn should_close(&self, window: &NSWindow) -> bool { if let Some(view) = window.contentView() { self.ivars().delegate.req_close(WinRef(&window, &view)) } else { true } } fn did_resize(&self, notification: &NSNotification) { if let Some(window) = unsafe { notification.object() } { let window: &NSWindow = unsafe { &*(&*window as *const AnyObject).cast() }; if let Some(view) = window.contentView() { let frame = view.frame(); let factor: Factor = Factor::from(window); let size = (factor.to_u32(frame.size.width), factor.to_u32(frame.size.height)); self.ivars().delegate.on_resize(WinRef(&window, &view), size); } } } }