import AppKit import ServiceManagement import os /// App lifecycle, the Accessibility permission gate, and the menu-bar item. /// Wires WindowLocator + FocusEnforcer to the events EventTapController /// reports; owns no event-tap or AX logic itself. final class AppDelegate: NSObject, NSApplicationDelegate { private let logger = Logger(subsystem: "com.local.focusfixer", category: "AppDelegate") private let preferences = Preferences.shared private let permissionManager = PermissionManager() private let eventTapController = EventTapController() private let focusEnforcer = FocusEnforcer() private var statusItem: NSStatusItem? func applicationDidFinishLaunching(_ notification: Notification) { setUpStatusItem() permissionManager.waitUntilTrusted { [weak self] in self?.startEventTap() } } private func startEventTap() { eventTapController.start { [weak self] point in self?.handleMouseDown(at: point) } } private func handleMouseDown(at point: CGPoint) { guard preferences.isEnabled else { return } guard let pid = WindowLocator.ownerPID(at: point) else { return } focusEnforcer.enforceFocus(forWindowOwnedBy: pid) } // MARK: - Menu bar private func setUpStatusItem() { let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) item.button?.image = NSImage(systemSymbolName: "scope", accessibilityDescription: "FocusFixer") let menu = NSMenu() let enabledItem = NSMenuItem(title: "Enabled", action: #selector(toggleEnabled(_:)), keyEquivalent: "") enabledItem.target = self enabledItem.state = preferences.isEnabled ? .on : .off menu.addItem(enabledItem) let loginItem = NSMenuItem(title: "Launch at Login", action: #selector(toggleLaunchAtLogin(_:)), keyEquivalent: "") loginItem.target = self loginItem.state = SMAppService.mainApp.status == .enabled ? .on : .off menu.addItem(loginItem) menu.addItem(.separator()) menu.addItem(NSMenuItem(title: "Quit FocusFixer", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) item.menu = menu statusItem = item } @objc private func toggleEnabled(_ sender: NSMenuItem) { preferences.isEnabled.toggle() sender.state = preferences.isEnabled ? .on : .off } @objc private func toggleLaunchAtLogin(_ sender: NSMenuItem) { do { if SMAppService.mainApp.status == .enabled { try SMAppService.mainApp.unregister() } else { try SMAppService.mainApp.register() } } catch { logger.error("Failed to toggle login item: \(error.localizedDescription, privacy: .public)") } sender.state = SMAppService.mainApp.status == .enabled ? .on : .off } }