status bar
git clone https://git.lucas.co/cce-status-interface.git
refactor: canonical pointers for light_source_position and module sides
light_source_position gets one shared reader in config.rs at its real
location (window_manager { light_source_position }), replacing two
divergent copies — main.rs only degree-converted integers, modules.rs
only floats; now any value above 2pi is taken as legacy degrees. The
per-module side lookup reads /layout/status_bar/<name> (the key the
compositor persists super+drag snaps into) before falling back to the
fuzzy search, and get_module_side now uses the cached merged config
instead of re-parsing the shared file on its own.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/config.rs | 37 +++++++++++++++++++++++++++++++++++++
src/main.rs | 45 +++++++++++++++++++++++----------------------
src/modules.rs | 13 +------------
3 files changed, 61 insertions(+), 34 deletions(-)
diff --git a/src/config.rs b/src/config.rs
index 203d28c..7f36302 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -217,6 +217,26 @@ pub(crate) fn parse_font_for_alias(content: &str, alias: &str) -> Option<String>
None
}
+/// The DE-wide light angle, canonical at `window_manager { light_source_position }`.
+/// Radians normally; a value above 2π is taken as legacy degrees (e.g. `135`)
+/// and converted. (This unifies the two previous readers, one of which only
+/// degree-converted integer values.)
+pub(crate) fn light_source_position_from(val: &serde_json::Value) -> f32 {
+ let raw = pointer_or_fuzzy(val, "/window_manager/light_source_position", "light_source_position")
+ .and_then(|v| v.as_f64())
+ .map(|f| f as f32)
+ .unwrap_or(2.356_194_5); // 135°, the compositor default
+ if raw > 2.0 * std::f32::consts::PI {
+ raw.to_radians()
+ } else {
+ raw
+ }
+}
+
+pub(crate) fn read_light_source_position_from_config() -> f32 {
+ light_source_position_from(&get_cached_config())
+}
+
pub(crate) fn read_status_background_blur_from_config() -> f32 {
cfg_f32("/style/status/background_blur", "status_background_blur").unwrap_or(0.0)
}
@@ -421,6 +441,23 @@ style {
);
}
+ // --- light_source_position ---
+
+ #[test]
+ fn light_source_position_canonical_and_units() {
+ // Canonical location, radians as-is.
+ let val = parse_kdl("window_manager {\n light_source_position (f64)2.5\n}");
+ assert!((light_source_position_from(&val) - 2.5).abs() < 1e-6);
+
+ // A value above 2π is legacy degrees.
+ let val = parse_kdl("window_manager {\n light_source_position (f64)135.0\n}");
+ assert!((light_source_position_from(&val) - 135.0f32.to_radians()).abs() < 1e-6);
+
+ // Absent: the compositor's 135° default.
+ let val = serde_json::json!({});
+ assert!((light_source_position_from(&val) - 2.356_194_5).abs() < 1e-6);
+ }
+
// --- color space (spec: text = raw sRGB, quads = linearized) ---
#[test]
diff --git a/src/main.rs b/src/main.rs
index 0db839a..2ab14d1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -861,35 +861,21 @@ impl StatusApp {
fn get_module_side(name: &str) -> Side {
- let content = std::fs::read_to_string(cce_ui::config::get_config_path()).unwrap_or_default();
- let val = cce_ui::config::parse_kdl_to_json(&content);
- module_side_from_json(&val, name)
+ module_side_from_json(&get_cached_config(), name)
}
fn module_side_from_json(val: &serde_json::Value, name: &str) -> Side {
if name == "light_source" {
- let mut light_pos = 2.356194490192345_f32; // Default 135 deg in rad
- if let Some(wm_obj) = json_find_key(val, "window_manager") {
- if let Some(pos_val) = json_find_key(&wm_obj, "light_source_position") {
- if let Some(f) = pos_val.as_f64() {
- light_pos = f as f32;
- } else if let Some(i) = pos_val.as_i64() {
- let deg = i as f32;
- if deg > 2.0 * std::f32::consts::PI {
- light_pos = deg.to_radians();
- } else {
- light_pos = deg;
- }
- }
- }
- }
-
+ // The light module ignores any status_bar side entry: it sits on
+ // whichever side the configured light angle points at.
+ let light_pos = crate::config::light_source_position_from(val);
+
let two_pi = 2.0 * std::f32::consts::PI;
let mut angle = light_pos % two_pi;
if angle < 0.0 {
angle += two_pi;
}
-
+
let pi = std::f32::consts::PI;
// Side mapping: Left side is roughly [5pi/8, 11pi/8)
if angle >= 5.0 * pi / 8.0 && angle < 11.0 * pi / 8.0 {
@@ -899,7 +885,10 @@ fn module_side_from_json(val: &serde_json::Value, name: &str) -> Side {
}
}
- if let Some(side_val) = json_find_key(val, name) {
+ // Canonical: `layout { status_bar <name>="top-left" }` — the same key the
+ // compositor persists a super+drag snap into.
+ let pointer = format!("/layout/status_bar/{}", name);
+ if let Some(side_val) = pointer_or_fuzzy(val, &pointer, name) {
if let Some(side_str) = side_val.as_str() {
match side_str.to_lowercase().as_str() {
"left" | "top-left" | "bottom-left" | "top-center" | "bottom-center" => return Side::Left,
@@ -1901,6 +1890,17 @@ mod tests {
}
}
+ #[test]
+ fn module_side_canonical_location_wins() {
+ // `layout { status_bar clock="left" }` beats a stray same-named key
+ // the fuzzy fallback would otherwise find.
+ let val = serde_json::json!({
+ "layout": {"status_bar": {"clock": "left"}},
+ "stray": {"clock": "right"}
+ });
+ assert_eq!(module_side_from_json(&val, "clock"), Side::Left);
+ }
+
#[test]
fn module_side_defaults() {
let val = serde_json::json!({});
@@ -1927,8 +1927,9 @@ mod tests {
Side::Left
);
assert_eq!(module_side_from_json(&mk(serde_json::json!(0.0)), "light_source"), Side::Right);
- // Integers > 2π are degrees, otherwise radians.
+ // Values > 2π are degrees (int or float), otherwise radians.
assert_eq!(module_side_from_json(&mk(serde_json::json!(180)), "light_source"), Side::Left);
+ assert_eq!(module_side_from_json(&mk(serde_json::json!(135.0)), "light_source"), Side::Left);
assert_eq!(module_side_from_json(&mk(serde_json::json!(3)), "light_source"), Side::Left);
assert_eq!(module_side_from_json(&mk(serde_json::json!(0)), "light_source"), Side::Right);
}
diff --git a/src/modules.rs b/src/modules.rs
index 156569c..04a1280 100644
--- a/src/modules.rs
+++ b/src/modules.rs
@@ -729,18 +729,7 @@ impl StatusModule for TrayModule {
pub struct LightSourceModule;
pub(crate) fn get_light_source_pos_from_config() -> f32 {
- let val = crate::get_cached_config();
- if let Some(pos_val) = crate::json_find_key(&val, "light_source_position") {
- if let Some(f) = pos_val.as_f64() {
- let val = f as f32;
- if val > 2.0 * std::f32::consts::PI {
- return val.to_radians();
- } else {
- return val;
- }
- }
- }
- 2.35619
+ crate::config::read_light_source_position_from_config()
}
impl StatusModule for LightSourceModule {