@@ -80,14 +80,51 @@ pub fn run() { |
| 80 | Ok(()) | 80 | Ok(()) |
| 81 | }) | 81 | }) |
| 82 | .on_window_event(|window, event| { | 82 | .on_window_event(|window, event| { |
| 83 | - if let tauri::WindowEvent::Destroyed = event { | 83 | + match event { |
| 84 | - // Best-effort cache flush + reap every live PTY so | 84 | + tauri::WindowEvent::Destroyed => { |
| 85 | - // we don't leave zombie claude subprocesses running | 85 | + // Best-effort cache flush + reap every live PTY so |
| 86 | - // after a hard app quit. | 86 | + // we don't leave zombie claude subprocesses running |
| 87 | - if let Some(state) = window.app_handle().try_state::<commands::AppState>() { | 87 | + // after a hard app quit. |
| 88 | - commands::persist_cache_on_exit(&state); | 88 | + if let Some(state) = |
| 89 | - commands::shutdown_active_ptys(&state); | 89 | + window.app_handle().try_state::<commands::AppState>() |
| | 90 | + { |
| | 91 | + commands::persist_cache_on_exit(&state); |
| | 92 | + commands::shutdown_active_ptys(&state); |
| | 93 | + } |
| 90 | } | 94 | } |
| | 95 | + tauri::WindowEvent::Resized(_) => { |
| | 96 | + // macOS moves the window when an external monitor |
| | 97 | + // disconnects. If the new position is fully |
| | 98 | + // off-screen the user can't see it. Re-center as |
| | 99 | + // a safety net. |
| | 100 | + if let Ok(pos) = window.outer_position() { |
| | 101 | + if let Ok(size) = window.outer_size() { |
| | 102 | + // Heuristic: if the window's left+width or |
| | 103 | + // top+height places it entirely off-screen |
| | 104 | + // (negative right edge or top below a |
| | 105 | + // reasonable bound), re-center it. We |
| | 106 | + // can't easily enumerate monitors from |
| | 107 | + // Tauri, so check against reasonable |
| | 108 | + // bounds: right edge < 0 OR left edge > |
| | 109 | + // 6000 OR top edge > 4000 OR bottom < 0. |
| | 110 | + let right = pos.x + size.width as i32; |
| | 111 | + let bottom = pos.y + size.height as i32; |
| | 112 | + if right < 0 |
| | 113 | + || pos.x > 6000 |
| | 114 | + || bottom < 0 |
| | 115 | + || pos.y > 4000 |
| | 116 | + { |
| | 117 | + tracing::info!( |
| | 118 | + x = pos.x, |
| | 119 | + y = pos.y, |
| | 120 | + "window off-screen after resize, re-centering" |
| | 121 | + ); |
| | 122 | + let _ = window.center(); |
| | 123 | + } |
| | 124 | + } |
| | 125 | + } |
| | 126 | + } |
| | 127 | + _ => {} |
| 91 | } | 128 | } |
| 92 | }) | 129 | }) |
| 93 | .invoke_handler(tauri::generate_handler![ | 130 | .invoke_handler(tauri::generate_handler![ |