Skip to content

Commit

Permalink
fixes, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
enomado committed Jul 22, 2022
1 parent c5e0bb3 commit 714e3d1
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 32 deletions.
22 changes: 20 additions & 2 deletions eframe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ use web::AppRunner;
#[cfg(target_arch = "wasm32")]
pub use web_sys;

#[cfg(target_arch = "wasm32")]
use arc_swap::ArcSwapOption;

#[cfg(target_arch = "wasm32")]
#[allow(unsafe_code)]
unsafe impl Send for AppRunner {}

#[cfg(target_arch = "wasm32")]
#[allow(unsafe_code)]
unsafe impl Sync for AppRunner {}

#[cfg(target_arch = "wasm32")]
static GLOBAL_HANDLE: ArcSwapOption<Mutex<AppRunner>> = ArcSwapOption::const_empty();

/// Install event listeners to register different input events
/// and start running the given app.
///
Expand All @@ -98,8 +112,9 @@ pub use web_sys;
/// use wasm_bindgen::prelude::*;
///
/// /// This is the entry-point for all the web-assembly.
/// /// This is called once from the HTML.
/// /// This is called from the HTML.
/// /// It loads the app, installs some callbacks, then returns.
/// /// It creates singleton app-handle that could be stopped calling `stop_web`
/// /// You can add more callbacks like this if you want to call in to your code.
/// #[cfg(target_arch = "wasm32")]
/// #[wasm_bindgen]
Expand Down Expand Up @@ -128,10 +143,13 @@ pub fn start_web(canvas_id: &str, web_options: WebOptions, app_creator: AppCreat
Ok(())
}

/// Stop all event listeners, created by start_web.
/// /// `start_web` could be called again after calling this.
/// /// It aims to destroy all Arc's to `AppRunner` to not cause memory leak in start/stop cycless
#[cfg(target_arch = "wasm32")]
pub fn stop_web() -> Result<(), wasm_bindgen::JsValue> {
if let Some(app_runner) = GLOBAL_HANDLE.load_full() {
uu.lock().destroy();
app_runner.lock().destroy()?;

GLOBAL_HANDLE.store(None);

Expand Down
79 changes: 49 additions & 30 deletions eframe/src/web/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ use super::{glow_wrapping::WrappedGlowPainter, *};

use crate::epi;

use egui::mutex::{Mutex, MutexGuard};
use egui::TexturesDelta;

pub use egui::{pos2, Color32};

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -36,38 +34,24 @@ impl WebInput {

use std::sync::atomic::Ordering::SeqCst;

/// Stores when to do the next repaint.
pub struct NeedRepaint(Mutex<f64>);
pub struct NeedRepaint(std::sync::atomic::AtomicBool);

impl Default for NeedRepaint {
fn default() -> Self {
Self(Mutex::new(f64::NEG_INFINITY)) // start with a repaint
Self(true.into())
}
}

impl NeedRepaint {
/// Returns the time (in [`now_sec`] scale) when
/// we should next repaint.
pub fn when_to_repaint(&self) -> f64 {
*self.0.lock()
}

/// Unschedule repainting.
pub fn clear(&self) {
*self.0.lock() = f64::INFINITY;
pub fn fetch_and_clear(&self) -> bool {
self.0.swap(false, SeqCst)
}

pub fn repaint_after(&self, num_seconds: f64) {
let mut repaint_time = self.0.lock();
*repaint_time = repaint_time.min(now_sec() + num_seconds);
}

pub fn repaint_asap(&self) {
*self.0.lock() = f64::NEG_INFINITY;
pub fn set_true(&self) {
self.0.store(true, SeqCst);
}
}


pub struct IsDestroyed(std::sync::atomic::AtomicBool);

impl Default for IsDestroyed {
Expand Down Expand Up @@ -238,7 +222,7 @@ impl AppRunner {
{
let needs_repaint = needs_repaint.clone();
egui_ctx.set_request_repaint_callback(move || {
needs_repaint.repaint_asap();
needs_repaint.0.store(true, SeqCst);
});
}

Expand Down Expand Up @@ -297,15 +281,16 @@ impl AppRunner {
Ok(())
}

pub fn destroy(&mut self) {
pub fn destroy(&mut self) -> Result<(), JsValue> {
tracing::debug!("destroying...");

self.events_to_unsubscribe
.drain(..)
.for_each(|x| x.unsubscribe());
for x in self.events_to_unsubscribe.drain(..) {
x.unsubscribe()?;
}

self.painter.destroy();
self.is_destroyed.set_true();
Ok(())
}

/// Returns how long to wait until the next repaint.
Expand Down Expand Up @@ -408,11 +393,48 @@ impl AppRunner {

pub type AppRunnerRef = Arc<Mutex<AppRunner>>;

pub struct TargetEvent {
target: EventTarget,
event_name: String,
closure: Closure<dyn FnMut(web_sys::Event)>,
}

pub struct RepetitativeHandle {
pub handle: i32,
pub closure: Closure<dyn FnMut()>,
}

pub enum EventToUnsubscribe {
TargetEvent(TargetEvent),
RepititativeHandle(RepetitativeHandle),
}

impl EventToUnsubscribe {
pub fn unsubscribe(self) -> Result<(), JsValue> {
use wasm_bindgen::JsCast;

match self {
EventToUnsubscribe::TargetEvent(handle) => {
handle.target.remove_event_listener_with_callback(
handle.event_name.as_str(),
handle.closure.as_ref().unchecked_ref(),
)?;
Ok(())
}
EventToUnsubscribe::RepititativeHandle(handle) => {
let window = web_sys::window().unwrap();
window.clear_interval_with_handle(handle.handle);
Ok(())
}
}
}
}
pub struct AppRunnerContainer {
pub runner: AppRunnerRef,
/// Set to `true` if there is a panic.
/// Used to ignore callbacks after a panic.
pub panicked: Arc<AtomicBool>,
pub events: Vec<EventToUnsubscribe>,
}

impl AppRunnerContainer {
Expand Down Expand Up @@ -457,9 +479,6 @@ impl AppRunnerContainer {

self.events.push(EventToUnsubscribe::TargetEvent(handle));

// Bypass closure drop so that event handler can call the closure
// closure.forget();

Ok(())
}
}
Expand Down

0 comments on commit 714e3d1

Please sign in to comment.