@@ -18,12 +18,13 @@ use parking_lot::Mutex;
use time::UtcOffset;
use util::{ResultExt, SemanticVersion};
use windows::Win32::{
- Foundation::{CloseHandle, GetLastError, HANDLE, HWND, WAIT_EVENT},
- System::Threading::{CreateEventW, INFINITE},
+ Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
+ Graphics::DirectComposition::DCompositionWaitForCompositorClock,
+ System::Threading::{CreateEventW, GetCurrentThreadId, INFINITE},
UI::WindowsAndMessaging::{
- DispatchMessageW, GetMessageW, MsgWaitForMultipleObjects, PostQuitMessage,
- SystemParametersInfoW, TranslateMessage, MSG, QS_ALLINPUT, SPI_GETWHEELSCROLLCHARS,
- SPI_GETWHEELSCROLLLINES, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
+ DispatchMessageW, EnumThreadWindows, PeekMessageW, PostQuitMessage, SystemParametersInfoW,
+ TranslateMessage, MSG, PM_REMOVE, SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES,
+ SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
},
};
@@ -169,26 +170,31 @@ impl WindowsPlatform {
}
}
- fn wait_message(&self) -> WindowsMessageWaitResult {
- let wait_result = unsafe {
- MsgWaitForMultipleObjects(Some(&[self.inner.event]), false, INFINITE, QS_ALLINPUT)
- };
-
- match wait_result {
- WAIT_EVENT(0) => WindowsMessageWaitResult::ForegroundExecution,
- WAIT_EVENT(1) => {
- let mut msg = MSG::default();
- unsafe { GetMessageW(&mut msg, HWND::default(), 0, 0) };
- WindowsMessageWaitResult::WindowsMessage(msg)
- }
- _ => {
- log::error!("unhandled windows wait message: {}", wait_result.0);
- WindowsMessageWaitResult::Error
- }
+ fn run_foreground_tasks(&self) {
+ for runnable in self.inner.main_receiver.drain() {
+ runnable.run();
}
}
}
+unsafe extern "system" fn invalidate_window_callback(hwnd: HWND, _: LPARAM) -> BOOL {
+ if let Some(inner) = try_get_window_inner(hwnd) {
+ inner.invalidate_client_area();
+ }
+ TRUE
+}
+
+/// invalidates all windows belonging to a thread causing a paint message to be scheduled
+fn invalidate_thread_windows(win32_thread_id: u32) {
+ unsafe {
+ EnumThreadWindows(
+ win32_thread_id,
+ Some(invalidate_window_callback),
+ LPARAM::default(),
+ )
+ };
+}
+
impl Platform for WindowsPlatform {
fn background_executor(&self) -> BackgroundExecutor {
self.inner.background_executor.clone()
@@ -204,16 +210,21 @@ impl Platform for WindowsPlatform {
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
on_finish_launching();
- loop {
- match self.wait_message() {
- WindowsMessageWaitResult::ForegroundExecution => {
- for runnable in self.inner.main_receiver.drain() {
- runnable.run();
- }
- }
- WindowsMessageWaitResult::WindowsMessage(msg) => {
+ 'a: loop {
+ let mut msg = MSG::default();
+ // will be 0 if woken up by self.inner.event or 1 if the compositor clock ticked
+ // SEE: https://learn.microsoft.com/en-us/windows/win32/directcomp/compositor-clock/compositor-clock
+ let wait_result =
+ unsafe { DCompositionWaitForCompositorClock(Some(&[self.inner.event]), INFINITE) };
+
+ // compositor clock ticked so we should draw a frame
+ if wait_result == 1 {
+ unsafe { invalidate_thread_windows(GetCurrentThreadId()) };
+
+ while unsafe { PeekMessageW(&mut msg, HWND::default(), 0, 0, PM_REMOVE) }.as_bool()
+ {
if msg.message == WM_QUIT {
- break;
+ break 'a;
}
if !self.run_immediate_msg_handlers(&msg) {
@@ -221,8 +232,9 @@ impl Platform for WindowsPlatform {
unsafe { DispatchMessageW(&msg) };
}
}
- WindowsMessageWaitResult::Error => {}
}
+
+ self.run_foreground_tasks();
}
let mut callbacks = self.inner.callbacks.lock();
@@ -17,7 +17,8 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use windows::{
core::{w, HSTRING, PCWSTR},
Win32::{
- Foundation::{HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
+ Foundation::{FALSE, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
+ Graphics::Gdi::{BeginPaint, EndPaint, InvalidateRect, PAINTSTRUCT},
System::SystemServices::{
MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_XBUTTON1, MK_XBUTTON2, MODIFIERKEYS_FLAGS,
},
@@ -158,6 +159,12 @@ impl WindowsWindowInner {
}
}
+ /// mark window client rect to be re-drawn
+ /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-invalidaterect
+ pub(crate) fn invalidate_client_area(&self) {
+ unsafe { InvalidateRect(self.hwnd, None, FALSE) };
+ }
+
/// returns true if message is handled and should not dispatch
pub(crate) fn handle_immediate_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> bool {
match msg {
@@ -245,16 +252,20 @@ impl WindowsWindowInner {
height: Pixels(height.0),
},
1.0,
- )
+ );
}
+ self.invalidate_client_area();
LRESULT(0)
}
fn handle_paint_msg(&self) -> LRESULT {
+ let mut paint_struct = PAINTSTRUCT::default();
+ let hdc = unsafe { BeginPaint(self.hwnd, &mut paint_struct) };
let mut callbacks = self.callbacks.borrow_mut();
- if let Some(callback) = callbacks.request_frame.as_mut() {
- callback()
+ if let Some(request_frame) = callbacks.request_frame.as_mut() {
+ request_frame();
}
+ unsafe { EndPaint(self.hwnd, &paint_struct) };
LRESULT(0)
}
@@ -403,18 +414,12 @@ impl WindowsWindowInner {
};
if callback(PlatformInput::KeyDown(event)) {
- if let Some(request_frame) = callbacks.request_frame.as_mut() {
- request_frame();
- }
CallbackResult::Handled { by_callback: true }
} else if let Some(mut input_handler) = self.input_handler.take() {
if let Some(ime_key) = ime_key {
input_handler.replace_text_in_range(None, &ime_key);
}
self.input_handler.set(Some(input_handler));
- if let Some(request_frame) = callbacks.request_frame.as_mut() {
- request_frame();
- }
CallbackResult::Handled { by_callback: true }
} else {
CallbackResult::Handled { by_callback: false }
@@ -433,9 +438,8 @@ impl WindowsWindowInner {
if let Some(keystroke) = keystroke {
if let Some(callback) = callbacks.input.as_mut() {
let event = KeyUpEvent { keystroke };
- CallbackResult::Handled {
- by_callback: callback(PlatformInput::KeyUp(event)),
- }
+ let by_callback = callback(PlatformInput::KeyUp(event));
+ CallbackResult::Handled { by_callback }
} else {
CallbackResult::Handled { by_callback: false }
}
@@ -527,12 +531,8 @@ impl WindowsWindowInner {
modifiers: self.current_modifiers(),
touch_phase: TouchPhase::Moved,
};
- if callback(PlatformInput::ScrollWheel(event)) {
- if let Some(request_frame) = callbacks.request_frame.as_mut() {
- request_frame();
- }
- return LRESULT(0);
- }
+ callback(PlatformInput::ScrollWheel(event));
+ return LRESULT(0);
}
LRESULT(1)
}
@@ -554,9 +554,6 @@ impl WindowsWindowInner {
touch_phase: TouchPhase::Moved,
};
if callback(PlatformInput::ScrollWheel(event)) {
- if let Some(request_frame) = callbacks.request_frame.as_mut() {
- request_frame();
- }
return LRESULT(0);
}
}