aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortomaka <pierre.krieger1708@gmail.com>2015-02-10 22:34:18 +0100
committertomaka <pierre.krieger1708@gmail.com>2015-02-10 22:34:18 +0100
commit4500702a0294065f876ca10e7629fd32e213ca76 (patch)
tree0bf6f0f1580345f6441765e6e74cc64bcaf7e79a /src
parent605bd37554655436841e4cd2c4fbb3d046de2330 (diff)
parent95b1c96181e538004800942ae8ab07a81ec49454 (diff)
downloadglutin-4500702a0294065f876ca10e7629fd32e213ca76.tar.gz
glutin-4500702a0294065f876ca10e7629fd32e213ca76.zip
Merge pull request #70 from tomaka/fix-iterators
Use platform-specific iterators instead
Diffstat (limited to 'src')
-rw-r--r--src/android/mod.rs78
-rw-r--r--src/cocoa/mod.rs260
-rw-r--r--src/lib.rs34
-rw-r--r--src/win32/mod.rs90
-rw-r--r--src/x11/mod.rs2
-rw-r--r--src/x11/window/mod.rs317
6 files changed, 440 insertions, 341 deletions
diff --git a/src/android/mod.rs b/src/android/mod.rs
index ec6e1a3..5f05300 100644
--- a/src/android/mod.rs
+++ b/src/android/mod.rs
@@ -74,6 +74,52 @@ unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}
+pub struct PollEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for PollEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ match self.window.event_rx.try_recv() {
+ Ok(event) => {
+ Some(match event {
+ android_glue::Event::EventDown => MouseInput(Pressed, MouseButton::Left),
+ android_glue::Event::EventUp => MouseInput(Released, MouseButton::Left),
+ android_glue::Event::EventMove(x, y) => MouseMoved((x as i32, y as i32)),
+ })
+ }
+ Err(_) => {
+ None
+ }
+ }
+ }
+}
+
+pub struct WaitEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for WaitEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ use std::time::Duration;
+ use std::old_io::timer;
+
+ loop {
+ // calling poll_events()
+ if let Some(ev) = self.window.poll_events().next() {
+ return Some(ev);
+ }
+
+ // TODO: Implement a proper way of sleeping on the event queue
+ timer::sleep(Duration::milliseconds(16));
+ }
+ }
+}
+
impl Window {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
use std::{mem, ptr};
@@ -242,34 +288,16 @@ impl Window {
WindowProxy
}
- pub fn poll_events(&self) -> RingBuf<Event> {
- let mut events = RingBuf::new();
- loop {
- match self.event_rx.try_recv() {
- Ok(event) => match event {
- android_glue::Event::EventDown => {
- events.push_back(MouseInput(Pressed, MouseButton::Left));
- },
- android_glue::Event::EventUp => {
- events.push_back(MouseInput(Released, MouseButton::Left));
- },
- android_glue::Event::EventMove(x, y) => {
- events.push_back(MouseMoved((x as i32, y as i32)));
- },
- },
- Err(_) => {
- break;
- },
- }
+ pub fn poll_events(&self) -> PollEventsIterator {
+ PollEventsIterator {
+ window: self
}
- events
}
- pub fn wait_events(&self) -> RingBuf<Event> {
- use std::time::Duration;
- use std::old_io::timer;
- timer::sleep(Duration::milliseconds(16));
- self.poll_events()
+ pub fn wait_events(&self) -> WaitEventsIterator {
+ WaitEventsIterator {
+ window: self
+ }
}
pub fn make_current(&self) {
diff --git a/src/cocoa/mod.rs b/src/cocoa/mod.rs
index 44a92cd..98b1879 100644
--- a/src/cocoa/mod.rs
+++ b/src/cocoa/mod.rs
@@ -25,6 +25,7 @@ use std::ptr;
use std::collections::RingBuf;
use std::str::FromStr;
use std::str::from_utf8;
+use std::sync::Mutex;
use std::ascii::AsciiExt;
use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel};
@@ -164,6 +165,9 @@ pub struct Window {
resize: Option<fn(u32, u32)>,
is_closed: Cell<bool>,
+
+ /// Events that have been retreived with XLib but not dispatched with iterators yet
+ pending_events: Mutex<RingBuf<Event>>,
}
#[cfg(feature = "window")]
@@ -189,6 +193,146 @@ impl WindowProxy {
}
}
+pub struct PollEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for PollEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
+ return Some(ev);
+ }
+
+ unsafe {
+ let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
+ NSAnyEventMask.bits(),
+ NSDate::distantPast(nil),
+ NSDefaultRunLoopMode,
+ YES);
+ if event == nil { return None; }
+ {
+ // 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.window.is_closed.get(),
+ context: self.window.context,
+ window: self.window.window,
+ view: self.window.view,
+ handler: self.window.resize,
+ };
+ self.window.delegate.set_state(&mut ds);
+ NSApp().sendEvent_(event);
+ self.window.delegate.set_state(ptr::null_mut());
+ self.window.is_closed.set(ds.is_closed);
+ }
+
+ let event = match msg_send()(event, selector("type")) {
+ NSLeftMouseDown => { Some(MouseInput(Pressed, MouseButton::Left)) },
+ NSLeftMouseUp => { Some(MouseInput(Released, MouseButton::Left)) },
+ NSRightMouseDown => { Some(MouseInput(Pressed, MouseButton::Right)) },
+ NSRightMouseUp => { Some(MouseInput(Released, MouseButton::Right)) },
+ NSMouseMoved => {
+ let window_point = event.locationInWindow();
+ let window: id = msg_send()(event, selector("window"));
+ let view_point = if window == 0 {
+ let window_rect = self.window.window.convertRectFromScreen_(NSRect::new(window_point, NSSize::new(0.0, 0.0)));
+ self.window.view.convertPoint_fromView_(window_rect.origin, nil)
+ } else {
+ self.window.view.convertPoint_fromView_(window_point, nil)
+ };
+ let view_rect = NSView::frame(self.window.view);
+ let scale_factor = self.window.hidpi_factor();
+ Some(MouseMoved(((scale_factor * view_point.x as f32) as i32,
+ (scale_factor * (view_rect.size.height - view_point.y) as f32) as i32)))
+ },
+ NSKeyDown => {
+ let mut events = RingBuf::new();
+ let received_c_str = event.characters().UTF8String();
+ let received_str = CString::from_slice(c_str_to_bytes(&received_c_str));
+ for received_char in from_utf8(received_str.as_bytes()).unwrap().chars() {
+ if received_char.is_ascii() {
+ events.push_back(ReceivedCharacter(received_char));
+ }
+ }
+
+ let vkey = event::vkeycode_to_element(NSEvent::keyCode(event));
+ events.push_back(KeyboardInput(Pressed, NSEvent::keyCode(event) as u8, vkey));
+ let event = events.pop_front();
+ self.window.pending_events.lock().unwrap().extend(events.into_iter());
+ event
+ },
+ NSKeyUp => {
+ let vkey = event::vkeycode_to_element(NSEvent::keyCode(event));
+ Some(KeyboardInput(Released, NSEvent::keyCode(event) as u8, vkey))
+ },
+ NSFlagsChanged => {
+ let mut events = RingBuf::new();
+ let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask, events::VirtualKeyCode::LShift, shift_pressed);
+ if shift_modifier.is_some() {
+ shift_pressed = !shift_pressed;
+ events.push_back(shift_modifier.unwrap());
+ }
+ let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask, events::VirtualKeyCode::LControl, ctrl_pressed);
+ if ctrl_modifier.is_some() {
+ ctrl_pressed = !ctrl_pressed;
+ events.push_back(ctrl_modifier.unwrap());
+ }
+ let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask, events::VirtualKeyCode::LWin, win_pressed);
+ if win_modifier.is_some() {
+ win_pressed = !win_pressed;
+ events.push_back(win_modifier.unwrap());
+ }
+ let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask, events::VirtualKeyCode::LAlt, alt_pressed);
+ if alt_modifier.is_some() {
+ alt_pressed = !alt_pressed;
+ events.push_back(alt_modifier.unwrap());
+ }
+ let event = events.pop_front();
+ self.window.pending_events.lock().unwrap().extend(events.into_iter());
+ event
+ },
+ NSScrollWheel => { Some(MouseWheel(-event.scrollingDeltaY() as i32)) },
+ _ => { None },
+ };
+
+ event
+ }
+ }
+}
+
+pub struct WaitEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for WaitEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ loop {
+ if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
+ return Some(ev);
+ }
+
+ unsafe {
+ let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
+ NSAnyEventMask.bits(),
+ NSDate::distantFuture(nil),
+ NSDefaultRunLoopMode,
+ NO);
+ }
+
+ // calling poll_events()
+ if let Some(ev) = self.window.poll_events().next() {
+ return Some(ev);
+ }
+ }
+ }
+}
+
impl Window {
#[cfg(feature = "window")]
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
@@ -234,6 +378,7 @@ impl Window {
resize: None,
is_closed: Cell::new(false),
+ pending_events: Mutex::new(RingBuf::new()),
};
Ok(window)
@@ -403,102 +548,16 @@ impl Window {
WindowProxy
}
- pub fn poll_events(&self) -> RingBuf<Event> {
- let mut events = RingBuf::new();
-
- loop {
- unsafe {
- let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
- NSAnyEventMask.bits(),
- NSDate::distantPast(nil),
- NSDefaultRunLoopMode,
- YES);
- 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,
- window: self.window,
- view: self.view,
- handler: self.resize,
- };
- self.delegate.set_state(&mut ds);
- NSApp().sendEvent_(event);
- self.delegate.set_state(ptr::null_mut());
- self.is_closed.set(ds.is_closed);
- }
-
- match msg_send()(event, selector("type")) {
- NSLeftMouseDown => { events.push_back(MouseInput(Pressed, MouseButton::Left)); },
- NSLeftMouseUp => { events.push_back(MouseInput(Released, MouseButton::Left)); },
- NSRightMouseDown => { events.push_back(MouseInput(Pressed, MouseButton::Right)); },
- NSRightMouseUp => { events.push_back(MouseInput(Released, MouseButton::Right)); },
- NSMouseMoved => {
- let window_point: NSPoint = msg_send()(event, selector("locationInWindow"));
- // let window_point = event.locationInWindow();
- let window: id = msg_send()(event, selector("window"));
- let view_point = if window == 0 {
- let window_rect = self.window.convertRectFromScreen_(NSRect::new(window_point, NSSize::new(0.0, 0.0)));
- self.view.convertPoint_fromView_(window_rect.origin, nil)
- } else {
- self.view.convertPoint_fromView_(window_point, nil)
- };
- let view_rect = NSView::frame(self.view);
- let scale_factor = self.hidpi_factor();
- events.push_back(MouseMoved(((scale_factor * view_point.x as f32) as i32,
- (scale_factor * (view_rect.size.height - view_point.y) as f32) as i32)));
- },
- NSKeyDown => {
- let received_c_str = event.characters().UTF8String();
- let received_str = CString::from_slice(c_str_to_bytes(&received_c_str));
- for received_char in from_utf8(received_str.as_bytes()).unwrap().chars() {
- if received_char.is_ascii() {
- events.push_back(ReceivedCharacter(received_char));
- }
- }
+ pub fn poll_events(&self) -> PollEventsIterator {
+ PollEventsIterator {
+ window: self
+ }
+ }
- let vkey = event::vkeycode_to_element(NSEvent::keyCode(event));
- events.push_back(KeyboardInput(Pressed, NSEvent::keyCode(event) as u8, vkey));
- },
- NSKeyUp => {
- let vkey = event::vkeycode_to_element(NSEvent::keyCode(event));
- events.push_back(KeyboardInput(Released, NSEvent::keyCode(event) as u8, vkey));
- },
- NSFlagsChanged => {
- let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask, events::VirtualKeyCode::LShift, shift_pressed);
- if shift_modifier.is_some() {
- shift_pressed = !shift_pressed;
- events.push_back(shift_modifier.unwrap());
- }
- let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask, events::VirtualKeyCode::LControl, ctrl_pressed);
- if ctrl_modifier.is_some() {
- ctrl_pressed = !ctrl_pressed;
- events.push_back(ctrl_modifier.unwrap());
- }
- let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask, events::VirtualKeyCode::LWin, win_pressed);
- if win_modifier.is_some() {
- win_pressed = !win_pressed;
- events.push_back(win_modifier.unwrap());
- }
- let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask, events::VirtualKeyCode::LAlt, alt_pressed);
- if alt_modifier.is_some() {
- alt_pressed = !alt_pressed;
- events.push_back(alt_modifier.unwrap());
- }
- },
- NSScrollWheel => { events.push_back(MouseWheel(event.scrollingDeltaY() as i32)); },
- NSOtherMouseDown => { },
- NSOtherMouseUp => { },
- NSOtherMouseDragged => { },
- _ => { },
- }
- }
+ pub fn wait_events(&self) -> WaitEventsIterator {
+ WaitEventsIterator {
+ window: self
}
- events
}
unsafe fn modifier_event(event: id, keymask: NSEventModifierFlags, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> {
@@ -511,19 +570,6 @@ impl Window {
return None;
}
- pub fn wait_events(&self) -> RingBuf<Event> {
- unsafe {
- let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
- NSAnyEventMask.bits(),
- NSDate::distantFuture(nil),
- NSDefaultRunLoopMode,
- NO);
- NSApp().sendEvent_(event);
-
- self.poll_events()
- }
- }
-
pub unsafe fn make_current(&self) {
let _: id = msg_send()(self.context, selector("update"));
self.context.makeCurrentContext();
diff --git a/src/lib.rs b/src/lib.rs
index 85d373a..49c7474 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -592,7 +592,7 @@ impl Window {
/// Contrary to `wait_events`, this function never blocks.
#[inline]
pub fn poll_events(&self) -> PollEventsIterator {
- PollEventsIterator { window: self, data: self.window.poll_events().into_iter() }
+ PollEventsIterator(self.window.poll_events())
}
/// Returns an iterator that returns events one by one, blocking if necessary until one is
@@ -601,7 +601,7 @@ impl Window {
/// The iterator never returns `None`.
#[inline]
pub fn wait_events(&self) -> WaitEventsIterator {
- WaitEventsIterator { window: self, data: self.window.wait_events().into_iter() }
+ WaitEventsIterator(self.window.wait_events())
}
/// Sets the context as the current context.
@@ -754,24 +754,13 @@ impl gl_common::GlFunctionsSource for HeadlessContext {
// Implementation note: we retreive the list once, then serve each element by one by one.
// This may change in the future.
#[cfg(feature = "window")]
-pub struct PollEventsIterator<'a> {
- window: &'a Window,
- data: RingBufIter<Event>,
-}
+pub struct PollEventsIterator<'a>(winimpl::PollEventsIterator<'a>);
#[cfg(feature = "window")]
impl<'a> Iterator for PollEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
- if let Some(ev) = self.data.next() {
- return Some(ev);
- }
-
- let PollEventsIterator { window, data } = self.window.poll_events();
- self.window = window;
- self.data = data;
-
- self.data.next()
+ self.0.next()
}
}
@@ -779,24 +768,13 @@ impl<'a> Iterator for PollEventsIterator<'a> {
// Implementation note: we retreive the list once, then serve each element by one by one.
// This may change in the future.
#[cfg(feature = "window")]
-pub struct WaitEventsIterator<'a> {
- window: &'a Window,
- data: RingBufIter<Event>,
-}
+pub struct WaitEventsIterator<'a>(winimpl::WaitEventsIterator<'a>);
#[cfg(feature = "window")]
impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
- if let Some(ev) = self.data.next() {
- return Some(ev);
- }
-
- let WaitEventsIterator { window, data } = self.window.wait_events();
- self.window = window;
- self.data = data;
-
- self.next()
+ self.0.next()
}
}
diff --git a/src/win32/mod.rs b/src/win32/mod.rs
index beb7825..c502e3d 100644
--- a/src/win32/mod.rs
+++ b/src/win32/mod.rs
@@ -201,50 +201,16 @@ impl Window {
}
/// See the docs in the crate root file.
- // TODO: return iterator
- pub fn poll_events(&self) -> RingBuf<Event> {
- let mut events = RingBuf::new();
- loop {
- match self.events_receiver.try_recv() {
- Ok(ev) => events.push_back(ev),
- Err(_) => break
- }
+ pub fn poll_events(&self) -> PollEventsIterator {
+ PollEventsIterator {
+ window: self,
}
-
- // if one of the received events is `Closed`, setting `is_closed` to true
- if events.iter().any(|e| match e { &::events::Event::Closed => true, _ => false }) {
- use std::sync::atomic::Ordering::Relaxed;
- self.is_closed.store(true, Relaxed);
- }
-
- events
}
/// See the docs in the crate root file.
- // TODO: return iterator
- pub fn wait_events(&self) -> RingBuf<Event> {
- match self.events_receiver.recv() {
- Ok(ev) => {
- // if the received event is `Closed`, setting `is_closed` to true
- match ev {
- ::events::Event::Closed => {
- use std::sync::atomic::Ordering::Relaxed;
- self.is_closed.store(true, Relaxed);
- },
- _ => ()
- };
-
- // looing for other possible events in the queue
- let mut result = self.poll_events();
- result.insert(0, ev);
- result
- },
-
- Err(_) => {
- use std::sync::atomic::Ordering::Relaxed;
- self.is_closed.store(true, Relaxed);
- RingBuf::new()
- }
+ pub fn wait_events(&self) -> WaitEventsIterator {
+ WaitEventsIterator {
+ window: self,
}
}
@@ -294,6 +260,50 @@ impl Window {
}
}
+pub struct PollEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for PollEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ use events::Event::Closed;
+
+ match self.window.events_receiver.recv() {
+ Ok(Closed) => {
+ use std::sync::atomic::Ordering::Relaxed;
+ self.window.is_closed.store(true, Relaxed);
+ Some(Closed)
+ },
+ Ok(ev) => Some(ev),
+ Err(_) => None
+ }
+ }
+}
+
+pub struct WaitEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for WaitEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ use events::Event::Closed;
+
+ match self.window.events_receiver.recv() {
+ Ok(Closed) => {
+ use std::sync::atomic::Ordering::Relaxed;
+ self.window.is_closed.store(true, Relaxed);
+ Some(Closed)
+ },
+ Ok(ev) => Some(ev),
+ Err(_) => None
+ }
+ }
+}
+
#[unsafe_destructor]
impl Drop for Window {
fn drop(&mut self) {
diff --git a/src/x11/mod.rs b/src/x11/mod.rs
index 22184a9..cc87b2b 100644
--- a/src/x11/mod.rs
+++ b/src/x11/mod.rs
@@ -3,6 +3,8 @@ pub use self::headless::HeadlessContext;
#[cfg(feature = "window")]
pub use self::window::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor};
+#[cfg(feature = "window")]
+pub use self::window::{WaitEventsIterator, PollEventsIterator};
mod ffi;
diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs
index bcb8726..b1cd6d4 100644
--- a/src/x11/window/mod.rs
+++ b/src/x11/window/mod.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
use std::sync::atomic::AtomicBool;
use std::collections::RingBuf;
use super::ffi;
-use std::sync::{Arc, Once, ONCE_INIT, Weak};
+use std::sync::{Arc, Mutex, Once, ONCE_INIT, Weak};
use std::sync::{StaticMutex, MUTEX_INIT};
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
@@ -105,11 +105,179 @@ impl WindowProxy {
}
}
+pub struct PollEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for PollEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ use std::num::Int;
+
+ if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
+ return Some(ev);
+ }
+
+ let mut xev = unsafe { mem::uninitialized() };
+ let res = unsafe { ffi::XCheckMaskEvent(self.window.x.display, Int::max_value(), &mut xev) };
+
+ if res == 0 {
+ let res = unsafe { ffi::XCheckTypedEvent(self.window.x.display, ffi::ClientMessage, &mut xev) };
+
+ if res == 0 {
+ return None;
+ }
+ }
+
+ match xev.type_ {
+ ffi::KeymapNotify => {
+ unsafe { ffi::XRefreshKeyboardMapping(&xev) }
+ },
+
+ ffi::ClientMessage => {
+ use events::Event::{Closed, Awakened};
+ use std::sync::atomic::Ordering::Relaxed;
+
+ let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) };
+
+ if client_msg.l[0] == self.window.wm_delete_window as libc::c_long {
+ self.window.is_closed.store(true, Relaxed);
+ return Some(Closed);
+ } else {
+ return Some(Awakened);
+ }
+ },
+
+ ffi::ConfigureNotify => {
+ use events::Event::Resized;
+ let cfg_event: &ffi::XConfigureEvent = unsafe { mem::transmute(&xev) };
+ let (current_width, current_height) = self.window.current_size.get();
+ if current_width != cfg_event.width || current_height != cfg_event.height {
+ self.window.current_size.set((cfg_event.width, cfg_event.height));
+ return Some(Resized(cfg_event.width as u32, cfg_event.height as u32));
+ }
+ },
+
+ ffi::MotionNotify => {
+ use events::Event::MouseMoved;
+ let event: &ffi::XMotionEvent = unsafe { mem::transmute(&xev) };
+ return Some(MouseMoved((event.x as i32, event.y as i32)));
+ },
+
+ ffi::KeyPress | ffi::KeyRelease => {
+ use events::Event::{KeyboardInput, ReceivedCharacter};
+ use events::ElementState::{Pressed, Released};
+ let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&xev) };
+
+ if event.type_ == ffi::KeyPress {
+ let raw_ev: *mut ffi::XKeyEvent = event;
+ unsafe { ffi::XFilterEvent(mem::transmute(raw_ev), self.window.x.window) };
+ }
+
+ let state = if xev.type_ == ffi::KeyPress { Pressed } else { Released };
+
+ let written = unsafe {
+ use std::str;
+
+ let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
+ let raw_ev: *mut ffi::XKeyEvent = event;
+ let count = ffi::Xutf8LookupString(self.window.x.ic, mem::transmute(raw_ev),
+ mem::transmute(buffer.as_mut_ptr()),
+ buffer.len() as libc::c_int, ptr::null_mut(), ptr::null_mut());
+
+ str::from_utf8(&buffer.as_slice()[..count as usize]).unwrap_or("").to_string()
+ };
+
+ {
+ let mut pending = self.window.pending_events.lock().unwrap();
+ for chr in written.as_slice().chars() {
+ pending.push_back(ReceivedCharacter(chr));
+ }
+ }
+
+ let keysym = unsafe {
+ ffi::XKeycodeToKeysym(self.window.x.display, event.keycode as ffi::KeyCode, 0)
+ };
+
+ let vkey = events::keycode_to_element(keysym as libc::c_uint);
+
+ return Some(KeyboardInput(state, event.keycode as u8, vkey));
+ },
+
+ ffi::ButtonPress | ffi::ButtonRelease => {
+ use events::Event::{MouseInput, MouseWheel};
+ use events::ElementState::{Pressed, Released};
+ use events::MouseButton::{Left, Right, Middle};
+
+ let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
+
+ let state = if xev.type_ == ffi::ButtonPress { Pressed } else { Released };
+
+ let button = match event.button {
+ ffi::Button1 => Some(Left),
+ ffi::Button2 => Some(Middle),
+ ffi::Button3 => Some(Right),
+ ffi::Button4 => {
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(1));
+ None
+ }
+ ffi::Button5 => {
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(-1));
+ None
+ }
+ _ => None
+ };
+
+ match button {
+ Some(button) =>
+ return Some(MouseInput(state, button)),
+ None => ()
+ };
+ },
+
+ _ => ()
+ };
+
+ return None;
+ }
+}
+
+pub struct WaitEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for WaitEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ use std::mem;
+
+ loop {
+ if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
+ return Some(ev);
+ }
+
+ // this will block until an event arrives, but doesn't remove
+ // it from the queue
+ let mut xev = unsafe { mem::uninitialized() };
+ unsafe { ffi::XPeekEvent(self.window.x.display, &mut xev) };
+
+ // calling poll_events()
+ if let Some(ev) = self.window.poll_events().next() {
+ return Some(ev);
+ }
+ }
+ }
+}
+
pub struct Window {
x: Arc<XWindow>,
is_closed: AtomicBool,
wm_delete_window: ffi::Atom,
current_size: Cell<(libc::c_int, libc::c_int)>,
+ /// Events that have been retreived with XLib but not dispatched with iterators yet
+ pending_events: Mutex<RingBuf<Event>>,
}
impl Window {
@@ -419,6 +587,7 @@ impl Window {
is_closed: AtomicBool::new(false),
wm_delete_window: wm_delete_window,
current_size: Cell::new((0, 0)),
+ pending_events: Mutex::new(RingBuf::new()),
};
// returning
@@ -500,149 +669,15 @@ impl Window {
}
}
- pub fn poll_events(&self) -> RingBuf<Event> {
- use std::mem;
-
- let mut events = RingBuf::new();
-
- loop {
- use std::num::Int;
-
- let mut xev = unsafe { mem::uninitialized() };
- let res = unsafe { ffi::XCheckMaskEvent(self.x.display, Int::max_value(), &mut xev) };
-
- if res == 0 {
- let res = unsafe { ffi::XCheckTypedEvent(self.x.display, ffi::ClientMessage, &mut xev) };
-
- if res == 0 {
- break
- }
- }
-
- match xev.type_ {
- ffi::KeymapNotify => {
- unsafe { ffi::XRefreshKeyboardMapping(&xev) }
- },
-
- ffi::ClientMessage => {
- use events::Event::{Closed, Awakened};
- use std::sync::atomic::Ordering::Relaxed;
-
- let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) };
-
- if client_msg.l[0] == self.wm_delete_window as libc::c_long {
- self.is_closed.store(true, Relaxed);
- events.push_back(Closed);
- } else {
- events.push_back(Awakened);
- }
- },
-
- ffi::ConfigureNotify => {
- use events::Event::Resized;
- let cfg_event: &ffi::XConfigureEvent = unsafe { mem::transmute(&xev) };
- let (current_width, current_height) = self.current_size.get();
- if current_width != cfg_event.width || current_height != cfg_event.height {
- self.current_size.set((cfg_event.width, cfg_event.height));
- events.push_back(Resized(cfg_event.width as u32, cfg_event.height as u32));
- }
- },
-
- ffi::MotionNotify => {
- use events::Event::MouseMoved;
- let event: &ffi::XMotionEvent = unsafe { mem::transmute(&xev) };
- events.push_back(MouseMoved((event.x as i32, event.y as i32)));
- },
-
- ffi::KeyPress | ffi::KeyRelease => {
- use events::Event::{KeyboardInput, ReceivedCharacter};
- use events::ElementState::{Pressed, Released};
- let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&xev) };
-
- if event.type_ == ffi::KeyPress {
- let raw_ev: *mut ffi::XKeyEvent = event;
- unsafe { ffi::XFilterEvent(mem::transmute(raw_ev), self.x.window) };
- }
-
- let state = if xev.type_ == ffi::KeyPress { Pressed } else { Released };
-
- let written = unsafe {
- use std::str;
-
- let mut buffer: [u8; 16] = [mem::uninitialized(); 16];
- let raw_ev: *mut ffi::XKeyEvent = event;
- let count = ffi::Xutf8LookupString(self.x.ic, mem::transmute(raw_ev),
- mem::transmute(buffer.as_mut_ptr()),
- buffer.len() as libc::c_int, ptr::null_mut(), ptr::null_mut());
-
- str::from_utf8(&buffer.as_slice()[..count as usize]).unwrap_or("").to_string()
- };
-
- for chr in written.as_slice().chars() {
- events.push_back(ReceivedCharacter(chr));
- }
-
- let keysym = unsafe {
- ffi::XKeycodeToKeysym(self.x.display, event.keycode as ffi::KeyCode, 0)
- };
-
- let vkey = events::keycode_to_element(keysym as libc::c_uint);
-
- events.push_back(KeyboardInput(state, event.keycode as u8, vkey));
- },
-
- ffi::ButtonPress | ffi::ButtonRelease => {
- use events::Event::{MouseInput, MouseWheel};
- use events::ElementState::{Pressed, Released};
- use events::MouseButton::{Left, Right, Middle};
-
- let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
-
- let state = if xev.type_ == ffi::ButtonPress { Pressed } else { Released };
-
- let button = match event.button {
- ffi::Button1 => Some(Left),
- ffi::Button2 => Some(Middle),
- ffi::Button3 => Some(Right),
- ffi::Button4 => {
- events.push_back(MouseWheel(1));
- None
- }
- ffi::Button5 => {
- events.push_back(MouseWheel(-1));
- None
- }
- _ => None
- };
-
- match button {
- Some(button) =>
- events.push_back(MouseInput(state, button)),
- None => ()
- };
- },
-
- _ => ()
- }
+ pub fn poll_events(&self) -> PollEventsIterator {
+ PollEventsIterator {
+ window: self
}
-
- events
}
- pub fn wait_events(&self) -> RingBuf<Event> {
- use std::mem;
-
- loop {
- // this will block until an event arrives, but doesn't remove
- // it from the queue
- let mut xev = unsafe { mem::uninitialized() };
- unsafe { ffi::XPeekEvent(self.x.display, &mut xev) };
-
- // calling poll_events()
- let ev = self.poll_events();
- if ev.len() >= 1 {
- return ev;
- }
+ pub fn wait_events(&self) -> WaitEventsIterator {
+ WaitEventsIterator {
+ window: self
}
}