Skip to content
140 changes: 140 additions & 0 deletions niri-config/src/animations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ pub struct Animations {
pub workspace_switch: WorkspaceSwitchAnim,
pub window_open: WindowOpenAnim,
pub window_close: WindowCloseAnim,
pub layer_open: LayerOpenAnim,
pub layer_close: LayerCloseAnim,
pub layer_bar_open: Option<LayerOpenAnim>,
pub layer_bar_close: Option<LayerCloseAnim>,
pub layer_wallpaper_open: Option<LayerOpenAnim>,
pub layer_wallpaper_close: Option<LayerCloseAnim>,
pub layer_launcher_open: Option<LayerOpenAnim>,
pub layer_launcher_close: Option<LayerCloseAnim>,
pub horizontal_view_movement: HorizontalViewMovementAnim,
pub window_movement: WindowMovementAnim,
pub window_resize: WindowResizeAnim,
Expand All @@ -31,6 +39,14 @@ impl Default for Animations {
window_movement: Default::default(),
window_open: Default::default(),
window_close: Default::default(),
layer_open: Default::default(),
layer_close: Default::default(),
layer_bar_open: None,
layer_bar_close: None,
layer_wallpaper_open: None,
layer_wallpaper_close: None,
layer_launcher_open: None,
layer_launcher_close: None,
window_resize: Default::default(),
config_notification_open_close: Default::default(),
exit_confirmation_open_close: Default::default(),
Expand All @@ -56,6 +72,22 @@ pub struct AnimationsPart {
#[knuffel(child)]
pub window_close: Option<WindowCloseAnim>,
#[knuffel(child)]
pub layer_open: Option<LayerOpenAnim>,
#[knuffel(child)]
pub layer_close: Option<LayerCloseAnim>,
#[knuffel(child)]
pub layer_bar_open: Option<LayerOpenAnim>,
#[knuffel(child)]
pub layer_bar_close: Option<LayerCloseAnim>,
#[knuffel(child)]
pub layer_wallpaper_open: Option<LayerOpenAnim>,
#[knuffel(child)]
pub layer_wallpaper_close: Option<LayerCloseAnim>,
#[knuffel(child)]
pub layer_launcher_open: Option<LayerOpenAnim>,
#[knuffel(child)]
pub layer_launcher_close: Option<LayerCloseAnim>,
#[knuffel(child)]
pub horizontal_view_movement: Option<HorizontalViewMovementAnim>,
#[knuffel(child)]
pub window_movement: Option<WindowMovementAnim>,
Expand Down Expand Up @@ -89,6 +121,8 @@ impl MergeWith<AnimationsPart> for Animations {
workspace_switch,
window_open,
window_close,
layer_open,
layer_close,
horizontal_view_movement,
window_movement,
window_resize,
Expand All @@ -98,6 +132,18 @@ impl MergeWith<AnimationsPart> for Animations {
overview_open_close,
recent_windows_close,
);

// Specific layer animation overrides: None means "fall back to the generic layer_open /
// layer_close at runtime". merge_clone_opt! preserves None when not set in the part.
merge_clone_opt!(
(self, part),
layer_bar_open,
layer_bar_close,
layer_wallpaper_open,
layer_wallpaper_close,
layer_launcher_open,
layer_launcher_close,
);
}
}

Expand Down Expand Up @@ -193,6 +239,48 @@ impl Default for WindowCloseAnim {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct LayerOpenAnim {
pub anim: Animation,
pub custom_shader: Option<String>,
}

impl Default for LayerOpenAnim {
fn default() -> Self {
Self {
anim: Animation {
off: false,
kind: Kind::Easing(EasingParams {
duration_ms: 150,
curve: Curve::EaseOutExpo,
}),
},
custom_shader: None,
}
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct LayerCloseAnim {
pub anim: Animation,
pub custom_shader: Option<String>,
}

impl Default for LayerCloseAnim {
fn default() -> Self {
Self {
anim: Animation {
off: false,
kind: Kind::Easing(EasingParams {
duration_ms: 150,
curve: Curve::EaseOutQuad,
}),
},
custom_shader: None,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct HorizontalViewMovementAnim(pub Animation);

Expand Down Expand Up @@ -449,6 +537,58 @@ where
}
}

impl<S> knuffel::Decode<S> for LayerOpenAnim
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 LayerCloseAnim
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,
Expand Down
30 changes: 30 additions & 0 deletions niri-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,36 @@ mod tests {
},
custom_shader: None,
},
layer_open: LayerOpenAnim {
anim: Animation {
off: false,
kind: Easing(
EasingParams {
duration_ms: 150,
curve: EaseOutExpo,
},
),
},
custom_shader: None,
},
layer_close: LayerCloseAnim {
anim: Animation {
off: false,
kind: Easing(
EasingParams {
duration_ms: 150,
curve: EaseOutQuad,
},
),
},
custom_shader: None,
},
layer_bar_open: None,
layer_bar_close: None,
layer_wallpaper_open: None,
layer_wallpaper_close: None,
layer_launcher_open: None,
layer_launcher_close: None,
horizontal_view_movement: HorizontalViewMovementAnim(
Animation {
off: false,
Expand Down
58 changes: 56 additions & 2 deletions src/backend/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,10 +821,64 @@ impl Tty {
shaders::set_custom_resize_program(gles_renderer, Some(src));
}
if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
shaders::set_custom_close_program(gles_renderer, Some(src));
shaders::set_custom_window_close_program(gles_renderer, Some(src));
}
if let Some(src) = config.animations.window_open.custom_shader.as_deref() {
shaders::set_custom_open_program(gles_renderer, Some(src));
shaders::set_custom_window_open_program(gles_renderer, Some(src));
}
if let Some(src) = config.animations.layer_close.custom_shader.as_deref() {
shaders::set_custom_layer_close_program(gles_renderer, Some(src));
}
if let Some(src) = config.animations.layer_open.custom_shader.as_deref() {
shaders::set_custom_layer_open_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_bar_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_bar_close_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_bar_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_bar_open_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_wallpaper_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_wallpaper_close_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_wallpaper_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_wallpaper_open_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_launcher_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_launcher_close_program(gles_renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_launcher_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_launcher_open_program(gles_renderer, Some(src));
}
drop(config);

Expand Down
58 changes: 56 additions & 2 deletions src/backend/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,64 @@ impl Winit {
shaders::set_custom_resize_program(renderer, Some(src));
}
if let Some(src) = config.animations.window_close.custom_shader.as_deref() {
shaders::set_custom_close_program(renderer, Some(src));
shaders::set_custom_window_close_program(renderer, Some(src));
}
if let Some(src) = config.animations.window_open.custom_shader.as_deref() {
shaders::set_custom_open_program(renderer, Some(src));
shaders::set_custom_window_open_program(renderer, Some(src));
}
if let Some(src) = config.animations.layer_close.custom_shader.as_deref() {
shaders::set_custom_layer_close_program(renderer, Some(src));
}
if let Some(src) = config.animations.layer_open.custom_shader.as_deref() {
shaders::set_custom_layer_open_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_bar_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_bar_close_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_bar_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_bar_open_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_wallpaper_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_wallpaper_close_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_wallpaper_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_wallpaper_open_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_launcher_close
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_launcher_close_program(renderer, Some(src));
}
if let Some(src) = config
.animations
.layer_launcher_open
.as_ref()
.and_then(|a| a.custom_shader.as_deref())
{
shaders::set_custom_layer_launcher_open_program(renderer, Some(src));
}
drop(config);

Expand Down
Loading