mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Implement Poll and WaitUntil in the stdweb backend
This commit is contained in:
parent
b59e3c670b
commit
2690306f4a
|
@ -14,6 +14,7 @@ categories = ["gui"]
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
instant = "0.1"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -73,6 +74,6 @@ percent-encoding = "1.0"
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "windows"))'.dependencies.parking_lot]
|
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "windows"))'.dependencies.parking_lot]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies.stdweb]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
path = "../stdweb"
|
stdweb = { path = "../stdweb", optional = true }
|
||||||
optional = true
|
instant = { version = "0.1", features = ["stdweb"] }
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! processed and used to modify the program state. For more details, see the root-level documentation.
|
//! processed and used to modify the program state. For more details, see the root-level documentation.
|
||||||
//!
|
//!
|
||||||
//! [event_loop_run]: ../event_loop/struct.EventLoop.html#method.run
|
//! [event_loop_run]: ../event_loop/struct.EventLoop.html#method.run
|
||||||
use std::time::Instant;
|
use instant::Instant;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use dpi::{LogicalPosition, LogicalSize};
|
use dpi::{LogicalPosition, LogicalSize};
|
||||||
|
@ -58,7 +58,7 @@ impl<T> Event<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the reason the event loop is resuming.
|
/// Describes the reason the event loop is resuming.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum StartCause {
|
pub enum StartCause {
|
||||||
/// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the
|
/// Sent if the time specified by `ControlFlow::WaitUntil` has been reached. Contains the
|
||||||
/// moment the timeout was requested and the requested resume time. The actual resume time is
|
/// moment the timeout was requested and the requested resume time. The actual resume time is
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
//! [event_loop_proxy]: ./struct.EventLoopProxy.html
|
//! [event_loop_proxy]: ./struct.EventLoopProxy.html
|
||||||
//! [send_event]: ./struct.EventLoopProxy.html#method.send_event
|
//! [send_event]: ./struct.EventLoopProxy.html#method.send_event
|
||||||
use std::{fmt, error};
|
use std::{fmt, error};
|
||||||
use std::time::Instant;
|
use instant::Instant;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use platform_impl;
|
use platform_impl;
|
||||||
|
@ -69,7 +69,7 @@ impl<T> fmt::Debug for EventLoopWindowTarget<T> {
|
||||||
/// the control flow to `Poll`.
|
/// the control flow to `Poll`.
|
||||||
///
|
///
|
||||||
/// [events_cleared]: ../event/enum.Event.html#variant.EventsCleared
|
/// [events_cleared]: ../event/enum.Event.html#variant.EventsCleared
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ControlFlow {
|
pub enum ControlFlow {
|
||||||
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
||||||
/// whether or not new events are available to process.
|
/// whether or not new events are available to process.
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
//! [`LoopDestroyed`]: ./event/enum.Event.html#variant.LoopDestroyed
|
//! [`LoopDestroyed`]: ./event/enum.Event.html#variant.LoopDestroyed
|
||||||
//! [`platform`]: ./platform/index.html
|
//! [`platform`]: ./platform/index.html
|
||||||
|
|
||||||
|
extern crate instant;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use super::*;
|
||||||
use dpi::LogicalPosition;
|
use dpi::LogicalPosition;
|
||||||
use event::{DeviceId as RootDI, ElementState, Event, KeyboardInput, MouseScrollDelta, StartCause, TouchPhase, WindowEvent};
|
use event::{DeviceId as RootDI, ElementState, Event, KeyboardInput, MouseScrollDelta, StartCause, TouchPhase, WindowEvent};
|
||||||
use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed};
|
use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed};
|
||||||
|
use instant::{Duration, Instant};
|
||||||
use window::{WindowId as RootWI};
|
use window::{WindowId as RootWI};
|
||||||
use stdweb::{
|
use stdweb::{
|
||||||
traits::*,
|
traits::*,
|
||||||
|
@ -10,15 +11,17 @@ use stdweb::{
|
||||||
document,
|
document,
|
||||||
event::*,
|
event::*,
|
||||||
html_element::CanvasElement,
|
html_element::CanvasElement,
|
||||||
|
window,
|
||||||
TimeoutHandle,
|
TimeoutHandle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::{
|
||||||
use std::collections::VecDeque;
|
cell::RefCell,
|
||||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
collections::{VecDeque, vec_deque::IntoIter as VecDequeIter},
|
||||||
use std::marker::PhantomData;
|
clone::Clone,
|
||||||
use std::rc::Rc;
|
marker::PhantomData,
|
||||||
use std::time::Instant;
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct DeviceId(i32);
|
pub struct DeviceId(i32);
|
||||||
|
@ -40,31 +43,37 @@ pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
impl<T> EventLoopWindowTarget<T> {
|
impl<T> EventLoopWindowTarget<T> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
EventLoopWindowTarget {
|
EventLoopWindowTarget {
|
||||||
runner: Rc::new(ELRShared {
|
runner: EventLoopRunnerShared(Rc::new(ELRShared {
|
||||||
runner: RefCell::new(None),
|
runner: RefCell::new(None),
|
||||||
events: RefCell::new(VecDeque::new())
|
events: RefCell::new(VecDeque::new())
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EventLoopProxy<T> {
|
pub struct EventLoopProxy<T: 'static> {
|
||||||
runner: EventLoopRunnerShared<T>
|
runner: EventLoopRunnerShared<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
|
||||||
self.runner.send_event(Event::UserEvent(event));
|
self.runner.send_event(Event::UserEvent(event));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
pub struct EventLoopRunnerShared<T>(Rc<ELRShared<T>>);
|
||||||
|
|
||||||
|
impl<T> Clone for EventLoopRunnerShared<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
EventLoopRunnerShared(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ELRShared<T> {
|
pub struct ELRShared<T> {
|
||||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||||
events: RefCell<VecDeque<Event<T>>>, // TODO: this may not be necessary?
|
events: RefCell<VecDeque<Event<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventLoopRunner<T> {
|
struct EventLoopRunner<T> {
|
||||||
|
@ -74,6 +83,7 @@ struct EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ControlFlowStatus {
|
enum ControlFlowStatus {
|
||||||
|
Init,
|
||||||
WaitUntil {
|
WaitUntil {
|
||||||
timeout: TimeoutHandle,
|
timeout: TimeoutHandle,
|
||||||
start: Instant,
|
start: Instant,
|
||||||
|
@ -91,6 +101,7 @@ enum ControlFlowStatus {
|
||||||
impl ControlFlowStatus {
|
impl ControlFlowStatus {
|
||||||
fn to_control_flow(&self) -> ControlFlow {
|
fn to_control_flow(&self) -> ControlFlow {
|
||||||
match self {
|
match self {
|
||||||
|
ControlFlowStatus::Init => ControlFlow::Poll, // During the Init loop, the user should get Poll, the default control value
|
||||||
ControlFlowStatus::WaitUntil { end, .. } => ControlFlow::WaitUntil(*end),
|
ControlFlowStatus::WaitUntil { end, .. } => ControlFlow::WaitUntil(*end),
|
||||||
ControlFlowStatus::Wait { .. } => ControlFlow::Wait,
|
ControlFlowStatus::Wait { .. } => ControlFlow::Wait,
|
||||||
ControlFlowStatus::Poll { .. } => ControlFlow::Poll,
|
ControlFlowStatus::Poll { .. } => ControlFlow::Poll,
|
||||||
|
@ -286,7 +297,7 @@ fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IE
|
||||||
|
|
||||||
target.add_event_listener(move |event: E| {
|
target.add_event_listener(move |event: E| {
|
||||||
// Don't capture the event if the events loop has been destroyed
|
// Don't capture the event if the events loop has been destroyed
|
||||||
match &*elrs.runner.borrow() {
|
match &*elrs.0.runner.borrow() {
|
||||||
Some(ref runner) if runner.control.is_exit() => return,
|
Some(ref runner) if runner.control.is_exit() => return,
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
@ -299,17 +310,17 @@ fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IE
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ELRShared<T> {
|
impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
// Set the event callback to use for the event loop runner
|
// Set the event callback to use for the event loop runner
|
||||||
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
||||||
// over a RootEventLoopWindowTarget reference
|
// over a RootEventLoopWindowTarget reference
|
||||||
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
|
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
|
||||||
// TODO: Start the poll here
|
*self.0.runner.borrow_mut() = Some(EventLoopRunner {
|
||||||
*self.runner.borrow_mut() = Some(EventLoopRunner {
|
control: ControlFlowStatus::Init,
|
||||||
control: ControlFlowStatus::Exit,
|
|
||||||
is_busy: false,
|
is_busy: false,
|
||||||
event_handler,
|
event_handler,
|
||||||
});
|
});
|
||||||
|
self.send_event(Event::NewEvents(StartCause::Init));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an event to the event loop runner
|
// Add an event to the event loop runner
|
||||||
|
@ -321,23 +332,46 @@ impl<T> ELRShared<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Determine if a timeout needs to be cleared
|
|
||||||
|
|
||||||
let start_cause = StartCause::Poll; // TODO: determine start cause
|
|
||||||
|
|
||||||
// Determine if event handling is in process, and then release the borrow on the runner
|
// Determine if event handling is in process, and then release the borrow on the runner
|
||||||
match *self.runner.borrow() {
|
match *self.0.runner.borrow() {
|
||||||
Some(ref runner) if !runner.is_busy => {
|
Some(ref runner) if !runner.is_busy => {
|
||||||
|
let (start_cause, event_is_start) = if let Event::NewEvents(cause) = event {
|
||||||
|
(cause, true)
|
||||||
|
} else {
|
||||||
|
(match runner.control {
|
||||||
|
ControlFlowStatus::Init => StartCause::Init,
|
||||||
|
ControlFlowStatus::Poll { ref timeout } => {
|
||||||
|
timeout.clear();
|
||||||
|
|
||||||
|
StartCause::Poll
|
||||||
|
}
|
||||||
|
ControlFlowStatus::Wait { start } => StartCause::WaitCancelled {
|
||||||
|
start,
|
||||||
|
requested_resume: None,
|
||||||
|
},
|
||||||
|
ControlFlowStatus::WaitUntil { start, end, ref timeout } => {
|
||||||
|
timeout.clear();
|
||||||
|
|
||||||
|
StartCause::WaitCancelled {
|
||||||
|
start,
|
||||||
|
requested_resume: Some(end)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ControlFlowStatus::Exit => { return; }
|
||||||
|
}, false)
|
||||||
|
};
|
||||||
let mut control = runner.control.to_control_flow();
|
let mut control = runner.control.to_control_flow();
|
||||||
// Handle starting a new batch of events
|
// Handle starting a new batch of events
|
||||||
//
|
//
|
||||||
// The user is informed via Event::NewEvents that there is a batch of events to process
|
// The user is informed via Event::NewEvents that there is a batch of events to process
|
||||||
// However, there is only one of these per batch of events
|
// However, there is only one of these per batch of events
|
||||||
self.handle_event(Event::NewEvents(start_cause), &mut control);
|
self.handle_event(Event::NewEvents(start_cause), &mut control);
|
||||||
self.handle_event(event, &mut control);
|
if !event_is_start {
|
||||||
|
self.handle_event(event, &mut control);
|
||||||
|
}
|
||||||
self.handle_event(Event::EventsCleared, &mut control);
|
self.handle_event(Event::EventsCleared, &mut control);
|
||||||
|
|
||||||
// TODO: integrate control flow change and set up the next iteration
|
self.apply_control_flow(control);
|
||||||
|
|
||||||
// If the event loop is closed, it has been closed this iteration and now the closing
|
// If the event loop is closed, it has been closed this iteration and now the closing
|
||||||
// event should be emitted
|
// event should be emitted
|
||||||
|
@ -346,31 +380,22 @@ impl<T> ELRShared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.events.borrow_mut().push_back(event);
|
self.0.events.borrow_mut().push_back(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the event loop is currntly closed
|
|
||||||
fn closed(&self) -> bool {
|
|
||||||
match *self.runner.borrow() {
|
|
||||||
Some(ref runner) => runner.control.is_exit(),
|
|
||||||
None => false, // If the event loop is None, it has not been intialised yet, so it cannot be closed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle_event takes in events and either queues them or applies a callback
|
// handle_event takes in events and either queues them or applies a callback
|
||||||
//
|
//
|
||||||
// It should only ever be called from send_event
|
// It should only ever be called from send_event
|
||||||
fn handle_event(&self, event: Event<T>, control: &mut ControlFlow) {
|
fn handle_event(&self, event: Event<T>, control: &mut ControlFlow) {
|
||||||
let closed = self.closed();
|
let closed = self.closed();
|
||||||
|
|
||||||
match *self.runner.borrow_mut() {
|
match *self.0.runner.borrow_mut() {
|
||||||
Some(ref mut runner) => {
|
Some(ref mut runner) => {
|
||||||
// An event is being processed, so the runner should be marked busy
|
// An event is being processed, so the runner should be marked busy
|
||||||
runner.is_busy = true;
|
runner.is_busy = true;
|
||||||
|
|
||||||
// TODO: bracket this in control flow events?
|
|
||||||
(runner.event_handler)(event, control);
|
(runner.event_handler)(event, control);
|
||||||
|
|
||||||
// Maintain closed state, even if the callback changes it
|
// Maintain closed state, even if the callback changes it
|
||||||
|
@ -383,18 +408,61 @@ impl<T> ELRShared<T> {
|
||||||
}
|
}
|
||||||
// If an event is being handled without a runner somehow, add it to the event queue so
|
// If an event is being handled without a runner somehow, add it to the event queue so
|
||||||
// it will eventually be processed
|
// it will eventually be processed
|
||||||
_ => self.events.borrow_mut().push_back(event)
|
_ => self.0.events.borrow_mut().push_back(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
|
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
|
||||||
// If the runner doesn't exist and this method recurses, it will recurse infinitely
|
// If the runner doesn't exist and this method recurses, it will recurse infinitely
|
||||||
if !closed && self.runner.borrow().is_some() {
|
if !closed && self.0.runner.borrow().is_some() {
|
||||||
// Take an event out of the queue and handle it
|
// Take an event out of the queue and handle it
|
||||||
if let Some(event) = self.events.borrow_mut().pop_front() {
|
if let Some(event) = self.0.events.borrow_mut().pop_front() {
|
||||||
self.handle_event(event, control);
|
self.handle_event(event, control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the new ControlFlow that has been selected by the user
|
||||||
|
// Start any necessary timeouts etc
|
||||||
|
fn apply_control_flow(&self, control_flow: ControlFlow) {
|
||||||
|
let control_flow_status = match control_flow {
|
||||||
|
ControlFlow::Poll => {
|
||||||
|
let cloned = self.clone();
|
||||||
|
ControlFlowStatus::Poll {
|
||||||
|
timeout: window().set_clearable_timeout(move || cloned.send_event(Event::NewEvents(StartCause::Poll)), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::Wait => ControlFlowStatus::Wait { start: Instant::now() },
|
||||||
|
ControlFlow::WaitUntil(end) => {
|
||||||
|
let cloned = self.clone();
|
||||||
|
let start = Instant::now();
|
||||||
|
let delay = if end <= start {
|
||||||
|
Duration::from_millis(0)
|
||||||
|
} else {
|
||||||
|
end - start
|
||||||
|
};
|
||||||
|
ControlFlowStatus::WaitUntil {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
timeout: window().set_clearable_timeout(move || cloned.send_event(Event::NewEvents(StartCause::Poll)), delay.as_millis() as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::Exit => ControlFlowStatus::Exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
match *self.0.runner.borrow_mut() {
|
||||||
|
Some(ref mut runner) => {
|
||||||
|
runner.control = control_flow_status;
|
||||||
|
}
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the event loop is currntly closed
|
||||||
|
fn closed(&self) -> bool {
|
||||||
|
match *self.0.runner.borrow() {
|
||||||
|
Some(ref runner) => runner.control.is_exit(),
|
||||||
|
None => false, // If the event loop is None, it has not been intialised yet, so it cannot be closed
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue