Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pump_events blocks with timout set to 0 in wayland #4130

Open
1 task done
sigmaSd opened this issue Feb 19, 2025 · 4 comments
Open
1 task done

pump_events blocks with timout set to 0 in wayland #4130

sigmaSd opened this issue Feb 19, 2025 · 4 comments
Labels
B - bug Dang, that shouldn't have happened DS - wayland

Comments

@sigmaSd
Copy link

sigmaSd commented Feb 19, 2025

Description

The docs of pump_events says it will never block if the timeout is 0

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.
(from https://docs.rs/winit/latest/winit/platform/pump_events/trait.EventLoopExtPumpEvents.html#tymethod.pump_events )

But there is a case in which it can block in wayland, and that is if the control flow is set to Wait and there are no events
Here is a simple reproduction, there are 3 XXX comments that explains my findings

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, ControlFlow, EventLoop};
    use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
    use winit::window::{Window, WindowId};

    #[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 => {
                    // XXX: If I uncomment this the event loop will continue working regardless of ControlFlow
                    // window.request_redraw();
                }
                _ => (),
            }
        }
    }

    let mut event_loop = EventLoop::new().unwrap();
    // XXX With Wait the event loop gets blocked unless I uncomment window redraw
   // If I change it to Poll the event loop never gets blocked even without redraw requests
   // In X11 even with Wait and no redraw requests, the event loop does not get blocked
    event_loop.set_control_flow(ControlFlow::Wait);

    let mut app = PumpDemo::default();

    loop {
        let timeout = Some(Duration::ZERO);
        // XXX: the block happen here
        let status = event_loop.pump_app_events(timeout, &mut app);

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

        println!("Update()");
        sleep(Duration::from_millis(16));
    }
}

I reached here while debugging slint-ui/slint#7657

Window isn't shown unless you draw

  • I understand that windows aren't shown on Wayland unless I draw and present to them.

Winit version

0.30.9

@sigmaSd sigmaSd added B - bug Dang, that shouldn't have happened DS - wayland labels Feb 19, 2025
@sigmaSd
Copy link
Author

sigmaSd commented Feb 19, 2025

The block happens here

@kchibisov
Copy link
Member

kchibisov commented Feb 19, 2025

I'd generally suggest to not use Wait with pump_events unless you know what you're doing, so not doing so would also help.

winit generally should just ignore control_flow entirely when this specific API is used, right now you have 2 of them interact in a bad way, since Wait + timeout is generally a WaitUntil, however in this case it just breaks, because it thinks that normal Wait is what was used.

X11 should generally be also affected, you just get lucky that it doesn't.

@tronical
Copy link
Contributor

Thanks @kchibisov for the quick response. @sigmaSd this suggests that we should use Poll when calling pump_events, which is in line with your observations, I think.

@kchibisov
Copy link
Member

If you always pass Duration(Some::Zero) it's Poll mode anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B - bug Dang, that shouldn't have happened DS - wayland
Development

No branches or pull requests

3 participants