Search code examples
swiftmacoscocoabackground-processmenubar

macOS menubar application: main menu not being displayed


I have a statusbar application, which runs in the menu bar. Therefore I set Application is agent (UIElement) to true in the info.plst. That results in no dock icon and no menu bar for my application.

However, I also have a preference window that the user can open from the statusbar menu. Here is how I open it:

if (!NSApp.setActivationPolicy(.regular)) {
    print("unable to set regular activation policy")
}
NSApp.activate(ignoringOtherApps: true)
if let window = preferencesWindowController.window {
    window.makeKeyAndOrderFront(nil)
}

The window shows up as expected, but the application's main menu bar with File, Edit and so on, does not show up. Only if I click on another app and come back to my app, the menubar is being displayed.

I noticed, that if I change the value in the info.plst to false and use NSApp.setActivationPolicy(.accessory) in applicationDidFinishLaunching(), it has the same result. However, if I call NSApp.setActivationPolicy(.accessory) with a timer a few milliseconds after applicationDidFinishLaunching() is being called, it works and the main menu is being displayed as expected. This however has the side effect that the app icon pops up in the dock for a few seconds (until the timer is being fired), which is not a nice user experience.

Does anyone have an idea what else I could try? What is happening when I switch the active app, that I am not doing in code?

I am using Version 8.2.1 (8C1002) on macOS 10.12.2 (16C67)

Thanks!


Solution

  • 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.