mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Fix crash when parent viewport is hidden (#8226)
Hey, this is my fist PR to fix the bug I just published #8225 I hope it helps. I tested the fix with wgpu but not glow. I must say that I am not very happy to have very similar function is_viewport_or_descendant_visible in both case. Let me know if you would prefer that I try to factorize it. * Closes <https://github.com/emilk/egui/issues/8225> * [X] I have followed the instructions in the PR template --------- Co-authored-by: Matthieu Casanova <public@kpouer.com>
This commit is contained in:
committed by
GitHub
parent
2c8c27c5df
commit
467c5b84f0
@@ -558,7 +558,7 @@ impl GlowWinitRunning<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
let (raw_input, viewport_ui_cb, is_visible) = {
|
||||
let (raw_input, viewport_ui_cb, is_visible, run_ui) = {
|
||||
let mut glutin = self.glutin.borrow_mut();
|
||||
let egui_ctx = glutin.egui_ctx.clone();
|
||||
let Some(viewport) = glutin.viewports.get_mut(&viewport_id) else {
|
||||
@@ -577,6 +577,9 @@ impl GlowWinitRunning<'_> {
|
||||
let mut raw_input = egui_winit.take_egui_input(window);
|
||||
let viewport_ui_cb = viewport.viewport_ui_cb.clone();
|
||||
|
||||
let run_ui =
|
||||
is_visible || is_viewport_or_descendant_visible(&glutin.viewports, viewport_id);
|
||||
|
||||
self.integration.pre_update();
|
||||
|
||||
raw_input.time = Some(self.integration.beginning.elapsed().as_secs_f64());
|
||||
@@ -586,7 +589,7 @@ impl GlowWinitRunning<'_> {
|
||||
.map(|(id, viewport)| (*id, viewport.info.clone()))
|
||||
.collect();
|
||||
|
||||
(raw_input, viewport_ui_cb, is_visible)
|
||||
(raw_input, viewport_ui_cb, is_visible, run_ui)
|
||||
};
|
||||
|
||||
// HACK: In order to get the right clear_color, the system theme needs to be set, which
|
||||
@@ -641,7 +644,7 @@ impl GlowWinitRunning<'_> {
|
||||
self.app.as_mut(),
|
||||
viewport_ui_cb.as_deref(),
|
||||
raw_input,
|
||||
is_visible,
|
||||
run_ui,
|
||||
);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
@@ -1462,6 +1465,28 @@ fn initialize_or_update_viewport(
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this viewport, or any of its (transitive) descendant viewports, visible?
|
||||
///
|
||||
/// Immediate viewports are rendered inline while their parent's UI runs, so even
|
||||
/// if this viewport's window is occluded or minimized we must still run its UI to
|
||||
/// give any visible descendant a chance to be painted.
|
||||
fn is_viewport_or_descendant_visible(
|
||||
viewports: &OrderedViewportIdMap<Viewport>,
|
||||
viewport_id: ViewportId,
|
||||
) -> bool {
|
||||
let Some(viewport) = viewports.get(&viewport_id) else {
|
||||
return false;
|
||||
};
|
||||
if viewport.info.visible().unwrap_or(true) {
|
||||
return true;
|
||||
}
|
||||
viewports.values().any(|child| {
|
||||
child.ids.parent == viewport_id
|
||||
&& child.ids.this != viewport_id // ROOT is its own parent; avoid self-recursion.
|
||||
&& is_viewport_or_descendant_visible(viewports, child.ids.this)
|
||||
})
|
||||
}
|
||||
|
||||
/// This is called (via a callback) by user code to render immediate viewports,
|
||||
/// i.e. viewport that are directly nested inside a parent viewport.
|
||||
fn render_immediate_viewport(
|
||||
|
||||
@@ -601,7 +601,7 @@ impl WgpuWinitRunning<'_> {
|
||||
let mut frame_timer = crate::stopwatch::Stopwatch::new();
|
||||
frame_timer.start();
|
||||
|
||||
let (viewport_ui_cb, raw_input, is_visible) = {
|
||||
let (viewport_ui_cb, raw_input, is_visible, run_ui) = {
|
||||
profiling::scope!("Prepare");
|
||||
let mut shared_lock = shared.borrow_mut();
|
||||
|
||||
@@ -657,6 +657,8 @@ impl WgpuWinitRunning<'_> {
|
||||
};
|
||||
let mut raw_input = egui_winit.take_egui_input(window);
|
||||
|
||||
let run_ui = is_visible || is_viewport_or_descendant_visible(viewports, viewport_id);
|
||||
|
||||
integration.pre_update();
|
||||
|
||||
raw_input.time = Some(integration.beginning.elapsed().as_secs_f64());
|
||||
@@ -667,19 +669,15 @@ impl WgpuWinitRunning<'_> {
|
||||
|
||||
painter.handle_screenshots(&mut raw_input.events);
|
||||
|
||||
(viewport_ui_cb, raw_input, is_visible)
|
||||
(viewport_ui_cb, raw_input, is_visible, run_ui)
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// Runs the update, which could call immediate viewports,
|
||||
// so make sure we hold no locks here!
|
||||
let full_output = integration.update(
|
||||
app.as_mut(),
|
||||
viewport_ui_cb.as_deref(),
|
||||
raw_input,
|
||||
is_visible,
|
||||
);
|
||||
let full_output =
|
||||
integration.update(app.as_mut(), viewport_ui_cb.as_deref(), raw_input, run_ui);
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
@@ -1026,6 +1024,25 @@ fn create_window(
|
||||
Ok((window, viewport_builder))
|
||||
}
|
||||
|
||||
/// Is this viewport, or any of its (transitive) descendant viewports, visible?
|
||||
///
|
||||
/// Immediate viewports are rendered inline while their parent's UI runs, so even
|
||||
/// if this viewport's window is occluded or minimized we must still run its UI to
|
||||
/// give any visible descendant a chance to be painted.
|
||||
fn is_viewport_or_descendant_visible(viewports: &Viewports, viewport_id: ViewportId) -> bool {
|
||||
let Some(viewport) = viewports.get(&viewport_id) else {
|
||||
return false;
|
||||
};
|
||||
if viewport.info.visible().unwrap_or(true) {
|
||||
return true;
|
||||
}
|
||||
viewports.values().any(|child| {
|
||||
child.ids.parent == viewport_id
|
||||
&& child.ids.this != viewport_id
|
||||
&& is_viewport_or_descendant_visible(viewports, child.ids.this)
|
||||
})
|
||||
}
|
||||
|
||||
fn render_immediate_viewport(
|
||||
beginning: Instant,
|
||||
shared: &RefCell<SharedState>,
|
||||
|
||||
Reference in New Issue
Block a user