-
Notifications
You must be signed in to change notification settings - Fork 920
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
Move ControlFlow
to EventLoopWindowTarget
#3056
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good from a brief look
@madsmtm could you check the iOS implementation? |
Honestly me neither, been meaning to rewrite it for a while now. I'll give it a short test drive, I suspect the situation is going to be somewhat improved (previously, there were certain events for which setting the control flow was ignored). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MacOS and iOS impl approved
25cd9eb
to
65b5cc3
Compare
I still need to go over the documentation again. |
Personally I like the previous model: it's possible to Now: if I call I would at least like getters for |
I think the Winit API in general is quite inconsistent with that, there are plenty of things that have setters but no getters. Events as well: some events can be queried, others can't. I would argue that the API would be better if all setters have getters and I don't think it hurts to be able to query any event instead of having to record events in case you need to know what the last status was. But that's a much bigger problem for another time.
Why would anything "take priority"? |
Just some thought I wanna drop here: The original motivation was to add platform-specific control flow variants. My thinking was to remove the enum in favor of setters to be able to add platform-specific methods through extension traits, which is the way Winit has continued to add platform-specific functionality until now. I was quite frustrated with the fact that we removed the In addition, this is a problem not specific to If we want to continue using the extension trait model for platform-specific features, I came up with the following idea that we could use for enums: enum Event {
EventA,
EventB(String),
EventC {
data: u16,
},
Platform(PlatformEvent),
}
impl PlatformEventExtWayland for PlatformEvent {
fn event(&self) -> WaylandEvent {
self.0
}
}
// Not really needed, just a neat idea.
impl PlatformEventExtWindows for PlatformEvent {
fn event(&self) -> ! {
match self.0 { }
}
} An alternative of course could be to simply mark the enum Personally I would be in favor of the first solution. We then could add a WDYT? |
I think this PR is still an improvement, I'd very much prefer to get rid of Whether the exact user-facing API uses I will say, I don't think |
Agreed, w/e further thoughts I'm dropping here, are just for follow-up.
I like that idea! |
I've never been a fan of Winit's Timers are such a basic building block for applications so it's always seemed odd to me that Winit doesn't support them. I'd love to see Winit provide a portable timer API which would replace the main use of |
I'm not sure winit should do that directly though. Maybe in a separate lib, because you can clearly implement timers based on |
This is an example of why control-flow is not a series of setters/getters:
On the whole I am not a fan of the platform-extension-trait model. For an app targetting only one platform the model is fine, but that's mostly not why you'd use Winit anyway. A cross-platform API should require as little platform-specific code to use as possible. If, say, |
To my mind it really needs to be Winit that supports timers otherwise they aren't portable. Even if you had a library that supported timers based on something like Portability for timers is only really practical / usable when they are supported by Winit directly. Handled in external libraries just means every app / framework has to come up with their own timer abstraction and although they could potentially use a utility crate for that, that in itself isn't really that beneficial (portability is more useful here imho than being able to share a small amount of utility code). |
I'd like to point out that I like the idea of having a |
@rib the issue I see there is that a "portable timer" is only really useful when a The way I've handled it in Kas is by storing (roughly) a |
yeah, although it's possible to write timers on top of a single, global timer, those timers are then only meaningful for Alacritty and it's not possible to write shared code for Winit applications that can utilize timers. I find this odd because implementing timers is definitely something that an event loop needs to be involved with but from an application development pov you generally want support for orthogonal timers and Winit is currently doing the absolute bare minimum to expose the timeout for polling. E.g. GLib mainloops have orthogonal timers as do libuv loops as does SDL... It'd be nicer imho if middleware crates / shared code could just assume that any Winit based app can register timers, regardless of whether they are used in Alacritty or Bevy or Egui etc. In this context I think having timers would essentially remove the need for ControlFlow, except for needing an ELWT API to request an exit(). |
If Winit supported orthogonal timers then there would be some kind of handle for a timer that you create and you'd get an event like |
This is ready now. I'm gonna update OP in a moment. There was a bunch of this code in various backends: match ... {
...
ControlFlow::ExitWithCode(_) => unreachable!(),
} I just removed them because I assume that they were there to exhaust |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good other than the nits
6e682ca
to
7020b6e
Compare
src/event_loop.rs
Outdated
/// Sets this to wait until a timeout has expired. | ||
/// | ||
/// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is | ||
/// instead set to [`Wait`]. | ||
/// | ||
/// [`WaitUntil`]: Self::WaitUntil | ||
/// [`Wait`]: Self::Wait | ||
pub fn set_wait_timeout(&mut self, timeout: Duration) { | ||
pub fn wait_duration(timeout: Duration) -> Self { | ||
match Instant::now().checked_add(timeout) { | ||
Some(instant) => self.set_wait_until(instant), | ||
None => self.set_wait(), | ||
Some(instant) => Self::WaitUntil(instant), | ||
None => Self::Wait, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function changed, however it doesn't explain what it wants to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did it change? Or do you just mean the documentation has to be adjusted to not say "set"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I adjusted the documentation a bit.
src/event_loop.rs
Outdated
/// Send a [`LoopExiting`] event and stop the event loop. | ||
/// | ||
/// [`LoopExiting`]: Event::LoopExiting | ||
pub fn exit(&self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue here is that we don't actually send anything, we basically say that we want to exit event loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So terminate
and is_terminating
are better names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the problem here was the documentation, which I adjusted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an event called LoopExiting
, not LoopTerminating
, so using the word terminate will be inconsistent with the event names.
7020b6e
to
f24e51f
Compare
f24e51f
to
cc6d8d8
Compare
This PR makes the following changes:
&mut ControlFlow
fromrun()
and adds a setter and getter toEventLoopWindowTarget
instead.exit()
andis_exit()
onEventLoopWindowTarget
.Fixes #3042.