mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 05:10:03 -04:00
Upgrade winit to 0.30.2 (#4849)
* Closes https://github.com/emilk/egui/issues/1918 * Closes https://github.com/emilk/egui/issues/4437 * Closes https://github.com/emilk/egui/issues/4709 * [x] I have followed the instructions in the PR template Hiya, I need new winit for a specific fix for a android_native_actvity. There are already two PRs, but both don't seem to have a lot of movement, or are entirely complete: https://github.com/emilk/egui/pull/4466 Seems to have gone stale & is missing some bits. https://github.com/emilk/egui/pull/4702 Also seems stale (if less so), and is missing a refactor to run_on_demand. I also *think* the accesskit integration has a mistake and can't be enabled. I've marked them as a co-author on this as I started from this branch. (I think! Haven't done that on git before...). Sorry for the wall of text but just dumping some details / thoughts here: - There's an issue with creating child windows in winit 0.30.1 and up on macOS. The multiple_viewports, "create immediate viewport" example crashes on anything later 0.30.1, with a stack overflow in unsafe code. I've create [a winit issue](https://github.com/rust-windowing/winit/issues/3800), it *might* already be fixed in 0.31.0 but I can't test as 0.31 will likely require another refactoring. For now I have just pinned things to 0.30.0 exatly. - Winit has deprecated run_on_demand, instead requiring the ApplicationHandler interface. In 0.31.0 run_on_demand is removed. I've refactored both the integration and the WinitApp trait to follow this pattern. I've left user_events a bit more opaque, as it seems 0.31.0 is doing a rework of UserEvents too. - I've used the new lazy init approach for access kit from this branch https://github.com/mwcampbell/egui/tree/accesskit-new-lazy-init and marked Matt as co-author, thanks Matt! - There was very similair but not quite the same code for run_and_return and run_and_exit. I've merged them, but looking at the github issues graveyard it seems vey finnicky. I *hope* this is more robust than before but it's a bit scary. - when receiving new_events this also used to check the redraw timing dictionary. That doesn't seem necesarry so left this out, but that is a slight behaviour change? - I have reeneabled serial_windows on macOS. I wondered whether it was fixed after this PR and does seem to be! However, even before this PR it seems to work, so maybe winit has sorted things out before that... Windows also works fine now without the extra hack. - I've done a very basic test of AccessKit on Windows and screen reader seems ok but I'm really not knowleadgable enough to say whether it's all good or not. - I've tested cargo tests & all examples on Windows & macOS, and ran a basic Android app. Still, testing native platforms is wel... hard so if anyone can test linux / iOs / older mac versions / windows 10 would probably be a good idea! - For consistencys sake I've made all event like functions in WinitApp return a `Result<EventResult>`. There's quite a bit of Ok-wrapping now, maybe too annoying? Not sure. Thank you for having a look! # Tested on * [x] macOS * [x] Windows * [x] Wayland (thanks [SiebenCorgie](https://github.com/SiebenCorgie)) * [x] X11 (thanks [crumblingstatue](https://github.com/crumblingstatue)!, [SiebenCorgie](https://github.com/SiebenCorgie)) # TODO * [x] Fix "follow system theme" not working on initial startup (winit issue, pinning to 0.30.2 for now). * [x] Fix `request_repaint_after` --------- Co-authored-by: mwcampbell <mattcampbell@pobox.com> Co-authored-by: j-axa <josef.axa@gmail.com> Co-authored-by: DataTriny <datatriny@gmail.com> Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -1,35 +1,28 @@
|
||||
use std::{cell::RefCell, time::Instant};
|
||||
|
||||
use winit::event_loop::{EventLoop, EventLoopBuilder};
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
|
||||
window::WindowId,
|
||||
};
|
||||
|
||||
use ahash::HashMap;
|
||||
|
||||
use super::winit_integration::{UserEvent, WinitApp};
|
||||
use crate::{
|
||||
epi,
|
||||
native::winit_integration::{short_event_description, EventResult},
|
||||
native::{event_loop_context, winit_integration::EventResult},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::winit_integration::{UserEvent, WinitApp};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fn create_event_loop_builder(
|
||||
native_options: &mut epi::NativeOptions,
|
||||
) -> EventLoopBuilder<UserEvent> {
|
||||
crate::profile_function!();
|
||||
let mut event_loop_builder = winit::event_loop::EventLoopBuilder::with_user_event();
|
||||
|
||||
if let Some(hook) = std::mem::take(&mut native_options.event_loop_builder) {
|
||||
hook(&mut event_loop_builder);
|
||||
}
|
||||
|
||||
event_loop_builder
|
||||
}
|
||||
|
||||
fn create_event_loop(native_options: &mut epi::NativeOptions) -> Result<EventLoop<UserEvent>> {
|
||||
crate::profile_function!();
|
||||
let mut builder = create_event_loop_builder(native_options);
|
||||
let mut builder = winit::event_loop::EventLoop::with_user_event();
|
||||
|
||||
if let Some(hook) = std::mem::take(&mut native_options.event_loop_builder) {
|
||||
hook(&mut builder);
|
||||
}
|
||||
|
||||
crate::profile_scope!("EventLoopBuilder::build");
|
||||
Ok(builder.build()?)
|
||||
@@ -59,306 +52,126 @@ fn with_event_loop<R>(
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
fn run_and_return(event_loop: &mut EventLoop<UserEvent>, mut winit_app: impl WinitApp) -> Result {
|
||||
use winit::{event_loop::ControlFlow, platform::run_on_demand::EventLoopExtRunOnDemand};
|
||||
/// Wraps a [`WinitApp`] to implement [`ApplicationHandler`]. This handles redrawing, exit states, and
|
||||
/// some events, but otherwise forwards events to the [`WinitApp`].
|
||||
struct WinitAppWrapper<T: WinitApp> {
|
||||
windows_next_repaint_times: HashMap<WindowId, Instant>,
|
||||
winit_app: T,
|
||||
return_result: Result<(), crate::Error>,
|
||||
run_and_return: bool,
|
||||
}
|
||||
|
||||
log::trace!("Entering the winit event loop (run_on_demand)…");
|
||||
|
||||
// When to repaint what window
|
||||
let mut windows_next_repaint_times = HashMap::default();
|
||||
|
||||
let mut returned_result = Ok(());
|
||||
|
||||
event_loop.run_on_demand(|event, event_loop_window_target| {
|
||||
crate::profile_scope!("winit_event", short_event_description(&event));
|
||||
|
||||
log::trace!("winit event: {event:?}");
|
||||
|
||||
if matches!(event, winit::event::Event::AboutToWait) {
|
||||
return; // early-out: don't trigger another wait
|
||||
impl<T: WinitApp> WinitAppWrapper<T> {
|
||||
fn new(winit_app: T, run_and_return: bool) -> Self {
|
||||
Self {
|
||||
windows_next_repaint_times: HashMap::default(),
|
||||
winit_app,
|
||||
return_result: Ok(()),
|
||||
run_and_return,
|
||||
}
|
||||
}
|
||||
|
||||
let event_result = match &event {
|
||||
winit::event::Event::LoopExiting => {
|
||||
// On Mac, Cmd-Q we get here and then `run_on_demand` doesn't return (despite its name),
|
||||
// so we need to save state now:
|
||||
log::debug!("Received Event::LoopExiting - saving app state…");
|
||||
winit_app.save_and_destroy();
|
||||
return;
|
||||
}
|
||||
fn handle_event_result(
|
||||
&mut self,
|
||||
event_loop: &ActiveEventLoop,
|
||||
event_result: Result<EventResult>,
|
||||
) {
|
||||
let mut exit = false;
|
||||
|
||||
winit::event::Event::WindowEvent {
|
||||
event: winit::event::WindowEvent::RedrawRequested,
|
||||
window_id,
|
||||
} => {
|
||||
windows_next_repaint_times.remove(window_id);
|
||||
winit_app.run_ui_and_paint(event_loop_window_target, *window_id)
|
||||
}
|
||||
log::trace!("event_result: {event_result:?}");
|
||||
|
||||
winit::event::Event::UserEvent(UserEvent::RequestRepaint {
|
||||
when,
|
||||
frame_nr,
|
||||
viewport_id,
|
||||
}) => {
|
||||
let current_frame_nr = winit_app.frame_nr(*viewport_id);
|
||||
if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 {
|
||||
log::trace!("UserEvent::RequestRepaint scheduling repaint at {when:?}");
|
||||
if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) {
|
||||
EventResult::RepaintAt(window_id, *when)
|
||||
let combined_result = event_result.and_then(|event_result| {
|
||||
match event_result {
|
||||
EventResult::Wait => {
|
||||
event_loop.set_control_flow(ControlFlow::Wait);
|
||||
Ok(event_result)
|
||||
}
|
||||
EventResult::RepaintNow(window_id) => {
|
||||
log::trace!("RepaintNow of {window_id:?}",);
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
// Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280
|
||||
self.windows_next_repaint_times.remove(&window_id);
|
||||
self.winit_app.run_ui_and_paint(event_loop, window_id)
|
||||
} else {
|
||||
EventResult::Wait
|
||||
// Fix for https://github.com/emilk/egui/issues/2425
|
||||
self.windows_next_repaint_times
|
||||
.insert(window_id, Instant::now());
|
||||
Ok(event_result)
|
||||
}
|
||||
} else {
|
||||
log::trace!("Got outdated UserEvent::RequestRepaint");
|
||||
EventResult::Wait // old request - we've already repainted
|
||||
}
|
||||
}
|
||||
|
||||
winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
|
||||
..
|
||||
}) => {
|
||||
log::trace!("Woke up to check next_repaint_time");
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
event => match winit_app.on_event(event_loop_window_target, event) {
|
||||
Ok(event_result) => {
|
||||
log::trace!("event_result: {event_result:?}");
|
||||
event_result
|
||||
EventResult::RepaintNext(window_id) => {
|
||||
log::trace!("RepaintNext of {window_id:?}",);
|
||||
self.windows_next_repaint_times
|
||||
.insert(window_id, Instant::now());
|
||||
Ok(event_result)
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Exiting because of error: {err} during event {event:?}");
|
||||
returned_result = Err(err);
|
||||
EventResult::Exit
|
||||
EventResult::RepaintAt(window_id, repaint_time) => {
|
||||
self.windows_next_repaint_times.insert(
|
||||
window_id,
|
||||
self.windows_next_repaint_times
|
||||
.get(&window_id)
|
||||
.map_or(repaint_time, |last| (*last).min(repaint_time)),
|
||||
);
|
||||
Ok(event_result)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match event_result {
|
||||
EventResult::Wait => {
|
||||
event_loop_window_target.set_control_flow(ControlFlow::Wait);
|
||||
}
|
||||
EventResult::RepaintNow(window_id) => {
|
||||
log::trace!(
|
||||
"RepaintNow of {window_id:?} caused by {}",
|
||||
short_event_description(&event)
|
||||
);
|
||||
if cfg!(target_os = "windows") {
|
||||
// Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280
|
||||
windows_next_repaint_times.remove(&window_id);
|
||||
|
||||
winit_app.run_ui_and_paint(event_loop_window_target, window_id);
|
||||
} else {
|
||||
// Fix for https://github.com/emilk/egui/issues/2425
|
||||
windows_next_repaint_times.insert(window_id, Instant::now());
|
||||
EventResult::Exit => {
|
||||
exit = true;
|
||||
Ok(event_result)
|
||||
}
|
||||
}
|
||||
EventResult::RepaintNext(window_id) => {
|
||||
log::trace!(
|
||||
"RepaintNext of {window_id:?} caused by {}",
|
||||
short_event_description(&event)
|
||||
);
|
||||
windows_next_repaint_times.insert(window_id, Instant::now());
|
||||
}
|
||||
EventResult::RepaintAt(window_id, repaint_time) => {
|
||||
windows_next_repaint_times.insert(
|
||||
window_id,
|
||||
windows_next_repaint_times
|
||||
.get(&window_id)
|
||||
.map_or(repaint_time, |last| (*last).min(repaint_time)),
|
||||
);
|
||||
}
|
||||
EventResult::Exit => {
|
||||
log::debug!("Asking to exit event loop…");
|
||||
winit_app.save_and_destroy();
|
||||
event_loop_window_target.exit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_repaint_time = windows_next_repaint_times.values().min().copied();
|
||||
|
||||
windows_next_repaint_times.retain(|window_id, repaint_time| {
|
||||
if Instant::now() < *repaint_time {
|
||||
return true; // not yet ready
|
||||
};
|
||||
|
||||
next_repaint_time = None;
|
||||
event_loop_window_target.set_control_flow(ControlFlow::Poll);
|
||||
|
||||
if let Some(window) = winit_app.window(*window_id) {
|
||||
log::trace!("request_redraw for {window_id:?}");
|
||||
let is_minimized = window.is_minimized().unwrap_or(false);
|
||||
if is_minimized {
|
||||
false
|
||||
} else {
|
||||
window.request_redraw();
|
||||
true
|
||||
}
|
||||
} else {
|
||||
log::trace!("No window found for {window_id:?}");
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(next_repaint_time) = next_repaint_time {
|
||||
event_loop_window_target.set_control_flow(ControlFlow::WaitUntil(next_repaint_time));
|
||||
};
|
||||
})?;
|
||||
|
||||
log::debug!("eframe window closed");
|
||||
|
||||
drop(winit_app);
|
||||
|
||||
// On Windows this clears out events so that we can later create another window.
|
||||
// See https://github.com/emilk/egui/pull/1889 for details.
|
||||
//
|
||||
// Note that this approach may cause issues on macOS (emilk/egui#2768); therefore,
|
||||
// we only apply this approach on Windows to minimize the affect.
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
event_loop
|
||||
.run_on_demand(|_, event_loop_window_target| {
|
||||
event_loop_window_target.exit();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
returned_result
|
||||
}
|
||||
|
||||
fn run_and_exit(
|
||||
event_loop: EventLoop<UserEvent>,
|
||||
mut winit_app: impl WinitApp + 'static,
|
||||
) -> Result {
|
||||
use winit::event_loop::ControlFlow;
|
||||
log::trace!("Entering the winit event loop (run)…");
|
||||
|
||||
// When to repaint what window
|
||||
let mut windows_next_repaint_times = HashMap::default();
|
||||
|
||||
event_loop.run(move |event, event_loop_window_target| {
|
||||
crate::profile_scope!("winit_event", short_event_description(&event));
|
||||
|
||||
log::trace!("winit event: {event:?}");
|
||||
|
||||
if matches!(event, winit::event::Event::AboutToWait) {
|
||||
return; // early-out: don't trigger another wait
|
||||
}
|
||||
|
||||
let event_result = match &event {
|
||||
winit::event::Event::LoopExiting => {
|
||||
log::debug!("Received Event::LoopExiting");
|
||||
EventResult::Exit
|
||||
}
|
||||
|
||||
winit::event::Event::WindowEvent {
|
||||
event: winit::event::WindowEvent::RedrawRequested,
|
||||
window_id,
|
||||
} => {
|
||||
windows_next_repaint_times.remove(window_id);
|
||||
winit_app.run_ui_and_paint(event_loop_window_target, *window_id)
|
||||
}
|
||||
|
||||
winit::event::Event::UserEvent(UserEvent::RequestRepaint {
|
||||
when,
|
||||
frame_nr,
|
||||
viewport_id,
|
||||
}) => {
|
||||
let current_frame_nr = winit_app.frame_nr(*viewport_id);
|
||||
if current_frame_nr == *frame_nr || current_frame_nr == *frame_nr + 1 {
|
||||
if let Some(window_id) = winit_app.window_id_from_viewport_id(*viewport_id) {
|
||||
EventResult::RepaintAt(window_id, *when)
|
||||
} else {
|
||||
EventResult::Wait
|
||||
}
|
||||
} else {
|
||||
log::trace!("Got outdated UserEvent::RequestRepaint");
|
||||
EventResult::Wait // old request - we've already repainted
|
||||
}
|
||||
}
|
||||
|
||||
winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
|
||||
..
|
||||
}) => {
|
||||
log::trace!("Woke up to check next_repaint_time");
|
||||
EventResult::Wait
|
||||
}
|
||||
|
||||
event => match winit_app.on_event(event_loop_window_target, event) {
|
||||
Ok(event_result) => {
|
||||
log::trace!("event_result: {event_result:?}");
|
||||
event_result
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("eframe encountered a fatal error: {err} during event {event:?}");
|
||||
}
|
||||
},
|
||||
if let Err(err) = combined_result {
|
||||
log::error!("Exiting because of error: {err}");
|
||||
exit = true;
|
||||
self.return_result = Err(err);
|
||||
};
|
||||
|
||||
match event_result {
|
||||
EventResult::Wait => {
|
||||
event_loop_window_target.set_control_flow(ControlFlow::Wait);
|
||||
}
|
||||
EventResult::RepaintNow(window_id) => {
|
||||
log::trace!("RepaintNow caused by {}", short_event_description(&event));
|
||||
if cfg!(target_os = "windows") {
|
||||
// Fix flickering on Windows, see https://github.com/emilk/egui/pull/2280
|
||||
windows_next_repaint_times.remove(&window_id);
|
||||
|
||||
winit_app.run_ui_and_paint(event_loop_window_target, window_id);
|
||||
} else {
|
||||
// Fix for https://github.com/emilk/egui/issues/2425
|
||||
windows_next_repaint_times.insert(window_id, Instant::now());
|
||||
}
|
||||
}
|
||||
EventResult::RepaintNext(window_id) => {
|
||||
log::trace!("RepaintNext caused by {}", short_event_description(&event));
|
||||
windows_next_repaint_times.insert(window_id, Instant::now());
|
||||
}
|
||||
EventResult::RepaintAt(window_id, repaint_time) => {
|
||||
windows_next_repaint_times.insert(
|
||||
window_id,
|
||||
windows_next_repaint_times
|
||||
.get(&window_id)
|
||||
.map_or(repaint_time, |last| (*last).min(repaint_time)),
|
||||
);
|
||||
}
|
||||
EventResult::Exit => {
|
||||
if exit {
|
||||
if self.run_and_return {
|
||||
log::debug!("Asking to exit event loop…");
|
||||
event_loop.exit();
|
||||
} else {
|
||||
log::debug!("Quitting - saving app state…");
|
||||
winit_app.save_and_destroy();
|
||||
self.winit_app.save_and_destroy();
|
||||
|
||||
log::debug!("Exiting with return code 0");
|
||||
|
||||
#[allow(clippy::exit)]
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_repaint_time = windows_next_repaint_times.values().min().copied();
|
||||
self.check_redraw_requests(event_loop);
|
||||
}
|
||||
|
||||
windows_next_repaint_times.retain(|window_id, repaint_time| {
|
||||
if Instant::now() < *repaint_time {
|
||||
return true; // not yet ready
|
||||
}
|
||||
fn check_redraw_requests(&mut self, event_loop: &ActiveEventLoop) {
|
||||
let mut next_repaint_time = self.windows_next_repaint_times.values().min().copied();
|
||||
|
||||
next_repaint_time = None;
|
||||
event_loop_window_target.set_control_flow(ControlFlow::Poll);
|
||||
self.windows_next_repaint_times
|
||||
.retain(|window_id, repaint_time| {
|
||||
if Instant::now() < *repaint_time {
|
||||
return true; // not yet ready
|
||||
};
|
||||
|
||||
if let Some(window) = winit_app.window(*window_id) {
|
||||
log::trace!("request_redraw for {window_id:?}");
|
||||
let is_minimized = window.is_minimized().unwrap_or(false);
|
||||
if is_minimized {
|
||||
false
|
||||
next_repaint_time = None;
|
||||
event_loop.set_control_flow(ControlFlow::Poll);
|
||||
|
||||
if let Some(window) = self.winit_app.window(*window_id) {
|
||||
log::trace!("request_redraw for {window_id:?}");
|
||||
let is_minimized = window.is_minimized().unwrap_or(false);
|
||||
if is_minimized {
|
||||
false
|
||||
} else {
|
||||
window.request_redraw();
|
||||
true
|
||||
}
|
||||
} else {
|
||||
window.request_redraw();
|
||||
true
|
||||
log::trace!("No window found for {window_id:?}");
|
||||
false
|
||||
}
|
||||
} else {
|
||||
log::trace!("No window found for {window_id:?}");
|
||||
false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if let Some(next_repaint_time) = next_repaint_time {
|
||||
// WaitUntil seems to not work on iOS
|
||||
@@ -371,12 +184,144 @@ fn run_and_exit(
|
||||
.map(|window| window.request_redraw())
|
||||
});
|
||||
|
||||
event_loop_window_target.set_control_flow(ControlFlow::WaitUntil(next_repaint_time));
|
||||
event_loop.set_control_flow(ControlFlow::WaitUntil(next_repaint_time));
|
||||
};
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WinitApp> ApplicationHandler<UserEvent> for WinitAppWrapper<T> {
|
||||
fn suspended(&mut self, event_loop: &ActiveEventLoop) {
|
||||
crate::profile_function!("Event::Suspended");
|
||||
|
||||
event_loop_context::with_event_loop_context(event_loop, move || {
|
||||
let event_result = self.winit_app.suspended(event_loop);
|
||||
self.handle_event_result(event_loop, event_result);
|
||||
});
|
||||
}
|
||||
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
crate::profile_function!("Event::Resumed");
|
||||
|
||||
// Nb: Make sure this guard is dropped after this function returns.
|
||||
event_loop_context::with_event_loop_context(event_loop, move || {
|
||||
let event_result = self.winit_app.resumed(event_loop);
|
||||
self.handle_event_result(event_loop, event_result);
|
||||
});
|
||||
}
|
||||
|
||||
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: winit::event::DeviceEvent,
|
||||
) {
|
||||
crate::profile_function!(egui_winit::short_device_event_description(&event));
|
||||
|
||||
// Nb: Make sure this guard is dropped after this function returns.
|
||||
event_loop_context::with_event_loop_context(event_loop, move || {
|
||||
let event_result = self.winit_app.device_event(event_loop, device_id, event);
|
||||
self.handle_event_result(event_loop, event_result);
|
||||
});
|
||||
}
|
||||
|
||||
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) {
|
||||
crate::profile_function!(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,
|
||||
frame_nr,
|
||||
viewport_id,
|
||||
} => {
|
||||
let current_frame_nr = self.winit_app.frame_nr(viewport_id);
|
||||
if current_frame_nr == frame_nr || current_frame_nr == frame_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) {
|
||||
if let winit::event::StartCause::ResumeTimeReached { .. } = cause {
|
||||
log::trace!("Woke up to check next_repaint_time");
|
||||
}
|
||||
|
||||
self.check_redraw_requests(event_loop);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &ActiveEventLoop,
|
||||
window_id: WindowId,
|
||||
event: winit::event::WindowEvent,
|
||||
) {
|
||||
crate::profile_function!(egui_winit::short_window_event_description(&event));
|
||||
|
||||
// Nb: Make sure this guard is dropped after this function returns.
|
||||
event_loop_context::with_event_loop_context(event_loop, move || {
|
||||
let event_result = match event {
|
||||
winit::event::WindowEvent::RedrawRequested => {
|
||||
self.windows_next_repaint_times.remove(&window_id);
|
||||
self.winit_app.run_ui_and_paint(event_loop, window_id)
|
||||
}
|
||||
_ => self.winit_app.window_event(event_loop, window_id, event),
|
||||
};
|
||||
|
||||
self.handle_event_result(event_loop, event_result);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
fn run_and_return(event_loop: &mut EventLoop<UserEvent>, winit_app: impl WinitApp) -> Result {
|
||||
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
|
||||
|
||||
log::trace!("Entering the winit event loop (run_app_on_demand)…");
|
||||
|
||||
let mut app = WinitAppWrapper::new(winit_app, true);
|
||||
event_loop.run_app_on_demand(&mut app)?;
|
||||
log::debug!("eframe window closed");
|
||||
app.return_result
|
||||
}
|
||||
|
||||
fn run_and_exit(event_loop: EventLoop<UserEvent>, winit_app: impl WinitApp + 'static) -> 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)?;
|
||||
|
||||
log::debug!("winit event loop unexpectedly returned");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user