slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.55k stars 601 forks source link

Timers do not execute when window is minimized with winit backend on Wayland #1695

Closed Be-ing closed 10 months ago

Be-ing commented 2 years ago

Using renderer-winit-femtovg feature on Wayland (KWin), Timer callbacks do not get executed when the window is minimized.

Context: https://codeberg.org/moire/moire/issues/73

Be-ing commented 2 years ago

The timer example is helpful to test this:

cargo run -p _7guis --bin timer

With SLINT_BACKEND=Qt, I cannot reproduce this, but I can with SLINT_BACKEND=winit-femtovg and SLINT_BACKEND=winit-skia.

Be-ing commented 2 years ago

I cannot reproduce this with winit-femtovg nor winit-skia on X11. It seems to be specific to winit on Wayland. Maybe there is an upstream bug in winit?

Be-ing commented 2 years ago

Slint relies on the Event::NewEvent in winit's EventLoop callback to update timers. Evidently that isn't sufficient on Wayland.

Be-ing commented 2 years ago

I cannot reproduce this on GNOME, but GNOME doesn't really have a concept of minimizing windows.

tronical commented 2 years ago

This is also not reproducible on macOS.

tronical commented 2 years ago

I can reproduce this on Linux with Weston.

tronical commented 2 years ago

I can't reproduce this (yet) with winit's control_flow example, so there's still a chance that this is an issue with Slint's use of winit.

tronical commented 2 years ago

Hm, I tried a minimal Slint example that doesn't even show a window, so just replacing the run() in the timer example with slint::run_event_loop(); - but oddly enough that works! So it really seems somehow related to minimising the window.

Vadoola commented 10 months ago

I cannot reproduce this on GNOME, but GNOME doesn't really have a concept of minimizing windows.

I can recreate this on gnome just by having the window fully hidden.

Edit: to clarify, hidden behind another window. For example I have a small slint window and when I drag a bigger window over it the timer stops. I meant to capture a video but forgot to hit record, where I was half tiling the VSCodium window, and would make it bigger until it fully overlapped my Slint window. As soon as the Slint window was fully covered the timer stopped, and would start again when I shrank the Code window again....I'll see if I can make a recording

Edit 2: I should test what happens when its not on the active workspace, see if that also stops the timer.

ogoffart commented 10 months ago

I can reproduce with weston. If i add a println in the printerdemo when the timer is executed, and minimize the window, it is clear that the timer is only ran once.

