2019-03-11 22:22:21 -04:00
|
|
|
use super::*;
|
|
|
|
|
|
2019-03-16 18:51:11 -04:00
|
|
|
use dpi::LogicalPosition;
|
|
|
|
|
use event::{DeviceId as RootDI, ElementState, Event, KeyboardInput, StartCause, WindowEvent};
|
2019-03-11 22:22:21 -04:00
|
|
|
use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed};
|
2019-03-16 18:51:11 -04:00
|
|
|
use window::{WindowId as RootWI};
|
2019-03-11 22:22:21 -04:00
|
|
|
use stdweb::{
|
|
|
|
|
traits::*,
|
|
|
|
|
web::{
|
|
|
|
|
document,
|
|
|
|
|
event::*,
|
|
|
|
|
html_element::CanvasElement,
|
|
|
|
|
},
|
|
|
|
|
};
|
2019-03-16 18:51:11 -04:00
|
|
|
use std::cell::RefCell;
|
2019-03-11 22:22:21 -04:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub struct DeviceId(i32);
|
|
|
|
|
|
|
|
|
|
impl DeviceId {
|
|
|
|
|
pub unsafe fn dummy() -> Self {
|
|
|
|
|
DeviceId(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct EventLoop<T: 'static> {
|
|
|
|
|
elw: RootELW<T>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct EventLoopWindowTarget<T: 'static> {
|
2019-03-16 18:40:35 -04:00
|
|
|
pub(crate) runner: EventLoopRunnerShared<T>,
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> EventLoopWindowTarget<T> {
|
|
|
|
|
fn new() -> Self {
|
|
|
|
|
EventLoopWindowTarget {
|
2019-03-16 18:40:35 -04:00
|
|
|
runner: Rc::new(ELRShared {
|
|
|
|
|
runner: RefCell::new(None),
|
|
|
|
|
events: RefCell::new(VecDeque::new())
|
|
|
|
|
})
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct EventLoopProxy<T> {
|
|
|
|
|
runner: EventLoopRunnerShared<T>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> EventLoopProxy<T> {
|
|
|
|
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
|
|
|
|
|
self.runner.send_event(Event::UserEvent(event));
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-16 18:40:35 -04:00
|
|
|
pub type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
2019-03-11 22:22:21 -04:00
|
|
|
|
2019-03-16 18:40:35 -04:00
|
|
|
pub struct ELRShared<T> {
|
2019-03-11 22:22:21 -04:00
|
|
|
runner: RefCell<Option<EventLoopRunner<T>>>,
|
|
|
|
|
events: RefCell<VecDeque<Event<T>>>, // TODO: this may not be necessary?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct EventLoopRunner<T> {
|
|
|
|
|
control: ControlFlow,
|
2019-04-25 00:02:13 -04:00
|
|
|
is_busy: bool,
|
2019-03-11 22:22:21 -04:00
|
|
|
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> EventLoop<T> {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
EventLoop {
|
|
|
|
|
elw: RootELW {
|
|
|
|
|
p: EventLoopWindowTarget::new(),
|
|
|
|
|
_marker: PhantomData
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_available_monitors(&self) -> VecDequeIter<MonitorHandle> {
|
|
|
|
|
VecDeque::new().into_iter()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_primary_monitor(&self) -> MonitorHandle {
|
|
|
|
|
MonitorHandle
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-16 18:51:11 -04:00
|
|
|
pub fn run<F>(self, mut event_handler: F) -> !
|
2019-03-18 22:13:30 -04:00
|
|
|
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow) {
|
2019-03-16 18:40:35 -04:00
|
|
|
let runner = self.elw.p.runner;
|
2019-03-18 22:13:30 -04:00
|
|
|
|
2019-03-11 22:22:21 -04:00
|
|
|
let relw = RootELW {
|
|
|
|
|
p: EventLoopWindowTarget::new(),
|
|
|
|
|
_marker: PhantomData
|
|
|
|
|
};
|
|
|
|
|
runner.set_listener(Box::new(move |evt, ctrl| event_handler(evt, &relw, ctrl)));
|
|
|
|
|
|
|
|
|
|
let document = &document();
|
2019-03-16 18:44:13 -04:00
|
|
|
add_event(&runner, document, |elrs, _: BlurEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::Focused(false)
|
|
|
|
|
});
|
2019-03-11 22:22:21 -04:00
|
|
|
});
|
2019-03-16 18:44:13 -04:00
|
|
|
add_event(&runner, document, |elrs, _: FocusEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::Focused(true)
|
|
|
|
|
});
|
2019-03-11 22:22:21 -04:00
|
|
|
|
|
|
|
|
});
|
|
|
|
|
add_event(&runner, document, |elrs, event: KeyDownEvent| {
|
|
|
|
|
let key = event.key();
|
|
|
|
|
let mut characters = key.chars();
|
|
|
|
|
let first = characters.next();
|
|
|
|
|
let second = characters.next();
|
|
|
|
|
if let (Some(key), None) = (first, second) {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::ReceivedCharacter(key)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::KeyboardInput {
|
|
|
|
|
device_id: RootDI(unsafe { DeviceId::dummy() }),
|
|
|
|
|
input: KeyboardInput {
|
|
|
|
|
scancode: scancode(&event),
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
virtual_keycode: button_mapping(&event),
|
|
|
|
|
modifiers: keyboard_modifiers_state(&event),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
add_event(&runner, document, |elrs, event: KeyUpEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::KeyboardInput {
|
|
|
|
|
device_id: RootDI(unsafe { DeviceId::dummy() }),
|
|
|
|
|
input: KeyboardInput {
|
|
|
|
|
scancode: scancode(&event),
|
|
|
|
|
state: ElementState::Released,
|
|
|
|
|
virtual_keycode: button_mapping(&event),
|
|
|
|
|
modifiers: keyboard_modifiers_state(&event),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
stdweb::event_loop(); // TODO: this is only necessary for stdweb emscripten, should it be here?
|
2019-03-16 18:40:35 -04:00
|
|
|
|
|
|
|
|
// Throw an exception to break out of Rust exceution and use unreachable to tell the
|
|
|
|
|
// compiler this function won't return, giving it a return type of '!'
|
2019-03-11 22:22:21 -04:00
|
|
|
js! {
|
|
|
|
|
throw "Using exceptions for control flow, don't mind me";
|
|
|
|
|
}
|
|
|
|
|
unreachable!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
|
|
|
|
EventLoopProxy {
|
2019-03-16 18:40:35 -04:00
|
|
|
runner: self.elw.p.runner.clone()
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn window_target(&self) -> &RootELW<T> {
|
|
|
|
|
&self.elw
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-16 18:40:35 -04:00
|
|
|
pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElement) {
|
2019-03-11 22:22:21 -04:00
|
|
|
add_event(elrs, canvas, |elrs, event: PointerOutEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::CursorLeft {
|
|
|
|
|
device_id: RootDI(DeviceId(event.pointer_id()))
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
add_event(elrs, canvas, |elrs, event: PointerOverEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::CursorEntered {
|
|
|
|
|
device_id: RootDI(DeviceId(event.pointer_id()))
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
add_event(elrs, canvas, |elrs, event: PointerMoveEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::CursorMoved {
|
|
|
|
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
|
|
|
|
position: LogicalPosition {
|
|
|
|
|
x: event.offset_x(),
|
|
|
|
|
y: event.offset_y()
|
|
|
|
|
},
|
|
|
|
|
modifiers: mouse_modifiers_state(&event)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
add_event(elrs, canvas, |elrs, event: PointerUpEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::MouseInput {
|
|
|
|
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
button: mouse_button(&event),
|
|
|
|
|
modifiers: mouse_modifiers_state(&event)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
add_event(elrs, canvas, |elrs, event: PointerDownEvent| {
|
|
|
|
|
elrs.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: RootWI(WindowId),
|
|
|
|
|
event: WindowEvent::MouseInput {
|
|
|
|
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
|
|
|
|
state: ElementState::Released,
|
|
|
|
|
button: mouse_button(&event),
|
|
|
|
|
modifiers: mouse_modifiers_state(&event)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IEventTarget, mut handler: F)
|
|
|
|
|
where E: ConcreteEvent, F: FnMut(&EventLoopRunnerShared<T>, E) + 'static {
|
2019-03-16 18:40:35 -04:00
|
|
|
let elrs = elrs.clone();
|
2019-03-11 22:22:21 -04:00
|
|
|
|
|
|
|
|
target.add_event_listener(move |event: E| {
|
2019-03-22 22:15:49 -04:00
|
|
|
// Don't capture the event if the events loop has been destroyed
|
2019-04-02 22:31:30 -04:00
|
|
|
match &*elrs.runner.borrow() {
|
|
|
|
|
Some(ref runner) if runner.control == ControlFlow::Exit => return,
|
|
|
|
|
_ => ()
|
2019-03-22 22:15:49 -04:00
|
|
|
}
|
|
|
|
|
|
2019-03-11 22:22:21 -04:00
|
|
|
event.prevent_default();
|
|
|
|
|
event.stop_propagation();
|
|
|
|
|
event.cancel_bubble();
|
|
|
|
|
|
|
|
|
|
handler(&elrs, event);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> ELRShared<T> {
|
2019-04-25 00:02:13 -04:00
|
|
|
// 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
|
|
|
|
|
// over a RootEventLoopWindowTarget reference
|
2019-03-11 22:22:21 -04:00
|
|
|
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
|
|
|
|
|
*self.runner.borrow_mut() = Some(EventLoopRunner {
|
|
|
|
|
control: ControlFlow::Poll,
|
2019-04-25 00:02:13 -04:00
|
|
|
is_busy: false,
|
2019-03-11 22:22:21 -04:00
|
|
|
event_handler
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-25 00:02:13 -04:00
|
|
|
// Add an event to the event loop runner
|
|
|
|
|
//
|
|
|
|
|
// It will determine if the event should be immediately sent to the user or buffered for later
|
2019-03-16 18:40:35 -04:00
|
|
|
pub fn send_event(&self, event: Event<T>) {
|
2019-04-25 00:02:13 -04:00
|
|
|
// If the event loop is closed, it should discard any new events
|
|
|
|
|
if self.closed() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-03-22 22:15:49 -04:00
|
|
|
|
2019-04-25 00:02:13 -04:00
|
|
|
let start_cause = StartCause::Poll; // TODO: determine start cause
|
|
|
|
|
|
|
|
|
|
// Determine if event handling is in process, and then release the borrow on the runner
|
|
|
|
|
let is_busy = if let Some(ref runner) = *self.runner.borrow() {
|
|
|
|
|
runner.is_busy
|
2019-03-22 22:15:49 -04:00
|
|
|
} else {
|
2019-04-25 00:02:13 -04:00
|
|
|
true // If there is no event runner yet, then there's no point in processing events
|
2019-03-22 22:15:49 -04:00
|
|
|
};
|
2019-04-25 00:02:13 -04:00
|
|
|
|
|
|
|
|
if is_busy {
|
|
|
|
|
self.events.borrow_mut().push_back(event);
|
|
|
|
|
} else {
|
|
|
|
|
// Handle starting a new batch of events
|
|
|
|
|
//
|
|
|
|
|
// 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
|
|
|
|
|
self.handle_event(Event::NewEvents(start_cause));
|
|
|
|
|
self.handle_event(event);
|
|
|
|
|
self.handle_event(Event::EventsCleared);
|
|
|
|
|
|
|
|
|
|
// If the event loop is closed, it has been closed this iteration and now the closing
|
|
|
|
|
// event should be emitted
|
|
|
|
|
if self.closed() {
|
|
|
|
|
self.handle_event(Event::LoopDestroyed);
|
|
|
|
|
}
|
2019-04-02 22:31:30 -04:00
|
|
|
}
|
2019-03-22 22:15:49 -04:00
|
|
|
}
|
|
|
|
|
|
2019-04-25 00:02:13 -04:00
|
|
|
// Check if the event loop is currntly closed
|
|
|
|
|
fn closed(&self) -> bool {
|
|
|
|
|
match *self.runner.borrow() {
|
|
|
|
|
Some(ref runner) => runner.control == ControlFlow::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
|
|
|
|
|
//
|
|
|
|
|
// It should only ever be called from send_event
|
2019-03-22 22:15:49 -04:00
|
|
|
fn handle_event(&self, event: Event<T>) {
|
2019-04-25 00:02:13 -04:00
|
|
|
let closed = self.closed();
|
|
|
|
|
|
2019-03-11 22:22:21 -04:00
|
|
|
match *self.runner.borrow_mut() {
|
2019-04-25 00:02:13 -04:00
|
|
|
Some(ref mut runner) => {
|
|
|
|
|
// An event is being processed, so the runner should be marked busy
|
|
|
|
|
runner.is_busy = true;
|
|
|
|
|
|
2019-03-11 22:22:21 -04:00
|
|
|
// TODO: bracket this in control flow events?
|
|
|
|
|
(runner.event_handler)(event, &mut runner.control);
|
2019-04-25 00:02:13 -04:00
|
|
|
|
|
|
|
|
// Maintain closed state, even if the callback changes it
|
2019-03-18 22:13:30 -04:00
|
|
|
if closed {
|
|
|
|
|
runner.control = ControlFlow::Exit;
|
|
|
|
|
}
|
2019-04-25 00:02:13 -04:00
|
|
|
|
|
|
|
|
// An event is no longer being processed
|
|
|
|
|
runner.is_busy = false;
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
2019-04-25 00:02:13 -04:00
|
|
|
// If an event is being handled without a runner somehow, add it to the event queue so
|
|
|
|
|
// it will eventually be processed
|
2019-03-18 22:13:30 -04:00
|
|
|
_ => self.events.borrow_mut().push_back(event)
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
2019-04-25 00:02:13 -04:00
|
|
|
|
|
|
|
|
// 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 !closed && self.runner.borrow().is_some() {
|
|
|
|
|
// Take an event out of the queue and handle it
|
2019-03-22 22:15:49 -04:00
|
|
|
if let Some(event) = self.events.borrow_mut().pop_front() {
|
|
|
|
|
self.handle_event(event);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-11 22:22:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|