I have a statusbar application, which runs in the menu bar. Therefore I set Application is agent (UIElement) to true in the info.plst.
Based on the fix (or workaround) from OP. The key is really to toggle out and back to focus (thanks @Daniel!).
Some small improvements:
No force unwrapping, no need to set ActivationPolicy and call activate twice.
NSApp.setActivationPolicy(.regular)
window.makeKeyAndOrderFront(nil)
NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: [])
OperationQueue.current?.underlyingQueue?.asyncAfter(deadline: .now() + .milliseconds(200), execute: {
NSApp.activate(ignoringOtherApps: true)
})
I tried with apple scripts, which appears working as expected.
Except, after closing by key strokes and then reopening a new window (short time interval), menu will stay selected.
if NSApp.activationPolicy() == .accessory {
NSApp.setActivationPolicy(.regular)
} else {
var errorDict: NSDictionary?
NSAppleScript(source: """
tell application "Dock" to activate current application
""")?.executeAndReturnError(&errorDict)
if errorDict != nil{
print(errorDict!)
// error executing apple script
NSApp.activate(ignoringOtherApps: true)
}
}
window?.makeKeyAndOrderFront(self)
GIF demo:
Video link
I might found another solution for this (which is still an issue on macOS 10.15). I found a similar issue + solution here. The idea is about to show and hide the menuBar for the current application. I needed to run it 2 different run loops but it worked. Here is the solution:
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(false)
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(true)
}
}
This is my workaround solution for now:
As I wrote in the question, if I click on another app and come back to my app, the menubar is being displayed. I am simulating this when I try to show the preference window:
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
if (NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: []))! {
let deadlineTime = DispatchTime.now() + .milliseconds(200)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
}
}
This is not a perfect solution. If I don't find a better solution, I will file a bug.