0

All OS X application that support NSWindowRestoration can be closed by selecting the menu entry "Quit and Close All Windows" (Option-Command Q). This disables the state restoration and the next time you open the app all windows will be in their default position.

The menu entry triggers the terminate: method on NSApplication. But so does the regular "Close App" menu as well (Command Q).

How can I do the "Quit and Close All Windows" programmatically? Do I really have to close all windows by myself and then call terminate:?

How does Apple magically decide what to do, when both actions are connected to the same terminate: method?

Klaas
  • 20,950
  • 10
  • 88
  • 98
  • Why don't you just loop through the windows on terminate and close them? – l'L'l Jun 13 '16 at 04:40
  • @l'L'l because that would be extra code to manage while Apple has a solution that works with a simple method call. – Klaas Jun 13 '16 at 09:07

1 Answers1

2

There doesn't seem to be a great way to do this. You might want to file a bug with Apple requesting (along with an explanation for why you need it).

How does Apple magically decide what to do, when both actions are connected to the same terminate: method?

Well, looking at the disassembly of AppKit, it appears that -[NSApplication terminate:] checks if the sender is an instance of NSMenuItem. If it is, it checks if its userInterfaceItemIdentifier is equal to @"NSAlternateQuitMenuItem".

You could, I suppose, create a dummy menu item with that identifier and pass that as the sender to -terminate:, although since this is relying on an implementation detail it could break at any time.

The other controlling factor is the setting of System Preferences > General > "Close windows when quitting an app". That corresponds to the user defaults key NSAlternateQuitMenuItem, although, again, that's an implementation detail. It appears that you could set that before calling -terminate: and then, in the -applicationWillTerminate: delegate method, remove that setting. (Your changes will be associated with your application. They won't affect other applications or the setting in System Preferences.) Of course, you'll have to make sure that sudden termination is disabled to get that delegate method call.

Ken Thomases
  • 83,395
  • 7
  • 101
  • 140
  • I did not know, that there is an `userInterfaceItemIdentifier` property on NSMenuItem. I just created the necessary interface definition in Objective-C to access it. Thank you so much! – Klaas Jun 13 '16 at 01:20
  • Some further investigation brought up, that this is the only menu item that gets such an identifier. It is initially not there but then added automatically some time after the app started. – Klaas Jun 13 '16 at 11:54
  • The whole menu item isn't there "initially". It's created by Cocoa when the main menu is set. It's bad enough if you're going to rely on this menu item having a particular identifier. Definitely do not rely on it being the only item with an identifier. – Ken Thomases Jun 13 '16 at 15:31
  • Of course, I just wanted to make sure that there is no more magic that I might have missed. I'm currently only localising the menu of an app and interestingly even the automatic text replacement between "Show Toolbar" and "Hide Toolbar" relies on the exact same wording as Apple chose for every language. – Klaas Jun 13 '16 at 18:58