import AppKit import SwiftUI nonisolated func mctLog(_ format: String, _ args: CVarArg...) { let msg = String(format: format, arguments: args) let line = "\(msg)\n" // Write to both stderr and file fputs(line, stderr) guard let data = line.data(using: .utf8) else { return } let path = "/tmp/mct_debug.log" let fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0o644) if fd >= 0 { _ = data.withUnsafeBytes { write(fd, $0.baseAddress!, $0.count) } close(fd) } } @MainActor final class AppDelegate: NSObject, NSApplicationDelegate { private let gestureProgressModel = GestureProgress() private lazy var overlayController = OverlayWindowController(gestureProgress: gestureProgressModel) private var hotKeyManager: HotKeyManager? private var gestureMonitor: GestureMonitor? private var settingsWindow: NSWindow? func applicationDidFinishLaunching(_ notification: Notification) { mctLog("[MCT] app launched") checkPermissions() syncLoginItem() setupHotKey() Task { await ThumbnailCapture.warmUp() } setupGestureMonitor() } func toggleOverlay() { overlayController.toggle() } func showSettings() { if let window = settingsWindow { window.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) return } let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 450, height: 320), styleMask: [.titled, .closable], backing: .buffered, defer: false ) window.title = "MCT Settings" window.contentView = NSHostingView(rootView: SettingsView()) window.center() window.isReleasedWhenClosed = false window.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) settingsWindow = window } // MARK: - Private private func syncLoginItem() { // Only register from /Applications — SMAppService records the bundle // path it was registered from, so dev builds in ~/misc would otherwise // pin the login item to the wrong location. let bundlePath = Bundle.main.bundlePath guard bundlePath.hasPrefix("/Applications/") else { mctLog("[MCT] not registering login item — not running from /Applications (%@)", bundlePath) return } if Preferences.shared.launchAtLogin { LoginItemManager.setEnabled(true) } } private func checkPermissions() { if !AccessibilityBridge.hasPermission { let hasPromptedBefore = UserDefaults.standard.bool(forKey: "hasPromptedAccessibility") if !hasPromptedBefore { AccessibilityBridge.requestPermissionIfNeeded() UserDefaults.standard.set(true, forKey: "hasPromptedAccessibility") } } } private func setupHotKey() { let prefs = Preferences.shared hotKeyManager = HotKeyManager { [weak self] in self?.toggleOverlay() } hotKeyManager?.register( keyCode: prefs.hotKeyKeyCode, modifiers: prefs.hotKeyModifiers ) } private func setupGestureMonitor() { gestureMonitor = GestureMonitor { [weak self] event in guard let self = self else { return } switch event { case .began: self.overlayController.gestureDidBegin() case .changed(let progress, let velocity): self.overlayController.gestureDidChange(rawDY: progress, rawVelocity: velocity) case .ended(let progress, let velocity): self.overlayController.gestureDidEnd(rawDY: progress, rawVelocity: velocity) case .cancelled: self.overlayController.gestureDidCancel() } } gestureMonitor?.start() } }