mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 21:31:29 +11:00
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:
parent
9393b14b01
commit
74a7cf55ea
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
}
|
);
|
||||||
_ => (),
|
}
|
||||||
},
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue