gardesk/gar / 592b9e2

Browse files

replace hardware DPMS with software blanking to prevent NVIDIA Xid 79 crashes

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
592b9e2fcc3af48f4a6cad6ae5332d3382cf58a6
Parents
e38ca11
Tree
e7598f6

1 changed file

StatusFile+-
M gar/src/config/mod.rs 29 38
gar/src/config/mod.rsmodified
@@ -415,63 +415,54 @@ wintypes:
415415
         let _ = Command::new("pkill").args(["-f", "garchomp"]).status();
416416
     }
417417
 
418
-    /// Apply screen timeout/DPMS settings using xset
418
+    /// Apply screen timeout settings using xset.
419
+    ///
420
+    /// Always disables hardware DPMS (causes Xid 79 GPU crashes on NVIDIA with
421
+    /// multi-monitor HDMI setups). Uses the X11 screen saver extension for software
422
+    /// blanking instead, which draws black without hardware power state changes.
419423
     pub fn apply_screen_timeout(&self) {
420424
         use std::process::Command;
421425
 
422
-        if self.screen_timeout_enabled {
423
-            // Enable DPMS and set timeout
424
-            let timeout = self.screen_timeout_seconds.to_string();
425
-            match Command::new("xset")
426
-                .args(["dpms", &timeout, &timeout, &timeout])
427
-                .status()
428
-            {
429
-                Ok(status) if status.success() => {
430
-                    tracing::info!("Set DPMS timeout to {} seconds", self.screen_timeout_seconds);
431
-                }
432
-                Ok(_) => tracing::warn!("xset dpms command failed"),
433
-                Err(e) => tracing::warn!("Failed to run xset: {}", e),
426
+        // Always disable hardware DPMS - it sends power state changes to monitors
427
+        // via the NVIDIA driver, which can crash the GPU (Xid 79) when HDMI displays
428
+        // have unreliable EDID links
429
+        match Command::new("xset").args(["dpms", "0", "0", "0"]).status() {
430
+            Ok(status) if status.success() => {
431
+                tracing::debug!("Disabled hardware DPMS timeouts");
434432
             }
433
+            Ok(_) => tracing::warn!("xset dpms 0 command failed"),
434
+            Err(e) => tracing::warn!("Failed to run xset: {}", e),
435
+        }
436
+        match Command::new("xset").args(["-dpms"]).status() {
437
+            Ok(_) => {}
438
+            Err(e) => tracing::warn!("Failed to disable DPMS: {}", e),
439
+        }
435440
 
436
-            // Enable screen saver with same timeout
441
+        if self.screen_timeout_enabled {
442
+            // Use X11 screen saver for software blanking (safe, no hardware power changes)
443
+            let timeout = self.screen_timeout_seconds.to_string();
437444
             match Command::new("xset")
438445
                 .args(["s", &timeout, &timeout])
439446
                 .status()
440447
             {
441448
                 Ok(status) if status.success() => {
442
-                    tracing::debug!("Set screen saver timeout to {} seconds", self.screen_timeout_seconds);
449
+                    tracing::info!(
450
+                        "Screen blanking enabled via X11 screen saver ({} seconds)",
451
+                        self.screen_timeout_seconds
452
+                    );
443453
                 }
444454
                 Ok(_) => tracing::warn!("xset s command failed"),
445455
                 Err(e) => tracing::warn!("Failed to run xset: {}", e),
446456
             }
447
-
448
-            // Make sure DPMS is enabled
449
-            match Command::new("xset").args(["+dpms"]).status() {
450
-                Ok(_) => {}
451
-                Err(e) => tracing::warn!("Failed to enable DPMS: {}", e),
452
-            }
453457
         } else {
454
-            // Disable DPMS and screen saver
455
-            match Command::new("xset").args(["dpms", "0", "0", "0"]).status() {
456
-                Ok(status) if status.success() => {
457
-                    tracing::info!("Disabled DPMS timeout");
458
-                }
459
-                Ok(_) => tracing::warn!("xset dpms 0 command failed"),
460
-                Err(e) => tracing::warn!("Failed to run xset: {}", e),
461
-            }
462
-
458
+            // Disable screen saver blanking too
463459
             match Command::new("xset").args(["s", "off"]).status() {
464460
                 Ok(status) if status.success() => {
465
-                    tracing::debug!("Disabled screen saver");
461
+                    tracing::info!("Screen blanking disabled");
466462
                 }
467463
                 Ok(_) => tracing::warn!("xset s off command failed"),
468464
                 Err(e) => tracing::warn!("Failed to run xset: {}", e),
469465
             }
470
-
471
-            match Command::new("xset").args(["-dpms"]).status() {
472
-                Ok(_) => {}
473
-                Err(e) => tracing::warn!("Failed to disable DPMS: {}", e),
474
-            }
475466
         }
476467
     }
477468
 
@@ -549,8 +540,8 @@ impl Default for Config {
549540
             notification_enabled: false,
550541
             // Monitor order: empty = sort by X position
551542
             monitor_order: Vec::new(),
552
-            // Screen timeout: disabled by default (DPMS causes Xid 79 GPU crashes on NVIDIA)
553
-            screen_timeout_enabled: false,
543
+            // Screen timeout: enabled by default (uses software blanking, never hardware DPMS)
544
+            screen_timeout_enabled: true,
554545
             screen_timeout_seconds: 600,
555546
             // Compositor selection: "picom" (default), "garchomp", or "none"
556547
             compositor: "picom".to_string(),