From de8fe684e7c8d7a37c98f045c9fe3b8551e1e83b Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 20 Jan 2015 08:12:53 +1100 Subject: Move osx delegate stuff into separate type --- src/osx/mod.rs | 166 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/osx/mod.rs b/src/osx/mod.rs index c7ce750..84a0fed 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -7,7 +7,7 @@ use libc; use BuilderAttribs; -use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; +use cocoa::base::{Class, id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; use cocoa::appkit; @@ -44,9 +44,6 @@ static mut ctrl_pressed: bool = false; static mut win_pressed: bool = false; static mut alt_pressed: bool = false; -static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; -static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; - struct DelegateState<'a> { is_closed: bool, context: id, @@ -55,11 +52,114 @@ struct DelegateState<'a> { handler: Option, } +struct WindowDelegate { + this: id, +} + +impl WindowDelegate { + fn class_name() -> &'static [u8] { + b"GlutinWindowDelegate\0" + } + + fn state_ivar_name() -> &'static [u8] { + b"glutinState" + } + + /// Get the delegate class, initiailizing it neccessary + fn class() -> Class { + use std::sync::{Once, ONCE_INIT}; + use std::rt; + + extern fn window_should_close(this: id, _: id) -> id { + unsafe { + let delegate = WindowDelegate { this: this }; + (*delegate.get_state()).is_closed = true; + mem::forget(delegate); + } + 0 + } + + extern fn window_did_resize(this: id, _: id) -> id { + unsafe { + let delegate = WindowDelegate { this: this }; + let state = &mut *delegate.get_state(); + mem::forget(delegate); + + let _: id = msg_send()(state.context, selector("update")); + + if let Some(handler) = state.handler { + let rect = NSView::frame(state.view); + let scale_factor = state.window.backingScaleFactor() as f32; + (handler)((scale_factor * rect.size.width as f32) as u32, + (scale_factor * rect.size.height as f32) as u32); + } + } + 0 + } + + static mut delegate_class: Class = nil; + static mut init: Once = ONCE_INIT; + + unsafe { + init.call_once(|| { + let ptr_size = mem::size_of::(); + // Create new NSWindowDelegate + delegate_class = objc_allocateClassPair( + class("NSObject"), + WindowDelegate::class_name().as_ptr() as *const i8, 0); + // Add callback methods + class_addMethod(delegate_class, + selector("windowShouldClose:"), + window_should_close, + CString::from_slice("B@:@".as_bytes()).as_ptr()); + class_addMethod(delegate_class, + selector("windowDidResize:"), + window_did_resize, + CString::from_slice("V@:@".as_bytes()).as_ptr()); + // Store internal state as user data + class_addIvar(delegate_class, WindowDelegate::state_ivar_name().as_ptr() as *const i8, + ptr_size as u64, 3, + CString::from_slice("?".as_bytes()).as_ptr()); + objc_registerClassPair(delegate_class); + // Free class at exit + rt::at_exit(|| { + // objc_disposeClassPair(delegate_class); + }); + }); + delegate_class + } + } + + fn new(window: id) -> WindowDelegate { + unsafe { + let delegate: id = msg_send()(WindowDelegate::class(), selector("new")); + let _: id = msg_send()(window, selector("setDelegate:"), delegate); + WindowDelegate { this: delegate } + } + } + + unsafe fn set_state(&self, state: *mut DelegateState) { + object_setInstanceVariable(self.this, + WindowDelegate::state_ivar_name().as_ptr() as *const i8, + state as *mut libc::c_void); + } + + fn get_state(&self) -> *mut DelegateState { + unsafe { + let mut state = ptr::null_mut(); + object_getInstanceVariable(self.this, + WindowDelegate::state_ivar_name().as_ptr() as *const i8, + &mut state); + state as *mut DelegateState + } + } +} + pub struct Window { view: id, window: id, context: id, - delegate: id, + delegate: WindowDelegate, resize: Option, is_closed: Cell, @@ -96,34 +196,6 @@ impl WindowProxy { } } -extern fn window_should_close(this: id, _: id) -> id { - unsafe { - let mut stored_value = ptr::null_mut(); - object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); - let state = stored_value as *mut DelegateState; - - (*state).is_closed = true; - } - 0 -} - -extern fn window_did_resize(this: id, _: id) -> id { - unsafe { - let mut stored_value = ptr::null_mut(); - object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); - let state = &mut *(stored_value as *mut DelegateState); - - let _: id = msg_send()(state.context, selector("update")); - - if let Some(handler) = state.handler { - let rect = NSView::frame(state.view); - let scale_factor = state.window.backingScaleFactor() as f32; - (handler)((scale_factor * rect.size.width as f32) as u32, (scale_factor * rect.size.height as f32) as u32); - } - } - 0 -} - impl Window { #[cfg(feature = "window")] pub fn new(builder: BuilderAttribs) -> Result { @@ -161,29 +233,11 @@ impl Window { } } - // Set up the window delegate to receive events - let ptr_size = mem::size_of::() as u64; - let ns_object = class("NSObject"); - - let delegate = unsafe { - // Create a delegate class, add callback methods and store InternalState as user data. - let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); - class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, CString::from_slice("B@:@".as_bytes()).as_ptr()); - class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, CString::from_slice("V@:@".as_bytes()).as_ptr()); - class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, CString::from_slice("?".as_bytes()).as_ptr()); - objc_registerClassPair(delegate); - - let del_obj = msg_send()(delegate, selector("alloc")); - let del_obj: id = msg_send()(del_obj, selector("init")); - let _: id = msg_send()(window, selector("setDelegate:"), del_obj); - del_obj - }; - let window = Window { view: view, window: window, context: context, - delegate: delegate, + delegate: WindowDelegate::new(window), resize: None, is_closed: Cell::new(false), @@ -363,13 +417,9 @@ impl Window { view: self.view, handler: self.resize, }; - object_setInstanceVariable(self.delegate, - DELEGATE_STATE_IVAR.as_ptr() as *const i8, - &mut ds as *mut DelegateState as *mut libc::c_void); + self.delegate.set_state(&mut ds); NSApp().sendEvent_(event); - object_setInstanceVariable(self.delegate, - DELEGATE_STATE_IVAR.as_ptr() as *const i8, - ptr::null_mut()); + self.delegate.set_state(ptr::null_mut()); self.is_closed.set(ds.is_closed); } -- cgit v1.2.3