From 7980401b253c78b7410f9386d3c817fa7e014ea4 Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Tue, 18 Nov 2025 17:17:25 +0100 Subject: [PATCH 1/2] Revert "Remove `accesskit` feature and always depend on `accesskit` (#7701)" This reverts commit 1af5d1d37ecba2c16a354d2d318d74a25c85da95. --- crates/eframe/Cargo.toml | 2 +- crates/eframe/src/web/app_runner.rs | 3 +- crates/egui-winit/Cargo.toml | 2 +- crates/egui-winit/src/lib.rs | 4 +-- crates/egui/Cargo.toml | 8 +++-- crates/egui/src/containers/window.rs | 1 + crates/egui/src/context.rs | 28 +++++++++------ crates/egui/src/data/input.rs | 1 + crates/egui/src/data/output.rs | 10 ++++-- crates/egui/src/id.rs | 1 + crates/egui/src/input_state/mod.rs | 4 +++ crates/egui/src/lib.rs | 2 ++ crates/egui/src/memory/mod.rs | 34 ++++++++++++------- crates/egui/src/pass_state.rs | 9 ++++- crates/egui/src/response.rs | 9 +++++ .../egui/src/text_selection/accesskit_text.rs | 3 +- .../egui/src/text_selection/cursor_range.rs | 2 ++ .../text_selection/label_text_selection.rs | 1 + crates/egui/src/text_selection/mod.rs | 1 + crates/egui/src/ui.rs | 7 ++++ crates/egui/src/ui_builder.rs | 9 ++++- crates/egui/src/widgets/drag_value.rs | 25 +++++++++----- crates/egui/src/widgets/slider.rs | 27 +++++++++------ crates/egui/src/widgets/text_edit/builder.rs | 1 + crates/egui_kittest/Cargo.toml | 2 +- 25 files changed, 140 insertions(+), 56 deletions(-) diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 6924633f1c3..ed9af012c0d 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -36,7 +36,7 @@ default = [ ] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). -accesskit = ["egui-winit/accesskit"] +accesskit = ["egui/accesskit", "egui-winit/accesskit"] # Allow crates to choose an android-activity backend via Winit # - It's important that most applications should not have to depend on android-activity directly, and can diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 8a10a90efba..41bb81ae7f6 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -358,7 +358,8 @@ impl AppRunner { events: _, // already handled mutable_text_under_cursor: _, // TODO(#4569): https://github.com/emilk/egui/issues/4569 ime, - accesskit_update: _, // not currently implemented + #[cfg(feature = "accesskit")] + accesskit_update: _, // not currently implemented num_completed_passes: _, // handled by `Context::run` request_discard_reasons: _, // handled by `Context::run` } = platform_output; diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index d1b2ab22050..a4c84b05f57 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -24,7 +24,7 @@ rustdoc-args = ["--generate-link-to-definition"] default = ["clipboard", "links", "wayland", "winit/default", "x11"] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). -accesskit = ["dep:accesskit_winit"] +accesskit = ["dep:accesskit_winit", "egui/accesskit"] # Allow crates to choose an android-activity backend via Winit # - It's important that most applications should not have to depend on android-activity directly, and can diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 7660e3cef17..d72c44245ee 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -888,6 +888,7 @@ impl State { events: _, // handled elsewhere mutable_text_under_cursor: _, // only used in eframe web ime, + #[cfg(feature = "accesskit")] accesskit_update, num_completed_passes: _, // `egui::Context::run` handles this request_discard_reasons: _, // `egui::Context::run` handles this @@ -946,9 +947,6 @@ impl State { profiling::scope!("accesskit"); accesskit.update_if_active(|| update); } - - #[cfg(not(feature = "accesskit"))] - let _ = accesskit_update; } fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) { diff --git a/crates/egui/Cargo.toml b/crates/egui/Cargo.toml index 764d2401ea7..c82ae5618e8 100644 --- a/crates/egui/Cargo.toml +++ b/crates/egui/Cargo.toml @@ -26,6 +26,10 @@ rustdoc-args = ["--generate-link-to-definition"] [features] default = ["default_fonts"] +## Exposes detailed accessibility implementation required by platform +## accessibility APIs. Also requires support in the egui integration. +accesskit = ["dep:accesskit"] + ## [`bytemuck`](https://docs.rs/bytemuck) enables you to cast [`epaint::Vertex`], [`emath::Vec2`] etc to `&[u8]`. bytemuck = ["epaint/bytemuck"] @@ -57,7 +61,7 @@ persistence = ["serde", "epaint/serde", "ron"] rayon = ["epaint/rayon"] ## Allow serialization using [`serde`](https://docs.rs/serde). -serde = ["dep:serde", "epaint/serde", "accesskit/serde"] +serde = ["dep:serde", "epaint/serde", "accesskit?/serde"] ## Change Vertex layout to be compatible with unity unity = ["epaint/unity"] @@ -71,7 +75,6 @@ _override_unity = ["epaint/_override_unity"] emath = { workspace = true, default-features = false } epaint = { workspace = true, default-features = false } -accesskit.workspace = true ahash.workspace = true bitflags.workspace = true log.workspace = true @@ -81,6 +84,7 @@ smallvec.workspace = true unicode-segmentation.workspace = true #! ### Optional dependencies +accesskit = { workspace = true, optional = true } backtrace = { workspace = true, optional = true } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 8d7a95be75b..7f4bdaa0831 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -910,6 +910,7 @@ fn resize_interaction( let rect = outer_rect.shrink(window_frame.stroke.width / 2.0); let side_response = |rect, id| { + #[cfg(feature = "accesskit")] ctx.register_accesskit_parent(id, _accessibility_parent); let response = ctx.create_widget( WidgetRect { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 2ca7af4fc3b..d8ff0a8565a 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -41,6 +41,7 @@ use crate::{ viewport::ViewportClass, }; +#[cfg(feature = "accesskit")] use crate::IdMap; /// Information given to the backend about when it is time to repaint the ui. @@ -403,6 +404,7 @@ struct ContextImpl { embed_viewports: bool, + #[cfg(feature = "accesskit")] is_accesskit_enabled: bool, loaders: Arc, @@ -505,6 +507,7 @@ impl ContextImpl { }, ); + #[cfg(feature = "accesskit")] if self.is_accesskit_enabled { profiling::scope!("accesskit"); use crate::pass_state::AccessKitPassState; @@ -586,10 +589,10 @@ impl ContextImpl { } } + #[cfg(feature = "accesskit")] fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::Node { let state = self.viewport().this_pass.accesskit_state.as_mut().unwrap(); let builders = &mut state.nodes; - if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) { entry.insert(Default::default()); @@ -616,7 +619,6 @@ impl ContextImpl { let parent_builder = builders.get_mut(&parent_id).unwrap(); parent_builder.push_child(id.accesskit_id()); } - builders.get_mut(&id).unwrap() } @@ -1202,6 +1204,7 @@ impl Context { plugins.on_widget_under_pointer(self, &w); } + #[cfg(feature = "accesskit")] if allow_focus && w.sense.is_focusable() { // Make sure anything that can receive focus has an AccessKit node. // TODO(mwcampbell): For nodes that are filled from widget info, @@ -1209,6 +1212,7 @@ impl Context { self.accesskit_node_builder(w.id, |builder| res.fill_accesskit_node_common(builder)); } + #[cfg(feature = "accesskit")] self.write(|ctx| { use crate::{Align, pass_state::ScrollTarget, style::ScrollAnimation}; let viewport = ctx.viewport_for(ctx.viewport_id()); @@ -1216,14 +1220,12 @@ impl Context { viewport .input .consume_accesskit_action_requests(res.id, |request| { - use accesskit::Action; - // TODO(lucasmerlin): Correctly handle the scroll unit: // https://github.com/AccessKit/accesskit/blob/e639c0e0d8ccbfd9dff302d972fa06f9766d608e/common/src/lib.rs#L2621 const DISTANCE: f32 = 100.0; match &request.action { - Action::ScrollIntoView => { + accesskit::Action::ScrollIntoView => { viewport.this_pass.scroll_target = [ Some(ScrollTarget::new( res.rect.x_range(), @@ -1237,16 +1239,16 @@ impl Context { )), ]; } - Action::ScrollDown => { + accesskit::Action::ScrollDown => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::UP; } - Action::ScrollUp => { + accesskit::Action::ScrollUp => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::DOWN; } - Action::ScrollLeft => { + accesskit::Action::ScrollLeft => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::LEFT; } - Action::ScrollRight => { + accesskit::Action::ScrollRight => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::RIGHT; } _ => return false, @@ -1339,6 +1341,7 @@ impl Context { res.flags.set(Flags::FAKE_PRIMARY_CLICKED, true); } + #[cfg(feature = "accesskit")] if enabled && sense.senses_click() && input.has_accesskit_action_request(id, accesskit::Action::Click) @@ -2495,6 +2498,7 @@ impl ContextImpl { let mut platform_output: PlatformOutput = std::mem::take(&mut viewport.output); + #[cfg(feature = "accesskit")] { profiling::scope!("accesskit"); let state = viewport.this_pass.accesskit_state.take(); @@ -3493,8 +3497,9 @@ impl Context { /// /// The `Context` lock is held while the given closure is called! /// - /// Returns `None` if accesskit is off. + /// Returns `None` if acesskit is off. // TODO(emilk): consider making both read-only and read-write versions + #[cfg(feature = "accesskit")] pub fn accesskit_node_builder( &self, id: Id, @@ -3510,6 +3515,7 @@ impl Context { }) } + #[cfg(feature = "accesskit")] pub(crate) fn register_accesskit_parent(&self, id: Id, parent_id: Id) { self.write(|ctx| { if let Some(state) = ctx.viewport().this_pass.accesskit_state.as_mut() { @@ -3519,11 +3525,13 @@ impl Context { } /// Enable generation of AccessKit tree updates in all future frames. + #[cfg(feature = "accesskit")] pub fn enable_accesskit(&self) { self.write(|ctx| ctx.is_accesskit_enabled = true); } /// Disable generation of AccessKit tree updates in all future frames. + #[cfg(feature = "accesskit")] pub fn disable_accesskit(&self) { self.write(|ctx| ctx.is_accesskit_enabled = false); } diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 61f6ae00c9d..869945ecec2 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -548,6 +548,7 @@ pub enum Event { WindowFocused(bool), /// An assistive technology (e.g. screen reader) requested an action. + #[cfg(feature = "accesskit")] AccessKitActionRequest(accesskit::ActionRequest), /// The reply of a screenshot requested with [`crate::ViewportCommand::Screenshot`]. diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index 2c6edba84cc..deec5162dcd 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -128,6 +128,7 @@ pub struct PlatformOutput { /// The difference in the widget tree since last frame. /// /// NOTE: this needs to be per-viewport. + #[cfg(feature = "accesskit")] pub accesskit_update: Option, /// How many ui passes is this the sum of? @@ -174,6 +175,7 @@ impl PlatformOutput { mut events, mutable_text_under_cursor, ime, + #[cfg(feature = "accesskit")] accesskit_update, num_completed_passes, mut request_discard_reasons, @@ -188,8 +190,12 @@ impl PlatformOutput { self.request_discard_reasons .append(&mut request_discard_reasons); - // egui produces a complete AccessKit tree for each frame, so overwrite rather than append: - self.accesskit_update = accesskit_update; + #[cfg(feature = "accesskit")] + { + // egui produces a complete AccessKit tree for each frame, + // so overwrite rather than appending. + self.accesskit_update = accesskit_update; + } } /// Take everything ephemeral (everything except `cursor_icon` currently) diff --git a/crates/egui/src/id.rs b/crates/egui/src/id.rs index 7484930c8f2..0565dc5670f 100644 --- a/crates/egui/src/id.rs +++ b/crates/egui/src/id.rs @@ -79,6 +79,7 @@ impl Id { self.0.get() } + #[cfg(feature = "accesskit")] pub(crate) fn accesskit_id(&self) -> accesskit::NodeId { self.value().into() } diff --git a/crates/egui/src/input_state/mod.rs b/crates/egui/src/input_state/mod.rs index 0c99b6ac3f0..e0628809e63 100644 --- a/crates/egui/src/input_state/mod.rs +++ b/crates/egui/src/input_state/mod.rs @@ -855,6 +855,7 @@ impl InputState { } } + #[cfg(feature = "accesskit")] pub fn accesskit_action_requests( &self, id: crate::Id, @@ -872,6 +873,7 @@ impl InputState { }) } + #[cfg(feature = "accesskit")] pub fn consume_accesskit_action_requests( &mut self, id: crate::Id, @@ -888,10 +890,12 @@ impl InputState { }); } + #[cfg(feature = "accesskit")] pub fn has_accesskit_action_request(&self, id: crate::Id, action: accesskit::Action) -> bool { self.accesskit_action_requests(id, action).next().is_some() } + #[cfg(feature = "accesskit")] pub fn num_accesskit_action_requests(&self, id: crate::Id, action: accesskit::Action) -> usize { self.accesskit_action_requests(id, action).count() } diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index bd4319f0bda..2652734cb5f 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -448,6 +448,7 @@ pub mod widgets; #[cfg(debug_assertions)] mod callstack; +#[cfg(feature = "accesskit")] pub use accesskit; #[deprecated = "Use the ahash crate directly."] @@ -707,6 +708,7 @@ pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) { }); } +#[cfg(feature = "accesskit")] pub fn accesskit_root_id() -> Id { Id::new("accesskit_root") } diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index d215a3beca1..c7bcc6fdccd 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -470,6 +470,7 @@ pub(crate) struct Focus { /// The ID of a widget to give the focus to in the next frame. id_next_frame: Option, + #[cfg(feature = "accesskit")] id_requested_by_accesskit: Option, /// If set, the next widget that is interested in focus will automatically get it. @@ -528,7 +529,10 @@ impl Focus { } let event_filter = self.focused_widget.map(|w| w.filter).unwrap_or_default(); - self.id_requested_by_accesskit = None; + #[cfg(feature = "accesskit")] + { + self.id_requested_by_accesskit = None; + } self.focus_direction = FocusDirection::None; @@ -563,13 +567,16 @@ impl Focus { self.focus_direction = cardinality; } - if let crate::Event::AccessKitActionRequest(accesskit::ActionRequest { - action: accesskit::Action::Focus, - target, - data: None, - }) = event + #[cfg(feature = "accesskit")] { - self.id_requested_by_accesskit = Some(*target); + if let crate::Event::AccessKitActionRequest(accesskit::ActionRequest { + action: accesskit::Action::Focus, + target, + data: None, + }) = event + { + self.id_requested_by_accesskit = Some(*target); + } } } } @@ -599,11 +606,14 @@ impl Focus { } fn interested_in_focus(&mut self, id: Id) { - if self.id_requested_by_accesskit == Some(id.accesskit_id()) { - self.focused_widget = Some(FocusWidget::new(id)); - self.id_requested_by_accesskit = None; - self.give_to_next = false; - self.reset_focus(); + #[cfg(feature = "accesskit")] + { + if self.id_requested_by_accesskit == Some(id.accesskit_id()) { + self.focused_widget = Some(FocusWidget::new(id)); + self.id_requested_by_accesskit = None; + self.give_to_next = false; + self.reset_focus(); + } } // The rect is updated at the end of the frame. diff --git a/crates/egui/src/pass_state.rs b/crates/egui/src/pass_state.rs index 9b323bfa07c..2be7e509856 100644 --- a/crates/egui/src/pass_state.rs +++ b/crates/egui/src/pass_state.rs @@ -67,6 +67,7 @@ impl ScrollTarget { } } +#[cfg(feature = "accesskit")] #[derive(Clone)] pub struct AccessKitPassState { pub nodes: IdMap, @@ -224,6 +225,7 @@ pub struct PassState { /// as when swiping down on a touch-screen or track-pad with natural scrolling. pub scroll_delta: (Vec2, style::ScrollAnimation), + #[cfg(feature = "accesskit")] pub accesskit_state: Option, /// Highlight these widgets the next pass. @@ -245,6 +247,7 @@ impl Default for PassState { used_by_panels: Rect::NAN, scroll_target: [None, None], scroll_delta: (Vec2::default(), style::ScrollAnimation::none()), + #[cfg(feature = "accesskit")] accesskit_state: None, highlight_next_pass: Default::default(), @@ -267,6 +270,7 @@ impl PassState { used_by_panels, scroll_target, scroll_delta, + #[cfg(feature = "accesskit")] accesskit_state, highlight_next_pass, @@ -289,7 +293,10 @@ impl PassState { *debug_rect = None; } - *accesskit_state = None; + #[cfg(feature = "accesskit")] + { + *accesskit_state = None; + } highlight_next_pass.clear(); } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index e89cb5252fc..4e75142cdcb 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -807,6 +807,7 @@ impl Response { if let Some(event) = event { self.output_event(event); } else { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { self.fill_accesskit_node_from_widget_info(builder, make_info()); }); @@ -816,6 +817,7 @@ impl Response { } pub fn output_event(&self, event: crate::output::OutputEvent) { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { self.fill_accesskit_node_from_widget_info(builder, event.widget_info().clone()); }); @@ -826,6 +828,7 @@ impl Response { self.ctx.output_mut(|o| o.events.push(event)); } + #[cfg(feature = "accesskit")] pub(crate) fn fill_accesskit_node_common(&self, builder: &mut accesskit::Node) { if !self.enabled() { builder.set_disabled(); @@ -844,6 +847,7 @@ impl Response { } } + #[cfg(feature = "accesskit")] fn fill_accesskit_node_from_widget_info( &self, builder: &mut accesskit::Node, @@ -918,9 +922,14 @@ impl Response { /// # }); /// ``` pub fn labelled_by(self, id: Id) -> Self { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { builder.push_labelled_by(id.accesskit_id()); }); + #[cfg(not(feature = "accesskit"))] + { + let _ = id; + } self } diff --git a/crates/egui/src/text_selection/accesskit_text.rs b/crates/egui/src/text_selection/accesskit_text.rs index 974a334d085..4d64229c540 100644 --- a/crates/egui/src/text_selection/accesskit_text.rs +++ b/crates/egui/src/text_selection/accesskit_text.rs @@ -42,9 +42,8 @@ pub fn update_accesskit_for_text_widget( for (row_index, row) in galley.rows.iter().enumerate() { let row_id = parent_id.with(row_index); - + #[cfg(feature = "accesskit")] ctx.register_accesskit_parent(row_id, parent_id); - ctx.accesskit_node_builder(row_id, |builder| { builder.set_role(accesskit::Role::TextRun); let rect = global_from_galley * row.rect_without_leading_space(); diff --git a/crates/egui/src/text_selection/cursor_range.rs b/crates/egui/src/text_selection/cursor_range.rs index a816f5f26e3..10980c581d9 100644 --- a/crates/egui/src/text_selection/cursor_range.rs +++ b/crates/egui/src/text_selection/cursor_range.rs @@ -190,6 +190,7 @@ impl CCursorRange { .. } => self.on_key_press(os, galley, modifiers, *key), + #[cfg(feature = "accesskit")] Event::AccessKitActionRequest(accesskit::ActionRequest { action: accesskit::Action::SetTextSelection, target, @@ -219,6 +220,7 @@ impl CCursorRange { // ---------------------------------------------------------------------------- +#[cfg(feature = "accesskit")] fn ccursor_from_accesskit_text_position( id: Id, galley: &Galley, diff --git a/crates/egui/src/text_selection/label_text_selection.rs b/crates/egui/src/text_selection/label_text_selection.rs index bc28844414e..0405ca5dad4 100644 --- a/crates/egui/src/text_selection/label_text_selection.rs +++ b/crates/egui/src/text_selection/label_text_selection.rs @@ -624,6 +624,7 @@ impl LabelSelectionState { ); } + #[cfg(feature = "accesskit")] super::accesskit_text::update_accesskit_for_text_widget( ui.ctx(), response.id, diff --git a/crates/egui/src/text_selection/mod.rs b/crates/egui/src/text_selection/mod.rs index cbd51c31a36..8d0943d6097 100644 --- a/crates/egui/src/text_selection/mod.rs +++ b/crates/egui/src/text_selection/mod.rs @@ -1,5 +1,6 @@ //! Helpers regarding text selection for labels and text edit. +#[cfg(feature = "accesskit")] pub mod accesskit_text; mod cursor_range; diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 3c7fca2f342..3097ad9bd6a 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -133,6 +133,7 @@ impl Ui { sizing_pass, style, sense, + #[cfg(feature = "accesskit")] accessibility_parent, } = ui_builder; @@ -174,6 +175,7 @@ impl Ui { min_rect_already_remembered: false, }; + #[cfg(feature = "accesskit")] if let Some(accessibility_parent) = accessibility_parent { ui.ctx() .register_accesskit_parent(ui.unique_id, accessibility_parent); @@ -200,6 +202,7 @@ impl Ui { ui.set_invisible(); } + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(ui.unique_id, |node| { node.set_role(accesskit::Role::GenericContainer); }); @@ -270,6 +273,7 @@ impl Ui { sizing_pass, style, sense, + #[cfg(feature = "accesskit")] accessibility_parent, } = ui_builder; @@ -339,6 +343,7 @@ impl Ui { child_ui.disable(); } + #[cfg(feature = "accesskit")] child_ui.ctx().register_accesskit_parent( child_ui.unique_id, accessibility_parent.unwrap_or(self.unique_id), @@ -358,6 +363,7 @@ impl Ui { true, ); + #[cfg(feature = "accesskit")] child_ui .ctx() .accesskit_node_builder(child_ui.unique_id, |node| { @@ -1123,6 +1129,7 @@ impl Ui { impl Ui { /// Check for clicks, drags and/or hover on a specific region of this [`Ui`]. pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response { + #[cfg(feature = "accesskit")] self.ctx().register_accesskit_parent(id, self.unique_id); self.ctx().create_widget( diff --git a/crates/egui/src/ui_builder.rs b/crates/egui/src/ui_builder.rs index 686fdcb479f..51b8ec8a51d 100644 --- a/crates/egui/src/ui_builder.rs +++ b/crates/egui/src/ui_builder.rs @@ -24,6 +24,7 @@ pub struct UiBuilder { pub sizing_pass: bool, pub style: Option>, pub sense: Option, + #[cfg(feature = "accesskit")] pub accessibility_parent: Option, } @@ -186,9 +187,15 @@ impl UiBuilder { /// /// This will override the automatic parent assignment for accessibility purposes. /// If not set, the parent [`Ui`]'s ID will be used as the accessibility parent. + /// + /// This does nothing if the `accesskit` feature is not enabled. + #[cfg_attr(not(feature = "accesskit"), expect(unused_mut, unused_variables))] #[inline] pub fn accessibility_parent(mut self, parent_id: Id) -> Self { - self.accessibility_parent = Some(parent_id); + #[cfg(feature = "accesskit")] + { + self.accessibility_parent = Some(parent_id); + } self } } diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 29d59620129..9515726c211 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -489,21 +489,27 @@ impl Widget for DragValue<'_> { - input.count_and_consume_key(Modifiers::NONE, Key::ArrowDown) as f64; } - use accesskit::Action; - change += input.num_accesskit_action_requests(id, Action::Increment) as f64 - - input.num_accesskit_action_requests(id, Action::Decrement) as f64; + #[cfg(feature = "accesskit")] + { + use accesskit::Action; + change += input.num_accesskit_action_requests(id, Action::Increment) as f64 + - input.num_accesskit_action_requests(id, Action::Decrement) as f64; + } change }); - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::{Action, ActionData}; - for request in input.accesskit_action_requests(id, Action::SetValue) { - if let Some(ActionData::NumericValue(new_value)) = request.data { - value = new_value; + ui.input(|input| { + for request in input.accesskit_action_requests(id, Action::SetValue) { + if let Some(ActionData::NumericValue(new_value)) = request.data { + value = new_value; + } } - } - }); + }); + } if clamp_existing_to_range { value = clamp_value_to_range(value, range.clone()); @@ -663,6 +669,7 @@ impl Widget for DragValue<'_> { response.widget_info(|| WidgetInfo::drag_value(ui.is_enabled(), value)); + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(response.id, |builder| { use accesskit::Action; // If either end of the range is unbounded, it's better diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 129c41c3b2a..7937e58974e 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -716,11 +716,14 @@ impl Slider<'_> { }); } - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::Action; - decrement += input.num_accesskit_action_requests(response.id, Action::Decrement); - increment += input.num_accesskit_action_requests(response.id, Action::Increment); - }); + ui.input(|input| { + decrement += input.num_accesskit_action_requests(response.id, Action::Decrement); + increment += input.num_accesskit_action_requests(response.id, Action::Increment); + }); + } let kb_step = increment as f32 - decrement as f32; @@ -756,14 +759,17 @@ impl Slider<'_> { self.set_value(new_value); } - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::{Action, ActionData}; - for request in input.accesskit_action_requests(response.id, Action::SetValue) { - if let Some(ActionData::NumericValue(new_value)) = request.data { - self.set_value(new_value); + ui.input(|input| { + for request in input.accesskit_action_requests(response.id, Action::SetValue) { + if let Some(ActionData::NumericValue(new_value)) = request.data { + self.set_value(new_value); + } } - } - }); + }); + } // Paint it: if ui.is_rect_visible(response.rect) { @@ -972,6 +978,7 @@ impl Slider<'_> { } response.widget_info(|| WidgetInfo::slider(ui.is_enabled(), value, self.text.text())); + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(response.id, |builder| { use accesskit::Action; builder.set_min_numeric_value(*self.range.start()); diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 6f2da1baa07..c0364e7eef2 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -844,6 +844,7 @@ impl TextEdit<'_> { }); } + #[cfg(feature = "accesskit")] { let role = if password { accesskit::Role::PasswordInput diff --git a/crates/egui_kittest/Cargo.toml b/crates/egui_kittest/Cargo.toml index 1de8ce7ac8a..c283d0734dd 100644 --- a/crates/egui_kittest/Cargo.toml +++ b/crates/egui_kittest/Cargo.toml @@ -35,7 +35,7 @@ x11 = ["eframe?/x11"] [dependencies] kittest.workspace = true -egui.workspace = true +egui = { workspace = true, features = ["accesskit"] } eframe = { workspace = true, optional = true } # wgpu dependencies From e285050abc8e99c92c353bf9ddd2e58577ddfa81 Mon Sep 17 00:00:00 2001 From: lucasmerlin Date: Wed, 19 Nov 2025 12:14:08 +0100 Subject: [PATCH 2/2] Get hello world simple to compile --- Cargo.lock | 420 +++++++++++++++- Cargo.toml | 5 +- crates/eframe/Cargo.toml | 6 +- crates/eframe/src/epi.rs | 2 +- crates/eframe/src/lib.rs | 17 +- crates/eframe/src/native/epi_integration.rs | 63 +-- .../eframe/src/native/event_loop_context.rs | 10 +- crates/eframe/src/native/run.rs | 197 ++++---- crates/eframe/src/native/wgpu_integration.rs | 158 +++--- crates/eframe/src/native/winit_integration.rs | 14 +- crates/egui-wgpu/Cargo.toml | 2 +- crates/egui-wgpu/src/winit.rs | 8 +- crates/egui-winit/Cargo.toml | 2 + crates/egui-winit/src/lib.rs | 467 ++++++++---------- crates/egui-winit/src/window_settings.rs | 152 +++--- crates/egui/Cargo.toml | 3 +- crates/egui/src/containers/panel.rs | 20 +- crates/egui/src/containers/resize.rs | 2 +- crates/egui/src/containers/window.rs | 8 +- crates/egui/src/data/output.rs | 208 ++------ crates/egui/src/style.rs | 10 +- crates/egui/src/widgets/drag_value.rs | 6 +- crates/egui/src/widgets/hyperlink.rs | 2 +- crates/egui_glow/Cargo.toml | 2 +- examples/hello_world_simple/Cargo.toml | 2 +- 25 files changed, 1018 insertions(+), 768 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61bf459b51b..3951f456018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,7 +109,7 @@ dependencies = [ "accesskit_unix", "accesskit_windows", "raw-window-handle", - "winit", + "winit 0.30.12", ] [[package]] @@ -647,6 +647,15 @@ dependencies = [ "piper", ] +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "bstr" version = "1.11.3" @@ -716,18 +725,43 @@ dependencies = [ "thiserror 1.0.66", ] +[[package]] +name = "calloop" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e" +dependencies = [ + "bitflags 2.9.4", + "polling", + "rustix 1.0.8", + "slab", + "tracing", +] + [[package]] name = "calloop-wayland-source" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "calloop", + "calloop 0.13.0", "rustix 0.38.38", "wayland-backend", "wayland-client", ] +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.3", + "rustix 1.0.8", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cast" version = "0.3.0" @@ -1082,9 +1116,12 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +dependencies = [ + "serde", +] [[package]] name = "custom_3d_glow" @@ -1242,9 +1279,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "ecolor" @@ -1294,7 +1331,8 @@ dependencies = [ "web-time", "wgpu", "windows-sys 0.61.2", - "winit", + "winit 0.31.0-beta.2", + "winit-core", ] [[package]] @@ -1305,6 +1343,7 @@ dependencies = [ "ahash", "backtrace", "bitflags 2.9.4", + "cursor-icon", "document-features", "emath", "epaint", @@ -1332,7 +1371,7 @@ dependencies = [ "type-map", "web-time", "wgpu", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -1343,11 +1382,12 @@ dependencies = [ "arboard", "bytemuck", "document-features", + "dpi", "egui", "log", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-ui-kit", + "objc2-ui-kit 0.2.2", "profiling", "raw-window-handle", "serde", @@ -1355,7 +1395,8 @@ dependencies = [ "wayland-cursor", "web-time", "webbrowser", - "winit", + "winit 0.31.0-beta.2", + "winit-core", ] [[package]] @@ -1440,7 +1481,7 @@ dependencies = [ "profiling", "wasm-bindgen", "web-sys", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -1664,7 +1705,7 @@ version = "0.1.0" dependencies = [ "eframe", "env_logger", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -1675,7 +1716,7 @@ dependencies = [ "env_logger", "log", "tokio", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -1987,7 +2028,7 @@ dependencies = [ "cfg_aliases", "glutin", "raw-window-handle", - "winit", + "winit 0.30.12", ] [[package]] @@ -2108,7 +2149,7 @@ dependencies = [ "egui_demo_lib", "egui_extras", "log", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -2126,7 +2167,7 @@ version = "0.1.0" dependencies = [ "eframe", "env_logger", - "winit", + "winit 0.31.0-beta.2", ] [[package]] @@ -2480,6 +2521,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyboard-types" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" +dependencies = [ + "bitflags 2.9.4", + "serde", +] + [[package]] name = "keyboard_events" version = "0.1.0" @@ -2955,6 +3006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.9.4", + "block2 0.6.2", "dispatch2", "objc2 0.6.3", ] @@ -2967,6 +3019,7 @@ checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ "bitflags 2.9.4", "dispatch2", + "libc", "objc2 0.6.3", "objc2-core-foundation", "objc2-io-surface", @@ -2996,6 +3049,17 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-core-video" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" +dependencies = [ + "bitflags 2.9.4", + "objc2-core-foundation", + "objc2-core-graphics", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -3022,6 +3086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.9.4", + "block2 0.6.2", "objc2 0.6.3", "objc2-core-foundation", ] @@ -3105,6 +3170,18 @@ dependencies = [ "objc2-user-notifications", ] +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-uniform-type-identifiers" version = "0.2.2" @@ -3972,14 +4049,14 @@ dependencies = [ [[package]] name = "sctk-adwaita" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +checksum = "1dd3accc0f3f4bbaf2c9e1957a030dc582028130c67660d44c0a0345a22ca69b" dependencies = [ "ab_glyph", "log", "memmap2", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "tiny-skia", ] @@ -4132,8 +4209,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.9.4", - "calloop", - "calloop-wayland-source", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", @@ -4150,6 +4227,33 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.9.4", + "calloop 0.14.3", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.0.8", + "thiserror 2.0.17", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smithay-clipboard" version = "0.7.2" @@ -4157,7 +4261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" dependencies = [ "libc", - "smithay-client-toolkit", + "smithay-client-toolkit 0.19.2", "wayland-backend", ] @@ -4170,6 +4274,16 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "socket2" version = "0.6.0" @@ -4514,6 +4628,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4897,6 +5012,32 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfe33d551eb8bffd03ff067a8b44bb963919157841a99957151299a6307d19c" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-plasma" version = "0.3.9" @@ -5603,7 +5744,7 @@ dependencies = [ "bitflags 2.9.4", "block2 0.5.1", "bytemuck", - "calloop", + "calloop 0.13.0", "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", @@ -5617,16 +5758,15 @@ dependencies = [ "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", - "objc2-ui-kit", + "objc2-ui-kit 0.2.2", "orbclient", "percent-encoding", "pin-project", "raw-window-handle", "redox_syscall 0.4.1", "rustix 0.38.38", - "sctk-adwaita", - "smithay-client-toolkit", - "smol_str", + "smithay-client-toolkit 0.19.2", + "smol_str 0.2.2", "tracing", "unicode-segmentation", "wasm-bindgen", @@ -5643,6 +5783,231 @@ dependencies = [ "xkbcommon-dl", ] +[[package]] +name = "winit" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa" +dependencies = [ + "bitflags 2.9.4", + "cfg_aliases", + "cursor-icon", + "dpi", + "libc", + "raw-window-handle", + "rustix 1.0.8", + "smol_str 0.3.2", + "tracing", + "winit-android", + "winit-appkit", + "winit-common", + "winit-core", + "winit-orbital", + "winit-uikit", + "winit-wayland", + "winit-web", + "winit-win32", + "winit-x11", +] + +[[package]] +name = "winit-android" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df" +dependencies = [ + "android-activity", + "bitflags 2.9.4", + "dpi", + "ndk", + "raw-window-handle", + "smol_str 0.3.2", + "tracing", + "winit-core", +] + +[[package]] +name = "winit-appkit" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.2", + "dispatch2", + "dpi", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-video", + "objc2-foundation 0.3.2", + "raw-window-handle", + "smol_str 0.3.2", + "tracing", + "winit-common", + "winit-core", +] + +[[package]] +name = "winit-common" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45375fbac4cbb77260d83a30b1f9d8105880dbac99a9ae97f56656694680ff69" +dependencies = [ + "memmap2", + "objc2 0.6.3", + "objc2-core-foundation", + "smol_str 0.3.2", + "tracing", + "winit-core", + "x11-dl", + "xkbcommon-dl", +] + +[[package]] +name = "winit-core" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583" +dependencies = [ + "bitflags 2.9.4", + "cursor-icon", + "dpi", + "keyboard-types", + "raw-window-handle", + "smol_str 0.3.2", + "web-time", +] + +[[package]] +name = "winit-orbital" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46" +dependencies = [ + "bitflags 2.9.4", + "dpi", + "orbclient", + "raw-window-handle", + "redox_syscall 0.5.7", + "smol_str 0.3.2", + "tracing", + "winit-core", +] + +[[package]] +name = "winit-uikit" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643" +dependencies = [ + "bitflags 2.9.4", + "block2 0.6.2", + "dispatch2", + "dpi", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-ui-kit 0.3.2", + "raw-window-handle", + "smol_str 0.3.2", + "tracing", + "winit-common", + "winit-core", +] + +[[package]] +name = "winit-wayland" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce5afb2ba07da603f84b722c95f9f9396d2cedae3944fb6c0cda4a6f88de545" +dependencies = [ + "ahash", + "bitflags 2.9.4", + "calloop 0.14.3", + "cursor-icon", + "dpi", + "libc", + "memmap2", + "raw-window-handle", + "rustix 1.0.8", + "sctk-adwaita", + "smithay-client-toolkit 0.20.0", + "smol_str 0.3.2", + "tracing", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "winit-common", + "winit-core", +] + +[[package]] +name = "winit-web" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92" +dependencies = [ + "atomic-waker", + "bitflags 2.9.4", + "concurrent-queue", + "cursor-icon", + "dpi", + "js-sys", + "pin-project", + "raw-window-handle", + "smol_str 0.3.2", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winit-core", +] + +[[package]] +name = "winit-win32" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa" +dependencies = [ + "bitflags 2.9.4", + "cursor-icon", + "dpi", + "raw-window-handle", + "smol_str 0.3.2", + "tracing", + "unicode-segmentation", + "windows-sys 0.59.0", + "winit-core", +] + +[[package]] +name = "winit-x11" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa5b600756534c7041aa93cd0d244d44b09fca1b89e202bd1cd80dd9f3636c46" +dependencies = [ + "bitflags 2.9.4", + "bytemuck", + "calloop 0.14.3", + "cursor-icon", + "dpi", + "libc", + "percent-encoding", + "raw-window-handle", + "rustix 1.0.8", + "smol_str 0.3.2", + "tracing", + "winit-common", + "winit-core", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" version = "0.7.3" @@ -5691,6 +6056,7 @@ dependencies = [ "once_cell", "rustix 1.0.8", "x11rb-protocol", + "xcursor", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b33ca445c55..e21ac32a7f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,9 +85,11 @@ chrono = { version = "0.4.42", default-features = false } cint = "0.3.1" color-hex = "0.2.0" criterion = { version = "0.7.0", default-features = false } +cursor-icon = "1" dify = { version = "0.7.4", default-features = false } directories = "6.0.0" document-features = "0.2.11" +dpi = "0.1" ehttp = { version = "0.5.0", default-features = false } enum-map = "2.7.3" env_logger = { version = "0.11.8", default-features = false } @@ -142,7 +144,8 @@ web-time = "1.1.0" # Timekeeping for native and web webbrowser = "1.0.5" wgpu = { version = "27.0.1", default-features = false, features = ["std"] } windows-sys = "0.61.2" -winit = { version = "0.30.12", default-features = false } +winit = { version = "0.31.0-beta.2", default-features = false } +winit-core = { version = "0.31.0-beta.2", default-features = false } [workspace.lints.rust] diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index ed9af012c0d..43a618f7d70 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -140,7 +140,8 @@ serde = { workspace = true, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] egui-winit = { workspace = true, default-features = false, features = ["clipboard", "links"] } image = { workspace = true, features = ["png"] } # Needed for app icon -winit = { workspace = true, default-features = false, features = ["rwh_06"] } +winit = { workspace = true, default-features = false } +winit-core.workspace = true # optional native: egui-wgpu = { workspace = true, optional = true, features = [ @@ -169,7 +170,10 @@ objc2-foundation = { workspace = true, default-features = false, features = [ objc2-app-kit = { workspace = true, default-features = false, features = [ "std", "NSApplication", + "NSBitmapImageRep", + "NSGraphics", "NSImage", + "NSImageRep", "NSMenu", "NSMenuItem", "NSResponder", diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index a7bcfd6ef4d..ea77d61dca1 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -31,7 +31,7 @@ pub use winit::{event_loop::EventLoopBuilder, window::WindowAttributes}; /// done by `EFrame`. #[cfg(not(target_arch = "wasm32"))] #[cfg(any(feature = "glow", feature = "wgpu_no_default_features"))] -pub type EventLoopBuilderHook = Box)>; +pub type EventLoopBuilderHook = Box; /// Hook into the building of a the native window. /// diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index d803a52496e..2489da6266a 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -327,7 +327,7 @@ pub fn create_native<'a>( app_name: &str, mut native_options: NativeOptions, app_creator: AppCreator<'a>, - event_loop: &winit::event_loop::EventLoop, + event_loop: &winit::event_loop::EventLoop, ) -> EframeWinitApplication<'a> { let renderer = init_native(app_name, &mut native_options); @@ -455,6 +455,10 @@ pub enum Error { #[cfg(not(target_arch = "wasm32"))] Winit(winit::error::OsError), + /// An request error from [`winit`]. + #[cfg(not(target_arch = "wasm32"))] + WinitRequest(winit::error::RequestError), + /// An error from [`winit::event_loop::EventLoop`]. #[cfg(not(target_arch = "wasm32"))] WinitEventLoop(winit::error::EventLoopError), @@ -486,6 +490,14 @@ impl From for Error { } } +#[cfg(not(target_arch = "wasm32"))] +impl From for Error { + #[inline] + fn from(err: winit::error::RequestError) -> Self { + Self::WinitRequest(err) + } +} + #[cfg(not(target_arch = "wasm32"))] impl From for Error { #[inline] @@ -555,6 +567,9 @@ impl std::fmt::Display for Error { Self::Wgpu(err) => { write!(f, "WGPU error: {err}") } + Error::WinitRequest(err) => { + write!(f, "winit request error: {err}") + } } } } diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 447b3ea9df0..2a94e03e1a0 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -15,7 +15,7 @@ use crate::epi; #[cfg_attr(target_os = "ios", allow(dead_code, unused_variables, unused_mut))] pub fn viewport_builder( egui_zoom_factor: f32, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, native_options: &mut epi::NativeOptions, window_settings: Option, ) -> ViewportBuilder { @@ -71,15 +71,16 @@ pub fn viewport_builder( .primary_monitor() .or_else(|| event_loop.available_monitors().next()) { - let monitor_size = monitor - .size() - .to_logical::(egui_zoom_factor as f64 * monitor.scale_factor()); - let inner_size = inner_size_points.unwrap_or(egui::Vec2 { x: 800.0, y: 600.0 }); - if 0.0 < monitor_size.width && 0.0 < monitor_size.height { - let x = (monitor_size.width - inner_size.x) / 2.0; - let y = (monitor_size.height - inner_size.y) / 2.0; - viewport_builder = viewport_builder.with_position([x, y]); - } + todo!() + // let monitor_size = monitor + // .size() + // .to_logical::(egui_zoom_factor as f64 * monitor.scale_factor()); + // let inner_size = inner_size_points.unwrap_or(egui::Vec2 { x: 800.0, y: 600.0 }); + // if 0.0 < monitor_size.width && 0.0 < monitor_size.height { + // let x = (monitor_size.width - inner_size.x) / 2.0; + // let y = (monitor_size.height - inner_size.y) / 2.0; + // viewport_builder = viewport_builder.with_position([x, y]); + // } } } @@ -90,7 +91,7 @@ pub fn viewport_builder( } pub fn apply_window_settings( - window: &winit::window::Window, + window: &dyn winit::window::Window, window_settings: Option, ) { profiling::function_scope!(); @@ -100,7 +101,7 @@ pub fn apply_window_settings( } #[cfg(not(target_os = "ios"))] -fn largest_monitor_point_size(egui_zoom_factor: f32, event_loop: &ActiveEventLoop) -> egui::Vec2 { +fn largest_monitor_point_size(egui_zoom_factor: f32, event_loop: &dyn ActiveEventLoop) -> egui::Vec2 { profiling::function_scope!(); let mut max_size = egui::Vec2::ZERO; @@ -110,11 +111,12 @@ fn largest_monitor_point_size(egui_zoom_factor: f32, event_loop: &ActiveEventLoo }; for monitor in available_monitors { - let size = monitor - .size() - .to_logical::(egui_zoom_factor as f64 * monitor.scale_factor()); - let size = egui::vec2(size.width, size.height); - max_size = max_size.max(size); + todo!() + // let size = monitor + // .size() + // .to_logical::(egui_zoom_factor as f64 * monitor.scale_factor()); + // let size = egui::vec2(size.width, size.height); + // max_size = max_size.max(size); } if max_size == egui::Vec2::ZERO { @@ -171,7 +173,7 @@ impl EpiIntegration { #[allow(clippy::allow_attributes, clippy::too_many_arguments)] pub fn new( egui_ctx: egui::Context, - window: &winit::window::Window, + window: &dyn winit::window::Window, app_name: &str, native_options: &crate::NativeOptions, storage: Option>, @@ -233,7 +235,7 @@ impl EpiIntegration { pub fn on_window_event( &mut self, - window: &winit::window::Window, + window: &dyn winit::window::Window, egui_winit: &mut egui_winit::State, event: &winit::event::WindowEvent, ) -> EventResponse { @@ -241,14 +243,15 @@ impl EpiIntegration { use winit::event::{ElementState, MouseButton, WindowEvent}; - if let WindowEvent::MouseInput { - button: MouseButton::Left, - state: ElementState::Pressed, - .. - } = event - { - self.can_drag_window = true; - } + // TODO + // if let WindowEvent::MouseInput { + // button: MouseButton::Left, + // state: ElementState::Pressed, + // .. + // } = event + // { + // self.can_drag_window = true; + // } egui_winit.on_window_event(window, event) } @@ -304,7 +307,7 @@ impl EpiIntegration { self.frame.info.cpu_usage = Some(seconds); } - pub fn post_rendering(&mut self, window: &winit::window::Window) { + pub fn post_rendering(&mut self, window: &dyn winit::window::Window) { profiling::function_scope!(); if std::mem::take(&mut self.is_first_frame) { // We keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279 @@ -318,7 +321,7 @@ impl EpiIntegration { pub fn maybe_autosave( &mut self, app: &mut dyn epi::App, - window: Option<&winit::window::Window>, + window: Option<&dyn winit::window::Window>, ) { let now = Instant::now(); if now - self.last_auto_save > app.auto_save_interval() { @@ -327,7 +330,7 @@ impl EpiIntegration { } } - pub fn save(&mut self, app: &mut dyn epi::App, window: Option<&winit::window::Window>) { + pub fn save(&mut self, app: &mut dyn epi::App, window: Option<&dyn winit::window::Window>) { #[cfg(not(feature = "persistence"))] let _ = (self, app, window); diff --git a/crates/eframe/src/native/event_loop_context.rs b/crates/eframe/src/native/event_loop_context.rs index 810db8e1fa2..5bb3be1ee5c 100644 --- a/crates/eframe/src/native/event_loop_context.rs +++ b/crates/eframe/src/native/event_loop_context.rs @@ -2,19 +2,19 @@ use std::cell::Cell; use winit::event_loop::ActiveEventLoop; thread_local! { - static CURRENT_EVENT_LOOP: Cell> = const { Cell::new(None) }; + static CURRENT_EVENT_LOOP: Cell> = const { Cell::new(None) }; } struct EventLoopGuard; impl EventLoopGuard { - fn new(event_loop: &ActiveEventLoop) -> Self { + fn new(event_loop: &dyn ActiveEventLoop) -> Self { CURRENT_EVENT_LOOP.with(|cell| { assert!( cell.get().is_none(), "Attempted to set a new event loop while one is already set" ); - cell.set(Some(std::ptr::from_ref::(event_loop))); + cell.set(Some(std::ptr::from_ref::(event_loop))); }); Self } @@ -30,7 +30,7 @@ impl Drop for EventLoopGuard { #[expect(unsafe_code)] pub fn with_current_event_loop(f: F) -> Option where - F: FnOnce(&ActiveEventLoop) -> R, + F: FnOnce(&dyn ActiveEventLoop) -> R, { CURRENT_EVENT_LOOP.with(|cell| { cell.get().map(|ptr| { @@ -47,7 +47,7 @@ where } // The only public interface to use the event loop -pub fn with_event_loop_context(event_loop: &ActiveEventLoop, f: impl FnOnce()) { +pub fn with_event_loop_context(event_loop: &dyn ActiveEventLoop, f: impl FnOnce()) { // NOTE: For safety, this guard must NOT be leaked. let _guard = EventLoopGuard::new(event_loop); f(); diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 7a3a8b4c450..fbe2f478644 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -15,12 +15,12 @@ use crate::{ }; // ---------------------------------------------------------------------------- -fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result> { +fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result { #[cfg(target_os = "android")] use winit::platform::android::EventLoopBuilderExtAndroid as _; profiling::function_scope!(); - let mut builder = winit::event_loop::EventLoop::with_user_event(); + let mut builder = winit::event_loop::EventLoop::builder(); #[cfg(target_os = "android")] let mut builder = @@ -45,9 +45,9 @@ fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result( mut native_options: epi::NativeOptions, - f: impl FnOnce(&mut EventLoop, epi::NativeOptions) -> R, + f: impl FnOnce(&mut EventLoop, epi::NativeOptions) -> R, ) -> Result { - thread_local!(static EVENT_LOOP: std::cell::RefCell>> = const { std::cell::RefCell::new(None) }); + thread_local!(static EVENT_LOOP: std::cell::RefCell> = const { std::cell::RefCell::new(None) }); EVENT_LOOP.with(|event_loop| { // Since we want to reference NativeOptions when creating the EventLoop we can't @@ -84,7 +84,7 @@ impl WinitAppWrapper { fn handle_event_result( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, event_result: Result, ) { let mut exit = false; @@ -174,7 +174,7 @@ impl WinitAppWrapper { self.check_redraw_requests(event_loop); } - fn check_redraw_requests(&mut self, event_loop: &ActiveEventLoop) { + fn check_redraw_requests(&mut self, event_loop: &dyn ActiveEventLoop) { let now = Instant::now(); self.windows_next_repaint_times @@ -201,8 +201,8 @@ impl WinitAppWrapper { } } -impl ApplicationHandler for WinitAppWrapper { - fn suspended(&mut self, event_loop: &ActiveEventLoop) { +impl ApplicationHandler for WinitAppWrapper { + fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { profiling::scope!("Event::Suspended"); event_loop_context::with_event_loop_context(event_loop, move || { @@ -211,7 +211,7 @@ impl ApplicationHandler for WinitAppWrapper { }); } - fn resumed(&mut self, event_loop: &ActiveEventLoop) { + fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { profiling::scope!("Event::Resumed"); // Nb: Make sure this guard is dropped after this function returns. @@ -221,19 +221,19 @@ impl ApplicationHandler for WinitAppWrapper { }); } - fn exiting(&mut self, event_loop: &ActiveEventLoop) { - // On Mac, Cmd-Q we get here and then `run_app_on_demand` doesn't return (despite its name), - // so we need to save state now: - log::debug!("Received Event::LoopExiting - saving app state…"); - event_loop_context::with_event_loop_context(event_loop, move || { - self.winit_app.save_and_destroy(); - }); - } + // fn exiting(&mut self, event_loop: &ActiveEventLoop) { + // // On Mac, Cmd-Q we get here and then `run_app_on_demand` doesn't return (despite its name), + // // so we need to save state now: + // log::debug!("Received Event::LoopExiting - saving app state…"); + // event_loop_context::with_event_loop_context(event_loop, move || { + // self.winit_app.save_and_destroy(); + // }); + // } fn device_event( &mut self, - event_loop: &ActiveEventLoop, - device_id: winit::event::DeviceId, + event_loop: &dyn ActiveEventLoop, + device_id: Option, event: winit::event::DeviceEvent, ) { profiling::function_scope!(egui_winit::short_device_event_description(&event)); @@ -245,50 +245,51 @@ impl ApplicationHandler for WinitAppWrapper { }); } - fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { - profiling::function_scope!(match &event { - UserEvent::RequestRepaint { .. } => "UserEvent::RequestRepaint", - #[cfg(feature = "accesskit")] - UserEvent::AccessKitActionRequest(_) => "UserEvent::AccessKitActionRequest", - }); - - event_loop_context::with_event_loop_context(event_loop, move || { - let event_result = match event { - UserEvent::RequestRepaint { - when, - cumulative_pass_nr, - viewport_id, - } => { - let current_pass_nr = self - .winit_app - .egui_ctx() - .map_or(0, |ctx| ctx.cumulative_pass_nr_for(viewport_id)); - if current_pass_nr == cumulative_pass_nr - || current_pass_nr == cumulative_pass_nr + 1 - { - log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); - if let Some(window_id) = - self.winit_app.window_id_from_viewport_id(viewport_id) - { - Ok(EventResult::RepaintAt(window_id, when)) - } else { - Ok(EventResult::Wait) - } - } else { - log::trace!("Got outdated UserEvent::RequestRepaint"); - Ok(EventResult::Wait) // old request - we've already repainted - } - } - #[cfg(feature = "accesskit")] - UserEvent::AccessKitActionRequest(request) => { - self.winit_app.on_accesskit_event(request) - } - }; - self.handle_event_result(event_loop, event_result); - }); - } - - fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) { + // TODO: User event handling? + // fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { + // profiling::function_scope!(match &event { + // UserEvent::RequestRepaint { .. } => "UserEvent::RequestRepaint", + // #[cfg(feature = "accesskit")] + // UserEvent::AccessKitActionRequest(_) => "UserEvent::AccessKitActionRequest", + // }); + // + // event_loop_context::with_event_loop_context(event_loop, move || { + // let event_result = match event { + // UserEvent::RequestRepaint { + // when, + // cumulative_pass_nr, + // viewport_id, + // } => { + // let current_pass_nr = self + // .winit_app + // .egui_ctx() + // .map_or(0, |ctx| ctx.cumulative_pass_nr_for(viewport_id)); + // if current_pass_nr == cumulative_pass_nr + // || current_pass_nr == cumulative_pass_nr + 1 + // { + // log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}"); + // if let Some(window_id) = + // self.winit_app.window_id_from_viewport_id(viewport_id) + // { + // Ok(EventResult::RepaintAt(window_id, when)) + // } else { + // Ok(EventResult::Wait) + // } + // } else { + // log::trace!("Got outdated UserEvent::RequestRepaint"); + // Ok(EventResult::Wait) // old request - we've already repainted + // } + // } + // #[cfg(feature = "accesskit")] + // UserEvent::AccessKitActionRequest(request) => { + // self.winit_app.on_accesskit_event(request) + // } + // }; + // self.handle_event_result(event_loop, event_result); + // }); + // } + + fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: winit::event::StartCause) { if let winit::event::StartCause::ResumeTimeReached { .. } = cause { log::trace!("Woke up to check next_repaint_time"); } @@ -298,7 +299,7 @@ impl ApplicationHandler for WinitAppWrapper { fn window_event( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: winit::event::WindowEvent, ) { @@ -316,11 +317,15 @@ impl ApplicationHandler for WinitAppWrapper { self.handle_event_result(event_loop, event_result); }); } + + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + + } } #[cfg(not(target_os = "ios"))] -fn run_and_return(event_loop: &mut EventLoop, winit_app: impl WinitApp) -> Result { - use winit::platform::run_on_demand::EventLoopExtRunOnDemand as _; +fn run_and_return(event_loop: &mut EventLoop, winit_app: impl WinitApp) -> Result { + use winit_core::event_loop::run_on_demand::EventLoopExtRunOnDemand as _; log::trace!("Entering the winit event loop (run_app_on_demand)…"); @@ -330,12 +335,16 @@ fn run_and_return(event_loop: &mut EventLoop, winit_app: impl WinitAp app.return_result } -fn run_and_exit(event_loop: EventLoop, winit_app: impl WinitApp) -> Result { +fn run_and_exit(event_loop: EventLoop, winit_app: impl WinitApp) -> Result { log::trace!("Entering the winit event loop (run_app)…"); // When to repaint what window let mut app = WinitAppWrapper::new(winit_app, false); - event_loop.run_app(&mut app)?; + // let mut app = Box::leak(Box::new(app)); // TODO: avoid leak + let app_mut: &mut dyn ApplicationHandler = &mut app; + #[allow(unsafe_code)] + let app_mut: &'static mut dyn ApplicationHandler = unsafe { std::mem::transmute(app_mut) }; // TODO: avoid unsafe + event_loop.run_app(app_mut)?; log::debug!("winit event loop unexpectedly returned"); Ok(()) @@ -371,8 +380,8 @@ pub fn create_glow<'a>( app_name: &str, native_options: epi::NativeOptions, app_creator: epi::AppCreator<'a>, - event_loop: &EventLoop, -) -> impl ApplicationHandler + 'a { + event_loop: &EventLoop, +) -> impl ApplicationHandler + 'a { use super::glow_integration::GlowWinitApp; let glow_eframe = GlowWinitApp::new(event_loop, app_name, native_options, app_creator); @@ -409,8 +418,8 @@ pub fn create_wgpu<'a>( app_name: &str, native_options: epi::NativeOptions, app_creator: epi::AppCreator<'a>, - event_loop: &EventLoop, -) -> impl ApplicationHandler + 'a { + event_loop: &EventLoop, +) -> impl ApplicationHandler + 'a { use super::wgpu_integration::WgpuWinitApp; let wgpu_eframe = WgpuWinitApp::new(event_loop, app_name, native_options, app_creator); @@ -424,61 +433,65 @@ pub fn create_wgpu<'a>( /// This can be run directly on your own [`EventLoop`] by itself or with other /// windows you manage outside of eframe. pub struct EframeWinitApplication<'a> { - wrapper: Box + 'a>, + wrapper: Box, control_flow: ControlFlow, } -impl ApplicationHandler for EframeWinitApplication<'_> { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { +impl ApplicationHandler for EframeWinitApplication<'_> { + fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { self.wrapper.resumed(event_loop); } fn window_event( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: winit::window::WindowId, event: winit::event::WindowEvent, ) { self.wrapper.window_event(event_loop, window_id, event); } - fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) { + fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: winit::event::StartCause) { self.wrapper.new_events(event_loop, cause); } - fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { - self.wrapper.user_event(event_loop, event); - } + // fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { + // self.wrapper.user_event(event_loop, event); + // } fn device_event( &mut self, - event_loop: &ActiveEventLoop, - device_id: winit::event::DeviceId, + event_loop: &dyn ActiveEventLoop, + device_id: Option, event: winit::event::DeviceEvent, ) { self.wrapper.device_event(event_loop, device_id, event); } - fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { + fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) { self.wrapper.about_to_wait(event_loop); self.control_flow = event_loop.control_flow(); } - fn suspended(&mut self, event_loop: &ActiveEventLoop) { + fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) { self.wrapper.suspended(event_loop); } - fn exiting(&mut self, event_loop: &ActiveEventLoop) { - self.wrapper.exiting(event_loop); - } + // fn exiting(&mut self, event_loop: &ActiveEventLoop) { + // self.wrapper.exiting(event_loop); + // } - fn memory_warning(&mut self, event_loop: &ActiveEventLoop) { + fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { self.wrapper.memory_warning(event_loop); } + + fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) { + todo!() + } } impl<'a> EframeWinitApplication<'a> { - pub(crate) fn new + 'a>(app: T) -> Self { + pub(crate) fn new(app: T) -> Self { Self { wrapper: Box::new(app), control_flow: ControlFlow::default(), @@ -495,12 +508,12 @@ impl<'a> EframeWinitApplication<'a> { #[cfg(not(target_os = "ios"))] pub fn pump_eframe_app( &mut self, - event_loop: &mut EventLoop, + event_loop: &mut EventLoop, timeout: Option, ) -> EframePumpStatus { - use winit::platform::pump_events::{EventLoopExtPumpEvents as _, PumpStatus}; + use winit_core::event_loop::pump_events::{EventLoopExtPumpEvents as _, PumpStatus}; - match event_loop.pump_app_events(timeout, self) { + match event_loop.pump_app_events(timeout, &mut *self) { PumpStatus::Continue => EframePumpStatus::Continue(self.control_flow), PumpStatus::Exit(code) => EframePumpStatus::Exit(code), } diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index c6c715c8cb3..b718327ae93 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -6,7 +6,7 @@ //! like removing a bunch of `unwraps`. use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc, time::Instant}; - +use std::ops::Deref; use egui_winit::ActionRequested; use parking_lot::Mutex; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; @@ -36,7 +36,7 @@ use super::{epi_integration, event_loop_context, winit_integration, winit_integr // Types: pub struct WgpuWinitApp<'app> { - repaint_proxy: Arc>>, + repaint_proxy: Arc>, app_name: String, native_options: NativeOptions, @@ -89,7 +89,7 @@ pub struct Viewport { /// Window surface state that's initialized when the app starts running via a Resumed event /// and on Android will also be destroyed if the application is paused. - window: Option>, + window: Option>, /// `window` and `egui_winit` are initialized together. egui_winit: Option, @@ -99,7 +99,7 @@ pub struct Viewport { impl<'app> WgpuWinitApp<'app> { pub fn new( - event_loop: &EventLoop, + event_loop: &EventLoop, app_name: &str, native_options: NativeOptions, app_creator: AppCreator<'app>, @@ -122,7 +122,7 @@ impl<'app> WgpuWinitApp<'app> { } /// Create a window for all viewports lacking one. - fn initialized_all_windows(&mut self, event_loop: &ActiveEventLoop) { + fn initialized_all_windows(&mut self, event_loop: &dyn ActiveEventLoop) { let Some(running) = &mut self.running else { return; }; @@ -178,9 +178,9 @@ impl<'app> WgpuWinitApp<'app> { fn init_run_state( &mut self, egui_ctx: egui::Context, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, storage: Option>, - window: Window, + window: Box, builder: ViewportBuilder, ) -> crate::Result<&mut WgpuWinitRunning<'app>> { profiling::function_scope!(); @@ -200,12 +200,12 @@ impl<'app> WgpuWinitApp<'app> { )); let mut viewport_info = ViewportInfo::default(); - egui_winit::update_viewport_info(&mut viewport_info, &egui_ctx, &window, true); + egui_winit::update_viewport_info(&mut viewport_info, &egui_ctx, window.deref(), true); { // Tell egui right away about native_pixels_per_point etc, // so that the app knows about it during app creation: - let pixels_per_point = egui_winit::pixels_per_point(&egui_ctx, &window); + let pixels_per_point = egui_winit::pixels_per_point(&egui_ctx, window.deref()); egui_ctx.input_mut(|i| { i.raw @@ -215,7 +215,7 @@ impl<'app> WgpuWinitApp<'app> { }); } - let window = Arc::new(window); + let window: Arc = Arc::from(window); { profiling::scope!("set_window"); @@ -226,7 +226,7 @@ impl<'app> WgpuWinitApp<'app> { let integration = EpiIntegration::new( egui_ctx.clone(), - &window, + window.deref(), &self.app_name, &self.native_options, storage, @@ -247,12 +247,14 @@ impl<'app> WgpuWinitApp<'app> { event_loop_proxy .lock() - .send_event(UserEvent::RequestRepaint { - when, - cumulative_pass_nr, - viewport_id: info.viewport_id, - }) - .ok(); + .wake_up(); + // TODO: Pass user info somehow + // .send_event(UserEvent::RequestRepaint { + // when, + // cumulative_pass_nr, + // viewport_id: info.viewport_id, + // }) + // .ok(); }); } @@ -260,7 +262,7 @@ impl<'app> WgpuWinitApp<'app> { let mut egui_winit = egui_winit::State::new( egui_ctx.clone(), ViewportId::ROOT, - event_loop, + &event_loop, Some(window.scale_factor() as f32), event_loop.system_theme(), painter.max_texture_side(), @@ -346,7 +348,7 @@ impl WinitApp for WgpuWinitApp<'_> { self.running.as_ref().map(|r| &r.integration.egui_ctx) } - fn window(&self, window_id: WindowId) -> Option> { + fn window(&self, window_id: WindowId) -> Option> { self.running .as_ref() .and_then(|r| { @@ -386,7 +388,7 @@ impl WinitApp for WgpuWinitApp<'_> { fn run_ui_and_paint( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: WindowId, ) -> Result { self.initialized_all_windows(event_loop); @@ -398,7 +400,7 @@ impl WinitApp for WgpuWinitApp<'_> { } } - fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result { + fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) -> crate::Result { log::debug!("Event::Resumed"); let running = if let Some(running) = &self.running { @@ -435,7 +437,7 @@ impl WinitApp for WgpuWinitApp<'_> { } } - fn suspended(&mut self, _: &ActiveEventLoop) -> crate::Result { + fn suspended(&mut self, _: &dyn ActiveEventLoop) -> crate::Result { #[cfg(target_os = "android")] self.drop_window()?; Ok(EventResult::Save) @@ -443,34 +445,35 @@ impl WinitApp for WgpuWinitApp<'_> { fn device_event( &mut self, - _: &ActiveEventLoop, - _: winit::event::DeviceId, + _: &dyn ActiveEventLoop, + _: Option, event: winit::event::DeviceEvent, ) -> crate::Result { - if let winit::event::DeviceEvent::MouseMotion { delta } = event - && let Some(running) = &mut self.running - { - let mut shared = running.shared.borrow_mut(); - if let Some(viewport) = shared - .focused_viewport - .and_then(|viewport| shared.viewports.get_mut(&viewport)) - { - if let Some(egui_winit) = viewport.egui_winit.as_mut() { - egui_winit.on_mouse_motion(delta); - } - - if let Some(window) = viewport.window.as_ref() { - return Ok(EventResult::RepaintNext(window.id())); - } - } - } + // TODO + // if let winit::event::DeviceEvent::MouseMotion { delta } = event + // && let Some(running) = &mut self.running + // { + // let mut shared = running.shared.borrow_mut(); + // if let Some(viewport) = shared + // .focused_viewport + // .and_then(|viewport| shared.viewports.get_mut(&viewport)) + // { + // if let Some(egui_winit) = viewport.egui_winit.as_mut() { + // egui_winit.on_mouse_motion(delta); + // } + // + // if let Some(window) = viewport.window.as_ref() { + // return Ok(EventResult::RepaintNext(window.id())); + // } + // } + // } Ok(EventResult::Wait) } fn window_event( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: winit::event::WindowEvent, ) -> crate::Result { @@ -606,7 +609,7 @@ impl WgpuWinitRunning<'_> { let Some(window) = window else { return Ok(EventResult::Wait); }; - egui_winit::update_viewport_info(info, &integration.egui_ctx, window, false); + egui_winit::update_viewport_info(info, &integration.egui_ctx, window.deref().deref(), false); { profiling::scope!("set_window"); @@ -616,7 +619,7 @@ impl WgpuWinitRunning<'_> { let Some(egui_winit) = egui_winit.as_mut() else { return Ok(EventResult::Wait); }; - let mut raw_input = egui_winit.take_egui_input(window); + let mut raw_input = egui_winit.take_egui_input(window.deref().deref()); integration.pre_update(); @@ -674,7 +677,7 @@ impl WgpuWinitRunning<'_> { return Ok(EventResult::Wait); }; - egui_winit.handle_platform_output(window, platform_output); + egui_winit.handle_platform_output(&**window, platform_output); let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point); @@ -721,7 +724,7 @@ impl WgpuWinitRunning<'_> { } } - integration.post_rendering(window); + integration.post_rendering(&**window); let active_viewports_ids: ViewportIdSet = viewport_output.keys().copied().collect(); @@ -824,24 +827,25 @@ impl WgpuWinitRunning<'_> { shared.focused_viewport = focused.then_some(viewport_id).flatten(); } - winit::event::WindowEvent::Resized(physical_size) => { - // Resize with 0 width and height is used by winit to signal a minimize event on Windows. - // See: https://github.com/rust-windowing/winit/issues/208 - // This solves an issue where the app would panic when minimizing on Windows. - if let Some(id) = viewport_id - && let (Some(width), Some(height)) = ( - NonZeroU32::new(physical_size.width), - NonZeroU32::new(physical_size.height), - ) - { - if shared.resized_viewport != viewport_id { - shared.resized_viewport = viewport_id; - shared.painter.on_window_resize_state_change(id, true); - } - shared.painter.on_window_resized(id, width, height); - repaint_asap = true; - } - } + // TODO + // winit::event::WindowEvent::Resized(physical_size) => { + // // Resize with 0 width and height is used by winit to signal a minimize event on Windows. + // // See: https://github.com/rust-windowing/winit/issues/208 + // // This solves an issue where the app would panic when minimizing on Windows. + // if let Some(id) = viewport_id + // && let (Some(width), Some(height)) = ( + // NonZeroU32::new(physical_size.width), + // NonZeroU32::new(physical_size.height), + // ) + // { + // if shared.resized_viewport != viewport_id { + // shared.resized_viewport = viewport_id; + // shared.painter.on_window_resize_state_change(id, true); + // } + // shared.painter.on_window_resized(id, width, height); + // repaint_asap = true; + // } + // } winit::event::WindowEvent::CloseRequested => { if viewport_id == Some(ViewportId::ROOT) && integration.should_close() { @@ -899,7 +903,7 @@ impl Viewport { /// Create winit window, if needed. fn initialize_window( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, egui_ctx: &egui::Context, windows_id: &mut HashMap, painter: &mut egui_wgpu::winit::Painter, @@ -916,7 +920,7 @@ impl Viewport { Ok(window) => { windows_id.insert(window.id(), viewport_id); - let window = Arc::new(window); + let window: Arc = Arc::from(window); if let Err(err) = pollster::block_on(painter.set_window(viewport_id, Some(window.clone()))) @@ -927,13 +931,13 @@ impl Viewport { self.egui_winit = Some(egui_winit::State::new( egui_ctx.clone(), viewport_id, - event_loop, + &event_loop, Some(window.scale_factor() as f32), event_loop.system_theme(), painter.max_texture_side(), )); - egui_winit::update_viewport_info(&mut self.info, egui_ctx, &window, true); + egui_winit::update_viewport_info(&mut self.info, egui_ctx, &*window, true); self.window = Some(window); } Err(err) => { @@ -945,10 +949,10 @@ impl Viewport { fn create_window( egui_ctx: &egui::Context, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, storage: Option<&dyn Storage>, native_options: &mut NativeOptions, -) -> Result<(Window, ViewportBuilder), winit::error::OsError> { +) -> Result<(Box, ViewportBuilder), winit::error::RequestError> { profiling::function_scope!(); let window_settings = epi_integration::load_window_settings(storage); @@ -961,7 +965,7 @@ fn create_window( .with_visible(false); // Start hidden until we render the first frame to fix white flash on startup (https://github.com/emilk/egui/pull/3631) let window = egui_winit::create_window(egui_ctx, event_loop, &viewport_builder)?; - epi_integration::apply_window_settings(&window, window_settings); + epi_integration::apply_window_settings(&*window, window_settings); Ok((window, viewport_builder)) } @@ -1004,9 +1008,9 @@ fn render_immediate_viewport( let (Some(window), Some(egui_winit)) = (&viewport.window, &mut viewport.egui_winit) else { return; }; - egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window, false); + egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, &**window, false); - let mut input = egui_winit.take_egui_input(window); + let mut input = egui_winit.take_egui_input(&**window); input.viewports = viewports .iter() .map(|(id, viewport)| (*id, viewport.info.clone())) @@ -1069,7 +1073,7 @@ fn render_immediate_viewport( vec![], ); - egui_winit.handle_platform_output(window, platform_output); + egui_winit.handle_platform_output(&**window, platform_output); handle_viewport_output( &egui_ctx, @@ -1120,7 +1124,7 @@ fn handle_viewport_output( initialize_or_update_viewport(viewports, ids, class, builder, viewport_ui_cb, painter); if let Some(window) = viewport.window.as_ref() { - let old_inner_size = window.inner_size(); + let old_inner_size = window.surface_size(); viewport.deferred_commands.append(&mut commands); @@ -1128,13 +1132,13 @@ fn handle_viewport_output( egui_ctx, &mut viewport.info, std::mem::take(&mut viewport.deferred_commands), - window, + &**window, &mut viewport.actions_requested, ); // For Wayland : https://github.com/emilk/egui/issues/4196 if cfg!(target_os = "linux") { - let new_inner_size = window.inner_size(); + let new_inner_size = window.surface_size(); if new_inner_size != old_inner_size && let (Some(width), Some(height)) = ( NonZeroU32::new(new_inner_size.width), diff --git a/crates/eframe/src/native/winit_integration.rs b/crates/eframe/src/native/winit_integration.rs index 2cf2e90195b..dc2cd914c92 100644 --- a/crates/eframe/src/native/winit_integration.rs +++ b/crates/eframe/src/native/winit_integration.rs @@ -66,7 +66,7 @@ impl From for UserEvent { pub trait WinitApp { fn egui_ctx(&self) -> Option<&egui::Context>; - fn window(&self, window_id: WindowId) -> Option>; + fn window(&self, window_id: WindowId) -> Option>; fn window_id_from_viewport_id(&self, id: ViewportId) -> Option; @@ -76,24 +76,24 @@ pub trait WinitApp { fn run_ui_and_paint( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: WindowId, ) -> crate::Result; - fn suspended(&mut self, event_loop: &ActiveEventLoop) -> crate::Result; + fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) -> crate::Result; - fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result; + fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) -> crate::Result; fn device_event( &mut self, - event_loop: &ActiveEventLoop, - device_id: winit::event::DeviceId, + event_loop: &dyn ActiveEventLoop, + device_id: Option, event: winit::event::DeviceEvent, ) -> crate::Result; fn window_event( &mut self, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, window_id: WindowId, event: winit::event::WindowEvent, ) -> crate::Result; diff --git a/crates/egui-wgpu/Cargo.toml b/crates/egui-wgpu/Cargo.toml index c514e0a4963..806ae5e0de2 100644 --- a/crates/egui-wgpu/Cargo.toml +++ b/crates/egui-wgpu/Cargo.toml @@ -31,7 +31,7 @@ default = ["fragile-send-sync-non-atomic-wasm", "macos-window-resize-jitter-fix" capture = ["dep:egui"] ## Enable [`winit`](https://docs.rs/winit) integration. On Linux, requires either `wayland` or `x11` -winit = ["dep:winit", "winit/rwh_06", "dep:egui", "capture"] +winit = ["dep:winit", "dep:egui", "capture"] ## Enables Wayland support for winit. wayland = ["winit?/wayland"] diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index 3a286cc9ea6..961273099f2 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -143,12 +143,12 @@ impl Painter { pub async fn set_window( &mut self, viewport_id: ViewportId, - window: Option>, + window: Option>, ) -> Result<(), crate::WgpuError> { profiling::scope!("Painter::set_window"); // profile_function gives bad names for async functions if let Some(window) = window { - let size = window.inner_size(); + let size = window.surface_size(); if !self.surfaces.contains_key(&viewport_id) { let surface = self.instance.create_surface(window)?; self.add_surface(surface, viewport_id, size).await?; @@ -169,12 +169,12 @@ impl Painter { pub async unsafe fn set_window_unsafe( &mut self, viewport_id: ViewportId, - window: Option<&winit::window::Window>, + window: Option<&dyn winit::window::Window>, ) -> Result<(), crate::WgpuError> { profiling::scope!("Painter::set_window_unsafe"); // profile_function gives bad names for async functions if let Some(window) = window { - let size = window.inner_size(); + let size = window.surface_size(); if !self.surfaces.contains_key(&viewport_id) { let surface = unsafe { self.instance diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index a4c84b05f57..fb0de81f08c 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -57,11 +57,13 @@ x11 = ["winit/x11", "bytemuck"] [dependencies] egui = { workspace = true, default-features = false } +dpi.workspace = true log.workspace = true profiling.workspace = true raw-window-handle.workspace = true web-time.workspace = true winit = { workspace = true, default-features = false } +winit-core.workspace = true #! ### Optional dependencies diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index d72c44245ee..9c69b6af4fb 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -9,6 +9,7 @@ #![allow(clippy::manual_range_contains)] +use std::ops::Deref; #[cfg(feature = "accesskit")] pub use accesskit_winit; pub use egui; @@ -31,21 +32,22 @@ use winit::{ event_loop::ActiveEventLoop, window::{CursorGrabMode, Window, WindowButtons, WindowLevel}, }; +use winit_core::event::Ime; -pub fn screen_size_in_pixels(window: &Window) -> egui::Vec2 { +pub fn screen_size_in_pixels(window: &dyn Window) -> egui::Vec2 { let size = if cfg!(target_os = "ios") { // `outer_size` Includes the area behind the "dynamic island". // It is up to the eframe user to make sure the dynamic island doesn't cover anything important. // That will be easier once https://github.com/rust-windowing/winit/pull/3890 lands window.outer_size() } else { - window.inner_size() + window.surface_size() }; egui::vec2(size.width as f32, size.height as f32) } /// Calculate the `pixels_per_point` for a given window, given the current egui zoom factor -pub fn pixels_per_point(egui_ctx: &egui::Context, window: &Window) -> f32 { +pub fn pixels_per_point(egui_ctx: &egui::Context, window: &dyn Window) -> f32 { let native_pixels_per_point = window.scale_factor() as f32; let egui_zoom_factor = egui_ctx.zoom_factor(); egui_zoom_factor * native_pixels_per_point @@ -166,9 +168,9 @@ impl State { #[cfg(feature = "accesskit")] pub fn init_accesskit + Send>( &mut self, - event_loop: &ActiveEventLoop, - window: &Window, - event_loop_proxy: winit::event_loop::EventLoopProxy, + event_loop: &dyn ActiveEventLoop, + window: &dyn Window, + event_loop_proxy: winit::event_loop::EventLoopProxy, ) { profiling::function_scope!(); @@ -231,7 +233,7 @@ impl State { /// You need to set [`egui::RawInput::viewports`] yourself though. /// Use [`update_viewport_info`] to update the info for each /// viewport. - pub fn take_egui_input(&mut self, window: &Window) -> egui::RawInput { + pub fn take_egui_input(&mut self, window: &dyn Window) -> egui::RawInput { profiling::function_scope!(); self.egui_input.time = Some(self.start_time.elapsed().as_secs_f64()); @@ -264,7 +266,7 @@ impl State { /// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`]. pub fn on_window_event( &mut self, - window: &Window, + window: &dyn Window, event: &winit::event::WindowEvent, ) -> EventResponse { profiling::function_scope!(short_window_event_description(event)); @@ -305,13 +307,13 @@ impl State { consumed: false, } } - WindowEvent::MouseInput { state, button, .. } => { - self.on_mouse_button_input(*state, *button); - EventResponse { - repaint: true, - consumed: self.egui_ctx.wants_pointer_input(), - } - } + // WindowEvent::MouseInput { state, button, .. } => { + // self.on_mouse_button_input(*state, *button); + // EventResponse { + // repaint: true, + // consumed: self.egui_ctx.wants_pointer_input(), + // } + // } WindowEvent::MouseWheel { delta, phase, .. } => { self.on_mouse_wheel(window, *delta, *phase); EventResponse { @@ -319,35 +321,35 @@ impl State { consumed: self.egui_ctx.wants_pointer_input(), } } - WindowEvent::CursorMoved { position, .. } => { - self.on_cursor_moved(window, *position); - EventResponse { - repaint: true, - consumed: self.egui_ctx.is_using_pointer(), - } - } - WindowEvent::CursorLeft { .. } => { - self.pointer_pos_in_points = None; - self.egui_input.events.push(egui::Event::PointerGone); - EventResponse { - repaint: true, - consumed: false, - } - } - // WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO(emilk) - WindowEvent::Touch(touch) => { - self.on_touch(window, touch); - let consumed = match touch.phase { - winit::event::TouchPhase::Started - | winit::event::TouchPhase::Ended - | winit::event::TouchPhase::Cancelled => self.egui_ctx.wants_pointer_input(), - winit::event::TouchPhase::Moved => self.egui_ctx.is_using_pointer(), - }; - EventResponse { - repaint: true, - consumed, - } - } + // WindowEvent::CursorMoved { position, .. } => { + // self.on_cursor_moved(window, *position); + // EventResponse { + // repaint: true, + // consumed: self.egui_ctx.is_using_pointer(), + // } + // } + // WindowEvent::CursorLeft { .. } => { + // self.pointer_pos_in_points = None; + // self.egui_input.events.push(egui::Event::PointerGone); + // EventResponse { + // repaint: true, + // consumed: false, + // } + // } + // // WindowEvent::TouchpadPressure {device_id, pressure, stage, .. } => {} // TODO(emilk) + // WindowEvent::PointerButton(touch) => { + // self.on_touch(window, touch); + // let consumed = match touch.phase { + // winit::event::TouchPhase::Started + // | winit::event::TouchPhase::Ended + // | winit::event::TouchPhase::Cancelled => self.egui_ctx.wants_pointer_input(), + // winit::event::TouchPhase::Moved => self.egui_ctx.is_using_pointer(), + // }; + // EventResponse { + // repaint: true, + // consumed, + // } + // } WindowEvent::Ime(ime) => { // on Mac even Cmd-C is pressed during ime, a `c` is pushed to Preedit. @@ -388,6 +390,9 @@ impl State { winit::event::Ime::Disabled | winit::event::Ime::Preedit(_, None) => { self.ime_event_disable(); } + Ime::DeleteSurrounding { .. } => { + todo!() + } } EventResponse { @@ -448,41 +453,41 @@ impl State { consumed: false, } } - WindowEvent::HoveredFile(path) => { - self.egui_input.hovered_files.push(egui::HoveredFile { - path: Some(path.clone()), - ..Default::default() - }); - EventResponse { - repaint: true, - consumed: false, - } - } - WindowEvent::HoveredFileCancelled => { - self.egui_input.hovered_files.clear(); - EventResponse { - repaint: true, - consumed: false, - } - } - WindowEvent::DroppedFile(path) => { - self.egui_input.hovered_files.clear(); - self.egui_input.dropped_files.push(egui::DroppedFile { - path: Some(path.clone()), - ..Default::default() - }); - EventResponse { - repaint: true, - consumed: false, - } - } + // WindowEvent::HoveredFile(path) => { + // self.egui_input.hovered_files.push(egui::HoveredFile { + // path: Some(path.clone()), + // ..Default::default() + // }); + // EventResponse { + // repaint: true, + // consumed: false, + // } + // } + // WindowEvent::HoveredFileCancelled => { + // self.egui_input.hovered_files.clear(); + // EventResponse { + // repaint: true, + // consumed: false, + // } + // } + // WindowEvent::DroppedFile(path) => { + // self.egui_input.hovered_files.clear(); + // self.egui_input.dropped_files.push(egui::DroppedFile { + // path: Some(path.clone()), + // ..Default::default() + // }); + // EventResponse { + // repaint: true, + // consumed: false, + // } + // } WindowEvent::ModifiersChanged(state) => { let state = state.state(); let alt = state.alt_key(); let ctrl = state.control_key(); let shift = state.shift_key(); - let super_ = state.super_key(); + let super_ = state.meta_key(); self.egui_input.modifiers.alt = alt; self.egui_input.modifiers.ctrl = ctrl; @@ -502,10 +507,10 @@ impl State { // Things that may require repaint: WindowEvent::RedrawRequested - | WindowEvent::CursorEntered { .. } + // | WindowEvent::CursorEntered { .. } | WindowEvent::Destroyed | WindowEvent::Occluded(_) - | WindowEvent::Resized(_) + // | WindowEvent::Resized(_) | WindowEvent::Moved(_) | WindowEvent::TouchpadPressure { .. } | WindowEvent::CloseRequested => EventResponse { @@ -515,7 +520,7 @@ impl State { // Things we completely ignore: WindowEvent::ActivationTokenDone { .. } - | WindowEvent::AxisMotion { .. } + // | WindowEvent::AxisMotion { .. } | WindowEvent::DoubleTapGesture { .. } => EventResponse { repaint: false, consumed: false, @@ -559,6 +564,20 @@ impl State { consumed: self.egui_ctx.wants_pointer_input(), } } + // WindowEvent::SurfaceResized(_) => {} + // WindowEvent::DragEntered { .. } => {} + // WindowEvent::DragMoved { .. } => {} + // WindowEvent::DragDropped { .. } => {} + // WindowEvent::DragLeft { .. } => {} + // WindowEvent::PointerMoved { .. } => {} + // WindowEvent::PointerEntered { .. } => {} + // WindowEvent::PointerLeft { .. } => {} + // WindowEvent::PointerButton { .. } => {} + // TODO: Handle these + _ => EventResponse { + repaint: false, + consumed: false, + }, } } @@ -642,7 +661,7 @@ impl State { fn on_cursor_moved( &mut self, - window: &Window, + window: &dyn Window, pos_in_pixels: winit::dpi::PhysicalPosition, ) { let pixels_per_point = pixels_per_point(&self.egui_ctx, window); @@ -674,69 +693,69 @@ impl State { } } - fn on_touch(&mut self, window: &Window, touch: &winit::event::Touch) { - let pixels_per_point = pixels_per_point(&self.egui_ctx, window); - - // Emit touch event - self.egui_input.events.push(egui::Event::Touch { - device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)), - id: egui::TouchId::from(touch.id), - phase: to_egui_touch_phase(touch.phase), - pos: egui::pos2( - touch.location.x as f32 / pixels_per_point, - touch.location.y as f32 / pixels_per_point, - ), - force: match touch.force { - Some(winit::event::Force::Normalized(force)) => Some(force as f32), - Some(winit::event::Force::Calibrated { - force, - max_possible_force, - .. - }) => Some((force / max_possible_force) as f32), - None => None, - }, - }); - // If we're not yet translating a touch or we're translating this very - // touch … - if self.pointer_touch_id.is_none() || self.pointer_touch_id.unwrap_or_default() == touch.id - { - // … emit PointerButton resp. PointerMoved events to emulate mouse - match touch.phase { - winit::event::TouchPhase::Started => { - self.pointer_touch_id = Some(touch.id); - // First move the pointer to the right location - self.on_cursor_moved(window, touch.location); - self.on_mouse_button_input( - winit::event::ElementState::Pressed, - winit::event::MouseButton::Left, - ); - } - winit::event::TouchPhase::Moved => { - self.on_cursor_moved(window, touch.location); - } - winit::event::TouchPhase::Ended => { - self.pointer_touch_id = None; - self.on_mouse_button_input( - winit::event::ElementState::Released, - winit::event::MouseButton::Left, - ); - // The pointer should vanish completely to not get any - // hover effects - self.pointer_pos_in_points = None; - self.egui_input.events.push(egui::Event::PointerGone); - } - winit::event::TouchPhase::Cancelled => { - self.pointer_touch_id = None; - self.pointer_pos_in_points = None; - self.egui_input.events.push(egui::Event::PointerGone); - } - } - } - } + // fn on_touch(&mut self, window: &Window, touch: &winit::event::Touch) { + // let pixels_per_point = pixels_per_point(&self.egui_ctx, window); + // + // // Emit touch event + // self.egui_input.events.push(egui::Event::Touch { + // device_id: egui::TouchDeviceId(egui::epaint::util::hash(touch.device_id)), + // id: egui::TouchId::from(touch.id), + // phase: to_egui_touch_phase(touch.phase), + // pos: egui::pos2( + // touch.location.x as f32 / pixels_per_point, + // touch.location.y as f32 / pixels_per_point, + // ), + // force: match touch.force { + // Some(winit::event::Force::Normalized(force)) => Some(force as f32), + // Some(winit::event::Force::Calibrated { + // force, + // max_possible_force, + // .. + // }) => Some((force / max_possible_force) as f32), + // None => None, + // }, + // }); + // // If we're not yet translating a touch or we're translating this very + // // touch … + // if self.pointer_touch_id.is_none() || self.pointer_touch_id.unwrap_or_default() == touch.id + // { + // // … emit PointerButton resp. PointerMoved events to emulate mouse + // match touch.phase { + // winit::event::TouchPhase::Started => { + // self.pointer_touch_id = Some(touch.id); + // // First move the pointer to the right location + // self.on_cursor_moved(window, touch.location); + // self.on_mouse_button_input( + // winit::event::ElementState::Pressed, + // winit::event::MouseButton::Left, + // ); + // } + // winit::event::TouchPhase::Moved => { + // self.on_cursor_moved(window, touch.location); + // } + // winit::event::TouchPhase::Ended => { + // self.pointer_touch_id = None; + // self.on_mouse_button_input( + // winit::event::ElementState::Released, + // winit::event::MouseButton::Left, + // ); + // // The pointer should vanish completely to not get any + // // hover effects + // self.pointer_pos_in_points = None; + // self.egui_input.events.push(egui::Event::PointerGone); + // } + // winit::event::TouchPhase::Cancelled => { + // self.pointer_touch_id = None; + // self.pointer_pos_in_points = None; + // self.egui_input.events.push(egui::Event::PointerGone); + // } + // } + // } + // } fn on_mouse_wheel( &mut self, - window: &Window, + window: &dyn Window, delta: winit::event::MouseScrollDelta, phase: winit::event::TouchPhase, ) { @@ -877,7 +896,7 @@ impl State { /// * pub fn handle_platform_output( &mut self, - window: &Window, + window: &dyn Window, platform_output: egui::PlatformOutput, ) { profiling::function_scope!(); @@ -929,11 +948,13 @@ impl State { winit::dpi::PhysicalPosition { x: ime_rect_px.min.x, y: ime_rect_px.min.y, - }, + } + .into(), winit::dpi::PhysicalSize { width: ime_rect_px.width(), height: ime_rect_px.height(), - }, + } + .into(), ); } } else { @@ -949,7 +970,7 @@ impl State { } } - fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) { + fn set_cursor_icon(&mut self, window: &dyn Window, cursor_icon: egui::CursorIcon) { if self.current_cursor_icon == Some(cursor_icon) { // Prevent flickering near frame boundary when Windows OS tries to control cursor icon for window resizing. // On other platforms: just early-out to save CPU. @@ -960,12 +981,7 @@ impl State { if is_pointer_in_window { self.current_cursor_icon = Some(cursor_icon); - if let Some(winit_cursor_icon) = translate_cursor(cursor_icon) { - window.set_cursor_visible(true); - window.set_cursor(winit_cursor_icon); - } else { - window.set_cursor_visible(false); - } + window.set_cursor_visible(true); } else { // Remember to set the cursor again once the cursor returns to the screen: self.current_cursor_icon = None; @@ -989,11 +1005,11 @@ fn to_egui_theme(theme: winit::window::Theme) -> Theme { } } -pub fn inner_rect_in_points(window: &Window, pixels_per_point: f32) -> Option { - let inner_pos_px = window.inner_position().ok()?; +pub fn inner_rect_in_points(window: &dyn Window, pixels_per_point: f32) -> Option { + let inner_pos_px = window.surface_position(); let inner_pos_px = egui::pos2(inner_pos_px.x as f32, inner_pos_px.y as f32); - let inner_size_px = window.inner_size(); + let inner_size_px = window.surface_size(); let inner_size_px = egui::vec2(inner_size_px.width as f32, inner_size_px.height as f32); let inner_rect_px = egui::Rect::from_min_size(inner_pos_px, inner_size_px); @@ -1001,7 +1017,7 @@ pub fn inner_rect_in_points(window: &Window, pixels_per_point: f32) -> Option Option { +pub fn outer_rect_in_points(window: &dyn Window, pixels_per_point: f32) -> Option { let outer_pos_px = window.outer_position().ok()?; let outer_pos_px = egui::pos2(outer_pos_px.x as f32, outer_pos_px.y as f32); @@ -1021,7 +1037,7 @@ pub fn outer_rect_in_points(window: &Window, pixels_per_point: f32) -> Option(pixels_per_point.into()); - Some(egui::vec2(size.width, size.height)) + // let size = monitor.size().to_logical::(pixels_per_point.into()); + // Some(egui::vec2(size.width, size.height)) + None // TODO } else { None } @@ -1122,7 +1139,8 @@ fn translate_mouse_button(button: winit::event::MouseButton) -> Option Some(egui::PointerButton::Middle), winit::event::MouseButton::Back => Some(egui::PointerButton::Extra1), winit::event::MouseButton::Forward => Some(egui::PointerButton::Extra2), - winit::event::MouseButton::Other(_) => None, + _ => None + // winit::event::MouseButton::Other(_) => None, } } @@ -1157,7 +1175,7 @@ fn key_from_named_key(named_key: winit::keyboard::NamedKey) -> Option NamedKey::Copy => Key::Copy, NamedKey::Paste => Key::Paste, - NamedKey::Space => Key::Space, + // NamedKey::SpaSpace => Key::Space, TODO: ?? NamedKey::F1 => Key::F1, NamedKey::F2 => Key::F2, @@ -1325,50 +1343,6 @@ fn key_from_key_code(key: winit::keyboard::KeyCode) -> Option { }) } -fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option { - match cursor_icon { - egui::CursorIcon::None => None, - - egui::CursorIcon::Alias => Some(winit::window::CursorIcon::Alias), - egui::CursorIcon::AllScroll => Some(winit::window::CursorIcon::AllScroll), - egui::CursorIcon::Cell => Some(winit::window::CursorIcon::Cell), - egui::CursorIcon::ContextMenu => Some(winit::window::CursorIcon::ContextMenu), - egui::CursorIcon::Copy => Some(winit::window::CursorIcon::Copy), - egui::CursorIcon::Crosshair => Some(winit::window::CursorIcon::Crosshair), - egui::CursorIcon::Default => Some(winit::window::CursorIcon::Default), - egui::CursorIcon::Grab => Some(winit::window::CursorIcon::Grab), - egui::CursorIcon::Grabbing => Some(winit::window::CursorIcon::Grabbing), - egui::CursorIcon::Help => Some(winit::window::CursorIcon::Help), - egui::CursorIcon::Move => Some(winit::window::CursorIcon::Move), - egui::CursorIcon::NoDrop => Some(winit::window::CursorIcon::NoDrop), - egui::CursorIcon::NotAllowed => Some(winit::window::CursorIcon::NotAllowed), - egui::CursorIcon::PointingHand => Some(winit::window::CursorIcon::Pointer), - egui::CursorIcon::Progress => Some(winit::window::CursorIcon::Progress), - - egui::CursorIcon::ResizeHorizontal => Some(winit::window::CursorIcon::EwResize), - egui::CursorIcon::ResizeNeSw => Some(winit::window::CursorIcon::NeswResize), - egui::CursorIcon::ResizeNwSe => Some(winit::window::CursorIcon::NwseResize), - egui::CursorIcon::ResizeVertical => Some(winit::window::CursorIcon::NsResize), - - egui::CursorIcon::ResizeEast => Some(winit::window::CursorIcon::EResize), - egui::CursorIcon::ResizeSouthEast => Some(winit::window::CursorIcon::SeResize), - egui::CursorIcon::ResizeSouth => Some(winit::window::CursorIcon::SResize), - egui::CursorIcon::ResizeSouthWest => Some(winit::window::CursorIcon::SwResize), - egui::CursorIcon::ResizeWest => Some(winit::window::CursorIcon::WResize), - egui::CursorIcon::ResizeNorthWest => Some(winit::window::CursorIcon::NwResize), - egui::CursorIcon::ResizeNorth => Some(winit::window::CursorIcon::NResize), - egui::CursorIcon::ResizeNorthEast => Some(winit::window::CursorIcon::NeResize), - egui::CursorIcon::ResizeColumn => Some(winit::window::CursorIcon::ColResize), - egui::CursorIcon::ResizeRow => Some(winit::window::CursorIcon::RowResize), - - egui::CursorIcon::Text => Some(winit::window::CursorIcon::Text), - egui::CursorIcon::VerticalText => Some(winit::window::CursorIcon::VerticalText), - egui::CursorIcon::Wait => Some(winit::window::CursorIcon::Wait), - egui::CursorIcon::ZoomIn => Some(winit::window::CursorIcon::ZoomIn), - egui::CursorIcon::ZoomOut => Some(winit::window::CursorIcon::ZoomOut), - } -} - // Helpers for egui Viewports // --------------------------------------------------------------------------- #[derive(PartialEq, Eq, Hash, Debug)] @@ -1383,7 +1357,7 @@ pub fn process_viewport_commands( egui_ctx: &egui::Context, info: &mut ViewportInfo, commands: impl IntoIterator, - window: &Window, + window: &dyn Window, actions_requested: &mut Vec, ) { for command in commands { @@ -1393,7 +1367,7 @@ pub fn process_viewport_commands( fn process_viewport_command( egui_ctx: &egui::Context, - window: &Window, + window: &dyn Window, command: ViewportCommand, info: &mut ViewportInfo, actions_requested: &mut Vec, @@ -1425,7 +1399,7 @@ fn process_viewport_command( let width_px = pixels_per_point * size.x.max(1.0); let height_px = pixels_per_point * size.y.max(1.0); let requested_size = PhysicalSize::new(width_px, height_px); - if let Some(_returned_inner_size) = window.request_inner_size(requested_size) { + if let Some(_returned_inner_size) = window.request_surface_size(requested_size.into()) { // On platforms where the size is entirely controlled by the user the // applied size will be returned immediately, resize event in such case // may not be generated. @@ -1470,21 +1444,21 @@ fn process_viewport_command( window.set_outer_position(PhysicalPosition::new( pixels_per_point * pos.x, pixels_per_point * pos.y, - )); + ).into()); } ViewportCommand::MinInnerSize(s) => { - window.set_min_inner_size((s.is_finite() && s != Vec2::ZERO).then_some( - PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y), + window.set_min_surface_size((s.is_finite() && s != Vec2::ZERO).then_some( + PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into(), )); } ViewportCommand::MaxInnerSize(s) => { - window.set_max_inner_size((s.is_finite() && s != Vec2::INFINITY).then_some( - PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y), + window.set_max_surface_size((s.is_finite() && s != Vec2::INFINITY).then_some( + PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into(), )); } ViewportCommand::ResizeIncrements(s) => { - window.set_resize_increments( - s.map(|s| PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y)), + window.set_surface_resize_increments( + s.map(|s| PhysicalSize::new(pixels_per_point * s.x, pixels_per_point * s.y).into()), ); } ViewportCommand::Resizable(v) => window.set_resizable(v), @@ -1516,7 +1490,7 @@ fn process_viewport_command( info.maximized = Some(v); } ViewportCommand::Fullscreen(v) => { - window.set_fullscreen(v.then_some(winit::window::Fullscreen::Borderless(None))); + window.set_fullscreen(v.then_some(winit_core::monitor::Fullscreen::Borderless(None))); } ViewportCommand::Decorations(v) => window.set_decorations(v), ViewportCommand::WindowLevel(l) => window.set_window_level(match l { @@ -1530,11 +1504,11 @@ fn process_viewport_command( } ViewportCommand::IMERect(rect) => { window.set_ime_cursor_area( - PhysicalPosition::new(pixels_per_point * rect.min.x, pixels_per_point * rect.min.y), + PhysicalPosition::new(pixels_per_point * rect.min.x, pixels_per_point * rect.min.y).into(), PhysicalSize::new( pixels_per_point * rect.size().x, pixels_per_point * rect.size().y, - ), + ).into(), ); } ViewportCommand::IMEAllowed(v) => window.set_ime_allowed(v), @@ -1569,7 +1543,7 @@ fn process_viewport_command( if let Err(err) = window.set_cursor_position(PhysicalPosition::new( pixels_per_point * pos.x, pixels_per_point * pos.y, - )) { + ).into()) { log::warn!("{command:?}: {err}"); } } @@ -1611,14 +1585,14 @@ fn process_viewport_command( /// Possible causes of error include denied permission, incompatible system, and lack of memory. pub fn create_window( egui_ctx: &egui::Context, - event_loop: &ActiveEventLoop, + event_loop: &dyn ActiveEventLoop, viewport_builder: &ViewportBuilder, -) -> Result { +) -> Result, winit::error::RequestError> { profiling::function_scope!(); let window_attributes = create_winit_window_attributes(egui_ctx, viewport_builder.clone()); let window = event_loop.create_window(window_attributes)?; - apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder); + apply_viewport_builder_to_window(egui_ctx, window.deref(), viewport_builder); Ok(window) } @@ -1686,7 +1660,7 @@ pub fn create_winit_window_attributes( egui::viewport::WindowLevel::Normal => WindowLevel::Normal, }) .with_fullscreen( - fullscreen.and_then(|e| e.then_some(winit::window::Fullscreen::Borderless(None))), + fullscreen.and_then(|e| e.then_some(winit_core::monitor::Fullscreen::Borderless(None))), ) .with_enabled_buttons({ let mut buttons = WindowButtons::empty(); @@ -1719,17 +1693,17 @@ pub fn create_winit_window_attributes( if let Some(size) = inner_size { window_attributes = window_attributes - .with_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); + .with_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); } if let Some(size) = min_inner_size { window_attributes = window_attributes - .with_min_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); + .with_min_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); } if let Some(size) = max_inner_size { window_attributes = window_attributes - .with_max_inner_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); + .with_max_surface_size(LogicalSize::new(zoom_factor * size.x, zoom_factor * size.y)); } if let Some(pos) = position { @@ -1798,26 +1772,27 @@ pub fn create_winit_window_attributes( #[cfg(target_os = "macos")] { - use winit::platform::macos::WindowAttributesExtMacOS as _; - window_attributes = window_attributes + let mac_window_attributes = winit::platform::macos::WindowAttributesMacOS::default() .with_title_hidden(!_title_shown.unwrap_or(true)) .with_titlebar_buttons_hidden(!_titlebar_buttons_shown.unwrap_or(true)) .with_titlebar_transparent(!_titlebar_shown.unwrap_or(true)) .with_fullsize_content_view(_fullsize_content_view.unwrap_or(false)) .with_movable_by_window_background(_movable_by_window_background.unwrap_or(false)) .with_has_shadow(_has_shadow.unwrap_or(true)); + window_attributes = + window_attributes.with_platform_attributes(Box::new(mac_window_attributes)); } window_attributes } -fn to_winit_icon(icon: &egui::IconData) -> Option { +fn to_winit_icon(icon: &egui::IconData) -> Option { if icon.is_empty() { None } else { profiling::function_scope!(); - match winit::window::Icon::from_rgba(icon.rgba.clone(), icon.width, icon.height) { - Ok(winit_icon) => Some(winit_icon), + match winit_core::icon::RgbaIcon::new(icon.rgba.clone(), icon.width, icon.height) { + Ok(winit_icon) => Some(winit_icon.into()), Err(err) => { log::warn!("Invalid IconData: {err}"); None @@ -1829,7 +1804,7 @@ fn to_winit_icon(icon: &egui::IconData) -> Option { /// Applies what `create_winit_window_builder` couldn't pub fn apply_viewport_builder_to_window( egui_ctx: &egui::Context, - window: &Window, + window: &dyn Window, builder: &ViewportBuilder, ) { if let Some(mouse_passthrough) = builder.mouse_passthrough @@ -1848,29 +1823,29 @@ pub fn apply_viewport_builder_to_window( if let Some(size) = builder.inner_size && window - .request_inner_size(PhysicalSize::new( + .request_surface_size(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, - )) + ).into()) .is_some() { log::debug!("Failed to set window size"); } if let Some(size) = builder.min_inner_size { - window.set_min_inner_size(Some(PhysicalSize::new( + window.set_min_surface_size(Some(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, - ))); + ).into())); } if let Some(size) = builder.max_inner_size { - window.set_max_inner_size(Some(PhysicalSize::new( + window.set_max_surface_size(Some(PhysicalSize::new( pixels_per_point * size.x, pixels_per_point * size.y, - ))); + ).into())); } if let Some(pos) = builder.position { let pos = PhysicalPosition::new(pixels_per_point * pos.x, pixels_per_point * pos.y); - window.set_outer_position(pos); + window.set_outer_position(pos.into()); } if let Some(maximized) = builder.maximized { window.set_maximized(maximized); @@ -1886,13 +1861,10 @@ pub fn short_device_event_description(event: &winit::event::DeviceEvent) -> &'st use winit::event::DeviceEvent; match event { - DeviceEvent::Added => "DeviceEvent::Added", - DeviceEvent::Removed => "DeviceEvent::Removed", - DeviceEvent::MouseMotion { .. } => "DeviceEvent::MouseMotion", DeviceEvent::MouseWheel { .. } => "DeviceEvent::MouseWheel", - DeviceEvent::Motion { .. } => "DeviceEvent::Motion", DeviceEvent::Button { .. } => "DeviceEvent::Button", DeviceEvent::Key { .. } => "DeviceEvent::Key", + DeviceEvent::PointerMotion { .. } => "DeviceEvent::PointerMotion", } } @@ -1903,32 +1875,31 @@ pub fn short_window_event_description(event: &winit::event::WindowEvent) -> &'st match event { WindowEvent::ActivationTokenDone { .. } => "WindowEvent::ActivationTokenDone", - WindowEvent::Resized { .. } => "WindowEvent::Resized", WindowEvent::Moved { .. } => "WindowEvent::Moved", WindowEvent::CloseRequested => "WindowEvent::CloseRequested", WindowEvent::Destroyed => "WindowEvent::Destroyed", - WindowEvent::DroppedFile { .. } => "WindowEvent::DroppedFile", - WindowEvent::HoveredFile { .. } => "WindowEvent::HoveredFile", - WindowEvent::HoveredFileCancelled => "WindowEvent::HoveredFileCancelled", WindowEvent::Focused { .. } => "WindowEvent::Focused", WindowEvent::KeyboardInput { .. } => "WindowEvent::KeyboardInput", WindowEvent::ModifiersChanged { .. } => "WindowEvent::ModifiersChanged", WindowEvent::Ime { .. } => "WindowEvent::Ime", - WindowEvent::CursorMoved { .. } => "WindowEvent::CursorMoved", - WindowEvent::CursorEntered { .. } => "WindowEvent::CursorEntered", - WindowEvent::CursorLeft { .. } => "WindowEvent::CursorLeft", WindowEvent::MouseWheel { .. } => "WindowEvent::MouseWheel", - WindowEvent::MouseInput { .. } => "WindowEvent::MouseInput", WindowEvent::PinchGesture { .. } => "WindowEvent::PinchGesture", WindowEvent::RedrawRequested => "WindowEvent::RedrawRequested", WindowEvent::DoubleTapGesture { .. } => "WindowEvent::DoubleTapGesture", WindowEvent::RotationGesture { .. } => "WindowEvent::RotationGesture", WindowEvent::TouchpadPressure { .. } => "WindowEvent::TouchpadPressure", - WindowEvent::AxisMotion { .. } => "WindowEvent::AxisMotion", - WindowEvent::Touch { .. } => "WindowEvent::Touch", WindowEvent::ScaleFactorChanged { .. } => "WindowEvent::ScaleFactorChanged", WindowEvent::ThemeChanged { .. } => "WindowEvent::ThemeChanged", WindowEvent::Occluded { .. } => "WindowEvent::Occluded", WindowEvent::PanGesture { .. } => "WindowEvent::PanGesture", + WindowEvent::SurfaceResized(_) => "WindowEvent::SurfaceResized", + WindowEvent::DragEntered { .. } => "WindowEvent::DragEntered", + WindowEvent::DragMoved { .. } => "WindowEvent::DragMoved", + WindowEvent::DragDropped { .. } => "WindowEvent::DragDropped", + WindowEvent::DragLeft { .. } => "WindowEvent::DragLeft", + WindowEvent::PointerMoved { .. } => "WindowEvent::PointerMoved", + WindowEvent::PointerEntered { .. } => "WindowEvent::PointerEntered", + WindowEvent::PointerLeft { .. } => "WindowEvent::PointerLeft", + WindowEvent::PointerButton { .. } => "WindowEvent::PointerButton", } } diff --git a/crates/egui-winit/src/window_settings.rs b/crates/egui-winit/src/window_settings.rs index d15712d4caf..ff809e73a9c 100644 --- a/crates/egui-winit/src/window_settings.rs +++ b/crates/egui-winit/src/window_settings.rs @@ -6,7 +6,7 @@ use egui::ViewportBuilder; #[cfg_attr(feature = "serde", serde(default))] pub struct WindowSettings { /// Position of window content in physical pixels. - inner_position_pixels: Option, + inner_position_pixels: egui::Pos2, /// Position of window frame/titlebar in physical pixels. outer_position_pixels: Option, @@ -20,15 +20,13 @@ pub struct WindowSettings { } impl WindowSettings { - pub fn from_window(egui_zoom_factor: f32, window: &winit::window::Window) -> Self { + pub fn from_window(egui_zoom_factor: f32, window: &dyn winit::window::Window) -> Self { let inner_size_points = window - .inner_size() + .surface_size() .to_logical::(egui_zoom_factor as f64 * window.scale_factor()); - let inner_position_pixels = window - .inner_position() - .ok() - .map(|p| egui::pos2(p.x as f32, p.y as f32)); + let inner_position = window.surface_position(); + let inner_position_pixels = egui::pos2(inner_position.x as f32, inner_position.y as f32); let outer_position_pixels = window .outer_position() @@ -56,7 +54,7 @@ impl WindowSettings { pub fn initialize_viewport_builder( &self, egui_zoom_factor: f32, - event_loop: &winit::event_loop::ActiveEventLoop, + event_loop: &dyn winit::event_loop::ActiveEventLoop, mut viewport_builder: ViewportBuilder, ) -> ViewportBuilder { profiling::function_scope!(); @@ -64,7 +62,7 @@ impl WindowSettings { // `WindowBuilder::with_position` expects inner position in Macos, and outer position elsewhere // See [`winit::window::WindowBuilder::with_position`] for details. let pos_px = if cfg!(target_os = "macos") { - self.inner_position_pixels + Some(self.inner_position_pixels) } else { self.outer_position_pixels }; @@ -90,12 +88,12 @@ impl WindowSettings { viewport_builder } - pub fn initialize_window(&self, window: &winit::window::Window) { + pub fn initialize_window(&self, window: &dyn winit::window::Window) { if cfg!(target_os = "macos") { // Mac sometimes has problems restoring the window to secondary monitors // using only `WindowBuilder::with_position`, so we need this extra step: if let Some(pos) = self.outer_position_pixels { - window.set_outer_position(winit::dpi::PhysicalPosition { x: pos.x, y: pos.y }); + window.set_outer_position(dpi::PhysicalPosition { x: pos.x, y: pos.y }.into()); } } } @@ -117,7 +115,7 @@ impl WindowSettings { pub fn clamp_position_to_monitors( &mut self, egui_zoom_factor: f32, - event_loop: &winit::event_loop::ActiveEventLoop, + event_loop: &dyn winit::event_loop::ActiveEventLoop, ) { // If the app last ran on two monitors and only one is now connected, then // the given position is invalid. @@ -132,9 +130,12 @@ impl WindowSettings { return; }; - if let Some(pos_px) = &mut self.inner_position_pixels { - clamp_pos_to_monitors(egui_zoom_factor, event_loop, inner_size_points, pos_px); - } + clamp_pos_to_monitors( + egui_zoom_factor, + event_loop, + inner_size_points, + &mut self.inner_position_pixels, + ); if let Some(pos_px) = &mut self.outer_position_pixels { clamp_pos_to_monitors(egui_zoom_factor, event_loop, inner_size_points, pos_px); } @@ -143,74 +144,75 @@ impl WindowSettings { fn find_active_monitor( egui_zoom_factor: f32, - event_loop: &winit::event_loop::ActiveEventLoop, + event_loop: &dyn winit::event_loop::ActiveEventLoop, window_size_pts: egui::Vec2, position_px: &egui::Pos2, ) -> Option { - profiling::function_scope!(); - let monitors = event_loop.available_monitors(); - - // default to primary monitor, in case the correct monitor was disconnected. - let Some(mut active_monitor) = event_loop - .primary_monitor() - .or_else(|| event_loop.available_monitors().next()) - else { - return None; // no monitors 🤷 - }; - - for monitor in monitors { - let window_size_px = window_size_pts * (egui_zoom_factor * monitor.scale_factor() as f32); - let monitor_x_range = (monitor.position().x - window_size_px.x as i32) - ..(monitor.position().x + monitor.size().width as i32); - let monitor_y_range = (monitor.position().y - window_size_px.y as i32) - ..(monitor.position().y + monitor.size().height as i32); - - if monitor_x_range.contains(&(position_px.x as i32)) - && monitor_y_range.contains(&(position_px.y as i32)) - { - active_monitor = monitor; - } - } - - Some(active_monitor) + None // TODO + // profiling::function_scope!(); + // let monitors = event_loop.available_monitors(); + // + // // default to primary monitor, in case the correct monitor was disconnected. + // let Some(mut active_monitor) = event_loop + // .primary_monitor() + // .or_else(|| event_loop.available_monitors().next()) + // else { + // return None; // no monitors 🤷 + // }; + // + // for monitor in monitors { + // let window_size_px = window_size_pts * (egui_zoom_factor * monitor.scale_factor() as f32); + // let monitor_x_range = (monitor.position().x - window_size_px.x as i32) + // ..(monitor.position().x + monitor.size().width as i32); + // let monitor_y_range = (monitor.position().y - window_size_px.y as i32) + // ..(monitor.position().y + monitor.size().height as i32); + // + // if monitor_x_range.contains(&(position_px.x as i32)) + // && monitor_y_range.contains(&(position_px.y as i32)) + // { + // active_monitor = monitor; + // } + // } + // + // Some(active_monitor) } fn clamp_pos_to_monitors( egui_zoom_factor: f32, - event_loop: &winit::event_loop::ActiveEventLoop, + event_loop: &dyn winit::event_loop::ActiveEventLoop, window_size_pts: egui::Vec2, position_px: &mut egui::Pos2, ) { - profiling::function_scope!(); - - let Some(active_monitor) = - find_active_monitor(egui_zoom_factor, event_loop, window_size_pts, position_px) - else { - return; // no monitors 🤷 - }; - - let mut window_size_px = - window_size_pts * (egui_zoom_factor * active_monitor.scale_factor() as f32); - // Add size of title bar. This is 32 px by default in Win 10/11. - if cfg!(target_os = "windows") { - window_size_px += egui::Vec2::new( - 0.0, - 32.0 * egui_zoom_factor * active_monitor.scale_factor() as f32, - ); - } - let monitor_position = egui::Pos2::new( - active_monitor.position().x as f32, - active_monitor.position().y as f32, - ); - let monitor_size_px = egui::Vec2::new( - active_monitor.size().width as f32, - active_monitor.size().height as f32, - ); - - // Window size cannot be negative or the subsequent `clamp` will panic. - let window_size = (monitor_size_px - window_size_px).max(egui::Vec2::ZERO); - // To get the maximum position, we get the rightmost corner of the display, then - // subtract the size of the window to get the bottom right most value window.position - // can have. - *position_px = position_px.clamp(monitor_position, monitor_position + window_size); + // profiling::function_scope!(); + // + // let Some(active_monitor) = + // find_active_monitor(egui_zoom_factor, event_loop, window_size_pts, position_px) + // else { + // return; // no monitors 🤷 + // }; + // + // let mut window_size_px = + // window_size_pts * (egui_zoom_factor * active_monitor.scale_factor() as f32); + // // Add size of title bar. This is 32 px by default in Win 10/11. + // if cfg!(target_os = "windows") { + // window_size_px += egui::Vec2::new( + // 0.0, + // 32.0 * egui_zoom_factor * active_monitor.scale_factor() as f32, + // ); + // } + // let monitor_position = egui::Pos2::new( + // active_monitor.position().x as f32, + // active_monitor.position().y as f32, + // ); + // let monitor_size_px = egui::Vec2::new( + // active_monitor.size().width as f32, + // active_monitor.size().height as f32, + // ); + // + // // Window size cannot be negative or the subsequent `clamp` will panic. + // let window_size = (monitor_size_px - window_size_px).max(egui::Vec2::ZERO); + // // To get the maximum position, we get the rightmost corner of the display, then + // // subtract the size of the window to get the bottom right most value window.position + // // can have. + // *position_px = position_px.clamp(monitor_position, monitor_position + window_size); } diff --git a/crates/egui/Cargo.toml b/crates/egui/Cargo.toml index c82ae5618e8..1d5ef1ec376 100644 --- a/crates/egui/Cargo.toml +++ b/crates/egui/Cargo.toml @@ -61,7 +61,7 @@ persistence = ["serde", "epaint/serde", "ron"] rayon = ["epaint/rayon"] ## Allow serialization using [`serde`](https://docs.rs/serde). -serde = ["dep:serde", "epaint/serde", "accesskit?/serde"] +serde = ["dep:serde", "epaint/serde", "accesskit?/serde", "cursor-icon/serde"] ## Change Vertex layout to be compatible with unity unity = ["epaint/unity"] @@ -77,6 +77,7 @@ epaint = { workspace = true, default-features = false } ahash.workspace = true bitflags.workspace = true +cursor-icon.workspace = true log.workspace = true nohash-hasher.workspace = true profiling.workspace = true diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index eb60f5f2156..a83cc89b6f2 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -846,28 +846,28 @@ impl Panel { if panel_sizer.size <= self.size_range.min { match self.side { PanelSide::Vertical(side) => match side { - VerticalSide::Left => CursorIcon::ResizeEast, - VerticalSide::Right => CursorIcon::ResizeWest, + VerticalSide::Left => CursorIcon::EResize, + VerticalSide::Right => CursorIcon::WResize, }, PanelSide::Horizontal(side) => match side { - HorizontalSide::Top => CursorIcon::ResizeSouth, - HorizontalSide::Bottom => CursorIcon::ResizeNorth, + HorizontalSide::Top => CursorIcon::SResize, + HorizontalSide::Bottom => CursorIcon::NResize, }, } } else if panel_sizer.size < self.size_range.max { match self.side { - PanelSide::Vertical(_) => CursorIcon::ResizeHorizontal, - PanelSide::Horizontal(_) => CursorIcon::ResizeVertical, + PanelSide::Vertical(_) => CursorIcon::ColResize, + PanelSide::Horizontal(_) => CursorIcon::RowResize, } } else { match self.side { PanelSide::Vertical(side) => match side { - VerticalSide::Left => CursorIcon::ResizeWest, - VerticalSide::Right => CursorIcon::ResizeEast, + VerticalSide::Left => CursorIcon::WResize, + VerticalSide::Right => CursorIcon::EResize, }, PanelSide::Horizontal(side) => match side { - HorizontalSide::Top => CursorIcon::ResizeNorth, - HorizontalSide::Bottom => CursorIcon::ResizeSouth, + HorizontalSide::Top => CursorIcon::NResize, + HorizontalSide::Bottom => CursorIcon::SResize, }, } } diff --git a/crates/egui/src/containers/resize.rs b/crates/egui/src/containers/resize.rs index 50cc2877426..fadbcdd9e42 100644 --- a/crates/egui/src/containers/resize.rs +++ b/crates/egui/src/containers/resize.rs @@ -362,7 +362,7 @@ impl Resize { paint_resize_corner(ui, &corner_response); if corner_response.hovered() || corner_response.dragged() { - ui.ctx().set_cursor_icon(CursorIcon::ResizeNwSe); + ui.ctx().set_cursor_icon(CursorIcon::NwseResize); } } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 7f4bdaa0831..d352e857073 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -798,13 +798,13 @@ impl ResizeInteraction { // TODO(emilk): use one-sided cursors for when we reached the min/max size. if (left && top) || (right && bottom) { - ctx.set_cursor_icon(CursorIcon::ResizeNwSe); + ctx.set_cursor_icon(CursorIcon::NwseResize); } else if (right && top) || (left && bottom) { - ctx.set_cursor_icon(CursorIcon::ResizeNeSw); + ctx.set_cursor_icon(CursorIcon::NwseResize); } else if left || right { - ctx.set_cursor_icon(CursorIcon::ResizeHorizontal); + ctx.set_cursor_icon(CursorIcon::ColResize); } else if bottom || top { - ctx.set_cursor_icon(CursorIcon::ResizeVertical); + ctx.set_cursor_icon(CursorIcon::RowResize); } } diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index deec5162dcd..a1679870aaa 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -261,174 +261,46 @@ pub enum UserAttentionType { Reset, } -/// A mouse cursor icon. -/// -/// egui emits a [`CursorIcon`] in [`PlatformOutput`] each frame as a request to the integration. -/// -/// Loosely based on . -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub enum CursorIcon { - /// Normal cursor icon, whatever that is. - #[default] - Default, - - /// Show no cursor - None, - - // ------------------------------------ - // Links and status: - /// A context menu is available - ContextMenu, - - /// Question mark - Help, - - /// Pointing hand, used for e.g. web links - PointingHand, - - /// Shows that processing is being done, but that the program is still interactive. - Progress, - - /// Not yet ready, try later. - Wait, - - // ------------------------------------ - // Selection: - /// Hover a cell in a table - Cell, - - /// For precision work - Crosshair, - - /// Text caret, e.g. "Click here to edit text" - Text, - - /// Vertical text caret, e.g. "Click here to edit vertical text" - VerticalText, - - // ------------------------------------ - // Drag-and-drop: - /// Indicated an alias, e.g. a shortcut - Alias, - - /// Indicate that a copy will be made - Copy, - - /// Omnidirectional move icon (e.g. arrows in all cardinal directions) - Move, - - /// Can't drop here - NoDrop, - - /// Forbidden - NotAllowed, - - /// The thing you are hovering can be grabbed - Grab, - - /// You are grabbing the thing you are hovering - Grabbing, - - // ------------------------------------ - /// Something can be scrolled in any direction (panned). - AllScroll, - - // ------------------------------------ - // Resizing in two directions: - /// Horizontal resize `-` to make something wider or more narrow (left to/from right) - ResizeHorizontal, - - /// Diagonal resize `/` (right-up to/from left-down) - ResizeNeSw, - - /// Diagonal resize `\` (left-up to/from right-down) - ResizeNwSe, - - /// Vertical resize `|` (up-down or down-up) - ResizeVertical, - - // ------------------------------------ - // Resizing in one direction: - /// Resize something rightwards (e.g. when dragging the right-most edge of something) - ResizeEast, - - /// Resize something down and right (e.g. when dragging the bottom-right corner of something) - ResizeSouthEast, - - /// Resize something downwards (e.g. when dragging the bottom edge of something) - ResizeSouth, - - /// Resize something down and left (e.g. when dragging the bottom-left corner of something) - ResizeSouthWest, - - /// Resize something leftwards (e.g. when dragging the left edge of something) - ResizeWest, - - /// Resize something up and left (e.g. when dragging the top-left corner of something) - ResizeNorthWest, - - /// Resize something up (e.g. when dragging the top edge of something) - ResizeNorth, - - /// Resize something up and right (e.g. when dragging the top-right corner of something) - ResizeNorthEast, - - // ------------------------------------ - /// Resize a column - ResizeColumn, - - /// Resize a row - ResizeRow, - - // ------------------------------------ - // Zooming: - /// Enhance! - ZoomIn, - - /// Let's get a better overview - ZoomOut, -} - -impl CursorIcon { - pub const ALL: [Self; 35] = [ - Self::Default, - Self::None, - Self::ContextMenu, - Self::Help, - Self::PointingHand, - Self::Progress, - Self::Wait, - Self::Cell, - Self::Crosshair, - Self::Text, - Self::VerticalText, - Self::Alias, - Self::Copy, - Self::Move, - Self::NoDrop, - Self::NotAllowed, - Self::Grab, - Self::Grabbing, - Self::AllScroll, - Self::ResizeHorizontal, - Self::ResizeNeSw, - Self::ResizeNwSe, - Self::ResizeVertical, - Self::ResizeEast, - Self::ResizeSouthEast, - Self::ResizeSouth, - Self::ResizeSouthWest, - Self::ResizeWest, - Self::ResizeNorthWest, - Self::ResizeNorth, - Self::ResizeNorthEast, - Self::ResizeColumn, - Self::ResizeRow, - Self::ZoomIn, - Self::ZoomOut, - ]; -} +pub use cursor_icon::CursorIcon; + +pub const ALL_CURSOR_ICONS: [CursorIcon; 36] = [ + CursorIcon::Default, + CursorIcon::ContextMenu, + CursorIcon::Help, + CursorIcon::Pointer, + CursorIcon::Progress, + CursorIcon::Wait, + CursorIcon::Cell, + CursorIcon::Crosshair, + CursorIcon::Text, + CursorIcon::VerticalText, + CursorIcon::Alias, + CursorIcon::Copy, + CursorIcon::Move, + CursorIcon::NoDrop, + CursorIcon::NotAllowed, + CursorIcon::Grab, + CursorIcon::Grabbing, + CursorIcon::EResize, + CursorIcon::NResize, + CursorIcon::NeResize, + CursorIcon::NwResize, + CursorIcon::SResize, + CursorIcon::SeResize, + CursorIcon::SwResize, + CursorIcon::WResize, + CursorIcon::EwResize, + CursorIcon::NsResize, + CursorIcon::NeswResize, + CursorIcon::NwseResize, + CursorIcon::ColResize, + CursorIcon::RowResize, + CursorIcon::AllScroll, + CursorIcon::ZoomIn, + CursorIcon::ZoomOut, + CursorIcon::DndAsk, + CursorIcon::AllResize, +]; /// Things that happened during this frame that the integration may be interested in. /// diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index b77536002ac..042af30e3dc 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -6,13 +6,7 @@ use emath::Align; use epaint::{AlphaFromCoverage, CornerRadius, Shadow, Stroke, text::FontTweak}; use std::{collections::BTreeMap, ops::RangeInclusive, sync::Arc}; -use crate::{ - ComboBox, CursorIcon, FontFamily, FontId, Grid, Margin, Response, RichText, TextWrapMode, - WidgetText, - ecolor::Color32, - emath::{Rangef, Rect, Vec2, pos2, vec2}, - reset_button_with, -}; +use crate::{ComboBox, CursorIcon, FontFamily, FontId, Grid, Margin, Response, RichText, TextWrapMode, WidgetText, ecolor::Color32, emath::{Rangef, Rect, Vec2, pos2, vec2}, reset_button_with, output}; /// How to format numbers in e.g. a [`crate::DragValue`]. #[derive(Clone)] @@ -2335,7 +2329,7 @@ impl Visuals { .show_ui(ui, |ui| { ui.selectable_value(interact_cursor, None, "-"); - for cursor in CursorIcon::ALL { + for cursor in output::ALL_CURSOR_ICONS { ui.selectable_value(interact_cursor, Some(cursor), format!("{cursor:?}")) .on_hover_cursor(cursor); } diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 9515726c211..cceda7caa4c 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -601,11 +601,11 @@ impl Widget for DragValue<'_> { .min_size(ui.spacing().interact_size); // TODO(emilk): find some more generic solution to `min_size` let cursor_icon = if value <= *range.start() { - CursorIcon::ResizeEast + CursorIcon::EResize } else if value < *range.end() { - CursorIcon::ResizeHorizontal + CursorIcon::RowResize } else { - CursorIcon::ResizeWest + CursorIcon::WResize }; let response = ui.add(button); diff --git a/crates/egui/src/widgets/hyperlink.rs b/crates/egui/src/widgets/hyperlink.rs index 989643304aa..e01218f5cca 100644 --- a/crates/egui/src/widgets/hyperlink.rs +++ b/crates/egui/src/widgets/hyperlink.rs @@ -65,7 +65,7 @@ impl Widget for Link { } if response.hovered() { - ui.ctx().set_cursor_icon(CursorIcon::PointingHand); + ui.ctx().set_cursor_icon(CursorIcon::Pointer); } } diff --git a/crates/egui_glow/Cargo.toml b/crates/egui_glow/Cargo.toml index 4a083611b2b..4f46d4a3717 100644 --- a/crates/egui_glow/Cargo.toml +++ b/crates/egui_glow/Cargo.toml @@ -58,7 +58,7 @@ profiling.workspace = true document-features = { workspace = true, optional = true } # Native: -winit = { workspace = true, optional = true, default-features = false, features = ["rwh_06"] } +winit = { workspace = true, optional = true, default-features = false } # Web: [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/examples/hello_world_simple/Cargo.toml b/examples/hello_world_simple/Cargo.toml index 954db50aa9d..2c3ab845c22 100644 --- a/examples/hello_world_simple/Cargo.toml +++ b/examples/hello_world_simple/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] eframe = { workspace = true, features = [ - "default", + "wgpu", "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO ] } env_logger = { workspace = true, features = ["auto-color", "humantime"] }