Never run an egui pass when nothing will be shown - #8387
Merged
Conversation
Add `Context::run_logic`, for ticking app logic without running a pass, and use it in the native eframe backends when a viewport is minimized or occluded (and has no visible descendant viewport). Since no pass runs, all ui state is left untouched: nothing to special-case inside egui, and the app finds everything where it left it once the window is visible again. `App::logic` is now always called outside of the egui pass. Any viewport commands it sends (e.g. `ViewportCommand::Focus`) come out of `LogicOutput` when there is no pass to carry them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Same as the native backends: tick `App::logic` via `Context::run_logic` and leave all ui state alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`Context::run_logic` now takes the new `RawInput`, and copies only `RawInput::viewports` into the `InputState`, so that `App::logic` can tell that the window is minimized/occluded. The ui input (events, time) is left for the next pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Preview available at https://egui-pr-preview.github.io/pr/8387-emilklogic-outside-of-pass View snapshot changes at kitdiff |
* One shared `sleep_if_invisible_or_minimized`, replacing two new helpers and two inlined copies. * `Viewport::process_commands` in each native backend, used both by the new no-pass path and by `handle_viewport_output`, replacing the commands-only helpers. * `EpiIntegration::pending_raw_input` needs no `Option`. * Assert in the test that the child viewport survives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
That way it sees the current frame's input, like it did before. While hidden there is no pass, and `Context::run_logic` only fills in the window state, so that the app can tell that it is hidden; the ui input is left for the next pass to interpret. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
emilk
marked this pull request as ready for review
August 4, 2026 17:56
wyvernbw
pushed a commit
to wyvernbw/egui
that referenced
this pull request
Aug 7, 2026
* Closes <emilk#8266> * Alternative to emilk#8385 Not the most simple or beautiful code, but it works, and makes sense. What makes it complex: `app.logic` should still see some input (e.g. what viewports are visible) and emit some output (e.g. "open this link", or "focus and repaint"). ## TODO * [x] test multiple viewports ## Clanker says Instead of teaching egui to skip book-keeping during a pass where no ui is shown, we simply run no pass at all. Then there is nothing to special-case: all ui state is left untouched, and the app finds everything where it left it when the window is shown again. * New `Context::run_logic(&raw_input, f)`: ticks app logic without a pass, returning the `LogicOutput` (platform output + viewport commands) that a pass would otherwise have carried, so e.g. `ViewportCommand::Focus` still reaches the integration. * All three eframe backends (glow, wgpu, web) call `run_logic` instead of `run_ui` when the viewport is minimized/occluded (and has no visible descendant viewport) or, on web, when the tab is hidden. * `App::logic` is still called from inside the pass when the window is visible, so it sees the current frame's input. While hidden, `run_logic` fills in only the window state (`RawInput::viewports` / `focused`), so the app can tell that it is hidden. The ui input (events, time, …) is not interpreted, and is instead given to the next real pass. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Area::begin/endis called when app is occluded / maximized / minimized (causing side effects/flicker) #8266uiless_passflag to retain state on occluded frames #8385Not the most simple or beautiful code, but it works, and makes sense.
What makes it complex:
app.logicshould still see some input (e.g. what viewports are visible) and emit some output (e.g. "open this link", or "focus and repaint").TODO
Clanker says
Instead of teaching egui to skip book-keeping during a pass where no ui is shown, we simply run no pass at all. Then there is nothing to special-case: all ui state is left untouched, and the app finds everything where it left it when the window is shown again.
Context::run_logic(&raw_input, f): ticks app logic without a pass, returning theLogicOutput(platform output + viewport commands) that a pass would otherwise have carried, so e.g.ViewportCommand::Focusstill reaches the integration.run_logicinstead ofrun_uiwhen the viewport is minimized/occluded (and has no visible descendant viewport) or, on web, when the tab is hidden.App::logicis still called from inside the pass when the window is visible, so it sees the current frame's input.While hidden,
run_logicfills in only the window state (RawInput::viewports/focused), so the app can tell that it is hidden. The ui input (events, time, …) is not interpreted, and is instead given to the next real pass.