-
Notifications
You must be signed in to change notification settings - Fork 903
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
Consolidate poll_events() and run_forever() into get_event(Timeout) #231
Comments
What you describe is more or less winit's old API. We transitioned to callbacks because it solves the fact that MacOS uses a resize callback, and also in the longer term because of Android and Emscripten.
It's the opposite, the |
Huh?
Couldn't this (and any similar system) be handled by putting the message in a queue in the event loop struct and waking it up? |
This is missing half of the documentation. If the future is not ready when you call |
@Ralith see #219 - The main problem is that in the macOS backend, I would recommend breaking this proposal into two distinct proposals: 1. Offer a way to timeout on waiting for events. I agree that this makes sense (as long as all platforms offer a native API for this) to avoid the need for users to spawn a thread. 2. Change the event emitting API by removing the user callback approach in favour of returning events from a function. From my understanding this is a much harder problem due to the frustrating behaviour of macOS that I mentioned above. As it stands, I can't really get behind this proposal without first solving this problem. As tomaka mentioned, this problem is one of the reasons we changed the API from returning Event iterators to user callbacks in the first place. That said, if we can work out how to solve this issue, I would love for a more control-flow friendly approach like we used to have! I just don't yet see a solution that will allow this with consistent behaviour across all platforms. |
Yes, with the caveat that the thread receiving the callback is the caller's thread, and there's an internal event loop that we don't control sitting between
The MacOS problem is sticky because the normal event handling scheme can wander into an internal event loop. Sure, you can get callbacks at various points -- The current approach plumbs the user's callback all the way down so that the MacOS callbacks can trigger them. That delivers resize events as they happen, yes, but it breaks the contract in other ways. My changes in #219 address the core of that issue, which is that some parts of the MacOS event loop can block for a long time.
Callbacks are insufficient to solve the MacOS problem; if Emscripten bring me to another question: is this the wrong model entirely? Should How does Android fit in? |
Ahh you're totally right, this is a pretty major issue with the current implementation. For anyone else reading along here: As I just mentioned in #219, I'd forgotten to enable |
Well yes, but as it is right now, the EventsLoop runs for literally every event, causing the whole app to lag, because there are way too many events and the closure-based design blocks on every event. Try resizing a window with the new The old |
I wonder why these issues aren't getting solved. Winit is basically useless as it is now. You can choose between using 100% CPU ( |
I'm using it without issues (high CPU usage) like this: for (now, delta_t) in FpsLoop::new(60) {
events_loop.poll_events(|event| match event {
...
});
} My FpsLoop does the necessary sleeping. It's an "inversion of control" but in a good way, winit gives you the control of how fast you want to loop. |
@Boscop It seems you alternate between waiting for the timer and polling events, but you can't wait for the timer and listen to events at the same time. When rendering 60 frames per second, it may not be noticeable, but when drawing only occasionally, it doesn't work. I don't see why there can't be a function like |
@portstrom But the issue above says:
Ok, that's my use case, too.
Yes, that's what my
Why does it require that? It seems to work without that for me.. @portstrom I'm not trying to be a dick. What is your use case and why can't it be done by looping at high FPS and only drawing sometimes? |
@Boscop I'm trying to make a program that draws only after events (user interaction, fs/network input, timers above 1 second). I expect to make a loop that waits until there is an event, then processes all pending events, then draws. The first thing I try is |
@portstrom In case you are looking for a workaround, I ran into the same problem. I forked and backported important patches to both glium (https://github.com/fschutt/glium-backport/tree/glium_backport - use the branch "glium_backport") and vulkano (https://github.com/fschutt/vulkano-win-backport). They are the last versions to use the old API. I am currently using those because of this issue. So if you have old code depending on the old glium API, you can depend on those. If you have issues, I'll help to backport fixes. It's not a perfect solution, but it's something until this situation is resolved. I can't accept performance problems just because of a macOS weirdness (which I don't even use). |
@portstrom So you want to avoid unnecessary redrawing? Why not set a flag from within your |
@fschutt: the worst part is, the I describe the problem in #219, but it boils down to a fundamental design mismatch: That PR would fix the problem on MacOS, which would eliminate the only technical blocker in this issue. Having said that, the fundamental design disagreement remains: some platforms want to run the event loop themselves, and |
@Boscop No matter how the flag is set that will lead to 100% CPU usage. |
@willglynn Doesn't |
@portstrom Sure, that would work. Removing |
I agree that there is kind of a problem with the current API. This is especially noticeable on the emscripten port of winit where paint messages are being dispatched by the JS engine in order to make it work. However I cannot think of any reasonable solution at the moment. |
One option is to totally invert the control flow: struct MyApp();
impl winit::App for MyApp {
fn create_windows(&mut self, window_builder: &mut winit::WindowBuilder) {
// use window_builder
}
fn on_event(&mut self, event: winit::Event) {
match event {
WindowEvent::Closed => {
// tell winit to shut down
}
WindowEvent::KeyboardInput { ... } => {
// change state and re-paint
}
// …
}
}
}
fn main() {
winit::Main(MyApp());
} The user's |
It's not sufficient to invert the control flow - you also need to provide a way to send custom events, otherwise there's no way to wake up the main thread, winit already supports this though I think. If you can send custom events then it will be possible to implement futures-compatible reactor. Even then, the callback based approach may not always be appropriate, as sometimes you just do need more control. I propose that winit supports two APIs:
|
@Diggsey I'm can imagine some situations when callbacks might be inconvenient, but what is the specific use case you have in mind? The web platform in particular makes me think that the user might need to surrender the main thread to |
There are any number of reasons: porting existing code which is not written in a callback style, to building libraries on top of winit to name a couple. If two libraries make the decision to control the event loop then those libraries are forever incompatible. Inconvenience is also an important factor - I may not even care about the resizing issue on macos, as for many applications it doesn't matter if the loop blocks for that period of time, and yet to implement the basic primitive of "wait with timeout" the universal operation support by synchronous APIs, I have to:
Even then, there's still a race condition between the "wake up" and the next event coming in - I'm not really sure how you avoid that if you're forced (by winit and not the platform) to use multiple threads! The stack swapping feature is a nice-to-have workaround for a relatively minor platform-specific bug: replacing winit's old API with the current one because of this bug was a terrible mistake. |
I opened this issue to propose poll-with-timeout as a more useful common denominator: this would let you block inside the windowing system and regain control again after a fixed period. This doesn't change the fact that IMO, the main issue here is control over the main thread. Right now, users call Poll-with-timeout is a more useful common denominator, but it's not the lowest common denominator. The common interface that all platforms can share is to have the user surrender their thread to Inverting control flow would absolutely be a giant breaking change, but that doesn't avoid the question: which is the right model? Should the user call If the user should call If |
In the past I was against inverting flow control for "ideological" reasons. After all in a pre-emptive multitasking model, from the point of view of the application everything happens linearly. My point of view is that the API provided by the OS was wrong and existed for legacy reasons, and that we should abstract over it. Newer models such as wayland seem to comply to this model after all. However on the other hand I'm generally in favour of exposing the lowest-level possible API on top of the OS, in order to not add any overhead. In addition to this, the pre-emptive multitasking model of execution isn't compatible with the cooperative model of Emscripten, Android and iOS. Maybe one possibility would be to use the new upcoming coroutines feature of Rust and ask the user to yield whenever they want to query for events. |
I finally found a way to make a meaningful program with Winit. It only works on X11. An answer on Stack Overflow suggested using I found out I can get the connection number of a window like this: let connection_number = {
let connection = window.get_xlib_xconnection().unwrap();
let display = window.get_xlib_display().unwrap();
unsafe {
(connection.xlib.XConnectionNumber)(display as _)
}
}; Then I can use it to set up Mio: let mut events = mio::Events::with_capacity(1);
let poll = mio::Poll::new().unwrap();
poll.register(
&mio::unix::EventedFd(&connection_number),
mio::Token(0), mio::Ready::readable(),
mio::PollOpt::edge()
).unwrap(); When done calling let current_time = chrono::offset::Local::now();
let _ = poll.poll(&mut events, Some(::std::time::Duration::new(0, 1000000000 - current_time.timestamp_subsec_nanos()))); I hope the event loop in Winit will be fixed soon, so I don't have to do this manually in a way that uses unsafe code and only works with X11. |
Unfortunately, using the X connection fd like this does not work reliably, because OpenGL/vulkan implementations will do IO on that fd internally, causing unrelated events to be read early and read-readiness notifications to be missed. |
@Ralith Could you expand on it? I was just searching for more information on polling XConnectionNumber and found this issue. Could you give an example when it happens? What can one do then? Just to do a busy loop? Or send to yourself a fake event to wake it? But then it just needs to be on separate thread. |
This commit uses `.poll_events()` to allow processing multiple events per rendered frame. (Before, only one event was processed per frame.) This is necessary because it's easy for the user to generate events much faster than frames can be rendered (e.g. by moving the mouse). Additionally, with `.run_forever()`, rendering blocked on receiving events. (An event had to occur before a frame was rendered.) In order to see an animation such as the `particle` example, the user had to generate events fast enough to cause frames to be rendered (e.g. by moving the mouse over the window). See also rust-windowing/winit#276 and rust-windowing/winit#231
This commit uses `.poll_events()` to allow processing multiple events per rendered frame. (Before, only one event was processed per frame.) This is necessary because it's easy for the user to generate events much faster than frames can be rendered (e.g. by moving the mouse). Additionally, with `.run_forever()`, rendering blocked on receiving events. (An event had to occur before a frame was rendered.) In order to see an animation such as the `particle` example, the user had to generate events fast enough to cause frames to be rendered (e.g. by moving the mouse over the window). See also rust-windowing/winit#276 and rust-windowing/winit#231
1822: Switch from .run_forever() to .poll_events() in gfx_app r=kvark a=jturner314 This commit uses `.poll_events()` to allow processing multiple events per rendered frame. (Before, only one event was processed per frame.) This is necessary because it's easy for the user to generate events much faster than frames can be rendered (e.g. by moving the mouse). Additionally, with `.run_forever()`, rendering blocked on receiving events. (An event had to occur before a frame was rendered.) In order to see an animation such as the `particle` example, the user had to generate events fast enough to cause frames to be rendered (e.g. by moving the mouse over the window). See also rust-windowing/winit#276 and rust-windowing/winit#231 PR checklist: - [ ] `make` succeeds (on *nix) I don't see a Makefile. `make` says `make: *** No targets specified and no makefile found. Stop.` - [ ] `make reftests` succeeds I don't see a Makefile. I did run `cargo test`, though, and that succeeded (although it ran only 3 tests). - [X] tested examples with the following backends: When I run `glxinfo`, I see `OpenGL core profile version string: 3.3 (Core Profile) Mesa 17.3.3`. I tested all of the examples. They all worked correctly, except `terrain_tessellated` (which failed to build even before this commit) and `triangle` (which still has the `.run_forever()` issue since it doesn't use `gfx_app`).
So, if I'm understanding things correctly, combining what's been outlined here with the problems we have with Windows, then doesn't this mean that our current design is at odds with most platforms? |
This issue is a total showstopper. It's amazing that the maintainers don't seem to care. I'm still using the workaround I posted above, which only works on X11. I never had the problem that @Ralith mentioned. I've now published an example program made with winit, which unfortunately only works on X11. |
They care very much so - I believe most of the points in this issue are being addressed in #638 in @Osspial's heroic effort to rewrite the event loop, though I'm not familiar enough with the PR to know for sure if everything in this issue has been addressed. That PR is just about ready to go - feel free to have a look, test it and share any constructive input you might have. The maintainers are a group of collaborators working on this in their limited, free time and for many, winit is just one of many open source crates to which they contribute, each with their own slew of "showstopper" issues to address. |
Honestly, I understand being frustrated about the lack of visible progress - there are several issues that can't be fixed without updating the main event loop API, and the changes have been in the pipeline for... uh... oh jeez has it really been over six months? Those changes should land Very Soon, though. Anyhow, I'm going to close this issue in favor of #459 since that's where the discussion on the event loop API ended up getting finished. |
* refactor(windows): `begin_resize_drag` now similar to gtk's (rust-windowing#200) * refactor(windows): `begin_resize_drag` now similart to gtk's * fix * feat(linux): skipping taskbar will now also skip pager (rust-windowing#198) * refactor(linux): clean dummy device_id (rust-windowing#195) * refactor(linux): clean dummy device_id * fmt * feat(linux): allow resizing undecorated window using touch (rust-windowing#199) * refactor(windows): only skip taskbar if needed when `set_visible` is called (rust-windowing#196) * fix: increase borderless resizing inset (rust-windowing#202) * fix: increase borderless resizing inset * update some comments * Replace winapi with windows crate bindings shared with WRY (rust-windowing#206) * fix(deps): update rust crate libayatana-appindicator to 0.1.6 (rust-windowing#190) Co-authored-by: Renovate Bot <[email protected]> * Add Windows crate and webview2-com-sys bindings * Initial port to webview2-com-sys * Finish conversion and remove winapi * Fix renamed lint warning * Fix all match arms referencing const variables * Put back the assert instead of expect * Point to the published version of webview2-com-sys * Cleanup slightly weird BOOL handling * Replace mem::zeroed with Default::default * Add a summary in .changes * Remove extra projects not in config.json * Fix clippy warnings * Update to 32-bit compatible webview2-com-sys * Better fix for merge conflict * Fix clippy errors on Windows * Use path prefix to prevent variable shadowing * Fix Windows clippy warnings with nightly toolchain * Fix Linux nightly/stable clippy warnings * Fix macOS nightly/stable clippy warnings * Put back public *mut libc::c_void for consistency * Re-run cargo fmt * Move call_default_window_proc to util mod * Remove unnecessary util::to_wstring calls * Don't repeat LRESULT expression in match arms * Replace bitwise operations with util functions * Cleanup more bit mask & shift with util fns * Prefer from conversions instead of as cast * Implement get_xbutton_wparam * Use *mut libc::c_void for return types Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Renovate Bot <[email protected]> * fix(keyboard): add mapping for space key on Windows (rust-windowing#209) * fix(keyboard): add mapping for space key on Windows * change file * feat: impl Clone for EventLoopWindowTarget (rust-windowing#211) * chore: add `on_issue_closed.yml` (rust-windowing#214) * Update tray dependency version (rust-windowing#217) * Delete on_issue_closed.yml (rust-windowing#221) * refactor(linux): event loop (rust-windowing#233) * Use crossbeam::channel * Fix crossbeam channel import * Add check on poll event * Fix deadlock when unregistering shortcut on Linux (rust-windowing#230) * Add fullscreen monitor selection support on Linux (rust-windowing#235) * Add fullscreen monitor support on Linux * Add change file * Remove todo on videomode * Fix clippy * Update to 2021 edition (rust-windowing#236) * Update to 2021 edition * Fix clippy * Add run_return on Linux (rust-windowing#237) * Add run_return on Linux * Add main context * Add run_return trait on Linux (rust-windowing#238) * Fix: rust-windowing#239 Update webview2-com and windows crates (rust-windowing#240) * Replace webivew2-com-sys with prebuilt windows * Use windows utility instead of direct GetLastError * Bump windows version and add changelog * Run cargo fmt * Restore inverted matches macro * Scope constants in match arms * Fix inverted null check * Update src/platform_impl/windows/util.rs Co-authored-by: Amr Bashir <[email protected]> * Use env_logger instead of simple_logger (rust-windowing#241) * Use env_logger instead of simple_logger * Make clippy happy * Cherry pick commits to next (rust-windowing#244) * feat(macos): Add `unhide_application` method, closes rust-windowing#182 (rust-windowing#231) * feat(macos): Add `unhide_application` method * Update src/platform/macos.rs Co-authored-by: Amr Bashir <[email protected]> * Reanme to `show_application()` * Remove broken doc link Co-authored-by: Amr Bashir <[email protected]> * feat: Allow more strings to parse to keycode (rust-windowing#229) * feat: support accelerator key strings `,` `-` `.` `Space` `Tab` and `F13`-`F24` (rust-windowing#228) * feat(macOS): support more accelerator key strings * Move function keys together * Add `,` `-` `.` `Space` `F20-F24` for Windows * Remove support for accelerators not found in `winapi` * Add `,` `-` `.` `Space` `F13-F24` for Linux * Update .changes * Add the rest for Windows * Add the rest for Linux * Add the rest on macOS * Update accelerator-strings.md * Fix git comments Co-authored-by: Kasper <[email protected]> Co-authored-by: Amr Bashir <[email protected]> * Add redraw events on Linux (rust-windowing#245) * Add redraw events on Linux * Update doc of RequestRedraw Event * Add change file * Fix missing menu bar on borderless window (rust-windowing#247) Credit goes to irh's work on winit commit f2de847 * refactor: improve `set_skip_taskbar` impl on Windows (rust-windowing#250) * fix: emit errors on parsing an invalid accelerator for string, closes rust-windowing#135 (rust-windowing#252) * chore: update comment * fix(linux): fix focus events not firing properly (rust-windowing#253) * fix(linux): fix focus events not firing properly * add changelog * chore: update focus events error message * chore: fmt * fix: revert windows-rs 0.28 version bump * fix(linux): fix native menu items (rust-windowing#256) * chore: remove examples commited by accident * Update `ReceivedImeText` (rust-windowing#251) * Allow receiving text without Ime on Windows * Avoid panic todo * Receive text without ime on mac * Fix CursorMoved event on Linux * Add ReceivedImeText on Linux This only add Simple IME from GTK for now. We should add the actual IME from system in the future. * Fix redraw event that causes inifinite loop (rust-windowing#260) * Fix redraw event that causes inifinite loop * Refactor event loop * Remove unused function * Add doc comment on linux's run_return * Ignore doc test on run_return * Add non blocking iteration on Linux (rust-windowing#261) * Docs: SystemTrayExtWindows::remove() is gone (rust-windowing#262) Fix docs following rust-windowing#153 * Fix busy loop on Linux (rust-windowing#265) * Update windows crate to 0.29.0 (rust-windowing#266) * Update to windows 0.29.0 * Add change description * Remove clippy check (rust-windowing#267) * refactor(windows): align util function with win32 names * chore: update PR template * fix(linux): fire resized & moved events on min/maximize, closes rust-windowing#219 (rust-windowing#254) * feat(linux): implement `raw_window_handle()` (rust-windowing#269) * chore(deps): update to raw-window-handle 0.4 * add linux raw-window-handle support * update macos/ios/android * fix ios * Fix core-video-sys dependency (rust-windowing#274) * The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#275) However, this does not work on macOS 10.7 (where AppKit does not link to ColorSync internally). Instead of relying on this, we should just link to ApplicationServices directly. * Fix some invalid msg_send! usage (rust-windowing#276) * Revert "Fix some invalid msg_send! usage (rust-windowing#276)" (rust-windowing#277) This reverts commit a3a2e0cfc49ddfa8cdf65cf9870fb8e3d45b4bc0. * Revert "The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#275)" (rust-windowing#279) This reverts commit 6f9c468f26ddb60e29be2139397bfaf3b30eab1e. * The `cocoa` crate links to AppKit, which made the symbol `CGDisplayCreateUUIDFromDisplayID` from ApplicationServices/ColorSync (which AppKit uses internally) available to us on macOS 10.8 to 10.13. (rust-windowing#280) However, this does not work on macOS 10.7 (where AppKit does not link to ColorSync internally). Instead of relying on this, we should just link to ApplicationServices directly. Co-authored-by: madsmtm <[email protected]> * Fix some invalid msg_send! usage (rust-windowing#278) Co-authored-by: madsmtm <[email protected]> * Add exit code to ControlFlow::Exit (rust-windowing#281) * Add exit code to ControlFlow::Exit * Cargo fmt * Add change files Co-authored-by: multisn8 <[email protected]> * Add new_any_thread to Unix event loop (rust-windowing#282) * Update windows crate to 0.30.0 (rust-windowing#283) * Update windows crate to 0.30.0 * Simplify new-type usage * Fix boxing in GWL_USERDATA * Make sure everyone is using Get/SetWindowLongPtrW * build the system_tray module when "ayatana" feature is enabled (rust-windowing#285) Without those cfg feature checks, the "ayatana" feature does actually not enable anything. * Fix click events missing whe tray has menu (rust-windowing#291) * Fix click events missing whe tray has menu * Add change file * Fix crash when tray has no menu (rust-windowing#294) * chore: update pull request commit exmple * fix(windows): send correct position for system tray events, closes rust-windowing#295 (rust-windowing#300) * fix(windows): revert maximized state handling to winit impl, closes rust-windowing#193 (rust-windowing#299) * fix(windows): revet maximized state handling to winit impl, closes rust-windowing#193 * add chanefile [skip ci] * fix: `MenuItem::Quit` on Windows (rust-windowing#303) * fix: `MenuItem::Close` on Windows * use `PostQuitMessage` instead Co-authored-by: amrbashir <[email protected]> * feat: v1 audit by Radically Open Security (rust-windowing#304) * Update to gtk 0.15 (rust-windowing#288) * Update to gtk 0.15 * Fix picky none on set_geometry_hint * Fix CursorMoved position Co-authored-by: Amr Bashir <[email protected]> Co-authored-by: Bill Avery <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Renovate Bot <[email protected]> Co-authored-by: Lucas Fernandes Nogueira <[email protected]> Co-authored-by: Kasper <[email protected]> Co-authored-by: amrbashir <[email protected]> Co-authored-by: Jay Oster <[email protected]> Co-authored-by: madsmtm <[email protected]> Co-authored-by: multisn8 <[email protected]> Co-authored-by: Aurélien Jacobs <[email protected]> Co-authored-by: Lucas Fernandes Nogueira <[email protected]>
* feat(macos): Add `unhide_application` method, closes rust-windowing#182 (rust-windowing#231) * feat(macos): Add `unhide_application` method * Update src/platform/macos.rs Co-authored-by: Amr Bashir <[email protected]> * Reanme to `show_application()` * Remove broken doc link Co-authored-by: Amr Bashir <[email protected]> * feat: Allow more strings to parse to keycode (rust-windowing#229) * feat: support accelerator key strings `,` `-` `.` `Space` `Tab` and `F13`-`F24` (rust-windowing#228) * feat(macOS): support more accelerator key strings * Move function keys together * Add `,` `-` `.` `Space` `F20-F24` for Windows * Remove support for accelerators not found in `winapi` * Add `,` `-` `.` `Space` `F13-F24` for Linux * Update .changes * Add the rest for Windows * Add the rest for Linux * Add the rest on macOS * Update accelerator-strings.md * publish new versions Co-authored-by: Kasper <[email protected]> Co-authored-by: Amr Bashir <[email protected]> Co-authored-by: wusyong <[email protected]> Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <[email protected]>
EDIT: THIS ISSUE HAS BEEN SUPERSEDED by #459.
In #219, I examined some unfortunate event handling complexities on MacOS X. That examination led me to view and re-implement both
poll_events()
andrun_forever()
as special cases of a more general API,get_event(Timeout) -> Option<Event>
.I propose:
get_event(Timeout)
interface,poll_events()
andrun_forever()
to be implemented in terms ofget_event(Timeout)
, andpoll_events()
andrun_forever()
in favor ofget_event(Timeout)
.This is a user-facing API change, so I'm accompanying this proposal with a larger than usual explanation.
Receive-with-time-constraint is the fundamental operation
poll_events()
allows the user to communicate "I want all the events that are ready, but I don't want you to wait". Let's call thatget_event(Timeout::Now)
, and make the loop explicit:run_forever()
allows the user to communicate "I want all the events until I tell you to stop", which… is kind of weird, isn't it? At any rate, it's the user's intention to block indefinitely and eventually break out of the loop. Let's call thatget_event(Timeout::Forever)
, and again push down the loop:Some users have additional needs, like "I want all the events between now and when I need to update my state/draw the next frame".
pistoncore-glutin_window
does this today by unconditionally spawning a thread that wakes up the event loop after a fixed period of time. We should be able to support it efficiently on every platform without needing extra threads, and with a timeout-centric API, we can:Timeouts are sufficient to justify a new API
Consider a game that wants to update and render at 60 fps. If the game is running faster than 60 fps, it should sleep and wait until it's time to start the next frame; if it's running slower, it should busy-wait.
This use case presently requires a calling
run_forever(callback)
to allow the thread to sleep, plus a second thread keeping track of time and callingProxy::wakeup()
as needed. That's wasteful and unnecessarily complex.winit
should support timeouts pattern directly. Additionally, this is a common requirement; every event loop has some way to block until a specified time, or some idiomaitc way to synthesize a timeout.winit
should use this where appropriate.Simplifies the API
winit
puts user code at the bottom of the stack, and does not force the user to organize their code in terms of callbacks… except for event handling. Changing the API so that the user callsget_event(Timeout)
in a loop adds consistency, and it lets the user define and manage their event loop with normal Rust statements instead of a callback that returns aControlFlow
enum.This also makes
EventsLoop
look more like afutures::stream
, or a generator, or many other things that users might already know. "I want to get a message from you" requires less explanation than having two different functions that take two different callbacks.Reduces duplication
poll_events()
andrun_forever()
have considerable overlap, and in the case of the MacOS platform, considerable code duplication. Not only canget_event(Timeout)
provide more functionality, in the case of the MacOS platform, refactoring into this caused a net reduction in code.Low risk
It's very easy to implement
poll_events()
andrun_forever()
in terms ofget_event(Timeout)
, which means there's very little risk in deciding to move that direction.winit
can continue to provide the samepoll_events()
+run_forever()
API to the user while refactoring platforms intoget_event(Timeout)
behind the scenes. Once they're all ready,winit
can update the examples, deprecatepoll_events()
andrun_forever()
, and ultimately remove at some later point.Next steps
I think this covers everything:
A change like this requires buy-in, and this isn't my project, so I don't know what all would need to happen. I'm happy to start by soliciting feedback, so: what does everyone think?
The text was updated successfully, but these errors were encountered: