aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/window.rs9
-rw-r--r--src/android/mod.rs3
-rw-r--r--src/lib.rs12
-rw-r--r--src/osx/mod.rs110
-rw-r--r--src/win32/mod.rs6
-rw-r--r--src/x11/headless.rs3
-rw-r--r--src/x11/window/mod.rs3
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")]
diff --git a/src/lib.rs b/src/lib.rs
index 029b576..a1c0a28 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)>) {
+ }
}