From 0e5f1c577ef6bb516b0d32612249077ab2ebe143 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Wed, 17 Apr 2019 22:53:57 -0700 Subject: [PATCH 01/14] all required types declared --- Cargo.toml | 19 +++++++++++++++++ src/platform_impl/mod.rs | 5 ++++- src/platform_impl/websys/event_loop.rs | 29 ++++++++++++++++++++++++++ src/platform_impl/websys/mod.rs | 5 +++++ src/platform_impl/websys/window.rs | 26 +++++++++++++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/platform_impl/websys/event_loop.rs create mode 100644 src/platform_impl/websys/mod.rs create mode 100644 src/platform_impl/websys/window.rs diff --git a/Cargo.toml b/Cargo.toml index 0599ec6927..07ef26b96a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,9 @@ categories = ["gui"] [package.metadata.docs.rs] features = ["serde"] +[features] +websys = ["wasm-bindgen", "web-sys"] + [dependencies] lazy_static = "1" libc = "0.2" @@ -72,3 +75,19 @@ 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.wasm-bindgen] +version = "0.2" +optional = true + +[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] +version = "0.3.4" +optional = true +features = [ + 'Document', + 'Element', + 'HtmlElement', + 'Node', + 'Window', + 'console' +] diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index be96878500..d28d423d26 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -18,9 +18,12 @@ mod platform; #[cfg(target_os = "emscripten")] #[path="emscripten/mod.rs"] mod platform; +#[cfg(all(target_arch = "wasm32", feature = "websys"))] +#[path="websys/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(target_os = "emscripten"), not(all(target_arch = "wasm32", feature="websys"))))] compile_error!("The platform you're compiling for is not supported by winit"); diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs new file mode 100644 index 0000000000..c54c82871d --- /dev/null +++ b/src/platform_impl/websys/event_loop.rs @@ -0,0 +1,29 @@ +use {event_loop::EventLoopClosed}; + +pub struct EventLoop { + pending_events: Vec +} + +impl EventLoop { + pub fn new() -> EventLoop { + EventLoop { pending_events: Vec::new() } + } + + pub fn create_proxy(&self) -> EventLoopProxy { + EventLoopProxy { _marker: std::marker::PhantomData } + } +} + +pub struct EventLoopProxy { + _marker: std::marker::PhantomData +} + +impl EventLoopProxy { + pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { + !unimplemented!() + } +} + +pub struct EventLoopWindowTarget { + _marker: std::marker::PhantomData +} diff --git a/src/platform_impl/websys/mod.rs b/src/platform_impl/websys/mod.rs new file mode 100644 index 0000000000..0445419730 --- /dev/null +++ b/src/platform_impl/websys/mod.rs @@ -0,0 +1,5 @@ +pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; +pub use self::window::{DeviceId, MonitorHandle, Window, WindowId, PlatformSpecificWindowBuilderAttributes}; + +mod event_loop; +pub mod window; \ No newline at end of file diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs new file mode 100644 index 0000000000..1e792ce156 --- /dev/null +++ b/src/platform_impl/websys/window.rs @@ -0,0 +1,26 @@ + +#[derive(Clone, Copy)] +pub struct DeviceId; + +pub struct PlatformSpecificWindowBuilderAttributes; + +pub struct MonitorHandle; + +pub struct Window { + +} + +#[derive(Clone, Copy)] +pub struct WindowId { + +} + +impl WindowId { + pub fn new() -> WindowId { + WindowId {} + } + + pub fn dummy() -> WindowId { + WindowId {} + } +} \ No newline at end of file From e6d1a50894931610c6a2ce0e2c6f8918c872fb0d Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Thu, 18 Apr 2019 23:53:39 -0700 Subject: [PATCH 02/14] stubbed out interfaces. it builds! --- src/platform_impl/websys/event_loop.rs | 41 ++- src/platform_impl/websys/window.rs | 352 ++++++++++++++++++++++++- 2 files changed, 382 insertions(+), 11 deletions(-) diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index c54c82871d..39c4b9254b 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,4 +1,8 @@ -use {event_loop::EventLoopClosed}; +use event_loop::{ControlFlow, EventLoopClosed}; +use event::Event; +use super::window::MonitorHandle; + +use std::collections::VecDeque; pub struct EventLoop { pending_events: Vec @@ -12,15 +16,48 @@ impl EventLoop { pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { _marker: std::marker::PhantomData } } + + #[inline] + pub fn get_available_monitors(&self) -> VecDeque { + vec!(MonitorHandle{}).into_iter().collect() + } + + #[inline] + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle{} + } + + /// Hijacks the calling thread and initializes the `winit` event loop with the provided + /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to + /// access any data from the calling context. + /// + /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the + /// event loop's behavior. + /// + /// Any values not passed to this function will *not* be dropped. + /// + /// [`ControlFlow`]: ./enum.ControlFlow.html + #[inline] + pub fn run(self, event_handler: F) -> ! + where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) + { + unimplemented!() + } + + pub fn window_target(&self) -> &::event_loop::EventLoopWindowTarget { + unimplemented!() + } + } +#[derive(Clone)] pub struct EventLoopProxy { _marker: std::marker::PhantomData } impl EventLoopProxy { pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { - !unimplemented!() + unimplemented!() } } diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 1e792ce156..fa4541f580 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,26 +1,360 @@ +use window::{WindowAttributes, CreationError, MouseCursor}; +use std::collections::VecDeque; +use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; +use icon::Icon; +use super::event_loop::{EventLoopWindowTarget}; -#[derive(Clone, Copy)] -pub struct DeviceId; +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DeviceId(u32); +impl DeviceId { + pub fn dummy() -> Self { + DeviceId(0) + } +} + +#[derive(Clone, Default)] pub struct PlatformSpecificWindowBuilderAttributes; +#[derive(Copy, Clone, Debug)] pub struct MonitorHandle; +impl MonitorHandle { + /// Returns a human-readable name of the monitor. + /// + /// Returns `None` if the monitor doesn't exist anymore. + #[inline] + pub fn get_name(&self) -> Option { + unimplemented!() + } + + /// Returns the monitor's resolution. + #[inline] + pub fn get_dimensions(&self) -> PhysicalSize { + unimplemented!() + } + + /// Returns the top-left corner position of the monitor relative to the larger full + /// screen area. + #[inline] + pub fn get_position(&self) -> PhysicalPosition { + unimplemented!() + } + + /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. + /// + /// See the [`dpi`](dpi/index.html) module for more information. + /// + /// ## Platform-specific + /// + /// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. + /// - **Android:** Always returns 1.0. + #[inline] + pub fn get_hidpi_factor(&self) -> f64 { + unimplemented!() + } +} + pub struct Window { +} + +impl Window { + /// Creates a new Window for platforms where this is appropriate. + /// + /// This function is equivalent to `WindowBuilder::new().build(event_loop)`. + /// + /// Error should be very rare and only occur in case of permission denied, incompatible system, + /// out of memory, etc. + #[inline] + pub fn new(target: &EventLoopWindowTarget, + attr: WindowAttributes, + ps_attr: PlatformSpecificWindowBuilderAttributes) + -> Result { + unimplemented!() + } + + /// Modifies the title of the window. + /// + /// This is a no-op if the window has already been closed. + #[inline] + pub fn set_title(&self, title: &str) { + } + + /// Shows the window if it was hidden. + /// + /// ## Platform-specific + /// + /// - Has no effect on Android + /// + #[inline] + pub fn show(&self) { + unimplemented!() + } + + /// Hides the window if it was visible. + /// + /// ## Platform-specific + /// + /// - Has no effect on Android + /// + #[inline] + pub fn hide(&self) { + unimplemented!() + } + + /// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS + /// events have been processed by the event loop. + /// + /// This is the **strongly encouraged** method of redrawing windows, as it can integrates with + /// OS-requested redraws (e.g. when a window gets resized). + /// + /// This function can cause `RedrawRequested` events to be emitted after `Event::EventsCleared` + /// but before `Event::NewEvents` if called in the following circumstances: + /// * While processing `EventsCleared`. + /// * While processing a `RedrawRequested` event that was sent during `EventsCleared` or any + /// directly subsequent `RedrawRequested` event. + pub fn request_redraw(&self) { + unimplemented!() + } + + /// Returns the position of the top-left hand corner of the window relative to the + /// top-left hand corner of the desktop. + /// + /// Note that the top-left hand corner of the desktop is not necessarily the same as + /// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner + /// of the desktop is the top-left hand corner of the monitor at the top-left of the desktop. + /// + /// The coordinates can be negative if the top-left hand corner of the window is outside + /// of the visible screen region. + /// + /// Returns `None` if the window no longer exists. + #[inline] + pub fn get_position(&self) -> Option { + unimplemented!() + } + + /// Returns the position of the top-left hand corner of the window's client area relative to the + /// top-left hand corner of the desktop. + /// + /// The same conditions that apply to `get_position` apply to this method. + #[inline] + pub fn get_inner_position(&self) -> Option { + unimplemented!() + } + + /// Modifies the position of the window. + /// + /// See `get_position` for more information about the coordinates. + /// + /// This is a no-op if the window has already been closed. + #[inline] + pub fn set_position(&self, position: LogicalPosition) { + unimplemented!() + } + + /// Returns the logical size of the window's client area. + /// + /// The client area is the content of the window, excluding the title bar and borders. + /// + /// Converting the returned `LogicalSize` to `PhysicalSize` produces the size your framebuffer should be. + /// + /// Returns `None` if the window no longer exists. + #[inline] + pub fn get_inner_size(&self) -> Option { + unimplemented!() + } + + /// Returns the logical size of the entire window. + /// + /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), + /// use `get_inner_size` instead. + /// + /// Returns `None` if the window no longer exists. + #[inline] + pub fn get_outer_size(&self) -> Option { + unimplemented!() + } + + /// Modifies the inner size of the window. + /// + /// See `get_inner_size` for more information about the values. + /// + /// This is a no-op if the window has already been closed. + #[inline] + pub fn set_inner_size(&self, size: LogicalSize) { + unimplemented!() + } + + /// Sets a minimum dimension size for the window. + #[inline] + pub fn set_min_dimensions(&self, dimensions: Option) { + unimplemented!() + } + + /// Sets a maximum dimension size for the window. + #[inline] + pub fn set_max_dimensions(&self, dimensions: Option) { + unimplemented!() + } + + /// Sets whether the window is resizable or not. + /// + /// Note that making the window unresizable doesn't exempt you from handling `Resized`, as that event can still be + /// triggered by DPI scaling, entering fullscreen mode, etc. + /// + /// ## Platform-specific + /// + /// This only has an effect on desktop platforms. + /// + /// Due to a bug in XFCE, this has no effect on Xfwm. + #[inline] + pub fn set_resizable(&self, resizable: bool) { + unimplemented!() + } + + /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. + /// + /// See the [`dpi`](dpi/index.html) module for more information. + /// + /// Note that this value can change depending on user action (for example if the window is + /// moved to another screen); as such, tracking `WindowEvent::HiDpiFactorChanged` events is + /// the most robust way to track the DPI you need to use to draw. + /// + /// ## Platform-specific + /// + /// - **X11:** This respects Xft.dpi, and can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. + /// - **Android:** Always returns 1.0. + #[inline] + pub fn get_hidpi_factor(&self) -> f64 { + 1.0 + } + + /// Modifies the mouse cursor of the window. + /// Has no effect on Android. + #[inline] + pub fn set_cursor(&self, cursor: MouseCursor) { + unimplemented!() + } + + /// Changes the position of the cursor in window coordinates. + #[inline] + pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), String> { + unimplemented!() + } + + /// Grabs the cursor, preventing it from leaving the window. + /// + /// ## Platform-specific + /// + /// On macOS, this presently merely locks the cursor in a fixed location, which looks visually awkward. + /// + /// This has no effect on Android or iOS. + #[inline] + pub fn grab_cursor(&self, grab: bool) -> Result<(), String> { + unimplemented!() + } + + /// Hides the cursor, making it invisible but still usable. + /// + /// ## Platform-specific + /// + /// On Windows and X11, the cursor is only hidden within the confines of the window. + /// + /// On macOS, the cursor is hidden as long as the window has input focus, even if the cursor is outside of the + /// window. + /// + /// This has no effect on Android or iOS. + #[inline] + pub fn hide_cursor(&self, hide: bool) { + unimplemented!() + } + + /// Sets the window to maximized or back + #[inline] + pub fn set_maximized(&self, maximized: bool) { + unimplemented!() + } + + /// Sets the window to fullscreen or back + #[inline] + pub fn set_fullscreen(&self, monitor: Option<::monitor::MonitorHandle>) { + unimplemented!() + } + + /// Turn window decorations on or off. + #[inline] + pub fn set_decorations(&self, decorations: bool) { + unimplemented!() + } + + /// Change whether or not the window will always be on top of other windows. + #[inline] + pub fn set_always_on_top(&self, always_on_top: bool) { + unimplemented!() + } + + /// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left + /// corner of the titlebar. + /// + /// For more usage notes, see `WindowBuilder::with_window_icon`. + /// + /// ## Platform-specific + /// + /// This only has an effect on Windows and X11. + #[inline] + pub fn set_window_icon(&self, window_icon: Option) { + unimplemented!() + } + + /// Sets location of IME candidate box in client area coordinates relative to the top left. + #[inline] + pub fn set_ime_spot(&self, position: LogicalPosition) { + unimplemented!() + } + + /// Returns the monitor on which the window currently resides + #[inline] + pub fn get_current_monitor(&self) -> ::monitor::MonitorHandle { + ::monitor::MonitorHandle{inner: MonitorHandle{}} + } + + /// Returns the list of all the monitors available on the system. + /// + /// This is the same as `EventLoop::get_available_monitors`, and is provided for convenience. + #[inline] + pub fn get_available_monitors(&self) -> VecDeque { + unimplemented!() + } + + /// Returns the primary monitor of the system. + /// + /// This is the same as `EventLoop::get_primary_monitor`, and is provided for convenience. + #[inline] + pub fn get_primary_monitor(&self) -> MonitorHandle { + MonitorHandle {} + } + + /// Returns an identifier unique to the window. + #[inline] + pub fn id(&self) -> WindowId { + unimplemented!() + } } -#[derive(Clone, Copy)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId { } -impl WindowId { - pub fn new() -> WindowId { - WindowId {} - } - pub fn dummy() -> WindowId { - WindowId {} +impl WindowId { + /// Returns a dummy `WindowId`, useful for unit testing. The only guarantee made about the return + /// value of this function is that it will always be equal to itself and to future values returned + /// by this function. No other guarantees are made. This may be equal to a real `WindowId`. + /// + /// **Passing this into a winit function will result in undefined behavior.** + pub unsafe fn dummy() -> Self { + WindowId{} } } \ No newline at end of file From 1a8b3c1fe51bdff32dea5fd6d1c8d8e6ff0062f8 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sat, 20 Apr 2019 02:09:17 -0700 Subject: [PATCH 03/14] beginnings of an event loop --- src/platform_impl/websys/event_loop.rs | 62 +++++++++++++++++++++++--- src/platform_impl/websys/window.rs | 2 +- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index 39c4b9254b..01b2f3d2b4 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,16 +1,41 @@ +extern crate web_sys; + use event_loop::{ControlFlow, EventLoopClosed}; use event::Event; -use super::window::MonitorHandle; +use super::window::{MonitorHandle, Window}; use std::collections::VecDeque; +use self::web_sys::Element; + +// A macro to provide `println!(..)`-style syntax for `console.log` logging. +macro_rules! log { + ( $( $t:tt )* ) => { + web_sys::console::log_1(&format!( $( $t )* ).into()); + } +} + pub struct EventLoop { - pending_events: Vec + pending_events: Vec, + window_target: ::event_loop::EventLoopWindowTarget } impl EventLoop { pub fn new() -> EventLoop { - EventLoop { pending_events: Vec::new() } + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + + let element = document.get_element_by_id("test").expect("no canvas"); + EventLoop { + pending_events: Vec::new(), + window_target: ::event_loop::EventLoopWindowTarget { + p: EventLoopWindowTarget { + element, + _marker: std::marker::PhantomData + }, + _marker: std::marker::PhantomData + } + } } pub fn create_proxy(&self) -> EventLoopProxy { @@ -27,7 +52,7 @@ impl EventLoop { MonitorHandle{} } - /// Hijacks the calling thread and initializes the `winit` event loop with the provided + /// Hijacks the calling thread and initializes the `winit` event loop with the provided /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to /// access any data from the calling context. /// @@ -41,11 +66,35 @@ impl EventLoop { pub fn run(self, event_handler: F) -> ! where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) { - unimplemented!() + self.run_return(event_handler); + log!("exiting"); + std::process::exit(0); } + fn run_return(&self, mut event_handler: F) + where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) + { + let mut control_flow = ControlFlow::default(); + + event_handler(::event::Event::NewEvents(::event::StartCause::Init), &self.window_target, &mut control_flow); + loop { + match control_flow { + ControlFlow::Poll => { + event_handler(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); + }, + ControlFlow::Wait => { + }, + ControlFlow::WaitUntil(Instant) => { + }, + ControlFlow::Exit => break + } + } + event_handler(::event::Event::LoopDestroyed, &self.window_target, &mut control_flow); + } + + pub fn window_target(&self) -> &::event_loop::EventLoopWindowTarget { - unimplemented!() + &self.window_target } } @@ -62,5 +111,6 @@ impl EventLoopProxy { } pub struct EventLoopWindowTarget { + element: Element, _marker: std::marker::PhantomData } diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index fa4541f580..d971bc794a 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -70,7 +70,7 @@ impl Window { attr: WindowAttributes, ps_attr: PlatformSpecificWindowBuilderAttributes) -> Result { - unimplemented!() + Ok(Window{}) } /// Modifies the title of the window. From 5be877ce544a7a2f7bf397122c93258e59f6c615 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sat, 20 Apr 2019 22:20:55 -0700 Subject: [PATCH 04/14] restructured, sketched out a few more types --- src/platform_impl/websys/event_loop.rs | 62 ++++++++++++++++---------- src/platform_impl/websys/window.rs | 24 +++++++++- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index 01b2f3d2b4..40da212ba9 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,11 +1,16 @@ extern crate web_sys; +extern crate wasm_bindgen; use event_loop::{ControlFlow, EventLoopClosed}; use event::Event; -use super::window::{MonitorHandle, Window}; +use super::window::{MonitorHandle, Window, WindowInternal}; use std::collections::VecDeque; +use std::rc::Rc; +use std::cell::RefCell; +use self::wasm_bindgen::prelude::*; +use self::wasm_bindgen::JsCast; use self::web_sys::Element; // A macro to provide `println!(..)`-style syntax for `console.log` logging. @@ -15,22 +20,21 @@ macro_rules! log { } } +#[wasm_bindgen(inline_js = "export function js_exit() { throw 'hacky exit!'; }")] +extern "C" { + fn js_exit(); +} + pub struct EventLoop { - pending_events: Vec, window_target: ::event_loop::EventLoopWindowTarget } impl EventLoop { pub fn new() -> EventLoop { - let window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - - let element = document.get_element_by_id("test").expect("no canvas"); EventLoop { - pending_events: Vec::new(), window_target: ::event_loop::EventLoopWindowTarget { p: EventLoopWindowTarget { - element, + window: RefCell::new(None), _marker: std::marker::PhantomData }, _marker: std::marker::PhantomData @@ -68,28 +72,30 @@ impl EventLoop { { self.run_return(event_handler); log!("exiting"); - std::process::exit(0); + js_exit(); + unreachable!() } - fn run_return(&self, mut event_handler: F) + fn run_return(self, mut event_handler: F) where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) { let mut control_flow = ControlFlow::default(); + let f: Rc>>> = Rc::new(RefCell::new(None)); + let g = f.clone(); + event_handler(::event::Event::NewEvents(::event::StartCause::Init), &self.window_target, &mut control_flow); - loop { - match control_flow { - ControlFlow::Poll => { - event_handler(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); - }, - ControlFlow::Wait => { - }, - ControlFlow::WaitUntil(Instant) => { - }, - ControlFlow::Exit => break + + *g.borrow_mut() = Some(Closure::wrap(Box::new(move || { + if control_flow == ControlFlow::Poll { + event_handler(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); } - } - event_handler(::event::Event::LoopDestroyed, &self.window_target, &mut control_flow); + + let window = web_sys::window().expect("should be a window"); + window.request_animation_frame(f.borrow().as_ref().unwrap().as_ref().unchecked_ref()); + }) as Box)); + let window = web_sys::window().expect("should be a window"); + window.request_animation_frame(g.borrow().as_ref().unwrap().as_ref().unchecked_ref()); } @@ -111,6 +117,16 @@ impl EventLoopProxy { } pub struct EventLoopWindowTarget { - element: Element, + window: RefCell>>, _marker: std::marker::PhantomData } + +impl EventLoopWindowTarget { + pub(crate) fn set_window(&self, window: Rc) { + self.window.borrow_mut().replace(window.clone()); + } + + pub(crate) fn window(&self) -> Rc { + self.window.borrow().as_ref().map(|w| w.clone()).unwrap() + } +} diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index d971bc794a..8ad5499a24 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,5 +1,6 @@ use window::{WindowAttributes, CreationError, MouseCursor}; use std::collections::VecDeque; +use std::rc::Rc; use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; @@ -56,6 +57,12 @@ impl MonitorHandle { } pub struct Window { + canvas: web_sys::Element, + internal: Rc +} + +pub(crate) struct WindowInternal { + pending_events: Vec<::event::WindowEvent> } impl Window { @@ -70,7 +77,22 @@ impl Window { attr: WindowAttributes, ps_attr: PlatformSpecificWindowBuilderAttributes) -> Result { - Ok(Window{}) + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + + // TODO: get the id from ps_attr + let element = document.get_element_by_id("test").expect("no canvas"); + + let internal = Rc::new(WindowInternal { + pending_events: vec![] + }); + + target.set_window(internal.clone()); + + Ok(Window { + canvas: element, + internal: internal.clone() + }) } /// Modifies the title of the window. From 840ffde29e77da8f3885821715c5ef0093082e09 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Mon, 22 Apr 2019 16:44:57 -0700 Subject: [PATCH 05/14] added example, light cleanup --- examples/wasm_bindgen.rs | 59 ++++++++++++++++++++++++++ src/platform_impl/websys/event_loop.rs | 27 ++---------- src/platform_impl/websys/mod.rs | 2 + src/platform_impl/websys/wasm_util.rs | 16 +++++++ src/platform_impl/websys/window.rs | 28 +++++++++--- 5 files changed, 104 insertions(+), 28 deletions(-) create mode 100644 examples/wasm_bindgen.rs create mode 100644 src/platform_impl/websys/wasm_util.rs diff --git a/examples/wasm_bindgen.rs b/examples/wasm_bindgen.rs new file mode 100644 index 0000000000..c649318628 --- /dev/null +++ b/examples/wasm_bindgen.rs @@ -0,0 +1,59 @@ +mod utils; + +extern crate web_sys; + +extern crate winit; +use winit::window::WindowBuilder; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{EventLoop, ControlFlow}; + +use wasm_bindgen::prelude::*; + +// A macro to provide `println!(..)`-style syntax for `console.log` logging. +macro_rules! log { + ( $( $t:tt )* ) => { + web_sys::console::log_1(&format!( $( $t )* ).into()); + } +} + +// use wee_alloc if it is available +#[cfg(feature = "wee_alloc")] +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +#[wasm_bindgen] +struct App {} + +#[wasm_bindgen] +impl App { + pub fn new() -> App { + App{} + } + + pub fn run(&self) { + // create an event loop + let event_loop = EventLoop::new(); + + // create a window and associate it with the event loop + let _window = WindowBuilder::new() + .with_title("A fantastic window!") + .build(&event_loop) + .unwrap(); + + // run! + // + // when using wasm_bindgen, this will currently throw a js + // exception once all browser event handlers have been installed. + event_loop.run(|event, _, control_flow| { + log!("{:?}", event); + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Poll, + } + }); + } +} diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index 40da212ba9..a1615fd297 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -4,6 +4,8 @@ extern crate wasm_bindgen; use event_loop::{ControlFlow, EventLoopClosed}; use event::Event; use super::window::{MonitorHandle, Window, WindowInternal}; +#[macro_use] +use platform_impl::platform::wasm_util as util; use std::collections::VecDeque; use std::rc::Rc; @@ -13,18 +15,6 @@ use self::wasm_bindgen::prelude::*; use self::wasm_bindgen::JsCast; use self::web_sys::Element; -// A macro to provide `println!(..)`-style syntax for `console.log` logging. -macro_rules! log { - ( $( $t:tt )* ) => { - web_sys::console::log_1(&format!( $( $t )* ).into()); - } -} - -#[wasm_bindgen(inline_js = "export function js_exit() { throw 'hacky exit!'; }")] -extern "C" { - fn js_exit(); -} - pub struct EventLoop { window_target: ::event_loop::EventLoopWindowTarget } @@ -56,23 +46,14 @@ impl EventLoop { MonitorHandle{} } - /// Hijacks the calling thread and initializes the `winit` event loop with the provided - /// closure. Since the closure is `'static`, it must be a `move` closure if it needs to - /// access any data from the calling context. - /// - /// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the - /// event loop's behavior. - /// - /// Any values not passed to this function will *not* be dropped. - /// - /// [`ControlFlow`]: ./enum.ControlFlow.html #[inline] pub fn run(self, event_handler: F) -> ! where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) { self.run_return(event_handler); log!("exiting"); - js_exit(); + + util::js_exit(); unreachable!() } diff --git a/src/platform_impl/websys/mod.rs b/src/platform_impl/websys/mod.rs index 0445419730..fcf20370e4 100644 --- a/src/platform_impl/websys/mod.rs +++ b/src/platform_impl/websys/mod.rs @@ -1,5 +1,7 @@ pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; pub use self::window::{DeviceId, MonitorHandle, Window, WindowId, PlatformSpecificWindowBuilderAttributes}; +#[macro_use] +mod wasm_util; mod event_loop; pub mod window; \ No newline at end of file diff --git a/src/platform_impl/websys/wasm_util.rs b/src/platform_impl/websys/wasm_util.rs new file mode 100644 index 0000000000..47ba09c29b --- /dev/null +++ b/src/platform_impl/websys/wasm_util.rs @@ -0,0 +1,16 @@ +extern crate wasm_bindgen; +extern crate web_sys; + +use self::wasm_bindgen::prelude::*; + +// A macro to provide `println!(..)`-style syntax for `console.log` logging. +macro_rules! log { + ( $( $t:tt )* ) => { + web_sys::console::log_1(&format!( $( $t )* ).into()); + } +} + +#[wasm_bindgen(inline_js = "export function js_exit() { throw 'hacky exit!'; }")] +extern "C" { + pub fn js_exit(); +} \ No newline at end of file diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 8ad5499a24..06a9b507d5 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -14,8 +14,23 @@ impl DeviceId { } } +/// +/// ElementSelection allows the window creator +/// to select an existing canvas in the DOM +/// or a container in which to create a canvas. +/// +enum ElementSelection { + CanvasId(String), + ContainerId(String) +} + +/// +/// Platform specific attributes for window creation. +/// #[derive(Clone, Default)] -pub struct PlatformSpecificWindowBuilderAttributes; +pub struct PlatformSpecificWindowBuilderAttributes { + pub element: ElementSelection +} #[derive(Copy, Clone, Debug)] pub struct MonitorHandle; @@ -89,6 +104,8 @@ impl Window { target.set_window(internal.clone()); + // TODO: install WindowEvent handlers + Ok(Window { canvas: element, internal: internal.clone() @@ -161,7 +178,8 @@ impl Window { /// The same conditions that apply to `get_position` apply to this method. #[inline] pub fn get_inner_position(&self) -> Option { - unimplemented!() + // websys: we have no concept of "inner" client area, so just return position. + self.get_position() } /// Modifies the position of the window. @@ -183,7 +201,8 @@ impl Window { /// Returns `None` if the window no longer exists. #[inline] pub fn get_inner_size(&self) -> Option { - unimplemented!() + // websys: we have no concept of "inner" client area, so just return size. + self.get_outer_size() } /// Returns the logical size of the entire window. @@ -366,12 +385,11 @@ impl Window { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId { - } impl WindowId { - /// Returns a dummy `WindowId`, useful for unit testing. The only guarantee made about the return + /// Returns a dummy `WindowId`, useful for unit testing. The only guarantee made about the return /// value of this function is that it will always be equal to itself and to future values returned /// by this function. No other guarantees are made. This may be equal to a real `WindowId`. /// From b93f0d4f93f0f41078e9697ff81d22c6b9cd8504 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sun, 28 Apr 2019 16:38:13 -0700 Subject: [PATCH 06/14] exposed canvas, some work on window creation --- Cargo.toml | 1 + examples/wasm_bindgen.rs | 15 +++++++-- src/platform/mod.rs | 1 + src/platform/websys.rs | 36 ++++++++++++++++++++++ src/platform_impl/websys/wasm_util.rs | 7 +++++ src/platform_impl/websys/window.rs | 44 ++++++++++++++++++++++----- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 src/platform/websys.rs diff --git a/Cargo.toml b/Cargo.toml index 07ef26b96a..d3320111ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ features = [ 'Document', 'Element', 'HtmlElement', + 'HtmlCanvasElement', 'Node', 'Window', 'console' diff --git a/examples/wasm_bindgen.rs b/examples/wasm_bindgen.rs index c649318628..1754311f37 100644 --- a/examples/wasm_bindgen.rs +++ b/examples/wasm_bindgen.rs @@ -6,6 +6,7 @@ extern crate winit; use winit::window::WindowBuilder; use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; +use winit::platform::websys::{WebsysWindowBuilderExt, WebsysWindowExt}; use wasm_bindgen::prelude::*; @@ -35,17 +36,25 @@ impl App { let event_loop = EventLoop::new(); // create a window and associate it with the event loop - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("A fantastic window!") + .with_canvas_id("test") .build(&event_loop) .unwrap(); - // run! + // do some drawing + let canvas = window.get_canvas(); + let ctx = canvas.get_context("2d").unwrap().unwrap() + .dyn_into::().unwrap(); + ctx.begin_path(); + ctx.arc(95.0, 50.0, 40.0, 0.0, 2.0 * 3.14159).unwrap(); + ctx.stroke(); + + // run forever // // when using wasm_bindgen, this will currently throw a js // exception once all browser event handlers have been installed. event_loop.run(|event, _, control_flow| { - log!("{:?}", event); match event { Event::WindowEvent { diff --git a/src/platform/mod.rs b/src/platform/mod.rs index ba494ac6d3..59cecde286 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -19,5 +19,6 @@ pub mod ios; pub mod macos; pub mod unix; pub mod windows; +pub mod websys; pub mod desktop; diff --git a/src/platform/websys.rs b/src/platform/websys.rs new file mode 100644 index 0000000000..ecaafb11e6 --- /dev/null +++ b/src/platform/websys.rs @@ -0,0 +1,36 @@ +extern crate wasm_bindgen; +extern crate web_sys; + +use platform_impl::Window as CanvasWindow; +use platform_impl::window::ElementSelection; +use window::{Window, WindowBuilder}; +use platform::websys::wasm_bindgen::prelude::*; +use platform::websys::wasm_bindgen::JsCast; + +pub trait WebsysWindowExt { + fn get_canvas<'a>(&'a self) -> &'a web_sys::HtmlCanvasElement; +} + +impl WebsysWindowExt for Window { + fn get_canvas<'a>(&'a self) -> &'a web_sys::HtmlCanvasElement { + &self.window.canvas + } +} + +pub trait WebsysWindowBuilderExt { + fn with_canvas_id(mut self, canvas_id: &str) -> WindowBuilder; + + fn with_container_id(mut self, container_id: &str) -> WindowBuilder; +} + +impl WebsysWindowBuilderExt for WindowBuilder { + fn with_canvas_id(mut self, canvas_id: &str) -> WindowBuilder { + self.platform_specific.element = ElementSelection::CanvasId(canvas_id.to_string()); + self + } + + fn with_container_id(mut self, container_id: &str) -> WindowBuilder { + self.platform_specific.element = ElementSelection::ContainerId(container_id.to_string()); + self + } +} diff --git a/src/platform_impl/websys/wasm_util.rs b/src/platform_impl/websys/wasm_util.rs index 47ba09c29b..a08c7927da 100644 --- a/src/platform_impl/websys/wasm_util.rs +++ b/src/platform_impl/websys/wasm_util.rs @@ -2,6 +2,7 @@ extern crate wasm_bindgen; extern crate web_sys; use self::wasm_bindgen::prelude::*; +use window::CreationError; // A macro to provide `println!(..)`-style syntax for `console.log` logging. macro_rules! log { @@ -13,4 +14,10 @@ macro_rules! log { #[wasm_bindgen(inline_js = "export function js_exit() { throw 'hacky exit!'; }")] extern "C" { pub fn js_exit(); +} + +impl From for CreationError { + fn from(error: wasm_bindgen::JsValue) -> Self { + CreationError::OsError(error.as_string().unwrap_or("Window error".to_string())) + } } \ No newline at end of file diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 06a9b507d5..6a348ea94a 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,9 +1,13 @@ +extern crate wasm_bindgen; + use window::{WindowAttributes, CreationError, MouseCursor}; use std::collections::VecDeque; use std::rc::Rc; use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; +use self::wasm_bindgen::prelude::*; +use self::wasm_bindgen::JsCast; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(u32); @@ -19,11 +23,16 @@ impl DeviceId { /// to select an existing canvas in the DOM /// or a container in which to create a canvas. /// -enum ElementSelection { +#[derive(Clone)] +pub enum ElementSelection { CanvasId(String), ContainerId(String) } +impl Default for ElementSelection { + fn default() -> Self { ElementSelection::CanvasId("".to_string()) } +} + /// /// Platform specific attributes for window creation. /// @@ -72,7 +81,7 @@ impl MonitorHandle { } pub struct Window { - canvas: web_sys::Element, + pub(crate) canvas: web_sys::HtmlCanvasElement, internal: Rc } @@ -92,11 +101,30 @@ impl Window { attr: WindowAttributes, ps_attr: PlatformSpecificWindowBuilderAttributes) -> Result { - let window = web_sys::window().expect("no global `window` exists"); - let document = window.document().expect("should have a document on window"); - - // TODO: get the id from ps_attr - let element = document.get_element_by_id("test").expect("no canvas"); + let window = web_sys::window() + .expect("No global window object found!"); + let document = window.document() + .expect("Global window does not have a document!"); + + let element = match ps_attr.element { + ElementSelection::CanvasId(id) => { + document.get_element_by_id(&id) + .expect(&format!("No canvas with ID {} found", id)) + .dyn_into::().unwrap() + }, + ElementSelection::ContainerId(id) => { + let parent = document.get_element_by_id(&id) + .expect(&format!("No container element with Id {} found", id)); + + let canvas = document.create_element("canvas") + .expect("Could not create a canvas") + .dyn_into::().unwrap(); + + parent.append_child(&canvas); + + canvas + } + }; let internal = Rc::new(WindowInternal { pending_events: vec![] @@ -397,4 +425,4 @@ impl WindowId { pub unsafe fn dummy() -> Self { WindowId{} } -} \ No newline at end of file +} From f83bd53002f712a0b0ae80993e5fd7f4f8c19561 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sun, 28 Apr 2019 16:53:56 -0700 Subject: [PATCH 07/14] wasm_bindgen example builds --- Cargo.toml | 1 + examples/wasm_bindgen.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3320111ad..65d5ee0ae6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ features = [ 'Element', 'HtmlElement', 'HtmlCanvasElement', + 'CanvasRenderingContext2d', 'Node', 'Window', 'console' diff --git a/examples/wasm_bindgen.rs b/examples/wasm_bindgen.rs index 1754311f37..79afa982a7 100644 --- a/examples/wasm_bindgen.rs +++ b/examples/wasm_bindgen.rs @@ -1,14 +1,15 @@ -mod utils; - extern crate web_sys; +extern crate wasm_bindgen; extern crate winit; use winit::window::WindowBuilder; use winit::event::{Event, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow}; -use winit::platform::websys::{WebsysWindowBuilderExt, WebsysWindowExt}; +use winit::platform::websys::WebsysWindowExt; +use winit::platform::websys::WebsysWindowBuilderExt; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; // A macro to provide `println!(..)`-style syntax for `console.log` logging. macro_rules! log { @@ -66,3 +67,8 @@ impl App { }); } } + +pub fn main() { + let app = App::new(); + app.run(); +} \ No newline at end of file From 6946fb1e85fb0cbe761299e14d92f3b4b0b82981 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Mon, 29 Apr 2019 22:04:57 -0700 Subject: [PATCH 08/14] simple mouse click event fires --- Cargo.toml | 1 + src/platform_impl/websys/event_loop.rs | 8 +++++++- src/platform_impl/websys/window.rs | 24 ++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65d5ee0ae6..4f6bf1ef87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,7 @@ features = [ 'HtmlElement', 'HtmlCanvasElement', 'CanvasRenderingContext2d', + 'MouseEvent', 'Node', 'Window', 'console' diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index a1615fd297..de35090553 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -3,7 +3,7 @@ extern crate wasm_bindgen; use event_loop::{ControlFlow, EventLoopClosed}; use event::Event; -use super::window::{MonitorHandle, Window, WindowInternal}; +use super::window::{MonitorHandle, Window, WindowId, WindowInternal}; #[macro_use] use platform_impl::platform::wasm_util as util; @@ -69,6 +69,12 @@ impl EventLoop { *g.borrow_mut() = Some(Closure::wrap(Box::new(move || { if control_flow == ControlFlow::Poll { + + let mut win_events = self.window_target.p.window().events(); + win_events.drain(..).for_each(|e| { + event_handler(::event::Event::WindowEvent{window_id: ::window::WindowId(WindowId{}), event: e}, &self.window_target, &mut control_flow); + }); + event_handler(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); } diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 6a348ea94a..3a8dae99b8 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -3,9 +3,11 @@ extern crate wasm_bindgen; use window::{WindowAttributes, CreationError, MouseCursor}; use std::collections::VecDeque; use std::rc::Rc; +use std::cell::RefCell; use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; + use self::wasm_bindgen::prelude::*; use self::wasm_bindgen::JsCast; @@ -86,7 +88,13 @@ pub struct Window { } pub(crate) struct WindowInternal { - pending_events: Vec<::event::WindowEvent> + pub pending_events: RefCell> +} + +impl WindowInternal { + pub fn events(&self) -> Vec<::event::WindowEvent> { + self.pending_events.replace(Vec::new()) + } } impl Window { @@ -127,12 +135,24 @@ impl Window { }; let internal = Rc::new(WindowInternal { - pending_events: vec![] + pending_events: RefCell::new(Vec::with_capacity(3)) }); target.set_window(internal.clone()); // TODO: install WindowEvent handlers + let mut win = internal.clone(); + let click_handler = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { + // TODO: process the event + win.pending_events.borrow_mut().push(::event::WindowEvent::MouseInput { + device_id: ::event::DeviceId(DeviceId(0)), + state: ::event::ElementState::Pressed, + button: ::event::MouseButton::Left, + modifiers: Default::default() + }); + }) as Box); + element.set_onmousedown(Some(click_handler.as_ref().unchecked_ref())); + click_handler.forget(); Ok(Window { canvas: element, From 52ed46cca50517e9da33bd534e6d0b963d674b62 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sun, 12 May 2019 15:55:42 -0700 Subject: [PATCH 09/14] cleanup of imports, added the event module --- src/lib.rs | 4 ++++ src/platform_impl/mod.rs | 2 +- src/platform_impl/websys/event.rs | 20 ++++++++++++++++++++ src/platform_impl/websys/event_loop.rs | 9 +++------ src/platform_impl/websys/mod.rs | 1 + src/platform_impl/websys/wasm_util.rs | 5 +---- src/platform_impl/websys/window.rs | 25 +++++++++---------------- 7 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 src/platform_impl/websys/event.rs diff --git a/src/lib.rs b/src/lib.rs index 347f8e1cf2..490cc4736b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,10 @@ extern crate percent_encoding; 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 calloop; +#[cfg(all(target_arch = "wasm32", target_os = "unknown", feature = "websys"))] +extern crate wasm_bindgen; +#[cfg(all(target_arch = "wasm32", target_os = "unknown", feature = "websys"))] +extern crate web_sys; pub mod dpi; #[macro_use] diff --git a/src/platform_impl/mod.rs b/src/platform_impl/mod.rs index d28d423d26..cca65b2578 100644 --- a/src/platform_impl/mod.rs +++ b/src/platform_impl/mod.rs @@ -18,7 +18,7 @@ mod platform; #[cfg(target_os = "emscripten")] #[path="emscripten/mod.rs"] mod platform; -#[cfg(all(target_arch = "wasm32", feature = "websys"))] +#[cfg(all(target_arch = "wasm32", target_os = "unknown", feature = "websys"))] #[path="websys/mod.rs"] mod platform; diff --git a/src/platform_impl/websys/event.rs b/src/platform_impl/websys/event.rs new file mode 100644 index 0000000000..fe5d71c25f --- /dev/null +++ b/src/platform_impl/websys/event.rs @@ -0,0 +1,20 @@ +use std::convert::From; + +use ::event::WindowEvent as WindowEvent; +use ::event::DeviceId as WDeviceId; +use ::event::{ElementState, MouseButton}; + +use ::wasm_bindgen::prelude::*; +use ::web_sys::MouseEvent; +use super::window::DeviceId; + +impl From for WindowEvent { + fn from(event: MouseEvent) -> Self { + WindowEvent::MouseInput { + device_id: WDeviceId(DeviceId::dummy()), + state: ElementState::Pressed, + button: MouseButton::Left, + modifiers: Default::default() + } + } +} \ No newline at end of file diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index de35090553..a6552f063e 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,6 +1,3 @@ -extern crate web_sys; -extern crate wasm_bindgen; - use event_loop::{ControlFlow, EventLoopClosed}; use event::Event; use super::window::{MonitorHandle, Window, WindowId, WindowInternal}; @@ -11,9 +8,9 @@ use std::collections::VecDeque; use std::rc::Rc; use std::cell::RefCell; -use self::wasm_bindgen::prelude::*; -use self::wasm_bindgen::JsCast; -use self::web_sys::Element; +use ::wasm_bindgen::prelude::*; +use ::wasm_bindgen::JsCast; +use ::web_sys::Element; pub struct EventLoop { window_target: ::event_loop::EventLoopWindowTarget diff --git a/src/platform_impl/websys/mod.rs b/src/platform_impl/websys/mod.rs index fcf20370e4..f9e7cf3dfd 100644 --- a/src/platform_impl/websys/mod.rs +++ b/src/platform_impl/websys/mod.rs @@ -4,4 +4,5 @@ pub use self::window::{DeviceId, MonitorHandle, Window, WindowId, PlatformSpecif #[macro_use] mod wasm_util; mod event_loop; +mod event; pub mod window; \ No newline at end of file diff --git a/src/platform_impl/websys/wasm_util.rs b/src/platform_impl/websys/wasm_util.rs index a08c7927da..fb9d014e88 100644 --- a/src/platform_impl/websys/wasm_util.rs +++ b/src/platform_impl/websys/wasm_util.rs @@ -1,7 +1,4 @@ -extern crate wasm_bindgen; -extern crate web_sys; - -use self::wasm_bindgen::prelude::*; +use wasm_bindgen::prelude::*; use window::CreationError; // A macro to provide `println!(..)`-style syntax for `console.log` logging. diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 3a8dae99b8..0d347a2c5f 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,5 +1,3 @@ -extern crate wasm_bindgen; - use window::{WindowAttributes, CreationError, MouseCursor}; use std::collections::VecDeque; use std::rc::Rc; @@ -8,8 +6,8 @@ use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; -use self::wasm_bindgen::prelude::*; -use self::wasm_bindgen::JsCast; +use ::wasm_bindgen::prelude::*; +use ::wasm_bindgen::JsCast; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(u32); @@ -83,7 +81,7 @@ impl MonitorHandle { } pub struct Window { - pub(crate) canvas: web_sys::HtmlCanvasElement, + pub(crate) canvas: ::web_sys::HtmlCanvasElement, internal: Rc } @@ -109,7 +107,7 @@ impl Window { attr: WindowAttributes, ps_attr: PlatformSpecificWindowBuilderAttributes) -> Result { - let window = web_sys::window() + let window = ::web_sys::window() .expect("No global window object found!"); let document = window.document() .expect("Global window does not have a document!"); @@ -118,7 +116,7 @@ impl Window { ElementSelection::CanvasId(id) => { document.get_element_by_id(&id) .expect(&format!("No canvas with ID {} found", id)) - .dyn_into::().unwrap() + .dyn_into::<::web_sys::HtmlCanvasElement>().unwrap() }, ElementSelection::ContainerId(id) => { let parent = document.get_element_by_id(&id) @@ -126,7 +124,7 @@ impl Window { let canvas = document.create_element("canvas") .expect("Could not create a canvas") - .dyn_into::().unwrap(); + .dyn_into::<::web_sys::HtmlCanvasElement>().unwrap(); parent.append_child(&canvas); @@ -142,15 +140,10 @@ impl Window { // TODO: install WindowEvent handlers let mut win = internal.clone(); - let click_handler = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { + let click_handler = Closure::wrap(Box::new(move |event: ::web_sys::MouseEvent| { // TODO: process the event - win.pending_events.borrow_mut().push(::event::WindowEvent::MouseInput { - device_id: ::event::DeviceId(DeviceId(0)), - state: ::event::ElementState::Pressed, - button: ::event::MouseButton::Left, - modifiers: Default::default() - }); - }) as Box); + win.pending_events.borrow_mut().push(event.into()); + }) as Box); element.set_onmousedown(Some(click_handler.as_ref().unchecked_ref())); click_handler.forget(); From 63fab765752d4e4f49e750c970b5bdfd387fe8fc Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sun, 12 May 2019 16:20:45 -0700 Subject: [PATCH 10/14] macro for installing simple events --- src/platform_impl/websys/window.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 0d347a2c5f..4fbf5d1d4d 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -95,6 +95,17 @@ impl WindowInternal { } } +macro_rules! install_simple_handler { + ($in:ty, $f:ident, $w:ident, $e:ident) => { + let mut win = $w.clone(); + let handler = Closure::wrap(Box::new(move |event: $in| { + win.pending_events.borrow_mut().push(event.into()); + }) as Box); + $e.$f(Some(handler.as_ref().unchecked_ref())); + handler.forget(); + } +} + impl Window { /// Creates a new Window for platforms where this is appropriate. /// @@ -138,14 +149,11 @@ impl Window { target.set_window(internal.clone()); - // TODO: install WindowEvent handlers - let mut win = internal.clone(); - let click_handler = Closure::wrap(Box::new(move |event: ::web_sys::MouseEvent| { - // TODO: process the event - win.pending_events.borrow_mut().push(event.into()); - }) as Box); - element.set_onmousedown(Some(click_handler.as_ref().unchecked_ref())); - click_handler.forget(); + install_simple_handler!(::web_sys::MouseEvent, set_onmousedown, internal, element); + install_simple_handler!(::web_sys::MouseEvent, set_onmouseup, internal, element); + install_simple_handler!(::web_sys::MouseEvent, set_onmouseenter, internal, element); + install_simple_handler!(::web_sys::MouseEvent, set_onmouseleave, internal, element); + Ok(Window { canvas: element, From 8b9280ebfed914eebca22ac87b12e2c7aff0a04a Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Wed, 22 May 2019 22:36:48 -0700 Subject: [PATCH 11/14] moved events back over to event_loop, sleeping works now --- src/platform_impl/websys/event_loop.rs | 147 ++++++++++++++++++------- src/platform_impl/websys/window.rs | 32 +++--- 2 files changed, 124 insertions(+), 55 deletions(-) diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index a6552f063e..8fc24e1921 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,31 +1,99 @@ -use event_loop::{ControlFlow, EventLoopClosed}; -use event::Event; +use ::event_loop::{ControlFlow, EventLoopClosed}; +use ::event_loop::EventLoopWindowTarget as WinitELT; +use ::event::{Event, StartCause}; use super::window::{MonitorHandle, Window, WindowId, WindowInternal}; #[macro_use] use platform_impl::platform::wasm_util as util; use std::collections::VecDeque; use std::rc::Rc; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use ::wasm_bindgen::prelude::*; use ::wasm_bindgen::JsCast; -use ::web_sys::Element; +use ::web_sys::{Element, HtmlCanvasElement}; + +#[derive(Clone, Copy, Eq, PartialEq)] +enum EventLoopState { + Sleeping, + Waking, + Polling +} + +impl Default for EventLoopState { + #[inline(always)] + fn default() -> Self { + EventLoopState::Polling + } +} + +pub struct EventLoopWindowTarget { + pub(crate) window_events: Rc>>, + pub(crate) internal: Rc, + _marker: std::marker::PhantomData +} + +impl EventLoopWindowTarget { + pub fn events(&self) -> Vec<::event::WindowEvent> { + self.window_events.replace(Vec::new()) + } + + + pub fn setup_window(&self, element: &HtmlCanvasElement) { + let events = self.window_events.clone(); + let internal = self.internal.clone(); + let handler = Closure::wrap(Box::new(move |event: ::web_sys::MouseEvent| { + events.borrow_mut().push(event.into()); + if internal.is_sleeping() { + internal.wake(); + } + }) as Box); + element.set_onmousedown(Some(handler.as_ref().unchecked_ref())); + handler.forget(); + } +} pub struct EventLoop { - window_target: ::event_loop::EventLoopWindowTarget + window_target: WinitELT, +} + +pub(crate) struct EventLoopInternal { + loop_fn: Rc>>>, + state: Cell, +} + +impl EventLoopInternal { + pub(crate) fn sleep(&self) { + self.state.set(EventLoopState::Sleeping); + } + + pub(crate) fn wake(&self) { + self.state.set(EventLoopState::Waking); + let window = web_sys::window().expect("should be a window"); + // TODO: call this directly? + window.request_animation_frame(self.loop_fn.borrow().as_ref().unwrap().as_ref().unchecked_ref()); + } + + pub(crate) fn is_sleeping(&self) -> bool { + self.state.get() == EventLoopState::Sleeping + } } impl EventLoop { pub fn new() -> EventLoop { + let loop_fn: Rc>>> = Rc::new(RefCell::new(None)); EventLoop { - window_target: ::event_loop::EventLoopWindowTarget { + window_target: WinitELT { p: EventLoopWindowTarget { - window: RefCell::new(None), + window_events: Rc::new(RefCell::new(Vec::new())), + internal: Rc::new(EventLoopInternal { + state: Cell::default(), + loop_fn, + }), _marker: std::marker::PhantomData }, _marker: std::marker::PhantomData - } + }, } } @@ -45,7 +113,7 @@ impl EventLoop { #[inline] pub fn run(self, event_handler: F) -> ! - where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) + where F: 'static + FnMut(Event, &WinitELT, &mut ControlFlow) { self.run_return(event_handler); log!("exiting"); @@ -55,35 +123,47 @@ impl EventLoop { } fn run_return(self, mut event_handler: F) - where F: 'static + FnMut(Event, &::event_loop::EventLoopWindowTarget, &mut ControlFlow) + where F: 'static + FnMut(Event, &WinitELT, &mut ControlFlow) { let mut control_flow = ControlFlow::default(); - let f: Rc>>> = Rc::new(RefCell::new(None)); - let g = f.clone(); + let g = self.window_target.p.internal.loop_fn.clone(); - event_handler(::event::Event::NewEvents(::event::StartCause::Init), &self.window_target, &mut control_flow); + event_handler(Event::NewEvents(StartCause::Init), &self.window_target, &mut control_flow); *g.borrow_mut() = Some(Closure::wrap(Box::new(move || { - if control_flow == ControlFlow::Poll { - - let mut win_events = self.window_target.p.window().events(); - win_events.drain(..).for_each(|e| { - event_handler(::event::Event::WindowEvent{window_id: ::window::WindowId(WindowId{}), event: e}, &self.window_target, &mut control_flow); - }); - - event_handler(::event::Event::NewEvents(::event::StartCause::Poll), &self.window_target, &mut control_flow); - } - - let window = web_sys::window().expect("should be a window"); - window.request_animation_frame(f.borrow().as_ref().unwrap().as_ref().unchecked_ref()); + match control_flow { + ControlFlow::Poll => { + log!("Starting poll!!!"); + let mut win_events = self.window_target.p.events(); + win_events.drain(..).for_each(|e| { + event_handler(Event::WindowEvent{window_id: ::window::WindowId(WindowId{}), event: e}, &self.window_target, &mut control_flow); + }); + + event_handler(Event::NewEvents(StartCause::Poll), &self.window_target, &mut control_flow); + + let window = web_sys::window().expect("should be a window"); + window.request_animation_frame(self.window_target.p.internal.loop_fn.borrow().as_ref().unwrap().as_ref().unchecked_ref()); + }, + ControlFlow::Wait => { + let mut win_events = self.window_target.p.events(); + win_events.drain(..).for_each(|e| { + event_handler(Event::WindowEvent{window_id: ::window::WindowId(WindowId{}), event: e}, &self.window_target, &mut control_flow); + }); + self.window_target.p.internal.sleep(); + event_handler(Event::Suspended(true), &self.window_target, &mut control_flow); + }, + _ => { + unreachable!(); + } + } }) as Box)); let window = web_sys::window().expect("should be a window"); window.request_animation_frame(g.borrow().as_ref().unwrap().as_ref().unchecked_ref()); } - pub fn window_target(&self) -> &::event_loop::EventLoopWindowTarget { + pub fn window_target(&self) -> &WinitELT { &self.window_target } @@ -99,18 +179,3 @@ impl EventLoopProxy { unimplemented!() } } - -pub struct EventLoopWindowTarget { - window: RefCell>>, - _marker: std::marker::PhantomData -} - -impl EventLoopWindowTarget { - pub(crate) fn set_window(&self, window: Rc) { - self.window.borrow_mut().replace(window.clone()); - } - - pub(crate) fn window(&self) -> Rc { - self.window.borrow().as_ref().map(|w| w.clone()).unwrap() - } -} diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index 4fbf5d1d4d..d271ad1125 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -82,24 +82,21 @@ impl MonitorHandle { pub struct Window { pub(crate) canvas: ::web_sys::HtmlCanvasElement, - internal: Rc } -pub(crate) struct WindowInternal { - pub pending_events: RefCell> -} - -impl WindowInternal { - pub fn events(&self) -> Vec<::event::WindowEvent> { - self.pending_events.replace(Vec::new()) - } +pub(crate) struct WindowInternal<'a, T: 'static> { + pub target: &'a EventLoopWindowTarget, + _marker: std::marker::PhantomData, } macro_rules! install_simple_handler { ($in:ty, $f:ident, $w:ident, $e:ident) => { - let mut win = $w.clone(); + let win = $w.clone(); let handler = Closure::wrap(Box::new(move |event: $in| { - win.pending_events.borrow_mut().push(event.into()); + win.target.window_events.borrow_mut().push(event.into()); + if win.target.is_sleeping() { + win.target.wake(); + } }) as Box); $e.$f(Some(handler.as_ref().unchecked_ref())); handler.forget(); @@ -144,20 +141,27 @@ impl Window { }; let internal = Rc::new(WindowInternal { - pending_events: RefCell::new(Vec::with_capacity(3)) + target: &target, + _marker: std::marker::PhantomData, }); - target.set_window(internal.clone()); + target.setup_window(&element); + // TODO: move these to event_loop. we can pass 'static closures to web_sys::Closure, + // meaning i can't use the reference to target. womp womp. + // + // we should still own the canvas, but events should be with the event loop. + // should bring back target.set_window, which can register the event handlers. + /* install_simple_handler!(::web_sys::MouseEvent, set_onmousedown, internal, element); install_simple_handler!(::web_sys::MouseEvent, set_onmouseup, internal, element); install_simple_handler!(::web_sys::MouseEvent, set_onmouseenter, internal, element); install_simple_handler!(::web_sys::MouseEvent, set_onmouseleave, internal, element); + */ Ok(Window { canvas: element, - internal: internal.clone() }) } From 7c144ae3685a4d8e34aac3566e88b48e5bc6634e Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sat, 8 Jun 2019 16:17:07 -0700 Subject: [PATCH 12/14] Updated for changing interfaces --- src/platform_impl/websys/event_loop.rs | 4 +- src/platform_impl/websys/mod.rs | 13 +- src/platform_impl/websys/wasm_util.rs | 10 +- src/platform_impl/websys/window.rs | 332 ++++++++++++++++--------- 4 files changed, 242 insertions(+), 117 deletions(-) diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index 8fc24e1921..8db2ed1dd4 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -102,12 +102,12 @@ impl EventLoop { } #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn available_monitors(&self) -> VecDeque { vec!(MonitorHandle{}).into_iter().collect() } #[inline] - pub fn get_primary_monitor(&self) -> MonitorHandle { + pub fn primary_monitor(&self) -> MonitorHandle { MonitorHandle{} } diff --git a/src/platform_impl/websys/mod.rs b/src/platform_impl/websys/mod.rs index f9e7cf3dfd..84173c90e6 100644 --- a/src/platform_impl/websys/mod.rs +++ b/src/platform_impl/websys/mod.rs @@ -1,8 +1,19 @@ pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; pub use self::window::{DeviceId, MonitorHandle, Window, WindowId, PlatformSpecificWindowBuilderAttributes}; +use std::fmt::{Display, Debug, Error, Formatter}; + #[macro_use] mod wasm_util; mod event_loop; mod event; -pub mod window; \ No newline at end of file +pub mod window; + +#[derive(Debug)] +pub struct OsError; + +impl Display for OsError { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { + formatter.pad(&format!("websys error")) + } +} \ No newline at end of file diff --git a/src/platform_impl/websys/wasm_util.rs b/src/platform_impl/websys/wasm_util.rs index fb9d014e88..780c6e0a2b 100644 --- a/src/platform_impl/websys/wasm_util.rs +++ b/src/platform_impl/websys/wasm_util.rs @@ -1,5 +1,9 @@ use wasm_bindgen::prelude::*; -use window::CreationError; + +#[macro_use] +use ::error::OsError as WOsError; + +use super::OsError; // A macro to provide `println!(..)`-style syntax for `console.log` logging. macro_rules! log { @@ -13,8 +17,8 @@ extern "C" { pub fn js_exit(); } -impl From for CreationError { +impl From for WOsError { fn from(error: wasm_bindgen::JsValue) -> Self { - CreationError::OsError(error.as_string().unwrap_or("Window error".to_string())) + os_error!(OsError{}) } } \ No newline at end of file diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index d271ad1125..bf2b613b15 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,4 +1,4 @@ -use window::{WindowAttributes, CreationError, MouseCursor}; +use window::{WindowAttributes}; use std::collections::VecDeque; use std::rc::Rc; use std::cell::RefCell; @@ -6,6 +6,10 @@ use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; +use ::error::{ExternalError, NotSupportedError}; +use ::monitor::AvailableMonitorsIter; +use ::window::CursorIcon; + use ::wasm_bindgen::prelude::*; use ::wasm_bindgen::JsCast; @@ -49,20 +53,20 @@ impl MonitorHandle { /// /// Returns `None` if the monitor doesn't exist anymore. #[inline] - pub fn get_name(&self) -> Option { + pub fn name(&self) -> Option { unimplemented!() } /// Returns the monitor's resolution. #[inline] - pub fn get_dimensions(&self) -> PhysicalSize { + pub fn dimensions(&self) -> PhysicalSize { unimplemented!() } /// Returns the top-left corner position of the monitor relative to the larger full /// screen area. #[inline] - pub fn get_position(&self) -> PhysicalPosition { + pub fn position(&self) -> PhysicalPosition { unimplemented!() } @@ -75,7 +79,7 @@ impl MonitorHandle { /// - **X11:** Can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. /// - **Android:** Always returns 1.0. #[inline] - pub fn get_hidpi_factor(&self) -> f64 { + pub fn hidpi_factor(&self) -> f64 { unimplemented!() } } @@ -114,7 +118,7 @@ impl Window { pub fn new(target: &EventLoopWindowTarget, attr: WindowAttributes, ps_attr: PlatformSpecificWindowBuilderAttributes) - -> Result { + -> Result { let window = ::web_sys::window() .expect("No global window object found!"); let document = window.document() @@ -165,33 +169,31 @@ impl Window { }) } - /// Modifies the title of the window. - /// - /// This is a no-op if the window has already been closed. + /// Returns an identifier unique to the window. #[inline] - pub fn set_title(&self, title: &str) { + pub fn id(&self) -> WindowId { + WindowId::dummy() } - /// Shows the window if it was hidden. - /// - /// ## Platform-specific + /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. /// - /// - Has no effect on Android + /// See the [`dpi`](dpi/index.html) module for more information. /// - #[inline] - pub fn show(&self) { - unimplemented!() - } - - /// Hides the window if it was visible. + /// Note that this value can change depending on user action (for example if the window is + /// moved to another screen); as such, tracking `WindowEvent::HiDpiFactorChanged` events is + /// the most robust way to track the DPI you need to use to draw. /// /// ## Platform-specific /// - /// - Has no effect on Android + /// - **X11:** This respects Xft.dpi, and can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. + /// - **Android:** Always returns 1.0. + /// - **iOS:** Can only be called on the main thread. Returns the underlying `UIView`'s + /// [`contentScaleFactor`]. /// + /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc #[inline] - pub fn hide(&self) { - unimplemented!() + pub fn hidpi_factor(&self) -> f64 { + 1.0 } /// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS @@ -205,9 +207,33 @@ impl Window { /// * While processing `EventsCleared`. /// * While processing a `RedrawRequested` event that was sent during `EventsCleared` or any /// directly subsequent `RedrawRequested` event. + /// + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. + #[inline] pub fn request_redraw(&self) { unimplemented!() } +} + +/// Position and size functions. +impl Window { + /// Returns the position of the top-left hand corner of the window's client area relative to the + /// top-left hand corner of the desktop. + /// + /// The same conditions that apply to `outer_position` apply to this method. + /// + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the + /// window's [safe area] in the screen space coordinate system. + /// + /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc + #[inline] + pub fn inner_position(&self) -> Result { + unimplemented!() + } /// Returns the position of the top-left hand corner of the window relative to the /// top-left hand corner of the desktop. @@ -219,29 +245,27 @@ impl Window { /// The coordinates can be negative if the top-left hand corner of the window is outside /// of the visible screen region. /// - /// Returns `None` if the window no longer exists. - #[inline] - pub fn get_position(&self) -> Option { - unimplemented!() - } - - /// Returns the position of the top-left hand corner of the window's client area relative to the - /// top-left hand corner of the desktop. + /// ## Platform-specific /// - /// The same conditions that apply to `get_position` apply to this method. + /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the + /// window in the screen space coordinate system. #[inline] - pub fn get_inner_position(&self) -> Option { - // websys: we have no concept of "inner" client area, so just return position. - self.get_position() + pub fn outer_position(&self) -> Result { + unimplemented!() } /// Modifies the position of the window. /// - /// See `get_position` for more information about the coordinates. + /// See `outer_position` for more information about the coordinates. /// /// This is a no-op if the window has already been closed. + /// + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the + /// window in the screen space coordinate system. #[inline] - pub fn set_position(&self, position: LogicalPosition) { + pub fn set_outer_position(&self, position: LogicalPosition) { unimplemented!() } @@ -251,43 +275,86 @@ impl Window { /// /// Converting the returned `LogicalSize` to `PhysicalSize` produces the size your framebuffer should be. /// - /// Returns `None` if the window no longer exists. + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. Returns the `LogicalSize` of the window's + /// [safe area] in screen space coordinates. + /// + /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc #[inline] - pub fn get_inner_size(&self) -> Option { - // websys: we have no concept of "inner" client area, so just return size. - self.get_outer_size() + pub fn inner_size(&self) -> LogicalSize { + unimplemented!() } - /// Returns the logical size of the entire window. + /// Modifies the inner size of the window. /// - /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), - /// use `get_inner_size` instead. + /// See `inner_size` for more information about the values. /// - /// Returns `None` if the window no longer exists. + /// ## Platform-specific + /// + /// - **iOS:** Unimplemented. Currently this panics, as it's not clear what `set_inner_size` + /// would mean for iOS. #[inline] - pub fn get_outer_size(&self) -> Option { + pub fn set_inner_size(&self, size: LogicalSize) { unimplemented!() } - /// Modifies the inner size of the window. + /// Returns the logical size of the entire window. /// - /// See `get_inner_size` for more information about the values. + /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), + /// use `inner_size` instead. /// - /// This is a no-op if the window has already been closed. + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. Returns the `LogicalSize` of the window in + /// screen space coordinates. #[inline] - pub fn set_inner_size(&self, size: LogicalSize) { + pub fn outer_size(&self) -> LogicalSize { unimplemented!() } /// Sets a minimum dimension size for the window. + /// + /// ## Platform-specific + /// + /// - **iOS:** Has no effect. #[inline] - pub fn set_min_dimensions(&self, dimensions: Option) { + pub fn set_min_inner_size(&self, dimensions: Option) { unimplemented!() } /// Sets a maximum dimension size for the window. + /// + /// ## Platform-specific + /// + /// - **iOS:** Has no effect. + #[inline] + pub fn set_max_inner_size(&self, dimensions: Option) { + unimplemented!() + } +} + +/// Misc. attribute functions. +impl Window { + /// Modifies the title of the window. + /// + /// ## Platform-specific + /// + /// - Has no effect on iOS. + #[inline] + pub fn set_title(&self, title: &str) { + unimplemented!() + } + + /// Modifies the window's visibility. + /// + /// If `false`, this will hide the window. If `true`, this will show the window. + /// ## Platform-specific + /// + /// - **Android:** Has no effect. + /// - **iOS:** Can only be called on the main thread. #[inline] - pub fn set_max_dimensions(&self, dimensions: Option) { + pub fn set_visible(&self, visible: bool) { unimplemented!() } @@ -301,141 +368,184 @@ impl Window { /// This only has an effect on desktop platforms. /// /// Due to a bug in XFCE, this has no effect on Xfwm. + /// + /// ## Platform-specific + /// + /// - **iOS:** Has no effect. #[inline] pub fn set_resizable(&self, resizable: bool) { unimplemented!() } - /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. - /// - /// See the [`dpi`](dpi/index.html) module for more information. - /// - /// Note that this value can change depending on user action (for example if the window is - /// moved to another screen); as such, tracking `WindowEvent::HiDpiFactorChanged` events is - /// the most robust way to track the DPI you need to use to draw. + /// Sets the window to maximized or back. /// /// ## Platform-specific /// - /// - **X11:** This respects Xft.dpi, and can be overridden using the `WINIT_HIDPI_FACTOR` environment variable. - /// - **Android:** Always returns 1.0. + /// - **iOS:** Has no effect. #[inline] - pub fn get_hidpi_factor(&self) -> f64 { - 1.0 + pub fn set_maximized(&self, maximized: bool) { + unimplemented!() } - /// Modifies the mouse cursor of the window. - /// Has no effect on Android. + /// Sets the window to fullscreen or back. + /// + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. #[inline] - pub fn set_cursor(&self, cursor: MouseCursor) { + pub fn set_fullscreen(&self, monitor: Option<::monitor::MonitorHandle>) { unimplemented!() } - /// Changes the position of the cursor in window coordinates. + /// Gets the window's current fullscreen state. + /// + /// ## Platform-specific + /// + /// - **iOS:** Can only be called on the main thread. #[inline] - pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), String> { + pub fn fullscreen(&self) -> Option<::monitor::MonitorHandle> { unimplemented!() } - /// Grabs the cursor, preventing it from leaving the window. + /// Turn window decorations on or off. /// /// ## Platform-specific /// - /// On macOS, this presently merely locks the cursor in a fixed location, which looks visually awkward. + /// - **iOS:** Can only be called on the main thread. Controls whether the status bar is hidden + /// via [`setPrefersStatusBarHidden`]. /// - /// This has no effect on Android or iOS. + /// [`setPrefersStatusBarHidden`]: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc #[inline] - pub fn grab_cursor(&self, grab: bool) -> Result<(), String> { + pub fn set_decorations(&self, decorations: bool) { unimplemented!() } - /// Hides the cursor, making it invisible but still usable. + /// Change whether or not the window will always be on top of other windows. /// /// ## Platform-specific /// - /// On Windows and X11, the cursor is only hidden within the confines of the window. - /// - /// On macOS, the cursor is hidden as long as the window has input focus, even if the cursor is outside of the - /// window. - /// - /// This has no effect on Android or iOS. + /// - **iOS:** Has no effect. #[inline] - pub fn hide_cursor(&self, hide: bool) { + pub fn set_always_on_top(&self, always_on_top: bool) { unimplemented!() } - /// Sets the window to maximized or back + /// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left + /// corner of the titlebar. + /// + /// For more usage notes, see `WindowBuilder::with_window_icon`. + /// + /// ## Platform-specific + /// + /// This only has an effect on Windows and X11. #[inline] - pub fn set_maximized(&self, maximized: bool) { + pub fn set_window_icon(&self, window_icon: Option) { unimplemented!() } - /// Sets the window to fullscreen or back + /// Sets location of IME candidate box in client area coordinates relative to the top left. + /// + /// ## Platform-specific + /// + /// **iOS:** Has no effect. #[inline] - pub fn set_fullscreen(&self, monitor: Option<::monitor::MonitorHandle>) { + pub fn set_ime_position(&self, position: LogicalPosition) { unimplemented!() } +} - /// Turn window decorations on or off. +/// Cursor functions. +impl Window { + /// Modifies the cursor icon of the window. + /// + /// ## Platform-specific + /// + /// - **iOS:** Has no effect. + /// - **Android:** Has no effect. #[inline] - pub fn set_decorations(&self, decorations: bool) { + pub fn set_cursor_icon(&self, cursor: CursorIcon) { unimplemented!() } - /// Change whether or not the window will always be on top of other windows. + /// Changes the position of the cursor in window coordinates. + /// + /// ## Platform-specific + /// + /// - **iOS:** Always returns an `Err`. #[inline] - pub fn set_always_on_top(&self, always_on_top: bool) { + pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), ExternalError> { unimplemented!() } - /// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left - /// corner of the titlebar. - /// - /// For more usage notes, see `WindowBuilder::with_window_icon`. + /// Grabs the cursor, preventing it from leaving the window. /// /// ## Platform-specific /// - /// This only has an effect on Windows and X11. + /// - **macOS:** This presently merely locks the cursor in a fixed location, which looks visually + /// awkward. + /// - **Android:** Has no effect. + /// - **iOS:** Always returns an Err. #[inline] - pub fn set_window_icon(&self, window_icon: Option) { + pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { unimplemented!() } - /// Sets location of IME candidate box in client area coordinates relative to the top left. + /// Modifies the cursor's visibility. + /// + /// If `false`, this will hide the cursor. If `true`, this will show the cursor. + /// + /// ## Platform-specific + /// + /// - **Windows:** The cursor is only hidden within the confines of the window. + /// - **X11:** The cursor is only hidden within the confines of the window. + /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is + /// outside of the window. + /// - **iOS:** Has no effect. + /// - **Android:** Has no effect. #[inline] - pub fn set_ime_spot(&self, position: LogicalPosition) { + pub fn set_cursor_visible(&self, visible: bool) { unimplemented!() } +} +/// Monitor info functions. +impl Window { /// Returns the monitor on which the window currently resides + /// + /// ## Platform-specific + /// + /// **iOS:** Can only be called on the main thread. #[inline] - pub fn get_current_monitor(&self) -> ::monitor::MonitorHandle { - ::monitor::MonitorHandle{inner: MonitorHandle{}} + pub fn current_monitor(&self) -> ::monitor::MonitorHandle { + unimplemented!() } /// Returns the list of all the monitors available on the system. /// - /// This is the same as `EventLoop::get_available_monitors`, and is provided for convenience. + /// This is the same as `EventLoop::available_monitors`, and is provided for convenience. + /// + /// ## Platform-specific + /// + /// **iOS:** Can only be called on the main thread. #[inline] - pub fn get_available_monitors(&self) -> VecDeque { + pub fn available_monitors(&self) -> std::collections::VecDeque { unimplemented!() } /// Returns the primary monitor of the system. /// - /// This is the same as `EventLoop::get_primary_monitor`, and is provided for convenience. - #[inline] - pub fn get_primary_monitor(&self) -> MonitorHandle { - MonitorHandle {} - } - - /// Returns an identifier unique to the window. + /// This is the same as `EventLoop::primary_monitor`, and is provided for convenience. + /// + /// ## Platform-specific + /// + /// **iOS:** Can only be called on the main thread. #[inline] - pub fn id(&self) -> WindowId { - unimplemented!() + pub fn primary_monitor(&self) -> MonitorHandle { + MonitorHandle { } } - } + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WindowId { } @@ -447,7 +557,7 @@ impl WindowId { /// by this function. No other guarantees are made. This may be equal to a real `WindowId`. /// /// **Passing this into a winit function will result in undefined behavior.** - pub unsafe fn dummy() -> Self { + pub fn dummy() -> Self { WindowId{} } } From ed2c76fa76eaccdb3b0762c91b306c407a96a5b7 Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sat, 8 Jun 2019 17:51:32 -0700 Subject: [PATCH 13/14] fleshed out the window --- Cargo.toml | 4 +- src/platform/websys.rs | 7 +- src/platform_impl/websys/event.rs | 1 - src/platform_impl/websys/event_loop.rs | 4 +- src/platform_impl/websys/mod.rs | 2 +- src/platform_impl/websys/wasm_util.rs | 4 +- src/platform_impl/websys/window.rs | 145 +++++++++++++++---------- 7 files changed, 96 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f6bf1ef87..bd47c33505 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,5 +92,7 @@ features = [ 'MouseEvent', 'Node', 'Window', - 'console' + 'console', + 'CssStyleDeclaration', + 'DomRect', ] diff --git a/src/platform/websys.rs b/src/platform/websys.rs index ecaafb11e6..b2c598f428 100644 --- a/src/platform/websys.rs +++ b/src/platform/websys.rs @@ -1,11 +1,8 @@ extern crate wasm_bindgen; extern crate web_sys; -use platform_impl::Window as CanvasWindow; use platform_impl::window::ElementSelection; use window::{Window, WindowBuilder}; -use platform::websys::wasm_bindgen::prelude::*; -use platform::websys::wasm_bindgen::JsCast; pub trait WebsysWindowExt { fn get_canvas<'a>(&'a self) -> &'a web_sys::HtmlCanvasElement; @@ -18,9 +15,9 @@ impl WebsysWindowExt for Window { } pub trait WebsysWindowBuilderExt { - fn with_canvas_id(mut self, canvas_id: &str) -> WindowBuilder; + fn with_canvas_id(self, canvas_id: &str) -> WindowBuilder; - fn with_container_id(mut self, container_id: &str) -> WindowBuilder; + fn with_container_id(self, container_id: &str) -> WindowBuilder; } impl WebsysWindowBuilderExt for WindowBuilder { diff --git a/src/platform_impl/websys/event.rs b/src/platform_impl/websys/event.rs index fe5d71c25f..0e428dbe5a 100644 --- a/src/platform_impl/websys/event.rs +++ b/src/platform_impl/websys/event.rs @@ -4,7 +4,6 @@ use ::event::WindowEvent as WindowEvent; use ::event::DeviceId as WDeviceId; use ::event::{ElementState, MouseButton}; -use ::wasm_bindgen::prelude::*; use ::web_sys::MouseEvent; use super::window::DeviceId; diff --git a/src/platform_impl/websys/event_loop.rs b/src/platform_impl/websys/event_loop.rs index 8db2ed1dd4..b00aed00a8 100644 --- a/src/platform_impl/websys/event_loop.rs +++ b/src/platform_impl/websys/event_loop.rs @@ -1,7 +1,7 @@ use ::event_loop::{ControlFlow, EventLoopClosed}; use ::event_loop::EventLoopWindowTarget as WinitELT; use ::event::{Event, StartCause}; -use super::window::{MonitorHandle, Window, WindowId, WindowInternal}; +use super::window::{MonitorHandle, WindowId}; #[macro_use] use platform_impl::platform::wasm_util as util; @@ -11,7 +11,7 @@ use std::cell::{Cell, RefCell}; use ::wasm_bindgen::prelude::*; use ::wasm_bindgen::JsCast; -use ::web_sys::{Element, HtmlCanvasElement}; +use ::web_sys::{HtmlCanvasElement}; #[derive(Clone, Copy, Eq, PartialEq)] enum EventLoopState { diff --git a/src/platform_impl/websys/mod.rs b/src/platform_impl/websys/mod.rs index 84173c90e6..7e58fbb77e 100644 --- a/src/platform_impl/websys/mod.rs +++ b/src/platform_impl/websys/mod.rs @@ -1,7 +1,7 @@ pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; pub use self::window::{DeviceId, MonitorHandle, Window, WindowId, PlatformSpecificWindowBuilderAttributes}; -use std::fmt::{Display, Debug, Error, Formatter}; +use std::fmt::{Display, Error, Formatter}; #[macro_use] mod wasm_util; diff --git a/src/platform_impl/websys/wasm_util.rs b/src/platform_impl/websys/wasm_util.rs index 780c6e0a2b..d7a18aa86f 100644 --- a/src/platform_impl/websys/wasm_util.rs +++ b/src/platform_impl/websys/wasm_util.rs @@ -1,6 +1,4 @@ use wasm_bindgen::prelude::*; - -#[macro_use] use ::error::OsError as WOsError; use super::OsError; @@ -21,4 +19,4 @@ impl From for WOsError { fn from(error: wasm_bindgen::JsValue) -> Self { os_error!(OsError{}) } -} \ No newline at end of file +} diff --git a/src/platform_impl/websys/window.rs b/src/platform_impl/websys/window.rs index bf2b613b15..8655bf44ee 100644 --- a/src/platform_impl/websys/window.rs +++ b/src/platform_impl/websys/window.rs @@ -1,17 +1,16 @@ use window::{WindowAttributes}; use std::collections::VecDeque; use std::rc::Rc; -use std::cell::RefCell; +use std::cell::Cell; use dpi::{PhysicalPosition, LogicalPosition, PhysicalSize, LogicalSize}; use icon::Icon; use super::event_loop::{EventLoopWindowTarget}; use ::error::{ExternalError, NotSupportedError}; -use ::monitor::AvailableMonitorsIter; use ::window::CursorIcon; -use ::wasm_bindgen::prelude::*; use ::wasm_bindgen::JsCast; +use web_sys::HtmlElement; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId(u32); @@ -54,20 +53,30 @@ impl MonitorHandle { /// Returns `None` if the monitor doesn't exist anymore. #[inline] pub fn name(&self) -> Option { - unimplemented!() + Some(String::from("Browser Window")) } /// Returns the monitor's resolution. #[inline] pub fn dimensions(&self) -> PhysicalSize { - unimplemented!() + let win = ::web_sys::window().expect("there to be a window"); + let w = match win.inner_width() { + Ok(val) => val.as_f64().unwrap(), + Err(val) => 0.0 + }; + let h = match win.inner_height() { + Ok(val) => val.as_f64().unwrap(), + Err(val) => 0.0 + }; + + (w, h).into() } /// Returns the top-left corner position of the monitor relative to the larger full /// screen area. #[inline] pub fn position(&self) -> PhysicalPosition { - unimplemented!() + (0, 0).into() } /// Returns the DPI factor that can be used to map logical pixels to physical pixels, and vice versa. @@ -80,12 +89,13 @@ impl MonitorHandle { /// - **Android:** Always returns 1.0. #[inline] pub fn hidpi_factor(&self) -> f64 { - unimplemented!() + 1.0 } } pub struct Window { pub(crate) canvas: ::web_sys::HtmlCanvasElement, + pub(crate) redraw_requested: Cell } pub(crate) struct WindowInternal<'a, T: 'static> { @@ -93,20 +103,6 @@ pub(crate) struct WindowInternal<'a, T: 'static> { _marker: std::marker::PhantomData, } -macro_rules! install_simple_handler { - ($in:ty, $f:ident, $w:ident, $e:ident) => { - let win = $w.clone(); - let handler = Closure::wrap(Box::new(move |event: $in| { - win.target.window_events.borrow_mut().push(event.into()); - if win.target.is_sleeping() { - win.target.wake(); - } - }) as Box); - $e.$f(Some(handler.as_ref().unchecked_ref())); - handler.forget(); - } -} - impl Window { /// Creates a new Window for platforms where this is appropriate. /// @@ -138,34 +134,17 @@ impl Window { .expect("Could not create a canvas") .dyn_into::<::web_sys::HtmlCanvasElement>().unwrap(); - parent.append_child(&canvas); + parent.append_child(&canvas)?; canvas } }; - let internal = Rc::new(WindowInternal { - target: &target, - _marker: std::marker::PhantomData, - }); - target.setup_window(&element); - // TODO: move these to event_loop. we can pass 'static closures to web_sys::Closure, - // meaning i can't use the reference to target. womp womp. - // - // we should still own the canvas, but events should be with the event loop. - // should bring back target.set_window, which can register the event handlers. - /* - install_simple_handler!(::web_sys::MouseEvent, set_onmousedown, internal, element); - install_simple_handler!(::web_sys::MouseEvent, set_onmouseup, internal, element); - install_simple_handler!(::web_sys::MouseEvent, set_onmouseenter, internal, element); - install_simple_handler!(::web_sys::MouseEvent, set_onmouseleave, internal, element); - */ - - Ok(Window { canvas: element, + redraw_requested: Cell::new(false) }) } @@ -213,7 +192,12 @@ impl Window { /// - **iOS:** Can only be called on the main thread. #[inline] pub fn request_redraw(&self) { - unimplemented!() + self.redraw_requested.replace(true); + } + + #[inline] + fn canvas_as_element(&self) -> &HtmlElement { + &self.canvas } } @@ -232,7 +216,8 @@ impl Window { /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc #[inline] pub fn inner_position(&self) -> Result { - unimplemented!() + let rect = self.canvas_as_element().get_bounding_client_rect(); + Ok((rect.x(), rect.y()).into()) } /// Returns the position of the top-left hand corner of the window relative to the @@ -251,7 +236,7 @@ impl Window { /// window in the screen space coordinate system. #[inline] pub fn outer_position(&self) -> Result { - unimplemented!() + self.inner_position() } /// Modifies the position of the window. @@ -266,6 +251,7 @@ impl Window { /// window in the screen space coordinate system. #[inline] pub fn set_outer_position(&self, position: LogicalPosition) { + // TODO: support this? unimplemented!() } @@ -283,7 +269,8 @@ impl Window { /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc #[inline] pub fn inner_size(&self) -> LogicalSize { - unimplemented!() + let rect = self.canvas_as_element().get_bounding_client_rect(); + (rect.width(), rect.height()).into() } /// Modifies the inner size of the window. @@ -310,7 +297,7 @@ impl Window { /// screen space coordinates. #[inline] pub fn outer_size(&self) -> LogicalSize { - unimplemented!() + self.inner_size() } /// Sets a minimum dimension size for the window. @@ -384,7 +371,7 @@ impl Window { /// - **iOS:** Has no effect. #[inline] pub fn set_maximized(&self, maximized: bool) { - unimplemented!() + // no-op } /// Sets the window to fullscreen or back. @@ -394,7 +381,7 @@ impl Window { /// - **iOS:** Can only be called on the main thread. #[inline] pub fn set_fullscreen(&self, monitor: Option<::monitor::MonitorHandle>) { - unimplemented!() + // no-op } /// Gets the window's current fullscreen state. @@ -404,7 +391,7 @@ impl Window { /// - **iOS:** Can only be called on the main thread. #[inline] pub fn fullscreen(&self) -> Option<::monitor::MonitorHandle> { - unimplemented!() + None } /// Turn window decorations on or off. @@ -417,7 +404,7 @@ impl Window { /// [`setPrefersStatusBarHidden`]: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc #[inline] pub fn set_decorations(&self, decorations: bool) { - unimplemented!() + // no-op } /// Change whether or not the window will always be on top of other windows. @@ -427,7 +414,7 @@ impl Window { /// - **iOS:** Has no effect. #[inline] pub fn set_always_on_top(&self, always_on_top: bool) { - unimplemented!() + // no-op } /// Sets the window icon. On Windows and X11, this is typically the small icon in the top-left @@ -440,6 +427,7 @@ impl Window { /// This only has an effect on Windows and X11. #[inline] pub fn set_window_icon(&self, window_icon: Option) { + // TODO: set favicon? unimplemented!() } @@ -450,7 +438,7 @@ impl Window { /// **iOS:** Has no effect. #[inline] pub fn set_ime_position(&self, position: LogicalPosition) { - unimplemented!() + // no-op } } @@ -464,7 +452,41 @@ impl Window { /// - **Android:** Has no effect. #[inline] pub fn set_cursor_icon(&self, cursor: CursorIcon) { - unimplemented!() + let cursor_style = match cursor { + CursorIcon::Crosshair => "crosshair", + CursorIcon::Hand => "pointer", + CursorIcon::Move => "move", + CursorIcon::Text => "text", + CursorIcon::Wait => "wait", + CursorIcon::Help => "help", + CursorIcon::Progress => "progress", + + /// Cursor showing that something cannot be done. + 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::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", + _ => "auto", + }; + self.canvas_as_element().style().set_property("cursor", cursor_style).unwrap(); } /// Changes the position of the cursor in window coordinates. @@ -474,7 +496,8 @@ impl Window { /// - **iOS:** Always returns an `Err`. #[inline] pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), ExternalError> { - unimplemented!() + // unsupported + Err(ExternalError::NotSupported(NotSupportedError::new())) } /// Grabs the cursor, preventing it from leaving the window. @@ -487,7 +510,8 @@ impl Window { /// - **iOS:** Always returns an Err. #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { - unimplemented!() + // unsupported + Err(ExternalError::NotSupported(NotSupportedError::new())) } /// Modifies the cursor's visibility. @@ -504,7 +528,12 @@ impl Window { /// - **Android:** Has no effect. #[inline] pub fn set_cursor_visible(&self, visible: bool) { - unimplemented!() + let style = self.canvas_as_element().style(); + if visible { + style.set_property("cursor", "none").unwrap(); + } else { + style.set_property("cursor", "auto").unwrap(); + } } } @@ -517,7 +546,7 @@ impl Window { /// **iOS:** Can only be called on the main thread. #[inline] pub fn current_monitor(&self) -> ::monitor::MonitorHandle { - unimplemented!() + ::monitor::MonitorHandle{ inner: MonitorHandle{} } } /// Returns the list of all the monitors available on the system. @@ -528,8 +557,8 @@ impl Window { /// /// **iOS:** Can only be called on the main thread. #[inline] - pub fn available_monitors(&self) -> std::collections::VecDeque { - unimplemented!() + pub fn available_monitors(&self) -> VecDeque { + vec![MonitorHandle{}].into() } /// Returns the primary monitor of the system. From d413a031e953e8b999e2b68d7dcb8190fb2653df Mon Sep 17 00:00:00 2001 From: Spencer Leslie Date: Sat, 8 Jun 2019 17:54:30 -0700 Subject: [PATCH 14/14] updated circlecli config with websys build --- .circleci/config.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b247266cf5..624f1e3164 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,7 +32,7 @@ jobs: paths: - target - wasm-test: + emscripten-test: working_directory: ~/winit docker: - image: tomaka/rustc-emscripten @@ -43,7 +43,22 @@ jobs: key: wasm-test-cache-{{ checksum "Cargo.toml" }} - run: cargo build --example window --target wasm32-unknown-emscripten - save_cache: + key: emscripten-test-cache-{{ checksum "Cargo.toml" }} + paths: + - target + + websys-test: + working_directory: ~/winit + docker: + - image: tomaka/rustc-emscripten + steps: + - run: apt-get -qq update && apt-get install -y git + - checkout + - restore_cache: key: wasm-test-cache-{{ checksum "Cargo.toml" }} + - run: cargo build --example wasm_bindgen --target wasm32-unknown-unknown --features websys + - save_cache: + key: websys-test-cache-{{ checksum "Cargo.toml" }} paths: - target @@ -53,4 +68,5 @@ workflows: jobs: - android-test - asmjs-test - - wasm-test + - emscripten-test + - websys-test