Slint recieve a RedrawRequested event from winit for the hidden window. Then nothing else (no AboutToWait

ogoffart commented 10 months ago

In fact, the process is blocked in eglSwapBuffers within femtovg.

Full backtrace:

#0  0x00007ffff7d1a18f in __GI___poll (fds=fds@entry=0x7fffffff9240, nfds=nfds@entry=1, timeout=timeout@entry=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
#1  0x00007ffff7fb2f3c in poll (__timeout=-1, __nfds=1, __fds=0x7fffffff9240) at /usr/include/x86_64-linux-gnu/bits/poll2.h:39
#2  wl_display_poll (display=0x5555572e58b0, events=1) at ../src/wayland-client.c:1914
#3  wl_display_dispatch_queue (queue=<optimized out>, display=<optimized out>) at ../src/wayland-client.c:1987
#4  wl_display_dispatch_queue (display=0x5555572e58b0, queue=0x55555738f0e0) at ../src/wayland-client.c:1960
#5  0x00007ffff777a5a4 in dri2_wl_swap_buffers_with_damage (disp=<optimized out>, draw=0x5555573a7720, rects=0x0, n_rects=0) at ../src/egl/drivers/dri2/platform_wayland.c:1616
#6  0x00007ffff776f087 in dri2_swap_buffers (disp=0x555557427370, surf=0x5555573a7720) at ../src/egl/drivers/dri2/egl_dri2.c:1881
#7  0x00007ffff77636bd in eglSwapBuffers (dpy=<optimized out>, surface=0x5555573a7720) at ../src/egl/main/eglapi.c:1433
#8  0x0000555555c65091 in glutin_egl_sys::egl::Egl::SwapBuffers (self=0x5555572d9260 <glutin::api::egl::EGL+16>, dpy=0x555557427370, surface=0x5555573a7720)
    at target/debug/build/glutin_egl_sys-3a172a1d9b482170/out/egl_bindings.rs:593
#9  0x0000555555cd180d in glutin::api::egl::surface::{impl#3}::swap_buffers<glutin::surface::WindowSurface> (self=0x555557394388, context=0x555557394368)
    at /home/olivier/.cargo/registry/src/index.crates.io-6f17d22bba15001f/glutin-0.31.1/src/api/egl/surface.rs:358
#10 0x0000555555ccf418 in glutin::surface::{impl#11}::swap_buffers<glutin::surface::WindowSurface> (self=0x555557394388, context=0x555557394360)
    at /home/olivier/.cargo/registry/src/index.crates.io-6f17d22bba15001f/glutin-0.31.1/src/surface.rs:319
#11 0x0000555555c49b64 in i_slint_backend_winit::renderer::femtovg::glcontext::{impl#0}::swap_buffers (self=0x555557394360) at internal/backends/winit/renderer/femtovg/glcontext.rs:30
#12 0x000055555611758a in i_slint_renderer_femtovg::FemtoVGRenderer::internal_render_with_post_callback (self=0x5555581d46d0, rotation_angle_degrees=0, translation=..., surface_size=..., post_render_cb=...)
    at internal/renderers/femtovg/lib.rs:317
#13 0x0000555556116d87 in i_slint_renderer_femtovg::FemtoVGRenderer::render (self=0x5555581d46d0) at internal/renderers/femtovg/lib.rs:174
#14 0x0000555555c991ab in i_slint_backend_winit::renderer::femtovg::{impl#1}::render (self=0x5555581d46d0, _window=0x555557331ca8) at internal/backends/winit/renderer/femtovg.rs:58
#15 0x0000555555bcdd6f in i_slint_backend_winit::winitwindowadapter::WinitWindowAdapter::draw (self=0x555557331b90) at internal/backends/winit/winitwindowadapter.rs:256
#16 0x0000555555c623ba in i_slint_backend_winit::event_loop::EventLoopState::process_event (self=0x7fffffffd6b8, event=..., event_loop_target=0x5555572f6640) at internal/backends/winit/event_loop.rs:456
#17 0x0000555555be0ed2 in i_slint_backend_winit::event_loop::{impl#6}::run::{closure#2}::{closure#0} () at internal/backends/winit/event_loop.rs:640
#18 0x0000555555be17d1 in i_slint_backend_winit::event_loop::CURRENT_WINDOW_TARGET::set<i_slint_backend_winit::event_loop::{impl#6}::run::{closure#2}::{closure_env#0}, ()> (
    self=0x5555571afed8 <i_slint_backend_winit::event_loop::CURRENT_WINDOW_TARGET>, t=0x7fffffffa160, f=...) at /home/olivier/.cargo/registry/src/index.crates.io-6f17d22bba15001f/scoped-tls-hkt-0.1.4/src/lib.rs:265
