1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 22:53:14 -04:00
Commit Graph

4344 Commits

Author SHA1 Message Date
lucasmerlin
c3a9b8d59f egui_kittest_mcp: delete the stdio shim; unify launch with attach
The kittest harness now dials the inspection socket directly, so the
stdio-relay shim is dead. Delete src/shim.rs and the dual-role main
(drop KITTEST_MCP_HANDSHAKE). Bridge::launch now reuses prepare_attach +
accept_pending: bind a socket, spawn the child with EGUI_INSPECTION_SOCKET
set (no more KITTEST_INSPECTOR / _PATH / current_exe), inherit stderr so
panics surface, and use a generous accept timeout for the compile-then-run
child.
2026-05-26 16:34:01 +02:00
lucasmerlin
732e81017e egui_kittest_mcp: pass through PNG frames; inherit child stderr
- Screenshots now arrive pre-encoded as PNG; drop the local re-encode helper and the
  direct `image` dependency.
- Drop the now-removed egui_inspection `protocol` feature.
- Inherit the spawned child's stderr so its panics and logs surface.
2026-05-26 16:34:01 +02:00
lucasmerlin
2fced8012c egui_kittest_mcp: cross-platform local socket via interprocess
Port the bridge listener (was tokio::net::UnixListener) and the shim client
(was std::os::unix::net::UnixStream) to the interprocess crate, so the MCP
inspection transport builds and runs on Windows (named pipe) as well as
unix/macOS (unix domain socket).

- bridge: bind via interprocess local_socket::tokio Listener + ListenerOptions;
  accept() yields a single Stream, split into async halves. read/write_message
  are now generic over AsyncRead/AsyncWrite.
- shim: connect via interprocess sync Stream and split for the byte relay;
  closing the write direction is done by dropping the send half.
- Allocate/parse socket names through egui_inspection::transport, so both ends
  agree on the platform-specific mapping. Drop the now-unused tempfile dep.
- Add a transport round-trip test (tokio listener <-> sync client).
2026-05-26 16:34:01 +02:00
lucasmerlin
e15ba138d6 Add egui_kittest_mcp server
New binary crate that exposes an MCP (Model Context Protocol) server backed by
the `egui_inspection` protocol. The server bridges a running egui peer — a
spawned `egui_kittest` harness child process or an attached live `eframe` app —
to MCP tool handlers that drive it.

Components:
- `bridge.rs`: spawns / attaches a peer over a unix socket, runs reader+writer
  Tokio tasks that pump `HarnessMessage` ↔ `InspectorCommand` and track the
  peer's `Hello`, latest frame, accesskit tree, and blocked / finished state.
- `tools.rs`: `rmcp`-derived tool router with commands for stepping, event
  injection (click / type / scroll / hover / drag / keys), resizing, screenshot
  capture, accesskit tree queries, and lifecycle (launch / attach / kill).
- `tree.rs`: accesskit-tree projection helpers shared by the tools.
- `shim.rs` / `main.rs`: shim role that lets the same binary act as the child
  inspector for kittest harnesses, relaying bytes between the harness stdio
  and the MCP server's unix socket.
- `server.rs`: rmcp stdio entry point.

Live-app example added at `examples/egui_mcp/`.
2026-05-26 16:34:01 +02:00
lucasmerlin
e3bdddf306 egui_kittest: connect inspector over local socket instead of child stdio
The harness inspector now speaks the wire protocol over the same
interprocess local socket as the live egui_inspection plugin, in two
modes:
- connect: EGUI_INSPECTION_SOCKET set -> dial the listening socket
  (e.g. the kittest MCP bridge).
- spawn: KITTEST_INSPECTOR truthy, no socket -> bind a socket, spawn
  the kittest_inspector binary pointed at it, accept.

env_enabled() now also auto-enables when the socket var is set. Pulls
egui_inspection/transport into the inspector_api feature.
2026-05-26 16:33:56 +02:00
lucasmerlin
501eaba386 egui_kittest: PNG-encode inspector screenshots via shared egui_inspection::encode_png
- Encode harness frames with egui_inspection::encode_png instead of sending raw RGBA, so
  the inspector socket carries compressed bytes.
- Features: pull egui_inspection/png + image/png for the encoder; drop the now-removed
  egui_inspection `protocol` feature.
2026-05-26 16:33:56 +02:00
lucasmerlin
e3414bec9d Add plugin-based kittest inspector
New `InspectorPlugin` (gated behind `inspector` feature) launches a
`kittest_inspector` child process and streams the harness's frames + accesskit
tree updates to it over framed MessagePack on stdin/stdout. The inspector
drives the harness by sending `InspectorCommand`s back; supported commands
include `Step` / `Run` / `Play` / `Pause` (deterministic stepping),
`Handle { events }` (event injection), `Resize`, and `Screenshot`.

Auto-attaches when the `KITTEST_INSPECTOR` env var is truthy — the inspector
binary path can be overridden via `KITTEST_INSPECTOR_PATH`. Uses the new
`egui_inspection::protocol` types and starts every connection with a
`HarnessMessage::Hello { peer_kind: Kittest, capabilities: KITTEST }` so the
inspector can render the right controls.

Also re-exports `egui_inspection` as `egui_kittest::inspector_api` for crates
that only depend on kittest.
2026-05-26 16:33:56 +02:00
lucasmerlin
6e679fdefc Use mem::take for snapshot_results instead of Option
The wrapping Option only existed so Drop could consume SnapshotResults
before plugins fire. mem::take swaps in a fresh default instead, dropping
the original — same outcome with no Option-juggling at every call site
(no more .as_mut().expect(...), and take_snapshot_results stops needing
.replace()).

The default SnapshotResults has handled = true so dropping the placeholder
is a no-op.
2026-05-26 16:33:56 +02:00
lucasmerlin
19e414fa93 Fix plugin example and remove plugin test 2026-05-26 16:33:56 +02:00
lucasmerlin
97c661263e Cleanup: rename plugin_dispatch to dispatch, drop fail_ref
Drop the redundant `plugin_` prefix on the dispatch helper (it's already a
method on `Harness`). Make `TestResult` `Copy` so it can be passed by value
inside the dispatch closure, removing the need for the `fail_ref` re-borrow
helper. Also drop the empty-plugins early-return microopt in `dispatch` —
the `mem::take`/`extend` dance is cheap on empty vecs.
2026-05-26 16:33:56 +02:00
lucasmerlin
c71e6e2c6a Pass accesskit tree to after_step, drop on_accesskit_update
Replaces the separate on_accesskit_update hook with a `&TreeUpdate`
parameter on `after_step` — one hook per step, tree delivered inline.
`step_no_side_effects` now returns the TreeUpdate so plugins driving
the harness from within their own hook (where nested dispatches are
suppressed) can still see it.

Also adds `#[track_caller]` to the internal `_step` / `_step_no_side_effects`
/ `_try_run` so `Location::caller()` inside `step()` walks up to the
user's original call site when reached via `run()`.
2026-05-26 16:33:56 +02:00
lucasmerlin
c6490fcaf7 More cleanup 2026-05-26 16:33:56 +02:00
lucasmerlin
121fa3447a Remove last_accesskit_update and add on_accesskit_update hook 2026-05-26 16:33:56 +02:00
lucasmerlin
2cb6b4b733 Remove some slightly overengineered stuff 2026-05-26 16:33:55 +02:00
lucasmerlin
e12b76365a Add example plugin 2026-05-26 16:33:55 +02:00
lucasmerlin
98cc957e8d Remove the as_any fns 2026-05-26 16:33:55 +02:00
lucasmerlin
62575e6345 Add kittest::Plugin 2026-05-26 16:33:55 +02:00
lucasmerlin
b27bc2b9ea egui_inspection: add transport connect/Listener helpers
Add transport::connect (dial + split) and a sync transport::Listener
(bind + accept) so both ends of the inspection connection build streams
identically without depending on interprocess directly. Plugin now dials
via transport::connect. These back the kittest harness moving onto the
same local socket as the live plugin.
2026-05-26 16:33:44 +02:00
lucasmerlin
72389ed5a8 egui_inspection: PNG-encode screenshots on the wire; collapse protocol feature
- FrameScreenshot now carries PNG bytes instead of raw RGBA (PROTOCOL_VERSION 1→2);
  add a shared `encode_png` helper behind a new `png` feature so the live plugin and the
  kittest harness encode frames identically.
- Make the protocol module unconditional: drop the `protocol` feature flag and the
  optional serde/serde_bytes/rmp-serde deps it gated.
