diff options
| author | Glenn Watson <gw@intuitionlibrary.com> | 2014-11-19 10:09:29 +1000 | 
|---|---|---|
| committer | Glenn Watson <gw@intuitionlibrary.com> | 2014-11-21 07:08:05 +1000 | 
| commit | cac0025abbbb90130a14bd8e601b47d371a5d31c (patch) | |
| tree | 1d838650506e3597618a16dcc04b1a616ffb2ca3 /src/osx | |
| parent | 696dcc9216e2323e2d34abbc2ebd520586cb9018 (diff) | |
| download | glutin-cac0025abbbb90130a14bd8e601b47d371a5d31c.tar.gz glutin-cac0025abbbb90130a14bd8e601b47d371a5d31c.zip  | |
Add support for setting a window delegate, and implement close event on mac.
Diffstat (limited to 'src/osx')
| -rw-r--r-- | src/osx/mod.rs | 63 | 
1 files changed, 56 insertions, 7 deletions
diff --git a/src/osx/mod.rs b/src/osx/mod.rs index fb10a57..64cc529 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -1,7 +1,6 @@  use {CreationError, Event};  use CreationError::OsError;  use libc; -use std::sync::atomic::AtomicBool;  #[cfg(feature = "window")]  use WindowBuilder; @@ -9,7 +8,9 @@ use WindowBuilder;  #[cfg(feature = "headless")]  use HeadlessRendererBuilder; -use cocoa::base::{id, NSUInteger, nil}; +use cocoa::base::{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;  use cocoa::appkit::*; @@ -18,6 +19,9 @@ use core_foundation::string::CFString;  use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};  use std::c_str::CString; +use std::mem; +use std::ptr; +use std::sync::atomic::{AtomicBool, Relaxed};  use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput};  use events::ElementState::{Pressed, Released}; @@ -34,11 +38,26 @@ 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_THIS_IVAR: &'static [u8] = b"glutin_this"; + +struct InternalState { +    is_closed: AtomicBool, +} + +impl InternalState { +    fn new() -> InternalState { +        InternalState { +            is_closed: AtomicBool::new(false), +        } +    } +} +  pub struct Window {      view: id,      window: id,      context: id, -    is_closed: AtomicBool, +    state: Box<InternalState>,  }  pub struct HeadlessContext(Window); @@ -64,6 +83,16 @@ impl HeadlessContext {      }  } +extern fn window_should_close(this: id, _: id) -> id { +    unsafe { +        let mut stored_value = ptr::null_mut(); +        object_getInstanceVariable(this, DELEGATE_THIS_IVAR.as_ptr() as *const i8, &mut stored_value); +        let state = stored_value as *mut InternalState; +        (*state).is_closed.store(true, Relaxed); +    } +    0 +} +  impl Window {      fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, visible: bool) -> Result<Window, CreationError> {          let app = match Window::create_app() { @@ -93,9 +122,27 @@ impl Window {              view: view,              window: window,              context: context, -            is_closed: AtomicBool::new(false), +            state: box InternalState::new(),          }; +        // Set up the window delegate to receive events +        let ptr_size = mem::size_of::<libc::intptr_t>() as u64; +        let ns_object = class("NSObject"); + +        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, "B@:@".to_c_str().as_ptr()); +            class_addIvar(delegate, DELEGATE_THIS_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr()); +            objc_registerClassPair(delegate); + +            let del_obj = msg_send()(delegate, selector("alloc")); +            let del_obj: id = msg_send()(del_obj, selector("init")); +            object_setInstanceVariable(del_obj, DELEGATE_THIS_IVAR.as_ptr() as *const i8, +                                        &*window.state as *const InternalState as *mut libc::c_void); +            let _: id = msg_send()(window.window, selector("setDelegate:"), del_obj); +        } +          Ok(window)      } @@ -127,7 +174,10 @@ impl Window {               let masks = match monitor {                  Some(_) => NSBorderlessWindowMask as NSUInteger, -                None    => NSTitledWindowMask as NSUInteger | NSClosableWindowMask as NSUInteger | NSMiniaturizableWindowMask as NSUInteger, +                None    => NSTitledWindowMask as NSUInteger | +                           NSClosableWindowMask as NSUInteger | +                           NSMiniaturizableWindowMask as NSUInteger | +                           NSResizableWindowMask as NSUInteger,              };              let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_( @@ -193,8 +243,7 @@ impl Window {      }      pub fn is_closed(&self) -> bool { -        use std::sync::atomic::Relaxed; -        self.is_closed.load(Relaxed) +        self.state.is_closed.load(Relaxed)      }      pub fn set_title(&self, title: &str) {  | 
