mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-06-04 06:28:38 +03:00
macOS: center window title when titlebar tabs enabled
Uses a custom toolbar that populates itself with a centered text field and provides a method to set the text.
This commit is contained in:
@ -65,6 +65,7 @@
|
||||
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */; };
|
||||
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */; };
|
||||
A5FEB3002ABB69450068369E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FEB2FF2ABB69450068369E /* main.swift */; };
|
||||
AEF9CE242B6AD07A0017E195 /* TerminalToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */; };
|
||||
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
|
||||
C159E89D2B69A2EF00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -125,6 +126,7 @@
|
||||
A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationController.swift; sourceTree = "<group>"; };
|
||||
A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationView.swift; sourceTree = "<group>"; };
|
||||
A5FEB2FF2ABB69450068369E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalToolbar.swift; sourceTree = "<group>"; };
|
||||
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSColor+Extension.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -281,6 +283,7 @@
|
||||
A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */,
|
||||
A596309D2AEE1D6C00D64628 /* TerminalView.swift */,
|
||||
A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */,
|
||||
AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */,
|
||||
A535B9D9299C569B0017E2E4 /* ErrorView.swift */,
|
||||
);
|
||||
path = Terminal;
|
||||
@ -493,6 +496,7 @@
|
||||
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */,
|
||||
8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */,
|
||||
A596309E2AEE1D6C00D64628 /* TerminalView.swift in Sources */,
|
||||
AEF9CE242B6AD07A0017E195 /* TerminalToolbar.swift in Sources */,
|
||||
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */,
|
||||
A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */,
|
||||
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */,
|
||||
|
@ -482,7 +482,13 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
||||
}
|
||||
|
||||
func titleDidChange(to: String) {
|
||||
self.window?.title = to
|
||||
guard let window = window as? TerminalWindow else { return }
|
||||
|
||||
window.title = to
|
||||
|
||||
// Custom toolbar-based title used when titlebar tabs are enabled.
|
||||
guard let toolbar = window.toolbar as? TerminalToolbar else { return }
|
||||
toolbar.setTitleText(to)
|
||||
}
|
||||
|
||||
func cellSizeDidChange(to: NSSize) {
|
||||
|
44
macos/Sources/Features/Terminal/TerminalToolbar.swift
Normal file
44
macos/Sources/Features/Terminal/TerminalToolbar.swift
Normal file
@ -0,0 +1,44 @@
|
||||
// Custom NSToolbar subclass that displays a centered window title,
|
||||
// in order to accommodate the titlebar tabs feature.
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import SwiftUI
|
||||
|
||||
class TerminalToolbar: NSToolbar, NSToolbarDelegate {
|
||||
static private let TitleIdentifier = NSToolbarItem.Identifier("TitleText")
|
||||
private let TitleTextField = NSTextField(
|
||||
labelWithString: "👻 Ghostty"
|
||||
)
|
||||
|
||||
func setTitleText(_ text: String) {
|
||||
self.TitleTextField.stringValue = text
|
||||
}
|
||||
|
||||
override init(identifier: NSToolbar.Identifier) {
|
||||
super.init(identifier: identifier)
|
||||
delegate = self
|
||||
if #available(macOS 13.0, *) {
|
||||
centeredItemIdentifiers.insert(Self.TitleIdentifier)
|
||||
} else {
|
||||
centeredItemIdentifier = Self.TitleIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
||||
guard itemIdentifier == Self.TitleIdentifier else { return nil }
|
||||
|
||||
let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
|
||||
toolbarItem.isEnabled = true
|
||||
toolbarItem.view = self.TitleTextField
|
||||
return toolbarItem
|
||||
}
|
||||
|
||||
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [Self.TitleIdentifier]
|
||||
}
|
||||
|
||||
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||
return [Self.TitleIdentifier]
|
||||
}
|
||||
}
|
@ -42,8 +42,12 @@ class TerminalWindow: NSWindow {
|
||||
// so we make sure it's the right size/position, and exists.
|
||||
self.toolbarStyle = .unifiedCompact
|
||||
if (self.toolbar == nil) {
|
||||
self.toolbar = NSToolbar(identifier: "Toolbar")
|
||||
self.toolbar = TerminalToolbar(identifier: "Toolbar")
|
||||
}
|
||||
// We directly hide the view containing the title text because if we use the
|
||||
// `titleVisibility` property for this it prevents the window from hiding the
|
||||
// tab bar when we get down to a single tab.
|
||||
self.hideTitleText()
|
||||
} else {
|
||||
// "expanded" places the toolbar below the titlebar, so setting this style and
|
||||
// removing the toolbar ensures that the titlebar will be the default height.
|
||||
@ -62,6 +66,21 @@ class TerminalWindow: NSWindow {
|
||||
titlebarContainer.layer?.backgroundColor = color
|
||||
}
|
||||
|
||||
// Directly hide the view containing the title text
|
||||
func hideTitleText() {
|
||||
guard let toolbarTitleView = contentView?.superview?.subviews.first(where: {
|
||||
$0.className == "NSTitlebarContainerView"
|
||||
})?.subviews.first(where: {
|
||||
$0.className == "NSTitlebarView"
|
||||
})?.subviews.first(where: {
|
||||
$0.className == "NSToolbarView"
|
||||
})?.subviews.first(where: {
|
||||
$0.className == "NSToolbarTitleView"
|
||||
}) else { return }
|
||||
|
||||
toolbarTitleView.isHidden = true
|
||||
}
|
||||
|
||||
// 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.
|
||||
override func addTitlebarAccessoryViewController(_ childViewController: NSTitlebarAccessoryViewController) {
|
||||
@ -74,7 +93,8 @@ class TerminalWindow: NSWindow {
|
||||
// Ensure it has the right layoutAttribute to force it next to our titlebar
|
||||
childViewController.layoutAttribute = .right
|
||||
|
||||
// Hide the title text if the tab bar is showing since we show it in the tab
|
||||
// If we don't set titleVisibility to hidden here, the toolbar will display a
|
||||
// "collapsed items" indicator which interferes with the tab bar.
|
||||
titleVisibility = .hidden
|
||||
|
||||
// Mark the controller for future reference so we can easily find it. Otherwise
|
||||
@ -90,9 +110,9 @@ class TerminalWindow: NSWindow {
|
||||
}
|
||||
|
||||
override func removeTitlebarAccessoryViewController(at index: Int) {
|
||||
let childViewController = titlebarAccessoryViewControllers[index]
|
||||
let isTabBar = titlebarAccessoryViewControllers[index].identifier == Self.TabBarController
|
||||
super.removeTitlebarAccessoryViewController(at: index)
|
||||
if (childViewController.identifier == Self.TabBarController) {
|
||||
if (isTabBar) {
|
||||
hideCustomTabBarViews()
|
||||
}
|
||||
}
|
||||
@ -104,9 +124,6 @@ class TerminalWindow: NSWindow {
|
||||
|
||||
// Hide the window drag handle.
|
||||
windowDragHandle?.isHidden = true
|
||||
|
||||
// Enable the window title text.
|
||||
titleVisibility = .visible
|
||||
}
|
||||
|
||||
private func pushTabsToTitlebar(_ tabBarController: NSTitlebarAccessoryViewController) {
|
||||
|
Reference in New Issue
Block a user