Skip to content

Commit

Permalink
Fix Missing Settings option
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Mazanov <alexandr.mazanov@gmail.com>
  • Loading branch information
melonamin committed Jan 29, 2024
1 parent c1f4880 commit 4c38b7a
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 18 deletions.
8 changes: 6 additions & 2 deletions TRex.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
FA66345C25DEFD500087CCEA /* NSImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA66345B25DEFD500087CCEA /* NSImage+Extension.swift */; };
FA66345F25DF05950087CCEA /* PagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA66345E25DF05950087CCEA /* PagerView.swift */; };
FA87AF11292A5C7600E50225 /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = FA87AF10292A5C7600E50225 /* LaunchAtLogin */; };
FA8A957C2B67CA41008C0B7B /* UniversalShowSettingsHack.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8A957B2B67CA41008C0B7B /* UniversalShowSettingsHack.swift */; };
FACA7A152B46119B004C5000 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FACA7A142B46119B004C5000 /* Helpers.swift */; };
FAE335C125E0A81500CFFDAF /* NotificationName+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE335C025E0A81500CFFDAF /* NotificationName+Extension.swift */; };
FAFAC6F5272C4CAE00011ED6 /* AboutSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAFAC6F4272C4CAE00011ED6 /* AboutSettingsView.swift */; };
Expand Down Expand Up @@ -112,6 +113,7 @@
FA5F876D25DDE3E400B1AF77 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
FA66345B25DEFD500087CCEA /* NSImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+Extension.swift"; sourceTree = "<group>"; };
FA66345E25DF05950087CCEA /* PagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagerView.swift; sourceTree = "<group>"; };
FA8A957B2B67CA41008C0B7B /* UniversalShowSettingsHack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalShowSettingsHack.swift; sourceTree = "<group>"; };
FACA7A142B46119B004C5000 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
FAE335C025E0A81500CFFDAF /* NotificationName+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationName+Extension.swift"; sourceTree = "<group>"; };
FAFAC6F4272C4CAE00011ED6 /* AboutSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutSettingsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -282,6 +284,7 @@
isa = PBXGroup;
children = (
FA5F876125DD63AA00B1AF77 /* KeyboardShortcuts+Extension.swift */,
FA8A957B2B67CA41008C0B7B /* UniversalShowSettingsHack.swift */,
FA58E39627AC7F630034837F /* Utils.swift */,
FA5F876825DDE18B00B1AF77 /* UI */,
);
Expand Down Expand Up @@ -590,6 +593,7 @@
FA66345C25DEFD500087CCEA /* NSImage+Extension.swift in Sources */,
FA5F875B25DD59D000B1AF77 /* MenuBarItem.swift in Sources */,
FA5F876225DD63AA00B1AF77 /* KeyboardShortcuts+Extension.swift in Sources */,
FA8A957C2B67CA41008C0B7B /* UniversalShowSettingsHack.swift in Sources */,
FA5F874B25DCB50A00B1AF77 /* SettingsView.swift in Sources */,
FAFAC6F9272C4CEA00011ED6 /* GeneralSettingsView.swift in Sources */,
FA48BA3025DDEBCE00E98F77 /* EnumPicker.swift in Sources */,
Expand Down Expand Up @@ -860,7 +864,7 @@
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 103;
CURRENT_PROJECT_VERSION = 108;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"TRex/Preview Content\"";
DEVELOPMENT_TEAM = X93LWC49WV;
Expand Down Expand Up @@ -890,7 +894,7 @@
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 103;
CURRENT_PROJECT_VERSION = 108;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"TRex/Preview Content\"";
DEVELOPMENT_TEAM = X93LWC49WV;
Expand Down
26 changes: 13 additions & 13 deletions TRex/App/UI/MenuBarItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MenubarItem: NSObject {
let captureTextAndTriggerAutomationItem = NSMenuItem(title: "Capture & Run Automation", action: #selector(captureScreenAndTriggerAutomation), keyEquivalent: "")
let captureFromClipboard = NSMenuItem(title: "Capture from Clipboard", action: #selector(captureClipboard), keyEquivalent: "")
let ignoreLineBreaksItem = NSMenuItem(title: "Ignore Line Breaks", action: #selector(ignoreLineBreaks), keyEquivalent: "")
let preferencesItem = NSMenuItem(title: "Preferences...", action: #selector(showPreferences), keyEquivalent: "")
let preferencesItem = NSMenuItem(title: "Settings...", action: #selector(showPreferences), keyEquivalent: ",")
let quitItem = NSMenuItem(title: "Quit", action: #selector(quit), keyEquivalent: "q")
let aboutItem = NSMenuItem(title: "About TRex", action: #selector(showAbout), keyEquivalent: "")

Expand Down Expand Up @@ -50,17 +50,7 @@ class MenubarItem: NSObject {
statusBarmenu.addItem(captureFromClipboard)
statusBarmenu.addItem(ignoreLineBreaksItem)
statusBarmenu.addItem(NSMenuItem.separator())
if #available(macOS 13.0, *) {
if let menu = NSApp.mainMenu?.items.first, let item = menu.submenu?.items[2] {
menu.submenu?.removeItem(item)
statusBarmenu.addItem(item)
}
} else {
if let menu = NSApp.mainMenu?.items.first, let item = menu.submenu?.items.first {
menu.submenu?.removeItem(item)
statusBarmenu.addItem(item)
}
}
statusBarmenu.addItem(preferencesItem)
statusBarmenu.addItem(aboutItem)
statusBarmenu.addItem(NSMenuItem.separator())
statusBarmenu.addItem(quitItem)
Expand Down Expand Up @@ -93,7 +83,17 @@ class MenubarItem: NSObject {
}

@objc func showPreferences() {
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: self, from: self)
NSApp.openSettings()
return
// if #available(macOS 14.0, *) {
// NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
// return
// }
// if #available(macOS 13.0, *) {
// NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
// return
// }
// NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
}
}

Expand Down
126 changes: 126 additions & 0 deletions TRex/App/UniversalShowSettingsHack.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import Cocoa

// https://stackoverflow.com/a/76714125

private let kAppMenuInternalIdentifier = "app"
private 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? {
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 item(withTitle: NSLocalizedString(
localizedTitleKey,
tableName: tableName,
bundle: localizationResource,
comment: ""
))
}
}

// MARK: - Mirror (Helper)

private extension Mirror {
/// The unconditional first child of the reflection subject.
var firstChild: Child? { children.first }

/// The first child of the reflection subject whose label matches the given string.
func firstChild(withLabel label: String) -> Child? {
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)
}
}
4 changes: 1 addition & 3 deletions TRex/Resources/TRex.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>X93LWC49WV.TRex.preferences</string>
</array>
<array/>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
Expand Down

0 comments on commit 4c38b7a

Please sign in to comment.