Handle changes during RedrawRequested in the same frame

This commit is contained in:
Héctor Ramón Jiménez 2025-10-15 19:08:39 +02:00
parent 869891bbf0
commit d2e192042f
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
4 changed files with 98 additions and 44 deletions

View file

@ -774,7 +774,7 @@ async fn run_instance<P>(
continue;
};
let Some((id, window)) =
let Some((id, mut window)) =
window_manager.get_mut_alias(id)
else {
continue;
@ -819,20 +819,61 @@ async fn run_instance<P>(
let cursor = window.state.cursor();
let ui = user_interfaces
let mut interface = user_interfaces
.get_mut(&id)
.expect("Get user interface");
let draw_span = debug::draw(id);
let (ui_state, _) = ui.update(
slice::from_ref(&redraw_event),
cursor,
&mut window.renderer,
&mut clipboard,
&mut messages,
);
let mut change_count = 0;
ui.draw(
let state = loop {
let (state, _) = interface.update(
slice::from_ref(&redraw_event),
cursor,
&mut window.renderer,
&mut clipboard,
&mut messages,
);
change_count += 1;
if messages.is_empty()
&& !state.has_layout_changed()
{
break state;
}
if change_count >= 10 {
log::warn!(
"More than 10 consecutive RedrawRequested events \
produced layout invalidation"
);
break state;
}
let caches: FxHashMap<_, _> =
ManuallyDrop::into_inner(user_interfaces)
.into_iter()
.map(|(id, interface)| {
(id, interface.into_cache())
})
.collect();
update(&mut program, &mut runtime, &mut messages);
user_interfaces =
ManuallyDrop::new(build_user_interfaces(
&program,
&mut window_manager,
caches,
));
window = window_manager.get_mut(id).unwrap();
interface = user_interfaces.get_mut(&id).unwrap();
};
interface.draw(
&mut window.renderer,
window.state.theme(),
&renderer::Style {
@ -842,23 +883,24 @@ async fn run_instance<P>(
);
draw_span.finish();
runtime.broadcast(subscription::Event::Interaction {
window: id,
event: redraw_event,
status: core::event::Status::Ignored,
});
if let user_interface::State::Updated {
redraw_request,
input_method,
mouse_interaction,
} = ui_state
..
} = state
{
window.request_redraw(redraw_request);
window.request_input_method(input_method);
window.update_mouse(mouse_interaction);
}
runtime.broadcast(subscription::Event::Interaction {
window: id,
event: redraw_event,
status: core::event::Status::Ignored,
});
window.draw_preedit();
let present_span = debug::present(id);
@ -1071,32 +1113,14 @@ async fn run_instance<P>(
}
if !messages.is_empty() || uis_stale {
let cached_interfaces: FxHashMap<
window::Id,
user_interface::Cache,
> = ManuallyDrop::into_inner(user_interfaces)
.drain()
.map(|(id, ui)| (id, ui.into_cache()))
.collect();
let cached_interfaces: FxHashMap<_, _> =
ManuallyDrop::into_inner(user_interfaces)
.into_iter()
.map(|(id, ui)| (id, ui.into_cache()))
.collect();
update(&mut program, &mut runtime, &mut messages);
for (id, window) in window_manager.iter_mut() {
window.state.synchronize(
&program,
id,
&window.raw,
);
window.raw.request_redraw();
}
debug::theme_changed(|| {
window_manager.first().and_then(|window| {
theme::Base::palette(window.state.theme())
})
});
user_interfaces =
ManuallyDrop::new(build_user_interfaces(
&program,
@ -1606,6 +1630,17 @@ where
C: Compositor<Renderer = P::Renderer>,
P::Theme: theme::Base,
{
for (id, window) in window_manager.iter_mut() {
window.state.synchronize(program, id, &window.raw);
window.raw.request_redraw();
}
debug::theme_changed(|| {
window_manager
.first()
.and_then(|window| theme::Base::palette(window.state.theme()))
});
cached_user_interfaces
.drain()
.filter_map(|(id, cache)| {