[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:
parent
c8e791b402
commit
f6587aed39
7 changed files with 149 additions and 34 deletions
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue