Add linear tiled window animations
This commit is contained in:
parent
a29937ebe8
commit
3540cdc4be
17 changed files with 913 additions and 64 deletions
200
docs/window-animations-plan.md
Normal file
200
docs/window-animations-plan.md
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
# Window Animations Plan
|
||||
|
||||
This document is the working plan for Wry's window animation system. It records
|
||||
the decisions already made, the implementation phases, and the risks that must
|
||||
be handled deliberately.
|
||||
|
||||
## Accepted Decisions
|
||||
|
||||
- The first landed slice is linear interpolation only, disabled by default.
|
||||
- Animation is presentation-only. Logical layout, input hit testing, focus, and
|
||||
Wayland configure state use final geometry immediately.
|
||||
- Pointer drag and resize initiated by the mouse or tablet do not animate.
|
||||
- Linear animations restart only for windows whose destination changes. Other
|
||||
in-flight windows keep their existing timelines.
|
||||
- Spawn-in uses scale and position. Spawn-out requires retained visual content
|
||||
and is deferred until the freezing layer exists.
|
||||
- Command-driven tile-to-float and float-to-tile transitions may animate.
|
||||
Protocol drag/drop paths do not.
|
||||
- The no-overlap multiphase system is a separate phase after the linear path is
|
||||
working and testable.
|
||||
- Content freezing will use retained per-surface texture references, not a full
|
||||
offscreen snapshot as the default design.
|
||||
- The multiphase animation concept is original to Wry. Hy3 is relevant only as
|
||||
partial inspiration for tiling style and titlebar/grouping behavior.
|
||||
- Mono mode should mostly avoid animations. Exceptions are windows entering or
|
||||
exiting mono mode, where a visual transition can clarify the hierarchy change.
|
||||
|
||||
## Texture Freezing Decision
|
||||
|
||||
The approved freezing design is to capture a renderable surface tree at animation
|
||||
start:
|
||||
|
||||
- texture references
|
||||
- source sample rects
|
||||
- target sizes
|
||||
- alpha and color metadata
|
||||
- subsurface offsets and stacking order
|
||||
- enough synchronization/release state to keep referenced buffers alive safely
|
||||
|
||||
This is lighter than rendering every toplevel into a compositor-owned offscreen
|
||||
texture, and it should handle normal GPU-backed windows without an extra full
|
||||
window copy. It also gives spawn-out a path: capture the surface tree before the
|
||||
toplevel is logically destroyed, then animate the retained records after the live
|
||||
node is gone.
|
||||
|
||||
Tradeoffs:
|
||||
|
||||
- Retained references can delay buffer release. For dmabuf clients this can
|
||||
increase memory pressure or throttle clients if many large windows animate.
|
||||
- SHM buffers still matter for simple clients, fallback paths, some utilities,
|
||||
and cursor-like surfaces. They are probably not the common case for large app
|
||||
windows, but the implementation must still treat SHM texture flipping as a
|
||||
correctness issue.
|
||||
- The release/sync contract must be explicit. A retained texture must not be
|
||||
released back to the client while the compositor may still render it.
|
||||
- True offscreen snapshots remain a possible fallback for cases where retained
|
||||
references cannot safely preserve the rendered content.
|
||||
|
||||
## Phase 1: Linear Presentation Animations
|
||||
|
||||
Goal: add the smallest correct animation layer without changing layout semantics.
|
||||
|
||||
Implementation shape:
|
||||
|
||||
- Add animation state owned by `State`.
|
||||
- Track per-toplevel animation entries keyed by `NodeId`.
|
||||
- Store logical target rect, current presentation rect, previous damaged rect,
|
||||
start time, duration, and curve.
|
||||
- On command-driven tiled layout geometry changes, animate from current
|
||||
presentation rect to new final rect.
|
||||
- On interruption, restart only the affected window from its current
|
||||
presentation rect.
|
||||
- Drive frames from the existing output latch/presentation event flow.
|
||||
- Damage the union of previous presentation rect, current presentation rect, and
|
||||
final logical rect.
|
||||
|
||||
Initial scope:
|
||||
|
||||
- Tiled reflow animation.
|
||||
- Floating command-driven moves, tile-to-float, float-to-tile, and spawn-in are
|
||||
deferred until after tiled reflow is validated.
|
||||
- Cross-output and cross-scale movements snap for now.
|
||||
- Linear mode may overlap windows during swaps. That is expected for the classic
|
||||
interpolation mode; no-overlap is Phase 3.
|
||||
- Live client buffers are rendered in Phase 1. Retained content freezing is
|
||||
deferred, but animated windows must still be clipped to their presentation
|
||||
bounds and must preserve the existing stretch behavior for undersized contents.
|
||||
- No spawn-out.
|
||||
- No content freezing.
|
||||
- No multiphase no-overlap planner.
|
||||
|
||||
Tests:
|
||||
|
||||
- rect interpolation is direction-independent
|
||||
- interruption restarts only changed windows
|
||||
- unchanged in-flight windows keep their original timeline
|
||||
- drag-driven floating movement bypasses animation
|
||||
- damage includes old, current, and final rects
|
||||
|
||||
## Phase 2: Retained Texture Freezing
|
||||
|
||||
Goal: freeze visual contents during movement and enable spawn-out.
|
||||
|
||||
Implementation shape:
|
||||
|
||||
- Add a retained render-record tree for toplevel surfaces.
|
||||
- Capture records before movement animations that require freezing.
|
||||
- Capture records before destroy/unmap for spawn-out.
|
||||
- Render retained records through the normal renderer primitives where possible.
|
||||
- Extend event/sync handling so retained buffers remain valid until the animation
|
||||
is complete.
|
||||
|
||||
Open design work:
|
||||
|
||||
- Exact lifetime model for retained `SurfaceBuffer` / `GfxTexture` references.
|
||||
- Whether retained records participate in frame callbacks or presentation
|
||||
feedback. Default assumption: no, because they are compositor animation frames,
|
||||
not client commits.
|
||||
- How to fall back when a buffer cannot be safely retained.
|
||||
|
||||
## Phase 3: Multiphase No-Overlap Animations
|
||||
|
||||
Goal: implement Wry's staged no-overlap planner while preserving the rule that
|
||||
windows never overlap.
|
||||
|
||||
Core rules:
|
||||
|
||||
- Each phase is a discrete animation using the full curve.
|
||||
- A phase performs only one action kind per window: move or scale.
|
||||
- Movement and scaling are split by axis.
|
||||
- No diagonal motion.
|
||||
- A window or synchronized group owns its own timeline.
|
||||
- New layout changes interrupt only windows/groups with changed destinations.
|
||||
- Current hierarchy and target hierarchy both matter. The planner must know
|
||||
whether a window is ascending toward a higher-level/toplevel position,
|
||||
descending into a container, or moving between containers at the same depth.
|
||||
- If some child windows require fewer phases than their parent/container
|
||||
context, parent/container-space changes generally happen first so space exists
|
||||
before the child moves into it. This rule can be overridden only when the
|
||||
non-overlap invariant still clearly holds.
|
||||
- Windows that become peers in the target hierarchy may synchronize later
|
||||
phases even if they were not peers in the source hierarchy.
|
||||
|
||||
Important parent/child synchronization issue:
|
||||
|
||||
The planner must not let a parent container and child window animate independent
|
||||
axes at the same time in a way that violates the visual rules. For example, a
|
||||
parent scaling horizontally while a child scales vertically can accidentally
|
||||
produce a diagonal or multi-axis motion in screen space.
|
||||
|
||||
Preferred approach:
|
||||
|
||||
- Plan in terms of leaf toplevel visual rectangles first.
|
||||
- Treat containers as constraints and grouping boundaries, not as independently
|
||||
animated visual actors.
|
||||
- Derive every leaf's per-phase rect from one phase schedule so parent and child
|
||||
effects cannot compose into forbidden motion.
|
||||
- Add container-level grouping only after the leaf planner proves correct.
|
||||
- Include hierarchy-transition metadata in the planner input: source parent,
|
||||
target parent, source depth, target depth, and whether the window is ascending,
|
||||
descending, or staying at the same hierarchy level.
|
||||
- For mono containers, suppress ordinary in-mono focus/tab changes. Animate only
|
||||
transitions into mono, out of mono, or across the mono boundary.
|
||||
|
||||
Tests:
|
||||
|
||||
- horizontal swaps shrink, move, then grow without overlap
|
||||
- extraction from a stack creates space before moving the extracted window
|
||||
- nested containers do not produce simultaneous cross-axis motion
|
||||
- interruption restarts only affected phase groups
|
||||
- reversing direction produces equivalent motion in reverse
|
||||
- child waits for parent/container-space phases when moving upward into a
|
||||
toplevel peer position
|
||||
- mono-mode tab switches do not animate, while entering/exiting mono can animate
|
||||
|
||||
## Configuration
|
||||
|
||||
Phase 1 should expose a disabled-by-default setting for:
|
||||
|
||||
- enabled/disabled
|
||||
- duration
|
||||
- curve preset or cubic bezier
|
||||
|
||||
Initial TOML shape:
|
||||
|
||||
```toml
|
||||
[animations]
|
||||
enabled = false
|
||||
duration-ms = 160
|
||||
curve = "ease-out"
|
||||
```
|
||||
|
||||
Bezier curves should be analyzed at configuration time and stored in a form that
|
||||
is cheap to evaluate during rendering.
|
||||
|
||||
## Existing Note
|
||||
|
||||
`docs/animation-integration.md` appears to document a prior animation attempt
|
||||
whose `src/animation/` implementation is not present in this checkout. Treat
|
||||
this plan as the current source of truth until implementation docs are updated.
|
||||
Loading…
Add table
Add a link
Reference in a new issue