@@ -253,12 +253,19 @@ impl HyprKvmGui { |
| 253 | let _ = reader.read_line(&mut response); | 253 | let _ = reader.read_line(&mut response); |
| 254 | } | 254 | } |
| 255 | // Give daemon time to shutdown | 255 | // Give daemon time to shutdown |
| 256 | - std::thread::sleep(std::time::Duration::from_millis(500)); | 256 | + std::thread::sleep(std::time::Duration::from_millis(1000)); |
| 257 | } | 257 | } |
| 258 | | 258 | |
| 259 | // Now spawn a new daemon process | 259 | // Now spawn a new daemon process |
| | 260 | + // Try current_exe first, fall back to PATH lookup |
| 260 | let exe = std::env::current_exe().unwrap_or_else(|_| "hyprkvm".into()); | 261 | let exe = std::env::current_exe().unwrap_or_else(|_| "hyprkvm".into()); |
| 261 | - match Command::new(&exe) | 262 | + tracing::info!("Restarting daemon with exe: {:?}", exe); |
| | 263 | + |
| | 264 | + // Use setsid to create a new session so daemon survives GUI exit |
| | 265 | + // This is the Unix way to properly daemonize |
| | 266 | + match Command::new("setsid") |
| | 267 | + .arg("--fork") |
| | 268 | + .arg(&exe) |
| 262 | .arg("daemon") | 269 | .arg("daemon") |
| 263 | .stdin(std::process::Stdio::null()) | 270 | .stdin(std::process::Stdio::null()) |
| 264 | .stdout(std::process::Stdio::null()) | 271 | .stdout(std::process::Stdio::null()) |
@@ -267,14 +274,44 @@ impl HyprKvmGui { |
| 267 | { | 274 | { |
| 268 | Ok(_) => { | 275 | Ok(_) => { |
| 269 | // Wait a moment for daemon to start | 276 | // Wait a moment for daemon to start |
| 270 | - std::thread::sleep(std::time::Duration::from_millis(500)); | 277 | + std::thread::sleep(std::time::Duration::from_millis(1000)); |
| 271 | - self.state.error = None; | 278 | + |
| 272 | - self.state.needs_restart = false; | 279 | + // Verify daemon actually started by checking socket |
| 273 | - self.state.success = Some("Daemon restarted".to_string()); | 280 | + if UnixStream::connect(&socket_path).is_ok() { |
| | 281 | + self.state.error = None; |
| | 282 | + self.state.needs_restart = false; |
| | 283 | + self.state.success = Some("Daemon restarted".to_string()); |
| | 284 | + } else { |
| | 285 | + self.state.error = Some("Daemon spawn succeeded but socket not available".to_string()); |
| | 286 | + self.state.needs_restart = true; |
| | 287 | + } |
| 274 | } | 288 | } |
| 275 | Err(e) => { | 289 | Err(e) => { |
| 276 | - self.state.error = Some(format!("Failed to start daemon: {}", e)); | 290 | + // setsid not available, try direct spawn |
| 277 | - self.state.needs_restart = false; | 291 | + tracing::warn!("setsid failed: {}, trying direct spawn", e); |
| | 292 | + match Command::new(&exe) |
| | 293 | + .arg("daemon") |
| | 294 | + .stdin(std::process::Stdio::null()) |
| | 295 | + .stdout(std::process::Stdio::null()) |
| | 296 | + .stderr(std::process::Stdio::null()) |
| | 297 | + .spawn() |
| | 298 | + { |
| | 299 | + Ok(_) => { |
| | 300 | + std::thread::sleep(std::time::Duration::from_millis(1000)); |
| | 301 | + if UnixStream::connect(&socket_path).is_ok() { |
| | 302 | + self.state.error = None; |
| | 303 | + self.state.needs_restart = false; |
| | 304 | + self.state.success = Some("Daemon restarted".to_string()); |
| | 305 | + } else { |
| | 306 | + self.state.error = Some("Daemon spawn succeeded but socket not available".to_string()); |
| | 307 | + self.state.needs_restart = true; |
| | 308 | + } |
| | 309 | + } |
| | 310 | + Err(e2) => { |
| | 311 | + self.state.error = Some(format!("Failed to start daemon: {}", e2)); |
| | 312 | + self.state.needs_restart = false; |
| | 313 | + } |
| | 314 | + } |
| 278 | } | 315 | } |
| 279 | } | 316 | } |
| 280 | } | 317 | } |