2

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?

Kyle KIM
  • 1,384
  • 2
  • 15
  • 31

2 Answers2

6

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

mangerlahn
  • 4,746
  • 2
  • 26
  • 50
  • still no luck. I have one window which the xcode template provides – Kyle KIM May 30 '16 at 12:54
  • Can you print the windows array? – mangerlahn May 30 '16 at 13:01
  • I have just solved. var window: NSWindow! with this property, window = NSApp.mainWindow! in applicationDidBecomeActive(), then self.window.makeKeyAndOrderFront(self) in my method. – Kyle KIM May 30 '16 at 13:06
  • But I do not know if the best place for window = NSApp.mainWindow! is inside applicationDidBecomeActive(). any suggestion do you have sir? – Kyle KIM May 30 '16 at 13:08
  • I guess this is ok as long as you only have one window. When it changes, this code might break. – mangerlahn May 30 '16 at 13:10
  • then it would be ok for my project this time. your mentioning about window creation after applicationDidFinishLaunching helped me. thank you. – Kyle KIM May 30 '16 at 13:11
  • has been changed to: NSApp.activate(ignoringOtherApps: true) – jeremyforan Oct 22 '17 at 20:46
  • NSApp.activateIgnoringOtherApps(true). The absence of this line caused me troubles (window front but not key) which are now solved. Thank U. – Fredo Jan 24 '18 at 15:19
1

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 {...}
}
Dominic Holmes
  • 581
  • 5
  • 13