Last active
April 27, 2024 04:49
-
-
Save stephancasas/887fdcc4e287ff498f74e6a71449a8b0 to your computer and use it in GitHub Desktop.
An extension enabling global access to settings scene of a macOS SwiftUI application.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSApplication+openSettings.swift | |
// | |
// Created by Stephan Casas on 12/3/23. | |
// | |
import SwiftUI; | |
fileprivate let kAppMenuInternalIdentifier = "app" | |
fileprivate let kSettingsLocalizedStringKey = "Settings\\U2026"; | |
extension NSApplication { | |
/// Open the application settings/preferences window. | |
func openSettings() { | |
// macOS 14 Sonoma | |
if let internalItemAction = NSApp.mainMenu?.item( | |
withInternalIdentifier: kAppMenuInternalIdentifier | |
)?.submenu?.item( | |
withLocalizedTitle: kSettingsLocalizedStringKey | |
)?.internalItemAction { | |
internalItemAction(); | |
return; | |
} | |
guard let delegate = NSApp.delegate else { return } | |
// macOS 13 Ventura | |
var selector = Selector(("showSettingsWindow:")); | |
if delegate.responds(to: selector) { | |
delegate.perform(selector, with: nil, with: nil); | |
return; | |
} | |
// macOS 12 Monterrey | |
selector = Selector(("showPreferencesWindow:")); | |
if delegate.responds(to: selector) { | |
delegate.perform(selector, with: nil, with: nil); | |
return; | |
} | |
} | |
} | |
// MARK: - NSMenuItem (Private) | |
extension NSMenuItem { | |
/// An internal SwiftUI menu item identifier that should be a public property on `NSMenuItem`. | |
var internalIdentifier: String? { | |
guard let id = Mirror.firstChild( | |
withLabel: "id", in: self | |
)?.value else { | |
return nil; | |
} | |
return "\(id)"; | |
} | |
/// A callback which is associated directly with this `NSMenuItem`. | |
var internalItemAction: (() -> Void)? { | |
guard | |
let platformItemAction = Mirror.firstChild( | |
withLabel: "platformItemAction", in: self)?.value, | |
let typeErasedCallback = Mirror.firstChild( | |
in: platformItemAction)?.value | |
else { | |
return nil; | |
} | |
return Mirror.firstChild( | |
in: typeErasedCallback | |
)?.value as? () -> Void; | |
} | |
} | |
// MARK: - NSMenu (Private) | |
extension NSMenu { | |
/// Get the first `NSMenuItem` whose internal identifier string matches the given value. | |
func item(withInternalIdentifier identifier: String) -> NSMenuItem? { | |
self.items.first(where: { | |
$0.internalIdentifier?.elementsEqual(identifier) ?? false | |
}) | |
} | |
/// Get the first `NSMenuItem` whose title is equivalent to the localized string referenced | |
/// by the given localized string key in the localization table identified by the given table name | |
/// from the bundle located at the given bundle path. | |
func item( | |
withLocalizedTitle localizedTitleKey: String, | |
inTable tableName: String = "MenuCommands", | |
fromBundle bundlePath: String = "/System/Library/Frameworks/AppKit.framework" | |
) -> NSMenuItem? { | |
guard let localizationResource = Bundle(path: bundlePath) else { | |
return nil; | |
} | |
return self.item(withTitle: NSLocalizedString( | |
localizedTitleKey, | |
tableName: tableName, | |
bundle: localizationResource, | |
comment: "")); | |
} | |
} | |
// MARK: - Mirror (Helper) | |
fileprivate extension Mirror { | |
/// The unconditional first child of the reflection subject. | |
var firstChild: Child? { self.children.first } | |
/// The first child of the reflection subject whose label matches the given string. | |
func firstChild(withLabel label: String) -> Child? { | |
self.children.first(where: { | |
$0.label?.elementsEqual(label) ?? false | |
}) | |
} | |
/// The unconditional first child of the given subject. | |
static func firstChild(in subject: Any) -> Child? { | |
Mirror(reflecting: subject).firstChild | |
} | |
/// The first child of the given subject whose label matches the given string. | |
static func firstChild( | |
withLabel label: String, in subject: Any | |
) -> Child? { | |
Mirror(reflecting: subject).firstChild(withLabel: label) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment