1use std::{sync::Arc, time::Instant};
23use winit::{
4 event_loop::ActiveEventLoop,
5 window::{Window, WindowId},
6};
78use egui::ViewportId;
9#[cfg(feature = "accesskit")]
10use egui_winit::accesskit_winit;
1112/// Create an egui context, restoring it from storage if possible.
13pub fn create_egui_context(storage: Option<&dyn crate::Storage>) -> egui::Context {
14profiling::function_scope!();
1516pub const IS_DESKTOP: bool = cfg!(any(
17 target_os = "freebsd",
18 target_os = "linux",
19 target_os = "macos",
20 target_os = "openbsd",
21 target_os = "windows",
22 ));
2324let egui_ctx = egui::Context::default();
2526 egui_ctx.set_embed_viewports(!IS_DESKTOP);
2728 egui_ctx.options_mut(|o| {
29// eframe supports multi-pass (Context::request_discard).
30o.max_passes = 2.try_into().unwrap();
31 });
3233let memory = crate::native::epi_integration::load_egui_memory(storage).unwrap_or_default();
34 egui_ctx.memory_mut(|mem| *mem = memory);
3536 egui_ctx
37}
3839/// The custom even `eframe` uses with the [`winit`] event loop.
40#[derive(Debug)]
41pub enum UserEvent {
42/// A repaint is requested.
43RequestRepaint {
44/// What to repaint.
45viewport_id: ViewportId,
4647/// When to repaint.
48when: Instant,
4950/// What the cumulative pass number was when the repaint was _requested_.
51cumulative_pass_nr: u64,
52 },
5354/// A request related to [`accesskit`](https://accesskit.dev/).
55#[cfg(feature = "accesskit")]
56AccessKitActionRequest(accesskit_winit::Event),
57}
5859#[cfg(feature = "accesskit")]
60impl From<accesskit_winit::Event> for UserEvent {
61fn from(inner: accesskit_winit::Event) -> Self {
62Self::AccessKitActionRequest(inner)
63 }
64}
6566pub trait WinitApp {
67fn egui_ctx(&self) -> Option<&egui::Context>;
6869fn window(&self, window_id: WindowId) -> Option<Arc<Window>>;
7071fn window_id_from_viewport_id(&self, id: ViewportId) -> Option<WindowId>;
7273fn save_and_destroy(&mut self);
7475fn run_ui_and_paint(
76&mut self,
77 event_loop: &ActiveEventLoop,
78 window_id: WindowId,
79 ) -> crate::Result<EventResult>;
8081fn suspended(&mut self, event_loop: &ActiveEventLoop) -> crate::Result<EventResult>;
8283fn resumed(&mut self, event_loop: &ActiveEventLoop) -> crate::Result<EventResult>;
8485fn device_event(
86&mut self,
87 event_loop: &ActiveEventLoop,
88 device_id: winit::event::DeviceId,
89 event: winit::event::DeviceEvent,
90 ) -> crate::Result<EventResult>;
9192fn window_event(
93&mut self,
94 event_loop: &ActiveEventLoop,
95 window_id: WindowId,
96 event: winit::event::WindowEvent,
97 ) -> crate::Result<EventResult>;
9899#[cfg(feature = "accesskit")]
100fn on_accesskit_event(&mut self, event: accesskit_winit::Event) -> crate::Result<EventResult>;
101}
102103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum EventResult {
105 Wait,
106107/// Causes a synchronous repaint inside the event handler. This should only
108 /// be used in special situations if the window must be repainted while
109 /// handling a specific event. This occurs on Windows when handling resizes.
110 ///
111 /// `RepaintNow` creates a new frame synchronously, and should therefore
112 /// only be used for extremely urgent repaints.
113RepaintNow(WindowId),
114115/// Queues a repaint for once the event loop handles its next redraw. Exists
116 /// so that multiple input events can be handled in one frame. Does not
117 /// cause any delay like `RepaintNow`.
118RepaintNext(WindowId),
119120 RepaintAt(WindowId, Instant),
121122 Exit,
123}
124125#[cfg(feature = "accesskit")]
126pub(crate) fn on_accesskit_window_event(
127 egui_winit: &mut egui_winit::State,
128 window_id: WindowId,
129 event: &accesskit_winit::WindowEvent,
130) -> EventResult {
131match event {
132 accesskit_winit::WindowEvent::InitialTreeRequested => {
133 egui_winit.egui_ctx().enable_accesskit();
134// Because we can't provide the initial tree synchronously
135 // (because that would require the activation handler to access
136 // the same mutable state as the winit event handler), some
137 // AccessKit platform adapters will use a placeholder tree
138 // until we send the first tree update. To minimize the possible
139 // bad effects of that workaround, repaint and send the tree
140 // immediately.
141EventResult::RepaintNow(window_id)
142 }
143 accesskit_winit::WindowEvent::ActionRequested(request) => {
144 egui_winit.on_accesskit_action_request(request.clone());
145// As a form of user input, accessibility actions should cause
146 // a repaint, but not until the next regular frame.
147EventResult::RepaintNext(window_id)
148 }
149 accesskit_winit::WindowEvent::AccessibilityDeactivated => {
150 egui_winit.egui_ctx().disable_accesskit();
151// Disabling AccessKit support should have no visible effect,
152 // so there's no need to repaint.
153EventResult::Wait
154 }
155 }
156}