Fix issues with redraw_requested when called during EventsCleared (#994)

* Fix issues with redraw_requested when called during EventsCleared

* Format

* Fix event dispatch after RedrawRequested but before EventsCleared

This could happen if the event queue was cleared, we processed WM_PAINT,
but the event queue got re-filled before we checked to see it was empty.

* Fix paint ordering issues when resizing window

* Format
This commit is contained in:
Osspial 2019-07-04 16:14:15 -04:00 committed by GitHub
parent 9393b14b01
commit 74a7cf55ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 23 deletions

View file

@ -9,6 +9,9 @@ and `WindowEvent::HoveredFile`.
- Revert the use of invisible surfaces in Wayland, which introduced graphical glitches with OpenGL (#835)
- On X11, implement `_NET_WM_PING` to allow desktop environment to kill unresponsive programs.
- On Windows, when a window is initially invisible, it won't take focus from the existing visible windows.
- On Windows, fix multiple calls to `request_redraw` during `EventsCleared` sending multiple `RedrawRequested events.`
- On Windows, fix edge case where `RedrawRequested` could be dispatched before input events in event loop iteration.
- On Windows, fix timing issue that could cause events to be improperly dispatched after `RedrawRequested` but before `EventsCleared`.
- On macOS, drop unused Metal dependency.
# 0.20.0 Alpha 1

View file

@ -195,6 +195,7 @@ impl<T: 'static> EventLoop<T> {
}
winuser::TranslateMessage(&mut msg);
winuser::DispatchMessageW(&mut msg);
msg_unprocessed = false;
}
runner!().events_cleared();
@ -202,6 +203,7 @@ impl<T: 'static> EventLoop<T> {
panic::resume_unwind(payload);
}
if !msg_unprocessed {
let control_flow = runner!().control_flow;
match control_flow {
ControlFlow::Exit => break 'main,
@ -218,6 +220,7 @@ impl<T: 'static> EventLoop<T> {
}
}
}
}
runner!().call_event_handler(Event::LoopDestroyed);
*self.window_target.p.runner_shared.runner.borrow_mut() = None;
@ -253,6 +256,7 @@ pub(crate) struct EventLoopRunner<T> {
runner_state: RunnerState,
modal_redraw_window: HWND,
in_modal_loop: bool,
in_repaint: bool,
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
panic_error: Option<PanicError>,
}
@ -316,6 +320,7 @@ impl<T> EventLoopRunner<T> {
control_flow: ControlFlow::default(),
runner_state: RunnerState::New,
in_modal_loop: false,
in_repaint: false,
modal_redraw_window: event_loop.window_target.p.thread_msg_target,
event_handler: mem::transmute::<
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
@ -429,10 +434,26 @@ impl<T> EventLoopRunner<T> {
}
self.runner_state = RunnerState::HandlingEvents;
self.call_event_handler(event);
match (self.in_repaint, &event) {
(
true,
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
},
)
| (false, _) => self.call_event_handler(event),
(true, _) => {
self.events_cleared();
self.new_events();
self.process_event(event);
}
}
}
fn events_cleared(&mut self) {
self.in_repaint = false;
match self.runner_state {
// If we were handling events, send the EventsCleared message.
RunnerState::HandlingEvents => {
@ -483,6 +504,10 @@ impl<T> EventLoopRunner<T> {
Event::EventsCleared => self
.trigger_newevents_on_redraw
.store(false, Ordering::Relaxed),
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..
} => self.in_repaint = true,
_ => (),
}
@ -871,12 +896,12 @@ unsafe extern "system" fn public_window_callback<T>(
_ if msg == *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID => {
use crate::event::WindowEvent::RedrawRequested;
let mut runner = subclass_input.event_loop_runner.runner.borrow_mut();
subclass_input.window_state.lock().queued_out_of_band_redraw = false;
if let Some(ref mut runner) = *runner {
// This check makes sure that calls to `request_redraw()` during `EventsCleared`
// handling dispatch `RedrawRequested` immediately after `EventsCleared`, without
// spinning up a new event loop iteration. We do this because that's what the API
// says to do.
let control_flow = runner.control_flow;
let runner_state = runner.runner_state;
let mut request_redraw = || {
runner.call_event_handler(Event::WindowEvent {
@ -886,15 +911,14 @@ unsafe extern "system" fn public_window_callback<T>(
};
match runner_state {
RunnerState::Idle(..) | RunnerState::DeferredNewEvents(..) => request_redraw(),
RunnerState::HandlingEvents => match control_flow {
ControlFlow::Poll => request_redraw(),
ControlFlow::WaitUntil(resume_time) => {
if resume_time <= Instant::now() {
request_redraw()
RunnerState::HandlingEvents => {
winuser::RedrawWindow(
window,
ptr::null(),
ptr::null_mut(),
winuser::RDW_INTERNALPAINT,
);
}
}
_ => (),
},
_ => (),
}
}

View file

@ -149,10 +149,14 @@ impl Window {
winuser::RDW_INTERNALPAINT,
);
} else {
let mut window_state = self.window_state.lock();
if !window_state.queued_out_of_band_redraw {
window_state.queued_out_of_band_redraw = true;
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0);
}
}
}
}
pub(crate) fn outer_position_physical(&self) -> (i32, i32) {
util::get_window_rect(self.window.0)

View file

@ -30,6 +30,9 @@ pub struct WindowState {
pub dpi_factor: f64,
pub fullscreen: Option<MonitorHandle>,
/// Used to supress duplicate redraw attempts when calling `request_redraw` multiple
/// times in `EventsCleared`.
pub queued_out_of_band_redraw: bool,
window_flags: WindowFlags,
}
@ -110,6 +113,7 @@ impl WindowState {
dpi_factor,
fullscreen: None,
queued_out_of_band_redraw: false,
window_flags: WindowFlags::empty(),
}
}