mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 14:21:31 +11:00
Draft web
platform structure
This commit is contained in:
parent
eea9530f38
commit
c5703eb00a
|
@ -9,13 +9,13 @@
|
||||||
//! [create_proxy]: ./struct.EventLoop.html#method.create_proxy
|
//! [create_proxy]: ./struct.EventLoop.html#method.create_proxy
|
||||||
//! [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 instant::Instant;
|
use instant::Instant;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::{error, fmt};
|
||||||
|
|
||||||
use platform_impl;
|
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use monitor::{AvailableMonitorsIter, MonitorHandle};
|
use monitor::{AvailableMonitorsIter, MonitorHandle};
|
||||||
|
use platform_impl;
|
||||||
|
|
||||||
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
||||||
/// the events loop.
|
/// the events loop.
|
||||||
|
@ -32,7 +32,7 @@ use monitor::{AvailableMonitorsIter, MonitorHandle};
|
||||||
/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread.
|
/// `EventLoopProxy` allows you to wake up an `EventLoop` from an other thread.
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
||||||
pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
|
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Target that associates windows with an `EventLoop`.
|
/// Target that associates windows with an `EventLoop`.
|
||||||
|
@ -42,7 +42,7 @@ pub struct EventLoop<T: 'static> {
|
||||||
/// take `&EventLoop`.
|
/// take `&EventLoop`.
|
||||||
pub struct EventLoopWindowTarget<T: 'static> {
|
pub struct EventLoopWindowTarget<T: 'static> {
|
||||||
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
|
pub(crate) p: platform_impl::EventLoopWindowTarget<T>,
|
||||||
pub(crate) _marker: ::std::marker::PhantomData<*mut ()> // Not Send nor Sync
|
pub(crate) _marker: ::std::marker::PhantomData<*mut ()>, // Not Send nor Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for EventLoop<T> {
|
impl<T> fmt::Debug for EventLoop<T> {
|
||||||
|
@ -82,7 +82,7 @@ pub enum ControlFlow {
|
||||||
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
/// Send a `LoopDestroyed` event and stop the event loop. This variant is *sticky* - once set,
|
||||||
/// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
|
/// `control_flow` cannot be changed from `Exit`, and any future attempts to do so will result
|
||||||
/// in the `control_flow` parameter being reset to `Exit`.
|
/// in the `control_flow` parameter being reset to `Exit`.
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ControlFlow {
|
impl Default for ControlFlow {
|
||||||
|
@ -133,7 +133,8 @@ impl<T> EventLoop<T> {
|
||||||
/// [`ControlFlow`]: ./enum.ControlFlow.html
|
/// [`ControlFlow`]: ./enum.ControlFlow.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn run<F>(self, event_handler: F) -> !
|
pub fn run<F>(self, event_handler: F) -> !
|
||||||
where F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.event_loop.run(event_handler)
|
self.event_loop.run(event_handler)
|
||||||
}
|
}
|
||||||
|
@ -151,13 +152,17 @@ impl<T> EventLoop<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> AvailableMonitorsIter {
|
pub fn available_monitors(&self) -> AvailableMonitorsIter {
|
||||||
let data = self.event_loop.available_monitors();
|
let data = self.event_loop.available_monitors();
|
||||||
AvailableMonitorsIter{ data: data.into_iter() }
|
AvailableMonitorsIter {
|
||||||
|
data: data.into_iter(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the primary monitor of the system.
|
/// Returns the primary monitor of the system.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
MonitorHandle { inner: self.event_loop.primary_monitor() }
|
MonitorHandle {
|
||||||
|
inner: self.event_loop.primary_monitor(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,4 +212,3 @@ impl error::Error for EventLoopClosed {
|
||||||
"Tried to wake up a closed `EventLoop`"
|
"Tried to wake up a closed `EventLoop`"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
src/lib.rs
49
src/lib.rs
|
@ -97,23 +97,54 @@ extern crate objc;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
extern crate cocoa;
|
extern crate cocoa;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
extern crate dispatch;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
extern crate core_foundation;
|
extern crate core_foundation;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
extern crate core_graphics;
|
extern crate core_graphics;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#[cfg(target_os = "macos")]
|
||||||
extern crate x11_dl;
|
extern crate dispatch;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "windows"))]
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd",
|
||||||
|
target_os = "windows"
|
||||||
|
))]
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
extern crate percent_encoding;
|
extern crate percent_encoding;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
extern crate smithay_client_toolkit as sctk;
|
extern crate smithay_client_toolkit as sctk;
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
extern crate x11_dl;
|
||||||
#[cfg(feature = "stdweb")]
|
#[cfg(feature = "stdweb")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate stdweb;
|
extern crate stdweb;
|
||||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "dragonfly",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
extern crate calloop;
|
extern crate calloop;
|
||||||
#[cfg(feature = "web-sys")]
|
#[cfg(feature = "web-sys")]
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
@ -126,8 +157,8 @@ pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod event_loop;
|
pub mod event_loop;
|
||||||
mod icon;
|
mod icon;
|
||||||
|
pub mod monitor;
|
||||||
mod platform_impl;
|
mod platform_impl;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
pub mod monitor;
|
|
||||||
|
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
|
|
|
@ -20,7 +20,5 @@ pub mod macos;
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
pub mod stdweb;
|
|
||||||
pub mod web_sys;
|
|
||||||
|
|
||||||
pub mod desktop;
|
pub mod desktop;
|
||||||
|
pub mod web;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#![cfg(feature = "stdweb")]
|
|
||||||
|
|
||||||
use stdweb::web::html_element::CanvasElement;
|
|
||||||
|
|
||||||
pub trait WindowExtStdweb {
|
|
||||||
fn canvas(&self) -> CanvasElement;
|
|
||||||
}
|
|
||||||
|
|
15
src/platform/web.rs
Normal file
15
src/platform/web.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#[cfg(feature = "stdweb")]
|
||||||
|
use stdweb::web::html_element::CanvasElement;
|
||||||
|
|
||||||
|
#[cfg(feature = "stdweb")]
|
||||||
|
pub trait WindowExtStdweb {
|
||||||
|
fn canvas(&self) -> CanvasElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "web-sys")]
|
||||||
|
use web_sys::HtmlCanvasElement;
|
||||||
|
|
||||||
|
#[cfg(feature = "web-sys")]
|
||||||
|
pub trait WindowExtWebSys {
|
||||||
|
fn canvas(&self) -> HtmlCanvasElement;
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
#![cfg(feature = "web-sys")]
|
|
||||||
|
|
||||||
use web_sys::HtmlCanvasElement;
|
|
||||||
|
|
||||||
pub trait WindowExtWebSys {
|
|
||||||
fn canvas(&self) -> HtmlCanvasElement;
|
|
||||||
}
|
|
|
@ -24,11 +24,8 @@ mod platform;
|
||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
#[path = "emscripten/mod.rs"]
|
#[path = "emscripten/mod.rs"]
|
||||||
mod platform;
|
mod platform;
|
||||||
#[cfg(feature = "stdweb")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[path = "stdweb/mod.rs"]
|
#[path = "web/mod.rs"]
|
||||||
mod platform;
|
|
||||||
#[cfg(feature = "web_sys")]
|
|
||||||
#[path = "web_sys/mod.rs"]
|
|
||||||
mod platform;
|
mod platform;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
|
@ -42,7 +39,6 @@ mod platform;
|
||||||
not(target_os = "netbsd"),
|
not(target_os = "netbsd"),
|
||||||
not(target_os = "openbsd"),
|
not(target_os = "openbsd"),
|
||||||
not(target_os = "emscripten"),
|
not(target_os = "emscripten"),
|
||||||
not(feature = "stdweb"),
|
not(target_arch = "wasm32"),
|
||||||
not(feature = "web_sys")
|
|
||||||
))]
|
))]
|
||||||
compile_error!("The platform you're compiling for is not supported by winit");
|
compile_error!("The platform you're compiling for is not supported by winit");
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use dpi::LogicalPosition;
|
use dpi::LogicalPosition;
|
||||||
use event::{DeviceId as RootDI, ElementState, Event, KeyboardInput, MouseScrollDelta, StartCause, TouchPhase, WindowEvent};
|
use event::{
|
||||||
use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed};
|
DeviceId as RootDI, ElementState, Event, KeyboardInput, MouseScrollDelta, StartCause,
|
||||||
use instant::{Duration, Instant};
|
TouchPhase, WindowEvent,
|
||||||
use window::{WindowId as RootWI};
|
|
||||||
use stdweb::{
|
|
||||||
traits::*,
|
|
||||||
web::{
|
|
||||||
document,
|
|
||||||
event::*,
|
|
||||||
html_element::CanvasElement,
|
|
||||||
window,
|
|
||||||
TimeoutHandle,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
use event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
||||||
|
use instant::{Duration, Instant};
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{VecDeque, vec_deque::IntoIter as VecDequeIter},
|
|
||||||
clone::Clone,
|
clone::Clone,
|
||||||
|
collections::{vec_deque::IntoIter as VecDequeIter, VecDeque},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
use stdweb::{
|
||||||
|
traits::*,
|
||||||
|
web::{document, event::*, html_element::CanvasElement, window, TimeoutHandle},
|
||||||
|
};
|
||||||
|
use window::WindowId as RootWI;
|
||||||
|
|
||||||
#[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);
|
||||||
|
@ -45,15 +42,15 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
EventLoopWindowTarget {
|
EventLoopWindowTarget {
|
||||||
runner: EventLoopRunnerShared(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: 'static> {
|
pub struct EventLoopProxy<T: 'static> {
|
||||||
runner: EventLoopRunnerShared<T>
|
runner: EventLoopRunnerShared<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
|
@ -87,15 +84,15 @@ enum ControlFlowStatus {
|
||||||
WaitUntil {
|
WaitUntil {
|
||||||
timeout: TimeoutHandle,
|
timeout: TimeoutHandle,
|
||||||
start: Instant,
|
start: Instant,
|
||||||
end: Instant
|
end: Instant,
|
||||||
},
|
},
|
||||||
Wait {
|
Wait {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
},
|
},
|
||||||
Poll {
|
Poll {
|
||||||
timeout: TimeoutHandle
|
timeout: TimeoutHandle,
|
||||||
},
|
},
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlFlowStatus {
|
impl ControlFlowStatus {
|
||||||
|
@ -122,7 +119,7 @@ impl<T> EventLoop<T> {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
elw: RootELW {
|
elw: RootELW {
|
||||||
p: EventLoopWindowTarget::new(),
|
p: EventLoopWindowTarget::new(),
|
||||||
_marker: PhantomData
|
_marker: PhantomData,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,12 +133,14 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F>(self, mut event_handler: F) -> !
|
pub fn run<F>(self, mut event_handler: F) -> !
|
||||||
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow) {
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
|
{
|
||||||
let runner = self.elw.p.runner;
|
let runner = self.elw.p.runner;
|
||||||
|
|
||||||
let relw = RootELW {
|
let relw = RootELW {
|
||||||
p: EventLoopWindowTarget::new(),
|
p: EventLoopWindowTarget::new(),
|
||||||
_marker: PhantomData
|
_marker: PhantomData,
|
||||||
};
|
};
|
||||||
runner.set_listener(Box::new(move |evt, ctrl| event_handler(evt, &relw, ctrl)));
|
runner.set_listener(Box::new(move |evt, ctrl| event_handler(evt, &relw, ctrl)));
|
||||||
|
|
||||||
|
@ -149,15 +148,14 @@ impl<T> EventLoop<T> {
|
||||||
add_event(&runner, document, |elrs, _: BlurEvent| {
|
add_event(&runner, document, |elrs, _: BlurEvent| {
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
window_id: RootWI(WindowId),
|
window_id: RootWI(WindowId),
|
||||||
event: WindowEvent::Focused(false)
|
event: WindowEvent::Focused(false),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(&runner, document, |elrs, _: FocusEvent| {
|
add_event(&runner, document, |elrs, _: FocusEvent| {
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
window_id: RootWI(WindowId),
|
window_id: RootWI(WindowId),
|
||||||
event: WindowEvent::Focused(true)
|
event: WindowEvent::Focused(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
add_event(&runner, document, |elrs, event: KeyDownEvent| {
|
add_event(&runner, document, |elrs, event: KeyDownEvent| {
|
||||||
let key = event.key();
|
let key = event.key();
|
||||||
|
@ -167,7 +165,7 @@ impl<T> EventLoop<T> {
|
||||||
if let (Some(key), None) = (first, second) {
|
if let (Some(key), None) = (first, second) {
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
window_id: RootWI(WindowId),
|
window_id: RootWI(WindowId),
|
||||||
event: WindowEvent::ReceivedCharacter(key)
|
event: WindowEvent::ReceivedCharacter(key),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
|
@ -179,8 +177,8 @@ impl<T> EventLoop<T> {
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
virtual_keycode: button_mapping(&event),
|
virtual_keycode: button_mapping(&event),
|
||||||
modifiers: keyboard_modifiers_state(&event),
|
modifiers: keyboard_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(&runner, document, |elrs, event: KeyUpEvent| {
|
add_event(&runner, document, |elrs, event: KeyUpEvent| {
|
||||||
|
@ -193,8 +191,8 @@ impl<T> EventLoop<T> {
|
||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
virtual_keycode: button_mapping(&event),
|
virtual_keycode: button_mapping(&event),
|
||||||
modifiers: keyboard_modifiers_state(&event),
|
modifiers: keyboard_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -210,7 +208,7 @@ impl<T> EventLoop<T> {
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||||
EventLoopProxy {
|
EventLoopProxy {
|
||||||
runner: self.elw.p.runner.clone()
|
runner: self.elw.p.runner.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,21 +217,21 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElement) {
|
pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElement) {
|
||||||
add_event(elrs, canvas, |elrs, event: PointerOutEvent| {
|
add_event(elrs, canvas, |elrs, event: PointerOutEvent| {
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
window_id: RootWI(WindowId),
|
window_id: RootWI(WindowId),
|
||||||
event: WindowEvent::CursorLeft {
|
event: WindowEvent::CursorLeft {
|
||||||
device_id: RootDI(DeviceId(event.pointer_id()))
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(elrs, canvas, |elrs, event: PointerOverEvent| {
|
add_event(elrs, canvas, |elrs, event: PointerOverEvent| {
|
||||||
elrs.send_event(Event::WindowEvent {
|
elrs.send_event(Event::WindowEvent {
|
||||||
window_id: RootWI(WindowId),
|
window_id: RootWI(WindowId),
|
||||||
event: WindowEvent::CursorEntered {
|
event: WindowEvent::CursorEntered {
|
||||||
device_id: RootDI(DeviceId(event.pointer_id()))
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(elrs, canvas, |elrs, event: PointerMoveEvent| {
|
add_event(elrs, canvas, |elrs, event: PointerMoveEvent| {
|
||||||
|
@ -243,10 +241,10 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElem
|
||||||
device_id: RootDI(DeviceId(event.pointer_id())),
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||||
position: LogicalPosition {
|
position: LogicalPosition {
|
||||||
x: event.offset_x(),
|
x: event.offset_x(),
|
||||||
y: event.offset_y()
|
y: event.offset_y(),
|
||||||
},
|
},
|
||||||
modifiers: mouse_modifiers_state(&event)
|
modifiers: mouse_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(elrs, canvas, |elrs, event: PointerUpEvent| {
|
add_event(elrs, canvas, |elrs, event: PointerUpEvent| {
|
||||||
|
@ -256,8 +254,8 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElem
|
||||||
device_id: RootDI(DeviceId(event.pointer_id())),
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
button: mouse_button(&event),
|
button: mouse_button(&event),
|
||||||
modifiers: mouse_modifiers_state(&event)
|
modifiers: mouse_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(elrs, canvas, |elrs, event: PointerDownEvent| {
|
add_event(elrs, canvas, |elrs, event: PointerDownEvent| {
|
||||||
|
@ -267,8 +265,8 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElem
|
||||||
device_id: RootDI(DeviceId(event.pointer_id())),
|
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
button: mouse_button(&event),
|
button: mouse_button(&event),
|
||||||
modifiers: mouse_modifiers_state(&event)
|
modifiers: mouse_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
add_event(elrs, canvas, |elrs, event: MouseWheelEvent| {
|
add_event(elrs, canvas, |elrs, event: MouseWheelEvent| {
|
||||||
|
@ -285,21 +283,27 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &CanvasElem
|
||||||
device_id: RootDI(DeviceId(0)),
|
device_id: RootDI(DeviceId(0)),
|
||||||
delta,
|
delta,
|
||||||
phase: TouchPhase::Moved,
|
phase: TouchPhase::Moved,
|
||||||
modifiers: mouse_modifiers_state(&event)
|
modifiers: mouse_modifiers_state(&event),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_event<T: 'static, E, F>(elrs: &EventLoopRunnerShared<T>, target: &impl IEventTarget, mut handler: F)
|
fn add_event<T: 'static, E, F>(
|
||||||
where E: ConcreteEvent, F: FnMut(&EventLoopRunnerShared<T>, E) + 'static {
|
elrs: &EventLoopRunnerShared<T>,
|
||||||
|
target: &impl IEventTarget,
|
||||||
|
mut handler: F,
|
||||||
|
) where
|
||||||
|
E: ConcreteEvent,
|
||||||
|
F: FnMut(&EventLoopRunnerShared<T>, E) + 'static,
|
||||||
|
{
|
||||||
let elrs = elrs.clone();
|
let elrs = elrs.clone();
|
||||||
|
|
||||||
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.0.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,
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
|
@ -338,23 +342,26 @@ impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
if let Event::NewEvents(cause) = event {
|
if let Event::NewEvents(cause) = event {
|
||||||
(cause, true)
|
(cause, true)
|
||||||
} else {
|
} else {
|
||||||
(match runner.control {
|
(
|
||||||
ControlFlowStatus::Init => StartCause::Init,
|
match runner.control {
|
||||||
ControlFlowStatus::Poll { .. } => {
|
ControlFlowStatus::Init => StartCause::Init,
|
||||||
StartCause::Poll
|
ControlFlowStatus::Poll { .. } => StartCause::Poll,
|
||||||
}
|
ControlFlowStatus::Wait { start } => StartCause::WaitCancelled {
|
||||||
ControlFlowStatus::Wait { start } => StartCause::WaitCancelled {
|
|
||||||
start,
|
|
||||||
requested_resume: None,
|
|
||||||
},
|
|
||||||
ControlFlowStatus::WaitUntil { start, end, .. } => {
|
|
||||||
StartCause::WaitCancelled {
|
|
||||||
start,
|
start,
|
||||||
requested_resume: Some(end)
|
requested_resume: None,
|
||||||
|
},
|
||||||
|
ControlFlowStatus::WaitUntil { start, end, .. } => {
|
||||||
|
StartCause::WaitCancelled {
|
||||||
|
start,
|
||||||
|
requested_resume: Some(end),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlowStatus::Exit => {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ControlFlowStatus::Exit => { return; }
|
false,
|
||||||
}, false)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -405,7 +412,7 @@ impl<T: 'static> EventLoopRunnerShared<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.0.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
|
||||||
|
@ -422,13 +429,18 @@ impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
// Start any necessary timeouts etc
|
// Start any necessary timeouts etc
|
||||||
fn apply_control_flow(&self, control_flow: ControlFlow) {
|
fn apply_control_flow(&self, control_flow: ControlFlow) {
|
||||||
let mut control_flow_status = match control_flow {
|
let mut control_flow_status = match control_flow {
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
let cloned = self.clone();
|
let cloned = self.clone();
|
||||||
ControlFlowStatus::Poll {
|
ControlFlowStatus::Poll {
|
||||||
timeout: window().set_clearable_timeout(move || cloned.send_event(Event::NewEvents(StartCause::Poll)), 1)
|
timeout: window().set_clearable_timeout(
|
||||||
|
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
|
||||||
|
1,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlFlow::Wait => ControlFlowStatus::Wait { start: Instant::now() },
|
ControlFlow::Wait => ControlFlowStatus::Wait {
|
||||||
|
start: Instant::now(),
|
||||||
|
},
|
||||||
ControlFlow::WaitUntil(end) => {
|
ControlFlow::WaitUntil(end) => {
|
||||||
let cloned = self.clone();
|
let cloned = self.clone();
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
@ -440,12 +452,15 @@ impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
ControlFlowStatus::WaitUntil {
|
ControlFlowStatus::WaitUntil {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
timeout: window().set_clearable_timeout(move || cloned.send_event(Event::NewEvents(StartCause::Poll)), delay.as_millis() as u32)
|
timeout: window().set_clearable_timeout(
|
||||||
|
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
|
||||||
|
delay.as_millis() as u32,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlFlow::Exit => ControlFlowStatus::Exit,
|
ControlFlow::Exit => ControlFlowStatus::Exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
match *self.0.runner.borrow_mut() {
|
match *self.0.runner.borrow_mut() {
|
||||||
Some(ref mut runner) => {
|
Some(ref mut runner) => {
|
||||||
// Put the new control flow status in the runner, and take out the old one
|
// Put the new control flow status in the runner, and take out the old one
|
||||||
|
@ -454,11 +469,12 @@ impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
// set_timeout invocations
|
// set_timeout invocations
|
||||||
std::mem::swap(&mut runner.control, &mut control_flow_status);
|
std::mem::swap(&mut runner.control, &mut control_flow_status);
|
||||||
match control_flow_status {
|
match control_flow_status {
|
||||||
ControlFlowStatus::Poll { timeout } | ControlFlowStatus::WaitUntil { timeout, .. } => timeout.clear(),
|
ControlFlowStatus::Poll { timeout }
|
||||||
|
| ControlFlowStatus::WaitUntil { timeout, .. } => timeout.clear(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => ()
|
None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,4 +494,3 @@ impl<T: 'static> EventLoopRunnerShared<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,13 @@ mod event_loop;
|
||||||
mod events;
|
mod events;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
pub use self::event_loop::{DeviceId, EventLoop, EventLoopRunnerShared, EventLoopWindowTarget, EventLoopProxy, register};
|
pub use self::event_loop::{
|
||||||
pub use self::window::{MonitorHandle, Window, WindowId, PlatformSpecificWindowBuilderAttributes};
|
register, DeviceId, EventLoop, EventLoopProxy, EventLoopRunnerShared, EventLoopWindowTarget,
|
||||||
pub use self::events::{button_mapping, mouse_modifiers_state, mouse_button, keyboard_modifiers_state, scancode};
|
};
|
||||||
|
pub use self::events::{
|
||||||
|
button_mapping, keyboard_modifiers_state, mouse_button, mouse_modifiers_state, scancode,
|
||||||
|
};
|
||||||
|
pub use self::window::{MonitorHandle, PlatformSpecificWindowBuilderAttributes, Window, WindowId};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OsError(String);
|
pub struct OsError(String);
|
||||||
|
|
|
@ -1,22 +1,16 @@
|
||||||
|
use super::{register, EventLoopWindowTarget, OsError};
|
||||||
use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
||||||
use error::{ExternalError, NotSupportedError, OsError as RootOE};
|
use error::{ExternalError, NotSupportedError, OsError as RootOE};
|
||||||
use event::{Event, WindowEvent};
|
use event::{Event, WindowEvent};
|
||||||
use icon::Icon;
|
use icon::Icon;
|
||||||
|
use monitor::MonitorHandle as RootMH;
|
||||||
use platform::stdweb::WindowExtStdweb;
|
use platform::stdweb::WindowExtStdweb;
|
||||||
use monitor::{MonitorHandle as RootMH};
|
|
||||||
use window::{CursorIcon, Window as RootWindow, WindowAttributes, WindowId as RootWI};
|
|
||||||
use super::{EventLoopWindowTarget, OsError, register};
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use stdweb::{
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||||
traits::*,
|
use std::collections::VecDeque;
|
||||||
unstable::TryInto
|
use stdweb::web::{document, html_element::CanvasElement, window};
|
||||||
};
|
use stdweb::{traits::*, unstable::TryInto};
|
||||||
use stdweb::web::{
|
use window::{CursorIcon, Window as RootWindow, WindowAttributes, WindowId as RootWI};
|
||||||
document, window,
|
|
||||||
html_element::CanvasElement,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct MonitorHandle;
|
pub struct MonitorHandle;
|
||||||
|
@ -59,14 +53,19 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new<T>(target: &EventLoopWindowTarget<T>, attr: WindowAttributes,
|
pub fn new<T>(
|
||||||
_: PlatformSpecificWindowBuilderAttributes) -> Result<Self, RootOE> {
|
target: &EventLoopWindowTarget<T>,
|
||||||
|
attr: WindowAttributes,
|
||||||
|
_: PlatformSpecificWindowBuilderAttributes,
|
||||||
|
) -> Result<Self, RootOE> {
|
||||||
let element = document()
|
let element = document()
|
||||||
.create_element("canvas")
|
.create_element("canvas")
|
||||||
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
||||||
let canvas: CanvasElement = element.try_into()
|
let canvas: CanvasElement = element
|
||||||
|
.try_into()
|
||||||
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
||||||
document().body()
|
document()
|
||||||
|
.body()
|
||||||
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
|
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
|
||||||
.append_child(&canvas);
|
.append_child(&canvas);
|
||||||
|
|
||||||
|
@ -75,20 +74,19 @@ impl Window {
|
||||||
let runner = target.runner.clone();
|
let runner = target.runner.clone();
|
||||||
let redraw = Box::new(move || {
|
let redraw = Box::new(move || {
|
||||||
let runner = runner.clone();
|
let runner = runner.clone();
|
||||||
window().request_animation_frame(move |_| runner.send_event(Event::WindowEvent {
|
window().request_animation_frame(move |_| {
|
||||||
window_id: RootWI(WindowId),
|
runner.send_event(Event::WindowEvent {
|
||||||
event: WindowEvent::RedrawRequested
|
window_id: RootWI(WindowId),
|
||||||
}));
|
event: WindowEvent::RedrawRequested,
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let window = Window {
|
let window = Window {
|
||||||
canvas,
|
canvas,
|
||||||
redraw,
|
redraw,
|
||||||
previous_pointer: RefCell::new("auto"),
|
previous_pointer: RefCell::new("auto"),
|
||||||
position: RefCell::new(LogicalPosition {
|
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
|
||||||
x: 0.0,
|
|
||||||
y: 0.0
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(inner_size) = attr.inner_size {
|
if let Some(inner_size) = attr.inner_size {
|
||||||
|
@ -139,11 +137,14 @@ impl Window {
|
||||||
|
|
||||||
pub fn set_outer_position(&self, position: LogicalPosition) {
|
pub fn set_outer_position(&self, position: LogicalPosition) {
|
||||||
*self.position.borrow_mut() = position;
|
*self.position.borrow_mut() = position;
|
||||||
self.canvas.set_attribute("position", "fixed")
|
self.canvas
|
||||||
|
.set_attribute("position", "fixed")
|
||||||
.expect("Setting the position for the canvas");
|
.expect("Setting the position for the canvas");
|
||||||
self.canvas.set_attribute("left", &position.x.to_string())
|
self.canvas
|
||||||
|
.set_attribute("left", &position.x.to_string())
|
||||||
.expect("Setting the position for the canvas");
|
.expect("Setting the position for the canvas");
|
||||||
self.canvas.set_attribute("top", &position.y.to_string())
|
self.canvas
|
||||||
|
.set_attribute("top", &position.y.to_string())
|
||||||
.expect("Setting the position for the canvas");
|
.expect("Setting the position for the canvas");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ impl Window {
|
||||||
pub fn inner_size(&self) -> LogicalSize {
|
pub fn inner_size(&self) -> LogicalSize {
|
||||||
LogicalSize {
|
LogicalSize {
|
||||||
width: self.canvas.width() as f64,
|
width: self.canvas.width() as f64,
|
||||||
height: self.canvas.height() as f64
|
height: self.canvas.height() as f64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +160,7 @@ impl Window {
|
||||||
pub fn outer_size(&self) -> LogicalSize {
|
pub fn outer_size(&self) -> LogicalSize {
|
||||||
LogicalSize {
|
LogicalSize {
|
||||||
width: self.canvas.width() as f64,
|
width: self.canvas.width() as f64,
|
||||||
height: self.canvas.height() as f64
|
height: self.canvas.height() as f64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +232,8 @@ impl Window {
|
||||||
CursorIcon::RowResize => "row-resize",
|
CursorIcon::RowResize => "row-resize",
|
||||||
};
|
};
|
||||||
*self.previous_pointer.borrow_mut() = text;
|
*self.previous_pointer.borrow_mut() = text;
|
||||||
self.canvas.set_attribute("cursor", text)
|
self.canvas
|
||||||
|
.set_attribute("cursor", text)
|
||||||
.expect("Setting the cursor on the canvas");
|
.expect("Setting the cursor on the canvas");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +252,12 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_visible(&self, visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
if !visible {
|
if !visible {
|
||||||
self.canvas.set_attribute("cursor", "none")
|
self.canvas
|
||||||
|
.set_attribute("cursor", "none")
|
||||||
.expect("Setting the cursor on the canvas");
|
.expect("Setting the cursor on the canvas");
|
||||||
} else {
|
} else {
|
||||||
self.canvas.set_attribute("cursor", *self.previous_pointer.borrow())
|
self.canvas
|
||||||
|
.set_attribute("cursor", *self.previous_pointer.borrow())
|
||||||
.expect("Setting the cursor on the canvas");
|
.expect("Setting the cursor on the canvas");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +301,7 @@ impl Window {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_monitor(&self) -> RootMH {
|
pub fn current_monitor(&self) -> RootMH {
|
||||||
RootMH {
|
RootMH {
|
||||||
inner: MonitorHandle
|
inner: MonitorHandle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
src/platform_impl/web/device.rs
Normal file
8
src/platform_impl/web/device.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Id(pub i32);
|
||||||
|
|
||||||
|
impl Id {
|
||||||
|
pub unsafe fn dummy() -> Self {
|
||||||
|
Id(0)
|
||||||
|
}
|
||||||
|
}
|
10
src/platform_impl/web/error.rs
Normal file
10
src/platform_impl/web/error.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OsError(pub String);
|
||||||
|
|
||||||
|
impl fmt::Display for OsError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
112
src/platform_impl/web/event_loop/mod.rs
Normal file
112
src/platform_impl/web/event_loop/mod.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
mod proxy;
|
||||||
|
mod runner;
|
||||||
|
mod state;
|
||||||
|
mod window_target;
|
||||||
|
|
||||||
|
pub use self::proxy::Proxy;
|
||||||
|
pub use self::window_target::WindowTarget;
|
||||||
|
|
||||||
|
use super::{backend, device, monitor, window};
|
||||||
|
use crate::event::{DeviceId, ElementState, Event, KeyboardInput, WindowEvent};
|
||||||
|
use crate::event_loop as root;
|
||||||
|
use crate::window::WindowId;
|
||||||
|
|
||||||
|
use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct EventLoop<T: 'static> {
|
||||||
|
elw: root::EventLoopWindowTarget<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> EventLoop<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
EventLoop {
|
||||||
|
elw: root::EventLoopWindowTarget {
|
||||||
|
p: WindowTarget::new(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
|
||||||
|
VecDeque::new().into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn primary_monitor(&self) -> monitor::Handle {
|
||||||
|
monitor::Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<F>(self, mut event_handler: F) -> !
|
||||||
|
where
|
||||||
|
F: 'static + FnMut(Event<T>, &root::EventLoopWindowTarget<T>, &mut root::ControlFlow),
|
||||||
|
{
|
||||||
|
let target = root::EventLoopWindowTarget {
|
||||||
|
p: self.elw.p.clone(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
let runner = self.elw.p.run(Box::new(move |event, flow| {
|
||||||
|
event_handler(event, &target, flow)
|
||||||
|
}));
|
||||||
|
|
||||||
|
backend::Document::on_blur(|| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::Focused(false),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
backend::Document::on_focus(|| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::Focused(true),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
backend::Document::on_key_down(|scancode, virtual_keycode, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::KeyboardInput {
|
||||||
|
device_id: DeviceId(unsafe { device::Id::dummy() }),
|
||||||
|
input: KeyboardInput {
|
||||||
|
scancode,
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
virtual_keycode,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
backend::Document::on_key_up(|scancode, virtual_keycode, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::KeyboardInput {
|
||||||
|
device_id: DeviceId(unsafe { device::Id::dummy() }),
|
||||||
|
input: KeyboardInput {
|
||||||
|
scancode,
|
||||||
|
state: ElementState::Released,
|
||||||
|
virtual_keycode,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 '!'
|
||||||
|
backend::throw(
|
||||||
|
"Using exceptions for control flow, don't mind me. This isn't actually an error!",
|
||||||
|
);
|
||||||
|
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_proxy(&self) -> Proxy<T> {
|
||||||
|
self.elw.p.proxy()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_target(&self) -> &root::EventLoopWindowTarget<T> {
|
||||||
|
&self.elw
|
||||||
|
}
|
||||||
|
}
|
19
src/platform_impl/web/event_loop/proxy.rs
Normal file
19
src/platform_impl/web/event_loop/proxy.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use super::runner;
|
||||||
|
use crate::event::Event;
|
||||||
|
use crate::event_loop::EventLoopClosed;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Proxy<T: 'static> {
|
||||||
|
runner: runner::Shared<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Proxy<T> {
|
||||||
|
pub fn new(runner: runner::Shared<T>) -> Self {
|
||||||
|
Proxy { runner }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
|
||||||
|
self.runner.send_event(Event::UserEvent(event));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
216
src/platform_impl/web/event_loop/runner.rs
Normal file
216
src/platform_impl/web/event_loop/runner.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
use super::{backend, state::State};
|
||||||
|
use crate::event::{Event, StartCause};
|
||||||
|
use crate::event_loop as root;
|
||||||
|
|
||||||
|
use instant::{Duration, Instant};
|
||||||
|
use std::{cell::RefCell, clone::Clone, collections::VecDeque, rc::Rc};
|
||||||
|
|
||||||
|
pub struct Shared<T>(Rc<Execution<T>>);
|
||||||
|
|
||||||
|
impl<T> Clone for Shared<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Shared(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Execution<T> {
|
||||||
|
runner: RefCell<Option<Runner<T>>>,
|
||||||
|
events: RefCell<VecDeque<Event<T>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Runner<T> {
|
||||||
|
state: State,
|
||||||
|
is_busy: bool,
|
||||||
|
event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Runner<T> {
|
||||||
|
pub fn new(event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) -> Self {
|
||||||
|
Runner {
|
||||||
|
state: State::Init,
|
||||||
|
is_busy: false,
|
||||||
|
event_handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Shared<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Shared(Rc::new(Execution {
|
||||||
|
runner: RefCell::new(None),
|
||||||
|
events: RefCell::new(VecDeque::new()),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
pub fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) {
|
||||||
|
self.0.runner.replace(Some(Runner::new(event_handler)));
|
||||||
|
self.send_event(Event::NewEvents(StartCause::Init));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
pub fn send_event(&self, event: Event<T>) {
|
||||||
|
// If the event loop is closed, it should discard any new events
|
||||||
|
if self.closed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if event handling is in process, and then release the borrow on the runner
|
||||||
|
let (start_cause, event_is_start) = match *self.0.runner.borrow() {
|
||||||
|
Some(ref runner) if !runner.is_busy => {
|
||||||
|
if let Event::NewEvents(cause) = event {
|
||||||
|
(cause, true)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
match runner.state {
|
||||||
|
State::Init => StartCause::Init,
|
||||||
|
State::Poll { .. } => StartCause::Poll,
|
||||||
|
State::Wait { start } => StartCause::WaitCancelled {
|
||||||
|
start,
|
||||||
|
requested_resume: None,
|
||||||
|
},
|
||||||
|
State::WaitUntil { start, end, .. } => StartCause::WaitCancelled {
|
||||||
|
start,
|
||||||
|
requested_resume: Some(end),
|
||||||
|
},
|
||||||
|
State::Exit => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Events are currently being handled, so queue this one and don't try to
|
||||||
|
// double-process the event queue
|
||||||
|
self.0.events.borrow_mut().push_back(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut control = self.current_control_flow();
|
||||||
|
// 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), &mut control);
|
||||||
|
if !event_is_start {
|
||||||
|
self.handle_event(event, &mut control);
|
||||||
|
}
|
||||||
|
self.handle_event(Event::EventsCleared, &mut control);
|
||||||
|
self.apply_control_flow(control);
|
||||||
|
// 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, &mut control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle_event takes in events and either queues them or applies a callback
|
||||||
|
//
|
||||||
|
// It should only ever be called from send_event
|
||||||
|
fn handle_event(&self, event: Event<T>, control: &mut root::ControlFlow) {
|
||||||
|
let closed = self.closed();
|
||||||
|
|
||||||
|
match *self.0.runner.borrow_mut() {
|
||||||
|
Some(ref mut runner) => {
|
||||||
|
// An event is being processed, so the runner should be marked busy
|
||||||
|
runner.is_busy = true;
|
||||||
|
|
||||||
|
(runner.event_handler)(event, control);
|
||||||
|
|
||||||
|
// Maintain closed state, even if the callback changes it
|
||||||
|
if closed {
|
||||||
|
*control = root::ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An event is no longer being processed
|
||||||
|
runner.is_busy = false;
|
||||||
|
}
|
||||||
|
// If an event is being handled without a runner somehow, add it to the event queue so
|
||||||
|
// it will eventually be processed
|
||||||
|
_ => 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
|
||||||
|
// If the runner doesn't exist and this method recurses, it will recurse infinitely
|
||||||
|
if !closed && self.0.runner.borrow().is_some() {
|
||||||
|
// Take an event out of the queue and handle it
|
||||||
|
if let Some(event) = self.0.events.borrow_mut().pop_front() {
|
||||||
|
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: root::ControlFlow) {
|
||||||
|
let mut control_flow_status = match control_flow {
|
||||||
|
root::ControlFlow::Poll => {
|
||||||
|
let cloned = self.clone();
|
||||||
|
State::Poll {
|
||||||
|
timeout: backend::Timeout::new(
|
||||||
|
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
|
||||||
|
Duration::from_millis(1),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root::ControlFlow::Wait => State::Wait {
|
||||||
|
start: Instant::now(),
|
||||||
|
},
|
||||||
|
root::ControlFlow::WaitUntil(end) => {
|
||||||
|
let cloned = self.clone();
|
||||||
|
let start = Instant::now();
|
||||||
|
let delay = if end <= start {
|
||||||
|
Duration::from_millis(0)
|
||||||
|
} else {
|
||||||
|
end - start
|
||||||
|
};
|
||||||
|
State::WaitUntil {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
timeout: backend::Timeout::new(
|
||||||
|
move || cloned.send_event(Event::NewEvents(StartCause::Poll)),
|
||||||
|
delay,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root::ControlFlow::Exit => State::Exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
match *self.0.runner.borrow_mut() {
|
||||||
|
Some(ref mut runner) => {
|
||||||
|
// Put the new control flow status in the runner, and take out the old one
|
||||||
|
// This way we can safely take ownership of the TimeoutHandle and clear it,
|
||||||
|
// so that we don't get 'ghost' invocations of Poll or WaitUntil from earlier
|
||||||
|
// set_timeout invocations
|
||||||
|
std::mem::swap(&mut runner.state, &mut control_flow_status);
|
||||||
|
match control_flow_status {
|
||||||
|
State::Poll { timeout } | State::WaitUntil { timeout, .. } => timeout.clear(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the event loop is currntly closed
|
||||||
|
fn closed(&self) -> bool {
|
||||||
|
match *self.0.runner.borrow() {
|
||||||
|
Some(ref runner) => runner.state.is_exit(),
|
||||||
|
None => false, // If the event loop is None, it has not been intialised yet, so it cannot be closed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current control flow state
|
||||||
|
fn current_control_flow(&self) -> root::ControlFlow {
|
||||||
|
match *self.0.runner.borrow() {
|
||||||
|
Some(ref runner) => runner.state.into(),
|
||||||
|
None => root::ControlFlow::Poll,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/platform_impl/web/event_loop/state.rs
Normal file
42
src/platform_impl/web/event_loop/state.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use super::backend;
|
||||||
|
use crate::event_loop::ControlFlow;
|
||||||
|
|
||||||
|
use instant::Instant;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum State {
|
||||||
|
Init,
|
||||||
|
WaitUntil {
|
||||||
|
timeout: backend::Timeout,
|
||||||
|
start: Instant,
|
||||||
|
end: Instant,
|
||||||
|
},
|
||||||
|
Wait {
|
||||||
|
start: Instant,
|
||||||
|
},
|
||||||
|
Poll {
|
||||||
|
timeout: backend::Timeout,
|
||||||
|
},
|
||||||
|
Exit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn is_exit(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
State::Exit => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<State> for ControlFlow {
|
||||||
|
fn from(state: State) -> ControlFlow {
|
||||||
|
match state {
|
||||||
|
State::Init => ControlFlow::Poll,
|
||||||
|
State::WaitUntil { end, .. } => ControlFlow::WaitUntil(end),
|
||||||
|
State::Wait { .. } => ControlFlow::Wait,
|
||||||
|
State::Poll { .. } => ControlFlow::Poll,
|
||||||
|
State::Exit => ControlFlow::Exit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
src/platform_impl/web/event_loop/window_target.rs
Normal file
106
src/platform_impl/web/event_loop/window_target.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
use super::{backend, device, proxy::Proxy, runner, window};
|
||||||
|
use crate::event::{DeviceId, ElementState, Event, TouchPhase, WindowEvent};
|
||||||
|
use crate::event_loop::ControlFlow;
|
||||||
|
use crate::window::WindowId;
|
||||||
|
use std::clone::Clone;
|
||||||
|
|
||||||
|
pub struct WindowTarget<T: 'static> {
|
||||||
|
pub(crate) runner: runner::Shared<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for WindowTarget<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
WindowTarget {
|
||||||
|
runner: self.runner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> WindowTarget<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
WindowTarget {
|
||||||
|
runner: runner::Shared::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> Proxy<T> {
|
||||||
|
Proxy::new(self.runner.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(
|
||||||
|
&self,
|
||||||
|
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
|
||||||
|
) -> &runner::Shared<T> {
|
||||||
|
self.runner.set_listener(event_handler);
|
||||||
|
&self.runner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(&self, canvas: &backend::Canvas) {
|
||||||
|
let runner = &self.runner;
|
||||||
|
|
||||||
|
canvas.on_mouse_out(|pointer_id| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::CursorLeft {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on_mouse_over(|pointer_id| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::CursorEntered {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on_mouse_move(|pointer_id, position, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::CursorMoved {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
position,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on_mouse_up(|pointer_id, button, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::MouseInput {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
state: ElementState::Released,
|
||||||
|
button,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on_mouse_down(|pointer_id, button, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::MouseInput {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
button,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.on_mouse_scroll(|pointer_id, delta, modifiers| {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: WindowId(window::Id),
|
||||||
|
event: WindowEvent::MouseWheel {
|
||||||
|
device_id: DeviceId(device::Id(pointer_id)),
|
||||||
|
delta,
|
||||||
|
phase: TouchPhase::Moved,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
27
src/platform_impl/web/mod.rs
Normal file
27
src/platform_impl/web/mod.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// TODO: dpi
|
||||||
|
// TODO: close events (stdweb PR required)
|
||||||
|
// TODO: pointer locking (stdweb PR required)
|
||||||
|
// TODO: mouse wheel events (stdweb PR required)
|
||||||
|
// TODO: key event: .which() (stdweb PR)
|
||||||
|
// TODO: should there be a maximization / fullscreen API?
|
||||||
|
|
||||||
|
mod device;
|
||||||
|
mod error;
|
||||||
|
mod event_loop;
|
||||||
|
mod monitor;
|
||||||
|
mod window;
|
||||||
|
|
||||||
|
#[cfg(feature = "web_sys")]
|
||||||
|
#[path = "web_sys/mod.rs"]
|
||||||
|
mod backend;
|
||||||
|
|
||||||
|
pub use self::device::Id as DeviceId;
|
||||||
|
pub use self::error::OsError;
|
||||||
|
pub use self::event_loop::{
|
||||||
|
EventLoop, Proxy as EventLoopProxy, WindowTarget as EventLoopWindowTarget,
|
||||||
|
};
|
||||||
|
pub use self::monitor::Handle as MonitorHandle;
|
||||||
|
pub use self::window::{
|
||||||
|
Id as WindowId, PlatformSpecificBuilderAttributes as PlatformSpecificWindowBuilderAttributes,
|
||||||
|
Window,
|
||||||
|
};
|
22
src/platform_impl/web/monitor.rs
Normal file
22
src/platform_impl/web/monitor.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Handle;
|
||||||
|
|
||||||
|
impl Handle {
|
||||||
|
pub fn hidpi_factor(&self) -> f64 {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position(&self) -> PhysicalPosition {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dimensions(&self) -> PhysicalSize {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<String> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
20
src/platform_impl/web/stdweb/canvas.rs
Normal file
20
src/platform_impl/web/stdweb/canvas.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
pub struct Canvas;
|
||||||
|
|
||||||
|
impl Canvas {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let element = document()
|
||||||
|
.create_element("canvas")
|
||||||
|
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
||||||
|
|
||||||
|
let canvas: CanvasElement = element
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
||||||
|
|
||||||
|
document()
|
||||||
|
.body()
|
||||||
|
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
|
||||||
|
.append_child(&canvas);
|
||||||
|
|
||||||
|
Canvas(canvas)
|
||||||
|
}
|
||||||
|
}
|
0
src/platform_impl/web/stdweb/mod.rs
Normal file
0
src/platform_impl/web/stdweb/mod.rs
Normal file
66
src/platform_impl/web/web_sys/canvas.rs
Normal file
66
src/platform_impl/web/web_sys/canvas.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use crate::dpi::LogicalSize;
|
||||||
|
use crate::error::OsError as RootOE;
|
||||||
|
use crate::platform_impl::OsError;
|
||||||
|
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::HtmlCanvasElement;
|
||||||
|
|
||||||
|
pub struct Canvas {
|
||||||
|
raw: HtmlCanvasElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Canvas {
|
||||||
|
pub fn create() -> Result<Self, RootOE> {
|
||||||
|
let window = web_sys::window().expect("Failed to obtain window");
|
||||||
|
let document = window.document().expect("Failed to obtain document");
|
||||||
|
|
||||||
|
let canvas: HtmlCanvasElement = document
|
||||||
|
.create_element("canvas")
|
||||||
|
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
|
||||||
|
.unchecked_into();
|
||||||
|
|
||||||
|
document
|
||||||
|
.body()
|
||||||
|
.ok_or_else(|| os_error!(OsError("Failed to find body node".to_owned())))?
|
||||||
|
.append_child(&canvas)
|
||||||
|
.map_err(|_| os_error!(OsError("Failed to append canvas".to_owned())))?;
|
||||||
|
|
||||||
|
Ok(Canvas { raw: canvas })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_attribute(&self, attribute: &str, value: &str) {
|
||||||
|
self.raw
|
||||||
|
.set_attribute(attribute, value)
|
||||||
|
.expect(&format!("Set attribute: {}", attribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position(&self) -> (f64, f64) {
|
||||||
|
let bounds = self.raw.get_bounding_client_rect();
|
||||||
|
|
||||||
|
(bounds.x(), bounds.y())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(&self) -> f64 {
|
||||||
|
self.raw.width() as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> f64 {
|
||||||
|
self.raw.height() as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&self, size: LogicalSize) {
|
||||||
|
self.raw.set_width(size.width as u32);
|
||||||
|
self.raw.set_height(size.height as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(&self) -> HtmlCanvasElement {
|
||||||
|
self.raw.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse_out<F>(&self, f: F) {}
|
||||||
|
pub fn on_mouse_over<F>(&self, f: F) {}
|
||||||
|
pub fn on_mouse_up<F>(&self, f: F) {}
|
||||||
|
pub fn on_mouse_down<F>(&self, f: F) {}
|
||||||
|
pub fn on_mouse_move<F>(&self, f: F) {}
|
||||||
|
pub fn on_mouse_scroll<F>(&self, f: F) {}
|
||||||
|
}
|
13
src/platform_impl/web/web_sys/document.rs
Normal file
13
src/platform_impl/web/web_sys/document.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
pub struct Document;
|
||||||
|
|
||||||
|
impl Document {
|
||||||
|
pub fn set_title(title: &str) {}
|
||||||
|
|
||||||
|
pub fn on_blur<F>(f: F) {}
|
||||||
|
|
||||||
|
pub fn on_focus<F>(f: F) {}
|
||||||
|
|
||||||
|
pub fn on_key_up<F>(f: F) {}
|
||||||
|
|
||||||
|
pub fn on_key_down<F>(f: F) {}
|
||||||
|
}
|
17
src/platform_impl/web/web_sys/mod.rs
Normal file
17
src/platform_impl/web/web_sys/mod.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
mod canvas;
|
||||||
|
mod document;
|
||||||
|
mod timeout;
|
||||||
|
|
||||||
|
pub use self::canvas::Canvas;
|
||||||
|
pub use self::document::Document;
|
||||||
|
pub use self::timeout::Timeout;
|
||||||
|
|
||||||
|
pub fn request_animation_frame<F>(f: F)
|
||||||
|
where
|
||||||
|
F: Fn(),
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn throw(msg: &str) {
|
||||||
|
wasm_bindgen::throw_str(msg);
|
||||||
|
}
|
12
src/platform_impl/web/web_sys/timeout.rs
Normal file
12
src/platform_impl/web/web_sys/timeout.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Timeout {}
|
||||||
|
|
||||||
|
impl Timeout {
|
||||||
|
pub fn new<F>(f: F, duration: Duration) -> Timeout {
|
||||||
|
Timeout {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(self) {}
|
||||||
|
}
|
276
src/platform_impl/web/window.rs
Normal file
276
src/platform_impl/web/window.rs
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||||
|
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
||||||
|
use crate::event::{Event, WindowEvent};
|
||||||
|
use crate::icon::Icon;
|
||||||
|
use crate::monitor::MonitorHandle as RootMH;
|
||||||
|
use crate::window::{CursorIcon, WindowAttributes, WindowId as RootWI};
|
||||||
|
|
||||||
|
use super::{backend, monitor, EventLoopWindowTarget};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
pub struct Window {
|
||||||
|
canvas: backend::Canvas,
|
||||||
|
redraw: Box<dyn Fn()>,
|
||||||
|
previous_pointer: RefCell<&'static str>,
|
||||||
|
position: RefCell<LogicalPosition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn new<T>(
|
||||||
|
target: &EventLoopWindowTarget<T>,
|
||||||
|
attr: WindowAttributes,
|
||||||
|
_: PlatformSpecificBuilderAttributes,
|
||||||
|
) -> Result<Self, RootOE> {
|
||||||
|
let canvas = backend::Canvas::create()?;
|
||||||
|
|
||||||
|
target.register(&canvas);
|
||||||
|
|
||||||
|
let runner = target.runner.clone();
|
||||||
|
let redraw = Box::new(move || {
|
||||||
|
let runner = runner.clone();
|
||||||
|
backend::request_animation_frame(move || {
|
||||||
|
runner.send_event(Event::WindowEvent {
|
||||||
|
window_id: RootWI(Id),
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let window = Window {
|
||||||
|
canvas,
|
||||||
|
redraw,
|
||||||
|
previous_pointer: RefCell::new("auto"),
|
||||||
|
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize {
|
||||||
|
width: 1024.0,
|
||||||
|
height: 768.0,
|
||||||
|
}));
|
||||||
|
window.set_title(&attr.title);
|
||||||
|
window.set_maximized(attr.maximized);
|
||||||
|
window.set_visible(attr.visible);
|
||||||
|
window.set_window_icon(attr.window_icon);
|
||||||
|
|
||||||
|
Ok(window)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_title(&self, title: &str) {
|
||||||
|
backend::Document::set_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_visible(&self, _visible: bool) {
|
||||||
|
// Intentionally a no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_redraw(&self) {
|
||||||
|
(self.redraw)();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
||||||
|
let (x, y) = self.canvas.position();
|
||||||
|
|
||||||
|
Ok(LogicalPosition { x, y })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
||||||
|
Ok(*self.position.borrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_outer_position(&self, position: LogicalPosition) {
|
||||||
|
*self.position.borrow_mut() = position;
|
||||||
|
|
||||||
|
self.canvas.set_attribute("position", "fixed");
|
||||||
|
self.canvas.set_attribute("left", &position.x.to_string());
|
||||||
|
self.canvas.set_attribute("top", &position.y.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn inner_size(&self) -> LogicalSize {
|
||||||
|
LogicalSize {
|
||||||
|
width: self.canvas.width() as f64,
|
||||||
|
height: self.canvas.height() as f64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn outer_size(&self) -> LogicalSize {
|
||||||
|
LogicalSize {
|
||||||
|
width: self.canvas.width() as f64,
|
||||||
|
height: self.canvas.height() as f64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_inner_size(&self, size: LogicalSize) {
|
||||||
|
self.canvas.set_size(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize>) {
|
||||||
|
// Intentionally a no-op: users can't resize canvas elements
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize>) {
|
||||||
|
// Intentionally a no-op: users can't resize canvas elements
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_resizable(&self, _resizable: bool) {
|
||||||
|
// Intentionally a no-op: users can't resize canvas elements
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn hidpi_factor(&self) -> f64 {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||||
|
let text = match cursor {
|
||||||
|
CursorIcon::Default => "auto",
|
||||||
|
CursorIcon::Crosshair => "crosshair",
|
||||||
|
CursorIcon::Hand => "pointer",
|
||||||
|
CursorIcon::Arrow => "default",
|
||||||
|
CursorIcon::Move => "move",
|
||||||
|
CursorIcon::Text => "text",
|
||||||
|
CursorIcon::Wait => "wait",
|
||||||
|
CursorIcon::Help => "help",
|
||||||
|
CursorIcon::Progress => "progress",
|
||||||
|
|
||||||
|
CursorIcon::NotAllowed => "not-allowed",
|
||||||
|
CursorIcon::ContextMenu => "context-menu",
|
||||||
|
CursorIcon::Cell => "cell",
|
||||||
|
CursorIcon::VerticalText => "vertical-text",
|
||||||
|
CursorIcon::Alias => "alias",
|
||||||
|
CursorIcon::Copy => "copy",
|
||||||
|
CursorIcon::NoDrop => "no-drop",
|
||||||
|
CursorIcon::Grab => "grab",
|
||||||
|
CursorIcon::Grabbing => "grabbing",
|
||||||
|
CursorIcon::AllScroll => "all-scroll",
|
||||||
|
CursorIcon::ZoomIn => "zoom-in",
|
||||||
|
CursorIcon::ZoomOut => "zoom-out",
|
||||||
|
|
||||||
|
CursorIcon::EResize => "e-resize",
|
||||||
|
CursorIcon::NResize => "n-resize",
|
||||||
|
CursorIcon::NeResize => "ne-resize",
|
||||||
|
CursorIcon::NwResize => "nw-resize",
|
||||||
|
CursorIcon::SResize => "s-resize",
|
||||||
|
CursorIcon::SeResize => "se-resize",
|
||||||
|
CursorIcon::SwResize => "sw-resize",
|
||||||
|
CursorIcon::WResize => "w-resize",
|
||||||
|
CursorIcon::EwResize => "ew-resize",
|
||||||
|
CursorIcon::NsResize => "ns-resize",
|
||||||
|
CursorIcon::NeswResize => "nesw-resize",
|
||||||
|
CursorIcon::NwseResize => "nwse-resize",
|
||||||
|
CursorIcon::ColResize => "col-resize",
|
||||||
|
CursorIcon::RowResize => "row-resize",
|
||||||
|
};
|
||||||
|
*self.previous_pointer.borrow_mut() = text;
|
||||||
|
self.canvas.set_attribute("cursor", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), ExternalError> {
|
||||||
|
// TODO: pointer capture
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
|
||||||
|
// TODO: pointer capture
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
|
if !visible {
|
||||||
|
self.canvas.set_attribute("cursor", "none");
|
||||||
|
} else {
|
||||||
|
self.canvas
|
||||||
|
.set_attribute("cursor", *self.previous_pointer.borrow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_maximized(&self, _maximized: bool) {
|
||||||
|
// TODO: should there be a maximization / fullscreen API?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn fullscreen(&self) -> Option<RootMH> {
|
||||||
|
// TODO: should there be a maximization / fullscreen API?
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fullscreen(&self, _monitor: Option<RootMH>) {
|
||||||
|
// TODO: should there be a maximization / fullscreen API?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_decorations(&self, _decorations: bool) {
|
||||||
|
// Intentionally a no-op, no canvas decorations
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
||||||
|
// Intentionally a no-op, no window ordering
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
|
||||||
|
// Currently an intentional no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_ime_position(&self, _position: LogicalPosition) {
|
||||||
|
// TODO: what is this?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn current_monitor(&self) -> RootMH {
|
||||||
|
RootMH {
|
||||||
|
inner: monitor::Handle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
|
||||||
|
VecDeque::new().into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn primary_monitor(&self) -> monitor::Handle {
|
||||||
|
monitor::Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn id(&self) -> Id {
|
||||||
|
// TODO ?
|
||||||
|
unsafe { Id::dummy() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stdweb")]
|
||||||
|
impl WindowExtStdweb for RootWindow {
|
||||||
|
fn canvas(&self) -> CanvasElement {
|
||||||
|
self.window.canvas.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct Id;
|
||||||
|
|
||||||
|
impl Id {
|
||||||
|
pub unsafe fn dummy() -> Id {
|
||||||
|
Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct PlatformSpecificBuilderAttributes;
|
Loading…
Reference in a new issue