mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Merge remote-tracking branch 'blm/web-sys' into stdweb-eventloop-2
This commit is contained in:
commit
eea9530f38
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -2,5 +2,9 @@ Cargo.lock
|
|||
target/
|
||||
rls/
|
||||
.vscode/
|
||||
util/
|
||||
*~
|
||||
*.wasm
|
||||
*.ts
|
||||
*.js
|
||||
#*#
|
||||
|
|
30
Cargo.toml
30
Cargo.toml
|
@ -20,6 +20,9 @@ libc = "0.2"
|
|||
log = "0.4"
|
||||
serde = { version = "1", optional = true, features = ["serde_derive"] }
|
||||
|
||||
[features]
|
||||
web_sys = ["web-sys", "wasm-bindgen"]
|
||||
|
||||
[dev-dependencies]
|
||||
image = "0.21"
|
||||
env_logger = "0.5"
|
||||
|
@ -74,9 +77,34 @@ 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]
|
||||
version = "0.8"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
|
||||
version = "0.3.22"
|
||||
optional = true
|
||||
features = [
|
||||
'console',
|
||||
'Document',
|
||||
'DomRect',
|
||||
'Element',
|
||||
'Event',
|
||||
'EventTarget',
|
||||
'FocusEvent',
|
||||
'HtmlCanvasElement',
|
||||
'HtmlElement',
|
||||
'KeyboardEvent',
|
||||
'MouseEvent',
|
||||
'Node',
|
||||
'PointerEvent',
|
||||
'Window',
|
||||
'WheelEvent'
|
||||
]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.wasm-bindgen]
|
||||
version = "0.2.45"
|
||||
optional = true
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
stdweb = { path = "../stdweb", optional = true }
|
||||
instant = { version = "0.1", features = ["stdweb"] }
|
||||
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
||||
|
||||
[patch.crates-io]
|
||||
stdweb = { path = "../stdweb" }
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
extern crate winit;
|
||||
#[cfg(feature = "stdweb")]
|
||||
#[macro_use]
|
||||
extern crate stdweb;
|
||||
#[cfg(feature = "wasm-bindgen")]
|
||||
extern crate wasm_bindgen;
|
||||
#[cfg(feature = "wasm-bindgen")]
|
||||
extern crate web_sys;
|
||||
|
||||
use winit::window::WindowBuilder;
|
||||
use winit::event::{Event, WindowEvent};
|
||||
use winit::event_loop::{EventLoop, ControlFlow};
|
||||
use wasm_bindgen::{prelude::*, JsValue};
|
||||
use web_sys::console;
|
||||
|
||||
fn main() {
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn main() {
|
||||
console::log_1(&JsValue::from_str("main"));
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let _window = WindowBuilder::new()
|
||||
.with_title("A fantastic window!")
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
console!(log, "Built window!");
|
||||
console::log_1(&JsValue::from_str("Created window"));
|
||||
|
||||
event_loop.run(|event, _, control_flow| {
|
||||
console!(log, format!("{:?}", event));
|
||||
console::log_1(&JsValue::from_str(&format!("{:?}", event)));
|
||||
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
|
@ -26,4 +35,4 @@ fn main() {
|
|||
_ => ()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -115,6 +115,10 @@ extern crate smithay_client_toolkit as sctk;
|
|||
extern crate stdweb;
|
||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
extern crate calloop;
|
||||
#[cfg(feature = "web-sys")]
|
||||
extern crate wasm_bindgen;
|
||||
#[cfg(feature = "web-sys")]
|
||||
extern crate web_sys;
|
||||
|
||||
pub mod dpi;
|
||||
#[macro_use]
|
||||
|
|
|
@ -21,5 +21,6 @@ pub mod unix;
|
|||
pub mod windows;
|
||||
|
||||
pub mod stdweb;
|
||||
pub mod web_sys;
|
||||
|
||||
pub mod desktop;
|
||||
|
|
7
src/platform/web_sys.rs
Normal file
7
src/platform/web_sys.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![cfg(feature = "web-sys")]
|
||||
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
||||
pub trait WindowExtWebSys {
|
||||
fn canvas(&self) -> HtmlCanvasElement;
|
||||
}
|
|
@ -1,30 +1,48 @@
|
|||
pub use self::platform::*;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[path="windows/mod.rs"]
|
||||
#[path = "windows/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[path="linux/mod.rs"]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[path = "linux/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(target_os = "macos")]
|
||||
#[path="macos/mod.rs"]
|
||||
#[path = "macos/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(target_os = "android")]
|
||||
#[path="android/mod.rs"]
|
||||
#[path = "android/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(target_os = "ios")]
|
||||
#[path="ios/mod.rs"]
|
||||
#[path = "ios/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(target_os = "emscripten")]
|
||||
#[path="emscripten/mod.rs"]
|
||||
#[path = "emscripten/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(feature = "stdweb")]
|
||||
#[path="stdweb/mod.rs"]
|
||||
#[path = "stdweb/mod.rs"]
|
||||
mod platform;
|
||||
#[cfg(feature = "web_sys")]
|
||||
#[path = "web_sys/mod.rs"]
|
||||
mod platform;
|
||||
|
||||
#[cfg(all(not(target_os = "ios"), not(target_os = "windows"), not(target_os = "linux"),
|
||||
not(target_os = "macos"), not(target_os = "android"), not(target_os = "dragonfly"),
|
||||
not(target_os = "freebsd"), not(target_os = "netbsd"), not(target_os = "openbsd"),
|
||||
not(target_os = "emscripten"),
|
||||
not(feature = "stdweb")))]
|
||||
#[cfg(all(
|
||||
not(target_os = "ios"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "linux"),
|
||||
not(target_os = "macos"),
|
||||
not(target_os = "android"),
|
||||
not(target_os = "dragonfly"),
|
||||
not(target_os = "freebsd"),
|
||||
not(target_os = "netbsd"),
|
||||
not(target_os = "openbsd"),
|
||||
not(target_os = "emscripten"),
|
||||
not(feature = "stdweb"),
|
||||
not(feature = "web_sys")
|
||||
))]
|
||||
compile_error!("The platform you're compiling for is not supported by winit");
|
||||
|
|
378
src/platform_impl/web_sys/event_loop.rs
Normal file
378
src/platform_impl/web_sys/event_loop.rs
Normal file
|
@ -0,0 +1,378 @@
|
|||
use super::*;
|
||||
|
||||
use dpi::LogicalPosition;
|
||||
use event::{
|
||||
DeviceId as RootDI, ElementState, Event, KeyboardInput, MouseScrollDelta, StartCause,
|
||||
TouchPhase, WindowEvent,
|
||||
};
|
||||
use event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
||||
use platform_impl::platform::document;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||
use std::collections::VecDeque;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use web_sys::{
|
||||
EventTarget, FocusEvent, HtmlCanvasElement, KeyboardEvent, PointerEvent, WheelEvent,
|
||||
};
|
||||
use window::WindowId as RootWI;
|
||||
|
||||
#[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> {
|
||||
pub(crate) runner: EventLoopRunnerShared<T>,
|
||||
}
|
||||
|
||||
impl<T> EventLoopWindowTarget<T> {
|
||||
fn new() -> Self {
|
||||
EventLoopWindowTarget {
|
||||
runner: Rc::new(ELRShared {
|
||||
runner: RefCell::new(None),
|
||||
events: RefCell::new(VecDeque::new()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
|
||||
|
||||
pub struct ELRShared<T> {
|
||||
runner: RefCell<Option<EventLoopRunner<T>>>,
|
||||
events: RefCell<VecDeque<Event<T>>>, // TODO: this may not be necessary?
|
||||
}
|
||||
|
||||
struct EventLoopRunner<T> {
|
||||
control: ControlFlow,
|
||||
is_busy: bool,
|
||||
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 available_monitors(&self) -> VecDequeIter<MonitorHandle> {
|
||||
VecDeque::new().into_iter()
|
||||
}
|
||||
|
||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||
MonitorHandle
|
||||
}
|
||||
|
||||
pub fn run<F>(self, mut event_handler: F) -> !
|
||||
where
|
||||
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
let runner = self.elw.p.runner;
|
||||
|
||||
let relw = RootELW {
|
||||
p: EventLoopWindowTarget::new(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
runner.set_listener(Box::new(move |evt, ctrl| event_handler(evt, &relw, ctrl)));
|
||||
|
||||
let document = &document();
|
||||
add_event(&runner, document, "blur", |elrs, _: FocusEvent| {
|
||||
elrs.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::Focused(false),
|
||||
});
|
||||
});
|
||||
add_event(&runner, document, "focus", |elrs, _: FocusEvent| {
|
||||
elrs.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::Focused(true),
|
||||
});
|
||||
});
|
||||
add_event(
|
||||
&runner,
|
||||
document,
|
||||
"keydown",
|
||||
|elrs, event: KeyboardEvent| {
|
||||
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, "keyup", |elrs, event: KeyboardEvent| {
|
||||
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),
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
runner.send_event(Event::NewEvents(StartCause::Init));
|
||||
|
||||
// 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 '!'
|
||||
wasm_bindgen::throw_str(
|
||||
"Using exceptions for control flow, don't mind me. This isn't actually an error!",
|
||||
);
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy {
|
||||
runner: self.elw.p.runner.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &RootELW<T> {
|
||||
&self.elw
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &HtmlCanvasElement) {
|
||||
add_event(elrs, canvas, "pointerout", |elrs, event: PointerEvent| {
|
||||
elrs.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::CursorLeft {
|
||||
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||
},
|
||||
});
|
||||
});
|
||||
add_event(elrs, canvas, "pointerover", |elrs, event: PointerEvent| {
|
||||
elrs.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::CursorEntered {
|
||||
device_id: RootDI(DeviceId(event.pointer_id())),
|
||||
},
|
||||
});
|
||||
});
|
||||
add_event(elrs, canvas, "pointermove", |elrs, event: PointerEvent| {
|
||||
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().into(),
|
||||
y: event.offset_y().into(),
|
||||
},
|
||||
modifiers: mouse_modifiers_state(&event),
|
||||
},
|
||||
});
|
||||
});
|
||||
add_event(elrs, canvas, "pointerup", |elrs, event: PointerEvent| {
|
||||
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, "pointerdown", |elrs, event: PointerEvent| {
|
||||
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),
|
||||
},
|
||||
});
|
||||
});
|
||||
add_event(elrs, canvas, "wheel", |elrs, event: WheelEvent| {
|
||||
let x = event.delta_x();
|
||||
let y = event.delta_y();
|
||||
let delta = match event.delta_mode() {
|
||||
WheelEvent::DOM_DELTA_LINE => MouseScrollDelta::LineDelta(x as f32, y as f32),
|
||||
WheelEvent::DOM_DELTA_PIXEL => MouseScrollDelta::PixelDelta(LogicalPosition { x, y }),
|
||||
_ => return,
|
||||
};
|
||||
elrs.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::MouseWheel {
|
||||
device_id: RootDI(DeviceId(0)),
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers: mouse_modifiers_state(&event),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn add_event<T: 'static, E, F>(
|
||||
elrs: &EventLoopRunnerShared<T>,
|
||||
target: &EventTarget,
|
||||
event: &str,
|
||||
mut handler: F,
|
||||
) where
|
||||
E: AsRef<web_sys::Event> + wasm_bindgen::convert::FromWasmAbi + 'static,
|
||||
F: FnMut(&EventLoopRunnerShared<T>, E) + 'static,
|
||||
{
|
||||
let elrs = elrs.clone();
|
||||
|
||||
let closure = Closure::wrap(Box::new(move |event: E| {
|
||||
// Don't capture the event if the events loop has been destroyed
|
||||
match &*elrs.runner.borrow() {
|
||||
Some(ref runner) if runner.control == ControlFlow::Exit => return,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
{
|
||||
let event_ref = event.as_ref();
|
||||
event_ref.prevent_default();
|
||||
event_ref.stop_propagation();
|
||||
event_ref.cancel_bubble();
|
||||
}
|
||||
|
||||
handler(&elrs, event);
|
||||
}) as Box<dyn FnMut(E)>);
|
||||
|
||||
target.add_event_listener_with_callback(event, &closure.as_ref().unchecked_ref());
|
||||
closure.forget(); // TODO: don't leak this.
|
||||
}
|
||||
|
||||
impl<T> ELRShared<T> {
|
||||
// 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
|
||||
fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) {
|
||||
*self.runner.borrow_mut() = Some(EventLoopRunner {
|
||||
control: ControlFlow::Poll,
|
||||
is_busy: false,
|
||||
event_handler,
|
||||
});
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
} else {
|
||||
true // If there is no event runner yet, then there's no point in processing events
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
fn handle_event(&self, event: Event<T>) {
|
||||
let closed = self.closed();
|
||||
|
||||
match *self.runner.borrow_mut() {
|
||||
Some(ref mut runner) => {
|
||||
// An event is being processed, so the runner should be marked busy
|
||||
runner.is_busy = true;
|
||||
|
||||
// TODO: bracket this in control flow events?
|
||||
(runner.event_handler)(event, &mut runner.control);
|
||||
|
||||
// Maintain closed state, even if the callback changes it
|
||||
if closed {
|
||||
runner.control = 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.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.runner.borrow().is_some() {
|
||||
// Take an event out of the queue and handle it
|
||||
if let Some(event) = self.events.borrow_mut().pop_front() {
|
||||
self.handle_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
201
src/platform_impl/web_sys/events.rs
Normal file
201
src/platform_impl/web_sys/events.rs
Normal file
|
@ -0,0 +1,201 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use web_sys::{KeyboardEvent, MouseEvent};
|
||||
use event::{MouseButton, ModifiersState, ScanCode, VirtualKeyCode};
|
||||
|
||||
pub fn button_mapping(event: &KeyboardEvent) -> Option<VirtualKeyCode> {
|
||||
Some(match &event.code()[..] {
|
||||
"Digit1" => VirtualKeyCode::Key1,
|
||||
"Digit2" => VirtualKeyCode::Key2,
|
||||
"Digit3" => VirtualKeyCode::Key3,
|
||||
"Digit4" => VirtualKeyCode::Key4,
|
||||
"Digit5" => VirtualKeyCode::Key5,
|
||||
"Digit6" => VirtualKeyCode::Key6,
|
||||
"Digit7" => VirtualKeyCode::Key7,
|
||||
"Digit8" => VirtualKeyCode::Key8,
|
||||
"Digit9" => VirtualKeyCode::Key9,
|
||||
"Digit0" => VirtualKeyCode::Key0,
|
||||
"KeyA" => VirtualKeyCode::A,
|
||||
"KeyB" => VirtualKeyCode::B,
|
||||
"KeyC" => VirtualKeyCode::C,
|
||||
"KeyD" => VirtualKeyCode::D,
|
||||
"KeyE" => VirtualKeyCode::E,
|
||||
"KeyF" => VirtualKeyCode::F,
|
||||
"KeyG" => VirtualKeyCode::G,
|
||||
"KeyH" => VirtualKeyCode::H,
|
||||
"KeyI" => VirtualKeyCode::I,
|
||||
"KeyJ" => VirtualKeyCode::J,
|
||||
"KeyK" => VirtualKeyCode::K,
|
||||
"KeyL" => VirtualKeyCode::L,
|
||||
"KeyM" => VirtualKeyCode::M,
|
||||
"KeyN" => VirtualKeyCode::N,
|
||||
"KeyO" => VirtualKeyCode::O,
|
||||
"KeyP" => VirtualKeyCode::P,
|
||||
"KeyQ" => VirtualKeyCode::Q,
|
||||
"KeyR" => VirtualKeyCode::R,
|
||||
"KeyS" => VirtualKeyCode::S,
|
||||
"KeyT" => VirtualKeyCode::T,
|
||||
"KeyU" => VirtualKeyCode::U,
|
||||
"KeyV" => VirtualKeyCode::V,
|
||||
"KeyW" => VirtualKeyCode::W,
|
||||
"KeyX" => VirtualKeyCode::X,
|
||||
"KeyY" => VirtualKeyCode::Y,
|
||||
"KeyZ" => VirtualKeyCode::Z,
|
||||
"Escape" => VirtualKeyCode::Escape,
|
||||
"F1" => VirtualKeyCode::F1,
|
||||
"F2" => VirtualKeyCode::F2,
|
||||
"F3" => VirtualKeyCode::F3,
|
||||
"F4" => VirtualKeyCode::F4,
|
||||
"F5" => VirtualKeyCode::F5,
|
||||
"F6" => VirtualKeyCode::F6,
|
||||
"F7" => VirtualKeyCode::F7,
|
||||
"F8" => VirtualKeyCode::F8,
|
||||
"F9" => VirtualKeyCode::F9,
|
||||
"F10" => VirtualKeyCode::F10,
|
||||
"F11" => VirtualKeyCode::F11,
|
||||
"F12" => VirtualKeyCode::F12,
|
||||
"F13" => VirtualKeyCode::F13,
|
||||
"F14" => VirtualKeyCode::F14,
|
||||
"F15" => VirtualKeyCode::F15,
|
||||
"F16" => VirtualKeyCode::F16,
|
||||
"F17" => VirtualKeyCode::F17,
|
||||
"F18" => VirtualKeyCode::F18,
|
||||
"F19" => VirtualKeyCode::F19,
|
||||
"F20" => VirtualKeyCode::F20,
|
||||
"F21" => VirtualKeyCode::F21,
|
||||
"F22" => VirtualKeyCode::F22,
|
||||
"F23" => VirtualKeyCode::F23,
|
||||
"F24" => VirtualKeyCode::F24,
|
||||
"PrintScreen" => VirtualKeyCode::Snapshot,
|
||||
"ScrollLock" => VirtualKeyCode::Scroll,
|
||||
"Pause" => VirtualKeyCode::Pause,
|
||||
"Insert" => VirtualKeyCode::Insert,
|
||||
"Home" => VirtualKeyCode::Home,
|
||||
"Delete" => VirtualKeyCode::Delete,
|
||||
"End" => VirtualKeyCode::End,
|
||||
"PageDown" => VirtualKeyCode::PageDown,
|
||||
"PageUp" => VirtualKeyCode::PageUp,
|
||||
"ArrowLeft" => VirtualKeyCode::Left,
|
||||
"ArrowUp" => VirtualKeyCode::Up,
|
||||
"ArrowRight" => VirtualKeyCode::Right,
|
||||
"ArrowDown" => VirtualKeyCode::Down,
|
||||
"Backspace" => VirtualKeyCode::Back,
|
||||
"Enter" => VirtualKeyCode::Return,
|
||||
"Space" => VirtualKeyCode::Space,
|
||||
"Compose" => VirtualKeyCode::Compose,
|
||||
"Caret" => VirtualKeyCode::Caret,
|
||||
"NumLock" => VirtualKeyCode::Numlock,
|
||||
"Numpad0" => VirtualKeyCode::Numpad0,
|
||||
"Numpad1" => VirtualKeyCode::Numpad1,
|
||||
"Numpad2" => VirtualKeyCode::Numpad2,
|
||||
"Numpad3" => VirtualKeyCode::Numpad3,
|
||||
"Numpad4" => VirtualKeyCode::Numpad4,
|
||||
"Numpad5" => VirtualKeyCode::Numpad5,
|
||||
"Numpad6" => VirtualKeyCode::Numpad6,
|
||||
"Numpad7" => VirtualKeyCode::Numpad7,
|
||||
"Numpad8" => VirtualKeyCode::Numpad8,
|
||||
"Numpad9" => VirtualKeyCode::Numpad9,
|
||||
"AbntC1" => VirtualKeyCode::AbntC1,
|
||||
"AbntC2" => VirtualKeyCode::AbntC2,
|
||||
"NumpadAdd" => VirtualKeyCode::Add,
|
||||
"Quote" => VirtualKeyCode::Apostrophe,
|
||||
"Apps" => VirtualKeyCode::Apps,
|
||||
"At" => VirtualKeyCode::At,
|
||||
"Ax" => VirtualKeyCode::Ax,
|
||||
"Backslash" => VirtualKeyCode::Backslash,
|
||||
"Calculator" => VirtualKeyCode::Calculator,
|
||||
"Capital" => VirtualKeyCode::Capital,
|
||||
"Semicolon" => VirtualKeyCode::Semicolon,
|
||||
"Comma" => VirtualKeyCode::Comma,
|
||||
"Convert" => VirtualKeyCode::Convert,
|
||||
"NumpadDecimal" => VirtualKeyCode::Decimal,
|
||||
"NumpadDivide" => VirtualKeyCode::Divide,
|
||||
"Equal" => VirtualKeyCode::Equals,
|
||||
"Backquote" => VirtualKeyCode::Grave,
|
||||
"Kana" => VirtualKeyCode::Kana,
|
||||
"Kanji" => VirtualKeyCode::Kanji,
|
||||
"AltLeft" => VirtualKeyCode::LAlt,
|
||||
"BracketLeft" => VirtualKeyCode::LBracket,
|
||||
"ControlLeft" => VirtualKeyCode::LControl,
|
||||
"ShiftLeft" => VirtualKeyCode::LShift,
|
||||
"MetaLeft" => VirtualKeyCode::LWin,
|
||||
"Mail" => VirtualKeyCode::Mail,
|
||||
"MediaSelect" => VirtualKeyCode::MediaSelect,
|
||||
"MediaStop" => VirtualKeyCode::MediaStop,
|
||||
"Minus" => VirtualKeyCode::Minus,
|
||||
"NumpadMultiply" => VirtualKeyCode::Multiply,
|
||||
"Mute" => VirtualKeyCode::Mute,
|
||||
"LaunchMyComputer" => VirtualKeyCode::MyComputer,
|
||||
"NavigateForward" => VirtualKeyCode::NavigateForward,
|
||||
"NavigateBackward" => VirtualKeyCode::NavigateBackward,
|
||||
"NextTrack" => VirtualKeyCode::NextTrack,
|
||||
"NoConvert" => VirtualKeyCode::NoConvert,
|
||||
"NumpadComma" => VirtualKeyCode::NumpadComma,
|
||||
"NumpadEnter" => VirtualKeyCode::NumpadEnter,
|
||||
"NumpadEquals" => VirtualKeyCode::NumpadEquals,
|
||||
"OEM102" => VirtualKeyCode::OEM102,
|
||||
"Period" => VirtualKeyCode::Period,
|
||||
"PlayPause" => VirtualKeyCode::PlayPause,
|
||||
"Power" => VirtualKeyCode::Power,
|
||||
"PrevTrack" => VirtualKeyCode::PrevTrack,
|
||||
"AltRight" => VirtualKeyCode::RAlt,
|
||||
"BracketRight" => VirtualKeyCode::RBracket,
|
||||
"ControlRight" => VirtualKeyCode::RControl,
|
||||
"ShiftRight" => VirtualKeyCode::RShift,
|
||||
"MetaRight" => VirtualKeyCode::RWin,
|
||||
"Slash" => VirtualKeyCode::Slash,
|
||||
"Sleep" => VirtualKeyCode::Sleep,
|
||||
"Stop" => VirtualKeyCode::Stop,
|
||||
"NumpadSubtract" => VirtualKeyCode::Subtract,
|
||||
"Sysrq" => VirtualKeyCode::Sysrq,
|
||||
"Tab" => VirtualKeyCode::Tab,
|
||||
"Underline" => VirtualKeyCode::Underline,
|
||||
"Unlabeled" => VirtualKeyCode::Unlabeled,
|
||||
"AudioVolumeDown" => VirtualKeyCode::VolumeDown,
|
||||
"AudioVolumeUp" => VirtualKeyCode::VolumeUp,
|
||||
"Wake" => VirtualKeyCode::Wake,
|
||||
"WebBack" => VirtualKeyCode::WebBack,
|
||||
"WebFavorites" => VirtualKeyCode::WebFavorites,
|
||||
"WebForward" => VirtualKeyCode::WebForward,
|
||||
"WebHome" => VirtualKeyCode::WebHome,
|
||||
"WebRefresh" => VirtualKeyCode::WebRefresh,
|
||||
"WebSearch" => VirtualKeyCode::WebSearch,
|
||||
"WebStop" => VirtualKeyCode::WebStop,
|
||||
"Yen" => VirtualKeyCode::Yen,
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mouse_modifiers_state(event: &MouseEvent) -> ModifiersState {
|
||||
ModifiersState {
|
||||
shift: event.shift_key(),
|
||||
ctrl: event.ctrl_key(),
|
||||
alt: event.alt_key(),
|
||||
logo: event.meta_key(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_button(event: &MouseEvent) -> MouseButton {
|
||||
match event.button() {
|
||||
0 => MouseButton::Left,
|
||||
1 => MouseButton::Middle,
|
||||
2 => MouseButton::Right,
|
||||
i => MouseButton::Other((i - 3).try_into().expect("very large mouse button value")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keyboard_modifiers_state(event: &KeyboardEvent) -> ModifiersState {
|
||||
ModifiersState {
|
||||
shift: event.shift_key(),
|
||||
ctrl: event.ctrl_key(),
|
||||
alt: event.alt_key(),
|
||||
logo: event.meta_key(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scancode(event: &KeyboardEvent) -> ScanCode {
|
||||
match event.key_code() {
|
||||
0 => event.char_code(),
|
||||
i => i,
|
||||
}
|
||||
}
|
30
src/platform_impl/web_sys/mod.rs
Normal file
30
src/platform_impl/web_sys/mod.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use std::fmt;
|
||||
|
||||
mod event_loop;
|
||||
mod events;
|
||||
mod window;
|
||||
|
||||
pub use self::event_loop::{
|
||||
register, DeviceId, EventLoop, EventLoopProxy, EventLoopRunnerShared, EventLoopWindowTarget,
|
||||
};
|
||||
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)]
|
||||
pub struct OsError(String);
|
||||
|
||||
impl fmt::Display for OsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn window() -> web_sys::Window {
|
||||
web_sys::window().unwrap()
|
||||
}
|
||||
|
||||
fn document() -> web_sys::Document {
|
||||
window().document().unwrap()
|
||||
}
|
330
src/platform_impl/web_sys/window.rs
Normal file
330
src/platform_impl/web_sys/window.rs
Normal file
|
@ -0,0 +1,330 @@
|
|||
use super::{register, EventLoopWindowTarget, OsError};
|
||||
use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use error::{ExternalError, NotSupportedError, OsError as RootOE};
|
||||
use event::{Event, WindowEvent};
|
||||
use icon::Icon;
|
||||
use monitor::MonitorHandle as RootMH;
|
||||
use platform::web_sys::WindowExtWebSys;
|
||||
use platform_impl::platform::{document, window};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||
use std::collections::VecDeque;
|
||||
use wasm_bindgen::{closure::Closure, JsCast};
|
||||
use web_sys::HtmlCanvasElement;
|
||||
use window::{CursorIcon, Window as RootWindow, WindowAttributes, WindowId as RootWI};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct MonitorHandle;
|
||||
|
||||
impl MonitorHandle {
|
||||
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!();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct WindowId;
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PlatformSpecificWindowBuilderAttributes;
|
||||
|
||||
impl WindowId {
|
||||
pub unsafe fn dummy() -> WindowId {
|
||||
WindowId
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Window {
|
||||
pub(crate) canvas: HtmlCanvasElement,
|
||||
pub(crate) redraw: Box<dyn Fn()>,
|
||||
previous_pointer: RefCell<&'static str>,
|
||||
position: RefCell<LogicalPosition>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new<T>(
|
||||
target: &EventLoopWindowTarget<T>,
|
||||
attr: WindowAttributes,
|
||||
_: PlatformSpecificWindowBuilderAttributes,
|
||||
) -> Result<Self, RootOE> {
|
||||
let element = document()
|
||||
.create_element("canvas")
|
||||
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
|
||||
let canvas: HtmlCanvasElement = element.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())))?;
|
||||
|
||||
register(&target.runner, &canvas);
|
||||
|
||||
let runner = target.runner.clone();
|
||||
let redraw = Box::new(move || {
|
||||
let runner = runner.clone();
|
||||
let closure = Closure::once_into_js(move |_: f64| {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWI(WindowId),
|
||||
event: WindowEvent::RedrawRequested,
|
||||
});
|
||||
});
|
||||
window().request_animation_frame(closure.as_ref().unchecked_ref());
|
||||
});
|
||||
|
||||
let window = Window {
|
||||
canvas,
|
||||
redraw,
|
||||
previous_pointer: RefCell::new("auto"),
|
||||
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
|
||||
};
|
||||
|
||||
if let Some(inner_size) = attr.inner_size {
|
||||
window.set_inner_size(inner_size);
|
||||
} else {
|
||||
window.set_inner_size(LogicalSize {
|
||||
width: 1024.0,
|
||||
height: 768.0,
|
||||
})
|
||||
}
|
||||
window.set_min_inner_size(attr.min_inner_size);
|
||||
window.set_max_inner_size(attr.max_inner_size);
|
||||
window.set_resizable(attr.resizable);
|
||||
window.set_title(&attr.title);
|
||||
window.set_maximized(attr.maximized);
|
||||
window.set_visible(attr.visible);
|
||||
//window.set_transparent(attr.transparent);
|
||||
window.set_decorations(attr.decorations);
|
||||
window.set_always_on_top(attr.always_on_top);
|
||||
window.set_window_icon(attr.window_icon);
|
||||
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
pub fn set_title(&self, title: &str) {
|
||||
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 bounds = self.canvas.get_bounding_client_rect();
|
||||
Ok(LogicalPosition {
|
||||
x: bounds.x(),
|
||||
y: bounds.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")
|
||||
.expect("Setting the position for the canvas");
|
||||
self.canvas
|
||||
.set_attribute("left", &position.x.to_string())
|
||||
.expect("Setting the position for the canvas");
|
||||
self.canvas
|
||||
.set_attribute("top", &position.y.to_string())
|
||||
.expect("Setting the position for the canvas");
|
||||
}
|
||||
|
||||
#[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_width(size.width as u32);
|
||||
self.canvas.set_height(size.height as u32);
|
||||
}
|
||||
|
||||
#[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)
|
||||
.expect("Setting the cursor on the canvas");
|
||||
}
|
||||
|
||||
#[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")
|
||||
.expect("Setting the cursor on the canvas");
|
||||
} else {
|
||||
self.canvas
|
||||
.set_attribute("cursor", *self.previous_pointer.borrow())
|
||||
.expect("Setting the cursor on the canvas");
|
||||
}
|
||||
}
|
||||
|
||||
#[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: MonitorHandle,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {
|
||||
VecDeque::new().into_iter()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||
MonitorHandle
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId {
|
||||
// TODO ?
|
||||
unsafe { WindowId::dummy() }
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowExtWebSys for RootWindow {
|
||||
fn canvas(&self) -> HtmlCanvasElement {
|
||||
self.window.canvas.clone()
|
||||
}
|
||||
}
|
20
test.html
Normal file
20
test.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="module">
|
||||
import { default as init } from './window.js';
|
||||
|
||||
async function run() {
|
||||
console.log("Loading");
|
||||
await init('./window_bg.wasm');
|
||||
console.log("Loaded");
|
||||
}
|
||||
|
||||
run();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas id="test_canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue