activateIgnoringOtherApps and makeKeyAndOrderFront not working after NSWindow is closed

3.2k views Asked by At

I started with a storyboard project. and I put Menubar item. When the menubar item is clicked, the following method is triggered in AppDelegate.swift.

func setWindowVisible() {
    NSApp.activateIgnoringOtherApps(ture)
    NSApp.mainWindow?.makeKeyAndOrderFront(self)
}

this brings my app in front. But once I click the close button, the red one on the window, it never works.

It used to work in non-storyboard based projects no matter I close the window.

I have set

NSApp.mainWindow?.releasedWhenClosed = false

in applicationDidFinishLaunching()

Can anyone help me please?

2

There are 2 answers

8
mangerlahn On BEST ANSWER

Setting releasedWhenClosed in applicationDidFinishLaunching has no effect as the mainWindow property is nil at this moment. → The window is created after this method is executed.

The releasedWhenClosed is defaulted to false anyway when the window is created in Interface Builder.

The mainWindow property is probably nil after closing the window, because then there is no mainWindow anymore. From the docs:

The value in this property is nil when the app’s storyboard or nib file has not yet finished loading. It might also be nil when the app is inactive or hidden.

I was able to show the window again (after closing) by accessing the window from within the windows array of NSApp.

NSApp.activateIgnoringOtherApps(true)
NSApp.windows[0].makeKeyAndOrderFront(self)

In case you have more than one window, you need to find the right one in the array..

1
Dominic Holmes On

Want to pull the answer by Kyle KIM into it's own answer, as the above solution with array access caused an exception for me.

In my use case, I'm using this keyboard shortcuts library to bring the app to foreground.

I'm also using this alongside the new SwiftUI app feature, and thankfully it all works together -- this will invoke again even if you click the close button.

class AppDelegate: NSObject, NSApplicationDelegate {

var window: NSWindow?

func applicationDidBecomeActive(_ notification: Notification) {
    self.window = NSApp.mainWindow
}

func applicationDidFinishLaunching(_ aNotification: Notification) {
    KeyboardShortcuts.onKeyUp(for: .toggleApp) {
        if !NSApp.isActive || !(self.window?.isKeyWindow ?? false) {
            NSApp.activate(ignoringOtherApps: true)
            self.window?.makeKeyAndOrderFront(self)
        } else {
            print("App already active")
        }
    }
}
}

!NSApp.isActive and the key window check are both required because when a user clicks the "close button" the widow is no longer key but still active. The app remains active until they click on a different app. You can see this happening with the focus colors of windows.

Note that this AppDelegate isn't the main entry point in my app, it's used alongside swiftUI:

@main
struct MainApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {...}
}