gardesk/gar / b44d141

Browse files

add compositor selection and focus_follows_mouse

- Add compositor config option: picom, garchomp, or none
- Add focus_follows_mouse setting (default: true)
- Add start_compositor() and stop_compositor() methods
- Generate picom config only when using picom
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
b44d1414dcf1627ddd01793f526df91a031c76be
Parents
bb18f1e
Tree
00020d9

3 changed files

StatusFile+-
M gar/src/config/lua.rs 18 0
M gar/src/config/mod.rs 70 1
M gar/src/core/mod.rs 2 4
gar/src/config/lua.rsmodified
@@ -383,11 +383,29 @@ impl LuaConfig {
383383
                         state.config.mouse_follows_focus = v;
384384
                     }
385385
                 }
386
+                "focus_follows_mouse" => {
387
+                    if let Value::Boolean(v) = value {
388
+                        state.config.focus_follows_mouse = v;
389
+                    }
390
+                }
386391
                 "bar_height" => {
387392
                     if let Value::Integer(v) = value {
388393
                         state.config.bar_height = v as u32;
389394
                     }
390395
                 }
396
+                // Compositor selection: "picom", "garchomp", or "none"
397
+                "compositor" => {
398
+                    if let Value::String(s) = value {
399
+                        if let Ok(str_val) = s.to_str() {
400
+                            let comp = str_val.to_lowercase();
401
+                            if comp == "picom" || comp == "garchomp" || comp == "none" {
402
+                                state.config.compositor = comp;
403
+                            } else {
404
+                                tracing::warn!("Unknown compositor '{}', using 'picom'", str_val);
405
+                            }
406
+                        }
407
+                    }
408
+                }
391409
                 // Compositor visual settings (picom)
392410
                 "corner_radius" => {
393411
                     if let Value::Integer(v) = value {
gar/src/config/mod.rsmodified
@@ -31,6 +31,7 @@ pub struct Config {
3131
     // Behavior settings
3232
     pub follow_window_on_move: bool,
3333
     pub mouse_follows_focus: bool,
34
+    pub focus_follows_mouse: bool,
3435
     // Manual bar/panel reserved space (overrides struts)
3536
     pub bar_height: u32,
3637
     // garbar integration: spawn garbar automatically if gar.bar is configured
@@ -43,6 +44,8 @@ pub struct Config {
4344
     // Screen timeout/DPMS settings
4445
     pub screen_timeout_enabled: bool,
4546
     pub screen_timeout_seconds: u32,
47
+    // Compositor selection: "picom" (default), "garchomp", or "none"
48
+    pub compositor: String,
4649
     // Compositor visual settings (picom)
4750
     // These are stored for reference and potential dynamic picom config generation
4851
     pub corner_radius: u32,
@@ -326,8 +329,15 @@ wintypes:
326329
         )
327330
     }
328331
 
329
-    /// Write picom config to ~/.config/gar/picom.conf and signal picom to reload.
332
+    /// Write picom config to ~/.config/gar/picom.conf and optionally restart picom.
333
+    /// Only writes/restarts if compositor is set to "picom".
330334
     pub fn write_picom_config(&self) -> std::io::Result<()> {
335
+        // Only generate picom config if using picom
336
+        if self.compositor != "picom" {
337
+            tracing::debug!("Skipping picom config (compositor={})", self.compositor);
338
+            return Ok(());
339
+        }
340
+
331341
         let config_dir = dirs::config_dir()
332342
             .ok_or_else(|| std::io::Error::new(
333343
                 std::io::ErrorKind::NotFound,
@@ -350,6 +360,61 @@ wintypes:
350360
         Ok(())
351361
     }
352362
 
363
+    /// Start the configured compositor.
364
+    /// Called on gar startup to launch the appropriate compositor.
365
+    pub fn start_compositor(&self) {
366
+        use std::process::Command;
367
+
368
+        match self.compositor.as_str() {
369
+            "picom" => {
370
+                // Generate picom config first
371
+                if let Err(e) = self.write_picom_config() {
372
+                    tracing::warn!("Failed to write picom config: {}", e);
373
+                }
374
+                // picom will be started by write_picom_config -> reload_picom
375
+            }
376
+            "garchomp" => {
377
+                // Kill any existing compositor first
378
+                let _ = Command::new("pkill").arg("picom").status();
379
+                let _ = Command::new("pkill").arg("garchomp").status();
380
+
381
+                std::thread::sleep(std::time::Duration::from_millis(100));
382
+
383
+                // Start garchomp
384
+                match Command::new("garchomp").spawn() {
385
+                    Ok(_) => {
386
+                        tracing::info!("Started garchomp compositor");
387
+                    }
388
+                    Err(e) => {
389
+                        tracing::error!("Failed to start garchomp: {}", e);
390
+                        // Fall back to picom
391
+                        tracing::info!("Falling back to picom");
392
+                        Self::reload_picom();
393
+                    }
394
+                }
395
+            }
396
+            "none" => {
397
+                tracing::info!("Compositor disabled (compositor=none)");
398
+                // Kill any running compositor
399
+                let _ = Command::new("pkill").arg("picom").status();
400
+                let _ = Command::new("pkill").arg("garchomp").status();
401
+            }
402
+            _ => {
403
+                tracing::warn!("Unknown compositor '{}', defaulting to picom", self.compositor);
404
+                if let Err(e) = self.write_picom_config() {
405
+                    tracing::warn!("Failed to write picom config: {}", e);
406
+                }
407
+            }
408
+        }
409
+    }
410
+
411
+    /// Stop any running compositor.
412
+    pub fn stop_compositor() {
413
+        use std::process::Command;
414
+        let _ = Command::new("pkill").arg("picom").status();
415
+        let _ = Command::new("pkill").arg("garchomp").status();
416
+    }
417
+
353418
     /// Apply screen timeout/DPMS settings using xset
354419
     pub fn apply_screen_timeout(&self) {
355420
         use std::process::Command;
@@ -474,6 +539,8 @@ impl Default for Config {
474539
             follow_window_on_move: false,
475540
             // Behavior: warp mouse pointer to center of focused window
476541
             mouse_follows_focus: false,
542
+            // Behavior: focus window when mouse enters it
543
+            focus_follows_mouse: true,
477544
             // Manual bar height (0 = use struts from dock windows)
478545
             bar_height: 0,
479546
             // garbar not enabled by default (enabled when gar.bar table is set)
@@ -485,6 +552,8 @@ impl Default for Config {
485552
             // Screen timeout: enabled by default with 10 minute timeout
486553
             screen_timeout_enabled: true,
487554
             screen_timeout_seconds: 600,
555
+            // Compositor selection: "picom" (default), "garchomp", or "none"
556
+            compositor: "picom".to_string(),
488557
             // Compositor settings (picom) - matching picom.conf defaults
489558
             corner_radius: 12,
490559
             blur_enabled: true,
gar/src/core/mod.rsmodified
@@ -75,10 +75,8 @@ impl WindowManager {
7575
         // Get config values from Lua state
7676
         let config = lua_state.lock().unwrap().config.clone();
7777
 
78
-        // Generate picom config from settings
79
-        if let Err(e) = config.write_picom_config() {
80
-            tracing::warn!("Failed to generate picom config: {}", e);
81
-        }
78
+        // Start the configured compositor (picom, garchomp, or none)
79
+        config.start_compositor();
8280
 
8381
         // Apply screen timeout/DPMS settings
8482
         config.apply_screen_timeout();