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

cursor grab fails in fullscreen on windows #574

Closed
gui1117 opened this issue Jun 18, 2018 · 13 comments
Closed

cursor grab fails in fullscreen on windows #574

gui1117 opened this issue Jun 18, 2018 · 13 comments
Labels
B - bug Dang, that shouldn't have happened C - waiting on author Waiting for a response or another PR D - hard Likely harder than most tasks here DS - windows
Milestone

Comments

@gui1117
Copy link

gui1117 commented Jun 18, 2018

When I add the line window.set_cursor(winit::CursorState:Grab).unwrap() after the window build in fullscreen example and run it on windows then it fails.

The window does not respond and windows ask to quit or wait.

@gui1117 gui1117 changed the title Windows cursor grab fails in fullscreen cursor grab fails in fullscreen on windows Jun 18, 2018
@rukai
Copy link
Contributor

rukai commented Jun 18, 2018

I think you mean: window.set_cursor_state(winit::CursorState::Grab).unwrap()

I have the same issue on Windows 10
It also occurs with CursorState::Hide.

The issue occurs when with_fullscreen(Some(..)) is used to create a window while cursor is Grab or Hide.
The issue also occurs when the cursor is Grab or Hide and then set_fullscreen(Some(..)) is called.

@francesca64 francesca64 added B - bug Dang, that shouldn't have happened DS - windows C - in progress Implementation is proceeding smoothly D - easy Likely easier than most tasks here D - hard Likely harder than most tasks here and removed D - easy Likely easier than most tasks here labels Jun 18, 2018
@francesca64
Copy link
Member

It looked like a deadlock was happening somewhere, and the results are a bit amusing.

As you might've heard by now, we block during resize events on Windows. However, we only unblock in run_forever/poll_events. Entering fullscreen triggers a resize, and thus a block. This means that all event processing is frozen in the duration between creating a fullscreen window and starting run_forever/poll_events execution, and due to some other fun complexities of our Windows implementation, cursor grabbing requires posting a message to the event queue. set_cursor_state doesn't return until it gets a result, but since event processing is still held up in the WM_SIZE handler, your program freezes.

Here's a really goofy temporary workaround you can use:

extern crate winit;

use winit::{ControlFlow, Event, WindowEvent};

fn main() {
    let mut event_loop = winit::EventsLoop::new();
    let monitor = event_loop.get_primary_monitor();
    let window = winit::WindowBuilder::new()
        .with_fullscreen(Some(monitor))
        .build(&event_loop)
        .unwrap();

    let mut run_count = Some(0);

    event_loop.run_forever(|event| {
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Resized(_) => {
                    if let Some(count) = run_count {
                        let dpi_factor = window.get_hidpi_factor();
                        if (dpi_factor == 1.0 && count == 0)
                        || (dpi_factor != 1.0 && count == 1) {
                            window.grab_cursor(true).unwrap();
                            run_count = None;
                        }
                    }
                },
                WindowEvent::CloseRequested
                | WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        virtual_keycode: Some(winit::VirtualKeyCode::Escape),
                        ..
                    }, ..
                } => return ControlFlow::Break,
                _ => (),
            },
            _ => (),
        }
        run_count = run_count.map(|n| n + 1);
        ControlFlow::Continue
    });
}

@Osspial are you still down to implement #459 on Windows? I'm ready to start this migration if you are.

@francesca64 francesca64 added C - waiting on author Waiting for a response or another PR and removed C - in progress Implementation is proceeding smoothly labels Jun 18, 2018
@francesca64 francesca64 added this to the EventsLoop 2.0 milestone Jun 18, 2018
@Osspial
Copy link
Contributor

Osspial commented Jul 12, 2018

@francesca64 I am, yes. Sorry about disappearing for a few weeks there! I'm going to be away from any Windows machines until the end of the month starting next week, but I'll try to make the most progress I can in the next couple days.

@LaylBongers
Copy link

Ran into this same deadlock when resizing a window, which triggered a Focused, which my game uses to know when to grab the cursor.

