winit icon indicating copy to clipboard operation
winit copied to clipboard

MacOS ControlFlow::Wait doesn't work properly when pointer leaves window

Open ocheret opened this issue 1 year ago • 13 comments

Description

When implementing ApplicationHandler I implemented my own about_to_wait() method. When control flow is set to ControlFlow::Wait and the pointer remains within the window, everything works as expected - the thread goes to sleep when nothing is happening. However, when the pointer leaves the window, the about_to_wait() method is called non-stop as if control flow was set to ControlFlow::Poll. When the pointer reenters the window, things work as expected again.

Super simple code example:

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

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

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        if self.window.is_none() {
            let window = event_loop
                .create_window(WindowAttributes::default())
                .expect("Failed to create window");
            self.window = Some(window);
        }
        println!("resumed");
    }

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

    // When the pointer leaves the window, this is called incessantly!
    fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
        println!("about_to_wait");
    }
}

fn main() {
    let event_loop = EventLoop::new().expect("Failed to create event loop");
    event_loop.set_control_flow(ControlFlow::Wait);

    let mut app = App::default();
    event_loop.run_app(&mut app).expect("Failed to run app");
}

macOS version

ProductName:            macOS
ProductVersion:         14.6.1
BuildVersion:           23G93

Winit version

0.30.5

ocheret avatar Sep 30 '24 20:09 ocheret

Does it happen with the window example?

kchibisov avatar Sep 30 '24 20:09 kchibisov

Hard to say. That example doesn't seem to open a window (I can't locate it on a screen anyway) and it also doesn't appear to call set_control_flow. Or maybe I'm missing something.

ocheret avatar Sep 30 '24 20:09 ocheret

Are you sure that it doesn't open anything at all? It should open a window and lists you some key bindings to press.

The default control flow is Wait, so it's what it's using, you don't have to explicitly set anything.

kchibisov avatar Sep 30 '24 21:09 kchibisov

Ok, had to get a desktop view - the window shows up behind the terminal I was using. I added an info! call to the about_to_wait call in there (it wasn't logging anything normally). I do not see the behavior there. :-(

My code snippet is quite short. Is there anything obvious that I'm doing wrong in there? I removed my set_control_flow call (to get the default behavior) and I see the same result. Is there some other option I need to set?

ocheret avatar Sep 30 '24 22:09 ocheret

maybe not drawing anything ends up like that, because macOS is confused. Also if you don't set ControlFlow to anything does it change behavior (it shouldn't, but just in case)?

kchibisov avatar Sep 30 '24 22:09 kchibisov

Not setting ControlFlow results in the same behavior as explicitly setting it to Wait (as you said it would). Basically, I'm trying to come up with bare-bones examples and build up slowly for a tutorial. Ultimately, I'm trying to get a good set of wgpu examples working with the latest winit (everything I can find out that uses older versions) and also illustrate integration with Tokio (among other things). Today was my first deep dive into 0.30.* and the docs are not super helpful. I'm happy to help improve them and provide more general tutorials if I can get it all figured out.

ocheret avatar Sep 30 '24 22:09 ocheret

Even GitHub Copilot begs me to use an older version. ;-)

ocheret avatar Sep 30 '24 22:09 ocheret

I mean, your provided code should generally work and I think it does. If macOS wakes you up, it's mostly up to it and given that our example also works, the issue could you not doing any drawing, so I'd suggest to draw something(even with softbuffer) and problem will likely go away.

0.30 and 0.29 don't differ much other than big callback vs trait, the rest is entirely the same, so wgpu examples for 0.29 will work fine. You can also look into glutin examples, it's using 0.30.

kchibisov avatar Sep 30 '24 22:09 kchibisov

@madsmtm do you know what the issue could be on macOS? I'd guess macOS compositor tries to ask for drawing and no drawing ever done so it kind of loops?

kchibisov avatar Sep 30 '24 22:09 kchibisov

I think I've been comparing apples and oranges. I've been trying to use v0.30.5, which is what I'm getting as the latest on crates.io for my test program. I was comparing that against master when running the window.rs example from GitHub. It is very different (e.g. create_window returns a Window in 0.30.5 but a Box(dyn Window) in master). When I look at the window.rs example from 0.30.5 it is completely different - it doesn't even use the ApplicationHandler trait. So I think I'm completely lost now. What should I be using?

ocheret avatar Oct 01 '24 03:10 ocheret

latest released version.

kchibisov avatar Oct 01 '24 10:10 kchibisov

Ok, so the problem seems to exist there (v0.30.5).

ocheret avatar Oct 01 '24 10:10 ocheret

I mean, I know that none of the examples that draw has this issue, otherwise I'd know it. So as I said, as soon as you start drawing it should go away.

kchibisov avatar Oct 01 '24 11:10 kchibisov