## Summary
* Closes#5229
* Closes#7776
On Windows, once a window is hidden with
`ViewportCommand::Visible(false)`, two problems occur:
1. **Window can never be shown again** — Windows stops sending
`RedrawRequested` events to invisible windows, and viewport commands are
only processed during `run_ui_and_paint`, which is triggered by
`RedrawRequested`. This creates a deadlock:
```
Visible(false) → window hidden → no RedrawRequested → run_ui_and_paint never called → Visible(true) stuck in queue → window stays hidden forever
```
2. **High CPU usage** — The event loop spins at full speed with
`ControlFlow::Poll` even for invisible windows, and repaint requests are
scheduled immediately, causing a tight loop that burns CPU.
## Fix
**For #5229:** In `check_redraw_requests`, after calling
`window.request_redraw()`, detect invisible windows via
`window.is_visible() == Some(false)` and call `run_ui_and_paint`
directly for them. This ensures pending viewport commands (including
`Visible(true)`) are still processed even when the OS doesn't send
redraw events.
**For #7776:** Three layers of throttling for invisible windows:
- **Heartbeat scheduling:** After painting an invisible window, schedule
the next repaint 100ms in the future (instead of immediately). This
keeps viewport commands flowing while limiting to ~10 repaints/sec.
- **Event throttling:** In `user_event`, throttle `RequestRepaint`
events for invisible windows to at least 100ms delay, preventing egui's
repaint callback from bypassing the heartbeat.
- **ControlFlow fix:** Only set `ControlFlow::Poll` for visible windows.
Invisible windows use `WaitUntil` instead of spinning.
- **Backend sleep:** Add `is_visible() == Some(false)` alongside the
existing `is_minimized()` sleep check in both wgpu and glow backends
(defense in depth).
The fix is platform-agnostic: `is_visible()` returns `Some(false)` only
when the platform can confirm invisibility, so it won't trigger on
platforms where invisible windows still receive `RedrawRequested`.
## Test plan
- [x] `cargo fmt` passes
- [x] `cargo clippy -p eframe --all-features` passes with no warnings
- [x] Manual test on Windows: window reappears after `Visible(true)`
when hidden
- [x] Manual test on Windows: CPU stays near 0% while window is
invisible (was ~16% before fix)
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
* [x] I have followed the instructions in the PR template
This updates wgpu to v29 across the egui crate stack.
There a a few API changes due to the requirement to provide a display
handle up front to properly support GLES on linux. I have done my best
to make the api changes as reasonable as possible, but I don't have all
the greater project context, so lmk if things should be done a bit
differently.
I've also updated glow to 0.17 to make cargo deny happy, there are no
source changes. I'm not sure how you want to land these.
---------
Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
## Summary
- Ignore raw device mouse motion unless the window is focused and the
pointer is inside it
- Also handles pointers starting down and then moving into or out of the
window (drag & drop)
- Prevents global mouse motion from triggering continuous repaint loops
- Applies to both glow and wgpu backends
## Testing
- I ran the check script, nothing seemed to fail
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/main/CONTRIBUTING.md)
before opening a Pull Request!
* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to test and add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.
Please be patient! I will review your PR, but my time is limited!
-->
* [x] I have followed the instructions in the PR template
`get_proc_address` was introduced in #4145, but its lifetime was
designed to be tied to the lifetime `'s` of `CreationContext`. This
means that using `get_proc_address` outside the lifetime of
`CreationContext` is undefined behavior. This contradicts the original
intent behind introducing `get_proc_address`, as this API is intended
for integration with external libraries that cannot easily guarantee
alignment with egui's lifetimes. This PR changes the type of
`get_proc_address` from a reference to an `Arc`, decoupling its lifetime
from `CreationContext` to achieve safer memory management.
* Part of https://github.com/emilk/egui/issues/5113
* Part of https://github.com/emilk/egui/issues/3524
## What
This deprecates `eframe::App::update` and replaces it with two new
functions:
```rs
pub trait App {
/// Called just before `ui`, and in the future this will
/// also be called for background apps when needed.
fn logic(&mut self, ctx: &egui::Context, frame: &mut Frame) { }
/// Show your user interface to the user.
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut Frame);
…
}
```
Similarly, `Context::run` is deprecated in favor of `Context::run_ui`.
`Plugin`s are now handed a `Ui` instead of just a `Context` in
`on_begin/end_frame`.
## TODO
…either in this PR or a later one
* [x] Deprecate `App::update`
* [x] Deprecate `Context::run`
* [x] Change plugins to get a `Ui`
* [x] Update kittest
* [x] Change viewports to get UI:s (`show_viewport_immediate` etc)
- https://github.com/emilk/egui/pull/7779
## Later PRs
* [ ] Deprecate `Panel::show`
* [ ] Deprecate `CentralPanel::show`
* [ ] Deprecate `CentralPanel` ?
### What
From the [lint
description](https://rust-lang.github.io/rust-clippy/master/index.html?search=or_fu#or_fun_call):
> The function will always be called. This is only bad if it allocates
or does some non-trivial amount of work.
But also:
> If the function has side-effects, not calling it will change the
semantic of the program, but you shouldn’t rely on that.
>
> The lint also cannot figure out whether the function you call is
actually expensive to call or not.
Still worth it to keep our happy paths clean, imo.
This combines `SidePanel` and `TopBottomPanel` into a single `Panel`.
The old types are still there as type aliases, but are deprecated.
`.min_width(…)` etc are now called `.min_size(…)` etc.
Again, the old names are still there, but deprecated.
(edited by @emilk)
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
* Closes https://github.com/emilk/egui/issues/5889
See the above issue for motivation.
To use glow instead, disable the default features of `eframe` and opt-in
to `glow`.
This also changes egui.rs to use wgpu, which means WebGPU when
available, and WebGL otherwise
This PR enables users of `egui-wgpu` to render `epaint` primitives
without having to bring in the complete `egui` crate and all it's
dependencies.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
* Part of https://github.com/emilk/egui/issues/5889
* Closes https://github.com/emilk/egui/issues/7106
This changes the `eframe/wgpu` feature to also enable all the `default`
features of `wgpu` and `egui-wgpu`. This makes switching `eframe`
backend from `glow` to `wgpu` a lot easier.
To get the old behavior (depend on `wgpu` but you must opt-in to all its
features), use the new `wgpu_no_default_features` feature.
* Closes#7657
* [x] I have followed the instructions in the PR template
On native this uses a new "touch phase" parameter of the mouse wheel
event to know if a scroll action is done.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
## Short bluesky announcement:
We just released egui 0.33.0!
Highlights:
- `egui::Plugin` a improved way to create and access egui plugins
- [kitdiff](https://github.com/rerun-io/kitdiff), a viewer for
egui_kittest image snapshots (and a general image diff tool)
- better kerning (check the diff on
[kitdiff](https://rerun-io.github.io/kitdiff/?url=https://github.com/emilk/egui/pull/7431))
https://github.com/user-attachments/assets/971f0493-6dae-42e5-8019-58b74cf5d203
## Relaese Changelog:
egui is an easy-to-use immediate mode GUI for Rust that runs on both web
and native.
Try it now: <https://www.egui.rs/>
egui development is sponsored by [Rerun](https://www.rerun.io/), a
startup building an SDK for visualizing streams of multimodal data.
# egui 0.33.0 changelog
Highlights from this release:
- `egui::Plugin` a improved way to create and access egui plugins
- [kitdiff](https://github.com/rerun-io/kitdiff), a viewer for
egui_kittest image snapshots (and a general image diff tool)
- better kerning
### Improved kerning
As a step towards using [parley](https://github.com/linebender/parley)
for font rendering, @valadaptive has refactored the font loading and
rendering code. A result of this (next to the font rendering code being
much nicer now) is improved kerning.
Notice how the c moved away from the k:

### `egui::Plugin` trait
We've added a new trait-based plugin api, meant to replace
`Context::on_begin_pass` and `Context::on_end_pass`.
This makes it a lot easier to handle state in your plugins. Instead of
having to write to egui memory it can live right on your plugin struct.
The trait based api also makes easier to add new hooks that plugins can
use. In addition to `on_begin_pass` and `on_end_pass`, the `Plugin`
trait now has a `input_hook` and `output_hook` which you can use to
inspect / modify the `RawInput` / `FullOutput`.
### kitdiff, a image diff viewer
At rerun we have a ton of snapshots. Some PRs will change most of them
(e.g. [the](https://github.com/rerun-io/rerun/pull/11253/files)
[one](https://rerun-io.github.io/kitdiff/?url=https://github.com/rerun-io/rerun/pull/11253/files)
that updated egui and introduced the kerning improvements, ~500
snapshots changed!).
If you really want to look at every changed snapshot it better be as
efficient as possible, and the experience on github, fiddeling with the
sliders, is kind of frustrating.
In order to fix this, we've made
[kitdiff](https://rerun-io.github.io/kitdiff/).
You can use it locally via
- `kitdiff files .` will search for .new.png and .diff.png files
- `kitdiff git` will compare the current files to the default branch
(main/master)
Or in the browser via
- going to https://rerun-io.github.io/kitdiff/ and pasting a PR or
github artifact url
- linking to kitdiff via e.g. a github workflow
`https://rerun-io.github.io/kitdiff/?url=<link_to_pr_or_artefact>`
To install kitdiff run `cargo install --git
https://github.com/rerun-io/kitdiff`
Here is a video showing the kerning changes in kitdiff ([try it
yourself](https://rerun-io.github.io/kitdiff/?url=https://github.com/rerun-io/rerun/pull/11253/files)):
https://github.com/user-attachments/assets/74640af1-09ba-435a-9d0c-2cbeee140c8f
### Migration guide
- `egui::Mutex` now has a timeout as a simple deadlock detection
- If you use a `egui::Mutex` in some place where it's held for longer
than a single frame, you should switch to the std mutex or parking_lot
instead (egui mutexes are wrappers around parking lot)
- `screen_rect` is deprecated
- In order to support safe areas, egui now has `viewport_rect` and
`content_rect`.
- Update all usages of `screen_rect` to `content_rect`, unless you are
sure that you want to draw outside the `safe area` (which would mean
your Ui may be covered by notches, system ui, etc.)