-
Notifications
You must be signed in to change notification settings - Fork 909
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
Add ApplicationHandler
trait
#3073
Conversation
406a723
to
a12b508
Compare
Sorry about the delay in #3056, will try to finish it up today. |
Now that I see it in real life, I'm not that sure about this one. It's still possible for users to just keep the |
For my part, this PR is mostly about ensuring that the application is initialized before you try to create windows, which solves sooo many issues on macOS and iOS, and unblocks a lot of my other work (it's really hard to make sure that e.g. fullscreen-ing works correctly when you basically have to work with the window in two states). This would also be possible with other solutions, e.g. nested closures in
True, but there are ways to fix that; one approach could be, drum roll, you guessed it, lifetimes! Queue the most general example I could conjure: mod winit {
pub struct Window<'running> { ... }
impl<'running> Window<'running> {
pub fn new(elwt: &'running EventLoopWindowTarget) -> Self { ... }
}
pub trait ApplicationHandler<'suspended: 'running, 'running, T = ()> {
type Suspended: 'suspended;
// Note that binding the elwt here to `'running` is non-trivial, because then we
// have to allow it to escape. But should be doable, in one form or another.
fn resume(suspended: Self::Suspended, elwt: &'running EventLoopWindowTarget) -> Self;
fn suspend(self) -> Self::Suspended;
}
}
struct State<'suspended> { ... }
struct App<'suspended, 'running> {
window: Window<'running>,
state: State<'suspended>,
}
impl<'suspended: 'running, 'running> ApplicationHandler<'suspended, 'running> for App<'suspended, 'running> {
type Suspended = State<'suspended>;
fn resume(
state: Self::Suspended,
elwt: &'running EventLoopWindowTarget,
) -> Self {
Self {
window: Window::new(elwt),
state,
}
}
fn suspend(self) -> Self::Suspended {
self.state
}
} But whether or not we decide to do that, I still think moving to a trait like this is the way forwards. (Again, the above is still possible using closures, but it becomes a nested mess. One closure is nice, three nested closures is quite enough thank you very much). |
The trait in the PR looks usable, but I think I'd just set struct WindowData<S: WindowSurface> {
window: winit::window::Window,
#[cfg(all(wayland_platform, feature = "clipboard"))]
wayland_clipboard: Option<smithay_clipboard::Clipboard>,
surface: S,
// ...
}
/// Per-window data
pub struct Window<A: AppData, S: WindowSurface> {
widget: kas::Window<A>,
ev_state: EventState,
// ...
window: Option<WindowData<S>>,
} For any app with multiple windows this strategy probably makes more sense than using a separate Regarding the lifetimes idea, I don't think it enforces anything (unless you are deliberately not passing |
The idea was that struct WindowData<S: WindowSurface{
window: winit::window::Window,
#[cfg(all(wayland_platform, feature = "clipboard"))]
wayland_clipboard: Option<smithay_clipboard::Clipboard>,
surface: S,
// ...
}
pub struct Window<A: AppData, S: WindowSurface{
widget: kas::Window<A>,
ev_state: EventState,
// ...
}
struct App {
windows: Vec<(Window<A, S>, WindowData<S>)>,
}
struct Suspended {
windows: Vec<Window<A, S>>,
}
No I definitely agree, we'd want something that was actually understandable and usable, the idea I sent was just to prove the concept (if you replace the But again, I'm definitely on the pragmatic side here, fixing the |
This works with your |
Oh yeah... I suspect there's probably still a way to do it, but let's handle that when we get there. |
Replaced by #3517 |
Part of #2903.
Builds upon #3056, so see the last commit(s) for the changes in this PR.
Add an
ApplicationHandler<T>
trait that replaces theEvent<T>
enum (should probably be kept around for at least one release, but be marked deprecated) by encoding these events as callbacks on a user-specified mutable application object instead.This allows us to fix many outstanding issues with the current event loop design, including ensuring that windows are only created after initialization, and helping users to properly suspended/resume their application (also here: recreating surfaces and such).
TODO:
ApplicationHandler
using closures #3074