Skip to content

Commit

Permalink
use ResizeObserver instead of resize event
Browse files Browse the repository at this point in the history
  • Loading branch information
jprochazk committed May 24, 2024
1 parent a98c42e commit 9c1d0f5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
3 changes: 3 additions & 0 deletions crates/eframe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ web-sys = { workspace = true, features = [
"MouseEvent",
"Navigator",
"Performance",
"ResizeObserver",
"ResizeObserverBoxOptions",
"ResizeObserverOptions",
"Storage",
"Touch",
"TouchEvent",
Expand Down
43 changes: 42 additions & 1 deletion crates/eframe/src/web/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ pub(crate) fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValu
runner.save();
})?;

for event_name in &["load", "pagehide", "pageshow", "resize"] {
// NOTE: resize is handled by `ResizeObserver` below
for event_name in &["load", "pagehide", "pageshow"] {
runner_ref.add_event_listener(&window, event_name, move |_: web_sys::Event, runner| {
// log::debug!("{event_name:?}");
runner.needs_repaint.repaint_asap();
Expand Down Expand Up @@ -590,3 +591,43 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu

Ok(())
}

trait JsValueExt {
fn get(&self, key: &str) -> Result<JsValue, JsValue>;
fn at(&self, idx: usize) -> Result<JsValue, JsValue>;
fn has(&self, key: &str) -> Result<bool, JsValue>;
}

impl JsValueExt for JsValue {
fn get(&self, key: &str) -> Result<JsValue, JsValue> {
js_sys::Reflect::get(self, &JsValue::from_str(key))
}

fn at(&self, idx: usize) -> Result<JsValue, JsValue> {
js_sys::Reflect::get(self, &JsValue::from_f64(idx as f64))
}

fn has(&self, key: &str) -> Result<bool, JsValue> {
js_sys::Reflect::has(self, &JsValue::from_str(key))
}
}

pub(crate) fn install_resize_observer(runner_ref: &WebRunner) -> Result<(), JsValue> {
let closure = Closure::wrap(Box::new({
let runner_ref = runner_ref.clone();
move |entries: js_sys::Array| {
// Only call the wrapped closure if the egui code has not panicked
if let Some(mut runner_lock) = runner_ref.try_lock() {
runner_lock.needs_repaint.repaint_asap();
}
}
}) as Box<dyn FnMut(js_sys::Array)>);

let observer = web_sys::ResizeObserver::new(closure.as_ref().unchecked_ref())?;
let mut options = web_sys::ResizeObserverOptions::new();
options.box_(web_sys::ResizeObserverBoxOptions::ContentBox);
observer.observe_with_options(runner_ref.try_lock().unwrap().canvas(), &options);
runner_ref.set_resize_observer(observer, closure);

Ok(())
}
25 changes: 25 additions & 0 deletions crates/eframe/src/web/web_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct WebRunner {

/// Used in `destroy` to cancel a pending frame.
request_animation_frame_id: Cell<Option<i32>>,

resize_observer: Rc<RefCell<Option<ResizeObserverContext>>>,
}

impl WebRunner {
Expand All @@ -48,6 +50,7 @@ impl WebRunner {
runner: Rc::new(RefCell::new(None)),
events_to_unsubscribe: Rc::new(RefCell::new(Default::default())),
request_animation_frame_id: Cell::new(None),
resize_observer: Default::default(),
}
}

Expand Down Expand Up @@ -78,6 +81,8 @@ impl WebRunner {
events::install_color_scheme_change_event(self)?;
}

events::install_resize_observer(self)?;

self.request_animation_frame()?;
}

Expand Down Expand Up @@ -109,6 +114,11 @@ impl WebRunner {
}
}
}

if let Some(context) = self.resize_observer.take() {
context.observer.disconnect();
drop(context.closure);
}
}

/// Shut down eframe and clean up resources.
Expand Down Expand Up @@ -203,10 +213,25 @@ impl WebRunner {
closure.forget(); // We must forget it, or else the callback is canceled on drop
Ok(())
}

pub(crate) fn set_resize_observer(
&self,
observer: web_sys::ResizeObserver,
closure: Closure<dyn FnMut(js_sys::Array)>,
) {
self.resize_observer
.borrow_mut()
.replace(ResizeObserverContext { observer, closure });
}
}

// ----------------------------------------------------------------------------

struct ResizeObserverContext {
observer: web_sys::ResizeObserver,
closure: Closure<dyn FnMut(js_sys::Array)>,
}

struct TargetEvent {
target: web_sys::EventTarget,
event_name: String,
Expand Down

0 comments on commit 9c1d0f5

Please sign in to comment.