Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7d261bc
Update to puffin 0.20 (#8185)
emilk May 22, 2026
c4599a7
Update to criterion 0.8.2 (#8186)
emilk May 22, 2026
ac24963
Update to skrifa 0.42.1 (#8187)
emilk May 22, 2026
27373b0
Style: forbid `.zip` and `.chain` (#8188)
emilk May 22, 2026
bea47a2
`Window`: move only by dragging title bar (#8183)
emilk May 22, 2026
3888087
Add `AsId` and `IdSalt` (#8184)
emilk May 22, 2026
e925a41
Fix glyph caching on font variations (#8189)
emilk May 22, 2026
dcefb2e
Add Context::set_cursor_image for OS-level custom cursors (#8155)
all3f0r1 May 22, 2026
3cf844c
Drag-to-close panels (#8182)
emilk May 22, 2026
27559ef
Rename `Panel` methods (#8192)
emilk May 24, 2026
22d1fa8
Panels: double-click resize edge to toggle (#8193)
emilk May 24, 2026
67322e3
Improve FileLoader file uri to path handling for windows (#8163)
aconbere May 25, 2026
46c2081
Remove `impl Into<f32>` arguments (#8194)
emilk May 25, 2026
4a89716
`generate_changelog.py`: use gh-cli instead of access token (#8197)
emilk May 25, 2026
f57291b
Choose restored window monitor by overlap (#8191)
YelovSK May 25, 2026
5669725
Smoother panel animation (#8199)
emilk May 25, 2026
71f22ff
Improve panel example (#8200)
emilk May 25, 2026
fc1b2a9
Rename `AlphaFromCoverage` to `FontColorTransferFunction` (#8201)
emilk May 26, 2026
0ce2b36
`Panel`: never overflow available width, nor `max_width` (#8198)
emilk May 26, 2026
a41bba3
Smoother collapsed-panel animation (#8202)
emilk May 26, 2026
622218e
Add egui_inspection crate and eframe inspection hooks
lucasmerlin May 21, 2026
d67862a
egui_inspection: cross-platform local socket via interprocess
lucasmerlin May 26, 2026
72389ed
egui_inspection: PNG-encode screenshots on the wire; collapse protoco…
lucasmerlin May 26, 2026
b27bc2b
egui_inspection: add transport connect/Listener helpers
lucasmerlin May 26, 2026
62575e6
Add kittest::Plugin
lucasmerlin Apr 23, 2026
98cc957
Remove the as_any fns
lucasmerlin Apr 23, 2026
e12b763
Add example plugin
lucasmerlin Apr 23, 2026
2cb6b4b
Remove some slightly overengineered stuff
lucasmerlin Apr 23, 2026
121fa34
Remove last_accesskit_update and add on_accesskit_update hook
lucasmerlin Apr 24, 2026
c6490fc
More cleanup
lucasmerlin Apr 24, 2026
c71e6e2
Pass accesskit tree to after_step, drop on_accesskit_update
lucasmerlin Apr 24, 2026
97c6612
Cleanup: rename plugin_dispatch to dispatch, drop fail_ref
lucasmerlin Apr 27, 2026
19e414f
Fix plugin example and remove plugin test
lucasmerlin Apr 27, 2026
6e679fd
Use mem::take for snapshot_results instead of Option
lucasmerlin Apr 27, 2026
e3414be
Add plugin-based kittest inspector
lucasmerlin May 21, 2026
501eaba
egui_kittest: PNG-encode inspector screenshots via shared egui_inspec…
lucasmerlin May 26, 2026
e3bdddf
egui_kittest: connect inspector over local socket instead of child stdio
lucasmerlin May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 207 additions & 57 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"crates/egui_demo_lib",
"crates/egui_extras",
"crates/egui_glow",
"crates/egui_inspection",
"crates/egui_kittest",
"crates/egui-wgpu",
"crates/egui-winit",
Expand Down Expand Up @@ -65,6 +66,7 @@ egui_extras = { version = "0.34.2", path = "crates/egui_extras", default-feature
egui-wgpu = { version = "0.34.2", path = "crates/egui-wgpu", default-features = false }
egui_demo_lib = { version = "0.34.2", path = "crates/egui_demo_lib", default-features = false }
egui_glow = { version = "0.34.2", path = "crates/egui_glow", default-features = false }
egui_inspection = { version = "0.34.2", path = "crates/egui_inspection", default-features = false }
egui_kittest = { version = "0.34.2", path = "crates/egui_kittest", default-features = false }
eframe = { version = "0.34.2", path = "crates/eframe", default-features = false }

Expand All @@ -82,7 +84,7 @@ bitflags = "2.9.4"
bytemuck = "1.24.0"
cint = "0.3.1"
color-hex = "0.2.0"
criterion = { version = "0.7.0", default-features = false }
criterion = { version = "0.8.2", default-features = false }
dify = { version = "0.8", default-features = false }
directories = "6.0.0"
document-features = "0.2.11"
Expand All @@ -93,9 +95,10 @@ font-types = { version = "0.11.0", default-features = false, features = ["std"]
glow = "0.17.0"
glutin = { version = "0.32.3", default-features = false }
glutin-winit = { version = "0.5.0", default-features = false }
harfrust = "0.5.2"
harfrust = "0.7.0"
home = "0.5.9"
image = { version = "0.25.6", default-features = false }
itertools = "0.14.0"
jiff = { version = "0.2.23", default-features = false }
js-sys = "0.3.77"
kittest = { version = "0.4.0" }
Expand All @@ -114,19 +117,20 @@ parking_lot = "0.12.5"
percent-encoding = "2.3.2"
poll-promise = { version = "0.3.0", default-features = false }
pollster = "0.4.0"
profiling = { version = "1.0.17", default-features = false }
puffin = "0.19.1"
puffin_http = "0.16.1"
profiling = { version = "1.0.18", default-features = false }
puffin = "0.20.0"
puffin_http = "0.17.0"
rand = "0.9.2"
raw-window-handle = "0.6.2"
rayon = "1.11.0"
resvg = { version = "0.45.1", default-features = false }
rfd = "0.17.2"
rmp-serde = "1.3.1"
ron = "0.12.0"
self_cell = "1.2.1"
serde = { version = "1.0.228", features = ["derive"] }
similar-asserts = "1.7.0"
skrifa = { version = "0.40.0", default-features = false, features = ["std", "autohint_shaping"] }
skrifa = { version = "0.42.1", default-features = false, features = ["std", "autohint_shaping"] }
smallvec = "1.15.1"
smithay-clipboard = "0.7.2"
static_assertions = "1.1.0"
Expand All @@ -139,7 +143,7 @@ type-map = "0.5.1"
unicode_names2 = { version = "2.0.0", default-features = false }
unicode-general-category = "1.1.0"
unicode-segmentation = "1.12.0"
vello_cpu = { version = "0.0.7", default-features = false, features = [
vello_cpu = { version = "0.0.8", default-features = false, features = [
"std",
"u8_pipeline",
"f32_pipeline",
Expand Down
2 changes: 1 addition & 1 deletion crates/ecolor/src/color32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ mod test {
} else {
// There will be small rounding errors whenever the alpha is not 0 or 255,
// because we multiply and then unmultiply the alpha.
for (&a, &b) in in_rgba.iter().zip(out_rgba.iter()) {
for (&a, &b) in std::iter::zip(&in_rgba, &out_rgba) {
assert!(a.abs_diff(b) <= 3, "{in_rgba:?} != {out_rgba:?}");
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ecolor/src/rgba.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ mod test {
} else {
// There will be small rounding errors whenever the alpha is not 0 or 255,
// because we multiply and then unmultiply the alpha.
for (&a, &b) in in_rgba.iter().zip(out_rgba.iter()) {
for (&a, &b) in std::iter::zip(&in_rgba, &out_rgba) {
assert!(a.abs_diff(b) <= 3, "{in_rgba:?} != {out_rgba:?}");
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/eframe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ x11 = [
## This is used to generate images for examples.
__screenshot = []

## Enable the [`egui_inspection`] plugin. When the `EGUI_INSPECTION_SOCKET` env var points
## at a unix socket, eframe attaches an `InspectionPlugin` to the egui context on startup
## that streams the AccessKit tree and applies received commands. Unix-only; no-op on
## non-unix targets.
inspection = ["dep:egui_inspection", "accesskit"]

[dependencies]
egui = { workspace = true, default-features = false, features = ["bytemuck"] }

Expand All @@ -131,6 +137,7 @@ web-time.workspace = true
# Optional dependencies

egui_glow = { workspace = true, optional = true, default-features = false }
egui_inspection = { workspace = true, optional = true, features = ["plugin"] }
glow = { workspace = true, optional = true }
ron = { workspace = true, optional = true, features = ["integer128"] }
serde = { workspace = true, optional = true }
Expand Down
35 changes: 31 additions & 4 deletions crates/eframe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
//!
//! impl eframe::App for MyEguiApp {
//! fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
//! egui::CentralPanel::default().show_inside(ui, |ui| {
//! egui::CentralPanel::default().show(ui, |ui| {
//! ui.heading("Hello World!");
//! });
//! }
Expand Down Expand Up @@ -209,6 +209,33 @@ pub use native::file_storage::storage_dir;
#[cfg(not(target_arch = "wasm32"))]
pub mod icon_data;

// ----------------------------------------------------------------------------

/// Attach an [`egui_inspection::InspectionPlugin`] to `ctx` if the
/// `EGUI_INSPECTION_SOCKET` env var points at a reachable unix socket.
///
/// No-op when:
/// - the `inspection` feature isn't enabled,
/// - the target isn't unix, or
/// - the env var is unset.
///
/// Connection failures are logged via `log::warn!` but do not abort startup — running
/// without an inspector is always valid.
#[cfg(all(feature = "inspection", unix, not(target_arch = "wasm32")))]
pub(crate) fn maybe_attach_inspection_plugin(ctx: &egui::Context, label: Option<String>) {
match egui_inspection::InspectionPlugin::from_env(label) {
Ok(Some(plugin)) => {
log::info!("eframe: attaching egui_inspection plugin");
ctx.add_plugin(plugin);
}
Ok(None) => {}
Err(err) => log::warn!("eframe: egui_inspection attach failed: {err}"),
}
}

#[cfg(not(all(feature = "inspection", unix, not(target_arch = "wasm32"))))]
pub(crate) fn maybe_attach_inspection_plugin(_ctx: &egui::Context, _label: Option<String>) {}

/// This is how you start a native (desktop) app.
///
/// The first argument is name of your app, which is an identifier
Expand Down Expand Up @@ -244,7 +271,7 @@ pub mod icon_data;
///
/// impl eframe::App for MyEguiApp {
/// fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// egui::CentralPanel::default().show(ui, |ui| {
/// ui.heading("Hello World!");
/// });
/// }
Expand Down Expand Up @@ -334,7 +361,7 @@ pub fn run_native_ext(
///
/// impl eframe::App for MyEguiApp {
/// fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// egui::CentralPanel::default().show(ui, |ui| {
/// ui.heading("Hello World!");
/// });
/// }
Expand Down Expand Up @@ -425,7 +452,7 @@ fn init_native(app_name: &str, native_options: &mut NativeOptions) -> Renderer {
/// let options = eframe::NativeOptions::default();
/// eframe::run_ui_native("My egui App", options, move |ui, _frame| {
/// // Wrap everything in a CentralPanel so we get some margins and a background color:
/// egui::CentralPanel::default().show_inside(ui, |ui| {
/// egui::CentralPanel::default().show(ui, |ui| {
/// ui.heading("My egui Application");
/// ui.horizontal(|ui| {
/// let name_label = ui.label("Your name: ");
Expand Down
4 changes: 3 additions & 1 deletion crates/eframe/src/native/glow_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ impl<'app> GlowWinitApp<'app> {
let app_creator = std::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken");

crate::maybe_attach_inspection_plugin(&integration.egui_ctx, Some(self.app_name.clone()));

let app: Box<dyn 'app + App> = {
// Use latest raw_window_handle for eframe compatibility
use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
Expand Down Expand Up @@ -679,7 +681,7 @@ impl GlowWinitRunning<'_> {
let gl_surface = viewport.gl_surface.as_ref().unwrap();
let egui_winit = viewport.egui_winit.as_mut().unwrap();

egui_winit.handle_platform_output(&window, platform_output);
egui_winit.handle_platform_output_with_event_loop(&window, event_loop, platform_output);

if is_visible {
let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point);
Expand Down
13 changes: 10 additions & 3 deletions crates/eframe/src/native/wgpu_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ impl<'app> WgpuWinitApp<'app> {

let app_creator = std::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken");

crate::maybe_attach_inspection_plugin(&egui_ctx, Some(self.app_name.clone()));

let cc = CreationContext {
egui_ctx: egui_ctx.clone(),
integration_info: integration.frame.info().clone(),
Expand Down Expand Up @@ -409,7 +412,7 @@ impl WinitApp for WgpuWinitApp<'_> {
self.initialized_all_windows(event_loop);

if let Some(running) = &mut self.running {
running.run_ui_and_paint(window_id)
running.run_ui_and_paint(window_id, event_loop)
} else {
Ok(EventResult::Wait)
}
Expand Down Expand Up @@ -569,7 +572,11 @@ impl WgpuWinitRunning<'_> {
}

/// This is called both for the root viewport, and all deferred viewports
fn run_ui_and_paint(&mut self, window_id: WindowId) -> Result<EventResult> {
fn run_ui_and_paint(
&mut self,
window_id: WindowId,
event_loop: &ActiveEventLoop,
) -> Result<EventResult> {
profiling::function_scope!();

let Some(viewport_id) = self
Expand Down Expand Up @@ -710,7 +717,7 @@ impl WgpuWinitRunning<'_> {
return Ok(EventResult::Wait);
};

egui_winit.handle_platform_output(window, platform_output);
egui_winit.handle_platform_output_with_event_loop(window, event_loop, platform_output);

let vsync_secs = if is_visible {
let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);
Expand Down
3 changes: 2 additions & 1 deletion crates/eframe/src/web/app_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,8 @@ impl AppRunner {
let egui::PlatformOutput {
commands,
cursor_icon,
events: _, // already handled
cursor_image: _, // TODO(alextournai): support custom bitmap cursors on the web (via CSS `url(...)`)
events: _, // already handled
mutable_text_under_cursor: _, // TODO(#4569): https://github.com/emilk/egui/issues/4569
ime,
accesskit_update: _, // not currently implemented
Expand Down
11 changes: 6 additions & 5 deletions crates/eframe/src/web/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ pub fn primary_touch_pos(
runner: &mut AppRunner,
event: &web_sys::TouchEvent,
) -> Option<(egui::Pos2, web_sys::Touch)> {
let all_touches: Vec<_> = (0..event.touches().length())
.filter_map(|i| event.touches().get(i))
// On touchend we don't get anything in `touches`, but we still get `changed_touches`, so include those:
.chain((0..event.changed_touches().length()).filter_map(|i| event.changed_touches().get(i)))
.collect();
// On touchend we don't get anything in `touches`, but we still get `changed_touches`, so include those:
let all_touches: Vec<_> = std::iter::chain(
(0..event.touches().length()).filter_map(|i| event.touches().get(i)),
(0..event.changed_touches().length()).filter_map(|i| event.changed_touches().get(i)),
)
.collect();

if let Some(primary_touch) = runner.input.primary_touch {
// Is the primary touch is gone?
Expand Down
2 changes: 1 addition & 1 deletion crates/eframe/src/web/web_painter_wgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ impl WebPainter for WebPainterWgpu {
// Submit the commands: both the main buffer and user-defined ones.
render_state
.queue
.submit(user_cmd_bufs.into_iter().chain([encoder.finish()]));
.submit(std::iter::chain(user_cmd_bufs, [encoder.finish()]));

if let Some((frame, capture_buffer)) = frame_and_capture_buffer {
if let Some(capture_buffer) = capture_buffer
Expand Down
2 changes: 1 addition & 1 deletion crates/egui-wgpu/src/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ impl Painter {
let start = web_time::Instant::now();
render_state
.queue
.submit(user_cmd_bufs.into_iter().chain([encoded]));
.submit(std::iter::chain(user_cmd_bufs, [encoded]));
vsync_sec += start.elapsed().as_secs_f32();
};

Expand Down
Loading
Loading