feat: support login-at-start on macos 11, 12, and m1 macs

This commit is contained in:
Louis Pontoise
2021-11-19 23:06:31 +09:00
committed by lwouis
parent 6f931305cc
commit 664c5b9628
2 changed files with 70 additions and 33 deletions
+44 -22
View File
@@ -159,33 +159,55 @@ class Preferences {
static var all: [String: Any] { defaults.persistentDomain(forName: NSRunningApplication.current.bundleIdentifier!)! }
static func migratePreferences() {
let preferencesVersion = "preferencesVersion"
if let currentVersion = defaults.string(forKey: preferencesVersion) {
if currentVersion.compare(App.version, options: .numeric) == .orderedAscending {
updateToNewPreferences(preferencesVersion)
let preferencesKey = "preferencesVersion"
if let diskVersion = defaults.string(forKey: preferencesKey) {
if diskVersion.compare(App.version, options: .numeric) == .orderedAscending {
updateToNewPreferences(diskVersion)
}
}
defaults.set(App.version, forKey: preferencesKey)
}
private static func updateToNewPreferences(_ currentVersion: String) {
if currentVersion.compare("6.27.1", options: .numeric) != .orderedDescending {
// "Start at login" new implem doesn't use Login Items; we remove the entry from previous versions
migrateLoginItem()
if currentVersion.compare("6.23.0", options: .numeric) != .orderedDescending {
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
if currentVersion.compare("6.18.1", options: .numeric) != .orderedDescending {
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
}
}
} else {
// first time migrating
updateToNewPreferences(preferencesVersion)
}
}
private static func updateToNewPreferences(_ preferencesVersion: String) {
if App.version.compare("6.3.0", options: .numeric) == .orderedAscending {
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
@available(OSX, deprecated: 10.11)
private static func migrateLoginItem() {
do {
let loginItems = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue()
let loginItemsSnapshot = LSSharedFileListCopySnapshot(loginItems, nil).takeRetainedValue() as! [LSSharedFileListItem]
let itemName = Bundle.main.bundleURL.lastPathComponent as CFString
let itemUrl = URL(fileURLWithPath: Bundle.main.bundlePath) as CFURL
loginItemsSnapshot.forEach {
if (LSSharedFileListItemCopyDisplayName($0)?.takeRetainedValue() == itemName) ||
(LSSharedFileListItemCopyResolvedURL($0, 0, nil)?.takeRetainedValue() == itemUrl) {
LSSharedFileListItemRemove(loginItems, $0)
}
}
} catch {
// the LSSharedFile API is deprecated, and has a runtime crash on M1 Monterey
// we catch any exception to void the app crashing
}
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
defaults.set(App.version, forKey: preferencesVersion)
}
private static func migrateShowWindowsFrom() {
+26 -11
View File
@@ -28,21 +28,36 @@ class GeneralTab {
return grid
}
// adding/removing login item depending on the checkbox state
@available(OSX, deprecated: 10.11)
// add/remove plist file in ~/Library/LaunchAgents/ depending on the checkbox state
static func startAtLoginCallback(_ sender: NSControl) {
let loginItems = LSSharedFileListCreate(nil, kLSSharedFileListSessionLoginItems.takeRetainedValue(), nil).takeRetainedValue()
let loginItemsSnapshot = LSSharedFileListCopySnapshot(loginItems, nil).takeRetainedValue() as! [LSSharedFileListItem]
let itemName = Bundle.main.bundleURL.lastPathComponent as CFString
let itemUrl = URL(fileURLWithPath: Bundle.main.bundlePath) as CFURL
loginItemsSnapshot.forEach {
if (LSSharedFileListItemCopyDisplayName($0)?.takeRetainedValue() == itemName) ||
(LSSharedFileListItemCopyResolvedURL($0, 0, nil)?.takeRetainedValue() == itemUrl) {
LSSharedFileListItemRemove(loginItems, $0)
var launchAgentsPath = (try? FileManager.default.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false)) ?? URL.init(fileURLWithPath: "~/Library", isDirectory: true)
launchAgentsPath.appendPathComponent("LaunchAgents", isDirectory: true)
if !FileManager.default.fileExists(atPath: launchAgentsPath.path) {
do {
try FileManager.default.createDirectory(at: launchAgentsPath, withIntermediateDirectories: false)
} catch let error {
debugPrint("Failed to create LaunchAgent directory at '\(launchAgentsPath.path)'", error)
}
}
launchAgentsPath.appendPathComponent("com.lwouis.alt-tab-macos.plist", isDirectory: false)
if (sender as! NSButton).state == .on {
let _ = LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst.takeRetainedValue(), nil, nil, itemUrl, nil, nil).takeRetainedValue()
let plist: NSDictionary = [
"Label": "com.lwouis.alt-tab-macos",
"Program": Bundle.main.executablePath ?? "/Applications/\(App.name).app/Contents/MacOS/\(App.name)",
"RunAtLoad": true,
"LimitLoadToSessionType": "Aqua",
"KeepAlive": [
"Crashed": true,
"SuccessfulExit": false,
],
]
plist.write(to: launchAgentsPath, atomically: true)
} else {
do {
try FileManager.default.removeItem(at: launchAgentsPath)
} catch let error {
debugPrint("Failed to remove LaunchAgent", error)
}
}
}
}