Self-heal off-screen main window instead of requiring quit/relaunch

macOS's built-in window-restore (Resume) can place the window at
coordinates for a display that's no longer connected, leaving it
visible-but-invisible with no way to recover short of quitting. Now
re-centers automatically on app activate/Dock reopen, plus a manual
"Reset Window Position" menu command as a guaranteed fallback.
This commit is contained in:
2026-08-18 14:20:17 +02:00
parent f3593dc23d
commit f5fd09ac33
2 changed files with 94 additions and 0 deletions
+45
View File
@@ -53,6 +53,41 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
return shouldTerminate ? .terminateNow : .terminateCancel return shouldTerminate ? .terminateNow : .terminateCancel
} }
// macOS's built-in window-restoration (Resume) can place the main window at coordinates
// that no longer correspond to any connected display (e.g. it was last positioned on an
// external monitor that's now disconnected). The window is still technically "visible"
// (isVisible == true), so clicking the Dock icon or Cmd+Tab-ing to the app doesn't trigger
// any of the usual recovery paths the process runs fine, there's just nothing on screen.
// Self-heal by re-centering any main-sized window that doesn't intersect a current screen,
// both whenever the app becomes active and when the Dock icon is clicked with the app
// already running.
func applicationDidBecomeActive(_ notification: Notification) {
AppDelegate.repositionOffscreenWindows()
}
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
AppDelegate.repositionOffscreenWindows()
return true
}
/// Pure geometry check, kept separate from AppKit so it's directly testable.
nonisolated static func isFrameOffscreen(_ frame: CGRect, screenFrames: [CGRect]) -> Bool {
!screenFrames.contains { $0.intersects(frame) }
}
/// Re-centers the main window if it's off-screen, or unconditionally when `force` is true
/// (used by the manual "Reset Window Position" menu command).
static func repositionOffscreenWindows(force: Bool = false) {
let screenFrames = NSScreen.screens.map(\.frame)
for window in NSApp.windows where window.isVisible && !(window is NSPanel) && window.frame.width > 200 && window.frame.height > 200 {
if force || isFrameOffscreen(window.frame, screenFrames: screenFrames) {
window.center()
}
window.makeKeyAndOrderFront(nil)
}
NSApp.activate(ignoringOtherApps: true)
}
// `chatViewModel` is wired from `ContentView.onAppear`, not from `oAIApp.init()` reading // `chatViewModel` is wired from `ContentView.onAppear`, not from `oAIApp.init()` reading
// the `@State private var chatViewModel` there returns a throwaway instance distinct from // the `@State private var chatViewModel` there returns a throwaway instance distinct from
// the one SwiftUI actually renders (confirmed via ObjectIdentifier logging: two different // the one SwiftUI actually renders (confirmed via ObjectIdentifier logging: two different
@@ -217,6 +252,16 @@ struct oAIApp: App {
chatViewModel.onlineMode.toggle() chatViewModel.onlineMode.toggle()
} }
.keyboardShortcut("o", modifiers: [.command, .shift]) .keyboardShortcut("o", modifiers: [.command, .shift])
Divider()
// Fallback for when the window ends up off-screen (stale macOS window-restore
// coordinates, e.g. after an external monitor is disconnected) see
// AppDelegate.repositionOffscreenWindows. No keyboard shortcut assigned yet;
// add one once it's been live-verified against macOS's reserved bindings.
Button("Reset Window Position") {
AppDelegate.repositionOffscreenWindows(force: true)
}
} }
// Help menu // Help menu
+49
View File
@@ -0,0 +1,49 @@
//
// WindowPositionTests.swift
// oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
import Testing
import Foundation
import CoreGraphics
@testable import Confab
@Suite("Off-screen window detection")
struct WindowPositionTests {
private let mainScreen = CGRect(x: 0, y: 0, width: 2560, height: 1664)
@Test("Window inside the only connected screen is not off-screen")
func onscreenWindow() {
let frame = CGRect(x: 100, y: 100, width: 1024, height: 800)
#expect(AppDelegate.isFrameOffscreen(frame, screenFrames: [mainScreen]) == false)
}
@Test("Window at coordinates from a now-disconnected external display is off-screen")
func offscreenWindow() {
// e.g. previously positioned on an external monitor to the right of the built-in display
let frame = CGRect(x: 3000, y: 200, width: 1024, height: 800)
#expect(AppDelegate.isFrameOffscreen(frame, screenFrames: [mainScreen]) == true)
}
@Test("Window merely partially overlapping a screen counts as on-screen")
func partiallyOverlappingWindow() {
let frame = CGRect(x: 2500, y: 100, width: 1024, height: 800)
#expect(AppDelegate.isFrameOffscreen(frame, screenFrames: [mainScreen]) == false)
}
@Test("Off-screen relative to one display but onscreen on a second connected display")
func multiMonitorOnscreen() {
let secondScreen = CGRect(x: 2560, y: 0, width: 1920, height: 1080)
let frame = CGRect(x: 3000, y: 200, width: 1024, height: 800)
#expect(AppDelegate.isFrameOffscreen(frame, screenFrames: [mainScreen, secondScreen]) == false)
}
@Test("No connected screens means every window is off-screen")
func noScreens() {
let frame = CGRect(x: 100, y: 100, width: 1024, height: 800)
#expect(AppDelegate.isFrameOffscreen(frame, screenFrames: []) == true)
}
}