Skip to content

Commit ae7497e

Browse files
authored
Remove RedrawEventsCleared + MainEventsCleared, and added AboutToWait
The idea that redraw events are dispatched with a specific ordering that makes it possible to specifically report when we have finished dispatching redraw events isn't portable and the way in which we dispatched RedrawEventsCleared was inconsistent across backends. More generally speaking, there is no inherent relationship between redrawing and event loop iterations. An event loop may wake up at any frequency depending on what sources of input events are being listened to but redrawing is generally throttled and in some way synchronized with the display frequency. Similarly there's no inherent relationship between a single event loop iteration and the dispatching of any specific kind of "main" event. An event loop wakes up when there are events to read (e.g. input events or responses from a display server / compositor) and goes back to waiting when there's nothing else to read. There isn't really a special kind of "main" event that is dispatched in order with respect to other events. What we can do more portably is emit an event when the event loop is about to block and wait for new events. In practice this is very similar to how MainEventsCleared was implemented except it wasn't the very last event previously since redraw events could be dispatched afterwards. The main backend where we don't strictly know when we're going to wait for events is Web (since the real event loop is internal to the browser). For now we emulate AboutToWait on Web similar to how MainEventsCleared was dispatched. In practice most applications almost certainly shouldn't care about AboutToWait because the frequency of event loop iterations is essentially arbitrary and usually irrelevant.
1 parent 935146d commit ae7497e

24 files changed

+76
-138
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ And please only add new entries to the top of this list, right below the `# Unre
3131
- `RedrawRequested` is no longer guaranteed to be emitted after `MainEventsCleared`, it is now platform-specific when the event is emitted after being requested via `redraw_request()`.
3232
- On Windows, `RedrawRequested` is now driven by `WM_PAINT` messages which are requested via `redraw_request()`
3333
- **Breaking** `LoopDestroyed` renamed to `LoopExiting` ([#2900](https://github.com/rust-windowing/winit/issues/2900))
34+
- **Breaking** `RedrawEventsCleared` removed ([#2900](https://github.com/rust-windowing/winit/issues/2900))
35+
- **Breaking** `MainEventsCleared` removed ([#2900](https://github.com/rust-windowing/winit/issues/2900))
36+
- Added `AboutToWait` event which is emitted when the event loop is about to block and wait for new events ([#2900](https://github.com/rust-windowing/winit/issues/2900))
3437

3538
# 0.29.0-beta.0
3639

examples/control_flow.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,11 @@ fn main() -> Result<(), impl std::error::Error> {
9595
},
9696
_ => (),
9797
},
98-
Event::MainEventsCleared => {
98+
Event::AboutToWait => {
9999
if request_redraw && !wait_cancelled && !close_requested {
100100
window.request_redraw();
101101
}
102-
if close_requested {
103-
control_flow.set_exit();
104-
}
105-
}
106-
Event::RedrawRequested(_window_id) => {
107-
fill::fill_window(&window);
108-
}
109-
Event::RedrawEventsCleared => {
102+
110103
match mode {
111104
Mode::Wait => control_flow.set_wait(),
112105
Mode::WaitUntil => {
@@ -119,6 +112,13 @@ fn main() -> Result<(), impl std::error::Error> {
119112
control_flow.set_poll();
120113
}
121114
};
115+
116+
if close_requested {
117+
control_flow.set_exit();
118+
}
119+
}
120+
Event::RedrawRequested(_window_id) => {
121+
fill::fill_window(&window);
122122
}
123123
_ => (),
124124
}

examples/web.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn main() -> Result<(), impl std::error::Error> {
3232
event: WindowEvent::CloseRequested,
3333
window_id,
3434
} if window_id == window.id() => control_flow.set_exit(),
35-
Event::MainEventsCleared => {
35+
Event::AboutToWait => {
3636
window.request_redraw();
3737
}
3838
Event::WindowEvent {

examples/window.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn main() -> Result<(), impl std::error::Error> {
2929
event: WindowEvent::CloseRequested,
3030
window_id,
3131
} if window_id == window.id() => control_flow.set_exit(),
32-
Event::MainEventsCleared => {
32+
Event::AboutToWait => {
3333
window.request_redraw();
3434
}
3535
Event::RedrawRequested(_) => {

examples/window_ondemand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn main() -> Result<(), impl std::error::Error> {
4343
println!("--------------------------------------------------------- Window {idx} CloseRequested");
4444
app.window = None;
4545
}
46-
Event::MainEventsCleared => window.request_redraw(),
46+
Event::AboutToWait => window.request_redraw(),
4747
Event::RedrawRequested(_) => {
4848
fill::fill_window(window);
4949
}

examples/window_option_as_alt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn main() -> Result<(), impl std::error::Error> {
5858
WindowEvent::KeyboardInput { .. } => println!("KeyboardInput: {event:?}"),
5959
_ => (),
6060
},
61-
Event::MainEventsCleared => {
61+
Event::AboutToWait => {
6262
window.request_redraw();
6363
}
6464
Event::RedrawRequested(_) => {

examples/window_pump_events.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn main() -> std::process::ExitCode {
4545
event: WindowEvent::CloseRequested,
4646
window_id,
4747
} if window_id == window.id() => control_flow.set_exit(),
48-
Event::MainEventsCleared => {
48+
Event::AboutToWait => {
4949
window.request_redraw();
5050
}
5151
Event::RedrawRequested(_) => {

examples/window_resize_increments.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn main() -> Result<(), impl std::error::Error> {
5454
debug!("Had increments: {}", new_increments.is_none());
5555
window.set_resize_increments(new_increments);
5656
}
57-
Event::MainEventsCleared => window.request_redraw(),
57+
Event::AboutToWait => window.request_redraw(),
5858
Event::RedrawRequested(_) => {
5959
fill::fill_window(&window);
6060
}

src/event.rs

+18-45
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@
1616
//! for e in (window events, user events, device events) {
1717
//! event_handler(e, ..., &mut control_flow);
1818
//! }
19-
//! event_handler(MainEventsCleared, ..., &mut control_flow);
2019
//!
2120
//! for w in (redraw windows) {
2221
//! event_handler(RedrawRequested(w), ..., &mut control_flow);
2322
//! }
24-
//! event_handler(RedrawEventsCleared, ..., &mut control_flow);
2523
//!
24+
//! event_handler(AboutToWait, ..., &mut control_flow);
2625
//! start_cause = wait_if_necessary(control_flow);
2726
//! }
2827
//!
@@ -207,53 +206,30 @@ pub enum Event<'a, T: 'static> {
207206
/// [`Suspended`]: Self::Suspended
208207
Resumed,
209208

210-
/// Emitted when all of the event loop's input events have been processed and redraw processing
211-
/// is about to begin.
209+
/// Emitted when the event loop is about to block and wait for new events.
212210
///
213-
/// This event is useful as a place to put your code that should be run after all
214-
/// state-changing events have been handled and you want to do stuff (updating state, performing
215-
/// calculations, etc) that happens as the "main body" of your event loop. If your program only draws
216-
/// graphics when something changes, it's usually better to do it in response to
217-
/// [`Event::RedrawRequested`](crate::event::Event::RedrawRequested), which gets emitted
218-
/// immediately after this event. Programs that draw graphics continuously, like most games,
219-
/// can render here unconditionally for simplicity.
220-
MainEventsCleared,
211+
/// Most applications shouldn't need to hook into this event since there is no real relationship
212+
/// between how often the event loop needs to wake up and the dispatching of any specific events.
213+
///
214+
/// High frequency event sources, such as input devices could potentially lead to lots of wake
215+
/// ups and also lots of corresponding `AboutToWait` events.
216+
///
217+
/// This is not an ideal event to drive application rendering from and instead applications
218+
/// should render in response to [`Event::RedrawRequested`](crate::event::Event::RedrawRequested)
219+
/// events.
220+
AboutToWait,
221221

222-
/// Emitted after [`MainEventsCleared`] when a window should be redrawn.
222+
/// Emitted when a window should be redrawn.
223223
///
224224
/// This gets triggered in two scenarios:
225225
/// - The OS has performed an operation that's invalidated the window's contents (such as
226226
/// resizing the window).
227227
/// - The application has explicitly requested a redraw via [`Window::request_redraw`].
228228
///
229-
/// During each iteration of the event loop, Winit will aggregate duplicate redraw requests
230-
/// into a single event, to help avoid duplicating rendering work.
231-
///
232-
/// Mainly of interest to applications with mostly-static graphics that avoid redrawing unless
233-
/// something changes, like most non-game GUIs.
234-
///
235-
///
236-
/// ## Platform-specific
237-
///
238-
/// - **macOS / iOS:** Due to implementation difficulties, this will often, but not always, be
239-
/// emitted directly inside `drawRect:`, with neither a preceding [`MainEventsCleared`] nor
240-
/// subsequent `RedrawEventsCleared`. See [#2640] for work on this.
241-
///
242-
/// [`MainEventsCleared`]: Self::MainEventsCleared
243-
/// [`RedrawEventsCleared`]: Self::RedrawEventsCleared
244-
/// [#2640]: https://github.com/rust-windowing/winit/issues/2640
229+
/// Winit will aggregate duplicate redraw requests into a single event, to
230+
/// help avoid duplicating rendering work.
245231
RedrawRequested(WindowId),
246232

247-
/// Emitted after all [`RedrawRequested`] events have been processed and control flow is about to
248-
/// be taken away from the program. If there are no `RedrawRequested` events, it is emitted
249-
/// immediately after `MainEventsCleared`.
250-
///
251-
/// This event is useful for doing any cleanup or bookkeeping work after all the rendering
252-
/// tasks have been completed.
253-
///
254-
/// [`RedrawRequested`]: Self::RedrawRequested
255-
RedrawEventsCleared,
256-
257233
/// Emitted when the event loop is being shut down.
258234
///
259235
/// This is irreversible - if this event is emitted, it is guaranteed to be the last event that
@@ -275,9 +251,8 @@ impl<T: Clone> Clone for Event<'static, T> {
275251
event: event.clone(),
276252
},
277253
NewEvents(cause) => NewEvents(*cause),
278-
MainEventsCleared => MainEventsCleared,
254+
AboutToWait => AboutToWait,
279255
RedrawRequested(wid) => RedrawRequested(*wid),
280-
RedrawEventsCleared => RedrawEventsCleared,
281256
LoopExiting => LoopExiting,
282257
Suspended => Suspended,
283258
Resumed => Resumed,
@@ -294,9 +269,8 @@ impl<'a, T> Event<'a, T> {
294269
WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
295270
DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
296271
NewEvents(cause) => Ok(NewEvents(cause)),
297-
MainEventsCleared => Ok(MainEventsCleared),
272+
AboutToWait => Ok(AboutToWait),
298273
RedrawRequested(wid) => Ok(RedrawRequested(wid)),
299-
RedrawEventsCleared => Ok(RedrawEventsCleared),
300274
LoopExiting => Ok(LoopExiting),
301275
Suspended => Ok(Suspended),
302276
Resumed => Ok(Resumed),
@@ -314,9 +288,8 @@ impl<'a, T> Event<'a, T> {
314288
UserEvent(event) => Some(UserEvent(event)),
315289
DeviceEvent { device_id, event } => Some(DeviceEvent { device_id, event }),
316290
NewEvents(cause) => Some(NewEvents(cause)),
317-
MainEventsCleared => Some(MainEventsCleared),
291+
AboutToWait => Some(AboutToWait),
318292
RedrawRequested(wid) => Some(RedrawRequested(wid)),
319-
RedrawEventsCleared => Some(RedrawEventsCleared),
320293
LoopExiting => Some(LoopExiting),
321294
Suspended => Some(Suspended),
322295
Resumed => Some(Resumed),

src/event_loop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl<T> fmt::Debug for EventLoopWindowTarget<T> {
149149

150150
/// Set by the user callback given to the [`EventLoop::run`] method.
151151
///
152-
/// Indicates the desired behavior of the event loop after [`Event::RedrawEventsCleared`] is emitted.
152+
/// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted.
153153
///
154154
/// Defaults to [`Poll`].
155155
///

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
//! println!("The close button was pressed; stopping");
7070
//! control_flow.set_exit();
7171
//! },
72-
//! Event::MainEventsCleared => {
72+
//! Event::AboutToWait => {
7373
//! // Application update code.
7474
//!
7575
//! // Queue a RedrawRequested event.
@@ -83,7 +83,7 @@
8383
//! // Redraw the application.
8484
//! //
8585
//! // It's preferable for applications that do not render continuously to render in
86-
//! // this event rather than in MainEventsCleared, since rendering in here allows
86+
//! // this event rather than in AboutToWait, since rendering in here allows
8787
//! // the program to gracefully handle redraws requested by the OS.
8888
//! },
8989
//! _ => ()

src/platform/pump_events.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub trait EventLoopExtPumpEvents {
7474
/// event: WindowEvent::CloseRequested,
7575
/// window_id,
7676
/// } if window_id == window.id() => control_flow.set_exit(),
77-
/// Event::MainEventsCleared => {
77+
/// Event::AboutToWait => {
7878
/// window.request_redraw();
7979
/// }
8080
/// _ => (),

src/platform_impl/android/mod.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -484,13 +484,6 @@ impl<T: 'static> EventLoop<T> {
484484
}
485485
}
486486

487-
sticky_exit_callback(
488-
event::Event::MainEventsCleared,
489-
self.window_target(),
490-
&mut control_flow,
491-
callback,
492-
);
493-
494487
if self.running {
495488
if resized {
496489
let size = if let Some(native_window) = self.android_app.native_window().as_ref() {
@@ -515,8 +508,9 @@ impl<T: 'static> EventLoop<T> {
515508
}
516509
}
517510

511+
// This is always the last event we dispatch before poll again
518512
sticky_exit_callback(
519-
event::Event::RedrawEventsCleared,
513+
event::Event::AboutToWait,
520514
self.window_target(),
521515
&mut control_flow,
522516
callback,

src/platform_impl/ios/app_state.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -753,21 +753,18 @@ pub unsafe fn handle_main_events_cleared() {
753753
};
754754
drop(this);
755755

756-
// User events are always sent out at the end of the "MainEventLoop"
757756
handle_user_events();
758-
handle_nonuser_event(EventWrapper::StaticEvent(Event::MainEventsCleared));
759757

760758
let mut this = AppState::get_mut();
761-
let mut redraw_events: Vec<EventWrapper> = this
759+
let redraw_events: Vec<EventWrapper> = this
762760
.main_events_cleared_transition()
763761
.into_iter()
764762
.map(|window| EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.id()))))
765763
.collect();
766-
767-
redraw_events.push(EventWrapper::StaticEvent(Event::RedrawEventsCleared));
768764
drop(this);
769765

770766
handle_nonuser_events(redraw_events);
767+
handle_nonuser_event(EventWrapper::StaticEvent(Event::AboutToWait));
771768
}
772769

773770
// requires main thread

src/platform_impl/ios/event_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@ fn setup_control_flow_observers() {
237237

238238
// Core Animation registers its `CFRunLoopObserver` that performs drawing operations in
239239
// `CA::Transaction::ensure_implicit` with a priority of `0x1e8480`. We set the main_end
240-
// priority to be 0, in order to send MainEventsCleared before RedrawRequested. This value was
240+
// priority to be 0, in order to send AboutToWait before RedrawRequested. This value was
241241
// chosen conservatively to guard against apple using different priorities for their redraw
242242
// observers in different OS's or on different devices. If it so happens that it's too
243-
// conservative, the main symptom would be non-redraw events coming in after `MainEventsCleared`.
243+
// conservative, the main symptom would be non-redraw events coming in after `AboutToWait`.
244244
//
245245
// The value of `0x1e8480` was determined by inspecting stack traces and the associated
246246
// registers for every `CFRunLoopAddObserver` call on an iPad Air 2 running iOS 11.4.

src/platform_impl/ios/view.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,9 @@ declare_class!(
4242
fn draw_rect(&self, rect: CGRect) {
4343
let window = self.window().unwrap();
4444
unsafe {
45-
app_state::handle_nonuser_events(
46-
std::iter::once(EventWrapper::StaticEvent(Event::RedrawRequested(
47-
RootWindowId(window.id()),
48-
)))
49-
.chain(std::iter::once(EventWrapper::StaticEvent(
50-
Event::RedrawEventsCleared,
51-
))),
52-
);
45+
app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::RedrawRequested(
46+
RootWindowId(window.id()),
47+
)));
5348
}
5449
let _: () = unsafe { msg_send![super(self), drawRect: rect] };
5550
}

src/platform_impl/linux/wayland/event_loop/mod.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -475,14 +475,6 @@ impl<T: 'static> EventLoop<T> {
475475
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
476476
}
477477

478-
// Send events cleared.
479-
sticky_exit_callback(
480-
Event::MainEventsCleared,
481-
&self.window_target,
482-
&mut control_flow,
483-
&mut callback,
484-
);
485-
486478
// Collect the window ids
487479
self.with_state(|state| {
488480
window_ids.extend(state.window_requests.get_mut().keys());
@@ -525,9 +517,9 @@ impl<T: 'static> EventLoop<T> {
525517
}
526518
}
527519

528-
// Send RedrawEventCleared.
520+
// This is always the last event we dispatch before poll again
529521
sticky_exit_callback(
530-
Event::RedrawEventsCleared,
522+
Event::AboutToWait,
531523
&self.window_target,
532524
&mut control_flow,
533525
&mut callback,

src/platform_impl/linux/x11/mod.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -659,15 +659,7 @@ impl<T: 'static> EventLoop<T> {
659659
);
660660
}
661661
}
662-
// send MainEventsCleared
663-
{
664-
sticky_exit_callback(
665-
crate::event::Event::MainEventsCleared,
666-
&self.target,
667-
&mut control_flow,
668-
callback,
669-
);
670-
}
662+
671663
// Empty the redraw requests
672664
{
673665
let mut windows = HashSet::new();
@@ -686,10 +678,11 @@ impl<T: 'static> EventLoop<T> {
686678
);
687679
}
688680
}
689-
// send RedrawEventsCleared
681+
682+
// This is always the last event we dispatch before poll again
690683
{
691684
sticky_exit_callback(
692-
crate::event::Event::RedrawEventsCleared,
685+
crate::event::Event::AboutToWait,
693686
&self.target,
694687
&mut control_flow,
695688
callback,

0 commit comments

Comments
 (0)