Reputation: 408
I'm trying to make my application call hide when the user attempts to close the last window via the red button.
Note: The tabs mentioned below are part of the sierra automatic tabbing feature.
I'm aware that I can hide the application with NSApplication.shared().hide()
, however, I only want to do this when the user has tried to close the last open window (meaning, the red button that would close ALL tabs for that window). However, I want to permit the close buttons on the tabs to perform normally, and close the tab.
So far a tab closure and a window closure appear identical in the API and I'm having a hard time achieving the behavior I want. Is there a way to determine if the is being closed via its red close button, or its tab close button?
Upvotes: 0
Views: 901
Reputation: 1420
Disclaimer:
So I could not find an easy way of doing this. The idea behind my implementation is to call a debounced function when a window closes. Since clicking the "X" in the corner closes all windows, the debouncing will allow you to have a function called once when it's all done.
There's some other stuff too: You've got to cache the number of windows in a tab. You've got to keep a list of the windows being closed.
But in the end, you can differentiate between:
Anyways, here's my implementation. You'll need debounce
from here:
// Stands for TabbedWindowCloseDebouncer
class TWCDebouncer {
private static var Debouncers = [NSWindowTabGroup: () -> Void]()
private static var TabStartCounts = [NSWindowTabGroup: Int]()
private static var Windows = [NSWindowTabGroup: [NSWindow]]()
private static var LastTabGroup: NSWindowTabGroup?
func handleClose(window: NSWindow) {
// This handles a window without tabs.
// Check presence in Debouncers, otherwise it will also catch the last
// window of a tabbed window closing.
if window.tabbedWindows == nil && TWCDebouncer.Debouncers[window.tabGroup!] == nil {
// You can consider this to be the same as closing a whole window.
return
}
// This could probably lead to problems.
TWCDebouncer.LastTabGroup = window.tabGroup
// Store the initial tab count.
if TWCDebouncer.TabStartCounts[TWCDebouncer.LastTabGroup!] == nil {
TWCDebouncer.TabStartCounts[TWCDebouncer.LastTabGroup!] = window.tabbedWindows?.count
}
// Initialize the list of windows closing.
if TWCDebouncer.Windows[TWCDebouncer.LastTabGroup!] == nil {
TWCDebouncer.Windows[TWCDebouncer.LastTabGroup!] = []
}
// Set up the debounced function.
if TWCDebouncer.Debouncers[TWCDebouncer.LastTabGroup!] == nil {
TWCDebouncer.Debouncers[TWCDebouncer.LastTabGroup!] = debounce(delay: .milliseconds(20), action: {
let countAfter = TWCDebouncer.LastTabGroup?.windows.count ?? 0
print(TWCDebouncer.Windows[TWCDebouncer.LastTabGroup!])
if countAfter == 0 {
// All windows were closed.
} else {
// One or more windows were closed in the tab group
}
// Reset.
TWCDebouncer.Debouncers[TWCDebouncer.LastTabGroup!] = nil
TWCDebouncer.TabStartCounts[TWCDebouncer.LastTabGroup!] = nil
TWCDebouncer.Windows[TWCDebouncer.LastTabGroup!] = nil
TWCDebouncer.LastTabGroup = nil
})
}
// Store the window.
TWCDebouncer.Windows[TWCDebouncer.LastTabGroup!]?.append(window)
// Call the debounced function.
TWCDebouncer.Debouncers[window.tabGroup!]!()
}
}
To use it, I've put it on my WindowController
. I had to put it in windowShouldClose
, by the time windowWillClose
is called, window.tabbedWindows
is nil
.
class WindowController: NSWindowController {
var closeDebouncer = TWCDebouncer()
func windowShouldClose(_ sender: NSWindow) -> Bool {
self.closeDebouncer.handleClose(window: self.window!)
return true
}
}
Upvotes: 0