@Osspial
Copy link
Contributor

Osspial commented Aug 15, 2018

I added the code to winit that blocks during windows resize events, in order to fix visual bugs that happened when resizing a window (see #250). I don't think that's as important as making sure programs don't freeze, though! I'm pretty sure getting rid of that block would not only fix this but also fix #391, so we may want to remove it in the meantime while #459 gets hammered out.

@francesca64
Copy link
Member

@Osspial if it's only a visual issue, then I'd definitely be in favor of that.

@Osspial
Copy link
Contributor

Osspial commented Aug 22, 2018

Removing that code should be pretty simple so I'll see if I can get a PR up in the next day or so.

@hobogenized
Copy link

hobogenized commented Oct 31, 2018

It seems that this might be related to a freeze when I try to resize the window on Windows builds. No issues happen on Mac or Linux. A snippet to reproduce, using the latest pull from the winit repo:

extern crate winit;

fn main() {

    let mut events = winit::EventsLoop::new();
    let window = winit::Window::new(&events).unwrap();
    
    while true {
        events.poll_events(|event| {
            match event {
                // Grab mouse cursor if window is focused; release otherwise
                winit::Event::WindowEvent {
                    event: winit::WindowEvent::Focused(focused),
                    ..
                } => {
                    if let Err(e) = window.grab_cursor(focused) {
                        eprintln!("{}", e);
                    }
                },
                _ => {}
            }
        });
    }
}

A sample stacktrace from debug calls:

[Inline Frame] demo.exe!std::sys::windows::c::SleepConditionVariableSRW() Line 78 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sys\windows\compat.rs:78)
[Inline Frame] demo.exe!std::sys::windows::condvar::Condvar::wait() Line 32 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sys\windows\condvar.rs:32)
[Inline Frame] demo.exe!std::sys_common::condvar::Condvar::wait() Line 51 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sys_common\condvar.rs:51)
[Inline Frame] demo.exe!std::sync::condvar::Condvar::wait() Line 214 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sync\condvar.rs:214)
demo.exe!std::thread::park() Line 885 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\thread\mod.rs:885)
demo.exe!std::sync::mpsc::blocking::WaitToken::wait() Line 81 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sync\mpsc\blocking.rs:81)
demo.exe!std::sync::mpsc::oneshot::Packet<core::result::Result<(), alloc::string::String>>::recv<core::result::Result<(), alloc::string::String>>(core::option::Option<std::time::Instant> self) Line 163 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sync\mpsc\oneshot.rs:163)
demo.exe!std::sync::mpsc::Receiver<core::result::Result<(), alloc::string::String>>::recv<core::result::Result<(), alloc::string::String>>() Line 1203 (d:\rustc\d586d5d2f51489821b471f20959333558c24b129\src\libstd\sync\mpsc\mod.rs:1203)
demo.exe!winit::platform::platform::window::Window::grab_cursor(bool self) Line 397 \.cargo\git\checkouts\winit-5993d63686bf7f83\214e157\src\platform\windows\window.rs:397)```

@hobogenized
Copy link

hobogenized commented Nov 1, 2018

@Osspial do you know if the issue I've posted above is related to the blocking issue? It seems that you're one of the people who are most knowledgeable about the Windows backend.

@Osspial
Copy link
Contributor

Osspial commented Nov 2, 2018

@hobogenized I don't think it's related. The previous issue would freeze the entire program, preventing Winit windows from being resized. It seems like a soft-lock is happening here that's still letting Windows process events (so resizing still works), it's just that those events aren't getting delivered to Winit.

@hobogenized
Copy link

@Osspial Thanks for the feedback. Should I open up a new issue for easier tracking?

@Osspial
Copy link
Contributor

Osspial commented Nov 2, 2018

@hobogenized Sure, that would be great!

We can also close this issue since the issue it describes is resolved. cc @francesca64

@francesca64
Copy link
Member

Thanks!

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 C - waiting on author Waiting for a response or another PR D - hard Likely harder than most tasks here DS - windows
Development

No branches or pull requests

6 participants