Add cleanup code to web backend, mostly web-sys (#1715)
* web-sys: Impl. event listeners removal for canvas * web-sys: Impl. media query listeners cleanup * web: Emit WindowEvent::Destroyed after Window is dropped * web-sys: Fix unload event closure being dropped early * web: Impl. cleanup on ControlFlow::Exit - Drops the Runner, which causes the event handler closure to be dropped. - (web-sys only:) Remove event listeners from DOM. * web: Do not remove canvas from DOM when dropping Window The canvas was inserted by the user, so it should be up to the user whether the canvas should be removed. * Update changelog
This commit is contained in:
parent
1c97a310b1
commit
47e7aa4209
13 changed files with 436 additions and 162 deletions
|
|
@ -1,8 +1,9 @@
|
|||
use super::super::ScaleChangeArgs;
|
||||
use super::media_query_handle::MediaQueryListHandle;
|
||||
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use wasm_bindgen::{prelude::Closure, JsCast};
|
||||
use web_sys::{MediaQueryList, MediaQueryListEvent};
|
||||
use wasm_bindgen::prelude::Closure;
|
||||
use web_sys::MediaQueryListEvent;
|
||||
|
||||
pub struct ScaleChangeDetector(Rc<RefCell<ScaleChangeDetectorInternal>>);
|
||||
|
||||
|
|
@ -19,8 +20,7 @@ impl ScaleChangeDetector {
|
|||
/// changes of the `devicePixelRatio`.
|
||||
struct ScaleChangeDetectorInternal {
|
||||
callback: Box<dyn FnMut(ScaleChangeArgs)>,
|
||||
closure: Option<Closure<dyn FnMut(MediaQueryListEvent)>>,
|
||||
mql: Option<MediaQueryList>,
|
||||
mql: Option<MediaQueryListHandle>,
|
||||
last_scale: f64,
|
||||
}
|
||||
|
||||
|
|
@ -32,27 +32,28 @@ impl ScaleChangeDetectorInternal {
|
|||
let current_scale = super::scale_factor();
|
||||
let new_self = Rc::new(RefCell::new(Self {
|
||||
callback: Box::new(handler),
|
||||
closure: None,
|
||||
mql: None,
|
||||
last_scale: current_scale,
|
||||
}));
|
||||
|
||||
let cloned_self = new_self.clone();
|
||||
let weak_self = Rc::downgrade(&new_self);
|
||||
let closure = Closure::wrap(Box::new(move |event: MediaQueryListEvent| {
|
||||
cloned_self.borrow_mut().handler(event)
|
||||
if let Some(rc_self) = weak_self.upgrade() {
|
||||
rc_self.borrow_mut().handler(event);
|
||||
}
|
||||
}) as Box<dyn FnMut(_)>);
|
||||
|
||||
let mql = Self::create_mql(&closure);
|
||||
let mql = Self::create_mql(closure);
|
||||
{
|
||||
let mut borrowed_self = new_self.borrow_mut();
|
||||
borrowed_self.closure = Some(closure);
|
||||
borrowed_self.mql = mql;
|
||||
}
|
||||
new_self
|
||||
}
|
||||
|
||||
fn create_mql(closure: &Closure<dyn FnMut(MediaQueryListEvent)>) -> Option<MediaQueryList> {
|
||||
let window = web_sys::window().expect("Failed to obtain window");
|
||||
fn create_mql(
|
||||
closure: Closure<dyn FnMut(MediaQueryListEvent)>,
|
||||
) -> Option<MediaQueryListHandle> {
|
||||
let current_scale = super::scale_factor();
|
||||
// This media query initially matches the current `devicePixelRatio`.
|
||||
// We add 0.0001 to the lower and upper bounds such that it won't fail
|
||||
|
|
@ -62,30 +63,20 @@ impl ScaleChangeDetectorInternal {
|
|||
current_scale - 0.0001,
|
||||
current_scale + 0.0001,
|
||||
);
|
||||
window
|
||||
.match_media(&media_query)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|mql| {
|
||||
assert_eq!(mql.matches(), true);
|
||||
mql.add_listener_with_opt_callback(Some(&closure.as_ref().unchecked_ref()))
|
||||
.map(|_| mql)
|
||||
.ok()
|
||||
})
|
||||
let mql = MediaQueryListHandle::new(&media_query, closure);
|
||||
if let Some(mql) = &mql {
|
||||
assert_eq!(mql.mql().matches(), true);
|
||||
}
|
||||
mql
|
||||
}
|
||||
|
||||
fn handler(&mut self, event: MediaQueryListEvent) {
|
||||
assert_eq!(event.matches(), false);
|
||||
let closure = self
|
||||
.closure
|
||||
.as_ref()
|
||||
.expect("DevicePixelRatioChangeDetector::closure should not be None");
|
||||
let mql = self
|
||||
.mql
|
||||
.take()
|
||||
.expect("DevicePixelRatioChangeDetector::mql should not be None");
|
||||
mql.remove_listener_with_opt_callback(Some(closure.as_ref().unchecked_ref()))
|
||||
.expect("Failed to remove listener from MediaQueryList");
|
||||
let closure = mql.remove();
|
||||
let new_scale = super::scale_factor();
|
||||
(self.callback)(ScaleChangeArgs {
|
||||
old_scale: self.last_scale,
|
||||
|
|
@ -96,15 +87,3 @@ impl ScaleChangeDetectorInternal {
|
|||
self.last_scale = new_scale;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScaleChangeDetectorInternal {
|
||||
fn drop(&mut self) {
|
||||
match (self.closure.as_ref(), self.mql.as_ref()) {
|
||||
(Some(closure), Some(mql)) => {
|
||||
let _ =
|
||||
mql.remove_listener_with_opt_callback(Some(closure.as_ref().unchecked_ref()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue