-
Notifications
You must be signed in to change notification settings - Fork 919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Encode event lifecycle in the type-system #2903
Comments
I generally like this idea, especially since the |
@madsmtm so you do you want more or less the API Wayland backend has internally, you can look at state and e.g pointer handlers to get a grasp on how it works? Since what you suggest is exactly how the API behaves on Wayland, it could simplify stuff for the wayland backend for sure, for example, but it could be hard for other backends like Windows and X11 where they have just one closure to handle all of that. |
cc @rib since it sort of interacts with the way we do event loop APIs and I'd like to hear what you think about all of that. |
Hmm, from a quick look, yeah, pretty closely.
Yeah, internally the backends would need some kind of enum State<T: ApplicationHandler> {
#[default]
Uninitialized,
Suspended(T::SuspendedState),
Running(T),
Dropped,
}; (Possibly using |
As a first impression - yeah implementing a trait on your App state sounds like it could work pretty nicely - though the devil will probably be in the details. Previously I think when the idea of splitting up the event callback has come up then I think the challenge with ergonomics has been with the way that you would currently capture your app state in the event closure and it becomes awkward to share app state across multiple closures. I think probably a trait on the user's app state addresses that concern.
I think it could hopefully be more-or-less orthogonal because this is about how you organize the app code that responds to events and that should be able to work consistently, regardless of exactly which way the event loop gets run. E.g. you could conceivably call let mut event_loop = EventLoop::new();
let mut app = App::default();
'main: loop {
let status = event_loop.pump_events(&app);
if let PumpStatus::Exit(exit_code) = status {
break 'main ExitCode::from(exit_code as u8);
}
println!("External Update()");
app.update();
} To allow for My initial impression is that this trait based approach would mainly just let us modularize the monolithic event closure and it would be easier to expose events that require the application to return values to Winit. Good first candidates to split out from the general event callback could be any events that may need to be synchronized with the windowing system - such as suspend/resume already in the example above, but probably also I might not have fully followed the idea with the enum for application states and I'm not quite sure what the ideas are with It could be good to think about extensibility of this approach though. E.g. what options do we have to apps to implement extension traits that maybe just certain backends deal with. It's not the focus here but I'd really like to replace / remove |
Agreed.
My evil scheme is to do something similar for window events (esp. drawing) later on (have a
The idea was that you'd be able to statically tell that "the render surfaces are currently valid", instead of relying on an In the example I gave, the suspended state and the running state would be the same, since the window itself would persist.
Good point! Let me enumerate a few options:
trait ApplicationHandlerMacOS: ApplicationHandler {
fn method();
}
trait EventLoopExtMacOS {
fn run_with_platform<T: ApplicationHandlerMacOS>(...);
}
Agreed, and it would vastly simplify the amount of code users have to write under this proposal. |
I've put up a PR with an initial implementation here: #3073 |
Blocked on #3432, which is part of the work to move to a handler trait.
Re-reading, this is actually pretty much on-spot for what we're doing now half a year later. |
A similar proposal was also posted here. |
I just want to note that providing an API like this can be done through a separate crate. |
We have a lot of invariants in how our events are delivered, but these are only vaguely documented. Examples of things that commonly go wrong:
NewEvents(Init)
/Resumed
Suspended
To remedy this situation, I propose we change the
run
method(s) to use a trait object instead of just a closure.Initial draft for what typical usage will look like (this will need a lot of tweaking, especially with regards to
ControlFlow
, and possibly we should consider aSimpleApplication
trait that handles some of this for you):The closure we have now is really nice though, we loose the easiness offered by that, but this is strictly more correct, which I think is important!
Again, this will need a lot of tweaking, opening as an issue first to gather opinions.
Relates to #2900, #2010, and many, many more.
The text was updated successfully, but these errors were encountered: