winit icon indicating copy to clipboard operation
winit copied to clipboard

Not receiving `RedrawRequested` events for all windows that `.request_redraw()`

Open ickk opened this issue 1 year ago • 2 comments

Description

When I create multiple windows with winit, and for each window call window.request_redraw() in the AboutToWait handler, I do not receive the corresponding WindowEvent::RedrawRequested for all of the windows that requested.


minimal reproduction:

use winit::{
    event::{Event, WindowEvent},
    event_loop::EventLoop,
    window::WindowBuilder,
};

const WINDOW_COUNT: usize = 5;

fn main() {
    let event_loop = EventLoop::new().unwrap();

    let windows = Vec::from_iter(
        std::iter::repeat_with(|| WindowBuilder::new().build(&event_loop).unwrap()).take(WINDOW_COUNT),
    );

    let mut ticks = 500;
    event_loop
        .run(|event, elwt| match event {
            Event::AboutToWait => {
                for (i, window) in windows.iter().enumerate() {
                    eprintln!("request_redraw for window {i}",);
                    window.request_redraw();
                }
                ticks -= 1;
                if ticks <= 0 {
                    elwt.exit()
                }
            }
            Event::WindowEvent {
                window_id,
                event: WindowEvent::RedrawRequested,
            } => {
                let i = windows.iter().position(|w| w.id() == window_id).unwrap();
                eprintln!("received RedrawRequested for window {i}");
            }
            _ => (),
        })
        .unwrap();
}

output observed:

..
request_redraw for window 0
request_redraw for window 1
request_redraw for window 2
request_redraw for window 3
request_redraw for window 4
received RedrawRequested for window 4
received RedrawRequested for window 3
request_redraw for window 0
request_redraw for window 1
request_redraw for window 2
request_redraw for window 3
request_redraw for window 4
received RedrawRequested for window 4
received RedrawRequested for window 3
..

that is, I only receive the RedrawRequested event for the last 2 windows.


If I also call request_redraw() inside the RedrawRequested handler for the given window, as follows:

            Event::WindowEvent {
                window_id,
                event: WindowEvent::RedrawRequested,
            } => {
                let i = windows.iter().position(|w| w.id() == window_id).unwrap();
                eprintln!("received RedrawRequested for window {i}, requesting redraw for window {i}");
                windows[i].request_redraw();
            }
            _ => (),

then I observe the following:

..
request_redraw for window 0
request_redraw for window 1
request_redraw for window 2
request_redraw for window 3
request_redraw for window 4
received RedrawRequested for window 4, requesting redraw for window 4
received RedrawRequested for window 4, requesting redraw for window 4
request_redraw for window 0
request_redraw for window 1
request_redraw for window 2
request_redraw for window 3
request_redraw for window 4
received RedrawRequested for window 4, requesting redraw for window 4
received RedrawRequested for window 4, requesting redraw for window 4
..

that is, I receive two consecutive RedrawRequested events (sometimes just 1), but only ever for the last window.


Neither approach behaves as I would expect. I would expect to reliably receive a single RedrawRequested event for each window

Windows version

Microsoft Windows [Version 10.0.19045.4291]

Winit version

v0.29.15

ickk avatar Apr 23 '24 18:04 ickk

I skimmed the source, and I think this might be because of the way winit tries to get RedrawWindow/WM_PAINT to throttle redraws?

ickk avatar Apr 23 '24 18:04 ickk

Yes, redraws are throttled by the compositor usually, though, WM_PAINT looks so broken that winit should likely use something else.

kchibisov avatar Apr 23 '24 19:04 kchibisov

I'm getting the same problem. I would have assumed that redraw events are only throttled per window? Is there any work around to this or does it require a patch to winit?

geom3trik avatar Jul 11 '24 15:07 geom3trik

I mean if you want to draw when your window is not visible and compositor thinks that you shouldn't, then just draw unconditionally after timeout or so. In general if you don't get the event back it means that you shouldn't draw at all, because the window is either obscured or something like that, so user wont ever see anything anyway.

kchibisov avatar Jul 11 '24 17:07 kchibisov

Is there any work around to this

I think what might mostly work is to send request_redraw for only your main window, and then draw to all windows when you receive it

ickk avatar Jul 11 '24 21:07 ickk

But why would you want to do that though? If you want to draw when you're suggested to not do so then just draw unconditionally?

kchibisov avatar Jul 11 '24 21:07 kchibisov

I don't believe the premise is that RedrawRequested is not sent because windows are obscured, the premise is that its a bug. In which case OP was just looking for a workaround.

@ickk it would be good to know if you are indeed not getting RedrawRequested events because wundows are obscured. Can you confirm that all windows are visible?

daxpedda avatar Jul 12 '24 11:07 daxpedda

it would be good to know if you are indeed not getting RedrawRequested events because wundows are obscured. Can you confirm that all windows are visible?

I can confirm the minimal reproduction included in the issue body produces the same result even when all windows are fully visible

ickk avatar Jul 12 '24 16:07 ickk