From e87bc3db20d7b7e8b2d717e386ea7e685cdd7853 Mon Sep 17 00:00:00 2001 From: Ryan G Date: Wed, 11 Sep 2019 11:47:03 -0400 Subject: [PATCH] Send a LoopDestroyed event when the browser is closed (#1155) * Add the plumbing for handling browser closes * Implement the business logic for handling closes --- Cargo.toml | 1 + src/platform_impl/web/event_loop/runner.rs | 9 +++++++++ src/platform_impl/web/stdweb/mod.rs | 7 +++++++ src/platform_impl/web/web_sys/mod.rs | 15 ++++++++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8617f5ec..814d6777 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ version = "0.3.22" optional = true features = [ 'console', + 'BeforeUnloadEvent', 'Document', 'DomRect', 'Element', diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index c5bb274b..cadd1dcd 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -48,6 +48,9 @@ impl Shared { pub fn set_listener(&self, event_handler: Box, &mut root::ControlFlow)>) { self.0.runner.replace(Some(Runner::new(event_handler))); self.send_event(Event::NewEvents(StartCause::Init)); + + let close_instance = self.clone(); + backend::on_unload(move || close_instance.handle_unload()); } // Add an event to the event loop runner @@ -110,6 +113,12 @@ impl Shared { } } + fn handle_unload(&self) { + self.apply_control_flow(root::ControlFlow::Exit); + let mut control = self.current_control_flow(); + self.handle_event(Event::LoopDestroyed, &mut control); + } + // handle_event takes in events and either queues them or applies a callback // // It should only ever be called from send_event diff --git a/src/platform_impl/web/stdweb/mod.rs b/src/platform_impl/web/stdweb/mod.rs index 87058b70..f7caa232 100644 --- a/src/platform_impl/web/stdweb/mod.rs +++ b/src/platform_impl/web/stdweb/mod.rs @@ -9,12 +9,19 @@ use crate::platform::web::WindowExtStdweb; use crate::window::Window; use stdweb::js; +use stdweb::web::event::BeforeUnloadEvent; use stdweb::web::html_element::CanvasElement; +use stdweb::web::window; +use stdweb::web::IEventTarget; pub fn throw(msg: &str) { js! { throw @{msg} } } +pub fn on_unload(mut handler: impl FnMut() + 'static) { + window().add_event_listener(move |_: BeforeUnloadEvent| handler()); +} + impl WindowExtStdweb for Window { fn canvas(&self) -> CanvasElement { self.window.canvas().raw().clone() diff --git a/src/platform_impl/web/web_sys/mod.rs b/src/platform_impl/web/web_sys/mod.rs index 33e217bd..811b6f68 100644 --- a/src/platform_impl/web/web_sys/mod.rs +++ b/src/platform_impl/web/web_sys/mod.rs @@ -7,12 +7,25 @@ pub use self::timeout::Timeout; use crate::platform::web::WindowExtWebSys; use crate::window::Window; -use web_sys::HtmlCanvasElement; +use wasm_bindgen::{closure::Closure, JsCast}; +use web_sys::{BeforeUnloadEvent, HtmlCanvasElement}; pub fn throw(msg: &str) { wasm_bindgen::throw_str(msg); } +pub fn on_unload(mut handler: impl FnMut() + 'static) { + let window = web_sys::window().expect("Failed to obtain window"); + + let closure = Closure::wrap( + Box::new(move |_: BeforeUnloadEvent| handler()) as Box + ); + + window + .add_event_listener_with_callback("beforeunload", &closure.as_ref().unchecked_ref()) + .expect("Failed to add close listener"); +} + impl WindowExtWebSys for Window { fn canvas(&self) -> HtmlCanvasElement { self.window.canvas().raw().clone()