1
0
Fork 0
forked from wry/wry

Add linear tiled window animations

This commit is contained in:
atagen 2026-05-21 15:20:46 +10:00
parent a29937ebe8
commit 3540cdc4be
17 changed files with 913 additions and 64 deletions

View file

@ -2,6 +2,7 @@ use {
crate::{
acceptor::Acceptor,
allocator::BufferObject,
animation::{AnimationCurve, AnimationState, AnimationTick, expand_damage_rect},
async_engine::{AsyncEngine, SpawnedFuture},
backend::{
Backend, BackendConnectorState, BackendConnectorStateSerials, BackendDrmDevice,
@ -102,11 +103,10 @@ use {
time::Time,
tree::{
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode,
TearingMode, TileState, ToplevelData, ToplevelIdentifier, ToplevelNode,
ToplevelNodeBase, Transform, VrrMode, WorkspaceDisplayOrder, WorkspaceNode,
WorkspaceNodeId,
WsMoveConfig, generic_node_visitor, move_ws_to_output,
FoundNode, LatchListener, Node, NodeId, NodeIds, NodeVisitorBase, OutputNode,
PlaceholderNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
ToplevelNode, ToplevelNodeBase, Transform, VrrMode, WorkspaceDisplayOrder,
WorkspaceNode, WorkspaceNodeId, WsMoveConfig, generic_node_visitor, move_ws_to_output,
},
udmabuf::UdmabufHolder,
utils::{
@ -264,6 +264,10 @@ pub struct State {
pub cpu_worker: Rc<CpuWorker>,
pub ui_drag_enabled: Cell<bool>,
pub ui_drag_threshold_squared: Cell<i32>,
pub animations: AnimationState,
pub layout_animations_requested: Cell<bool>,
pub layout_animations_active: Cell<bool>,
pub suppress_animations_for_next_layout: Cell<bool>,
pub toplevels: CopyHashMap<ToplevelIdentifier, Weak<dyn ToplevelNode>>,
pub const_40hz_latch: EventSource<dyn LatchListener>,
pub tray_item_ids: TrayItemIds,
@ -1115,6 +1119,10 @@ impl State {
self.pending_screencast_reallocs_or_reconfigures.clear();
self.pending_placeholder_render_textures.clear();
self.pending_container_tab_render_textures.clear();
self.animations.clear();
self.layout_animations_requested.set(false);
self.layout_animations_active.set(false);
self.suppress_animations_for_next_layout.set(false);
self.render_ctx_watchers.clear();
self.workspace_watchers.clear();
self.toplevel_lists.clear();
@ -1461,6 +1469,88 @@ impl State {
self.eng.now().msec()
}
pub fn queue_tiled_animation(self: &Rc<Self>, node_id: NodeId, old: Rect, new: Rect) {
if !self.animations.enabled.get()
|| !self.layout_animations_active.get()
|| self.suppress_animations_for_next_layout.get()
{
return;
}
let (old_output, old_scale) = {
let (x, y) = old.center();
let (output, _, _) = self.find_closest_output(x, y);
(output.id, output.global.persistent.scale.get())
};
let (new_output, new_scale) = {
let (x, y) = new.center();
let (output, _, _) = self.find_closest_output(x, y);
(output.id, output.global.persistent.scale.get())
};
if old_output != new_output || old_scale != new_scale {
return;
}
let now = self.now_nsec();
let started = self.animations.set_target(
node_id,
old,
new,
now,
self.animations.duration_ms.get(),
self.animations.curve.get(),
);
if started {
self.damage(expand_damage_rect(
old.union(new),
self.theme.sizes.border_width.get().max(0),
));
self.ensure_animation_tick();
}
}
pub fn set_animations_enabled(&self, enabled: bool) {
if self.animations.enabled.replace(enabled) && !enabled {
self.animations.clear();
self.damage(self.root.extents.get());
}
}
pub fn set_animation_duration_ms(&self, duration_ms: u32) {
self.animations.duration_ms.set(duration_ms);
}
pub fn set_animation_curve(&self, curve: u32) {
self.animations
.curve
.set(AnimationCurve::from_config(curve));
}
pub fn with_layout_animations<T>(&self, f: impl FnOnce() -> T) -> T {
let prev_requested = self.layout_animations_requested.replace(true);
let prev_active = self.layout_animations_active.replace(true);
let res = f();
self.layout_animations_requested.set(prev_requested);
self.layout_animations_active.set(prev_active);
res
}
fn ensure_animation_tick(self: &Rc<Self>) {
if self.animations.tick_is_active() {
return;
}
let outputs: Vec<_> = self.root.outputs.lock().values().cloned().collect();
if outputs.is_empty() {
return;
}
let tick = Rc::new_cyclic(|weak| AnimationTick::new(self, weak));
for output in &outputs {
tick.attach(output);
}
self.animations.set_tick(tick);
for output in &outputs {
self.damage(output.global.pos.get());
}
}
pub fn output_extents_changed(&self) {
self.root.update_extents();
for seat in self.globals.seats.lock().values() {