Add animation style toggle
This commit is contained in:
parent
02222d5189
commit
e7f9a5cb09
15 changed files with 238 additions and 20 deletions
|
|
@ -6,11 +6,11 @@ be handled deliberately.
|
|||
|
||||
## Accepted Decisions
|
||||
|
||||
- The first landed slice is linear interpolation only, disabled by default.
|
||||
- The first landed slice is plain 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
|
||||
- Plain animations restart only for windows whose destination changes. Other
|
||||
in-flight windows keep their existing timelines.
|
||||
- Spawn-in uses scale and position for newly mapped tiled and floating app
|
||||
windows. Layer-shell, overlay, override-redirect, and fullscreen surfaces do
|
||||
|
|
@ -19,7 +19,7 @@ be handled deliberately.
|
|||
destroy.
|
||||
- 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
|
||||
- The no-overlap multiphase system is a separate phase after the plain path is
|
||||
working and testable.
|
||||
- Content freezing will use retained per-surface texture references, not a full
|
||||
offscreen snapshot as the default design.
|
||||
|
|
@ -34,7 +34,7 @@ be handled deliberately.
|
|||
below roughly one quarter of the relevant full size. The implementation may
|
||||
enforce a conservative sanity minimum, and pathological cases may fall back.
|
||||
- If the no-overlap planner cannot produce a legal sequence, only the affected
|
||||
group should fall back to linear animation. This is expected to be rare for
|
||||
group should fall back to plain animation. This is expected to be rare for
|
||||
valid tiling layouts.
|
||||
- When entering mono mode, the active child should animate to the mono geometry.
|
||||
Inactive siblings may snap invisible. Floats may overlap normally and do not
|
||||
|
|
@ -285,6 +285,7 @@ Phase 1 should expose a disabled-by-default setting for:
|
|||
|
||||
- enabled/disabled
|
||||
- duration
|
||||
- style: `plain` or `multiphase`
|
||||
- curve preset or cubic bezier
|
||||
|
||||
Initial TOML shape:
|
||||
|
|
@ -293,6 +294,7 @@ Initial TOML shape:
|
|||
[animations]
|
||||
enabled = false
|
||||
duration-ms = 160
|
||||
style = "multiphase"
|
||||
curve = "ease-out"
|
||||
# or:
|
||||
curve = [0.25, 0.1, 0.25, 1.0]
|
||||
|
|
|
|||
|
|
@ -24,9 +24,24 @@ Relevant internal config hooks:
|
|||
|
||||
- `SetAnimationsEnabled`
|
||||
- `SetAnimationDurationMs`
|
||||
- `SetAnimationStyle`
|
||||
- `SetAnimationCurve`
|
||||
- `SetAnimationCubicBezier`
|
||||
|
||||
TOML example:
|
||||
|
||||
```toml
|
||||
[animations]
|
||||
enabled = true
|
||||
duration-ms = 600
|
||||
style = "multiphase"
|
||||
curve = "ease-out"
|
||||
```
|
||||
|
||||
Set `style = "plain"` to force ordinary one-step movement interpolation while
|
||||
keeping the configured curve. `curve = "linear"` only changes easing; it does
|
||||
not select the plain animation style.
|
||||
|
||||
Current curve IDs in code:
|
||||
|
||||
- `0`: linear
|
||||
|
|
@ -37,19 +52,20 @@ Current curve IDs in code:
|
|||
|
||||
## Enabling Multiphase Tests
|
||||
|
||||
There is currently no separate user-facing multiphase toggle. To exercise the
|
||||
multiphase planner:
|
||||
To exercise the multiphase planner:
|
||||
|
||||
1. Enable animations with `SetAnimationsEnabled`.
|
||||
2. Set a slow duration with `SetAnimationDurationMs`, around `400-700ms`.
|
||||
3. Use tiled layout commands that are wired through `State::with_layout_animations`.
|
||||
4. Use layouts where at least two tiled windows change geometry in the same
|
||||
3. Select `style = "multiphase"` in TOML, or call `SetAnimationStyle` with
|
||||
`AnimationStyle::MULTIPHASE`.
|
||||
4. Use tiled layout commands that are wired through `State::with_layout_animations`.
|
||||
5. Use layouts where at least two tiled windows change geometry in the same
|
||||
container layout batch.
|
||||
|
||||
The compositor then attempts multiphase planning automatically when the batched
|
||||
layout pass completes. If the planner proves a legal no-overlap sequence, that
|
||||
group uses phased animation. If it cannot prove one, only that motion group falls
|
||||
back to ordinary linear animation.
|
||||
back to ordinary plain animation.
|
||||
|
||||
Good command families for multiphase testing:
|
||||
|
||||
|
|
@ -64,7 +80,7 @@ Good command families for multiphase testing:
|
|||
|
||||
These paths should not be used as evidence of multiphase behavior:
|
||||
|
||||
- tile-to-float and float-to-tile, which deliberately use linear animation
|
||||
- tile-to-float and float-to-tile, which deliberately use plain animation
|
||||
- command-driven floating move/resize, which may animate but can overlap
|
||||
- pointer or tablet drag/resize, which should not animate
|
||||
- spawn-in and spawn-out, which are single-phase and use the configured curve
|
||||
|
|
@ -73,7 +89,7 @@ These paths should not be used as evidence of multiphase behavior:
|
|||
|
||||
Useful debug signal:
|
||||
|
||||
- `falling back to linear layout animation for group ...` means the group entered
|
||||
- `falling back to plain layout animation for group ...` means the group entered
|
||||
the multiphase gate but the planner rejected it. That is acceptable for
|
||||
unsupported patterns, but unexpected for the supported swap/extraction cases
|
||||
below.
|
||||
|
|
|
|||
|
|
@ -1035,6 +1035,10 @@ impl ConfigClient {
|
|||
self.send(&ClientMessage::SetAnimationCurve { curve });
|
||||
}
|
||||
|
||||
pub fn set_animation_style(&self, style: u32) {
|
||||
self.send(&ClientMessage::SetAnimationStyle { style });
|
||||
}
|
||||
|
||||
pub fn set_animation_cubic_bezier(&self, x1: f32, y1: f32, x2: f32, y2: f32) {
|
||||
self.send(&ClientMessage::SetAnimationCubicBezier { x1, y1, x2, y2 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,6 +554,9 @@ pub enum ClientMessage<'a> {
|
|||
SetAnimationCurve {
|
||||
curve: u32,
|
||||
},
|
||||
SetAnimationStyle {
|
||||
style: u32,
|
||||
},
|
||||
SetAnimationCubicBezier {
|
||||
x1: f32,
|
||||
y1: f32,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,15 @@ impl AnimationCurve {
|
|||
pub const EASE_IN_OUT: Self = Self(4);
|
||||
}
|
||||
|
||||
/// The presentation style used for tiled window movement animations.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AnimationStyle(pub u32);
|
||||
|
||||
impl AnimationStyle {
|
||||
pub const PLAIN: Self = Self(0);
|
||||
pub const MULTIPHASE: Self = Self(1);
|
||||
}
|
||||
|
||||
/// Exits the compositor.
|
||||
pub fn quit() {
|
||||
get!().quit()
|
||||
|
|
@ -320,6 +329,13 @@ pub fn set_animation_curve(curve: AnimationCurve) {
|
|||
get!().set_animation_curve(curve.0);
|
||||
}
|
||||
|
||||
/// Sets the presentation style used for tiled window movement animations.
|
||||
///
|
||||
/// The default is [`AnimationStyle::MULTIPHASE`].
|
||||
pub fn set_animation_style(style: AnimationStyle) {
|
||||
get!().set_animation_style(style.0);
|
||||
}
|
||||
|
||||
/// Sets a custom cubic-bezier curve used by tiled window animations.
|
||||
///
|
||||
/// `x1` and `x2` must be between `0.0` and `1.0`. The curve starts at `(0, 0)`
|
||||
|
|
|
|||
|
|
@ -30,6 +30,22 @@ pub enum AnimationCurve {
|
|||
Piecewise(PiecewiseCurve),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum AnimationStyle {
|
||||
Plain,
|
||||
Multiphase,
|
||||
}
|
||||
|
||||
impl AnimationStyle {
|
||||
pub fn from_config(value: u32) -> Option<Self> {
|
||||
match value {
|
||||
0 => Some(Self::Plain),
|
||||
1 => Some(Self::Multiphase),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnimationCurve {
|
||||
pub fn from_config(value: u32) -> Self {
|
||||
match value {
|
||||
|
|
@ -129,6 +145,7 @@ pub struct AnimationState {
|
|||
pub enabled: Cell<bool>,
|
||||
pub duration_ms: Cell<u32>,
|
||||
pub curve: Cell<AnimationCurve>,
|
||||
pub style: Cell<AnimationStyle>,
|
||||
windows: RefCell<AHashMap<NodeId, WindowAnimation>>,
|
||||
phased: RefCell<AHashMap<NodeId, PhasedWindowAnimation>>,
|
||||
exits: RefCell<Vec<ExitAnimation>>,
|
||||
|
|
@ -267,6 +284,7 @@ impl Default for AnimationState {
|
|||
enabled: Cell::new(false),
|
||||
duration_ms: Cell::new(DEFAULT_DURATION_MS),
|
||||
curve: Cell::new(AnimationCurve::from_config(3)),
|
||||
style: Cell::new(AnimationStyle::Multiphase),
|
||||
windows: Default::default(),
|
||||
phased: Default::default(),
|
||||
exits: Default::default(),
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ fn start_compositor2(
|
|||
layout_animations_requested: Default::default(),
|
||||
layout_animations_active: Default::default(),
|
||||
layout_animation_curve_override: Default::default(),
|
||||
layout_animation_style_override: Default::default(),
|
||||
layout_animation_batch: Default::default(),
|
||||
suppress_animations_for_next_layout: Default::default(),
|
||||
toplevels: Default::default(),
|
||||
|
|
|
|||
|
|
@ -1005,6 +1005,12 @@ impl ConfigProxyHandler {
|
|||
self.state.set_animation_curve(curve);
|
||||
}
|
||||
|
||||
fn handle_set_animation_style(&self, style: u32) {
|
||||
if !self.state.set_animation_style(style) {
|
||||
log::warn!("Ignoring invalid animation style");
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_set_animation_cubic_bezier(&self, x1: f32, y1: f32, x2: f32, y2: f32) {
|
||||
if !self.state.set_animation_cubic_bezier(x1, y1, x2, y2) {
|
||||
log::warn!("Ignoring invalid animation cubic-bezier curve");
|
||||
|
|
@ -3249,6 +3255,7 @@ impl ConfigProxyHandler {
|
|||
self.handle_set_animation_duration_ms(duration_ms)
|
||||
}
|
||||
ClientMessage::SetAnimationCurve { curve } => self.handle_set_animation_curve(curve),
|
||||
ClientMessage::SetAnimationStyle { style } => self.handle_set_animation_style(style),
|
||||
ClientMessage::SetAnimationCubicBezier { x1, y1, x2, y2 } => {
|
||||
self.handle_set_animation_cubic_bezier(x1, y1, x2, y2)
|
||||
}
|
||||
|
|
|
|||
70
src/state.rs
70
src/state.rs
|
|
@ -3,7 +3,8 @@ use {
|
|||
acceptor::Acceptor,
|
||||
allocator::BufferObject,
|
||||
animation::{
|
||||
AnimationCurve, AnimationState, AnimationTick, RetainedExitLayer, RetainedToplevel,
|
||||
AnimationCurve, AnimationState, AnimationStyle, AnimationTick, RetainedExitLayer,
|
||||
RetainedToplevel,
|
||||
expand_damage_rect,
|
||||
multiphase::{
|
||||
MultiphaseRequest, MultiphaseWindow, MultiphaseWindowHierarchy,
|
||||
|
|
@ -168,6 +169,7 @@ pub(crate) struct LayoutAnimationCandidate {
|
|||
old: Rect,
|
||||
new: Rect,
|
||||
curve: AnimationCurve,
|
||||
style: AnimationStyle,
|
||||
hierarchy: MultiphaseWindowHierarchy,
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +184,7 @@ fn coalesce_layout_animation_candidates(
|
|||
{
|
||||
existing.new = candidate.new;
|
||||
existing.curve = candidate.curve;
|
||||
existing.style = candidate.style;
|
||||
existing.hierarchy = MultiphaseWindowHierarchy::new(
|
||||
existing.hierarchy.source,
|
||||
candidate.hierarchy.target,
|
||||
|
|
@ -193,6 +196,15 @@ fn coalesce_layout_animation_candidates(
|
|||
merged
|
||||
}
|
||||
|
||||
fn layout_animation_group_uses_plain(
|
||||
candidates: &[LayoutAnimationCandidate],
|
||||
group: &[usize],
|
||||
) -> bool {
|
||||
group
|
||||
.iter()
|
||||
.any(|&idx| candidates[idx].style == AnimationStyle::Plain)
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub pid: c::pid_t,
|
||||
pub kb_ctx: KbvmContext,
|
||||
|
|
@ -307,6 +319,7 @@ pub struct State {
|
|||
pub layout_animations_requested: Cell<bool>,
|
||||
pub layout_animations_active: Cell<bool>,
|
||||
pub layout_animation_curve_override: Cell<Option<AnimationCurve>>,
|
||||
pub layout_animation_style_override: Cell<Option<AnimationStyle>>,
|
||||
pub(crate) layout_animation_batch: RefCell<Option<Vec<LayoutAnimationCandidate>>>,
|
||||
pub suppress_animations_for_next_layout: Cell<bool>,
|
||||
pub toplevels: CopyHashMap<ToplevelIdentifier, Weak<dyn ToplevelNode>>,
|
||||
|
|
@ -1172,6 +1185,7 @@ impl State {
|
|||
self.layout_animations_requested.set(false);
|
||||
self.layout_animations_active.set(false);
|
||||
self.layout_animation_curve_override.set(None);
|
||||
self.layout_animation_style_override.set(None);
|
||||
self.suppress_animations_for_next_layout.set(false);
|
||||
self.render_ctx_watchers.clear();
|
||||
self.workspace_watchers.clear();
|
||||
|
|
@ -1599,6 +1613,10 @@ impl State {
|
|||
old,
|
||||
new,
|
||||
curve,
|
||||
style: self
|
||||
.layout_animation_style_override
|
||||
.get()
|
||||
.unwrap_or_else(|| self.animations.style.get()),
|
||||
hierarchy,
|
||||
};
|
||||
if let Some(batch) = self.layout_animation_batch.borrow_mut().as_mut() {
|
||||
|
|
@ -1659,6 +1677,12 @@ impl State {
|
|||
})
|
||||
.collect();
|
||||
for group in partition_motion_groups(&windows, self.layout_animation_clearance()) {
|
||||
if layout_animation_group_uses_plain(&candidates, &group) {
|
||||
for idx in group {
|
||||
self.start_layout_animation_candidate(candidates[idx].clone(), now);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if self.start_multiphase_layout_animation(&candidates, &windows, &group, now) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1701,7 +1725,7 @@ impl State {
|
|||
Ok(plan) => plan,
|
||||
Err(diagnostic) => {
|
||||
log::debug!(
|
||||
"falling back to linear layout animation for group {:?}: {:?}",
|
||||
"falling back to plain layout animation for group {:?}: {:?}",
|
||||
group,
|
||||
diagnostic
|
||||
);
|
||||
|
|
@ -1881,6 +1905,14 @@ impl State {
|
|||
.set(AnimationCurve::from_config(curve));
|
||||
}
|
||||
|
||||
pub fn set_animation_style(&self, style: u32) -> bool {
|
||||
let Some(style) = AnimationStyle::from_config(style) else {
|
||||
return false;
|
||||
};
|
||||
self.animations.style.set(style);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_animation_cubic_bezier(&self, x1: f32, y1: f32, x2: f32, y2: f32) -> bool {
|
||||
let Some(curve) = AnimationCurve::from_cubic_bezier(x1, y1, x2, y2) else {
|
||||
return false;
|
||||
|
|
@ -1904,10 +1936,14 @@ impl State {
|
|||
let prev_curve = self
|
||||
.layout_animation_curve_override
|
||||
.replace(Some(AnimationCurve::Linear));
|
||||
let prev_style = self
|
||||
.layout_animation_style_override
|
||||
.replace(Some(AnimationStyle::Plain));
|
||||
let res = f();
|
||||
self.layout_animations_requested.set(prev_requested);
|
||||
self.layout_animations_active.set(prev_active);
|
||||
self.layout_animation_curve_override.set(prev_curve);
|
||||
self.layout_animation_style_override.set(prev_style);
|
||||
res
|
||||
}
|
||||
|
||||
|
|
@ -2475,6 +2511,28 @@ mod tests {
|
|||
MultiphaseWindowHierarchy::new(source, target)
|
||||
}
|
||||
|
||||
fn candidate(node_id: u32, style: AnimationStyle) -> LayoutAnimationCandidate {
|
||||
LayoutAnimationCandidate {
|
||||
node_id: NodeId(node_id),
|
||||
old: rect(0, 0, 100, 100),
|
||||
new: rect(100, 0, 200, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style,
|
||||
hierarchy: MultiphaseWindowHierarchy::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_style_candidate_forces_group_plain() {
|
||||
let candidates = vec![
|
||||
candidate(1, AnimationStyle::Multiphase),
|
||||
candidate(2, AnimationStyle::Plain),
|
||||
];
|
||||
|
||||
assert!(!layout_animation_group_uses_plain(&candidates, &[0]));
|
||||
assert!(layout_animation_group_uses_plain(&candidates, &[0, 1]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_animation_candidates_coalesce_duplicate_nodes() {
|
||||
let source = MultiphaseHierarchyPosition {
|
||||
|
|
@ -2514,6 +2572,7 @@ mod tests {
|
|||
old: rect(0, 0, 100, 100),
|
||||
new: rect(0, 0, 80, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style: AnimationStyle::Multiphase,
|
||||
hierarchy: hierarchy(source, intermediate),
|
||||
},
|
||||
LayoutAnimationCandidate {
|
||||
|
|
@ -2521,6 +2580,7 @@ mod tests {
|
|||
old: rect(100, 0, 200, 100),
|
||||
new: rect(120, 0, 220, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style: AnimationStyle::Multiphase,
|
||||
hierarchy: hierarchy(second_source, second_target),
|
||||
},
|
||||
LayoutAnimationCandidate {
|
||||
|
|
@ -2528,6 +2588,7 @@ mod tests {
|
|||
old: rect(0, 0, 80, 100),
|
||||
new: rect(0, 0, 60, 100),
|
||||
curve: AnimationCurve::from_config(4),
|
||||
style: AnimationStyle::Plain,
|
||||
hierarchy: hierarchy(intermediate, target),
|
||||
},
|
||||
];
|
||||
|
|
@ -2539,6 +2600,7 @@ mod tests {
|
|||
assert_eq!(merged[0].old, rect(0, 0, 100, 100));
|
||||
assert_eq!(merged[0].new, rect(0, 0, 60, 100));
|
||||
assert_eq!(merged[0].curve, AnimationCurve::from_config(4));
|
||||
assert_eq!(merged[0].style, AnimationStyle::Plain);
|
||||
assert_eq!(merged[0].hierarchy, hierarchy(source, target));
|
||||
assert_eq!(merged[1].node_id, NodeId(2));
|
||||
assert_eq!(merged[1].old, rect(100, 0, 200, 100));
|
||||
|
|
@ -2555,6 +2617,7 @@ mod tests {
|
|||
old: rect(0, 0, 100, 100),
|
||||
new: rect(0, 0, 80, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style: AnimationStyle::Multiphase,
|
||||
hierarchy,
|
||||
},
|
||||
LayoutAnimationCandidate {
|
||||
|
|
@ -2562,6 +2625,7 @@ mod tests {
|
|||
old: rect(0, 0, 80, 100),
|
||||
new: rect(0, 0, 100, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style: AnimationStyle::Plain,
|
||||
hierarchy,
|
||||
},
|
||||
LayoutAnimationCandidate {
|
||||
|
|
@ -2569,6 +2633,7 @@ mod tests {
|
|||
old: rect(100, 0, 200, 100),
|
||||
new: rect(120, 0, 220, 100),
|
||||
curve: AnimationCurve::Linear,
|
||||
style: AnimationStyle::Multiphase,
|
||||
hierarchy,
|
||||
},
|
||||
];
|
||||
|
|
@ -2579,6 +2644,7 @@ mod tests {
|
|||
assert_eq!(merged[0].node_id, NodeId(1));
|
||||
assert_eq!(merged[0].old, rect(0, 0, 100, 100));
|
||||
assert_eq!(merged[0].new, rect(0, 0, 100, 100));
|
||||
assert_eq!(merged[0].style, AnimationStyle::Plain);
|
||||
assert_eq!(merged[1].node_id, NodeId(2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ pub struct UiDrag {
|
|||
pub struct Animations {
|
||||
pub enabled: Option<bool>,
|
||||
pub duration_ms: Option<u32>,
|
||||
pub style: Option<String>,
|
||||
pub curve: Option<AnimationCurveConfig>,
|
||||
}
|
||||
|
||||
|
|
@ -678,3 +679,13 @@ fn custom_animation_curve_parses() {
|
|||
Some(AnimationCurveConfig::CubicBezier([0.25, 0.1, 0.25, 1.0]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn animation_style_parses() {
|
||||
let input = b"
|
||||
[animations]
|
||||
style = \"plain\"
|
||||
";
|
||||
let config = parse_config(input, &Default::default(), |_| ()).unwrap();
|
||||
assert_eq!(config.animations.style.as_deref(), Some("plain"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use {
|
|||
config::{
|
||||
AnimationCurveConfig, Animations,
|
||||
context::Context,
|
||||
extractor::{Extractor, ExtractorError, bol, n32, opt, recover, val},
|
||||
extractor::{Extractor, ExtractorError, bol, n32, opt, recover, str, val},
|
||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||
},
|
||||
toml::{
|
||||
|
|
@ -44,9 +44,10 @@ impl Parser for AnimationsParser<'_> {
|
|||
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
||||
) -> ParseResult<Self> {
|
||||
let mut ext = Extractor::new(self.0, span, table);
|
||||
let (enabled, duration_ms, curve) = ext.extract((
|
||||
let (enabled, duration_ms, style, curve) = ext.extract((
|
||||
recover(opt(bol("enabled"))),
|
||||
recover(opt(n32("duration-ms"))),
|
||||
recover(opt(str("style"))),
|
||||
opt(val("curve")),
|
||||
))?;
|
||||
let curve = match curve {
|
||||
|
|
@ -56,6 +57,7 @@ impl Parser for AnimationsParser<'_> {
|
|||
Ok(Animations {
|
||||
enabled: enabled.despan(),
|
||||
duration_ms: duration_ms.despan(),
|
||||
style: style.despan().map(|style| style.to_string()),
|
||||
curve,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use {
|
|||
ahash::{AHashMap, AHashSet},
|
||||
error_reporter::Report,
|
||||
jay_config::{
|
||||
AnimationCurve, Axis,
|
||||
AnimationCurve, AnimationStyle, Axis,
|
||||
client::Client,
|
||||
config, config_dir,
|
||||
exec::{Command, set_env, unset_env},
|
||||
|
|
@ -38,8 +38,9 @@ use {
|
|||
keyboard::Keymap,
|
||||
logging::{clean_logs_older_than, set_log_level},
|
||||
on_devices_enumerated, on_idle, on_unload, quit, reload, set_animation_cubic_bezier,
|
||||
set_animation_curve, set_animation_duration_ms, set_animations_enabled, set_autotile,
|
||||
set_color_management_enabled, set_corner_radius, set_default_workspace_capture,
|
||||
set_animation_curve, set_animation_duration_ms, set_animation_style,
|
||||
set_animations_enabled, set_autotile, set_color_management_enabled, set_corner_radius,
|
||||
set_default_workspace_capture,
|
||||
set_explicit_sync_enabled, set_float_above_fullscreen, set_floating_titles, set_idle,
|
||||
set_idle_grace_period, set_middle_click_paste_enabled, set_show_bar,
|
||||
set_show_float_pin_icon, set_show_titles, set_tab_title_align, set_ui_drag_enabled,
|
||||
|
|
@ -1652,6 +1653,11 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
|
|||
}
|
||||
set_animations_enabled(config.animations.enabled.unwrap_or(false));
|
||||
set_animation_duration_ms(config.animations.duration_ms.unwrap_or(160));
|
||||
match config.animations.style.as_deref().unwrap_or("multiphase") {
|
||||
"plain" => set_animation_style(AnimationStyle::PLAIN),
|
||||
"multiphase" => set_animation_style(AnimationStyle::MULTIPHASE),
|
||||
style_name => log::warn!("Unknown animation style: {style_name}"),
|
||||
}
|
||||
match config
|
||||
.animations
|
||||
.curve
|
||||
|
|
|
|||
|
|
@ -665,8 +665,16 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"AnimationStyle": {
|
||||
"type": "string",
|
||||
"description": "Describes a tiled window movement animation style.\n",
|
||||
"enum": [
|
||||
"plain",
|
||||
"multiphase"
|
||||
]
|
||||
},
|
||||
"Animations": {
|
||||
"description": "Describes window animation settings.\n\n- Example:\n\n ```toml\n [animations]\n enabled = true\n duration-ms = 160\n curve = [0.25, 0.1, 0.25, 1.0]\n ```\n",
|
||||
"description": "Describes window animation settings.\n\n- Example:\n\n ```toml\n [animations]\n enabled = true\n duration-ms = 160\n style = \"multiphase\"\n curve = [0.25, 0.1, 0.25, 1.0]\n ```\n",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
|
|
@ -677,6 +685,10 @@
|
|||
"type": "integer",
|
||||
"description": "Sets the animation duration in milliseconds.\n\nThe default is `160`.\n"
|
||||
},
|
||||
"style": {
|
||||
"description": "Sets the animation style used for tiled window movement animations.\n\nThe default is `multiphase`.\n",
|
||||
"$ref": "#/$defs/AnimationStyle"
|
||||
},
|
||||
"curve": {
|
||||
"description": "Sets the animation curve.\n\nThe default is `ease-out`.\n",
|
||||
"$ref": "#/$defs/AnimationCurve"
|
||||
|
|
@ -1129,7 +1141,7 @@
|
|||
"$ref": "#/$defs/UiDrag"
|
||||
},
|
||||
"animations": {
|
||||
"description": "Configures window animations.\n\nAnimations are disabled by default.\n\n- Example:\n\n ```toml\n [animations]\n enabled = true\n duration-ms = 160\n curve = \"ease-out\"\n ```\n",
|
||||
"description": "Configures window animations.\n\nAnimations are disabled by default.\n\n- Example:\n\n ```toml\n [animations]\n enabled = true\n duration-ms = 160\n style = \"multiphase\"\n curve = \"ease-out\"\n ```\n",
|
||||
"$ref": "#/$defs/Animations"
|
||||
},
|
||||
"xwayland": {
|
||||
|
|
|
|||
|
|
@ -987,6 +987,26 @@ be between `0` and `1`.
|
|||
Each element of this array should be a number.
|
||||
|
||||
|
||||
<a name="types-AnimationStyle"></a>
|
||||
### `AnimationStyle`
|
||||
|
||||
Describes a tiled window movement animation style.
|
||||
|
||||
Values of this type should be strings.
|
||||
|
||||
The string should have one of the following values:
|
||||
|
||||
- `plain`:
|
||||
|
||||
Uses a single interpolated movement from each window's current visual
|
||||
rectangle to its destination rectangle.
|
||||
|
||||
- `multiphase`:
|
||||
|
||||
Uses the no-overlap multiphase planner for tiled window movement when a
|
||||
supported plan exists.
|
||||
|
||||
|
||||
<a name="types-Animations"></a>
|
||||
### `Animations`
|
||||
|
||||
|
|
@ -998,6 +1018,7 @@ Describes window animation settings.
|
|||
[animations]
|
||||
enabled = true
|
||||
duration-ms = 160
|
||||
style = "multiphase"
|
||||
curve = [0.25, 0.1, 0.25, 1.0]
|
||||
```
|
||||
|
||||
|
|
@ -1023,6 +1044,14 @@ The table has the following fields:
|
|||
|
||||
The numbers should be integers.
|
||||
|
||||
- `style` (optional):
|
||||
|
||||
Sets the animation style used for tiled window movement animations.
|
||||
|
||||
The default is `multiphase`.
|
||||
|
||||
The value of this field should be a [AnimationStyle](#types-AnimationStyle).
|
||||
|
||||
- `curve` (optional):
|
||||
|
||||
Sets the animation curve.
|
||||
|
|
@ -2271,6 +2300,7 @@ The table has the following fields:
|
|||
[animations]
|
||||
enabled = true
|
||||
duration-ms = 160
|
||||
style = "multiphase"
|
||||
curve = "ease-out"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -2956,6 +2956,7 @@ Config:
|
|||
[animations]
|
||||
enabled = true
|
||||
duration-ms = 160
|
||||
style = "multiphase"
|
||||
curve = "ease-out"
|
||||
```
|
||||
xwayland:
|
||||
|
|
@ -3682,6 +3683,7 @@ Animations:
|
|||
[animations]
|
||||
enabled = true
|
||||
duration-ms = 160
|
||||
style = "multiphase"
|
||||
curve = [0.25, 0.1, 0.25, 1.0]
|
||||
```
|
||||
fields:
|
||||
|
|
@ -3700,6 +3702,13 @@ Animations:
|
|||
Sets the animation duration in milliseconds.
|
||||
|
||||
The default is `160`.
|
||||
style:
|
||||
ref: AnimationStyle
|
||||
required: false
|
||||
description: |
|
||||
Sets the animation style used for tiled window movement animations.
|
||||
|
||||
The default is `multiphase`.
|
||||
curve:
|
||||
ref: AnimationCurve
|
||||
required: false
|
||||
|
|
@ -3709,6 +3718,21 @@ Animations:
|
|||
The default is `ease-out`.
|
||||
|
||||
|
||||
AnimationStyle:
|
||||
kind: string
|
||||
description: |
|
||||
Describes a tiled window movement animation style.
|
||||
values:
|
||||
- value: plain
|
||||
description: |
|
||||
Uses a single interpolated movement from each window's current visual
|
||||
rectangle to its destination rectangle.
|
||||
- value: multiphase
|
||||
description: |
|
||||
Uses the no-overlap multiphase planner for tiled window movement when a
|
||||
supported plan exists.
|
||||
|
||||
|
||||
AnimationCurve:
|
||||
kind: variable
|
||||
description: |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue