windows: Improve foreground task dispatching on Windows (#23283)
Closes #22653 After some investigation, I found this bug is due to that sometimes `foreground_task` is not dispatched to the main thread unless there is user input. The current Windows implementation works as follows: when the `WindowsDispatcher` receives a `foreground_task`, it adds the task to a queue and uses `SetEvent(dispatch_event)` to notify the main thread. The main thread then listens for notifications using `MsgWaitForMultipleObjects(&[dispatch_event])`. Essentially, this is a synchronous method, but it is not robust. For example, if 100 `foreground_task`s are sent, `dispatch_event` should theoretically be triggered 100 times, and `MsgWaitForMultipleObjects(&[dispatch_event])` should receive 100 notifications, causing the main thread to execute all 100 tasks. However, in practice, some `foreground_task`s may not get a chance to execute due to certain reasons. As shown in the attached video, when I don't move the mouse, there are about 20-30 `foreground_task`s waiting in the queue to be executed. When I move the mouse, `run_foreground_tasks()` is called, which processes the tasks in the queue. https://github.com/user-attachments/assets/83cd09ca-4b17-4a1f-9a2a-5d1569b23483 To address this, this PR adopts an approach similar to `winit`. In `winit`, an invisible window is created for message passing. In this PR, we use `PostThreadMessage` to directly send messages to the main thread. With this implementation, when 100 `foreground_task`s are sent, the `WindowsDispatcher` uses `PostThreadMessageW(thread_id, RUNNABLE_DISPATCHED)` to notify the main thread. This approach enqueues 100 `RUNNABLE_DISPATCHED` messages in the main thread's message queue, ensuring that each `foreground_task` is executed as expected. The main thread continuously processes these messages, guaranteeing that all 100 tasks are executed. Release Notes: - N/A
This commit is contained in:
parent
5138e6a3c7
commit
728a874b1e
4 changed files with 110 additions and 66 deletions
|
@ -16,8 +16,9 @@ use windows::Win32::{
|
|||
|
||||
use crate::*;
|
||||
|
||||
pub(crate) const CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;
|
||||
pub(crate) const CLOSE_ONE_WINDOW: u32 = WM_USER + 2;
|
||||
pub(crate) const WM_ZED_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;
|
||||
pub(crate) const WM_ZED_CLOSE_ONE_WINDOW: u32 = WM_USER + 2;
|
||||
pub(crate) const WM_ZED_EVENT_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3;
|
||||
|
||||
const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
|
||||
const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 1;
|
||||
|
@ -89,7 +90,7 @@ pub(crate) fn handle_msg(
|
|||
WM_SETCURSOR => handle_set_cursor(lparam, state_ptr),
|
||||
WM_SETTINGCHANGE => handle_system_settings_changed(handle, state_ptr),
|
||||
WM_DWMCOLORIZATIONCOLORCHANGED => handle_system_theme_changed(state_ptr),
|
||||
CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||
WM_ZED_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(n) = handled {
|
||||
|
@ -243,9 +244,9 @@ fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Opt
|
|||
callback();
|
||||
}
|
||||
unsafe {
|
||||
PostMessageW(
|
||||
None,
|
||||
CLOSE_ONE_WINDOW,
|
||||
PostThreadMessageW(
|
||||
state_ptr.main_thread_id_win32,
|
||||
WM_ZED_CLOSE_ONE_WINDOW,
|
||||
WPARAM(state_ptr.validation_number),
|
||||
LPARAM(handle.0 as isize),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue