-
Notifications
You must be signed in to change notification settings - Fork 914
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
Using custom super loop for managing events #2857
Comments
I believe what you are looking for (just barely glanced at your post yet) is #2767. |
Integrating the For your use case, I would expose an |
Yea, I suspected needing to implement the I was trying to follow along with a GUI tutorial, that built up an abstracted game engine. Granted they were doing it in C++ using I do have a hacky idea which I want to stubbornly try first before I throw in the towel and do it properly though. |
Yeah, it definitely comes with a lot of traps and I wouldn't recommend it if you can possibly avoid it. I only really implemented the There are numerous platform-specific limitations with trying to write portable graphical applications within an explicit loop like above. I feel like it's fair to say that it's become an out-dated design trait to build graphical applications based on an explicit loop in the app. APIs like SDL have also bent over backwards to try and support that view but end up dealing with various special cases because the underlying window systems on some platforms aren't really compatible with this model. It's probably best to generally think of window systems as being event based, and not expect everything to be pollable within a while loop. Not sure if you would want to support Web for example but there's no way to run an endless loop in a browser - you instead need to build on top of the event model of the browser since the event loop is an implementation details of the browser. The tricks required to make MacOS look like it supports polling inside an external event loop also aren't possible on iOS. Some things should be handled in sync with the operating system (such as lifecycle events on mobile devices) or drawRect callbacks on macOS / iOS but it's more tricky to ensure this with an external loop design. |
Could you explain a bit more about why that is the case? For instance at the moment I'm doing a constant cycle of But obviously there must be something more to it, because every windowing library or event library I come across has a very similar architecture for rust. Utilising a run loop where you put all your code inside. And more than that having the events inside that loop only exist within the closure. So you can't do anything with them unless it's within the closure. I'm just curious why this structure is the preferred case for rust and/or modern windowing systems. run(|event, _, control_flow| {
/* handle events */
}); it was a system like this let (event, _, control_flow) = run_return();
/* handle events */ What actually breaks when doing this? Other than needing to put it in a loop so it continuously does the poll like so while running {
let(event, _, control_flow) = run_return();
/* handle events */
} I just don't really know why it's discouraged, because as far as I can tell. I'm more or less doing this anyway, just in a different more round about manner. I'm instantly returning from the run_return() loop, and I'm sending all of the events it got during the loop though a callback. Then i'm continuing past the loop and processing the events I got in the rest of my application. |
It's not really anything special for Rust here; it more a question of how the various OSs and window systems are designed. Web is the most exaggerated example here where we have a platform that fundamentally doesn't support having a long running loop that an application can run (since that would block the browser). The other awkward cases generally revolve around events that need to be synchronized with the window system or operating system. Take for example a "suspend" event on Android. Android has a Java based application programming model and it notifies applications that they are about to be paused via a Java callback on an Activity class. What's important here is that Android expects the application to handle that event during the Java callback. It's not something that can be added to a queue of events to process later. Conceptually it wouldn't make sense to buffer an application lifecycle event - those need to be handled in sync with the operating system. Another case is the These things that need to be handled synchronously don't really lend themselves to being processed within a loop that the application has created because the thread that runs the loop then needs to make sure it's in control of when the window system dispatches events (e.g. by calling an api like It's also not possible to control when the window system / OS dispatches those events on all platforms. On iOS for example you have an So more specifically to try and highly what goes wrong based on your example. If you follow a model like this... while running { // This loop itself would freeze a browser
let(event, _, control_flow) = run_return(); // There's no way to implement a function like run_return on iOS because NSApplication can't be stopped
/*
Then by the time you get here you have implicitly already missed your deadline for handling any event
that needs to be synchronized with the window system, such as 'drawRect' on macOS / iOS or mobile life cycle events.
Some window system / OS events fundamentally can't be buffered.
*/
} Hope that clarifies a bit some of the challenges |
Ah, I see. Thanks, |
I'm trying to build a project that is heavily abstracted, where the window is a trait and it's called into a super loop which would run something like
window.on_update()
Primarily I'm doing this so I can switch out the windowing library or the graphics library (currently winit and wgpu) in the future with ease. It's unlikely, but it's possible and I wanted to future proof myself.
And in an application somewhere my goal is to simply run
But I'm having an extreme amount of difficulty working around the run and run_return loops. (Still learning all there is to rust, I come from a c++ background so my code is still reminiscent of that style).
Up til now I've mostly been fine using run_return because I'm currently using my own event system, so technically all the events are processed in the platform dependent window which has the run_return. Then it matches the type of event and uses a callback function which dispatches my own events in my application.
Here is the full implementation used for processing the events
But while this has worked great, I'm trying to add a debugging window using egui, and I'm trying really hard not to place it in this implementation. Because I'm wanting to keep to the abstract nature, so I've separated egui into it's own module and now I'm trying to link it up.
My problem becomes apparent when I have to provide egui with the winit events. If I were able to control egui with my own custom events then life would be gravy. But egui is pretty heavily tied to winit, and I'm using the
egui_winit_platform
andegui_wgpu_backend
crates as the contexts. I tried to do the same thing as my own events by creating a callback, but instead calling back the raw winit events instead. But this caused a closure break. Because event can't be moved outside of the run_return or run loops. And as far as I can tell in rust, there is no way to get around that. Which is a tad annoying, just being able to create a static copy of it and send it through the callback is not allowed in rusts rule book. Which is frustrating.More or less I just need to get the events from
run_return
to a function like thisBut, I've given up on that dream using the
run_return
, so now I'm curious if there is an actual event polling system I can use, to forgo the need to put everything related to rendering in that run_return/run and poll the events in my own way.TL;DR
I'm wondering if there is a way to poll the events without the event_loop? I have my own super loop which I want to use, I have my own events which I'm already using, and I'd like to pass those raw winit events through a callback which I can use for egui. I'm unsure if this exists or not, I have this funny feeling that it probably doesn't, because this is rust, and it's not rust unless it's beating me with a stick each time I make progress.
The text was updated successfully, but these errors were encountered: