Search code examples
macosnswindownsdocument

Make "Close All" (cmd+option+W) apply only to one type of document windows


I have an application that manages different types of NSDocument subclasses (along with matching NSWindow subclasses).

For instance, it's possible that the app has one window of type A open, and two windows of type B.

Now, if a window of type B is active, and the user chooses "Close All" or hits cmd+option+W, all my app's windows are sent the close message.

But I only want all of the active window type's windows closed instead, i.e. only the two type B, not the type A window. How do I accomplish this?

I currently have no explicit menu entry for "Close All". Instead, macOS provides that automagically. If there perhaps a way to intercept a "closeAll" message? Can't find one, though.


Solution

  • After some digging I figured out where the auto-generated "Close All" menu item sends its action to: To the closeAll: selector of the application target:

    Xcode property view of NSMenuItem

    Thus my solution is to subclass NSApplication and implement the handler there, which then simply closes all windows that are of the same type (this assumes that I use specific subclasses for my different types of windows):

    - (IBAction)closeAll:(id)sender {
        Class windowClass = self.keyWindow.class;
        for (NSWindow *w in self.windows) {
            if (windowClass == w.class) {
                [w performClose:sender];
            }
        }
    }
    

    Caution: If you adopt this pattern be aware that:

    1. The closeAll: selector is not documented nor mentioned in the header files, meaning that Apple might feel free to change in a future SDK, though I find that unlikely. It will probably not break anything if that happens, but instead your custom handler won't be called any more.

    2. The code simply tells all windows to close, ignoring the fact that one might reject to be closed, e.g. by user interaction. In that case you may want to stop the loop instead of continuing to close more windows (though I know of no easy way to accomplish that).