mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: fix tabs vs spaces
This commit is contained in:
@ -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,
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user