Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions crates/gpui_windows/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5;
pub(crate) const WM_GPUI_KEYBOARD_LAYOUT_CHANGED: u32 = WM_USER + 6;
pub(crate) const WM_GPUI_GPU_DEVICE_LOST: u32 = WM_USER + 7;
pub(crate) const WM_GPUI_KEYDOWN: u32 = WM_USER + 8;
pub(crate) const WM_GPUI_VSYNC_FRAME: u32 = WM_USER + 9;

const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;

Expand Down Expand Up @@ -158,6 +159,7 @@ impl WindowsWindowInner {
WM_SHOWWINDOW => self.handle_window_visibility_changed(handle, wparam),
WM_GPUI_CURSOR_STYLE_CHANGED => self.handle_cursor_changed(lparam),
WM_GPUI_FORCE_UPDATE_WINDOW => self.draw_window(handle, true),
WM_GPUI_VSYNC_FRAME => self.handle_vsync_frame(handle),
WM_GPUI_GPU_DEVICE_LOST => self.handle_device_lost(lparam),
DM_POINTERHITTEST => self.handle_dm_pointer_hit_test(wparam),
WM_GETOBJECT => self.handle_wm_getobject(wparam, lparam),
Expand Down Expand Up @@ -312,6 +314,34 @@ impl WindowsWindowInner {
self.draw_window(handle, false)
}

/// Deliver the frame the vsync thread invalidated.
///
/// `WM_PAINT` is synthesized rather than queued. The thread only receives one
/// once its queue holds nothing else, so sustained input (a high-polling mouse,
/// a held key) starves it and frames stop reaching the display. A posted message
/// queues behind that input instead of losing to it, and `UpdateWindow` then
/// delivers the pending paint directly.
///
/// Queued duplicates are dropped first, otherwise a window that can't keep up
/// with the refresh rate would accumulate them faster than it retires them,
/// since the vsync thread re-invalidates before the previous frame is done.
fn handle_vsync_frame(&self, handle: HWND) -> Option<isize> {
unsafe {
let mut msg = MSG::default();
while PeekMessageW(
&mut msg,
Some(handle),
WM_GPUI_VSYNC_FRAME,
WM_GPUI_VSYNC_FRAME,
PM_REMOVE,
)
.as_bool()
{}
UpdateWindow(handle).ok().log_err();
}
Some(0)
}

fn handle_close_msg(&self) -> Option<isize> {
let mut callback = self.state.callbacks.should_close.take()?;
let should_close = callback();
Expand Down
10 changes: 10 additions & 0 deletions crates/gpui_windows/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,16 @@ impl WindowsPlatform {
for hwnd in all_windows.read().iter() {
unsafe {
let _ = RedrawWindow(Some(hwnd.as_raw()), None, None, RDW_INVALIDATE);
// `WM_PAINT` is synthesized only once the target
// thread's queue is empty, so high-rate input
// starves it. Post a message too, which queues
// behind that input. See `handle_vsync_frame`.
let _ = PostMessageW(
Some(hwnd.as_raw()),
WM_GPUI_VSYNC_FRAME,
WPARAM(0),
LPARAM(0),
);
}
}
}
Expand Down