diff options
author | 2021-10-21 22:42:14 +0300 | |
---|---|---|
committer | 2022-01-28 21:37:14 +0700 | |
commit | bdca20fc4a3e8f6bd8ffb59de75e6ca0f8a94b6a (patch) | |
tree | 8ea0d2ff0a0d780ff763d7491fc67878f549a615 | |
parent | c75ed37148b019358b0297171cf31b2577eeb9ae (diff) | |
download | iced-bdca20fc4a3e8f6bd8ffb59de75e6ca0f8a94b6a.tar.gz iced-bdca20fc4a3e8f6bd8ffb59de75e6ca0f8a94b6a.tar.bz2 iced-bdca20fc4a3e8f6bd8ffb59de75e6ca0f8a94b6a.zip |
Experimental wgpu WebGL backend support
- Added missing `draw_cache_align_4x4` call for `brush_glyph` on wasm32 target
- Added WebGL support to `integratio_wgpu` example
- Fixed test.yml CI workflow
- Removed spir-v shader in `integration_wgpu`; Fixed formatting
- Removed redundant `BoxStream` typedef
-rw-r--r-- | .github/workflows/test.yml | 2 | ||||
-rw-r--r-- | examples/integration_wgpu/.gitignore | 2 | ||||
-rw-r--r-- | examples/integration_wgpu/Cargo.toml | 13 | ||||
-rw-r--r-- | examples/integration_wgpu/README.md | 17 | ||||
-rw-r--r-- | examples/integration_wgpu/index.html | 21 | ||||
-rw-r--r-- | examples/integration_wgpu/src/controls.rs | 19 | ||||
-rw-r--r-- | examples/integration_wgpu/src/main.rs | 94 | ||||
-rw-r--r-- | examples/integration_wgpu/src/scene.rs | 23 | ||||
-rw-r--r-- | examples/integration_wgpu/src/shader/frag.spv | bin | 352 -> 0 bytes | |||
-rw-r--r-- | examples/integration_wgpu/src/shader/frag.wgsl | 4 | ||||
-rw-r--r-- | examples/integration_wgpu/src/shader/vert.spv | bin | 904 -> 0 bytes | |||
-rw-r--r-- | examples/integration_wgpu/src/shader/vert.wgsl | 6 | ||||
-rw-r--r-- | futures/src/runtime.rs | 49 | ||||
-rw-r--r-- | futures/src/subscription/tracker.rs | 52 | ||||
-rw-r--r-- | glow/src/text.rs | 12 | ||||
-rw-r--r-- | native/src/subscription.rs | 42 | ||||
-rw-r--r-- | wgpu/Cargo.toml | 1 | ||||
-rw-r--r-- | wgpu/src/text.rs | 10 | ||||
-rw-r--r-- | winit/Cargo.toml | 4 | ||||
-rw-r--r-- | winit/src/application.rs | 106 | ||||
-rw-r--r-- | winit/src/clipboard.rs | 25 |
21 files changed, 415 insertions, 87 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0450f13d..433afadc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,3 +37,5 @@ jobs: run: cargo build --package tour --target wasm32-unknown-unknown - name: Check compilation of `todos` example run: cargo build --package todos --target wasm32-unknown-unknown + - name: Check compilation of `integration_wgpu` example + run: cargo build --package integration_wgpu --target wasm32-unknown-unknown diff --git a/examples/integration_wgpu/.gitignore b/examples/integration_wgpu/.gitignore new file mode 100644 index 00000000..e188dc28 --- /dev/null +++ b/examples/integration_wgpu/.gitignore @@ -0,0 +1,2 @@ +*.wasm +*.js diff --git a/examples/integration_wgpu/Cargo.toml b/examples/integration_wgpu/Cargo.toml index a088dd1b..0ded1a56 100644 --- a/examples/integration_wgpu/Cargo.toml +++ b/examples/integration_wgpu/Cargo.toml @@ -7,5 +7,16 @@ publish = false [dependencies] iced_winit = { path = "../../winit" } -iced_wgpu = { path = "../../wgpu", features = ["spirv"] } +iced_wgpu = { path = "../../wgpu", features = ["webgl"] } env_logger = "0.8" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +console_error_panic_hook = "0.1.7" +console_log = "0.2.0" +log = "0.4" +wasm-bindgen = "0.2" +web-sys = { version = "0.3", features = ["Element", "HtmlCanvasElement", "Window", "Document"] } +# This dependency a little bit quirky, it is deep in the tree and without `js` feature it +# refuses to work with `wasm32-unknown-unknown target`. Unfortunately, we need this patch +# to make it work +getrandom = { version = "0.2", features = ["js"] } diff --git a/examples/integration_wgpu/README.md b/examples/integration_wgpu/README.md index c51c2c65..faefa153 100644 --- a/examples/integration_wgpu/README.md +++ b/examples/integration_wgpu/README.md @@ -15,5 +15,22 @@ You can run it with `cargo run`: cargo run --package integration ``` +### How to run this example with WebGL backend +NOTE: Currently, WebGL backend is is still experimental, so expect bugs. + +```sh +# 0. Install prerequisites +cargo install wasm-bindgen-cli https +# 1. cd to the current folder +# 2. Compile wasm module +cargo build -p integration_wgpu --target wasm32-unknown-unknown +# 3. Invoke wasm-bindgen +wasm-bindgen ../../target/wasm32-unknown-unknown/debug/integration_wgpu.wasm --out-dir . --target web --no-typescript +# 4. run http server +http +# 5. Open 127.0.0.1:8000 in browser +``` + + [`main`]: src/main.rs [`wgpu`]: https://github.com/gfx-rs/wgpu diff --git a/examples/integration_wgpu/index.html b/examples/integration_wgpu/index.html new file mode 100644 index 00000000..461e67a4 --- /dev/null +++ b/examples/integration_wgpu/index.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> + <title>Iced - wgpu + WebGL integration</title> + </head> + <body> + <h1>integration_wgpu</h1> + <canvas id="iced_canvas"></canvas> + <script type="module"> + import init from "./integration_wgpu.js"; + init('./integration_wgpu_bg.wasm'); + </script> + <style> + body { + width: 100%; + text-align: center; + } + </style> + </body> +</html> diff --git a/examples/integration_wgpu/src/controls.rs b/examples/integration_wgpu/src/controls.rs index 4f110bd2..9bca40eb 100644 --- a/examples/integration_wgpu/src/controls.rs +++ b/examples/integration_wgpu/src/controls.rs @@ -1,23 +1,29 @@ use iced_wgpu::Renderer; use iced_winit::widget::slider::{self, Slider}; +use iced_winit::widget::text_input::{self, TextInput}; use iced_winit::widget::{Column, Row, Text}; use iced_winit::{Alignment, Color, Command, Element, Length, Program}; pub struct Controls { background_color: Color, + text: String, sliders: [slider::State; 3], + text_input: text_input::State, } #[derive(Debug, Clone)] pub enum Message { BackgroundColorChanged(Color), + TextChanged(String), } impl Controls { pub fn new() -> Controls { Controls { background_color: Color::BLACK, + text: Default::default(), sliders: Default::default(), + text_input: Default::default(), } } @@ -35,6 +41,9 @@ impl Program for Controls { Message::BackgroundColorChanged(color) => { self.background_color = color; } + Message::TextChanged(text) => { + self.text = text; + } } Command::none() @@ -42,7 +51,9 @@ impl Program for Controls { fn view(&mut self) -> Element<Message, Renderer> { let [r, g, b] = &mut self.sliders; + let t = &mut self.text_input; let background_color = self.background_color; + let text = &self.text; let sliders = Row::new() .width(Length::Units(500)) @@ -96,7 +107,13 @@ impl Program for Controls { Text::new(format!("{:?}", background_color)) .size(14) .color(Color::WHITE), - ), + ) + .push(TextInput::new( + t, + "Placeholder", + text, + move |text| Message::TextChanged(text), + )), ), ) .into() diff --git a/examples/integration_wgpu/src/main.rs b/examples/integration_wgpu/src/main.rs index 35a69a7d..045ee0d3 100644 --- a/examples/integration_wgpu/src/main.rs +++ b/examples/integration_wgpu/src/main.rs @@ -14,11 +14,39 @@ use winit::{ event_loop::{ControlFlow, EventLoop}, }; +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::JsCast; +#[cfg(target_arch = "wasm32")] +use web_sys::HtmlCanvasElement; +#[cfg(target_arch = "wasm32")] +use winit::platform::web::WindowBuilderExtWebSys; + pub fn main() { + #[cfg(target_arch = "wasm32")] + let canvas_element = { + console_log::init_with_level(log::Level::Debug) + .expect("could not initialize logger"); + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| doc.get_element_by_id("iced_canvas")) + .and_then(|element| element.dyn_into::<HtmlCanvasElement>().ok()) + .expect("Canvas with id `iced_canvas` is missing") + }; + #[cfg(not(target_arch = "wasm32"))] env_logger::init(); // Initialize winit let event_loop = EventLoop::new(); + + #[cfg(target_arch = "wasm32")] + let window = winit::window::WindowBuilder::new() + .with_canvas(Some(canvas_element)) + .build(&event_loop) + .expect("Failed to build winit window"); + + #[cfg(not(target_arch = "wasm32"))] let window = winit::window::Window::new(&event_loop).unwrap(); let physical_size = window.inner_size(); @@ -31,18 +59,35 @@ pub fn main() { let mut clipboard = Clipboard::connect(&window); // Initialize wgpu - let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); + + #[cfg(target_arch = "wasm32")] + let default_backend = wgpu::Backends::GL; + #[cfg(not(target_arch = "wasm32"))] + let default_backend = wgpu::Backends::PRIMARY; + + let backend = + wgpu::util::backend_bits_from_env().unwrap_or(default_backend); + + let instance = wgpu::Instance::new(backend); let surface = unsafe { instance.create_surface(&window) }; let (format, (mut device, queue)) = futures::executor::block_on(async { - let adapter = instance - .request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::HighPerformance, - compatible_surface: Some(&surface), - force_fallback_adapter: false, - }) - .await - .expect("Request adapter"); + let adapter = wgpu::util::initialize_adapter_from_env_or_default( + &instance, + backend, + Some(&surface), + ) + .await + .expect("No suitable GPU adapters found on the system!"); + + let adapter_features = adapter.features(); + + #[cfg(target_arch = "wasm32")] + let needed_limits = wgpu::Limits::downlevel_webgl2_defaults() + .using_resolution(adapter.limits()); + + #[cfg(not(target_arch = "wasm32"))] + let needed_limits = wgpu::Limits::default(); ( surface @@ -52,8 +97,8 @@ pub fn main() { .request_device( &wgpu::DeviceDescriptor { label: None, - features: wgpu::Features::empty(), - limits: wgpu::Limits::default(), + features: adapter_features & wgpu::Features::default(), + limits: needed_limits, }, None, ) @@ -62,20 +107,17 @@ pub fn main() { ) }); - { - let size = window.inner_size(); - - surface.configure( - &device, - &wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format, - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Mailbox, - }, - ) - }; + surface.configure( + &device, + &wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format, + width: physical_size.width, + height: physical_size.height, + present_mode: wgpu::PresentMode::Mailbox, + }, + ); + let mut resized = false; // Initialize staging belt and local pool @@ -83,7 +125,7 @@ pub fn main() { let mut local_pool = futures::executor::LocalPool::new(); // Initialize scene and GUI controls - let scene = Scene::new(&mut device); + let scene = Scene::new(&mut device, format); let controls = Controls::new(); // Initialize iced diff --git a/examples/integration_wgpu/src/scene.rs b/examples/integration_wgpu/src/scene.rs index 910d8d8c..fbda1326 100644 --- a/examples/integration_wgpu/src/scene.rs +++ b/examples/integration_wgpu/src/scene.rs @@ -6,8 +6,11 @@ pub struct Scene { } impl Scene { - pub fn new(device: &wgpu::Device) -> Scene { - let pipeline = build_pipeline(device); + pub fn new( + device: &wgpu::Device, + texture_format: wgpu::TextureFormat, + ) -> Scene { + let pipeline = build_pipeline(device, texture_format); Scene { pipeline } } @@ -47,12 +50,14 @@ impl Scene { } } -fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { - let vs_module = - device.create_shader_module(&wgpu::include_spirv!("shader/vert.spv")); - - let fs_module = - device.create_shader_module(&wgpu::include_spirv!("shader/frag.spv")); +fn build_pipeline( + device: &wgpu::Device, + texture_format: wgpu::TextureFormat, +) -> wgpu::RenderPipeline { + let (vs_module, fs_module) = ( + device.create_shader_module(&wgpu::include_wgsl!("shader/vert.wgsl")), + device.create_shader_module(&wgpu::include_wgsl!("shader/frag.wgsl")), + ); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { @@ -74,7 +79,7 @@ fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { module: &fs_module, entry_point: "main", targets: &[wgpu::ColorTargetState { - format: wgpu::TextureFormat::Bgra8UnormSrgb, + format: texture_format, blend: Some(wgpu::BlendState { color: wgpu::BlendComponent::REPLACE, alpha: wgpu::BlendComponent::REPLACE, diff --git a/examples/integration_wgpu/src/shader/frag.spv b/examples/integration_wgpu/src/shader/frag.spv Binary files differdeleted file mode 100644 index 9d6807c9..00000000 --- a/examples/integration_wgpu/src/shader/frag.spv +++ /dev/null diff --git a/examples/integration_wgpu/src/shader/frag.wgsl b/examples/integration_wgpu/src/shader/frag.wgsl new file mode 100644 index 00000000..a6f61336 --- /dev/null +++ b/examples/integration_wgpu/src/shader/frag.wgsl @@ -0,0 +1,4 @@ +[[stage(fragment)]] +fn main() -> [[location(0)]] vec4<f32> { + return vec4<f32>(1.0, 0.0, 0.0, 1.0); +} diff --git a/examples/integration_wgpu/src/shader/vert.spv b/examples/integration_wgpu/src/shader/vert.spv Binary files differdeleted file mode 100644 index 0cabc9c0..00000000 --- a/examples/integration_wgpu/src/shader/vert.spv +++ /dev/null diff --git a/examples/integration_wgpu/src/shader/vert.wgsl b/examples/integration_wgpu/src/shader/vert.wgsl new file mode 100644 index 00000000..7ef47fb2 --- /dev/null +++ b/examples/integration_wgpu/src/shader/vert.wgsl @@ -0,0 +1,6 @@ +[[stage(vertex)]] +fn main([[builtin(vertex_index)]] in_vertex_index: u32) -> [[builtin(position)]] vec4<f32> { + let x = f32(1 - i32(in_vertex_index)) * 0.5; + let y = f32(1 - i32(in_vertex_index & 1u) * 2) * 0.5; + return vec4<f32>(x, y, 0.0, 1.0); +} diff --git a/futures/src/runtime.rs b/futures/src/runtime.rs index 7779e235..96104cd9 100644 --- a/futures/src/runtime.rs +++ b/futures/src/runtime.rs @@ -5,6 +5,50 @@ use crate::{subscription, Executor, Subscription}; use futures::{channel::mpsc, Sink}; use std::marker::PhantomData; +#[cfg(not(target_arch = "wasm32"))] +mod trait_aliases { + use super::*; + + pub trait RuntimeMessage: Send + 'static {} + + impl<T> RuntimeMessage for T where T: Send + 'static {} + + pub trait RuntimeMessageSender<Message: RuntimeMessage>: + Sink<Message, Error = mpsc::SendError> + Unpin + Send + Clone + 'static + { + } + + impl<Message: RuntimeMessage, T> RuntimeMessageSender<Message> for T where + T: Sink<Message, Error = mpsc::SendError> + + Unpin + + Send + + Clone + + 'static + { + } +} + +#[cfg(target_arch = "wasm32")] +mod trait_aliases { + use super::*; + + pub trait RuntimeMessage: 'static {} + + impl<T> RuntimeMessage for T where T: 'static {} + + pub trait RuntimeMessageSender<Message: RuntimeMessage>: + Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static + { + } + + impl<Message: RuntimeMessage, T> RuntimeMessageSender<Message> for T where + T: Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static + { + } +} + +pub use trait_aliases::{RuntimeMessage, RuntimeMessageSender}; + /// A batteries-included runtime of commands and subscriptions. /// /// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any @@ -23,9 +67,8 @@ where Hasher: std::hash::Hasher + Default, Event: Send + Clone + 'static, Executor: self::Executor, - Sender: - Sink<Message, Error = mpsc::SendError> + Unpin + Send + Clone + 'static, - Message: Send + 'static, + Sender: RuntimeMessageSender<Message>, + Message: RuntimeMessage, { /// Creates a new empty [`Runtime`]. /// diff --git a/futures/src/subscription/tracker.rs b/futures/src/subscription/tracker.rs index 3a8d4a87..01e0c105 100644 --- a/futures/src/subscription/tracker.rs +++ b/futures/src/subscription/tracker.rs @@ -3,6 +3,50 @@ use crate::{BoxFuture, Subscription}; use futures::{channel::mpsc, sink::Sink}; use std::{collections::HashMap, marker::PhantomData}; +#[cfg(not(target_arch = "wasm32"))] +mod trait_aliases { + use super::*; + + pub trait TrackerMessage: Send + 'static {} + + impl<T> TrackerMessage for T where T: Send + 'static {} + + pub trait TrackerMessageReceiver<Message: TrackerMessage>: + Sink<Message, Error = mpsc::SendError> + Unpin + Send + Clone + 'static + { + } + + impl<Message: TrackerMessage, T> TrackerMessageReceiver<Message> for T where + T: Sink<Message, Error = mpsc::SendError> + + Unpin + + Send + + Clone + + 'static + { + } +} + +#[cfg(target_arch = "wasm32")] +mod trait_aliases { + use super::*; + + pub trait TrackerMessage: 'static {} + + impl<T> TrackerMessage for T where T: 'static {} + + pub trait TrackerMessageReceiver<Message: TrackerMessage>: + Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static + { + } + + impl<Message: TrackerMessage, T> TrackerMessageReceiver<Message> for T where + T: Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static + { + } +} + +pub use trait_aliases::{TrackerMessage, TrackerMessageReceiver}; + /// A registry of subscription streams. /// /// If you have an application that continuously returns a [`Subscription`], @@ -57,12 +101,8 @@ where receiver: Receiver, ) -> Vec<BoxFuture<()>> where - Message: 'static + Send, - Receiver: 'static - + Sink<Message, Error = mpsc::SendError> - + Unpin - + Send - + Clone, + Message: TrackerMessage, + Receiver: TrackerMessageReceiver<Message>, { use futures::{future::FutureExt, stream::StreamExt}; diff --git a/glow/src/text.rs b/glow/src/text.rs index 3b6f3bf5..834e7902 100644 --- a/glow/src/text.rs +++ b/glow/src/text.rs @@ -46,11 +46,15 @@ impl Pipeline { .expect("Load fallback font") }); - let draw_brush = - glow_glyph::GlyphBrushBuilder::using_font(font.clone()) + let draw_brush_builder = + wgpu_glyph::GlyphBrushBuilder::using_font(font.clone()) .initial_cache_size((2048, 2048)) - .draw_cache_multithread(multithreading) - .build(&gl); + .draw_cache_multithread(multithreading); + + #[cfg(target_arch = "wasm32")] + let draw_brush_builder = draw_brush_builder.draw_cache_align_4x4(true); + + let draw_brush = draw_brush_builder.build(&gl); let measure_brush = glyph_brush::GlyphBrushBuilder::using_font(font).build(); diff --git a/native/src/subscription.rs b/native/src/subscription.rs index 63834654..4fb7e760 100644 --- a/native/src/subscription.rs +++ b/native/src/subscription.rs @@ -7,6 +7,37 @@ use iced_futures::BoxStream; use std::hash::Hash; +#[cfg(not(target_arch = "wasm32"))] +mod trait_aliases { + use super::*; + + /// Wrapper type + pub trait RunnerStream<Message>: + Stream<Item = Message> + Send + 'static + { + } + + impl<T, Message> RunnerStream<Message> for T where + T: Stream<Item = Message> + Send + 'static + { + } +} + +#[cfg(target_arch = "wasm32")] +mod trait_aliases { + use super::*; + + /// Wrapper type + pub trait RunnerStream<Message>: Stream<Item = Message> + 'static {} + + impl<T, Message> RunnerStream<Message> for T where + T: Stream<Item = Message> + 'static + { + } +} + +pub use trait_aliases::RunnerStream; + /// A request to listen to external events. /// /// Besides performing async actions on demand with [`Command`], most @@ -191,7 +222,7 @@ impl<I, S, F, Message> Recipe<Hasher, (Event, event::Status)> where I: Hash + 'static, F: FnOnce(EventStream) -> S, - S: Stream<Item = Message> + Send + 'static, + S: RunnerStream<Message>, { type Output = Message; @@ -203,6 +234,13 @@ where fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> { use futures::stream::StreamExt; - (self.spawn)(input).boxed() + #[cfg(target_arch = "wasm32")] + { + (self.spawn)(input).boxed_local() + } + #[cfg(not(target_arch = "wasm32"))] + { + (self.spawn)(input).boxed() + } } } diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index f4c4fa2c..46012ea7 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -25,6 +25,7 @@ canvas = ["iced_graphics/canvas"] qr_code = ["iced_graphics/qr_code"] default_system_font = ["iced_graphics/font-source"] spirv = ["wgpu/spirv"] +webgl = ["wgpu/webgl"] [dependencies] wgpu = "0.12" diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 336696ee..45f1f2de 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -48,11 +48,15 @@ impl Pipeline { .expect("Load fallback font") }); - let draw_brush = + let draw_brush_builder = wgpu_glyph::GlyphBrushBuilder::using_font(font.clone()) .initial_cache_size((2048, 2048)) - .draw_cache_multithread(multithreading) - .build(device, format); + .draw_cache_multithread(multithreading); + + #[cfg(target_arch = "wasm32")] + let draw_brush_builder = draw_brush_builder.draw_cache_align_4x4(true); + + let draw_brush = draw_brush_builder.build(device, format); let measure_brush = glyph_brush::GlyphBrushBuilder::using_font(font).build(); diff --git a/winit/Cargo.toml b/winit/Cargo.toml index bfcfacbc..e0581b00 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -14,7 +14,6 @@ categories = ["gui"] debug = ["iced_native/debug"] [dependencies] -window_clipboard = "0.2" log = "0.4" thiserror = "1.0" @@ -37,3 +36,6 @@ path = "../futures" [target.'cfg(target_os = "windows")'.dependencies.winapi] version = "0.3.6" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies.window_clipboard] +version = "0.2" diff --git a/winit/src/application.rs b/winit/src/application.rs index e9212b5e..a3715b04 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -115,12 +115,16 @@ where use futures::task; use futures::Future; use winit::event_loop::EventLoop; + #[cfg(not(target_arch = "wasm32"))] use winit::platform::run_return::EventLoopExtRunReturn; let mut debug = Debug::new(); debug.startup_started(); + #[cfg(not(target_arch = "wasm32"))] let mut event_loop = EventLoop::with_user_event(); + #[cfg(target_arch = "wasm32")] + let event_loop = EventLoop::with_user_event(); let mut proxy = event_loop.create_proxy(); let mut runtime = { @@ -179,41 +183,81 @@ where let mut context = task::Context::from_waker(task::noop_waker_ref()); - event_loop.run_return(move |event, _, control_flow| { - use winit::event_loop::ControlFlow; + #[cfg(not(target_arch = "wasm32"))] + { + event_loop.run_return(move |event, _, control_flow| { + use winit::event_loop::ControlFlow; - if let ControlFlow::Exit = control_flow { - return; - } + if let ControlFlow::Exit = control_flow { + return; + } - let event = match event { - winit::event::Event::WindowEvent { - event: - winit::event::WindowEvent::ScaleFactorChanged { - new_inner_size, - .. - }, - window_id, - } => Some(winit::event::Event::WindowEvent { - event: winit::event::WindowEvent::Resized(*new_inner_size), - window_id, - }), - _ => event.to_static(), - }; - - if let Some(event) = event { - sender.start_send(event).expect("Send event"); - - let poll = instance.as_mut().poll(&mut context); - - *control_flow = match poll { - task::Poll::Pending => ControlFlow::Wait, - task::Poll::Ready(_) => ControlFlow::Exit, + let event = match event { + winit::event::Event::WindowEvent { + event: + winit::event::WindowEvent::ScaleFactorChanged { + new_inner_size, + .. + }, + window_id, + } => Some(winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::Resized(*new_inner_size), + window_id, + }), + _ => event.to_static(), }; - } - }); - Ok(()) + if let Some(event) = event { + sender.start_send(event).expect("Send event"); + + let poll = instance.as_mut().poll(&mut context); + + *control_flow = match poll { + task::Poll::Pending => ControlFlow::Wait, + task::Poll::Ready(_) => ControlFlow::Exit, + }; + } + }); + + Ok(()) + } + + #[cfg(target_arch = "wasm32")] + { + event_loop.run(move |event, _, control_flow| { + use winit::event_loop::ControlFlow; + + if let ControlFlow::Exit = control_flow { + return; + } + + let event = match event { + winit::event::Event::WindowEvent { + event: + winit::event::WindowEvent::ScaleFactorChanged { + new_inner_size, + .. + }, + window_id, + } => Some(winit::event::Event::WindowEvent { + event: winit::event::WindowEvent::Resized(*new_inner_size), + window_id, + }), + _ => event.to_static(), + }; + + if let Some(event) = event { + sender.start_send(event).expect("Send event"); + + let poll = instance.as_mut().poll(&mut context); + + *control_flow = match poll { + task::Poll::Pending => ControlFlow::Wait, + task::Poll::Ready(_) => ControlFlow::Exit, + }; + } + }); + } } async fn run_instance<A, E, C>( diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index 1b92b28d..197d32b3 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -6,15 +6,40 @@ use crate::command::{self, Command}; /// A buffer for short-term storage and transfer within and between /// applications. #[allow(missing_debug_implementations)] +#[cfg(target_arch = "wasm32")] +pub struct Clipboard; + +#[cfg(target_arch = "wasm32")] +impl Clipboard { + /// Creates a new [`Clipboard`] for the given window. + pub fn connect(_window: &winit::window::Window) -> Clipboard { + Clipboard + } + + /// Reads the current content of the [`Clipboard`] as text. + pub fn read(&self) -> Option<String> { + None + } + + /// Writes the given text contents to the [`Clipboard`]. + pub fn write(&mut self, _contents: String) {} +} + +/// A buffer for short-term storage and transfer within and between +/// applications. +#[allow(missing_debug_implementations)] +#[cfg(not(target_arch = "wasm32"))] pub struct Clipboard { state: State, } +#[cfg(not(target_arch = "wasm32"))] enum State { Connected(window_clipboard::Clipboard), Unavailable, } +#[cfg(not(target_arch = "wasm32"))] impl Clipboard { /// Creates a new [`Clipboard`] for the given window. pub fn connect(window: &winit::window::Window) -> Clipboard { |