diff --git a/Downterm/Downterm.xcodeproj/project.pbxproj b/Downterm/Downterm.xcodeproj/project.pbxproj index 912a38f..93e17ed 100644 --- a/Downterm/Downterm.xcodeproj/project.pbxproj +++ b/Downterm/Downterm.xcodeproj/project.pbxproj @@ -27,12 +27,14 @@ C4C93F2911B41BC19A2AE934 /* SettingsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A973877BCE6084D0EBBBDBD /* SettingsWindowController.swift */; }; CC26C1677258E44F0D7B106A /* SwiftTermView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E47000112562615C7E59489 /* SwiftTermView.swift */; }; E9A064422790735E033E534F /* TerminalManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA6843B571B41986DE386F5F /* TerminalManager.swift */; }; + EA604F3F38D6638C7236CDC2 /* LaunchAtLoginHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B567F3B5D006D2B35630CFF /* LaunchAtLoginHelper.swift */; }; F0130A88D1453CD199FA65D7 /* NSScreen+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0CED6A0F25A6E57D8AA308A /* NSScreen+Extensions.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 02FEFF9074A85F02C43D9408 /* NotchWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchWindow.swift; sourceTree = ""; }; 0A973877BCE6084D0EBBBDBD /* SettingsWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindowController.swift; sourceTree = ""; }; + 0B567F3B5D006D2B35630CFF /* LaunchAtLoginHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLoginHelper.swift; sourceTree = ""; }; 15A290D4D21D6C01A583A372 /* ScreenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenManager.swift; sourceTree = ""; }; 1E47000112562615C7E59489 /* SwiftTermView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTermView.swift; sourceTree = ""; }; 1FC09C538CBE7C2D072008B2 /* NotchShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchShape.swift; sourceTree = ""; }; @@ -79,6 +81,7 @@ isa = PBXGroup; children = ( 3B72743F178231E0B06DD3DE /* HotkeyManager.swift */, + 0B567F3B5D006D2B35630CFF /* LaunchAtLoginHelper.swift */, EA1CD1DE020F0467AFB98DE3 /* PopoutWindowController.swift */, 15A290D4D21D6C01A583A372 /* ScreenManager.swift */, 0A973877BCE6084D0EBBBDBD /* SettingsWindowController.swift */, @@ -223,6 +226,7 @@ 88EBFBB2292659EA7C42A8F9 /* HotkeyBinding.swift in Sources */, 4D5125E11B4DDBDB3DFACBAF /* HotkeyManager.swift in Sources */, 7BD705CA6A34117929B362EC /* HotkeyRecorderView.swift in Sources */, + EA604F3F38D6638C7236CDC2 /* LaunchAtLoginHelper.swift in Sources */, F0130A88D1453CD199FA65D7 /* NSScreen+Extensions.swift in Sources */, 2213F430F3D8A88033607CD2 /* NotchSettings.swift in Sources */, 4566E6B87CB62AF5C8D4B9D8 /* NotchShape.swift in Sources */, diff --git a/Downterm/Downterm.xcodeproj/project.xcworkspace/xcuserdata/harvmaster.xcuserdatad/UserInterfaceState.xcuserstate b/Downterm/Downterm.xcodeproj/project.xcworkspace/xcuserdata/harvmaster.xcuserdatad/UserInterfaceState.xcuserstate index 86a7023..3a96b67 100644 Binary files a/Downterm/Downterm.xcodeproj/project.xcworkspace/xcuserdata/harvmaster.xcuserdatad/UserInterfaceState.xcuserstate and b/Downterm/Downterm.xcodeproj/project.xcworkspace/xcuserdata/harvmaster.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Downterm/Downterm/AppDelegate.swift b/Downterm/Downterm/AppDelegate.swift index fe435ae..1b8a522 100644 --- a/Downterm/Downterm/AppDelegate.swift +++ b/Downterm/Downterm/AppDelegate.swift @@ -11,6 +11,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { NotchSettings.registerDefaults() NSApp.setActivationPolicy(.accessory) + // Sync the launch-at-login toggle with the actual system state + // in case the user toggled it from System Settings. + UserDefaults.standard.set(LaunchAtLoginHelper.isEnabled, forKey: NotchSettings.Keys.launchAtLogin) + ScreenManager.shared.start() observeDisplayPreference() observeSizePreferences() diff --git a/Downterm/Downterm/Managers/LaunchAtLoginHelper.swift b/Downterm/Downterm/Managers/LaunchAtLoginHelper.swift new file mode 100644 index 0000000..954b83f --- /dev/null +++ b/Downterm/Downterm/Managers/LaunchAtLoginHelper.swift @@ -0,0 +1,24 @@ +import ServiceManagement + +/// Registers / unregisters the app as a login item using the +/// modern SMAppService API (macOS 13+). +enum LaunchAtLoginHelper { + + static func setEnabled(_ enabled: Bool) { + let service = SMAppService.mainApp + do { + if enabled { + try service.register() + } else { + try service.unregister() + } + } catch { + print("[LaunchAtLogin] Failed to \(enabled ? "register" : "unregister"): \(error)") + } + } + + /// Reads the current registration state from the system. + static var isEnabled: Bool { + SMAppService.mainApp.status == .enabled + } +} diff --git a/Downterm/Downterm/Models/NotchSettings.swift b/Downterm/Downterm/Models/NotchSettings.swift index 869ecbc..e8c7d0b 100644 --- a/Downterm/Downterm/Models/NotchSettings.swift +++ b/Downterm/Downterm/Models/NotchSettings.swift @@ -9,6 +9,7 @@ enum NotchSettings { static let openNotchOnHover = "openNotchOnHover" static let minimumHoverDuration = "minimumHoverDuration" static let showMenuBarIcon = "showMenuBarIcon" + static let launchAtLogin = "launchAtLogin" // Sizing — closed state static let notchHeight = "notchHeight" @@ -58,6 +59,7 @@ enum NotchSettings { static let openNotchOnHover: Bool = true static let minimumHoverDuration: Double = 0.3 static let showMenuBarIcon: Bool = true + static let launchAtLogin: Bool = false static let notchHeight: Double = 32 static let nonNotchHeight: Double = 32 @@ -102,6 +104,7 @@ enum NotchSettings { Keys.openNotchOnHover: Defaults.openNotchOnHover, Keys.minimumHoverDuration: Defaults.minimumHoverDuration, Keys.showMenuBarIcon: Defaults.showMenuBarIcon, + Keys.launchAtLogin: Defaults.launchAtLogin, Keys.notchHeight: Defaults.notchHeight, Keys.nonNotchHeight: Defaults.nonNotchHeight, diff --git a/Downterm/Downterm/Views/SettingsView.swift b/Downterm/Downterm/Views/SettingsView.swift index 3b8c2c5..2341edb 100644 --- a/Downterm/Downterm/Views/SettingsView.swift +++ b/Downterm/Downterm/Views/SettingsView.swift @@ -73,6 +73,7 @@ struct GeneralSettingsView: View { @AppStorage(NotchSettings.Keys.openNotchOnHover) private var openNotchOnHover = NotchSettings.Defaults.openNotchOnHover @AppStorage(NotchSettings.Keys.minimumHoverDuration) private var minimumHoverDuration = NotchSettings.Defaults.minimumHoverDuration @AppStorage(NotchSettings.Keys.showMenuBarIcon) private var showMenuBarIcon = NotchSettings.Defaults.showMenuBarIcon + @AppStorage(NotchSettings.Keys.launchAtLogin) private var launchAtLogin = NotchSettings.Defaults.launchAtLogin @AppStorage(NotchSettings.Keys.enableGestures) private var enableGestures = NotchSettings.Defaults.enableGestures @AppStorage(NotchSettings.Keys.gestureSensitivity) private var gestureSensitivity = NotchSettings.Defaults.gestureSensitivity @@ -89,6 +90,10 @@ struct GeneralSettingsView: View { Section("Display") { Toggle("Show on all displays", isOn: $showOnAllDisplays) Toggle("Show menu bar icon", isOn: $showMenuBarIcon) + Toggle("Launch at login", isOn: $launchAtLogin) + .onChange(of: launchAtLogin) { _, newValue in + LaunchAtLoginHelper.setEnabled(newValue) + } } Section("Hover Behavior") {