Hello, all!
I'm one of the maintainers of Winit, the main pure-Rust window creation library written. Even if you haven't used it directly, you've probably heard of projects that depends on it - Servo and Alacritty being the best-known applications that depend on our codebase. If you've done any graphics programming in Rust using Glutin (or dependent projects including gfx-rs, Glium, and Amethyst) we've been the ones making the windows actually show up on your desktop.
There are a few important announcements I'd like to make:
The highlight of this release is the final major overhaul of Winit's core Event Loop API. This change vastly improving Winit's stability and introduces a few quality-of-life upgrades, such as native timer support and an API for injecting custom user events into the Winit event loop. For example:
#[derive(Debug, Clone, Copy)]
enum CustomEvent {
Timer,
}
let event_loop = EventLoop::<CustomEvent>::new_user_event();
// `EventLoopProxy` allows you to dispatch custom events to the main Winit event
/// loop from any thread.
let event_loop_proxy = event_loop.create_proxy();
let timer_length = Duration::new(1, 0);
event_loop.run(move |event, _, control_flow| {
match event {
// When the event loop initially starts up, queue the timer.
Event::NewEvents(StartCause::Init) => {
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
},
// When the timer expires, dispatch a timer event and queue a new timer.
Event::NewEvents(StartCause::ResumeTimeReached{..}) => {
event_loop_proxy.send_event(CustomEvent::Timer).ok();
*control_flow = ControlFlow::WaitUntil(Instant::now() + timer_length);
},
Event::UserEvent(event) => println!("user event: {:?}", event),
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
*control_flow = ControlFlow::Exit;
},
_ => ()
}
});
This release also cleans up Winit's API, universally improving both its internal consistency and its consistency with the rest of the Rust ecosystem.
There are a few reasons we're introducing this as an alpha:
- All implementations still need thorough testing, and some platforms still have major, application-breaking bugs.
- We'd like to merge an overhaul of Winit's HiDPI API, but the overhaul is only implemented on Windows.
However, we lack the personnel necessary to implement those changes!
That segues nicely into the second point I'd like to bring up: for such a core piece of infrastructure
in the Rust ecosystem, we have astonishingly little manpower. Only three of the seven platforms we support
have active maintainers: X11, macOS, Android, iOS, and WASM are all largely unmaintained, despite their
importance! Additionally, Glutin is currently maintained by just a single person, despite being a project
no lone individual has the time to handle. This had led to a great deal of issue buildup on those platforms,
since we lack contributors with enough time to debug and resolve issues on those platforms. Major new features
and API improvements can't land on crates.io
since we currently can't implement them across all platforms -
gamepad support being the most significant (although certainly not only) example.
If you are interested in Rust becoming a larger force in graphics ecosystem, please take a look at the issues below and find one you can contribute to! We encourage all types of contributions, so go out and write, test, review, and submit PRs, add and review documentation, and whatever else you would like to do. No matter what you do, your time would be very much appreciated, and would result in widespread improvements across the Rust community.
- Sign up on a testing list for any platform we support
- Gamepad support on all non-Windows platforms:
- X11 bugfixing
- macOS bugfixing
- Android's Eventloop 2.0 implementation
- iOS features and bugfixing (link)
- Maintainers for the following platforms:
- macOS
- X11
- Android
- iOS
poll_events
only functions as expected on Linux.
All other platforms break in some way with applications built around poll_events
- some breaking
in subtle ways, others breaking completely. For example, when a user resizes the application's
window, Windows* and macOS freeze the main event loop completely if the event loop uses
poll_events
. On the more extreme end, Mobile and Web platforms don't ever return from
poll_events
, completely breaking any application that relies on poll_events
functioning.
As much as we'd like to expose poll_events
as an API, the reality is that we cannot expose it
without fundamentally lying about its cross-platform functionality.
* You might notice that calling poll_events
on Windows in legacy Winit doesn't
freeze the event loop. This is because legacy Winit spawns an entire background thread to run
the Windows event loop in order to hide the freezing behavior. This has caused innumerable
amounts of stability and UX problems, and moving to the new event loop model is the only way to
fix those issues without creating an unstable tower of hacks.
Yep! The run_forever
API has been renamed to run
, and received a few major usability upgrades:
- You now receive an event when the platform event queue has been drained, allowing you to bundle your application logic into a single event handler.
- New windows can be created within the event handler closure, using the
EventLoopWindowTarget
field. - You can now set timers in the event loop, adding proper support for framerate limiters and other timer-based functionality.
These new features make run
actually usable in a real application, and should more than compensate
for poll_events
' removal.
It was the only way for us to expose a single API that more or less behaves the same way on all platforms.
Admittedly, it isn't necessary on desktop platforms (Windows, macOS, and Linux). However, Android, iOS, and WASM all require the host platform take exclusive control over the application's event loop, and this API allows us to expose that behavior under the same API as our desktop backends.
If, for whatever reason, you absolutely must be able to return from the run
function, we expose
[run_return
](LINK TO DOCS) on our desktop platforms. We'd discourage using that unless absolutely
necessary, since it breaks cross-platform compatibility and can lead to subtle bugs on desktop
platforms if used improperly.
There were several small details in Winit's public API that we weren't happy with, but required breaking changes to fix. Since we were already breaking downstream applications with the new event loop API, we decided to try bundling all our desired breaking changes into a single release instead of painfully staggering them out over several point releases. This will make upgrading to 0.20 a bit more of a hassle, but should make the API significantly easier to use going forward.
Unfortunately we didn't quite manage to include all the breaking changes we wanted this release, but breaking changes in the future should be significantly less disruptive and will be bundled with major feature releases.
Wow, there were an embarrassing number of mistakes there. Thank you so much!