Trait winit::platform::pump_events::EventLoopExtPumpEvents

source ·
pub trait EventLoopExtPumpEvents {
    type UserEvent: 'static;

    // Required method
    fn pump_events<F>(
        &mut self,
        timeout: Option<Duration>,
        event_handler: F
    ) -> PumpStatus
       where F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop);

    // Provided method
    fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
        &mut self,
        timeout: Option<Duration>,
        app: &mut A
    ) -> PumpStatus { ... }
}
Available on windows_platform or macos_platform or android_platform or x11_platform or wayland_platform only.
Expand description

Additional methods on EventLoop for pumping events within an external event loop

Required Associated Types§

source

type UserEvent: 'static

A type provided by the user that can be passed through Event::UserEvent.

Required Methods§

source

fn pump_events<F>( &mut self, timeout: Option<Duration>, event_handler: F ) -> PumpStatus
where F: FnMut(Event<Self::UserEvent>, &ActiveEventLoop),

👎Deprecated: use EventLoopExtPumpEvents::pump_app_events

Provided Methods§

source

fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>( &mut self, timeout: Option<Duration>, app: &mut A ) -> PumpStatus

Pump the EventLoop to check for and dispatch pending events.

This API is designed to enable applications to integrate Winit into an external event loop, for platforms that can support this.

The given timeout limits how long it may block waiting for new events.

Passing a timeout of Some(Duration::ZERO) would ensure your external event loop is never blocked but you would likely need to consider how to throttle your own external loop.

Passing a timeout of None means that it may wait indefinitely for new events before returning control back to the external loop.

Note: This is not a portable API, and its usage involves a number of caveats and trade offs that should be considered before using this API!

You almost certainly shouldn’t use this API, unless you absolutely know it’s the only practical option you have.

§Synchronous events

Some events must only be handled synchronously via the closure that is passed to Winit so that the handler will also be synchronized with the window system and operating system.

This is because some events are driven by a window system callback where the window systems expects the application to have handled the event before returning.

These events can not be buffered and handled outside of the closure passed to Winit.

As a general rule it is not recommended to ever buffer events to handle them outside of the closure passed to Winit since it’s difficult to provide guarantees about which events are safe to buffer across all operating systems.

Notable events that will certainly create portability problems if buffered and handled outside of Winit include:

  • RedrawRequested events, used to schedule rendering.

    macOS for example uses a drawRect callback to drive rendering within applications and expects rendering to be finished before the drawRect callback returns.

    For portability it’s strongly recommended that applications should keep their rendering inside the closure provided to Winit.

  • Any lifecycle events, such as Suspended / Resumed.

    The handling of these events needs to be synchronized with the operating system and it would never be appropriate to buffer a notification that your application has been suspended or resumed and then handled that later since there would always be a chance that other lifecycle events occur while the event is buffered.

§Supported Platforms
  • Windows
  • Linux
  • MacOS
  • Android
§Unsupported Platforms
  • Web: This API is fundamentally incompatible with the event-based way in which Web browsers work because it’s not possible to have a long-running external loop that would block the browser and there is nothing that can be polled to ask for new new events. Events are delivered via callbacks based on an event loop that is internal to the browser itself.
  • iOS: It’s not possible to stop and start an NSApplication repeatedly on iOS so there’s no way to support the same approach to polling as on MacOS.
§Platform-specific
  • Windows: The implementation will use PeekMessage when checking for window messages to avoid blocking your external event loop.

  • MacOS: The implementation works in terms of stopping the global application whenever the application RunLoop indicates that it is preparing to block and wait for new events.

    This is very different to the polling APIs that are available on other platforms (the lower level polling primitives on MacOS are private implementation details for NSApplication which aren’t accessible to application developers)

    It’s likely this will be less efficient than polling on other OSs and it also means the NSApplication is stopped while outside of the Winit event loop - and that’s observable (for example to crates like rfd) because the NSApplication is global state.

    If you render outside of Winit you are likely to see window resizing artifacts since MacOS expects applications to render synchronously during any drawRect callback.

Examples found in repository?
examples/pump_events.rs (line 62)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fn main() -> std::process::ExitCode {
    use std::process::ExitCode;
    use std::thread::sleep;
    use std::time::Duration;

    use winit::application::ApplicationHandler;
    use winit::event::WindowEvent;
    use winit::event_loop::{ActiveEventLoop, EventLoop};
    use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
    use winit::window::{Window, WindowId};

    #[path = "util/fill.rs"]
    mod fill;

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

    impl ApplicationHandler for PumpDemo {
        fn resumed(&mut self, event_loop: &ActiveEventLoop) {
            let window_attributes = Window::default_attributes().with_title("A fantastic window!");
            self.window = Some(event_loop.create_window(window_attributes).unwrap());
        }

        fn window_event(
            &mut self,
            event_loop: &ActiveEventLoop,
            _window_id: WindowId,
            event: WindowEvent,
        ) {
            println!("{event:?}");

            let window = match self.window.as_ref() {
                Some(window) => window,
                None => return,
            };

            match event {
                WindowEvent::CloseRequested => event_loop.exit(),
                WindowEvent::RedrawRequested => {
                    fill::fill_window(window);
                    window.request_redraw();
                },
                _ => (),
            }
        }
    }

    let mut event_loop = EventLoop::new().unwrap();

    tracing_subscriber::fmt::init();

    let mut app = PumpDemo::default();

    loop {
        let timeout = Some(Duration::ZERO);
        let status = event_loop.pump_app_events(timeout, &mut app);

        if let PumpStatus::Exit(exit_code) = status {
            break ExitCode::from(exit_code as u8);
        }

        // Sleep for 1/60 second to simulate application work
        //
        // Since `pump_events` doesn't block it will be important to
        // throttle the loop in the app somehow.
        println!("Update()");
        sleep(Duration::from_millis(16));
    }
}

Object Safety§

This trait is not object safe.

Implementors§