mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Use Window.requestIdleCallback()
This commit is contained in:
parent
a444637b18
commit
7ce86c3d2a
|
@ -78,6 +78,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- On Web, fix the bfcache by not using the `beforeunload` event.
|
- On Web, fix the bfcache by not using the `beforeunload` event.
|
||||||
- On Web, fix scale factor resize suggestion always overwriting the canvas size.
|
- On Web, fix scale factor resize suggestion always overwriting the canvas size.
|
||||||
- On macOS, fix crash when dropping `Window`.
|
- On macOS, fix crash when dropping `Window`.
|
||||||
|
- On Web, use `Window.requestIdleCallback()` for `ControlFlow::Poll` when available.
|
||||||
|
|
||||||
# 0.28.6
|
# 0.28.6
|
||||||
|
|
||||||
|
|
|
@ -158,13 +158,6 @@ impl<T> fmt::Debug for EventLoopWindowTarget<T> {
|
||||||
pub enum ControlFlow {
|
pub enum ControlFlow {
|
||||||
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
||||||
/// whether or not new events are available to process.
|
/// whether or not new events are available to process.
|
||||||
///
|
|
||||||
/// ## Platform-specific
|
|
||||||
///
|
|
||||||
/// - **Web:** Events are queued and usually sent when `requestAnimationFrame` fires but sometimes
|
|
||||||
/// the events in the queue may be sent before the next `requestAnimationFrame` callback, for
|
|
||||||
/// example when the scaling of the page has changed. This should be treated as an implementation
|
|
||||||
/// detail which should not be relied on.
|
|
||||||
Poll,
|
Poll,
|
||||||
|
|
||||||
/// When the current loop iteration finishes, suspend the thread until another event arrives.
|
/// When the current loop iteration finishes, suspend the thread until another event arrives.
|
||||||
|
|
|
@ -442,10 +442,9 @@ impl<T: 'static> Shared<T> {
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
let cloned = self.clone();
|
let cloned = self.clone();
|
||||||
State::Poll {
|
State::Poll {
|
||||||
request: backend::AnimationFrameRequest::new(
|
request: backend::IdleCallback::new(self.window().clone(), move || {
|
||||||
self.window().clone(),
|
cloned.poll()
|
||||||
move || cloned.poll(),
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlFlow::Wait => State::Wait {
|
ControlFlow::Wait => State::Wait {
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub enum State {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
},
|
},
|
||||||
Poll {
|
Poll {
|
||||||
request: backend::AnimationFrameRequest,
|
request: backend::IdleCallback,
|
||||||
},
|
},
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ mod timeout;
|
||||||
pub use self::canvas::Canvas;
|
pub use self::canvas::Canvas;
|
||||||
pub use self::event::ButtonsState;
|
pub use self::event::ButtonsState;
|
||||||
pub use self::scaling::ScaleChangeDetector;
|
pub use self::scaling::ScaleChangeDetector;
|
||||||
pub use self::timeout::{AnimationFrameRequest, Timeout};
|
pub use self::timeout::{IdleCallback, Timeout};
|
||||||
|
|
||||||
use crate::dpi::{LogicalSize, Size};
|
use crate::dpi::{LogicalSize, Size};
|
||||||
use crate::platform::web::WindowExtWebSys;
|
use crate::platform::web::WindowExtWebSys;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
use once_cell::unsync::OnceCell;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_bindgen::closure::Closure;
|
use wasm_bindgen::closure::Closure;
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Timeout {
|
pub struct Timeout {
|
||||||
|
@ -40,16 +43,21 @@ impl Drop for Timeout {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnimationFrameRequest {
|
pub struct IdleCallback {
|
||||||
window: web_sys::Window,
|
window: web_sys::Window,
|
||||||
handle: i32,
|
handle: Handle,
|
||||||
// track callback state, because `cancelAnimationFrame` is slow
|
|
||||||
fired: Rc<Cell<bool>>,
|
fired: Rc<Cell<bool>>,
|
||||||
_closure: Closure<dyn FnMut()>,
|
_closure: Closure<dyn FnMut()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnimationFrameRequest {
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub fn new<F>(window: web_sys::Window, mut f: F) -> AnimationFrameRequest
|
enum Handle {
|
||||||
|
IdleCallback(u32),
|
||||||
|
Timeout(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdleCallback {
|
||||||
|
pub fn new<F>(window: web_sys::Window, mut f: F) -> IdleCallback
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(),
|
F: 'static + FnMut(),
|
||||||
{
|
{
|
||||||
|
@ -60,11 +68,21 @@ impl AnimationFrameRequest {
|
||||||
f();
|
f();
|
||||||
}) as Box<dyn FnMut()>);
|
}) as Box<dyn FnMut()>);
|
||||||
|
|
||||||
let handle = window
|
let handle = if has_idle_callback_support(&window) {
|
||||||
.request_animation_frame(closure.as_ref().unchecked_ref())
|
Handle::IdleCallback(
|
||||||
.expect("Failed to request animation frame");
|
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"),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
AnimationFrameRequest {
|
IdleCallback {
|
||||||
window,
|
window,
|
||||||
handle,
|
handle,
|
||||||
fired,
|
fired,
|
||||||
|
@ -73,12 +91,34 @@ impl AnimationFrameRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AnimationFrameRequest {
|
impl Drop for IdleCallback {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !(*self.fired).get() {
|
if !(*self.fired).get() {
|
||||||
self.window
|
match self.handle {
|
||||||
.cancel_animation_frame(self.handle)
|
Handle::IdleCallback(handle) => self.window.cancel_idle_callback(handle),
|
||||||
.expect("Failed to cancel animation frame");
|
Handle::Timeout(handle) => self.window.clear_timeout_with_handle(handle),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue