From 0ad9c3d453076adc5d94008d7e155d7ee5536225 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 16 Dec 2014 15:49:22 +1000 Subject: Add callback function to allow resize messages to be sent on mac. --- src/android/mod.rs | 3 ++ src/lib.rs | 10 +++++ src/osx/mod.rs | 109 +++++++++++++++++++++++++++++++++++--------------- src/win32/mod.rs | 6 +++ src/x11/headless.rs | 3 ++ src/x11/window/mod.rs | 3 ++ 6 files changed, 102 insertions(+), 32 deletions(-) diff --git a/src/android/mod.rs b/src/android/mod.rs index 8bc82ce..ad9d00a 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, _: fn(uint, uint)) { + } } #[cfg(feature = "window")] diff --git a/src/lib.rs b/src/lib.rs index 029b576..48fcc85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -482,6 +482,13 @@ 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. + pub fn set_window_resize_callback(&mut self, callback: fn(uint, uint)) { + self.window.set_window_resize_callback(callback); + } } #[cfg(feature = "window")] @@ -542,6 +549,9 @@ impl HeadlessContext { pub fn get_api(&self) -> Api { self.context.get_api() } + + pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + } } #[cfg(feature = "headless")] diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 42a9ea2..2634491 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,24 @@ 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, + window: &'a Window, + handler: fn(uint, uint), } pub struct Window { view: id, window: id, context: id, - state: Box, + delegate: id, + resize: fn(uint, uint), + + is_closed: Cell, } #[cfg(feature = "window")] @@ -103,9 +102,24 @@ 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")); + + let rect = NSView::frame(state.view); + (state.handler)(rect.size.width as uint, rect.size.height as uint); } 0 } @@ -136,34 +150,41 @@ 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::() 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: Window::resize, + + is_closed: Cell::new(false), + }; Ok(window) } + fn resize(_: uint, _: uint) { + + } + fn create_app() -> Option { unsafe { let app = NSApp(); @@ -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,27 @@ 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, + 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); + 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 +475,8 @@ impl Window { pub fn get_api(&self) -> ::Api { ::Api::OpenGl } + + pub fn set_window_resize_callback(&mut self, callback: fn(uint, uint)) { + self.resize = callback; + } } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 978e3b5..2e0dcae 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, _: 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, _: fn(uint, uint)) { + } } #[unsafe_destructor] diff --git a/src/x11/headless.rs b/src/x11/headless.rs index 78fb985..3bcea29 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, _: fn(uint, uint)) { + } } impl Drop for HeadlessContext { diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index a0e7078..0a3ba01 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, _: fn(uint, uint)) { + } } -- cgit v1.2.3 From fa5cb66cff2e13a5ee75c4f99abe5f93bede7dd1 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 17 Dec 2014 09:41:27 +1000 Subject: Add resize example, fix warnings, make callback an option so it can be removed. --- examples/window.rs | 9 +++++++-- src/android/mod.rs | 2 +- src/lib.rs | 4 ++-- src/osx/mod.rs | 25 ++++++++++++------------- src/win32/mod.rs | 4 ++-- src/x11/headless.rs | 2 +- src/x11/window/mod.rs | 2 +- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/examples/window.rs b/examples/window.rs index e947234..dce8f3a 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -14,11 +14,16 @@ android_start!(main) #[cfg(not(feature = "window"))] 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 ad9d00a..3a86779 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -274,7 +274,7 @@ impl Window { ::Api::OpenGlEs } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } diff --git a/src/lib.rs b/src/lib.rs index 48fcc85..eee166b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -486,7 +486,7 @@ impl Window { /// 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)) { + pub fn set_window_resize_callback(&mut self, callback: Option) { self.window.set_window_resize_callback(callback); } } @@ -550,7 +550,7 @@ impl HeadlessContext { self.context.get_api() } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 2634491..110113b 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -48,8 +48,7 @@ struct DelegateState<'a> { is_closed: bool, context: id, view: id, - window: &'a Window, - handler: fn(uint, uint), + handler: Option, } pub struct Window { @@ -57,7 +56,7 @@ pub struct Window { window: id, context: id, delegate: id, - resize: fn(uint, uint), + resize: Option, is_closed: Cell, } @@ -118,15 +117,20 @@ extern fn window_did_resize(this: id, _: id) -> id { 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); + 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, - vsync: bool, visible: bool) -> Result { + vsync: bool, _visible: bool) -> Result { let app = match Window::create_app() { Some(app) => app, None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, @@ -173,7 +177,7 @@ impl Window { window: window, context: context, delegate: delegate, - resize: Window::resize, + resize: None, is_closed: Cell::new(false), }; @@ -181,10 +185,6 @@ impl Window { Ok(window) } - fn resize(_: uint, _: uint) { - - } - fn create_app() -> Option { unsafe { let app = NSApp(); @@ -349,7 +349,6 @@ impl Window { is_closed: self.is_closed.get(), context: self.context, view: self.view, - window: self, handler: self.resize, }; object_setInstanceVariable(self.delegate, @@ -476,7 +475,7 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, callback: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, callback: Option) { self.resize = callback; } } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 2e0dcae..f900c1f 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -47,7 +47,7 @@ impl HeadlessContext { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } @@ -280,7 +280,7 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } diff --git a/src/x11/headless.rs b/src/x11/headless.rs index 3bcea29..95f5233 100644 --- a/src/x11/headless.rs +++ b/src/x11/headless.rs @@ -53,7 +53,7 @@ impl HeadlessContext { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index 0a3ba01..422b5b6 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -599,6 +599,6 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: fn(uint, uint)) { + pub fn set_window_resize_callback(&mut self, _: Option) { } } -- cgit v1.2.3 From f2d112213ba889eddb6c1b0fab878bcd4f500c64 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 19 Dec 2014 05:06:56 +1000 Subject: Add experimental attribute since this API will need to be cleaned up. --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index eee166b..a1c0a28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -486,6 +486,7 @@ impl Window { /// 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) { self.window.set_window_resize_callback(callback); } @@ -550,6 +551,7 @@ impl HeadlessContext { self.context.get_api() } + #[experimental] pub fn set_window_resize_callback(&mut self, _: Option) { } } -- cgit v1.2.3