---
# System prepended metadata

title: Winit meeting 2024-01-25

---

# Winit meeting

Date: 2024-01-26T14:00:00Z (UTC)

Attended: @madsmtm, @daxpedda, @kchibisov

Last meeting notes: <https://hackmd.io/vvcTgQEmTIa8nyPR8vxJ_w>


## Organizational

Make these HackMDs public, at least post on Matrix? Should we keep a historic account of meeting notes? @madsmtm has created an account, so they're at least stored there now (also, you don't seem to be able to change the title without an account).
- Should we even use HackMD? Are there better tools for this kind of stuff? Google Docs?
- How much should we use Discord? (Ideally not for anything other than the call, )

- Conclusion: Post HackMDs on Matrix before the call.
- (Optional?) Post summary on github discussions in a thread for meetings.

How are the meeting notes as laid out here? Are they fine, or should we do something else?
- They're fine.

Move more discussion to GitHub, but inside `winit` repo, not `winit-next`.
- Communicate [upgrade plan](https://hackmd.io/vvcTgQEmTIa8nyPR8vxJ_w#Upgrade-plan) for everyone to follow along, probably on <https://github.com/rust-windowing/winit/issues/3367>.
- Document weekly meetings and core team _somewhere_.

Communicate bigger changes in changelog.
- Example of how docs are done right https://docs.rs/winnow/
- Move changelog to docs.rs (cargo doc as well)?

Are GitHub Discussions worth it? To me, it just seems like two places to have issues...
- Useful for user questions.
- Maybe move user questions inside issues to discussions?
- Postponed to later


## User communication

What's the best way to communicate why `v0.30` changes are to be had? A new GitHub issue/discussion that outlines the reasoning and migration steps, and then users can comment there why their use-case doesn't work with the new design? Or note this in the changelog, and encourage users to open new issues for each complaint? I think having an existing issue is lower-friction for feedback.
- Open issue for 0.30 planning and pin it(and make it accesible for maintainers only, how it was done for 0.29), and also link to discussion thread for users to ask/complain.

Draft text for the trait rework at the bottom, other big changes will need a similar thing.


## Event handling and hooks

`tracing-subscriber` and why that doesn't work?

<https://matrix.to/#/!DGpLzJTRzBDTwZiogk:matrix.org/$M2KtcQIpR0OMKpf_Z2HiTFbei-VgoRuwMrxhfXereoc?via=matrix.org&via=ralith.com&via=mozilla.org>

Maybe trait that is used both for users and subscribers.

```rust

impl ApplicationHandler for EguiContext {
    ...
}

impl ApplicationHandler for App {
    ...
}

let mut state = ...;

event_loop.run(|runner| {
    // This closure is run on every event.
    
    // subscriber
    if runner.run(&mut state.egui_context) {
        // event was consumed
        return
    }

    // user
    runner.run(&mut state.app);
});

// Internally

struct BackendState {
    winit: Winit,
    runner: Box<Fn(Runner)>
}

// Called when I get an event from Wayland connection.
fn resize(&mut self, window_id: WindowId, new_size: Size) {
    user_state = &mut state.app;
    user_state.resize(&mut state.winit, window_id, new_size);
    // Push back to event_sink: Vec<Event>.

    let mut new_size = None;
    self.runner.call(|app: &mut dyn ApplicationHandler| {
        new_size = Some(app.resize(window_id));
    });
}
```

Make sure you can always just not return anything, and just have some default behaviour? Are there methods that will be required?

Events with special default behaviour:
- CloseRequested: Deny closing?
- Scaling Wayland: ?


#### Meeting stopped around here ####
<hr>

Other idea:



```rust
// (ab)use type-system magic to use closures and avoid implementing a trait
struct App {
    // ... state
}
event_loop
    .with_state(App { ... })
    .on_wakeup(|state, active, start_cause| {
        match start_cause {
            // ...
        }
    })
    .on_window_event(|state, active, window_id, event| {
        match event {
            // ...
        }
    })
    .run()?;
```


## Dropping `Window`

[#3317](https://github.com/rust-windowing/winit/issues/3317)


## @madsmtm's GitHub nitpicking

Get rid of the [Testers and Contributors table](https://github.com/rust-windowing/winit/wiki/Testers-and-Contributors), and the wiki in general.

Get rid of `FEATURES.md`, replace with a section in the `README.md` that documents the intended scope only.

Add [issue templates](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/about-issue-and-pull-request-templates) so we don't have to waste time asking users which platform they're using.




---
---

Will need to be adjusted once [#3386](https://github.com/rust-windowing/winit/pull/3386) lands.

# We're changing Winit's event loop callback

Hey everyone!

There are some big changes in Winit `v0.30` that are going to affect you.

In particular, we're changing the event loop callback from a closure to a trait-based system. This is done in anticipation of [further design changes](https://github.com/rust-windowing/winit/issues/3367), but will primarily enable you to return values back to the event loop - which in turn will allow us to correctly implement oft-requested features like clipboard access, drag and drop, better IME, and so on.

## Migration

The migration _should_ be fairly straightforward, although it will probably take a bit of time and manual work.

The key change is that instead of `event_loop.run` taking a closure, you must now create a new type that implements the `ApplicationHandler` trait, and which contains the state that was previously implicit in the closure, see the following code example.


```rust
// Before
let mut click_counter = 0;
let mut window = None;

event_loop.run(|event, window_target| {
    dbg!(event);
    match event {
        Event::NewEvents(StartCause::Init) => {
            window = Some(Window::new().build(window_target));
        }
        Event::WindowEvent { event, window_id } => {
            match event {
                WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => {
                    self.click_counter += 1;
                    if let Some(window) = window.as_ref() {
                        window.set_title(format!("clicked {click_counter} times"));
                    }
                }
                _ => {
                    // .. handle other window events
                }
            }
        }
        _ => {
            // .. handle other events
        }
    }
})?;

// After
struct App {
    my_counter: i32,
    window: Option<Window>,
}

impl App for ApplicationHandler {
    fn all_events_hook(&mut self, active: ActiveEventLoop<'_>, event: &Event) {
        dbg!(event);
    }

    fn wakeup(&mut self, active: ActiveEventLoop<'_>, start_cause: StartCause) {
        if let StartCause::Init = start_cause {
            self.window = Some(active.create_window(WindowAttributes::new()));
        }
    }

    fn window_event(
        &mut self,
        active: ActiveEventLoop<'_>,
        window_id: WindowId,
        event: WindowEvent,
    ) {
        match event {
            WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => {
                self.click_counter += 1;
                if let Some(window) = self.window.as_ref() {
                    window.set_title(format!("clicked {} times", self.click_counter));
                }
            }
            _ => {
                // .. handle other window events
            }
        }
    }

    // .. handle other events
}

event_loop.run(App {
    click_counter: 0,
    window: None,
})?;
```


## Feedback

If you run into any problems with migrating, please feel free to submit feedback on this issue, especially if you have use-cases that are not possible, or are more difficult to do with the new design.
