winit/src/platform_impl/web/web_sys/timeout.rs

125 lines
3.2 KiB
Rust
Raw Normal View History

2023-06-13 16:39:06 +02:00
use once_cell::unsync::OnceCell;
use std::cell::Cell;
use std::rc::Rc;
2019-06-25 03:15:34 +02:00
use std::time::Duration;
use wasm_bindgen::closure::Closure;
2023-06-13 16:39:06 +02:00
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsCast;
2023-06-13 16:39:06 +02:00
use wasm_bindgen::JsValue;
2019-06-25 03:15:34 +02:00
#[derive(Debug)]
pub struct Timeout {
window: web_sys::Window,
handle: i32,
2019-07-01 20:23:42 +02:00
_closure: Closure<dyn FnMut()>,
}
2019-06-25 03:15:34 +02:00
impl Timeout {
pub fn new<F>(window: web_sys::Window, f: F, duration: Duration) -> Timeout
where
F: 'static + FnMut(),
{
let closure = Closure::wrap(Box::new(f) as Box<dyn FnMut()>);
let handle = window
.set_timeout_with_callback_and_timeout_and_arguments_0(
2022-06-10 13:43:33 +03:00
closure.as_ref().unchecked_ref(),
duration.as_millis() as i32,
)
.expect("Failed to set timeout");
Timeout {
window,
handle,
_closure: closure,
}
2019-06-25 03:15:34 +02:00
}
}
impl Drop for Timeout {
fn drop(&mut self) {
self.window.clear_timeout_with_handle(self.handle);
}
2019-06-25 03:15:34 +02:00
}
#[derive(Debug)]
2023-06-13 16:39:06 +02:00
pub struct IdleCallback {
window: web_sys::Window,
2023-06-13 16:39:06 +02:00
handle: Handle,
fired: Rc<Cell<bool>>,
_closure: Closure<dyn FnMut()>,
}
2023-06-13 16:39:06 +02:00
#[derive(Clone, Copy, Debug)]
enum Handle {
IdleCallback(u32),
Timeout(i32),
}
impl IdleCallback {
pub fn new<F>(window: web_sys::Window, mut f: F) -> IdleCallback
where
F: 'static + FnMut(),
{
let fired = Rc::new(Cell::new(false));
let c_fired = fired.clone();
let closure = Closure::wrap(Box::new(move || {
(*c_fired).set(true);
f();
}) as Box<dyn FnMut()>);
2023-06-13 16:39:06 +02:00
let handle = if has_idle_callback_support(&window) {
Handle::IdleCallback(
window
.request_idle_callback(closure.as_ref().unchecked_ref())
.expect("Failed to request idle callback"),
)
} else {
Handle::Timeout(
window
.set_timeout_with_callback(closure.as_ref().unchecked_ref())
.expect("Failed to set timeout"),
)
};
2023-06-13 16:39:06 +02:00
IdleCallback {
window,
handle,
fired,
_closure: closure,
}
}
}
2023-06-13 16:39:06 +02:00
impl Drop for IdleCallback {
fn drop(&mut self) {
if !(*self.fired).get() {
2023-06-13 16:39:06 +02:00
match self.handle {
Handle::IdleCallback(handle) => self.window.cancel_idle_callback(handle),
Handle::Timeout(handle) => self.window.clear_timeout_with_handle(handle),
}
}
}
}
2023-06-13 16:39:06 +02:00
fn has_idle_callback_support(window: &web_sys::Window) -> bool {
thread_local! {
static IDLE_CALLBACK_SUPPORT: OnceCell<bool> = OnceCell::new();
}
IDLE_CALLBACK_SUPPORT.with(|support| {
*support.get_or_init(|| {
#[wasm_bindgen]
extern "C" {
type IdleCallbackSupport;
#[wasm_bindgen(method, getter, js_name = requestIdleCallback)]
fn has_request_idle_callback(this: &IdleCallbackSupport) -> JsValue;
}
let support: &IdleCallbackSupport = window.unchecked_ref();
!support.has_request_idle_callback().is_undefined()
})
})
}