From 28a50817aff48d3535ec92681206f788223ef693 Mon Sep 17 00:00:00 2001 From: Ryan G Date: Mon, 23 Sep 2019 09:14:26 -0400 Subject: [PATCH] Fix web redraw requested (#1181) * Keep track of what windows have requested redraw Instead of using request_animation_frame and sending redraw request events, just keep track of all windows that have asked for a redraw. This doesn't handle dispatching the events * Issue redraw events to windows that request it * Cargo fmt --- src/platform_impl/web/event_loop/runner.rs | 27 ++++++++++++++++++++-- src/platform_impl/web/stdweb/canvas.rs | 15 ++---------- src/platform_impl/web/web_sys/canvas.rs | 14 +---------- src/platform_impl/web/window.rs | 14 +++++------ 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index f704346e..b3889fad 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -1,9 +1,15 @@ use super::{backend, state::State}; -use crate::event::{Event, StartCause}; +use crate::event::{Event, StartCause, WindowEvent}; use crate::event_loop as root; +use crate::window::WindowId; use instant::{Duration, Instant}; -use std::{cell::RefCell, clone::Clone, collections::VecDeque, rc::Rc}; +use std::{ + cell::RefCell, + clone::Clone, + collections::{HashSet, VecDeque}, + rc::Rc, +}; pub struct Shared(Rc>); @@ -17,6 +23,7 @@ pub struct Execution { runner: RefCell>>, events: RefCell>>, id: RefCell, + redraw_pending: RefCell>, } struct Runner { @@ -41,6 +48,7 @@ impl Shared { runner: RefCell::new(None), events: RefCell::new(VecDeque::new()), id: RefCell::new(0), + redraw_pending: RefCell::new(HashSet::new()), })) } @@ -64,6 +72,10 @@ impl Shared { *id } + pub fn request_redraw(&self, id: WindowId) { + self.0.redraw_pending.borrow_mut().insert(id); + } + // Add an event to the event loop runner // // It will determine if the event should be immediately sent to the user or buffered for later @@ -115,6 +127,17 @@ impl Shared { if !event_is_start { self.handle_event(event, &mut control); } + // Collect all of the redraw events to avoid double-locking the RefCell + let redraw_events: Vec = self.0.redraw_pending.borrow_mut().drain().collect(); + for window_id in redraw_events { + self.handle_event( + Event::WindowEvent { + window_id, + event: WindowEvent::RedrawRequested, + }, + &mut control, + ); + } self.handle_event(Event::EventsCleared, &mut control); self.apply_control_flow(control); // If the event loop is closed, it has been closed this iteration and now the closing diff --git a/src/platform_impl/web/stdweb/canvas.rs b/src/platform_impl/web/stdweb/canvas.rs index cf670471..92e46bac 100644 --- a/src/platform_impl/web/stdweb/canvas.rs +++ b/src/platform_impl/web/stdweb/canvas.rs @@ -4,7 +4,6 @@ use crate::error::OsError as RootOE; use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; use crate::platform_impl::OsError; -use std::rc::Rc; use stdweb::traits::IPointerEvent; use stdweb::unstable::TryInto; use stdweb::web::event::{ @@ -13,12 +12,11 @@ use stdweb::web::event::{ }; use stdweb::web::html_element::CanvasElement; use stdweb::web::{ - document, window, EventListenerHandle, IChildNode, IElement, IEventTarget, IHtmlElement, + document, EventListenerHandle, IChildNode, IElement, IEventTarget, IHtmlElement, }; pub struct Canvas { raw: CanvasElement, - on_redraw: Rc, on_focus: Option, on_blur: Option, on_keyboard_release: Option, @@ -39,10 +37,7 @@ impl Drop for Canvas { } impl Canvas { - pub fn create(on_redraw: F) -> Result - where - F: 'static + Fn(), - { + pub fn create() -> Result { let canvas: CanvasElement = document() .create_element("canvas") .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? @@ -60,7 +55,6 @@ impl Canvas { Ok(Canvas { raw: canvas, - on_redraw: Rc::new(on_redraw), on_blur: None, on_focus: None, on_keyboard_release: None, @@ -104,11 +98,6 @@ impl Canvas { &self.raw } - pub fn request_redraw(&self) { - let on_redraw = self.on_redraw.clone(); - window().request_animation_frame(move |_| on_redraw()); - } - pub fn on_blur(&mut self, mut handler: F) where F: 'static + FnMut(), diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 39a17e5b..bcf6ce4a 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -9,7 +9,6 @@ use web_sys::{FocusEvent, HtmlCanvasElement, KeyboardEvent, PointerEvent, WheelE pub struct Canvas { raw: HtmlCanvasElement, - on_redraw: Closure, on_focus: Option>, on_blur: Option>, on_keyboard_release: Option>, @@ -30,10 +29,7 @@ impl Drop for Canvas { } impl Canvas { - pub fn create(on_redraw: F) -> Result - where - F: 'static + Fn(), - { + pub fn create() -> Result { let window = web_sys::window().ok_or(os_error!(OsError("Failed to obtain window".to_owned())))?; @@ -57,7 +53,6 @@ impl Canvas { Ok(Canvas { raw: canvas, - on_redraw: Closure::wrap(Box::new(on_redraw) as Box), on_blur: None, on_focus: None, on_keyboard_release: None, @@ -101,13 +96,6 @@ impl Canvas { &self.raw } - pub fn request_redraw(&self) { - let window = web_sys::window().expect("Failed to obtain window"); - window - .request_animation_frame(&self.on_redraw.as_ref().unchecked_ref()) - .expect("Failed to request animation frame"); - } - pub fn on_blur(&mut self, mut handler: F) where F: 'static + FnMut(), diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index be9a9082..5a14c6db 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -1,6 +1,5 @@ use crate::dpi::{LogicalPosition, LogicalSize}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOE}; -use crate::event::{Event, WindowEvent}; use crate::icon::Icon; use crate::monitor::MonitorHandle as RootMH; use crate::window::{CursorIcon, WindowAttributes, WindowId as RootWI}; @@ -16,6 +15,7 @@ pub struct Window { previous_pointer: RefCell<&'static str>, position: RefCell, id: Id, + register_redraw_request: Box, } impl Window { @@ -28,12 +28,9 @@ impl Window { let id = target.generate_id(); - let mut canvas = backend::Canvas::create(move || { - runner.send_event(Event::WindowEvent { - window_id: RootWI(id), - event: WindowEvent::RedrawRequested, - }) - })?; + let mut canvas = backend::Canvas::create()?; + + let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id))); target.register(&mut canvas, id); @@ -42,6 +39,7 @@ impl Window { previous_pointer: RefCell::new("auto"), position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }), id, + register_redraw_request, }; window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize { @@ -69,7 +67,7 @@ impl Window { } pub fn request_redraw(&self) { - self.canvas.request_redraw(); + (self.register_redraw_request)(); } pub fn outer_position(&self) -> Result {