From 6884160bfeb57d46df2644b232da6e9efd20c2dd Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Fri, 4 Sep 2026 17:47:44 -0400 Subject: [PATCH] Make iris ask for the frame a resize needs `update` redrew everything when `resized` was set, but `needs_redraw` -- which is what decides whether to request a frame at all -- did not know about `resized`. A condition in one and not the other is a frame nobody asks for and a stale window. The two share one `needs_redraw_all` now. Latent on Wayland, because winit requests a redraw after a resize by itself; a resize changes neither the root nor any widget, so nothing else here would have asked. It stops being latent on Android, where the surface work will not have winit underneath it and every rotation and keyboard open is a resize. This is not a fix for the startup defect recorded in RUST.md, where the window keeps its pre-configure layout: that reproduces with this change in place, and the frame it needs is requested and drawn. Co-Authored-By: Claude Opus 5 --- core/src/ui/render_state.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 57e79a6..8bada33 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -52,7 +52,7 @@ impl UiRenderState { ); } let root = root.into(); - if self.root_changed(root) || self.resized { + if self.needs_redraw_all(root) { self.redraw_all(root, rsc); self.old_root = root.map(|r| r.id()); self.resized = false; @@ -218,12 +218,24 @@ impl UiRenderState { root.into().map(|r| r.id()) != self.old_root } + /// What `update` will redraw everything for. Named and shared with + /// `needs_redraw` rather than written out twice, because the two must + /// agree: `needs_redraw` is what asks for the frame that `update` would + /// draw, so a condition in one and not the other is a frame nobody + /// requests and a stale window. `resized` was missing from `needs_redraw`, + /// which is latent on Wayland only because winit asks for a redraw after a + /// resize by itself -- a resize changes neither the root nor any widget, + /// so nothing else here would have asked. + fn needs_redraw_all<'a>(&self, root: impl Into>) -> bool { + self.root_changed(root) || self.resized + } + pub fn needs_redraw<'a>( &self, root: impl Into>, widgets: &Widgets, ) -> bool { - self.root_changed(root) || widgets.has_updates() + self.needs_redraw_all(root) || widgets.has_updates() } pub fn active_widgets(&self) -> usize { @@ -317,3 +329,18 @@ impl Default for UiRenderState { Self::new() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a_resize_requests_a_frame_without_widget_changes() { + let widgets = Widgets::new(); + let mut state = UiRenderState::new(); + + assert!(!state.needs_redraw(None::<&StrongWidget>, &widgets)); + state.resize((800, 600)); + assert!(state.needs_redraw(None::<&StrongWidget>, &widgets)); + } +}