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) - 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 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, 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. - On macOS, drop unused Metal dependency.
# 0.20.0 Alpha 1 # 0.20.0 Alpha 1

View file

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

View file

@ -149,7 +149,11 @@ impl Window {
winuser::RDW_INTERNALPAINT, winuser::RDW_INTERNALPAINT,
); );
} else { } else {
winuser::PostMessageW(self.window.0, *REQUEST_REDRAW_NO_NEWEVENTS_MSG_ID, 0, 0); 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);
}
} }
} }
} }

View file

@ -30,6 +30,9 @@ pub struct WindowState {
pub dpi_factor: f64, pub dpi_factor: f64,
pub fullscreen: Option<MonitorHandle>, 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, window_flags: WindowFlags,
} }
@ -110,6 +113,7 @@ impl WindowState {
dpi_factor, dpi_factor,
fullscreen: None, fullscreen: None,
queued_out_of_band_redraw: false,
window_flags: WindowFlags::empty(), window_flags: WindowFlags::empty(),
} }
} }