[WIP] Have EventsLoopProxy::wakeup return a Result. Begin linux impl.

X11 and Wayland implementations are now half implemented, however both
still do not correctly break from the inner blocking event dispatch
functions when `wakeup` is called, which they should do.
This commit is contained in:
mitchmindtree 2017-05-25 23:19:13 +10:00
parent c8e791b402
commit f6587aed39
7 changed files with 149 additions and 34 deletions

View file

@ -7,10 +7,11 @@ pub use self::xdisplay::{XConnection, XNotSupported, XError};
pub mod ffi;
use platform::PlatformSpecificWindowBuilderAttributes;
use {CreationError, Event, WindowEvent, DeviceEvent, AxisId, ButtonId, KeyboardInput};
use {CreationError, Event, EventsLoopClosed, WindowEvent, DeviceEvent, AxisId, ButtonId, KeyboardInput};
use std::{mem, ptr, slice};
use std::sync::{Arc, Mutex, Weak};
use std::sync::atomic::{self, AtomicBool};
use std::collections::HashMap;
use std::ffi::CStr;
@ -29,15 +30,20 @@ mod xdisplay;
// the one generated by the macro.
pub struct EventsLoop {
interrupted: ::std::sync::atomic::AtomicBool,
interrupted: AtomicBool,
display: Arc<XConnection>,
wm_delete_window: ffi::Atom,
windows: Mutex<HashMap<WindowId, WindowData>>,
devices: Mutex<HashMap<DeviceId, Device>>,
xi2ext: XExtension,
pending_wakeup: Arc<AtomicBool>,
root: ffi::Window,
}
pub struct EventsLoopProxy {
pending_wakeup: Weak<AtomicBool>,
}
impl EventsLoop {
pub fn new(display: Arc<XConnection>) -> EventsLoop {
let wm_delete_window = unsafe { (display.xlib.XInternAtom)(display.display, b"WM_DELETE_WINDOW\0".as_ptr() as *const c_char, 0) };
@ -73,7 +79,8 @@ impl EventsLoop {
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
let result = EventsLoop {
interrupted: ::std::sync::atomic::AtomicBool::new(false),
interrupted: AtomicBool::new(false),
pending_wakeup: Arc::new(AtomicBool::new(false)),
display: display,
wm_delete_window: wm_delete_window,
windows: Mutex::new(HashMap::new()),
@ -101,8 +108,14 @@ impl EventsLoop {
result
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy {
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
}
}
pub fn interrupt(&self) {
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
self.interrupted.store(true, atomic::Ordering::Relaxed);
// Push an event on the X event queue so that methods like run_forever will advance.
let mut xev = ffi::XClientMessageEvent {
@ -126,7 +139,7 @@ impl EventsLoop {
pub fn poll_events<F>(&self, mut callback: F)
where F: FnMut(Event)
{
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
self.interrupted.store(false, atomic::Ordering::Relaxed);
let xlib = &self.display.xlib;
let mut xev = unsafe { mem::uninitialized() };
@ -142,7 +155,7 @@ impl EventsLoop {
(xlib.XNextEvent)(self.display.display, &mut xev);
}
self.process_event(&mut xev, &mut callback);
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
if self.interrupted.load(atomic::Ordering::Relaxed) {
break;
}
}
@ -151,7 +164,7 @@ impl EventsLoop {
pub fn run_forever<F>(&self, mut callback: F)
where F: FnMut(Event)
{
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
self.interrupted.store(false, atomic::Ordering::Relaxed);
let xlib = &self.display.xlib;
@ -160,7 +173,7 @@ impl EventsLoop {
loop {
unsafe { (xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary
self.process_event(&mut xev, &mut callback);
if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
if self.interrupted.load(atomic::Ordering::Relaxed) {
break;
}
}
@ -197,7 +210,7 @@ impl EventsLoop {
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Closed })
} else {
// FIXME: Prone to spurious wakeups
callback(Event::WindowEvent { window_id: wid, event: WindowEvent::Awakened })
callback(Event::Awakened)
}
}
@ -523,6 +536,19 @@ impl EventsLoop {
}
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
// Update the `EventsLoop`'s `pending_wakeup` flag.
match self.pending_wakeup.upgrade() {
Some(wakeup) => Ok(wakeup.store(true, atomic::Ordering::Relaxed)),
None => Err(EventsLoopClosed),
}
// TODO:
// Cause the `EventsLoop` to break if it is currently blocked.
}
}
struct DeviceInfo<'a> {
display: &'a XConnection,
info: *const ffi::XIDeviceInfo,