macos: fix tabs vs spaces

This commit is contained in:
Mitchell Hashimoto
2024-01-31 12:06:58 -08:00
parent 939bb22615
commit 1a3d2d151e
2 changed files with 78 additions and 78 deletions

View File

@ -204,11 +204,11 @@ class TerminalController: NSWindowController, NSWindowDelegate,
// Center the window to start, we'll move the window frame automatically // Center the window to start, we'll move the window frame automatically
// when cascading. // when cascading.
window.center() window.center()
// Set the background color of the window // Set the background color of the window
window.backgroundColor = NSColor(ghostty.config.backgroundColor) window.backgroundColor = NSColor(ghostty.config.backgroundColor)
// Handle titlebar tabs config option // Handle titlebar tabs config option
window.titlebarTabs = ghostty.config.macosTitlebarTabs window.titlebarTabs = ghostty.config.macosTitlebarTabs
window.setTitlebarBackground( window.setTitlebarBackground(
window window
@ -216,7 +216,7 @@ class TerminalController: NSWindowController, NSWindowDelegate,
.withAlphaComponent(ghostty.config.backgroundOpacity) .withAlphaComponent(ghostty.config.backgroundOpacity)
.cgColor .cgColor
) )
// Initialize our content view to the SwiftUI root // Initialize our content view to the SwiftUI root
window.contentView = NSHostingView(rootView: TerminalView( window.contentView = NSHostingView(rootView: TerminalView(
ghostty: self.ghostty, ghostty: self.ghostty,

View File

@ -19,8 +19,8 @@ class TerminalWindow: NSWindow {
} }
// MARK: - Titlebar Tabs // MARK: - Titlebar Tabs
// Used by the window controller to enable/disable titlebar tabs. // Used by the window controller to enable/disable titlebar tabs.
var titlebarTabs = false { var titlebarTabs = false {
didSet { didSet {
changedTitlebarTabs(to: titlebarTabs) changedTitlebarTabs(to: titlebarTabs)
@ -32,7 +32,7 @@ class TerminalWindow: NSWindow {
// The tab bar controller ID from macOS // The tab bar controller ID from macOS
static private let TabBarController = NSUserInterfaceItemIdentifier("_tabBarController") static private let TabBarController = NSUserInterfaceItemIdentifier("_tabBarController")
/// This is called by titlebarTabs changing so that we can setup the rest of our window /// This is called by titlebarTabs changing so that we can setup the rest of our window
private func changedTitlebarTabs(to newValue: Bool) { private func changedTitlebarTabs(to newValue: Bool) {
self.titlebarAppearsTransparent = newValue self.titlebarAppearsTransparent = newValue
@ -61,41 +61,41 @@ class TerminalWindow: NSWindow {
titlebarContainer.wantsLayer = true titlebarContainer.wantsLayer = true
titlebarContainer.layer?.backgroundColor = color titlebarContainer.layer?.backgroundColor = color
} }
// 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) {
let isTabBar = self.titlebarTabs && ( let isTabBar = self.titlebarTabs && (
childViewController.layoutAttribute == .bottom || childViewController.layoutAttribute == .bottom ||
childViewController.identifier == Self.TabBarController childViewController.identifier == Self.TabBarController
) )
if (isTabBar) { if (isTabBar) {
// Ensure it has the right layoutAttribute to force it next to our titlebar // Ensure it has the right layoutAttribute to force it next to our titlebar
childViewController.layoutAttribute = .right childViewController.layoutAttribute = .right
// Hide the title text if the tab bar is showing since we show it in the tab // Hide the title text if the tab bar is showing since we show it in the tab
titleVisibility = .hidden titleVisibility = .hidden
// Mark the controller for future reference so we can easily find it. Otherwise // Mark the controller for future reference so we can easily find it. Otherwise
// the tab bar has no ID by default. // the tab bar has no ID by default.
childViewController.identifier = Self.TabBarController childViewController.identifier = Self.TabBarController
} }
super.addTitlebarAccessoryViewController(childViewController) super.addTitlebarAccessoryViewController(childViewController)
if (isTabBar) { if (isTabBar) {
pushTabsToTitlebar(childViewController) pushTabsToTitlebar(childViewController)
} }
} }
override func removeTitlebarAccessoryViewController(at index: Int) { override func removeTitlebarAccessoryViewController(at index: Int) {
let childViewController = titlebarAccessoryViewControllers[index] let childViewController = titlebarAccessoryViewControllers[index]
super.removeTitlebarAccessoryViewController(at: index) super.removeTitlebarAccessoryViewController(at: index)
if (childViewController.identifier == Self.TabBarController) { if (childViewController.identifier == Self.TabBarController) {
hideCustomTabBarViews() hideCustomTabBarViews()
} }
} }
// To be called immediately after the tab bar is disabled. // To be called immediately after the tab bar is disabled.
private func hideCustomTabBarViews() { private func hideCustomTabBarViews() {
@ -108,45 +108,45 @@ class TerminalWindow: NSWindow {
// Enable the window title text. // Enable the window title text.
titleVisibility = .visible titleVisibility = .visible
} }
private func pushTabsToTitlebar(_ tabBarController: NSTitlebarAccessoryViewController) { private func pushTabsToTitlebar(_ tabBarController: NSTitlebarAccessoryViewController) {
let accessoryView = tabBarController.view let accessoryView = tabBarController.view
guard let accessoryClipView = accessoryView.superview else { return } guard let accessoryClipView = accessoryView.superview else { return }
guard let titlebarView = accessoryClipView.superview else { return } guard let titlebarView = accessoryClipView.superview else { return }
guard titlebarView.className == "NSTitlebarView" else { return } guard titlebarView.className == "NSTitlebarView" else { return }
guard let toolbarView = titlebarView.subviews.first(where: { guard let toolbarView = titlebarView.subviews.first(where: {
$0.className == "NSToolbarView" $0.className == "NSToolbarView"
}) else { return } }) else { return }
addWindowButtonsBackdrop(titlebarView: titlebarView, toolbarView: toolbarView) addWindowButtonsBackdrop(titlebarView: titlebarView, toolbarView: toolbarView)
guard let windowButtonsBackdrop = windowButtonsBackdrop else { return } guard let windowButtonsBackdrop = windowButtonsBackdrop else { return }
windowButtonsBackdrop.isHidden = false windowButtonsBackdrop.isHidden = false
addWindowDragHandle(titlebarView: titlebarView, toolbarView: toolbarView) addWindowDragHandle(titlebarView: titlebarView, toolbarView: toolbarView)
windowDragHandle?.isHidden = false windowDragHandle?.isHidden = false
accessoryClipView.translatesAutoresizingMaskIntoConstraints = false accessoryClipView.translatesAutoresizingMaskIntoConstraints = false
accessoryClipView.leftAnchor.constraint(equalTo: windowButtonsBackdrop.rightAnchor).isActive = true accessoryClipView.leftAnchor.constraint(equalTo: windowButtonsBackdrop.rightAnchor).isActive = true
accessoryClipView.rightAnchor.constraint(equalTo: toolbarView.rightAnchor).isActive = true accessoryClipView.rightAnchor.constraint(equalTo: toolbarView.rightAnchor).isActive = true
accessoryClipView.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true accessoryClipView.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
accessoryClipView.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true accessoryClipView.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
accessoryClipView.needsLayout = true accessoryClipView.needsLayout = true
accessoryView.translatesAutoresizingMaskIntoConstraints = false accessoryView.translatesAutoresizingMaskIntoConstraints = false
accessoryView.leftAnchor.constraint(equalTo: accessoryClipView.leftAnchor).isActive = true accessoryView.leftAnchor.constraint(equalTo: accessoryClipView.leftAnchor).isActive = true
accessoryView.rightAnchor.constraint(equalTo: accessoryClipView.rightAnchor).isActive = true accessoryView.rightAnchor.constraint(equalTo: accessoryClipView.rightAnchor).isActive = true
accessoryView.topAnchor.constraint(equalTo: accessoryClipView.topAnchor).isActive = true accessoryView.topAnchor.constraint(equalTo: accessoryClipView.topAnchor).isActive = true
accessoryView.heightAnchor.constraint(equalTo: accessoryClipView.heightAnchor).isActive = true accessoryView.heightAnchor.constraint(equalTo: accessoryClipView.heightAnchor).isActive = true
accessoryView.needsLayout = true accessoryView.needsLayout = true
// This is a horrible hack. During the transition while things are resizing to make room for // This is a horrible hack. During the transition while things are resizing to make room for
// new tabs or expand existing tabs to fill the empty space after one is closed, the centering // new tabs or expand existing tabs to fill the empty space after one is closed, the centering
// of the tab titles can't be properly calculated, so we wait for 0.2 seconds and then mark // of the tab titles can't be properly calculated, so we wait for 0.2 seconds and then mark
// the entire view hierarchy for the tab bar as dirty to fix the positioning... // the entire view hierarchy for the tab bar as dirty to fix the positioning...
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.markHierarchyForLayout(accessoryView) self.markHierarchyForLayout(accessoryView)
} }
} }
private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) { private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) {
guard windowButtonsBackdrop == nil else { return } guard windowButtonsBackdrop == nil else { return }
@ -190,18 +190,18 @@ class TerminalWindow: NSWindow {
windowDragHandle = view windowDragHandle = view
} }
// This forces this view and all subviews to update layout and redraw. This is // This forces this view and all subviews to update layout and redraw. This is
// a hack (see the caller). // a hack (see the caller).
private func markHierarchyForLayout(_ view: NSView) { private func markHierarchyForLayout(_ view: NSView) {
view.needsUpdateConstraints = true view.needsUpdateConstraints = true
view.needsLayout = true view.needsLayout = true
view.needsDisplay = true view.needsDisplay = true
view.setNeedsDisplay(view.bounds) view.setNeedsDisplay(view.bounds)
for subview in view.subviews { for subview in view.subviews {
markHierarchyForLayout(subview) markHierarchyForLayout(subview)
} }
} }
} }
// Passes mouseDown events from this view to window.performDrag so that you can drag the window by it. // Passes mouseDown events from this view to window.performDrag so that you can drag the window by it.