emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
22.43k stars 1.6k forks source link

Run `App::update` even when hidden #5112

Open emilk opened 2 months ago

emilk commented 2 months ago

If the eframe web app is in hidden (e.g. is in a background tab in the browser), then any call to request_repaint will be ignored, and not result in a call to App::update.

That's because eframe checks if request_repaint has been called from requestAnimationFrame callback, which is not called if the application is hidden.

Solution

If the web page is hidden, then calling request_repaint should schedule a setTimer(…) callback to call App::update() (must done via a setTimer delay, or we could have App::update call request_repaint which in turn calls App::update.

We also need some guards to make sure that multiple calls to request_repaint in a row only results in one call to App::update, for instance via this pseudo-code:

// Won't be called if hidden
fn on_request_animation_frame() {
    if state.needs_repaint {
       app.update();
       paint();
       state.needs_repaint = false;
    }
}

fn on_request_repaint() {
   state.needs_repaint = true;
    if document.is_hidden {
       setTime(10ms, app_update_if_needed);
    }
}

fn app_update_if_needed() {
   if state.needs_repaint {
       app.update();
       state.needs_repaint = false;  
    }
}

Related

Mingun commented 2 months ago

Probably you shouldn't do that. Correct me if I'm wrong, but it seems there a battle of two opinions. When egui starts updating in background, someone complain why application consumes CPU when it hidden. Then egui stops updating in background and another people asks why his code didn't run when app not on the screen. It seems to me that there was a several iterations of this issue at the time present.

egui is a GUI library. The GUI code should not drive the application logic. Period. If you need other activities except GUI, create another thread and do it there as frequently as you want.

emilk commented 1 month ago

When egui starts updating in background, someone complain why application consumes CPU when it hidden.

It will only update if someone calls ctx.request_repaint. With https://github.com/emilk/egui/issues/5113 it will also be free if nobody adds any logic to tick().

If you need other activities except GUI, create another thread and do it there as frequently as you want.

That's difficult on web (no easy access to threads). It also introduces the need for users to add locks to the data in their App.