@@ -1148,8 +1148,10 @@ impl WindowManager { |
| 1148 | 1148 | self.reload_config()?; |
| 1149 | 1149 | } |
| 1150 | 1150 | Action::Exit => { |
| 1151 | | - tracing::info!("Exit requested"); |
| 1151 | + tracing::info!("Exit requested, will exit event loop"); |
| 1152 | 1152 | self.running = false; |
| 1153 | + // Force an immediate return from event handling |
| 1154 | + return Ok(()); |
| 1153 | 1155 | } |
| 1154 | 1156 | Action::ToggleFloating => { |
| 1155 | 1157 | if let Some(window) = self.focused_window { |
@@ -1743,12 +1745,30 @@ impl WindowManager { |
| 1743 | 1745 | std::thread::sleep(std::time::Duration::from_millis(10)); |
| 1744 | 1746 | } |
| 1745 | 1747 | |
| 1748 | + // Unmap all managed windows so they don't persist on the X server |
| 1749 | + // This ensures windows aren't visible when returning to the greeter |
| 1750 | + tracing::info!("Unmapping {} managed windows", self.windows.len()); |
| 1751 | + for &window in self.windows.keys() { |
| 1752 | + tracing::debug!("Unmapping window {}", window); |
| 1753 | + let _ = self.conn.conn.unmap_window(window); |
| 1754 | + } |
| 1755 | + // Sync to ensure X server processes all unmap requests before we exit |
| 1756 | + let _ = self.conn.sync(); |
| 1757 | + tracing::info!("Windows unmapped and synced"); |
| 1758 | + |
| 1746 | 1759 | // Stop garbar if it was spawned |
| 1747 | 1760 | if let Some(ref mut child) = self.garbar_process { |
| 1748 | 1761 | stop_garbar(child); |
| 1749 | 1762 | } |
| 1750 | 1763 | self.garbar_process = None; |
| 1751 | 1764 | |
| 1765 | + // Kill picom to prevent compositor effects from bleeding into the greeter |
| 1766 | + tracing::info!("Killing picom..."); |
| 1767 | + let _ = std::process::Command::new("pkill") |
| 1768 | + .arg("-x") |
| 1769 | + .arg("picom") |
| 1770 | + .status(); |
| 1771 | + |
| 1752 | 1772 | // Signal systemd that graphical session has ended |
| 1753 | 1773 | // This stops user services bound to graphical-session.target (like garbg) |
| 1754 | 1774 | stop_graphical_session(); |