aboutsummaryrefslogtreecommitdiff
path: root/niri-config/src/lib.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-08-27 09:57:56 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-08-27 10:43:57 +0300
commitda5e33775cbb7a4e64189360b4eb00eab6dbb1b3 (patch)
treed01aff0c078f8f0ec8795daba28183d6808222f5 /niri-config/src/lib.rs
parent1e3ab8a8808db07742825678ca38ed992bdf6767 (diff)
downloadniri-da5e33775cbb7a4e64189360b4eb00eab6dbb1b3.tar.gz
niri-da5e33775cbb7a4e64189360b4eb00eab6dbb1b3.tar.bz2
niri-da5e33775cbb7a4e64189360b4eb00eab6dbb1b3.zip
config: Extract animations
Diffstat (limited to 'niri-config/src/lib.rs')
-rw-r--r--niri-config/src/lib.rs668
1 files changed, 4 insertions, 664 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index f0b89a4a..f5aa3e1a 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -12,7 +12,6 @@ use std::time::Duration;
use bitflags::bitflags;
use knuffel::errors::DecodeError;
-use knuffel::Decode as _;
use miette::{miette, Context, IntoDiagnostic};
use niri_ipc::{
ColumnDisplay, ConfiguredMode, LayoutSwitchTarget, PositionChange, SizeChange, Transform,
@@ -27,10 +26,14 @@ use smithay::reexports::input;
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::from_array_unpremul([0.25, 0.25, 0.25, 1.]);
pub const DEFAULT_BACKDROP_COLOR: Color = Color::from_array_unpremul([0.15, 0.15, 0.15, 1.]);
+pub mod animations;
pub mod layer_rule;
pub mod utils;
pub mod window_rule;
+pub use crate::animations::{
+ Animation, AnimationCurve, AnimationKind, Animations, EasingParams, SpringParams,
+};
pub use crate::layer_rule::LayerRule;
pub use crate::window_rule::{FloatingPosition, RelativeTo, WindowRule};
@@ -1089,261 +1092,6 @@ pub struct Clipboard {
pub disable_primary: bool,
}
-#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
-pub struct Animations {
- #[knuffel(child)]
- pub off: bool,
- #[knuffel(child, unwrap(argument), default = FloatOrInt(1.))]
- pub slowdown: FloatOrInt<0, { i32::MAX }>,
- #[knuffel(child, default)]
- pub workspace_switch: WorkspaceSwitchAnim,
- #[knuffel(child, default)]
- pub window_open: WindowOpenAnim,
- #[knuffel(child, default)]
- pub window_close: WindowCloseAnim,
- #[knuffel(child, default)]
- pub horizontal_view_movement: HorizontalViewMovementAnim,
- #[knuffel(child, default)]
- pub window_movement: WindowMovementAnim,
- #[knuffel(child, default)]
- pub window_resize: WindowResizeAnim,
- #[knuffel(child, default)]
- pub config_notification_open_close: ConfigNotificationOpenCloseAnim,
- #[knuffel(child, default)]
- pub exit_confirmation_open_close: ExitConfirmationOpenCloseAnim,
- #[knuffel(child, default)]
- pub screenshot_ui_open: ScreenshotUiOpenAnim,
- #[knuffel(child, default)]
- pub overview_open_close: OverviewOpenCloseAnim,
-}
-
-impl Default for Animations {
- fn default() -> Self {
- Self {
- off: false,
- slowdown: FloatOrInt(1.),
- workspace_switch: Default::default(),
- horizontal_view_movement: Default::default(),
- window_movement: Default::default(),
- window_open: Default::default(),
- window_close: Default::default(),
- window_resize: Default::default(),
- config_notification_open_close: Default::default(),
- exit_confirmation_open_close: Default::default(),
- screenshot_ui_open: Default::default(),
- overview_open_close: Default::default(),
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct WorkspaceSwitchAnim(pub Animation);
-
-impl Default for WorkspaceSwitchAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 1.,
- stiffness: 1000,
- epsilon: 0.0001,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct WindowOpenAnim {
- pub anim: Animation,
- pub custom_shader: Option<String>,
-}
-
-impl Default for WindowOpenAnim {
- fn default() -> Self {
- Self {
- anim: Animation {
- off: false,
- kind: AnimationKind::Easing(EasingParams {
- duration_ms: 150,
- curve: AnimationCurve::EaseOutExpo,
- }),
- },
- custom_shader: None,
- }
- }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct WindowCloseAnim {
- pub anim: Animation,
- pub custom_shader: Option<String>,
-}
-
-impl Default for WindowCloseAnim {
- fn default() -> Self {
- Self {
- anim: Animation {
- off: false,
- kind: AnimationKind::Easing(EasingParams {
- duration_ms: 150,
- curve: AnimationCurve::EaseOutQuad,
- }),
- },
- custom_shader: None,
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct HorizontalViewMovementAnim(pub Animation);
-
-impl Default for HorizontalViewMovementAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 1.,
- stiffness: 800,
- epsilon: 0.0001,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct WindowMovementAnim(pub Animation);
-
-impl Default for WindowMovementAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 1.,
- stiffness: 800,
- epsilon: 0.0001,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct WindowResizeAnim {
- pub anim: Animation,
- pub custom_shader: Option<String>,
-}
-
-impl Default for WindowResizeAnim {
- fn default() -> Self {
- Self {
- anim: Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 1.,
- stiffness: 800,
- epsilon: 0.0001,
- }),
- },
- custom_shader: None,
- }
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct ConfigNotificationOpenCloseAnim(pub Animation);
-
-impl Default for ConfigNotificationOpenCloseAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 0.6,
- stiffness: 1000,
- epsilon: 0.001,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct ExitConfirmationOpenCloseAnim(pub Animation);
-
-impl Default for ExitConfirmationOpenCloseAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 0.6,
- stiffness: 500,
- epsilon: 0.01,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct ScreenshotUiOpenAnim(pub Animation);
-
-impl Default for ScreenshotUiOpenAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Easing(EasingParams {
- duration_ms: 200,
- curve: AnimationCurve::EaseOutQuad,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct OverviewOpenCloseAnim(pub Animation);
-
-impl Default for OverviewOpenCloseAnim {
- fn default() -> Self {
- Self(Animation {
- off: false,
- kind: AnimationKind::Spring(SpringParams {
- damping_ratio: 1.,
- stiffness: 800,
- epsilon: 0.0001,
- }),
- })
- }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Animation {
- pub off: bool,
- pub kind: AnimationKind,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum AnimationKind {
- Easing(EasingParams),
- Spring(SpringParams),
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct EasingParams {
- pub duration_ms: u32,
- pub curve: AnimationCurve,
-}
-
-#[derive(knuffel::DecodeScalar, Debug, Clone, Copy, PartialEq)]
-pub enum AnimationCurve {
- Linear,
- EaseOutQuad,
- EaseOutCubic,
- EaseOutExpo,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct SpringParams {
- pub damping_ratio: f64,
- pub stiffness: u32,
- pub epsilon: f64,
-}
-
#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
pub struct Gestures {
#[knuffel(child, default)]
@@ -3061,51 +2809,6 @@ fn parse_arg_node<S: knuffel::traits::ErrorSpan, T: knuffel::traits::DecodeScala
Ok(value)
}
-impl<S> knuffel::Decode<S> for WorkspaceSwitchAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl<S> knuffel::Decode<S> for HorizontalViewMovementAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl<S> knuffel::Decode<S> for WindowMovementAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
impl<S: knuffel::traits::ErrorSpan> knuffel::DecodeScalar<S> for WorkspaceName {
fn type_check(
type_name: &Option<knuffel::span::Spanned<knuffel::ast::TypeName, S>>,
@@ -3157,369 +2860,6 @@ impl<S: knuffel::traits::ErrorSpan> knuffel::DecodeScalar<S> for WorkspaceName {
}
}
-impl<S> knuffel::Decode<S> for WindowOpenAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().anim;
- let mut custom_shader = None;
- let anim = Animation::decode_node(node, ctx, default, |child, ctx| {
- if &**child.node_name == "custom-shader" {
- custom_shader = parse_arg_node("custom-shader", child, ctx)?;
- Ok(true)
- } else {
- Ok(false)
- }
- })?;
-
- Ok(Self {
- anim,
- custom_shader,
- })
- }
-}
-
-impl<S> knuffel::Decode<S> for WindowCloseAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().anim;
- let mut custom_shader = None;
- let anim = Animation::decode_node(node, ctx, default, |child, ctx| {
- if &**child.node_name == "custom-shader" {
- custom_shader = parse_arg_node("custom-shader", child, ctx)?;
- Ok(true)
- } else {
- Ok(false)
- }
- })?;
-
- Ok(Self {
- anim,
- custom_shader,
- })
- }
-}
-
-impl<S> knuffel::Decode<S> for WindowResizeAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().anim;
- let mut custom_shader = None;
- let anim = Animation::decode_node(node, ctx, default, |child, ctx| {
- if &**child.node_name == "custom-shader" {
- custom_shader = parse_arg_node("custom-shader", child, ctx)?;
- Ok(true)
- } else {
- Ok(false)
- }
- })?;
-
- Ok(Self {
- anim,
- custom_shader,
- })
- }
-}
-
-impl<S> knuffel::Decode<S> for ConfigNotificationOpenCloseAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl<S> knuffel::Decode<S> for ExitConfirmationOpenCloseAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl<S> knuffel::Decode<S> for ScreenshotUiOpenAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl<S> knuffel::Decode<S> for OverviewOpenCloseAnim
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- let default = Self::default().0;
- Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
- Ok(false)
- })?))
- }
-}
-
-impl Animation {
- pub fn new_off() -> Self {
- Self {
- off: true,
- kind: AnimationKind::Easing(EasingParams {
- duration_ms: 0,
- curve: AnimationCurve::Linear,
- }),
- }
- }
-
- fn decode_node<S: knuffel::traits::ErrorSpan>(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- default: Self,
- mut process_children: impl FnMut(
- &knuffel::ast::SpannedNode<S>,
- &mut knuffel::decode::Context<S>,
- ) -> Result<bool, DecodeError<S>>,
- ) -> Result<Self, DecodeError<S>> {
- #[derive(Default, PartialEq)]
- struct OptionalEasingParams {
- duration_ms: Option<u32>,
- curve: Option<AnimationCurve>,
- }
-
- expect_only_children(node, ctx);
-
- let mut off = false;
- let mut easing_params = OptionalEasingParams::default();
- let mut spring_params = None;
-
- for child in node.children() {
- match &**child.node_name {
- "off" => {
- knuffel::decode::check_flag_node(child, ctx);
- if off {
- ctx.emit_error(DecodeError::unexpected(
- &child.node_name,
- "node",
- "duplicate node `off`, single node expected",
- ));
- } else {
- off = true;
- }
- }
- "spring" => {
- if easing_params != OptionalEasingParams::default() {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- "cannot set both spring and easing parameters at once",
- ));
- }
- if spring_params.is_some() {
- ctx.emit_error(DecodeError::unexpected(
- &child.node_name,
- "node",
- "duplicate node `spring`, single node expected",
- ));
- }
-
- spring_params = Some(SpringParams::decode_node(child, ctx)?);
- }
- "duration-ms" => {
- if spring_params.is_some() {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- "cannot set both spring and easing parameters at once",
- ));
- }
- if easing_params.duration_ms.is_some() {
- ctx.emit_error(DecodeError::unexpected(
- &child.node_name,
- "node",
- "duplicate node `duration-ms`, single node expected",
- ));
- }
-
- easing_params.duration_ms = Some(parse_arg_node("duration-ms", child, ctx)?);
- }
- "curve" => {
- if spring_params.is_some() {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- "cannot set both spring and easing parameters at once",
- ));
- }
- if easing_params.curve.is_some() {
- ctx.emit_error(DecodeError::unexpected(
- &child.node_name,
- "node",
- "duplicate node `curve`, single node expected",
- ));
- }
-
- easing_params.curve = Some(parse_arg_node("curve", child, ctx)?);
- }
- name_str => {
- if !process_children(child, ctx)? {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- format!("unexpected node `{}`", name_str.escape_default()),
- ));
- }
- }
- }
- }
-
- let kind = if let Some(spring_params) = spring_params {
- // Configured spring.
- AnimationKind::Spring(spring_params)
- } else if easing_params == OptionalEasingParams::default() {
- // Did not configure anything.
- default.kind
- } else {
- // Configured easing.
- let default = if let AnimationKind::Easing(easing) = default.kind {
- easing
- } else {
- // Generic fallback values for when the default animation is spring, but the user
- // configured an easing animation.
- EasingParams {
- duration_ms: 250,
- curve: AnimationCurve::EaseOutCubic,
- }
- };
-
- AnimationKind::Easing(EasingParams {
- duration_ms: easing_params.duration_ms.unwrap_or(default.duration_ms),
- curve: easing_params.curve.unwrap_or(default.curve),
- })
- };
-
- Ok(Self { off, kind })
- }
-}
-
-impl<S> knuffel::Decode<S> for SpringParams
-where
- S: knuffel::traits::ErrorSpan,
-{
- fn decode_node(
- node: &knuffel::ast::SpannedNode<S>,
- ctx: &mut knuffel::decode::Context<S>,
- ) -> Result<Self, DecodeError<S>> {
- if let Some(type_name) = &node.type_name {
- ctx.emit_error(DecodeError::unexpected(
- type_name,
- "type name",
- "no type name expected for this node",
- ));
- }
- if let Some(val) = node.arguments.first() {
- ctx.emit_error(DecodeError::unexpected(
- &val.literal,
- "argument",
- "unexpected argument",
- ));
- }
- for child in node.children() {
- ctx.emit_error(DecodeError::unexpected(
- child,
- "node",
- format!("unexpected node `{}`", child.node_name.escape_default()),
- ));
- }
-
- let mut damping_ratio = None;
- let mut stiffness = None;
- let mut epsilon = None;
- for (name, val) in &node.properties {
- match &***name {
- "damping-ratio" => {
- damping_ratio = Some(knuffel::traits::DecodeScalar::decode(val, ctx)?);
- }
- "stiffness" => {
- stiffness = Some(knuffel::traits::DecodeScalar::decode(val, ctx)?);
- }
- "epsilon" => {
- epsilon = Some(knuffel::traits::DecodeScalar::decode(val, ctx)?);
- }
- name_str => {
- ctx.emit_error(DecodeError::unexpected(
- name,
- "property",
- format!("unexpected property `{}`", name_str.escape_default()),
- ));
- }
- }
- }
- let damping_ratio = damping_ratio
- .ok_or_else(|| DecodeError::missing(node, "property `damping-ratio` is required"))?;
- let stiffness = stiffness
- .ok_or_else(|| DecodeError::missing(node, "property `stiffness` is required"))?;
- let epsilon =
- epsilon.ok_or_else(|| DecodeError::missing(node, "property `epsilon` is required"))?;
-
- if !(0.1..=10.).contains(&damping_ratio) {
- ctx.emit_error(DecodeError::conversion(
- node,
- "damping-ratio must be between 0.1 and 10.0",
- ));
- }
- if stiffness < 1 {
- ctx.emit_error(DecodeError::conversion(node, "stiffness must be >= 1"));
- }
- if !(0.00001..=0.1).contains(&epsilon) {
- ctx.emit_error(DecodeError::conversion(
- node,
- "epsilon must be between 0.00001 and 0.1",
- ));
- }
-
- Ok(SpringParams {
- damping_ratio,
- stiffness,
- epsilon,
- })
- }
-}
-
impl<S> knuffel::Decode<S> for CornerRadius
where
S: knuffel::traits::ErrorSpan,