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 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 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 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
|
# 0.29.1-beta
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1168,19 +1168,28 @@ unsafe fn public_window_callback_inner<T: 'static>(
|
||||||
}
|
}
|
||||||
|
|
||||||
WM_PAINT => {
|
WM_PAINT => {
|
||||||
if userdata.event_loop_runner.should_buffer() {
|
userdata.window_state_lock().redraw_requested =
|
||||||
// this branch can happen in response to `UpdateWindow`, if win32 decides to
|
userdata.event_loop_runner.should_buffer();
|
||||||
// redraw the window outside the normal flow of the event loop.
|
|
||||||
unsafe { RedrawWindow(window, ptr::null(), 0, RDW_INTERNALPAINT) };
|
// We'll buffer only in response to `UpdateWindow`, if win32 decides to redraw the
|
||||||
} else {
|
// 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 {
|
userdata.send_event(Event::WindowEvent {
|
||||||
window_id: RootWindowId(WindowId(window)),
|
window_id: RootWindowId(WindowId(window)),
|
||||||
event: WindowEvent::RedrawRequested,
|
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 => {
|
WM_WINDOWPOSCHANGING => {
|
||||||
let mut window_state = userdata.window_state_lock();
|
let mut window_state = userdata.window_state_lock();
|
||||||
if let Some(ref mut fullscreen) = window_state.fullscreen {
|
if let Some(ref mut fullscreen) = window_state.fullscreen {
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,8 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_redraw(&self) {
|
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 {
|
unsafe {
|
||||||
RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT);
|
RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ pub(crate) struct WindowState {
|
||||||
pub is_active: bool,
|
pub is_active: bool,
|
||||||
pub is_focused: bool,
|
pub is_focused: bool,
|
||||||
|
|
||||||
|
// Flag whether redraw was requested.
|
||||||
|
pub redraw_requested: bool,
|
||||||
|
|
||||||
pub dragging: bool,
|
pub dragging: bool,
|
||||||
|
|
||||||
pub skip_taskbar: bool,
|
pub skip_taskbar: bool,
|
||||||
|
|
@ -166,6 +169,7 @@ impl WindowState {
|
||||||
|
|
||||||
is_active: false,
|
is_active: false,
|
||||||
is_focused: false,
|
is_focused: false,
|
||||||
|
redraw_requested: false,
|
||||||
|
|
||||||
dragging: false,
|
dragging: false,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -585,8 +585,7 @@ impl Window {
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// - **Windows** This API uses `RedrawWindow` to request a `WM_PAINT` message and `RedrawRequested`
|
/// - **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`
|
/// is emitted in sync with any `WM_PAINT` messages.
|
||||||
/// event handler won't produce a `RedrawRequested` event**.
|
|
||||||
/// - **iOS:** Can only be called on the main thread.
|
/// - **iOS:** Can only be called on the main thread.
|
||||||
/// - **Wayland:** The events are aligned with the frame callbacks when [`Window::pre_present_notify`]
|
/// - **Wayland:** The events are aligned with the frame callbacks when [`Window::pre_present_notify`]
|
||||||
/// is used.
|
/// is used.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue