@@ -224,7 +224,12 @@ impl Daemon { |
| 224 | } | 224 | } |
| 225 | | 225 | |
| 226 | /// Attempt to establish/re-establish X11 connection | 226 | /// Attempt to establish/re-establish X11 connection |
| | 227 | + /// |
| | 228 | + /// On reconnection, refreshes `DISPLAY` from the systemd user environment |
| | 229 | + /// since the X display number may change across session restarts (e.g. `:0` -> `:1`). |
| 227 | fn try_connect_x11(&mut self) -> bool { | 230 | fn try_connect_x11(&mut self) -> bool { |
| | 231 | + Self::refresh_display_env(); |
| | 232 | + |
| 228 | match Connection::new() { | 233 | match Connection::new() { |
| 229 | Ok(conn) => { | 234 | Ok(conn) => { |
| 230 | let (width, height) = conn.screen_dimensions(); | 235 | let (width, height) = conn.screen_dimensions(); |
@@ -239,6 +244,42 @@ impl Daemon { |
| 239 | } | 244 | } |
| 240 | } | 245 | } |
| 241 | | 246 | |
| | 247 | + /// Refresh DISPLAY (and XAUTHORITY) from the systemd user manager environment. |
| | 248 | + /// |
| | 249 | + /// When the X session restarts, the display number can change (e.g. `:0` -> `:1`). |
| | 250 | + /// systemd's user manager gets updated via `systemctl --user import-environment`, |
| | 251 | + /// but a long-running daemon keeps the stale value in its own process environment. |
| | 252 | + fn refresh_display_env() { |
| | 253 | + let output = match std::process::Command::new("systemctl") |
| | 254 | + .args(["--user", "show-environment"]) |
| | 255 | + .output() |
| | 256 | + { |
| | 257 | + Ok(o) if o.status.success() => o, |
| | 258 | + _ => return, |
| | 259 | + }; |
| | 260 | + |
| | 261 | + let env_str = match std::str::from_utf8(&output.stdout) { |
| | 262 | + Ok(s) => s, |
| | 263 | + Err(_) => return, |
| | 264 | + }; |
| | 265 | + |
| | 266 | + for line in env_str.lines() { |
| | 267 | + if let Some(val) = line.strip_prefix("DISPLAY=") { |
| | 268 | + let current = std::env::var("DISPLAY").unwrap_or_default(); |
| | 269 | + if current != val { |
| | 270 | + tracing::info!("DISPLAY changed: {} -> {}", current, val); |
| | 271 | + std::env::set_var("DISPLAY", val); |
| | 272 | + } |
| | 273 | + } else if let Some(val) = line.strip_prefix("XAUTHORITY=") { |
| | 274 | + let current = std::env::var("XAUTHORITY").unwrap_or_default(); |
| | 275 | + if current != val { |
| | 276 | + tracing::info!("XAUTHORITY changed: {} -> {}", current, val); |
| | 277 | + std::env::set_var("XAUTHORITY", val); |
| | 278 | + } |
| | 279 | + } |
| | 280 | + } |
| | 281 | + } |
| | 282 | + |
| 242 | /// Check if X11 connection is alive | 283 | /// Check if X11 connection is alive |
| 243 | fn x11_is_alive(&self) -> bool { | 284 | fn x11_is_alive(&self) -> bool { |
| 244 | self.conn.as_ref().map(|c| c.is_alive()).unwrap_or(false) | 285 | self.conn.as_ref().map(|c| c.is_alive()).unwrap_or(false) |