1
0
Fork 0
forked from wry/wry

Add open and close animations, xdg_popup blur pre-pass,

damage viz config option.
This commit is contained in:
entailz 2026-05-20 18:50:11 -07:00
parent 12adb678bb
commit e35dce433a
24 changed files with 1056 additions and 67 deletions

View file

@ -393,6 +393,30 @@ pub struct BlurConfig {
pub size: Option<f32>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AnimationCurve {
Linear,
EaseOut,
EaseInOut,
Bezier { x1: f32, y1: f32, x2: f32, y2: f32 },
}
#[derive(Debug, Clone, Copy)]
pub struct AnimationsConfig {
pub enabled: Option<bool>,
pub open_duration_ms: Option<u32>,
pub open_curve: Option<AnimationCurve>,
pub close_duration_ms: Option<u32>,
pub close_curve: Option<AnimationCurve>,
}
#[derive(Debug, Clone, Copy)]
pub struct DamageVisualization {
pub enabled: Option<bool>,
pub color: Option<jay_config::theme::Color>,
pub decay_ms: Option<u64>,
}
#[derive(Debug, Clone)]
pub enum DrmDeviceMatch {
Any(Vec<DrmDeviceMatch>),
@ -607,6 +631,8 @@ pub struct Config {
pub window_rules: Vec<WindowRule>,
pub layer_rules: Vec<LayerRule>,
pub blur: Option<BlurConfig>,
pub damage_visualization: Option<DamageVisualization>,
pub animations: Option<AnimationsConfig>,
pub pointer_revert_key: Option<KeySym>,
pub use_hardware_cursor: Option<bool>,
pub show_bar: Option<bool>,

View file

@ -8,6 +8,7 @@ use {
pub mod action;
mod actions;
mod animations;
mod blur;
mod capabilities;
mod clean_logs_older_than;
@ -19,6 +20,7 @@ pub mod config;
mod connector;
mod connector_match;
mod content_type;
mod damage_visualization;
mod drm_device;
mod drm_device_match;
mod env;

View file

@ -0,0 +1,73 @@
use {
crate::{
config::{
AnimationCurve, AnimationsConfig,
context::Context,
extractor::{Extractor, ExtractorError, bol, int, opt, recover, str},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
},
toml::{
toml_span::{DespanExt, Span, Spanned, SpannedExt},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum AnimationsConfigParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
#[error("unknown animation curve `{0}`; expected one of: linear, ease-out, ease-in-out")]
UnknownCurve(String),
}
pub struct AnimationsConfigParser<'a>(pub &'a Context<'a>);
impl Parser for AnimationsConfigParser<'_> {
type Value = AnimationsConfig;
type Error = AnimationsConfigParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (enabled_val, open_duration_val, open_curve_val, close_duration_val, close_curve_val) =
ext.extract((
recover(opt(bol("enabled"))),
recover(opt(int("open-duration-ms"))),
opt(str("open-curve")),
recover(opt(int("close-duration-ms"))),
opt(str("close-curve")),
))?;
let enabled = enabled_val.despan();
let open_duration_ms = open_duration_val.despan().and_then(|v| u32::try_from(v).ok());
let close_duration_ms = close_duration_val.despan().and_then(|v| u32::try_from(v).ok());
let parse_curve = |val: Option<Spanned<&str>>| match val {
Some(s) => match s.value {
"linear" => Ok(Some(AnimationCurve::Linear)),
"ease-out" => Ok(Some(AnimationCurve::EaseOut)),
"ease-in-out" => Ok(Some(AnimationCurve::EaseInOut)),
other => {
Err(AnimationsConfigParserError::UnknownCurve(other.to_string()).spanned(s.span))
}
},
None => Ok(None),
};
let open_curve = parse_curve(open_curve_val)?;
let close_curve = parse_curve(close_curve_val)?;
Ok(AnimationsConfig {
enabled,
open_duration_ms,
open_curve,
close_duration_ms,
close_curve,
})
}
}

View file

@ -8,8 +8,10 @@ use {
parsers::{
action::ActionParser,
actions::ActionsParser,
animations::AnimationsConfigParser,
blur::BlurConfigParser,
clean_logs_older_than::CleanLogsOlderThanParser,
damage_visualization::DamageVisualizationParser,
client_rule::ClientRulesParser,
color_management::ColorManagementParser,
connector::ConnectorsParser,
@ -157,7 +159,7 @@ impl Parser for ConfigParser<'_> {
mouse_follows_focus,
layer_rules_val,
),
(blur_val,),
(blur_val, damage_visualization_val, animations_val),
) = ext.extract((
(
opt(val("keymap")),
@ -219,7 +221,11 @@ impl Parser for ConfigParser<'_> {
recover(opt(bol("unstable-mouse-follows-focus"))),
opt(val("layers")),
),
(opt(val("blur")),),
(
opt(val("blur")),
opt(val("damage-visualization")),
opt(val("animations")),
),
))?;
let mut keymap = None;
if let Some(value) = keymap_val {
@ -515,6 +521,26 @@ impl Parser for ConfigParser<'_> {
Err(e) => log::warn!("Could not parse the blur config: {}", self.0.error(e)),
}
}
let mut damage_visualization = None;
if let Some(value) = damage_visualization_val {
match value.parse(&mut DamageVisualizationParser(self.0)) {
Ok(v) => damage_visualization = Some(v),
Err(e) => log::warn!(
"Could not parse the damage-visualization config: {}",
self.0.error(e)
),
}
}
let mut animations = None;
if let Some(value) = animations_val {
match value.parse(&mut AnimationsConfigParser(self.0)) {
Ok(v) => animations = Some(v),
Err(e) => log::warn!(
"Could not parse the animations config: {}",
self.0.error(e)
),
}
}
let mut pointer_revert_key = None;
if let Some(value) = pointer_revert_key_str {
match Keysym::from_str(value.value) {
@ -616,6 +642,8 @@ impl Parser for ConfigParser<'_> {
window_rules,
layer_rules,
blur,
damage_visualization,
animations,
pointer_revert_key,
use_hardware_cursor: use_hardware_cursor.despan(),
show_bar: show_bar.despan(),

View file

@ -0,0 +1,65 @@
use {
crate::{
config::{
DamageVisualization,
context::Context,
extractor::{Extractor, ExtractorError, bol, int, opt, recover, str},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
parsers::color::{ColorParser, ColorParserError},
},
toml::{
toml_span::{DespanExt, Span, Spanned, SpannedExt},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum DamageVisualizationParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
#[error(transparent)]
Color(#[from] ColorParserError),
}
pub struct DamageVisualizationParser<'a>(pub &'a Context<'a>);
impl Parser for DamageVisualizationParser<'_> {
type Value = DamageVisualization;
type Error = DamageVisualizationParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (enabled_val, color_val, decay_val) = ext.extract((
recover(opt(bol("enabled"))),
opt(str("color")),
recover(opt(int("decay-ms"))),
))?;
let enabled = enabled_val.despan();
let color = match color_val {
Some(s) => match ColorParser.parse_string(s.span, s.value) {
Ok(c) => Some(c),
Err(e) => {
return Err(DamageVisualizationParserError::Color(e.value)
.spanned(s.span));
}
},
None => None,
};
let decay_ms = decay_val.despan().and_then(|v| u64::try_from(v).ok());
Ok(DamageVisualization {
enabled,
color,
decay_ms,
})
}
}

View file

@ -13,7 +13,8 @@ mod toml;
use {
crate::{
config::{
Action, BlurConfig, ClientRule, Config, ConfigConnector, ConfigDrmDevice, ConfigKeymap,
Action, AnimationCurve, AnimationsConfig, BlurConfig, ClientRule, Config,
ConfigConnector, ConfigDrmDevice, ConfigKeymap,
ConnectorMatch, DrmDeviceMatch, Exec, Input, InputMatch, LayerKind, LayerRule, Output,
OutputMatch, SimpleCommand, Status, Theme, WindowRule, parse_config,
},
@ -23,8 +24,12 @@ use {
ahash::{AHashMap, AHashSet},
error_reporter::Report,
jay_config::{
_private::{BlurConfigIpc, LayerKindIpc, LayerMatchIpc, LayerRuleIpc},
_set_blur_config, _set_layer_rules, Axis,
_private::{
AnimationCurveIpc, AnimationsConfigIpc, BlurConfigIpc, DamageVisualizationIpc,
LayerKindIpc, LayerMatchIpc, LayerRuleIpc,
},
_set_animations_config, _set_blur_config, _set_damage_visualization, _set_layer_rules,
Axis,
client::Client,
config, config_dir,
exec::{Command, set_env, unset_env},
@ -1471,6 +1476,8 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
persistent.window_rules.set(window_rules);
push_layer_rules(&config.layer_rules);
push_blur_config(config.blur);
push_damage_visualization(config.damage_visualization);
push_animations_config(config.animations);
state.set_status(&config.status);
persistent.actions.borrow_mut().clear();
for a in config.named_actions {
@ -1720,6 +1727,33 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
}
}
fn push_animations_config(anim: Option<AnimationsConfig>) {
let default = AnimationsConfigIpc::default();
let to_ipc = |c: AnimationCurve| match c {
AnimationCurve::Linear => AnimationCurveIpc::Linear,
AnimationCurve::EaseOut => AnimationCurveIpc::EaseOut,
AnimationCurve::EaseInOut => AnimationCurveIpc::EaseInOut,
AnimationCurve::Bezier { x1, y1, x2, y2 } => AnimationCurveIpc::Bezier { x1, y1, x2, y2 },
};
let cfg = match anim {
Some(a) => AnimationsConfigIpc {
enabled: a.enabled.unwrap_or(default.enabled),
open_duration_ms: a
.open_duration_ms
.unwrap_or(default.open_duration_ms)
.clamp(0, 10_000),
open_curve: to_ipc(a.open_curve.unwrap_or(AnimationCurve::EaseOut)),
close_duration_ms: a
.close_duration_ms
.unwrap_or(default.close_duration_ms)
.clamp(0, 10_000),
close_curve: to_ipc(a.close_curve.unwrap_or(AnimationCurve::EaseOut)),
},
None => default,
};
_set_animations_config(cfg);
}
fn push_blur_config(blur: Option<BlurConfig>) {
let default = BlurConfigIpc::default();
let cfg = match blur {
@ -1732,6 +1766,19 @@ fn push_blur_config(blur: Option<BlurConfig>) {
_set_blur_config(cfg);
}
fn push_damage_visualization(dv: Option<crate::config::DamageVisualization>) {
let default = DamageVisualizationIpc::default();
let cfg = match dv {
Some(d) => DamageVisualizationIpc {
enabled: d.enabled.unwrap_or(default.enabled),
color: d.color.unwrap_or(default.color),
decay_millis: d.decay_ms.unwrap_or(default.decay_millis),
},
None => default,
};
_set_damage_visualization(cfg);
}
fn push_layer_rules(rules: &[LayerRule]) {
let ipc: Vec<LayerRuleIpc> = rules
.iter()