Preserve live dimming settings and stabilize theme transition borders
This commit is contained in:
1 parent
dec4d54bd4
commit
9e966f81a0
9 files changed
+102
-30
No files matched your search
@@ -94,16 +94,13 @@ impl Config {
|
||||
|
||||
pub(crate) fn resolved_theme_settings(
|
||||
theme: &ferese_config::theme::ResolvedTheme,
|
||||
inactive_dim: InactiveDimSettings,
|
||||
) -> Result<ThemeSettings, ConfigError> {
|
||||
let config = Self {
|
||||
theme: serde_json::from_value(serde_json::to_value(&theme.tokens).unwrap())
|
||||
.expect("resolved theme matches runtime schema"),
|
||||
..Self::default()
|
||||
};
|
||||
let mut settings = config.theme_settings()?;
|
||||
settings.inactive_dim = inactive_dim;
|
||||
Ok(settings)
|
||||
config.theme_settings()
|
||||
}
|
||||
|
||||
pub(crate) fn runtime_config(&self) -> Result<crate::RuntimeConfig, ConfigError> {
|
||||
@@ -126,6 +123,7 @@ impl Config {
|
||||
bindings,
|
||||
window_rules: self.window_rules()?,
|
||||
theme_settings: self.theme_settings()?,
|
||||
inactive_dim: self.inactive_dim_settings()?,
|
||||
default_column_width: self.default_column_width()?,
|
||||
scrolling_focus_strategy: self.scrolling_focus_strategy(),
|
||||
column_width_presets: self.width_presets()?,
|
||||
@@ -622,11 +620,6 @@ mod tests {
|
||||
bar_background_color: RgbaColor([17.0 / 255.0, 24.0 / 255.0, 33.0 / 255.0, 1.0,]),
|
||||
text_primary_color: RgbaColor([244.0 / 255.0, 247.0 / 255.0, 251.0 / 255.0, 1.0]),
|
||||
shell_opacity: 0.78,
|
||||
inactive_dim: InactiveDimSettings {
|
||||
enabled: false,
|
||||
amount: 0.15,
|
||||
duration_ms: 150.0
|
||||
},
|
||||
window_radius: 12.0,
|
||||
shadow_offset_y: -2.0,
|
||||
shadow_blur: 24.0,
|
||||
@@ -756,15 +749,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn inactive_dimming_is_opt_in_and_configurable() {
|
||||
let defaults = parse("").theme_settings().unwrap().inactive_dim;
|
||||
let defaults = parse("").inactive_dim_settings().unwrap();
|
||||
assert!(!defaults.enabled);
|
||||
assert_eq!(defaults.amount, 0.15);
|
||||
assert_eq!(defaults.duration_ms, 150.0);
|
||||
let settings =
|
||||
parse("appearance {\n inactive-dim {\n enabled #true\n amount 0.25\n duration-ms 100\n }\n}\n")
|
||||
.theme_settings()
|
||||
.unwrap()
|
||||
.inactive_dim;
|
||||
.inactive_dim_settings()
|
||||
.unwrap();
|
||||
assert!(settings.enabled);
|
||||
assert_eq!(settings.amount, 0.25);
|
||||
assert_eq!(settings.duration_ms, 100.0);
|
||||
@@ -777,7 +769,7 @@ mod tests {
|
||||
] {
|
||||
assert!(
|
||||
Config::parse_source(&format!("appearance {{ inactive-dim {{ {key} {value}; }} }}"))
|
||||
.and_then(|config| config.theme_settings())
|
||||
.and_then(|config| config.runtime_config())
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
use super::*;
|
||||
|
||||
impl Config {
|
||||
pub(crate) fn inactive_dim_settings(&self) -> Result<InactiveDimSettings, ConfigError> {
|
||||
Ok(InactiveDimSettings {
|
||||
enabled: self.appearance.inactive_dim.enabled,
|
||||
amount: unit_theme_value(self.appearance.inactive_dim.amount, "appearance.inactive_dim.amount")?,
|
||||
duration_ms: nonnegative_theme_value(
|
||||
self.appearance.inactive_dim.duration_ms,
|
||||
"appearance.inactive_dim.duration_ms",
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn theme_settings(&self) -> Result<ThemeSettings, ConfigError> {
|
||||
let border_width = nonnegative_theme_value(self.theme.geometry.border_width, "geometry.border_width")?;
|
||||
let focus_ring_width =
|
||||
@@ -39,14 +50,6 @@ impl Config {
|
||||
"surface.bar.background",
|
||||
)?,
|
||||
shell_opacity: unit_theme_value(self.theme.material.opacity, "material.opacity")?,
|
||||
inactive_dim: InactiveDimSettings {
|
||||
enabled: self.appearance.inactive_dim.enabled,
|
||||
amount: unit_theme_value(self.appearance.inactive_dim.amount, "appearance.inactive_dim.amount")?,
|
||||
duration_ms: nonnegative_theme_value(
|
||||
self.appearance.inactive_dim.duration_ms,
|
||||
"appearance.inactive_dim.duration_ms",
|
||||
)?,
|
||||
},
|
||||
window_radius,
|
||||
shadow_offset_y,
|
||||
shadow_blur,
|
||||
@@ -210,7 +213,6 @@ pub struct ThemeSettings {
|
||||
pub bar_background_color: RgbaColor,
|
||||
pub text_primary_color: RgbaColor,
|
||||
pub shell_opacity: f64,
|
||||
pub inactive_dim: InactiveDimSettings,
|
||||
pub window_radius: f64,
|
||||
pub shadow_offset_y: f64,
|
||||
pub shadow_blur: f64,
|
||||
|
||||
@@ -194,6 +194,62 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn live_reload_keeps_dimming_policy_independent_of_theme_transitions() {
|
||||
if std::env::var_os("FERESE_DIM_RELOAD_TEST_CHILD").is_none() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let directory = Directory::new();
|
||||
std::fs::set_permissions(&directory.0, std::fs::Permissions::from_mode(0o700)).unwrap();
|
||||
let output = std::process::Command::new(std::env::current_exe().unwrap())
|
||||
.args([
|
||||
"--exact",
|
||||
"reload::tests::live_reload_keeps_dimming_policy_independent_of_theme_transitions",
|
||||
"--nocapture",
|
||||
])
|
||||
.env("FERESE_DIM_RELOAD_TEST_CHILD", "1")
|
||||
.env("XDG_RUNTIME_DIR", &directory.0)
|
||||
.env("XDG_CONFIG_HOME", &directory.0)
|
||||
.env_remove("FERESE_SOCKET")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{}\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
return;
|
||||
}
|
||||
let source = "appearance { inactive-dim { enabled #true; amount 0.25; }; }";
|
||||
let directory = Directory::new();
|
||||
let (_, runtime, candidate) = crate::theme::prepare(source, &directory.0).unwrap();
|
||||
let mut event_loop = smithay::reexports::calloop::EventLoop::try_new().unwrap();
|
||||
let display = smithay::reexports::wayland_server::Display::new().unwrap();
|
||||
let mut state = crate::Ferese::new(&mut event_loop, display, runtime).unwrap();
|
||||
state.config_source = Some(source.into());
|
||||
state.theme_engine.snapshot.theme = candidate.theme.clone();
|
||||
state.theme_engine.snapshot.presented = candidate.theme;
|
||||
|
||||
for enabled in [false, true, false] {
|
||||
let source = format!("appearance {{ inactive-dim {{ enabled #{enabled}; amount 0.25; }}; }}");
|
||||
state.reload_config_source(source).unwrap();
|
||||
assert_eq!(state.inactive_dim.enabled, enabled);
|
||||
let opacity = crate::dimming::target(
|
||||
state.inactive_dim,
|
||||
Some(ferese_layout::WindowId(1)),
|
||||
ferese_layout::WindowId(2),
|
||||
false,
|
||||
);
|
||||
assert_eq!(opacity, if enabled { 0.25 } else { 0.0 });
|
||||
}
|
||||
state
|
||||
.reload_config_source("appearance { inactive-dim { enabled #false; }; }; theme { mode \"light\"; }".into())
|
||||
.unwrap();
|
||||
state.poll_theme();
|
||||
assert!(!state.inactive_dim.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_validation_rejects_bad_edits_before_application() {
|
||||
for source in [
|
||||
|
||||
@@ -372,6 +372,7 @@ pub struct Ferese {
|
||||
window_rules: Vec<WindowRule>,
|
||||
window_rules_applied: HashSet<WindowId>,
|
||||
pub(crate) theme_settings: ThemeSettings,
|
||||
pub(crate) inactive_dim: crate::config::InactiveDimSettings,
|
||||
animations_enabled: bool,
|
||||
animation_speed: f64,
|
||||
spring_config: SpringConfig,
|
||||
@@ -450,6 +451,7 @@ pub struct RuntimeConfig {
|
||||
pub workspace_auto_back_and_forth: bool,
|
||||
pub window_rules: Vec<WindowRule>,
|
||||
pub theme_settings: ThemeSettings,
|
||||
pub inactive_dim: crate::config::InactiveDimSettings,
|
||||
pub default_column_width: ColumnWidth,
|
||||
pub scrolling_focus_strategy: ViewportFocusStrategy,
|
||||
pub column_width_presets: Vec<ColumnWidth>,
|
||||
@@ -602,6 +604,7 @@ impl Ferese {
|
||||
window_rules: config.window_rules,
|
||||
window_rules_applied: HashSet::new(),
|
||||
theme_settings: config.theme_settings,
|
||||
inactive_dim: config.inactive_dim,
|
||||
animations_enabled: config.animations_enabled,
|
||||
animation_speed: config.animation_speed,
|
||||
spring_config: config.spring_config,
|
||||
@@ -739,6 +742,7 @@ impl Ferese {
|
||||
self.portal_shortcuts.reconcile(&self.bindings, &self.input_settings);
|
||||
let old_rules = std::mem::replace(&mut self.window_rules, config.window_rules);
|
||||
self.theme_settings = config.theme_settings;
|
||||
self.inactive_dim = config.inactive_dim;
|
||||
self.column_width_presets = config.column_width_presets;
|
||||
self.animations_enabled = config.animations_enabled;
|
||||
if !self.animations_enabled {
|
||||
|
||||
@@ -69,7 +69,7 @@ impl Ferese {
|
||||
active
|
||||
});
|
||||
|
||||
let dim_settings = self.theme_settings.inactive_dim;
|
||||
let dim_settings = self.inactive_dim;
|
||||
let duration = if self.animations_enabled {
|
||||
dim_settings.duration_ms
|
||||
} else {
|
||||
|
||||
@@ -562,8 +562,7 @@ impl Ferese {
|
||||
} else {
|
||||
transition.from.transition(target, progress)
|
||||
};
|
||||
self.theme_settings = Config::resolved_theme_settings(&presented, self.theme_settings.inactive_dim)
|
||||
.expect("validated resolved theme");
|
||||
self.theme_settings = Config::resolved_theme_settings(&presented).expect("validated resolved theme");
|
||||
self.theme_engine.snapshot.presented = presented;
|
||||
self.theme_engine.publish();
|
||||
self.backdrop_generation = self.backdrop_generation.wrapping_add(1);
|
||||
|
||||
Reference in new issue
Block a user