#19 0x0000555555be0e7e in i_slint_backend_winit::event_loop::{impl#6}::run::{closure#2} (event=..., event_loop_target=0x5555572f6640) at internal/backends/winit/event_loop.rs:639
#20 0x0000555555bdef2f in core::ops::function::impls::{impl#3}::call_mut<(winit::event::Event<i_slint_backend_winit::SlintUserEvent>, &winit::event_loop::EventLoopWindowTarget<i_slint_backend_winit::SlintUserEvent>), i_sl
int_backend_winit::event_loop::{impl#6}::run::{closure_env#2}> (self=0x7fffffffbd60, args=...) at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/core/src/ops/function.rs:294
#21 0x0000555555bdf020 in core::ops::function::impls::{impl#3}::call_mut<(winit::event::Event<i_slint_backend_winit::SlintUserEvent>, &winit::event_loop::EventLoopWindowTarget<i_slint_backend_winit::SlintUserEvent>), &mut
 i_slint_backend_winit::event_loop::{impl#6}::run::{closure_env#2}> (self=0x7fffffffbbb0, args=...) at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/core/src/ops/function.rs:294
#22 0x0000555555c2ecaf in winit::platform_impl::platform::wayland::event_loop::EventLoop<i_slint_backend_winit::SlintUserEvent>::single_iteration<i_slint_backend_winit::SlintUserEvent, &mut &mut i_slint_backend_winit::eve
nt_loop::{impl#6}::run::{closure_env#2}> (self=0x5555572f6590, callback=0x7fffffffbbb0, cause=...)
    at /home/olivier/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.4/src/platform_impl/linux/wayland/event_loop/mod.rs:504
#23 0x0000555555c342b8 in winit::platform_impl::platform::wayland::event_loop::EventLoop<i_slint_backend_winit::SlintUserEvent>::poll_events_with_timeout<i_slint_backend_winit::SlintUserEvent, &mut &mut i_slint_backend_wi
nit::event_loop::{impl#6}::run::{closure_env#2}> (self=0x5555572f6590, timeout=..., callback=0x7fffffffbd60)
    at /home/olivier/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.4/src/platform_impl/linux/wayland/event_loop/mod.rs:323
#24 0x0000555555c2de75 in winit::platform_impl::platform::wayland::event_loop::EventLoop<i_slint_backend_winit::SlintUserEvent>::pump_events<i_slint_backend_winit::SlintUserEvent, &mut i_slint_backend_winit::event_loop::{

@tronical: should we somehow detect in Slint that the window is minimized or and avoid calling swap_buffers until the window is back visible?

ogoffart commented 10 months ago

(the problem is not reproducable with the software renderer, but can be reproduced with femtovg and skia renderer)

tronical commented 10 months ago

should we somehow detect in Slint that the window is minimized or and avoid calling swap_buffers until the window is back visible?

Perhaps that's indeed be the only way out :(. It sucks that we're even getting a RedrawRequest in the first place. The only alternative I can think of is #4200 . Winit's API here that we should use will use wayland frame callbacks, which should cover this.

tronical commented 10 months ago

Olivier, could you give the wayland-throttle branch a try?

ogoffart commented 10 months ago

The wayland-throttle branch doesn't solve the problem. (But it changes the backtrace a bit so the draw is now called from AboutToWait in https://github.com/slint-ui/slint/blob/0dd46ad4b79dd8a57a14690176dd9310855861cf/internal/backends/winit/event_loop.rs#L561 , and it is still blocked in eglSwapBuffers)

ogoffart commented 10 months ago

Removing the windows_with_pending_redraw_requests hack entirely seems to fix the problem. Maybe this should only be done on platform which have that bug?

tronical commented 10 months ago

I can confirm. The hack might be safe to remove after https://github.com/rust-windowing/winit/issues/3150 . It works for me only with the frame callbacks and the hack removed.

tronical commented 10 months ago

I'll try to verify that the hack can be safely removed and make a PR for that. After that I can try to implement the frame throttling - we need it anyway.

Be-ing commented 10 months ago

Removing the windows_with_pending_redraw_requests hack entirely seems to fix the problem. Maybe this should only be done on platform which have that bug?

Just tried Slint master branch after #4253 was merged and I can still reproduce https://codeberg.org/moire/moire/issues/73

tronical commented 10 months ago

Yes, https://github.com/slint-ui/slint/pull/4258 is also needed. That's why I haven't closed this issue yet :)

tronical commented 10 months ago

After merging #4258 this works for me now :)

Be-ing commented 10 months ago

Now it works after a cargo update :)