* Rename `StyleProvider::theme_type_id` to `type_id`
* Reword the `Ui::widget_style` docstring
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`widget_style.rs` becomes `widget_style/mod.rs`, with `Classes`,
`HasClasses`, `ClassName` and the class constants in `widget_style/classes.rs`.
All public paths are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Move each type into its own file under `crates/egui/src/theme/`:
`StyleProvider`, `ThemeCache`, `DefaultStyle`, and `Themes`.
The module is renamed `egui::theme_plugin` -> `egui::theme`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The `textures_delta` in `AppRunner::logic()` comes from
`TextureManager::take_delta()` via `end_pass()`. Previously, if
`is_visible` was `false`, these deltas would have been dropped and never
applied, so the `TextureManager` state gets out of sync with the
`Renderer`.
That causes https://github.com/emilk/egui/issues/8228: When the app is
loaded in a background tab and the first frame occurs via the
`setTimeout` path prior to the tab becoming visible, it loses the
`ImageDelta` representing the initial creation of the font atlas
texture. When the user then switches to the tab, it panics at
crates/egui-wgpu/src/renderer.rs:669:18 with `Tried to update a texture
that has not been allocated yet` when attempting to update the texture
that the wgpu renderer never saw when it was created.
Testing: To make it load in a background tab, put `data:text/html,<a
href=http://127.0.0.1:8765/>Click</a>` in the address bar and then
middle click the resulting link. On Chrome you also have to hover the
tab preview before switching to the tab to reproduce the issue.
<!--
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!
-->
* Closes <https://github.com/emilk/egui/issues/8228> and its duplicate
https://github.com/emilk/egui/issues/8278
* [x] I have followed the instructions in the PR template
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
After upgrading to wgpu v30, it requires to drop the `BufferView` return
by `get_mapped_range` before unmap the buffer. Fix it in this pr, making
screenshot event crash no more
- needs #8335
Previously it was impossible to correctly set modifiers via egui
inspection, since that only passes egui::Event and egui::Event had no
way to generally express modifiers.
Now modifiers are passed to egui as a Event and not as a field of
`RawInput`.
---------
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
## Summary
- [x] I have followed the instructions in the PR template
Fixes comment-style violations of the `CONTRIBUTING.md` code style rule:
> `// Comment like this.` and not `//like this`
### Files changed
- `crates/epaint/src/shapes/bezier_shape.rs`: `//temporary solution` →
`// temporary solution`, and 22× `//add the start point` → `// add the
start point`
- `crates/egui/src/animation_manager.rs`: `//start new animation…` → `//
start new animation…`
- `crates/eframe/src/web/web_painter_wgpu.rs`:
`//create_new.instance_descriptor…` → `//
create_new.instance_descriptor…`
No code logic changes — only adding the missing space after `//` in
inline and standalone comments.
## Test plan
- [x] `cargo fmt --check`
- [x] `cargo clippy -p epaint -p egui`
- [x] `cargo test -p epaint --lib`
## Summary
- [x] I have followed the instructions in the PR template
Fixes the 12 failing `cargo-deny` CI checks on `main` (introduced by
#8289).
### Root cause
`rustybuzz` was flagged as unmaintained by
[RUSTSEC-2026-0206](https://rustsec.org/advisories/RUSTSEC-2026-0206),
reported on 2026-07-12 — after the previous cargo-deny fix (#8300) was
merged on 2026-07-07. The advisory fires on all 12 cargo-deny target
triples.
`rustybuzz` is pulled in transitively via `resvg` → `usvg`, which
`egui_extras` uses for SVG support.
### Why ignore (not fix)?
- `resvg` is pinned at `0.45.1` and cannot be bumped: `0.47` needs
`tiny-skia 0.12`, but `winit 0.30`'s `sctk-adwaita` is stuck on
`tiny-skia 0.11` (see comment in `Cargo.toml` line 128).
- The advisory's recommended replacement is
[`harfrust`](https://github.com/harfbuzz/harfrust), which `resvg` has
not adopted yet.
- This is the same pattern used for the other transitively-unmaintained
advisories already in the ignore list (`ttf-parser` via winit,
`quick-xml` via accesskit/wayland, `bincode`, `yaml-rust`).
### Change
Added `RUSTSEC-2026-0206` to the `[advisories] ignore` list in
`deny.toml` with an explanatory comment.
## Test plan
- [x] `cargo deny check advisories` — passes (`advisories ok`)
- [x] `cargo deny check` — all sections pass (`advisories ok, bans ok,
licenses ok, sources ok`)
---------
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
* Closes <https://github.com/emilk/egui/issues/8115>
* [x] I have followed the instructions in the PR template
## Summary
- Recalculate a menu popup's cached `Area` size when it reopens.
- Preserve cached sizing for continuously open menus and leave tooltips
and general popups unchanged.
- Add a headless regression test covering a wider item added while the
menu is closed.
## Root cause
`Area` keeps its cached size after a menu closes. When that menu
reopened with wider content, the
cached width constrained the new item and caused it to wrap instead of
allowing the popup to grow.
The fix requests the same invisible sizing pass used for a first-open
`Area` whenever a menu was not
open during the previous frame.
## User impact
Menus now expand to fit newly added wider items after reopening.
Existing wrapping, explicit-width,
alignment, screen-constraining, and continuously open menu behavior
remain unchanged.
## Validation
- `cargo test -p egui_kittest --test menu`
- `cargo check -p egui`
- `cargo fmt --all -- --check`
* Closes <https://github.com/emilk/egui/issues/8295>
* [x] I have followed the instructions in the PR template
When an eframe app is embedded in a scrollable host page, the host page
jumped to the top whenever the app booted or grabbed keyboard focus.
Cause: the hidden text-agent `<input>` sat at (0,0) of `<body>` with the
`autofocus` attribute, and all focus calls (text agent and canvas) used
plain `focus()`, so the browser scrolled the focused element into view —
i.e. to the top of the page.
Changes:
* All focus calls in `eframe` web (text agent, canvas, Gboard
blur/refocus workaround) now go through a new `focus_without_scroll()`
helper that uses `focus_with_options` with `preventScroll: true`
(supported by all evergreen browsers).
* The `autofocus` attribute is replaced with an explicit focus call
after DOM insertion — the browser-internal autofocus path always scrolls
the element into view and cannot be prevented by any focus option.
Boot-focus behavior is preserved.
* The text-agent input is initially parked at the canvas origin instead
of (0,0) of the page, so any residual scroll-into-view would target the
canvas rather than the top of the host page. (`move_to` keeps
repositioning it for IME as before.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Semver-compatible dependency updates (~200 transitive crates in
`Cargo.lock`), plus housekeeping of the version pins in `Cargo.toml`.
## Changes
* Normalize version strings in `[workspace.dependencies]`
(`similar-asserts = "2.0"`, `unicode_names2 = "3.1"`)
* `cargo update`: bump all semver-compatible transitive dependencies
* `itertools` 0.14 → 0.15; the duplicate with puffin's 0.14 /
criterion's 0.13 is now allowed in `deny.toml`
* `rand_core` duplicate (0.6 via phf_generator's rand 0.8, 0.10 via
getrandom 0.4/chacha20) also allowed in `deny.toml` — rand ecosystem is
mid-migration
* `toml` lock moved to 1.1.2 — the old winnow-duplicate blocker is gone
(winit's `toml_edit` now uses winnow 1.x), so the stale comment is
removed
* `wgpu` got a lock-only patch bump 29.0.1 → 29.0.4 (still on the 29.x
line; wgpu 30 intentionally not taken)
## Held back (would fail `cargo deny` with duplicate crates)
* `env_logger` 0.11.8 — newer pulls env_filter 1.x, duplicating the
0.1.x that android_logger needs
* `image` 0.25.6 — needs png 0.18, blocked on resvg
* `smithay-clipboard` 0.7.2 — pulls calloop 0.14, duplicating winit's
0.13
* accesskit platform adapters — newer ones need accesskit_consumer
0.36/0.37, duplicating the 0.35 that kittest 0.4 pins (comments added
for `accesskit_consumer`/`accesskit_winit`)
* wasm-bindgen family kept at 0.2.108 per the sync comment
Majors still blocked (documented in `Cargo.toml`):
`font-types`/`skrifa`/`harfrust` (vello_cpu 0.0.9), `resvg` (winit
0.30).
Verified: `scripts/cargo_deny.sh` green on all targets, `cargo clippy
--all-features --all-targets` clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* [x] I have followed the instructions in the PR template
Just a small docs change, since I saw this trip someone up. The ones on
`Response` may be redundant.
## Summary
This fixes macOS live-resize behavior for the `eframe`/`egui-wgpu` path
when using the low-latency wgpu surface configuration.
The problem I was seeing is that native window resize can look visibly
below the baseline expected from a desktop GUI: stale or stretched
frames (manifesting as wobble/jitter), or severe lag while dragging a
window edge.
The fix has three parts:
- use `CAMetalLayer.presentsWithTransaction` during live resize to avoid
stale/stretched frames
- temporarily use at least `desired_maximum_frame_latency = 2` while
live resize is active, so transaction presentation does not stall when
the app normally uses `SurfaceConfig::LOW_LATENCY`
- treat macOS `WindowEvent::Moved` as part of the live-resize event
stream, since resizing from the top or left edge changes the window
origin
This PR depends on the winit-side AppKit live-resize timing fix in
[rust-windowing/winit#4588](https://github.com/rust-windowing/winit/pull/4588)
A renderer-only frame-latency change is not enough by itself. The
temporary latency bump only solves the drawable starvation caused by
combining `presentsWithTransaction` with `SurfaceConfig::LOW_LATENCY`.
It does not change when winit emits resize/redraw events, whether
redraws are delivered during AppKit's live-resize event-tracking loop,
or whether the surface size is derived from the current backing rect.
That is why the winit fix is needed first: it makes the windowing layer
report the current AppKit backing size and request redraws from the
live-resize/display callbacks. egui-wgpu still needs this PR on top
because winit does not own the wgpu `Surface` or the underlying
`CAMetalLayer` presentation policy.
In other words: winit fixes when the windowing layer reports
resize/redraw work, while this PR fixes how egui-wgpu presents
Metal-backed wgpu frames during that resize.
## Why change the existing feature?
The existing `macos-window-resize-jitter-fix` feature addresses one
symptom by enabling transaction presentation during resize, but it is
not enough for the low-latency wgpu path.
In particular, `presentsWithTransaction` and
`SurfaceConfig::LOW_LATENCY` interact poorly during AppKit live resize.
The old code avoids that by [skipping transaction presentation when
latency is
`1`](71c4ff3c33/crates/egui-wgpu/src/winit.rs (L417)),
but that means low-latency users get the resize jitter/wobble back.
This PR keeps the low-latency path normally, but temporarily bumps frame
latency only while live resize is active. That gives the resize path
enough drawable slack without changing normal interaction latency.
I removed the `macos-window-resize-jitter-fix` feature because this
seems like the behavior the macOS wgpu path should have by default, not
a separate opt-in. If keeping the feature as a no-op compatibility alias
is preferred, I can adjust the PR.
## Validation
I created a small demo app that somewhat resembles the layout of my
actual app and highlights both horizontal and vertical resize jitter:
- a borderless macOS window
- a simple toolbar
- a scrolling side list
- `SurfaceConfig::LOW_LATENCY`
The toolbar and list make stale or stretched frames easy to see during
native resize. The jitter is visible even on the traffic light buttons.
Recordings:
### Before 1: no transaction presentation, low latency
Shows jitter/wobble and stale/stretched frames during live resize.
https://github.com/user-attachments/assets/2cf4467b-e14c-4f41-8021-0b8c23f41004
### Before 2: transaction presentation with low latency
Shows the other failure mode: live resize can become severely laggy when
transaction presentation is used while keeping
`SurfaceConfig::LOW_LATENCY`.
https://github.com/user-attachments/assets/2f866790-f472-4ede-a3c0-480e8f0f041a
### After: patched egui-wgpu + patched winit, low latency
No visible wobble/jitter and no severe live-resize lag.
https://github.com/user-attachments/assets/59e46e9f-7906-4b5c-a6c7-1d09eae644cd
---------
Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
<!--
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
This PR adds a `remove_string()` API to the Storage trait and also
implements it in the `FileStorage` and `LocalStorage` stucts.
A get atoms trait for Button, checkbox etc. I made it because I had time
to kill after I tried sorting buttons in a Vec by the image in their
atoms, but couldn't get to it because it was private.
---------
Co-authored-by: Lucas Meurer <hi@lucasmerlin.me>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This is a bit like my previous pr
(<https://github.com/emilk/egui/pull/8037>), but addresses the final bit
of 64 bit atomic dependent code, the svg loader in the `egui_extras`
crate.
As with the previous pr, this improves egui's compatibility on platforms
without 64 bit atomics.
* Closes <https://github.com/emilk/egui/issues/7692>
* [x] I have followed the instructions in the PR template
Fixes#8079, where font hinting only sharpens the vertical axis
(vertical stems stay blurry), and none of the skrifa knobs were
reachable — only switching to `Target::Mono` helped, but that wasn't
exposed.
This makes the hinting target configurable instead of hardcoding
`Target::Smooth { symmetric_rendering: true, preserve_linear_metrics:
true }`.
### API
- New `epaint::text::HintingTarget` mirroring `skrifa::outline::Target`:
- `Mono`
- `Smooth(SmoothHinting)` where `SmoothHinting { light,
symmetric_rendering, preserve_linear_metrics }`
- New field `FontTweak::hinting_target: HintingTarget`.
- Each variant/field is documented with what it does and the
egui-specific caveats (e.g. `symmetric_rendering` only affects
interpreter-hinted fonts; egui positions glyphs from shaper advances so
`preserve_linear_metrics` mostly affects sharpness, not layout).
### Render
- `font.rs` converts `HintingTarget` → `skrifa::outline::Target` and
threads it into the per-glyph `reconfigure` call; the hinting instance
is also reconfigured when the target changes.
### UI
- The font-tweak settings panel gets a `hinting_target` row: Smooth/Mono
radios, `light` / `symmetric_rendering` / `preserve_linear_metrics`
checkboxes, and a `Reset` button — all with tooltips.
### Behavior
- `HintingTarget::default()` matches egui's previous hardcoded target,
so **rendering is unchanged** unless you opt in. To fix the horizontal
blur from #8079, uncheck `preserve_linear_metrics` (or pick `Mono`).
Whether to flip the *default* is left as a follow-up.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>