Merge pull request #2254 from qwerasd205/sequoia-title-fix

Sequoia titlebar tabs fix
This commit is contained in:
Mitchell Hashimoto
2024-09-17 12:36:03 -07:00
committed by GitHub
2 changed files with 62 additions and 30 deletions

View File

@ -634,6 +634,12 @@ class TerminalController: NSWindowController, NSWindowDelegate,
// Custom toolbar-based title used when titlebar tabs are enabled. // Custom toolbar-based title used when titlebar tabs are enabled.
if let toolbar = window.toolbar as? TerminalToolbar { if let toolbar = window.toolbar as? TerminalToolbar {
if (window.titlebarTabs) {
// Updating the title text as above automatically reveals the
// native title view in macOS 15.0 and above. Since we're using
// a custom view instead, we need to re-hide it.
window.titleVisibility = .hidden
}
toolbar.titleText = to toolbar.titleText = to
} }
} }

View File

@ -140,6 +140,10 @@ class TerminalWindow: NSWindow {
guard hasStyledTabs else { return } guard hasStyledTabs else { return }
titlebarSeparatorStyle = tabbedWindows != nil && !titlebarTabs ? .line : .none titlebarSeparatorStyle = tabbedWindows != nil && !titlebarTabs ? .line : .none
if titlebarTabs {
hideToolbarOverflowButton()
hideTitleBarSeparators()
}
if !effectViewIsHidden { if !effectViewIsHidden {
// By hiding the visual effect view, we allow the window's (or titlebar's in this case) // By hiding the visual effect view, we allow the window's (or titlebar's in this case)
@ -165,6 +169,7 @@ class TerminalWindow: NSWindow {
super.updateConstraintsIfNeeded() super.updateConstraintsIfNeeded()
if titlebarTabs { if titlebarTabs {
hideToolbarOverflowButton()
hideTitleBarSeparators() hideTitleBarSeparators()
} }
} }
@ -418,7 +423,9 @@ class TerminalWindow: NSWindow {
self.titleVisibility = titlebarTabs ? .hidden : .visible self.titleVisibility = titlebarTabs ? .hidden : .visible
if titlebarTabs { if titlebarTabs {
generateToolbar() generateToolbar()
} } else {
toolbar = nil
}
} }
} }
@ -452,6 +459,20 @@ class TerminalWindow: NSWindow {
} }
} }
// HACK: hide the "collapsed items" marker from the toolbar if it's present.
// idk why it appears in macOS 15.0+ but it does... so... make it go away. (sigh)
private func hideToolbarOverflowButton() {
guard let windowButtonsBackdrop = windowButtonsBackdrop else { return }
guard let titlebarView = windowButtonsBackdrop.superview else { return }
guard titlebarView.className == "NSTitlebarView" else { return }
guard let toolbarView = titlebarView.subviews.first(where: {
$0.className == "NSToolbarView"
}) else { return }
toolbarView.subviews.first(where: { $0.className == "NSToolbarClippedItemsIndicatorViewer" })?.isHidden = true
}
// This is called by macOS for native tabbing in order to add the tab bar. We hook into // This is called by macOS for native tabbing in order to add the tab bar. We hook into
// this, detect the tab bar being added, and override its behavior. // this, detect the tab bar being added, and override its behavior.
override func addTitlebarAccessoryViewController(_ childViewController: NSTitlebarAccessoryViewController) { override func addTitlebarAccessoryViewController(_ childViewController: NSTitlebarAccessoryViewController) {
@ -498,40 +519,45 @@ class TerminalWindow: NSWindow {
} }
private func pushTabsToTitlebar(_ tabBarController: NSTitlebarAccessoryViewController) { private func pushTabsToTitlebar(_ tabBarController: NSTitlebarAccessoryViewController) {
let accessoryView = tabBarController.view // We need a toolbar as a target for our titlebar tabs.
guard let accessoryClipView = accessoryView.superview else { return } if (toolbar == nil) {
guard let titlebarView = accessoryClipView.superview else { return } generateToolbar()
guard titlebarView.className == "NSTitlebarView" else { return } }
guard let toolbarView = titlebarView.subviews.first(where: {
$0.className == "NSToolbarView"
}) else { return }
addWindowButtonsBackdrop(titlebarView: titlebarView, toolbarView: toolbarView) // HACK: wait a tick before doing anything, to avoid edge cases during startup... :/
guard let windowButtonsBackdrop = windowButtonsBackdrop else { return } // If we don't do this then on launch windows with restored state with tabs will end
// up with messed up tab bars that don't show all tabs.
DispatchQueue.main.async { [weak self] in
let accessoryView = tabBarController.view
guard let accessoryClipView = accessoryView.superview else { return }
guard let titlebarView = accessoryClipView.superview else { return }
guard titlebarView.className == "NSTitlebarView" else { return }
guard let toolbarView = titlebarView.subviews.first(where: {
$0.className == "NSToolbarView"
}) else { return }
addWindowDragHandle(titlebarView: titlebarView, toolbarView: toolbarView) self?.addWindowButtonsBackdrop(titlebarView: titlebarView, toolbarView: toolbarView)
guard let windowButtonsBackdrop = self?.windowButtonsBackdrop else { return }
accessoryClipView.translatesAutoresizingMaskIntoConstraints = false self?.addWindowDragHandle(titlebarView: titlebarView, toolbarView: toolbarView)
accessoryClipView.leftAnchor.constraint(equalTo: windowButtonsBackdrop.rightAnchor).isActive = true
accessoryClipView.rightAnchor.constraint(equalTo: toolbarView.rightAnchor).isActive = true
accessoryClipView.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
accessoryClipView.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
accessoryClipView.needsLayout = true
accessoryView.translatesAutoresizingMaskIntoConstraints = false accessoryClipView.translatesAutoresizingMaskIntoConstraints = false
accessoryView.leftAnchor.constraint(equalTo: accessoryClipView.leftAnchor).isActive = true accessoryClipView.leftAnchor.constraint(equalTo: windowButtonsBackdrop.rightAnchor).isActive = true
accessoryView.rightAnchor.constraint(equalTo: accessoryClipView.rightAnchor).isActive = true accessoryClipView.rightAnchor.constraint(equalTo: toolbarView.rightAnchor).isActive = true
accessoryView.topAnchor.constraint(equalTo: accessoryClipView.topAnchor).isActive = true accessoryClipView.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
accessoryView.heightAnchor.constraint(equalTo: accessoryClipView.heightAnchor).isActive = true accessoryClipView.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
accessoryView.needsLayout = true accessoryClipView.needsLayout = true
// This is a horrible hack. During the transition while things are resizing to make room for accessoryView.translatesAutoresizingMaskIntoConstraints = false
// new tabs or expand existing tabs to fill the empty space after one is closed, the centering accessoryView.leftAnchor.constraint(equalTo: accessoryClipView.leftAnchor).isActive = true
// of the tab titles can't be properly calculated, so we wait for 0.2 seconds and then mark accessoryView.rightAnchor.constraint(equalTo: accessoryClipView.rightAnchor).isActive = true
// the entire view hierarchy for the tab bar as dirty to fix the positioning... accessoryView.topAnchor.constraint(equalTo: accessoryClipView.topAnchor).isActive = true
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { accessoryView.heightAnchor.constraint(equalTo: accessoryClipView.heightAnchor).isActive = true
// self.markHierarchyForLayout(accessoryView) accessoryView.needsLayout = true
// }
self?.hideToolbarOverflowButton()
self?.hideTitleBarSeparators()
}
} }
private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) { private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) {