Wayland: `request_repaint` ignored if minimized
According to @jleibs, calling ctx.request_repaint does not result in a call to App::update when on Wayland and the app is minimized (Hyprland placed on non-visible workspace).
- See https://github.com/rerun-io/rerun/pull/7422 for more
- We have the same problem on web: https://github.com/emilk/egui/issues/5112
- Related: https://github.com/emilk/egui/issues/5113
I came across this because I noticed my app is not responding to closing when it is minimized. It seems that actually no events are received when the window is minimized. This is caused because of this call hanging and blocking the event loop thread.
I found exactly this reported in this issue https://github.com/rust-windowing/glutin/issues/1591
This post (written by someone who works on Wayland itself) goes in detail about this.
Based on that, adding this line (note: this is an ignored result)
_ = gl_surface.set_swap_interval(context, glutin::surface::SwapInterval::DontWait);
before calling swap_buffers will make it not block therefore fixing this issue and the closing thing I mentioned, but now it repaints faster than vsync. This has the same effect as setting vsync to false in NativeOptions. I believe this matches the behavior of egui on other platforms, repaint even if hidden and pay the GUI code cost.
Sidenote, according to the post this is the equivalent code that should be added to write a proper Wayland render loop
_ = gl_surface.set_swap_interval(context, glutin::surface::SwapInterval::DontWait);
window.pre_present_notify();
But since this makes winit repaint only when the compositor wants, this issue re-appears. The proper way is to probably have that App:tick.
Hello, I'm experiencing this issue right now as I'm trying to build a GUI. I'm on Hyprland and the issue is the same as the one described. In my case it doesn't even matter if the app is in a hidden workspace, the only way I can get the update function to run is if something happens, like mouse movement.
I tested this by putting a print statement in the update function, and it doesn't print unless my mouse is hovering the app, and also moving as well.
Needless to say this makes the app unusable. Is a fix on the way? Is there any way I could patch this behaviour myself? I just need the app the visually update regardless of what i'm doing or where the app is (different workspace, etc.)
Thanks.
Ok, I kind of fixed my own problem by doing two things:
- Disabled vsync
- Started a loop in a thread from update() that repaints the UI at a specific FPS.
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if self.ctx.is_none() {
self.ctx = Some(ctx.clone());
}
if !self.repaint_started {
self.repaint_started = true;
let ctx_clone = ctx.clone();
tokio::spawn(async move {
loop {
tokio::time::sleep(Duration::from_secs_f64(1.0 / 60.0)).await;
ctx_clone.request_repaint();
}
});
}
}
}
I don't know if this is how I was supposed to do it from the beginning but at least it works to fix the issue for now.
Got something even worse - I get a dialog from Hyprland saying that the application is not responsive, for an application that called request_repaint_after, while I switched to another workspace. I have an update loop that is triggered via request_repaint_after. If the loop is not active, there's no issue. The application continues to be responsive when I return to the workspace where it is visible.
According to gdb the main thread is stuck here in wgpu. So maybe it is an egui_wgpu issue?
>>> bt
#0 0x00007f1a9611f7ef in poll () from /lib64/libc.so.6
#1 0x00007f1a8c17f5ec in wl_display_dispatch_queue () from /lib64/libwayland-client.so.0
#2 0x00007f1a7a12b3ec in ?? () from /lib64/libnvidia-glcore.so.580.95.05
#3 0x00007f1a7a3a22b2 in ?? () from /lib64/libnvidia-glcore.so.580.95.05
#4 0x000055880b616c94 in <wgpu_hal::vulkan::Queue as wgpu_hal::Queue>::present ()
#5 0x000055880b57faef in <Q as wgpu_hal::dynamic::queue::DynQueue>::present ()
#6 0x000055880b5ad873 in wgpu_core::present::<impl wgpu_core::instance::Surface>::present ()
#7 0x000055880b513d67 in wgpu_core::present::<impl wgpu_core::global::Global>::surface_present ()
#8 0x000055880b4f8346 in wgpu::api::surface_texture::SurfaceTexture::present ()
#9 0x000055880b3425a7 in egui_wgpu::winit::Painter::paint_and_update_textures ()
#10 0x000055880af4d4a9 in <eframe::native::wgpu_integration::WgpuWinitApp as eframe::native::winit_integration::WinitApp>::run_ui_and_paint ()
#11 0x000055880afee97d in eframe::native::event_loop_context::with_event_loop_context ()
#12 0x000055880afd0ff3 in core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut ()
#13 0x000055880afcaaa4 in winit::platform_impl::linux::wayland::event_loop::EventLoop<T>::pump_events ()
#14 0x000055880afb08db in winit::platform_impl::linux::EventLoop<T>::run_on_demand ()
#15 0x000055880afe3a81 in eframe::native::run::run_and_return ()
#16 0x000055880afe7442 in std::thread::local::LocalKey<T>::with ()
#17 0x000055880afe4af9 in eframe::native::run::run_wgpu ()
#18 0x000055880af1db8f in eframe::run_native ()
#19 0x000055880aa95228 in app::run_main_common ()
#20 0x000055880aa93122 in app::main ()
#21 0x000055880ab04453 in std::sys::backtrace::__rust_begin_short_backtrace ()
#22 0x000055880ab4a30d in std::rt::lang_start::{{closure}} ()
#23 0x000055880b972730 in std::rt::lang_start_internal ()
#24 0x000055880aa97345 in main ()
Turning on wgpu for eframe fixes this for me