Search code examples
macosswiftuimenubar

MacOS SwiftUI Menu Bar App Settings opening in background


I'm building a macOS menu bar app with SwiftUI's new MenuBarExtra API and running into a bit of an odd issue.

I've implemented a settings window that I can open with the following call:

if #available(macOS 13, *) {
    NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
} else {
    NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
}

I've also set the Application is agent flag to YES in info my project's properties.

Unfortunately, whenever I open the settings window via the MenuBar, it opens in the background and isn't visible at all. I'm really not sure how to proceed from here. I've thought about the following:

  • Programmatically change focus (Doesn't appear to exist)
  • Open a separate window (This seems to not work due to the Agent setting)

Has anyone come across this issue and implemented a solution to it?


Solution

  • You can change the activation policy programatically. Before you open your preferences, run the following code:

    NSApp.setActivationPolicy(.regular) //makes the app a "normal" app again with a menu bar and a visible dock icon
    NSApp.activate(ignoringOtherApps: ignoringOtherApps) // Activates the app in order to bring the window to front. Otherwise your window may be hidden behind windows of other apps
    

    As soon as your last window closes, make the app an agent/accessory app again:

     NSApp.hide(self)
     NSApp.setActivationPolicy(.accessory)
    

    You may want to use this extension:

    extension NSApplication {
    
        static func show(ignoringOtherApps: Bool = true) {
            NSApp.setActivationPolicy(.regular)
            NSApp.activate(ignoringOtherApps: ignoringOtherApps)
        }
    
        static func hide() {
            NSApp.hide(self)
            NSApp.setActivationPolicy(.accessory)
    }