Skip to content

Commit

Permalink
Add workaround to handle clear event
Browse files Browse the repository at this point in the history
  • Loading branch information
Wu Yu Wei committed Jun 20, 2022
1 parent 6adc1d1 commit 2984537
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 28 deletions.
48 changes: 26 additions & 22 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2018,9 +2018,11 @@ unsafe extern "system" fn thread_event_target_callback<T: 'static>(
) -> LRESULT {
let subclass_input = Box::from_raw(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput<T>);

// if msg != WM_PAINT {
// RedrawWindow(window, ptr::null(), HRGN::default(), RDW_INTERNALPAINT);
// }
// Calling RedrawWindow will cause other window busy waiting. So we handle clear event directly
// as long as there's a thread event target message.
if msg != WM_PAINT {
handle_clear_event(&subclass_input.event_loop_runner, window);
}

let mut subclass_removed = false;

Expand All @@ -2037,25 +2039,8 @@ unsafe extern "system" fn thread_event_target_callback<T: 'static>(
// when the event queue has been emptied. See `process_event` for more details.
win32wm::WM_PAINT => {
ValidateRect(window, ptr::null());
// If the WM_PAINT handler in `public_window_callback` has already flushed the redraw
// events, `handling_events` will return false and we won't emit a second
// `RedrawEventsCleared` event.
if subclass_input.event_loop_runner.handling_events() {
if subclass_input.event_loop_runner.should_buffer() {
// This branch can be triggered when a nested win32 event loop is triggered
// inside of the `event_handler` callback.
RedrawWindow(window, ptr::null(), HRGN::default(), RDW_INTERNALPAINT);
} else {
// This WM_PAINT handler will never be re-entrant because `flush_paint_messages`
// doesn't call WM_PAINT for the thread event target (i.e. this window).
assert!(flush_paint_messages(
None,
&subclass_input.event_loop_runner
));
subclass_input.event_loop_runner.redraw_events_cleared();
process_control_flow(&subclass_input.event_loop_runner);
}
}

handle_clear_event(&subclass_input.event_loop_runner, window);

// Default WM_PAINT behaviour. This makes sure modals and popups are shown immediatly when opening them.
DefSubclassProc(window, msg, wparam, lparam)
Expand Down Expand Up @@ -2323,3 +2308,22 @@ unsafe fn handle_raw_input<T: 'static>(
});
}
}

unsafe fn handle_clear_event<T: 'static>(event_loop_runner: &EventLoopRunner<T>, window: HWND) {
// If the WM_PAINT handler in `public_window_callback` has already flushed the redraw
// events, `handling_events` will return false and we won't emit a second
// `RedrawEventsCleared` event.
if event_loop_runner.handling_events() {
if event_loop_runner.should_buffer() {
// This branch can be triggered when a nested win32 event loop is triggered
// inside of the `event_handler` callback.
RedrawWindow(window, ptr::null(), HRGN::default(), RDW_INTERNALPAINT);
} else {
// This WM_PAINT handler will never be re-entrant because `flush_paint_messages`
// doesn't call WM_PAINT for the thread event target (i.e. this window).
assert!(flush_paint_messages(None, &event_loop_runner));
event_loop_runner.redraw_events_cleared();
process_control_flow(&event_loop_runner);
}
}
}
23 changes: 17 additions & 6 deletions src/platform_impl/windows/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ impl<T> EventLoopRunner<T> {
owned_windows.extend(&new_owned_windows);
self.owned_windows.set(owned_windows);
}

pub fn no_owned_windows(&self) -> bool {
let owned_windows = self.owned_windows.take();
let result = owned_windows.is_empty();
self.owned_windows.set(owned_windows);
result
}
}

/// Event dispatch functions.
Expand Down Expand Up @@ -394,12 +401,16 @@ impl<T> EventLoopRunner<T> {
};
self.call_event_handler(Event::NewEvents(start_cause));
self.dispatch_buffered_events();
// RedrawWindow(
// self.thread_msg_target,
// ptr::null(),
// HRGN::default(),
// RDW_INTERNALPAINT,
// );
// Calling RedrawWindow will cause other window busy waiting. So we only call it when
// there's no window.
if self.no_owned_windows() {
RedrawWindow(
self.thread_msg_target,
ptr::null(),
HRGN::default(),
RDW_INTERNALPAINT,
);
}
}

unsafe fn call_redraw_events_cleared(&self) {
Expand Down

0 comments on commit 2984537

Please sign in to comment.