from pathlib import Path from datetime import datetime import shutil root = Path.cwd() path = root / "OrionToolbar/OrionMenuView.swift" if not path.is_file(): raise SystemExit("ERROR: OrionMenuView.swift not found.") source = path.read_text() marker = "// A MenuBarExtra window is transient." if marker not in source: raise SystemExit( "ERROR: Existing Settings presenter not found. " "No changes made." ) # The presenter is the final declaration in the file. prefix, existing = source.split(marker, 1) if "private final class OrionSettingsWindowPresenter" not in existing: raise SystemExit( "ERROR: Unexpected Settings presenter. No changes made." ) replacement = r'''// Settings must be independent of the transient MenuBarExtra panel. // An AppKit modal session keeps Settings open and blocks other app windows. @MainActor private final class OrionSettingsWindowPresenter: NSObject, NSWindowDelegate { private static var current: OrionSettingsWindowPresenter? private var window: NSWindow? private var modalSession: NSApplication.ModalSession? private var modalTimer: Timer? static func present(vm: OrionVMController) { if let current, let window = current.window { NSApp.activate(ignoringOtherApps: true) window.makeKeyAndOrderFront(nil) window.orderFrontRegardless() return } let presenter = OrionSettingsWindowPresenter() current = presenter presenter.open(vm: vm) } private func open(vm: OrionVMController) { let content = SettingsView() .environmentObject(vm) .preferredColorScheme(.dark) let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 650, height: 380), styleMask: [.titled, .closable], backing: .buffered, defer: false ) window.title = "OrionToolbar Settings" window.contentViewController = NSHostingController(rootView: content) window.delegate = self window.isReleasedWhenClosed = false window.level = .floating window.center() self.window = window NSApp.activate(ignoringOtherApps: true) window.makeKeyAndOrderFront(nil) window.orderFrontRegardless() // Begin a non-blocking AppKit modal session. // Unlike runModal(for:), this does not block SwiftUI's event loop. modalSession = NSApp.beginModalSession(for: window) modalTimer = Timer.scheduledTimer( withTimeInterval: 0.05, repeats: true ) { [weak self] _ in MainActor.assumeIsolated { guard let self, let session = self.modalSession else { return } let response = NSApp.runModalSession(session) if response != .continue { self.closeModalSession() } } } } private func closeModalSession() { modalTimer?.invalidate() modalTimer = nil if let session = modalSession { NSApp.endModalSession(session) modalSession = nil } } func windowWillClose(_ notification: Notification) { closeModalSession() window = nil Self.current = nil } } ''' backup_dir = ( root / "backups" / datetime.now().strftime("%Y%m%d-%H%M%S-%f") ) backup = backup_dir / path.relative_to(root) backup.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(path, backup) path.write_text(prefix + replacement) print("UPDATED:", path.relative_to(root)) print("BACKUP:", backup.relative_to(root)) print("Settings now uses an AppKit modal session.")