- plugin.rs: re-stamp screenshot-bearing frames with the current step (so inspectors
  waiting for step > prev don't reject them) and pump a tail-side repaint while awaiting
  the GPU readback.
2026-05-26 16:20:07 +02:00
lucasmerlin
d67862ace6 egui_inspection: cross-platform local socket via interprocess
Replace std::os::unix::net::UnixStream in the InspectionPlugin with the
interprocess crate's local_socket::Stream, so the transport works on Windows
(named pipe) as well as unix/macOS (unix domain socket).

- New transport module (transport feature) with socket_name() and
  generate_socket_target() — one shared, platform-split place to build/allocate
  local-socket names, used by both ends of the connection.
- Drop the cfg(unix) gates on the plugin module; gate on the plugin feature only.
- attach() now takes a socket name string and connects via interprocess; the
  stream is split with Stream::split() instead of UnixStream::try_clone().
2026-05-26 14:26:18 +02:00
lucasmerlin
622218e94f Add egui_inspection crate and eframe inspection hooks
New `egui_inspection` crate ships:
- `protocol` (default): wire types + length-prefixed msgpack framing for the
  inspector ↔ egui-peer connection. Transport-neutral (stdio / unix socket / TCP).
- `plugin`: `InspectionPlugin`, an `egui::Plugin` that dials a unix socket from
  `EGUI_INSPECTION_SOCKET`, streams frames + accesskit tree updates, and applies
  inbound `InspectorCommand`s back into the running `egui::Context`.

eframe gains an `inspection` feature that auto-attaches the plugin during native
startup (glow + wgpu integrations) when the env var is set. Connection failures
log via `log::warn!` and do not abort startup.

Lives in its own crate (rather than `egui_kittest`) so eframe can pull the
protocol in without picking up the test harness, and so external tools can
depend on it directly.
2026-05-26 11:37:01 +02:00
Emil Ernerfeldt
a41bba33a0 Smoother collapsed-panel animation (#8202)
* Follows https://github.com/emilk/egui/pull/8199

This makes the animation of the collapsing panel a bit smoother, by
taking into account the spacing between the header and the body.
2026-05-26 10:59:39 +02:00
Emil Ernerfeldt
0ce2b3699b Panel: never overflow available width, nor max_width (#8198)
* Closes https://github.com/emilk/egui/issues/8055
* Closes https://github.com/emilk/egui/pull/8056

This changes the behavior of `Panel` to NEVER overflow
`Panel::max_size`, nor the available space in the parent UI.

If you do overflow it, the content will be silently clipped.
2026-05-26 10:54:38 +02:00
Emil Ernerfeldt
fc1b2a99fd Rename AlphaFromCoverage to FontColorTransferFunction (#8201)
`ab_glyph` would output coverage values, but `vello` outputs RGBA. So
the old name was a misnomer.

I also suspect our default values are wrong, but I need to investigate
that more properly in a separate PR.
2026-05-26 10:51:39 +02:00
Emil Ernerfeldt
71f22ff1a5 Improve panel example (#8200) 2026-05-25 15:45:00 +02:00
Emil Ernerfeldt
5669725b1c Smoother panel animation (#8199) 2026-05-25 15:25:26 +02:00
Patrik Hampel
f57291bac0 Choose restored window monitor by overlap (#8191)
This changes the monitor selection used when restoring a persisted
window position.

Currently, `egui-winit` picks a monitor by checking whether the saved
window position fits inside a loose monitor range. This can choose the
wrong monitor when a saved window rectangle slightly overlaps another
monitor.

My failure case was on Windows with two monitors:
- primary monitor on the right
- secondary monitor on the left
- window maximized on the primary monitor
- persisted outer position was slightly negative, e.g. `x = -8`, because
of the invisible window border

That position matched both monitor ranges, so the restored maximized
window could
open on the secondary monitor instead of the primary one.

This PR picks the monitor with the largest overlap with the saved window
rectangle instead.

Related note: probably the best solution would be to save the normal
window position when maximized, so that when unmaximizing, the window
would get restored to the previous state. It's mentioned in this comment
https://github.com/emilk/egui/issues/3494#issuecomment-1986985211. I
tried doing that in
[fix-windows-maximized-restore-placement](https://github.com/YelovSK/egui/tree/fix-windows-maximized-restore-placement),
and it works, but it requires adding windows-sys as a dependency to call
a relevant winapi, so that's probably not the right solution. Winit
doesn't seem to provide an API that would return this information.

* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
2026-05-25 12:10:07 +02:00
Emil Ernerfeldt
4a897168a6 generate_changelog.py: use gh-cli instead of access token (#8197) 2026-05-25 12:09:54 +02:00
Emil Ernerfeldt
46c20810ba Remove impl Into<f32> arguments (#8194)
* Closes https://github.com/emilk/egui/issues/8179
2026-05-25 10:59:03 +02:00
Anders Conbere
67322e3ebf Improve FileLoader file uri to path handling for windows (#8163)
Current behavior fails when translating file uris that contain windows
UNC paths. This commit attempts to fix that behavior by looking at the
hostname attribute of the uri and changing behavior if the hostname is
present.

* Closes <https://github.com/emilk/egui/issues/8161>
* [x] I have followed the instructions in the PR template
2026-05-25 10:50:31 +02:00
Emil Ernerfeldt
22d1fa8f5b Panels: double-click resize edge to toggle (#8193)
Double-clicking the edge of a resizable panel will now toggle it
collapsed/expanded
2026-05-24 12:32:03 +02:00
Emil Ernerfeldt
27559ef3fd Rename Panel methods (#8192)
The three methods for showing a `Panel` are now:

* `panel.show`: always show the panel.
* `panel.show_collapsible`: show or hide the panel, with a slide
animation in between.
* `Panel::show_switched`: animate between two different panels: a
thin/collapsed one and a thick/expanded one.
2026-05-24 12:22:32 +02:00
Emil Ernerfeldt
3cf844c542 Drag-to-close panels (#8182)
* Closes https://github.com/emilk/egui/pull/7254

You can now drag-to-close a panel. Also drag-to-expand panels.

This is a breaking change: the animated panel functions now take a
`open: &mut bool` instead of `open: bool`.

This is only enabled for resizable panels
2026-05-22 16:05:39 +02:00
all3f0r1
dcefb2e3b8 Add Context::set_cursor_image for OS-level custom cursors (#8155)
## What

Adds a way for apps to push an RGBA bitmap as the OS cursor — the
missing companion to `Context::set_cursor_icon`. The integration
translates it into a real `winit::CustomCursor`, so the cursor is drawn
by the compositor and can extend past the egui window edge like any
native cursor.

## Why

Apps with custom-shaped windows (Winamp-style skins, themed launchers,
kiosk apps) currently have no clean way to display a custom cursor:
- `CursorIcon` is limited to the standard system enum.
- Painting the cursor sprite via `egui::Painter` works inside the canvas
but gets clipped at the window edge — the bottom/right of the cursor
disappears the moment the pointer is near the boundary, and there's no
way to render onto the desktop area exposed by a
transparent/region-shaped window.

`winit` 0.30+ already supports `CustomCursor::from_rgba` +
`ActiveEventLoop::create_custom_cursor`, but `egui-winit` doesn't
surface it. This PR exposes it through egui.

### Visual demonstration

Driving use case: a Winamp WSZ skin player
([all3f0r1/oneamp](https://github.com/all3f0r1/oneamp)) with a
transparent + region-shaped window where the skin ships its own `.cur`
files. The bottom-right corner of the playlist exposes the resize cursor
— notice how it gets clipped at the window edge in the painter-based
approach.

| Before (cursor painted via `egui::Painter`) | After (cursor pushed via
`set_cursor_image`) |
| --- | --- |
| ![cursor clipped at the bottom-right of the playlist
window](https://raw.githubusercontent.com/all3f0r1/egui/pr-assets/cursor-clipping-before.png)
| ![cursor extends cleanly past the window edge onto the
desktop](https://raw.githubusercontent.com/all3f0r1/egui/pr-assets/cursor-clipping-after.png)
|

## API

```rust
// new in egui::data::output
pub struct CustomCursorImage {
    pub rgba: std::sync::Arc<[u8]>,
    pub size: [u16; 2],     // matches winit's u16 to avoid lossy casts
    pub hotspot: [u16; 2],
}

// new field on PlatformOutput (skipped from serde — ephemeral)
pub cursor_image: Option<CustomCursorImage>,

// new method on Context
ctx.set_cursor_image(Some(image)); // overrides cursor_icon for this frame
ctx.set_cursor_image(None);        // revert to cursor_icon
```

`Arc<[u8]>` is intentional: the integration dedupes by `Arc::as_ptr`, so
reusing the same Arc across frames means the bitmap is only uploaded to
the OS once per skin, not once per frame.

## Integration changes

- `egui_winit::State::handle_platform_output_with_event_loop(window,
Option<&ActiveEventLoop>, ...)` is a new method that threads the active
event loop so it can call `event_loop.create_custom_cursor(...)`.
- The legacy `handle_platform_output(window, ...)` delegates with `None`
and silently drops `cursor_image`. **No existing callers break.**
- The icon and bitmap paths are unified in a private `apply_cursor`. The
no-flicker dedupe of the old `set_cursor_icon` is preserved on both
paths.
- If `CustomCursor::from_rgba` rejects the bitmap (bad dimensions,
hotspot OOB, etc.), we log a warning and fall back to the icon path.
- eframe's wgpu + glow integrations thread `&ActiveEventLoop` through
`run_ui_and_paint` (glow already had it; wgpu needed one extra
parameter) and call the new method.
- Immediate viewports keep the old path because they're invoked from a
`Context` callback that doesn't have an event loop reference. Custom
cursors are a no-op in immediate viewports — acceptable since they're a
niche path.

## Fallback semantics

| backend / context              | what happens                  |
|--------------------------------|-------------------------------|
| eframe wgpu/glow main viewport | bitmap displayed via OS       |
| eframe immediate viewport      | falls back to `cursor_icon`   |
| eframe web                     | falls back to `cursor_icon`   |
| custom integrations not opted in | falls back to `cursor_icon` |
| `from_rgba` returns `BadImage` | warning + falls back to icon  |

## Verification

- `cargo fmt --all -- --check` 
- `cargo clippy -p egui -p egui-winit -p eframe --all-targets
--all-features -- -D warnings` 
- `cargo doc --lib --no-deps -p egui -p egui-winit -p eframe
--all-features` 
- `cargo check -p egui --no-default-features --features serde` 
(validates the `serde(skip)` on `cursor_image`)
- Interactive validation on Linux/Wayland with the OneAmp WSZ skin
player — see screenshots above.

I haven't run the full snapshot test suite (`scripts/check.sh`) because
we're on Linux and the snapshots are macOS-rendered — happy to run it if
you'd like.

## Notes

Drafted per the contributing guide ("open a draft PR, you may get
helpful feedback early"). Open to design feedback on:
1. Whether `CustomCursorImage` should live in `egui::viewport` rather
than `egui::data::output`.
2. Whether the legacy `handle_platform_output` should grow `event_loop`
directly (breaking) instead of getting a sibling method (non-breaking,
what I did).
3. Whether to also wire it through eframe-web (probably not —
`wasm-bindgen-cursor` would need its own path).

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 15:31:52 +02:00
Emil Ernerfeldt
e925a41419 Fix glyph caching on font variations (#8189)
* Closes https://github.com/emilk/egui/pull/8029

---------

Co-authored-by: lucasmerlin <hi@lucasmerlin.me>
2026-05-22 15:30:21 +02:00
Emil Ernerfeldt
3888087dc5 Add AsId and IdSalt (#8184)
## Related
* https://github.com/emilk/egui/pull/5851
* https://github.com/emilk/egui/pull/7988

## What
We want to make it easier to understand the lineage of a `Id` (which is
the parent `Id`, and the parent of that, etc?)

As a first step of that, we want to clarify the different between a
globally unique `Id`, and an `IdSalt`

I also introduced the `AsId` and `AsIdSalt` traits, which are
implemented of anything that implements `Hash` and `Debug`. The `Debug`
half of that is unused here, but will later be used in `Debug` builds to
produce a proper tree.
2026-05-22 15:19:55 +02:00
Emil Ernerfeldt
bea47a2ce7 Window: move only by dragging title bar (#8183)
* Part of https://github.com/emilk/egui/issues/8180

So far, you've been able to move any `egui::Window` by dragging anywhere
on it. This makes sense on touch screens with thick fingers, but less so
on non-touch-screens.

With this PR, you can now control it with a new enum `WindowDrag`
2026-05-22 12:39:43 +02:00
Emil Ernerfeldt
27373b06d0 Style: forbid .zip and .chain (#8188)
The `zip(a, b)` variant produces clearer code imho.

Downside: added dependency on `itertools`
2026-05-22 12:25:34 +02:00
Emil Ernerfeldt
ac2496318f Update to skrifa 0.42.1 (#8187) 2026-05-22 12:07:37 +02:00
Emil Ernerfeldt
c4599a7340 Update to criterion 0.8.2 (#8186) 2026-05-22 12:07:28 +02:00
Emil Ernerfeldt
7d261bc311 Update to puffin 0.20 (#8185) 2026-05-22 11:57:06 +02:00
Emil Ernerfeldt
e64b7683a2 Drag-to-scroll: now only on touch screens (#8181)
* Part of https://github.com/emilk/egui/issues/8180

Drag-to-scroll is a must-have on touch-screens, since there is no other
way to scroll.

However, when you are not on a touch screens, it is more surprising than
useful.
2026-05-20 10:41:51 +02:00
Jochen Görtler
07c6e0de0f Exclude take_app from wasm32 in egui_kittest (#8178)
Otherwise `egui` won't compile for `wasm32` targets anymore.

A bit odd that this was not caught in CI.
2026-05-19 18:00:50 +02:00
Emil Ernerfeldt
9650ef85d6 Smoother CollapsingHeader animation (#8177)
Animate the spacing between the header and the body. It's subtle, but
looks slightly nicer when closing a panel.
2026-05-19 17:09:33 +02:00
Emil Ernerfeldt
f91b3ac10b Slow down animation time from 0.1s to 0.2s (#8176)
We now have easings, and we have nice animations of panels. I think
100ms feels a bit rushed now. 200ms feels nicer.
2026-05-19 16:20:05 +02:00
Emil Ernerfeldt
f9f589f460 Slide panels when animating them (#8175)
This looks A LOT nicer


https://github.com/user-attachments/assets/6f208e6c-6b6d-46d2-a40d-832be1256ca7
2026-05-19 15:53:05 +02:00
Jochen Görtler
a5ba0d23ce Default app_id to app_name on native (#8172)
### Related

* Closes #7872.

### What

On native (this is not limited to Wayland) we set the `app_id` to the
`app_name` if it is `None`.
2026-05-19 15:51:25 +02:00
Emil Ernerfeldt
85ad9cac7e Rework Window margins and set clip_rect_margin to zero (#7725)
* Follows https://github.com/emilk/egui/pull/7722
* Part of https://github.com/emilk/egui/issues/5605
* Closes https://github.com/emilk/egui/issues/3385

## What
Sets `clip_rect_margin` to zero, and moves the margin of `Window`s with
`ScrollAreas`, so that the scroll bars are now on the very edge of the
windows they are in.

Windows with a bulit-in scroll area now lets the content go all the way
to the edges (left image).
However, if you just manually add a `ScrollArea` to a `Window`, you
won't get this effect (right image).
<img width="763" height="345" alt="Screenshot 2026-05-18 at 22 04 01"
src="https://github.com/user-attachments/assets/e41cdfcb-b0a6-4e5e-9691-d132a602d6a7"
/>

## Required
* #7803
* #7804
* #7805
* #7806
* https://github.com/emilk/egui/pull/7807
* https://github.com/emilk/egui/pull/7808
2026-05-19 15:43:42 +02:00
Emil Ernerfeldt
bcfb5bf493 Refactor Panels (#8174)
In preparation for nicer panel animation.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-19 14:41:16 +02:00
Jochen Görtler
7dba2e99fa Fix random hangs by improving wgpu::Surface lifecycle handling (#8171)
### Related

* Closes #8134.
* Related to #5136.

Possibly fixes:

* #8123
* #5145 

### What

We did not properly handle the variants of
[`CurrentSurfaceTexture`](https://docs.rs/wgpu/latest/wgpu/enum.CurrentSurfaceTexture.html)
and always returned `SkipFrame`.

Because of this `egui` could end up in a state where frames are always
skipped after observing `Outdated`, without the chance to recover
(unless an event arrives from the outside).

> [!NOTE]
> This is not Wayland-specific, but could happen on all platforms. It
just happens frequently for Wayland compositors that directly resize a
window after creation (such as tiling/scrolling compositors like
`hyprland` and `niri`).

This PR improves this by separating the code paths for `Outdated` and
`Lost`, to help recover from those events.
2026-05-19 11:06:09 +02:00