1
0
Fork 0
forked from wry/wry

Fallback layout animations by motion group

This commit is contained in:
atagen 2026-05-21 18:46:10 +10:00
parent a516b2e721
commit 4ee2c324e1
3 changed files with 115 additions and 27 deletions

View file

@ -5,7 +5,9 @@ use {
animation::{
AnimationCurve, AnimationState, AnimationTick, RetainedExitLayer, RetainedToplevel,
expand_damage_rect,
multiphase::{MultiphaseRequest, MultiphaseWindow, plan_no_overlap},
multiphase::{
MultiphaseRequest, MultiphaseWindow, partition_motion_groups, plan_no_overlap,
},
spawn_in_start_rect,
},
async_engine::{AsyncEngine, SpawnedFuture},
@ -1586,51 +1588,59 @@ impl State {
return;
};
let now = self.now_nsec();
if self.start_multiphase_layout_animation(&candidates, now) {
return;
}
for candidate in candidates {
self.start_layout_animation_candidate(candidate, now);
}
}
fn start_multiphase_layout_animation(
self: &Rc<Self>,
candidates: &[LayoutAnimationCandidate],
now_nsec: u64,
) -> bool {
if candidates.len() < 2 {
return false;
}
let windows: Vec<_> = candidates
.iter()
.map(|candidate| MultiphaseWindow {
node_id: candidate.node_id,
from: self
.animations
.visual_rect(candidate.node_id, candidate.old, now_nsec),
.visual_rect(candidate.node_id, candidate.old, now),
to: candidate.new,
})
.collect();
let Some(first) = windows.first() else {
for group in partition_motion_groups(&windows) {
if self.start_multiphase_layout_animation(&candidates, &windows, &group, now) {
continue;
}
for idx in group {
self.start_layout_animation_candidate(candidates[idx].clone(), now);
}
}
}
fn start_multiphase_layout_animation(
self: &Rc<Self>,
candidates: &[LayoutAnimationCandidate],
windows: &[MultiphaseWindow],
group: &[usize],
now_nsec: u64,
) -> bool {
if group.len() < 2 {
return false;
}
let request_windows: Vec<_> = group.iter().map(|&idx| windows[idx]).collect();
let Some(first) = request_windows.first() else {
return false;
};
let mut bounds = first.from.union(first.to);
for window in &windows[1..] {
for window in &request_windows[1..] {
bounds = bounds.union(window.from).union(window.to);
}
let Ok(plan) = plan_no_overlap(&MultiphaseRequest { bounds, windows }) else {
let Ok(plan) = plan_no_overlap(&MultiphaseRequest {
bounds,
windows: request_windows,
}) else {
return false;
};
if plan.phases.is_empty() {
return false;
}
let mut entries = vec![];
for candidate in candidates {
let mut current =
self.animations
.visual_rect(candidate.node_id, candidate.old, now_nsec);
let mut damage = current.union(candidate.new);
for &idx in group {
let candidate = &candidates[idx];
let window = windows[idx];
let mut current = window.from;
let mut damage = current.union(window.to);
let mut phases = vec![];
for phase in &plan.phases {
match phase
@ -1646,7 +1656,7 @@ impl State {
None => phases.push((current, current)),
}
}
if current != candidate.new {
if current != window.to {
return false;
}
let retained = self