ensure app is idle

This commit is contained in:
Junkui Zhang 2025-07-23 23:28:05 +08:00
parent 63daf44693
commit 6964cecc14
4 changed files with 23 additions and 8 deletions

View file

@ -479,7 +479,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
fn zoom(&self); fn zoom(&self);
fn toggle_fullscreen(&self); fn toggle_fullscreen(&self);
fn is_fullscreen(&self) -> bool; fn is_fullscreen(&self) -> bool;
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>); fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions) -> bool>);
fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>); fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> DispatchEventResult>);
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>); fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);
fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>); fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>);

View file

@ -237,12 +237,23 @@ fn handle_timer_msg(
fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> { fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
let mut lock = state_ptr.state.borrow_mut(); let mut lock = state_ptr.state.borrow_mut();
if let Some(mut request_frame) = lock.callbacks.request_frame.take() { let is_idle = if let Some(mut request_frame) = lock.callbacks.request_frame.take() {
drop(lock); drop(lock);
request_frame(Default::default()); // request_frame(RequestFrameOptions {
// require_presentation: true,
// });
let is_idle = request_frame(Default::default());
state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame); state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
} is_idle
} else {
false
};
unsafe { ValidateRect(Some(handle), None).ok().log_err() }; unsafe { ValidateRect(Some(handle), None).ok().log_err() };
if is_idle {
unsafe {
MsgWaitForMultipleObjects(None, false, 100, QS_ALLINPUT);
}
}
Some(0) Some(0)
} }

View file

@ -38,7 +38,7 @@ pub struct WindowsWindowState {
pub border_offset: WindowBorderOffset, pub border_offset: WindowBorderOffset,
pub appearance: WindowAppearance, pub appearance: WindowAppearance,
pub scale_factor: f32, pub scale_factor: f32,
pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>, pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions) -> bool>>,
pub callbacks: Callbacks, pub callbacks: Callbacks,
pub input_handler: Option<PlatformInputHandler>, pub input_handler: Option<PlatformInputHandler>,
@ -312,7 +312,7 @@ impl WindowsWindowStatePtr {
#[derive(Default)] #[derive(Default)]
pub(crate) struct Callbacks { pub(crate) struct Callbacks {
pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>, pub(crate) request_frame: Option<Box<dyn FnMut(RequestFrameOptions) -> bool>>,
pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>, pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>, pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>, pub(crate) hovered_status_change: Option<Box<dyn FnMut(bool)>>,
@ -734,7 +734,7 @@ impl PlatformWindow for WindowsWindow {
self.0.state.borrow().is_fullscreen() self.0.state.borrow().is_fullscreen()
} }
fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) { fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions) -> bool>) {
self.0.state.borrow_mut().callbacks.request_frame = Some(callback); self.0.state.borrow_mut().callbacks.request_frame = Some(callback);
} }

View file

@ -1012,6 +1012,7 @@ impl Window {
.log_err(); .log_err();
} }
let invalidator_is_dirty = invalidator.is_dirty();
// Keep presenting the current scene for 1 extra second since the // Keep presenting the current scene for 1 extra second since the
// last input to prevent the display from underclocking the refresh rate. // last input to prevent the display from underclocking the refresh rate.
let needs_present = request_frame_options.require_presentation let needs_present = request_frame_options.require_presentation
@ -1019,7 +1020,7 @@ impl Window {
|| (active.get() || (active.get()
&& last_input_timestamp.get().elapsed() < Duration::from_secs(1)); && last_input_timestamp.get().elapsed() < Duration::from_secs(1));
if invalidator.is_dirty() { if invalidator_is_dirty {
measure("frame duration", || { measure("frame duration", || {
handle handle
.update(&mut cx, |_, window, cx| { .update(&mut cx, |_, window, cx| {
@ -1041,6 +1042,9 @@ impl Window {
window.complete_frame(); window.complete_frame();
}) })
.log_err(); .log_err();
// Return true if app is idle
!(invalidator_is_dirty || needs_present)
} }
})); }));
platform_window.on_resize(Box::new({ platform_window.on_resize(Box::new({