diff --git a/CHANGELOG.md b/CHANGELOG.md index 248e1d34..1e68938c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ And please only add new entries to the top of this list, right below the `# Unre - On macOS, fix assertion when pressing `Globe` key. - On Windows, updated `WM_MOUSEMOVE` to detect when cursor Enter or Leave window client area while captured and send the corresponding events. (#3153) - On macOS, fix crash when accessing tabbing APIs. +- On Windows, fix `RedrawRequested` not being delivered when calling `Window::request_redraw` from `RedrawRequested`. # 0.29.1-beta diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c29997c2..7cc105a3 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1168,19 +1168,28 @@ unsafe fn public_window_callback_inner( } WM_PAINT => { - if userdata.event_loop_runner.should_buffer() { - // this branch can happen in response to `UpdateWindow`, if win32 decides to - // redraw the window outside the normal flow of the event loop. - unsafe { RedrawWindow(window, ptr::null(), 0, RDW_INTERNALPAINT) }; - } else { + userdata.window_state_lock().redraw_requested = + userdata.event_loop_runner.should_buffer(); + + // We'll buffer only in response to `UpdateWindow`, if win32 decides to redraw the + // window outside the normal flow of the event loop. This way mark event as handled + // and request a normal redraw with `RedrawWindow`. + if !userdata.event_loop_runner.should_buffer() { userdata.send_event(Event::WindowEvent { window_id: RootWindowId(WindowId(window)), event: WindowEvent::RedrawRequested, }); } - result = ProcResult::DefWindowProc(wparam); - } + // NOTE: calling `RedrawWindow` during `WM_PAINT` does nothing, since to mark + // `WM_PAINT` as handled we should call the `DefWindowProcW`. Call it and check whether + // user asked for redraw during `RedrawRequested` event handling and request it again + // after marking `WM_PAINT` as handled. + result = ProcResult::Value(unsafe { DefWindowProcW(window, msg, wparam, lparam) }); + if std::mem::take(&mut userdata.window_state_lock().redraw_requested) { + unsafe { RedrawWindow(window, ptr::null(), 0, RDW_INTERNALPAINT) }; + } + } WM_WINDOWPOSCHANGING => { let mut window_state = userdata.window_state_lock(); if let Some(ref mut fullscreen) = window_state.fullscreen { diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index cda5563d..bb571123 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -149,6 +149,8 @@ impl Window { #[inline] pub fn request_redraw(&self) { + // NOTE: mark that we requested a redraw to handle requests during `WM_PAINT` handling. + self.window_state.lock().unwrap().redraw_requested = true; unsafe { RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT); } diff --git a/src/platform_impl/windows/window_state.rs b/src/platform_impl/windows/window_state.rs index 233430ab..cefaab68 100644 --- a/src/platform_impl/windows/window_state.rs +++ b/src/platform_impl/windows/window_state.rs @@ -52,6 +52,9 @@ pub(crate) struct WindowState { pub is_active: bool, pub is_focused: bool, + // Flag whether redraw was requested. + pub redraw_requested: bool, + pub dragging: bool, pub skip_taskbar: bool, @@ -166,6 +169,7 @@ impl WindowState { is_active: false, is_focused: false, + redraw_requested: false, dragging: false, diff --git a/src/window.rs b/src/window.rs index 8800b62c..5c79df48 100644 --- a/src/window.rs +++ b/src/window.rs @@ -585,8 +585,7 @@ impl Window { /// ## Platform-specific /// /// - **Windows** This API uses `RedrawWindow` to request a `WM_PAINT` message and `RedrawRequested` - /// is emitted in sync with any `WM_PAINT` messages. **Calling this method from `RedrawRequested` - /// event handler won't produce a `RedrawRequested` event**. + /// is emitted in sync with any `WM_PAINT` messages. /// - **iOS:** Can only be called on the main thread. /// - **Wayland:** The events are aligned with the frame callbacks when [`Window::pre_present_notify`] /// is used.