diff options
| author | Brendan Zabarauskas <bjzaba@yahoo.com.au> | 2015-01-20 22:38:25 +1100 | 
|---|---|---|
| committer | Brendan Zabarauskas <bjzaba@yahoo.com.au> | 2015-01-20 22:38:25 +1100 | 
| commit | 4d12d3ea3d44a4e63297a5a4f342301ac2fa6070 (patch) | |
| tree | 3c5f196990cc0428590c5d316e32c1dadb93fc98 /src | |
| parent | d48ccb381a99948f05bf09ee3a6bf0580d77392d (diff) | |
| parent | de8fe684e7c8d7a37c98f045c9fe3b8551e1e83b (diff) | |
| download | glutin-4d12d3ea3d44a4e63297a5a4f342301ac2fa6070.tar.gz glutin-4d12d3ea3d44a4e63297a5a4f342301ac2fa6070.zip  | |
Merge pull request #214 from bjz/osx-window
Move osx delegate stuff into separate type
Diffstat (limited to 'src')
| -rw-r--r-- | src/osx/mod.rs | 171 | 
1 files changed, 109 insertions, 62 deletions
diff --git a/src/osx/mod.rs b/src/osx/mod.rs index b338184..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<fn(u32, u32)>,  } +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::<libc::intptr_t>(); +                    // 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<fn(u32, u32)>,      is_closed: Cell<bool>, @@ -96,37 +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")); - -        match state.handler { -            Some(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); -            } -            None => {} -        } -    } -    0 -} -  impl Window {      #[cfg(feature = "window")]      pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { @@ -164,29 +233,11 @@ impl Window {              }          } -        // Set up the window delegate to receive events -        let ptr_size = mem::size_of::<libc::intptr_t>() 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), @@ -366,15 +417,11 @@ 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); -} +                }                  match event.get_type() {                      NSLeftMouseDown         => { events.push_back(MouseInput(Pressed, LeftMouseButton)); },  | 
