mirror of
https://github.com/rust-windowing/winit.git
synced 2026-09-01 22:30:04 -04:00
Verify event order
When debug assertions are enabled, check that events are emitted in the expected order, and if not, log an error.
This commit is contained in:
@@ -17,7 +17,9 @@ use softbuffer::{Context, Surface};
|
|||||||
|
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||||
use winit::event::{DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, WindowEvent};
|
use winit::event::{
|
||||||
|
DeviceEvent, DeviceId, Ime, MouseButton, MouseScrollDelta, StartCause, WindowEvent,
|
||||||
|
};
|
||||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
use winit::keyboard::{Key, ModifiersState};
|
use winit::keyboard::{Key, ModifiersState};
|
||||||
use winit::window::{
|
use winit::window::{
|
||||||
@@ -303,6 +305,12 @@ impl Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler<UserEvent> for Application {
|
impl ApplicationHandler<UserEvent> for Application {
|
||||||
|
fn new_events(&mut self, _event_loop: &ActiveEventLoop, start_cause: StartCause) {
|
||||||
|
if let StartCause::Init = start_cause {
|
||||||
|
info!("Started the event loop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) {
|
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) {
|
||||||
info!("User event: {event:?}");
|
info!("User event: {event:?}");
|
||||||
}
|
}
|
||||||
@@ -320,6 +328,7 @@ impl ApplicationHandler<UserEvent> for Application {
|
|||||||
|
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
|
info!("Resized({size:?})");
|
||||||
window.resize(size);
|
window.resize(size);
|
||||||
},
|
},
|
||||||
WindowEvent::Focused(focused) => {
|
WindowEvent::Focused(focused) => {
|
||||||
|
|||||||
@@ -209,6 +209,110 @@ impl EventLoop<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub(crate) fn ensure_event_order<'a, T: 'static>(
|
||||||
|
handler: impl ApplicationHandler<T> + 'a,
|
||||||
|
) -> impl ApplicationHandler<T> + 'a {
|
||||||
|
use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent};
|
||||||
|
use crate::window::WindowId;
|
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq, Eq, Clone)]
|
||||||
|
enum State {
|
||||||
|
#[default]
|
||||||
|
NotRunning,
|
||||||
|
Suspended,
|
||||||
|
Running,
|
||||||
|
Waiting,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
#[track_caller]
|
||||||
|
fn expect(&self, expected: State) {
|
||||||
|
if *self != expected {
|
||||||
|
tracing::error!("expected state to be {expected:?}, found {self:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn transition(&mut self, from: State, to: State) {
|
||||||
|
if *self != from {
|
||||||
|
tracing::error!(
|
||||||
|
"invalid state transition to {to:?}. Expected {from:?}, found {self:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*self = to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EnsureEventOrder<A> {
|
||||||
|
inner: A,
|
||||||
|
state: State,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for EnsureEventOrder<A> {
|
||||||
|
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
|
match cause {
|
||||||
|
StartCause::Init => self.state.transition(State::NotRunning, State::Suspended),
|
||||||
|
_ => self.state.transition(State::Waiting, State::Running),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inner.new_events(event_loop, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.state.transition(State::Suspended, State::Running);
|
||||||
|
self.inner.resumed(event_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suspended(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.state.transition(State::Running, State::Suspended);
|
||||||
|
self.inner.suspended(event_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.state.transition(State::Running, State::Waiting);
|
||||||
|
self.inner.about_to_wait(event_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exiting(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.state.transition(State::Suspended, State::NotRunning);
|
||||||
|
self.inner.exiting(event_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
|
||||||
|
self.state.expect(State::Running);
|
||||||
|
self.inner.user_event(event_loop, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
window_id: WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
self.state.expect(State::Running);
|
||||||
|
self.inner.window_event(event_loop, window_id, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
device_id: DeviceId,
|
||||||
|
event: DeviceEvent,
|
||||||
|
) {
|
||||||
|
self.state.expect(State::Running);
|
||||||
|
self.inner.device_event(event_loop, device_id, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_warning(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
// TODO: What states are allowed when receiving this?
|
||||||
|
self.inner.memory_warning(event_loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureEventOrder { inner: handler, state: State::NotRunning }
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl<T> EventLoop<T> {
|
||||||
/// Start building a new event loop, with the given type as the user event
|
/// Start building a new event loop, with the given type as the user event
|
||||||
/// type.
|
/// type.
|
||||||
@@ -247,6 +351,8 @@ impl<T> EventLoop<T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let app = &mut ensure_event_order(app);
|
||||||
self.event_loop.run_app(app)
|
self.event_loop.run_app(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user