[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
|
|
@ -1,7 +1,7 @@
|
|||
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput};
|
||||
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase, ModifiersState, KeyboardInput, EventsLoopClosed};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
|
||||
use super::{DecoratedHandler, WindowId, DeviceId, WaylandContext};
|
||||
|
||||
|
|
@ -71,7 +71,38 @@ pub struct EventsLoop {
|
|||
interrupted: AtomicBool,
|
||||
// trigger cleanup of the dead surfaces
|
||||
cleanup_needed: Arc<AtomicBool>,
|
||||
hid: usize
|
||||
// Whether or not there is a pending `Awakened` event to be emitted.
|
||||
pending_wakeup: Arc<AtomicBool>,
|
||||
hid: usize,
|
||||
}
|
||||
|
||||
// A handle that can be sent across threads and used to wake up the `EventsLoop`.
|
||||
//
|
||||
// We should only try and wake up the `EventsLoop` if it still exists, so we hold Weak ptrs.
|
||||
pub struct EventsLoopProxy {
|
||||
ctxt: Weak<WaylandContext>,
|
||||
pending_wakeup: Weak<AtomicBool>,
|
||||
}
|
||||
|
||||
impl EventsLoopProxy {
|
||||
// Causes the `EventsLoop` to stop blocking on `run_forever` and emit an `Awakened` event.
|
||||
//
|
||||
// Returns `Err` if the associated `EventsLoop` no longer exists.
|
||||
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||
let ctxt = self.ctxt.upgrade();
|
||||
let wakeup = self.pending_wakeup.upgrade();
|
||||
match (ctxt, wakeup) {
|
||||
(Some(ctxt), Some(wakeup)) => {
|
||||
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
||||
wakeup.store(true, atomic::Ordering::Relaxed);
|
||||
// TODO:
|
||||
// Cause the `EventsLoop` to break from `dispatch` if it is currently blocked.
|
||||
ctxt.display.sync();
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(EventsLoopClosed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventsLoop {
|
||||
|
|
@ -85,11 +116,19 @@ impl EventsLoop {
|
|||
decorated_ids: Mutex::new(Vec::new()),
|
||||
sink: sink,
|
||||
interrupted: AtomicBool::new(false),
|
||||
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
||||
cleanup_needed: Arc::new(AtomicBool::new(false)),
|
||||
hid: hid
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||
EventsLoopProxy {
|
||||
ctxt: Arc::downgrade(&self.ctxt),
|
||||
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
||||
}
|
||||
}
|
||||
|
||||
// some internals that Window needs access to
|
||||
pub fn get_window_init(&self) -> (Arc<Mutex<EventQueue>>, Arc<AtomicBool>) {
|
||||
(self.evq.clone(), self.cleanup_needed.clone())
|
||||
|
|
@ -120,7 +159,7 @@ impl EventsLoop {
|
|||
}
|
||||
|
||||
pub fn interrupt(&self) {
|
||||
self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
|
||||
self.interrupted.store(true, atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn prune_dead_windows(&self) {
|
||||
|
|
@ -160,6 +199,8 @@ impl EventsLoop {
|
|||
self.ctxt.dispatch_pending();
|
||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||
|
||||
self.emit_pending_wakeup();
|
||||
|
||||
{
|
||||
let mut sink_guard = self.sink.lock().unwrap();
|
||||
|
||||
|
|
@ -173,7 +214,7 @@ impl EventsLoop {
|
|||
unsafe { sink_guard.set_callback(old_cb) };
|
||||
}
|
||||
|
||||
if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) {
|
||||
if self.cleanup_needed.swap(false, atomic::Ordering::Relaxed) {
|
||||
self.prune_dead_windows()
|
||||
}
|
||||
}
|
||||
|
|
@ -181,7 +222,7 @@ impl EventsLoop {
|
|||
pub fn run_forever<F>(&self, callback: F)
|
||||
where F: FnMut(::Event)
|
||||
{
|
||||
self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
|
||||
self.interrupted.store(false, atomic::Ordering::Relaxed);
|
||||
|
||||
// send pending requests to the server...
|
||||
self.ctxt.flush();
|
||||
|
|
@ -195,16 +236,19 @@ impl EventsLoop {
|
|||
let static_cb = unsafe { ::std::mem::transmute(Box::new(callback) as Box<FnMut(_)>) };
|
||||
let old_cb = unsafe { self.sink.lock().unwrap().set_callback(static_cb) };
|
||||
|
||||
while !self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
|
||||
while !self.interrupted.load(atomic::Ordering::Relaxed) {
|
||||
self.ctxt.dispatch();
|
||||
evq_guard.dispatch_pending().expect("Wayland connection unexpectedly lost");
|
||||
|
||||
self.emit_pending_wakeup();
|
||||
|
||||
let ids_guard = self.decorated_ids.lock().unwrap();
|
||||
self.sink.lock().unwrap().with_callback(
|
||||
|cb| Self::process_resize(&mut evq_guard, &ids_guard, cb)
|
||||
);
|
||||
self.ctxt.flush();
|
||||
|
||||
if self.cleanup_needed.swap(false, ::std::sync::atomic::Ordering::Relaxed) {
|
||||
if self.cleanup_needed.swap(false, atomic::Ordering::Relaxed) {
|
||||
self.prune_dead_windows()
|
||||
}
|
||||
}
|
||||
|
|
@ -212,6 +256,14 @@ impl EventsLoop {
|
|||
// replace the old noop callback
|
||||
unsafe { self.sink.lock().unwrap().set_callback(old_cb) };
|
||||
}
|
||||
|
||||
// If an `EventsLoopProxy` has signalled a wakeup, emit an event and reset the flag.
|
||||
fn emit_pending_wakeup(&self) {
|
||||
if self.pending_wakeup.load(atomic::Ordering::Relaxed) {
|
||||
self.sink.lock().unwrap().with_callback(|cb| cb(::Event::Awakened));
|
||||
self.pending_wakeup.store(false, atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum KbdType {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
|
||||
|
||||
pub use self::window::{Window, WindowId};
|
||||
pub use self::event_loop::EventsLoop;
|
||||
pub use self::event_loop::{EventsLoop, EventsLoopProxy};
|
||||
pub use self::context::{WaylandContext, MonitorId, get_available_monitors,
|
||||
get_primary_monitor};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue