Add callback function to allow resize messages to be sent on mac.

This commit is contained in:
Glenn Watson 2014-12-16 15:49:22 +10:00
parent 0164449955
commit 0ad9c3d453
6 changed files with 102 additions and 32 deletions

View file

@ -273,6 +273,9 @@ impl Window {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGlEs ::Api::OpenGlEs
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }
#[cfg(feature = "window")] #[cfg(feature = "window")]

View file

@ -482,6 +482,13 @@ impl Window {
proxy: self.window.create_window_proxy() proxy: self.window.create_window_proxy()
} }
} }
/// Sets a resize callback that is called by Mac (and potentially other
/// operating systems) during resize operations. This can be used to repaint
/// during window resizing.
pub fn set_window_resize_callback(&mut self, callback: fn(uint, uint)) {
self.window.set_window_resize_callback(callback);
}
} }
#[cfg(feature = "window")] #[cfg(feature = "window")]
@ -542,6 +549,9 @@ impl HeadlessContext {
pub fn get_api(&self) -> Api { pub fn get_api(&self) -> Api {
self.context.get_api() self.context.get_api()
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }
#[cfg(feature = "headless")] #[cfg(feature = "headless")]

View file

@ -18,12 +18,12 @@ use core_foundation::base::TCFType;
use core_foundation::string::CFString; use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
use std::cell::Cell;
use std::c_str::CString; use std::c_str::CString;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::sync::atomic::{AtomicBool, Relaxed};
use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, Resized, MouseWheel};
use events::ElementState::{Pressed, Released}; use events::ElementState::{Pressed, Released};
use events::MouseButton::{LeftMouseButton, RightMouseButton}; use events::MouseButton::{LeftMouseButton, RightMouseButton};
use events; use events;
@ -42,25 +42,24 @@ static mut win_pressed: bool = false;
static mut alt_pressed: bool = false; static mut alt_pressed: bool = false;
static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0";
static DELEGATE_THIS_IVAR: &'static [u8] = b"glutin_this"; static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state";
struct InternalState { struct DelegateState<'a> {
is_closed: AtomicBool, is_closed: bool,
} context: id,
view: id,
impl InternalState { window: &'a Window,
fn new() -> InternalState { handler: fn(uint, uint),
InternalState {
is_closed: AtomicBool::new(false),
}
}
} }
pub struct Window { pub struct Window {
view: id, view: id,
window: id, window: id,
context: id, context: id,
state: Box<InternalState>, delegate: id,
resize: fn(uint, uint),
is_closed: Cell<bool>,
} }
#[cfg(feature = "window")] #[cfg(feature = "window")]
@ -103,9 +102,24 @@ impl WindowProxy {
extern fn window_should_close(this: id, _: id) -> id { extern fn window_should_close(this: id, _: id) -> id {
unsafe { unsafe {
let mut stored_value = ptr::null_mut(); let mut stored_value = ptr::null_mut();
object_getInstanceVariable(this, DELEGATE_THIS_IVAR.as_ptr() as *const i8, &mut stored_value); object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value);
let state = stored_value as *mut InternalState; let state = stored_value as *mut DelegateState;
(*state).is_closed.store(true, Relaxed);
(*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"));
let rect = NSView::frame(state.view);
(state.handler)(rect.size.width as uint, rect.size.height as uint);
} }
0 0
} }
@ -136,34 +150,41 @@ impl Window {
window.makeKeyAndOrderFront_(nil); window.makeKeyAndOrderFront_(nil);
} }
let window = Window {
view: view,
window: window,
context: context,
state: box InternalState::new(),
};
// Set up the window delegate to receive events // Set up the window delegate to receive events
let ptr_size = mem::size_of::<libc::intptr_t>() as u64; let ptr_size = mem::size_of::<libc::intptr_t>() as u64;
let ns_object = class("NSObject"); let ns_object = class("NSObject");
unsafe { let delegate = unsafe {
// Create a delegate class, add callback methods and store InternalState as user data. // 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); 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_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()); class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, "V@:@".to_c_str().as_ptr());
class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr());
objc_registerClassPair(delegate); objc_registerClassPair(delegate);
let del_obj = msg_send()(delegate, selector("alloc")); let del_obj = msg_send()(delegate, selector("alloc"));
let del_obj: id = msg_send()(del_obj, selector("init")); let del_obj: id = msg_send()(del_obj, selector("init"));
object_setInstanceVariable(del_obj, DELEGATE_THIS_IVAR.as_ptr() as *const i8, let _: id = msg_send()(window, selector("setDelegate:"), del_obj);
&*window.state as *const InternalState as *mut libc::c_void); del_obj
let _: id = msg_send()(window.window, selector("setDelegate:"), del_obj); };
}
let window = Window {
view: view,
window: window,
context: context,
delegate: delegate,
resize: Window::resize,
is_closed: Cell::new(false),
};
Ok(window) Ok(window)
} }
fn resize(_: uint, _: uint) {
}
fn create_app() -> Option<id> { fn create_app() -> Option<id> {
unsafe { unsafe {
let app = NSApp(); let app = NSApp();
@ -267,7 +288,7 @@ impl Window {
} }
pub fn is_closed(&self) -> bool { pub fn is_closed(&self) -> bool {
self.state.is_closed.load(Relaxed) self.is_closed.get()
} }
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
@ -319,7 +340,27 @@ impl Window {
NSDefaultRunLoopMode, NSDefaultRunLoopMode,
true); true);
if event == nil { break; } if event == nil { break; }
{
// Create a temporary structure with state that delegates called internally
// by sendEvent can read and modify. When that returns, update window state.
// This allows the synchronous resize loop to continue issuing callbacks
// to the user application, by passing handler through to the delegate state.
let mut ds = DelegateState {
is_closed: self.is_closed.get(),
context: self.context,
view: self.view,
window: self,
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);
NSApp().sendEvent_(event); NSApp().sendEvent_(event);
object_setInstanceVariable(self.delegate,
DELEGATE_STATE_IVAR.as_ptr() as *const i8,
ptr::null_mut());
self.is_closed.set(ds.is_closed);
}
match event.get_type() { match event.get_type() {
NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); }, NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); },
@ -434,4 +475,8 @@ impl Window {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGl ::Api::OpenGl
} }
pub fn set_window_resize_callback(&mut self, callback: fn(uint, uint)) {
self.resize = callback;
}
} }

View file

@ -46,6 +46,9 @@ impl HeadlessContext {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGl ::Api::OpenGl
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }
/// The Win32 implementation of the main `Window` object. /// The Win32 implementation of the main `Window` object.
@ -276,6 +279,9 @@ impl Window {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGl ::Api::OpenGl
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }
#[unsafe_destructor] #[unsafe_destructor]

View file

@ -52,6 +52,9 @@ impl HeadlessContext {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGl ::Api::OpenGl
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }
impl Drop for HeadlessContext { impl Drop for HeadlessContext {

View file

@ -598,4 +598,7 @@ impl Window {
pub fn get_api(&self) -> ::Api { pub fn get_api(&self) -> ::Api {
::Api::OpenGl ::Api::OpenGl
} }
pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) {
}
} }