Files
downterm/Downterm/CommandNotch/AppDelegate.swift

118 lines
3.9 KiB
Swift

import AppKit
import Combine
/// Application delegate that bootstraps the notch overlay system.
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
private enum UITestLaunchArgument {
static let regularActivation = "--uitest-regular-activation"
static let showSettings = "--uitest-show-settings"
static let openNotch = "--uitest-open-notch"
}
private var cancellables = Set<AnyCancellable>()
private let settingsController = AppSettingsController.shared
func applicationDidFinishLaunching(_ notification: Notification) {
NotchSettings.registerDefaults()
if isRunningUITests {
NSApp.setActivationPolicy(.regular)
} else {
NSApp.setActivationPolicy(.accessory)
}
// Sync the launch-at-login toggle with the actual system state
// in case the user toggled it from System Settings.
settingsController.update {
$0.display.launchAtLogin = LaunchAtLoginHelper.isEnabled
}
ScreenManager.shared.start()
observeDisplayPreference()
observeSizePreferences()
observeFontSizeChanges()
observeTerminalThemeChanges()
applyUITestLaunchBehaviorIfNeeded()
}
func applicationWillTerminate(_ notification: Notification) {
ScreenManager.shared.stop()
}
// MARK: - Preference observers
/// Only rebuild windows when the display-count preference changes.
private func observeDisplayPreference() {
settingsController.$settings
.map(\.display.showOnAllDisplays)
.removeDuplicates()
.dropFirst()
.sink { _ in
ScreenManager.shared.rebuildWindows()
}
.store(in: &cancellables)
}
/// Reposition (not rebuild) when any sizing preference changes.
private func observeSizePreferences() {
settingsController.$settings
.map(\.display.layoutSignature)
.removeDuplicates()
.dropFirst()
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.sink { _ in
ScreenManager.shared.repositionWindows()
}
.store(in: &cancellables)
}
/// Live-update terminal font size across all sessions.
private func observeFontSizeChanges() {
settingsController.$settings
.map(\.terminal.fontSize)
.removeDuplicates()
.sink { newSize in
guard newSize > 0 else { return }
WorkspaceRegistry.shared.updateAllWorkspacesFontSizes(CGFloat(newSize))
}
.store(in: &cancellables)
}
/// Live-update terminal colors across all sessions.
private func observeTerminalThemeChanges() {
settingsController.$settings
.map(\.terminal.themeRawValue)
.removeDuplicates()
.sink { newTheme in
WorkspaceRegistry.shared.updateAllWorkspacesThemes(TerminalTheme.resolve(newTheme))
}
.store(in: &cancellables)
}
private var launchArguments: [String] {
ProcessInfo.processInfo.arguments
}
private var isRunningUITests: Bool {
launchArguments.contains(UITestLaunchArgument.regularActivation)
|| launchArguments.contains(UITestLaunchArgument.showSettings)
|| launchArguments.contains(UITestLaunchArgument.openNotch)
}
private func applyUITestLaunchBehaviorIfNeeded() {
guard isRunningUITests else { return }
DispatchQueue.main.async { @MainActor in
if self.launchArguments.contains(UITestLaunchArgument.showSettings) {
SettingsWindowController.shared.showSettings()
}
if self.launchArguments.contains(UITestLaunchArgument.openNotch),
let screenID = ScreenRegistry.shared.activeScreenID() {
ScreenManager.shared.openNotch(screenID: screenID)
}
}
}
}