On Windows, fix RedrawRequested delivery
When calling `Window::request_redraw` from the `RedrawRequested` handler the `RedrawWindow` won't result in `WM_PAINT` being delivered due since user callback is run before `DefWindowProcW` is called. Track whether the user called `Window::request_redraw` and ask for `RedrawWindow` after running the said function during `WM_PAINT` handling. Fixes #3150.
This commit is contained in:
parent
c0db53a516
commit
98b3508aca
5 changed files with 24 additions and 9 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1168,19 +1168,28 @@ unsafe fn public_window_callback_inner<T: 'static>(
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue