| Crates.io | lenient_winit |
| lib.rs | lenient_winit |
| version | 0.2.3 |
| created_at | 2025-10-12 05:06:16.60427+00 |
| updated_at | 2025-10-12 05:06:16.60427+00 |
| description | A wrapper around winit to provide a nicer experience for developers. Experience similar to SDL2/GLFW |
| homepage | https://github.com/RustyCrabs100/lenient_winit |
| repository | https://github.com/RustyCrabs100/lenient_winit |
| max_upload_size | |
| id | 1878919 |
| size | 70,901 |
This crate is designed to wrap around winit, as to simplify the experience of many people.
Think of this as a more high-level winit, where the main pain points are already dealt with.
This acts less like regular winit, but more like an SDL2/GLFW kind of experience.
This crate is very simple to use. Simply call the run() function, and you can call poll_events() wherever you wish, excluding the main thread.
use lenient_winit::window;
fn main() {
let mut app = window::App::default();
// Don't do this unless your replacing it with non-default attributes
// This is just to showcase the function
app.replace_window_attributes(window::WindowAttributes::default());
std::thread::spawn(|| {
'main: loop {
#[cfg(test)]
{
break 'main;
}
#[cfg(not(test))]
for event in window::App::poll_events() {
match event {
_ => {}
}
}
}
});
app.run(window::ControlFlow::Poll)
.expect("Event Loop Error");
}
It really is that simple!
Now, the above example was for our single-window system, our multi-window system uses lenient_winit::multi_window, and is slightly more complicated.
It shouldn't be that much different from the single-window system, just that all events are paired with their corresponding WindowId.
For our multi-window system, this is how you use it:
use lenient_winit::multi_window;
use lenient_winit::window;
fn main() {
let mut app = multi_window::MultiApp::default();
for _ in 1..5 {
app.add_window_attributes(window::WindowAttributes::default());
}
std::thread::spawn(|| {
'main: loop {
#[cfg(test)]
{
break 'main;
}
#[cfg(not(test))]
for event in multi_window::MultiApp::poll_events() {
match event {
_ => {
println!("Testing Testing");
}
}
}
}
});
app.run(window::ControlFlow::Poll)
.expect("Event Loop Error");
}
Currently everything displayed in the documentation is available to be used, and whenever we add new features, anything hidden/missing will be shown in the documentation.
Whenever we update, it won't be a breaking change, as the things you do using this crate should remain mostly the same. The only changes we will do are normal changes, where only the backend changes. However, sometimes breaking changes are necessary.
Whenever a breaking change happens, it's usually 1 of 2 things:
Now, we will try to make sure breaking changes don't happen, but if it ever does, a new branch will be made. We will also increment the major version by 1.
run() function. While this isn't a limitation if you look at it's surface value, once you take a deep look into it, it's quite the limitation.run() function, once executed, consumes itself, and takes full control over the main thread. Do any work prior windowing or in a seperate thread.Currently, once you use the run() function, the main loop is no longer yours.
You can never use it again, which means you have to do the rest of your work in a different thread.
We are working to get rid of this, however, the normal run() function will always be available.
This is because the method to let the user keep the main loop is NOT cross-platform.
The only method we can use is not available for iOS, MacOS, and the Web.
This is because the main loop must be owned by the windowing system for these platforms.
This limitation does not come from lenient_winit, but instead from the operating system.
In lenient_winit, we classify breaking changes as anything that significantly impacts the user.
This includes making the user change their code significantly, rethink their model, or increase their compile times significantly.
What we DON'T classify as a breaking change would be adding a small dependency, removing a non-exposed dependency, or renaming a certain item.
The only time we do classify those as breaking changes, is if it breaks the backend, requires more effort than necessary for the change, or noticeably lowers performance.
Examples:
Versioning will only apply once this crate gets posted on crates.io, until then, we are free to add and remove things at free will.
Certain items that are necessary to be used have been re-exported, but if anything that you require is not being re-exported, create an issue on our repository or create a pull request and do it yourself. There is also the option to add winit as a direct dependency if necessary.
Our versions are written as Major.Minor.Patch-Release.
Some versions will omit the -Release part of the version, however most will include it.
The -Release portion defines the stability of the version.
If the -Release portion is missing, then the version is stable.
If the -Release portion is included, then the stability is less than reliable, but it's reliability varies depending on the name.
This -Release portion can be many things, but these are the 4 main one's we will use.
-prealpha: VERY not stable. Many thing's are still being figured out. Be warned...-alpha: Not stable, but still usable. This is where either many things are untested or volatile.-beta: Slightly stable. You can use this with moderate worry about it breaking, but most common uses are stable.-nightly: This one is special; it can be included alongside the other 3 (written as -Version_nightly). This means that this version uses experimental methods, either lacking testing or being very experimental. If left by itself, it means that this version IS stable, but requires a nightly version of rust.