diff options
-rw-r--r-- | examples/window.rs | 9 | ||||
-rw-r--r-- | src/android/mod.rs | 3 | ||||
-rw-r--r-- | src/lib.rs | 12 | ||||
-rw-r--r-- | src/osx/mod.rs | 110 | ||||
-rw-r--r-- | src/win32/mod.rs | 6 | ||||
-rw-r--r-- | src/x11/headless.rs | 3 | ||||
-rw-r--r-- | src/x11/window/mod.rs | 3 |
7 files changed, 111 insertions, 35 deletions
diff --git a/examples/window.rs b/examples/window.rs index e947234..dce8f3a 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -15,10 +15,15 @@ android_start!(main) fn main() { println!("This example requires glutin to be compiled with the `window` feature"); } #[cfg(feature = "window")] +fn resize_callback(width: uint, height: uint) { + println!("Window resized to {}x{}", width, height); +} + +#[cfg(feature = "window")] fn main() { - let window = glutin::Window::new().unwrap(); + let mut window = glutin::Window::new().unwrap(); window.set_title("A fantastic window!"); - + window.set_window_resize_callback(Some(resize_callback)); unsafe { window.make_current() }; let context = support::load(&window); diff --git a/src/android/mod.rs b/src/android/mod.rs index 8bc82ce..3a86779 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -273,6 +273,9 @@ impl Window { pub fn get_api(&self) -> ::Api { ::Api::OpenGlEs } + + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } #[cfg(feature = "window")] @@ -482,6 +482,14 @@ impl Window { 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. + #[experimental] + pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + self.window.set_window_resize_callback(callback); + } } #[cfg(feature = "window")] @@ -542,6 +550,10 @@ impl HeadlessContext { pub fn get_api(&self) -> Api { self.context.get_api() } + + #[experimental] + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } #[cfg(feature = "headless")] diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 42a9ea2..110113b 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -18,12 +18,12 @@ use core_foundation::base::TCFType; use core_foundation::string::CFString; use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; +use std::cell::Cell; use std::c_str::CString; use std::mem; 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::MouseButton::{LeftMouseButton, RightMouseButton}; use events; @@ -42,25 +42,23 @@ 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"; +static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; -struct InternalState { - is_closed: AtomicBool, -} - -impl InternalState { - fn new() -> InternalState { - InternalState { - is_closed: AtomicBool::new(false), - } - } +struct DelegateState<'a> { + is_closed: bool, + context: id, + view: id, + handler: Option<fn(uint, uint)>, } pub struct Window { view: id, window: id, context: id, - state: Box<InternalState>, + delegate: id, + resize: Option<fn(uint, uint)>, + + is_closed: Cell<bool>, } #[cfg(feature = "window")] @@ -103,16 +101,36 @@ impl WindowProxy { 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); + 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); + (handler)(rect.size.width as uint, rect.size.height as uint); + } + None => {} + } } 0 } impl Window { fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, - vsync: bool, visible: bool) -> Result<Window, CreationError> { + vsync: bool, _visible: bool) -> Result<Window, CreationError> { let app = match Window::create_app() { Some(app) => app, None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, @@ -136,30 +154,33 @@ impl Window { window.makeKeyAndOrderFront_(nil); } - let window = Window { - view: view, - window: window, - context: context, - 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 { + 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, "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); 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); - } + let _: id = msg_send()(window, selector("setDelegate:"), del_obj); + del_obj + }; + + let window = Window { + view: view, + window: window, + context: context, + delegate: delegate, + resize: None, + + is_closed: Cell::new(false), + }; Ok(window) } @@ -267,7 +288,7 @@ impl Window { } pub fn is_closed(&self) -> bool { - self.state.is_closed.load(Relaxed) + self.is_closed.get() } pub fn set_title(&self, title: &str) { @@ -319,7 +340,26 @@ impl Window { NSDefaultRunLoopMode, true); if event == nil { break; } - NSApp().sendEvent_(event); + { + // 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, + 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); + 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() { NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); }, @@ -434,4 +474,8 @@ impl Window { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + self.resize = callback; + } } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 978e3b5..f900c1f 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -46,6 +46,9 @@ impl HeadlessContext { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } /// The Win32 implementation of the main `Window` object. @@ -276,6 +279,9 @@ impl Window { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } #[unsafe_destructor] diff --git a/src/x11/headless.rs b/src/x11/headless.rs index 78fb985..95f5233 100644 --- a/src/x11/headless.rs +++ b/src/x11/headless.rs @@ -52,6 +52,9 @@ impl HeadlessContext { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } impl Drop for HeadlessContext { diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index a0e7078..422b5b6 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -598,4 +598,7 @@ impl Window { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + } } |