git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit0cf7c541a8ed28b8dc08276c8d5abd2d0fbfc044
parentb0a306e1d7
authorLucas Galante <[email protected]>
date2026-05-26 15:20
Update system configuration and interface modules

 src/config.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++----------
 src/ipc.rs    |  4 ++--
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/src/config.rs b/src/config.rs
index 4f30e19..90a1e79 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -74,9 +74,9 @@ pub struct LayoutConfig {
     pub hsplit_border_width: i64,
     #[serde(default = "default_floating_border_width")]
     pub floating_border_width: i64,
-    #[serde(default = "default_border_color")]
+    #[serde(default = "default_border_color", alias = "high_color")]
     pub border_color: String,
-    #[serde(default = "default_background_color")]
+    #[serde(default = "default_background_color", alias = "low_color")]
     pub background_color: String,
 }
 
@@ -228,6 +228,7 @@ pub struct StartupEntryConfig {
     pub exec: String,
     #[serde(default)]
     pub once: bool,
+    pub restart: Option<bool>,
 }
 
 #[derive(Debug, Deserialize)]
@@ -386,15 +387,38 @@ pub fn parse_config(path: &str, cold_start: bool, state: &mut WindowManager) ->
     );
     for (i, entry) in config.startup.iter().enumerate() {
         let name = extract_program_name(&entry.exec);
-        if entry.once && !cold_start {
+        let should_restart = entry.restart.unwrap_or(false);
+
+        if entry.once && !cold_start && !should_restart {
             eprintln!(
                 "[config] startup[{}]: exec=\"{}\" once=true → skipped (not cold start)",
                 i, entry.exec
             );
             continue;
         }
+
         let running = process_running(&name);
-        if running {
+        if should_restart && running {
+            eprintln!(
+                "[config] startup[{}]: exec=\"{}\" restart=true → killing existing process {}",
+                i, entry.exec, name
+            );
+            let mut pkill_cmd = std::process::Command::new("pkill");
+            if name.len() > 15 {
+                pkill_cmd.arg("-f").arg(&name);
+            } else {
+                pkill_cmd.arg("-x").arg(&name);
+            }
+            match pkill_cmd.status() {
+                Ok(status) => {
+                    eprintln!("[config] pkill status: {}", status);
+                }
+                Err(e) => {
+                    eprintln!("[config] failed to execute pkill: {:?}", e);
+                }
+            }
+            state.pending_startup_apps.push(entry.exec.clone());
+        } else if running {
             eprintln!("[config] startup[{}]: exec=\"{}\" once={} → skipped (already running, pgrep -x {})", i, entry.exec, entry.once, name);
         } else {
             eprintln!(
@@ -560,11 +584,13 @@ pub fn spawn_command_bg(cmd: &str) {
     };
 }
 pub fn process_running(name: &str) -> bool {
-    match std::process::Command::new("pgrep")
-        .arg("-x")
-        .arg(name)
-        .output()
-    {
+    let mut cmd = std::process::Command::new("pgrep");
+    if name.len() > 15 {
+        cmd.arg("-f").arg(name);
+    } else {
+        cmd.arg("-x").arg(name);
+    }
+    match cmd.output() {
         Ok(output) => output.status.success(),
         Err(_) => false,
     }
@@ -696,13 +722,21 @@ exec = "waybar"
 [[startup]]
 exec = "fuzzel"
 once = true
+
+[[startup]]
+exec = "clear-system-interface"
+once = true
+restart = true
 "#;
         let config: Config = toml::from_str(toml_str).expect("TOML parse failed");
-        assert_eq!(config.startup.len(), 2);
+        assert_eq!(config.startup.len(), 3);
         assert_eq!(config.startup[0].exec, "waybar");
         assert!(!config.startup[0].once);
         assert_eq!(config.startup[1].exec, "fuzzel");
         assert!(config.startup[1].once);
+        assert_eq!(config.startup[2].exec, "clear-system-interface");
+        assert!(config.startup[2].once);
+        assert_eq!(config.startup[2].restart, Some(true));
         assert_eq!(config.env.get("XDG_CURRENT_DESKTOP").unwrap(), "river");
     }
 
diff --git a/src/ipc.rs b/src/ipc.rs
index e51ee61..1e3560e 100644
--- a/src/ipc.rs
+++ b/src/ipc.rs
@@ -320,7 +320,7 @@ fn handle_layout_command(rest: &str, state: &mut WindowManager) {
                 }
             }
         }
-        "border_color" => {
+        "border_color" | "high_color" => {
             if let Some((r, g, b, a)) = parse_hex_color(value_str) {
                 state.layout.border_r = r;
                 state.layout.border_g = g;
@@ -331,7 +331,7 @@ fn handle_layout_command(rest: &str, state: &mut WindowManager) {
                 }
             }
         }
-        "background_color" => {
+        "background_color" | "low_color" => {
             if let Some((r, g, b, a)) = parse_hex_color(value_str) {
                 state.layout.background_r = r;
                 state.layout.background_g = g;