From 78bde54b8b439af81e380627f6aadfa7aea0e0e8 Mon Sep 17 00:00:00 2001 From: mvlabat Date: Sun, 28 Jul 2024 14:16:49 +0300 Subject: [PATCH] Fix repaint corner cases --- examples/side_panel.rs | 13 +++++++++---- src/systems.rs | 20 ++++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/examples/side_panel.rs b/examples/side_panel.rs index e129d51b7..14e9c56ef 100644 --- a/examples/side_panel.rs +++ b/examples/side_panel.rs @@ -1,5 +1,4 @@ -use bevy::{prelude::*, window::PrimaryWindow}; -use bevy::winit::WinitSettings; +use bevy::{prelude::*, window::PrimaryWindow, winit::WinitSettings}; use bevy_egui::{EguiContexts, EguiPlugin}; #[derive(Default, Resource)] @@ -38,10 +37,16 @@ fn ui_example_system( .resizable(true) .show(ctx, |ui| { ui.label("Left resizeable panel"); - if ui.add(egui::widgets::Button::new("A button").selected(!*is_last_selected)).clicked() { + if ui + .add(egui::widgets::Button::new("A button").selected(!*is_last_selected)) + .clicked() + { *is_last_selected = false; } - if ui.add(egui::widgets::Button::new("Another button").selected(*is_last_selected)).clicked() { + if ui + .add(egui::widgets::Button::new("Another button").selected(*is_last_selected)) + .clicked() + { *is_last_selected = true; } ui.allocate_rect(ui.available_rect_before_wrap(), egui::Sense::hover()); diff --git a/src/systems.rs b/src/systems.rs index 8f0827d6b..44cb35c7e 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -14,11 +14,12 @@ use bevy::{ ButtonState, }, log, - prelude::{Entity, EventReader, Query, Resource, Time}, + prelude::{Entity, EventReader, NonSend, Query, Resource, Time}, time::Real, window::{CursorMoved, RequestRedraw}, + winit::{EventLoopProxy, WakeUp}, }; -use std::marker::PhantomData; +use std::{marker::PhantomData, time::Duration}; #[allow(missing_docs)] #[derive(SystemParam)] @@ -474,6 +475,7 @@ pub fn process_output_system( mut egui_clipboard: bevy::ecs::system::ResMut, mut event: EventWriter, #[cfg(windows)] mut last_cursor_icon: Local>, + event_loop_proxy: Option>>, ) { let mut should_request_redraw = false; @@ -522,6 +524,20 @@ pub fn process_output_system( let needs_repaint = !context.render_output.is_empty(); should_request_redraw |= ctx.has_requested_repaint() && needs_repaint; + // The resource doesn't exist in the headless mode. + if let Some(event_loop_proxy) = &event_loop_proxy { + // A zero duration indicates that it's an outstanding redraw request, which gives Egui an + // opportunity to settle the effects of interactions with widgets. Such repaint requests + // are processed not immediately but on a next frame. In this case, we need to indicate to + // winit, that it needs to wake up next frame as well even if there are no inputs. + // + // TLDR: this solves repaint corner cases of `WinitSettings::desktop_app()`. + if let Some(Duration::ZERO) = ctx.viewport(|viewport| viewport.input.wants_repaint_after()) + { + let _ = event_loop_proxy.send_event(WakeUp); + } + } + #[cfg(feature = "open_url")] if let Some(egui::output::OpenUrl { url, new_tab }) = platform_output.open_url { let target = if new_tab {