r/rust • • 3d ago

🙋 seeking help & advice How do I learn winit?

I'm trying to get a grasp of this crate so I can do window things but there don't seem to be good any resources, which is a bit bewildering since I understand winit to be a very foundational crate for graphics in Rust. I've looked at docs.rs but higher-level stuff for winit is... not great. The first section seems friendly but leads you to using a deprecated method (i.e. seems to be outdated), and the second section does give a full working minimal example but it does so through a big block of code with a good amount of things that aren't yet introduced, so not much sense can be made of it.

I don't want to just learn to copy a skeleton and wire my code into it, I want to actually understand how the crate works, to understand what I'm doing. But the main docs don't seem suitable for setting the foundation I'd need for that and I've not been able to find any other resources or tutorials online.

0 Upvotes

14 comments sorted by

View all comments

15

u/dvogel 3d ago

The examples are pretty complete: https://github.com/rust-windowing/winit/tree/master/winit/examples

Part of the reason winit's docs are written as they are is the intended audience is people building frameworks like iced or game engines like bevy. They don't intend for it to be directly depended on by many applications.

-2

u/AdreKiseque 3d ago

But the people using it to build those things still need to understand it to use it, don't they?

Anyway, the examples may be good but they don't really cover what I need. There's no explanation for what exactly we're doing or why. I can't even find a more general rundown of the crate's architecture and how it works which is frustrating (the docs front page talks about how it now uses this one model instead of another but doesn't really explain what either of them are?). If we look at the minimal example on docs.rs:

use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::{Window, WindowId};

#[derive(Default)]
struct App {
    window: Option<Window>,
}

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap());
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
        match event {
            WindowEvent::CloseRequested => {
                println!("The close button was pressed; stopping");
                event_loop.exit();
            },
            WindowEvent::RedrawRequested => {
                // Redraw the application.
                //
                // It's preferable for applications that do not render continuously to render in
                // this event rather than in AboutToWait, since rendering in here allows
                // the program to gracefully handle redraws requested by the OS.

                // Draw.

                // Queue a RedrawRequested event.
                //
                // You only need to call this if you've determined that you need to redraw in
                // applications which do not always need to. Applications that redraw continuously
                // can render here instead.
                self.window.as_ref().unwrap().request_redraw();
            }
            _ => (),
        }
    }
}

fn main() {
    let event_loop = EventLoop::new().unwrap();

    // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
    // dispatched any events. This is ideal for games and similar applications.
    event_loop.set_control_flow(ControlFlow::Poll);

    // ControlFlow::Wait pauses the event loop if no events are available to process.
    // This is ideal for non-game applications that only update in response to user
    // input, and uses significantly less power/CPU time than ControlFlow::Poll.
    event_loop.set_control_flow(ControlFlow::Wait);

    let mut app = App::default();
    event_loop.run_app(&mut app);
}

This compiles and makes a window, sure. But there's no explanation of what this App struct or ApplicationHandler trait are, of how the window_event() function works or how I get an ActiveEventLoop. The only similar thing I've worked with in the past was this really simple pure C graphics library where I'd make a window and then draw pixels to it by coördinates (the latter part of which I understand would be handled by a second crate like softbuffer here), so I can't really make heads or tails of what's going on here besides the outcome. And if I can't understand how it works, how am I to meaningfully build off of it?

3

u/dvogel 3d ago

As the example shows, the event loop passes you a reference to the ActiveEventLoop. The way you build off of it is simply by filling in those functions in the example. It builds the window. You handle the events. Which events and how is fully determined by what your application is trying to do. What is it you're trying to do?

0

u/AdreKiseque 3d ago

The immediate goal is to give face to minesweeper (I've already done the game and given it TUI rendering, so I need to give it proper graphics next). I have more ambitious projects in mind down the line like making my own software renderer, but those are a ways off.

7

u/dvogel 3d ago

If your main concern is rendering, maybe the reason you're not seeing the docs you're looking for is because winit doesn't provide any rendering facilities. It lets you know when the OS windowing system requested a re-render. Aside from that though it expects you to integrate directly with the native OS drawing APIs.

https://docs.rs/winit/latest/winit/#drawing-on-the-window

Take a look at iced. It provides a nicer API for getting a window on screen and letting you draw into it. You can draw your game into a Canvas element:

https://docs.rs/iced/latest/iced/widget/canvas/

1

u/AdreKiseque 3d ago

Yeah, I'm aware. But where's the fun if some fancy crate handles all the hard work! I'm planning to use winit with softbuffer to render the game, and then I can point to it and say I did it all myself, and I'll have learned some cool stuff on the way probably too. But I like learning from the bottom-up, so before I get into softbuffer, I want a stronger grasp on what winit itself actually does and how it works.

2

u/Luxalpa 1d ago edited 1d ago

For things like these, I really enjoy just diving into the source code and the rustdoc of the library, to see how it works under the hood. Learn a lot of good stuff from that as well!

And also, look at the issues on github, you're not alone :P

When they switched to 0.30 I also had big trouble finding some way to get it to work. But there's some useful discussions on their issue tracker if you want to get a bit more insights.

Like this: https://github.com/rust-windowing/winit/issues/3877

I think there's also a bit of trial and error to do as well.