silkenweb_dom/
render.rs

1use std::cell::RefCell;
2
3use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
4
5use crate::window;
6
7pub fn queue_update(x: impl 'static + FnOnce()) {
8    let len = {
9        PENDING_UPDATES.with(|update_queue| {
10            let mut update_queue = update_queue.borrow_mut();
11
12            update_queue.push(Box::new(x));
13            update_queue.len()
14        })
15    };
16
17    if len == 1 {
18        request_render_updates();
19    }
20}
21
22/// Run a closure after the next render.
23pub fn after_render(x: impl 'static + FnOnce()) {
24    PENDING_EFFECTS.with(|pending_effects| pending_effects.borrow_mut().push(Box::new(x)));
25}
26
27/// Render any pending updates.
28///
29/// This is mostly useful for testing.
30pub fn render_updates() {
31    PENDING_UPDATES.with(|update_queue| {
32        let update_queue = update_queue.take();
33
34        for update in update_queue {
35            update();
36        }
37    });
38
39    PENDING_EFFECTS.with(|effect_queue| {
40        for effect in effect_queue.take() {
41            effect();
42        }
43    });
44}
45
46fn request_render_updates() {
47    ON_ANIMATION_FRAME.with(|process_updates| {
48        window()
49            .request_animation_frame(process_updates.as_ref().unchecked_ref())
50            .unwrap()
51    });
52}
53
54thread_local!(
55    static PENDING_UPDATES: RefCell<Vec<Box<dyn FnOnce()>>> = RefCell::new(Vec::new());
56    static PENDING_EFFECTS: RefCell<Vec<Box<dyn FnOnce()>>> = RefCell::new(Vec::new());
57    static ON_ANIMATION_FRAME: Closure<dyn FnMut(JsValue)> =
58        Closure::wrap(Box::new(move |_time_stamp: JsValue| {
59            render_updates();
60        }));
61);