From c0951ce6d8887ea81e29b3485dc828d3f9191601 Mon Sep 17 00:00:00 2001 From: Denys Zhak Date: Sat, 6 Dec 2025 20:44:30 +0000 Subject: [PATCH 1/3] macOS: fix tab context menu opens on macOS 26 with titlebar tabs --- .../TitlebarTabsTahoeTerminalWindow.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift index 7ce138c2a..802e98dc1 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift @@ -8,6 +8,9 @@ import SwiftUI class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSToolbarDelegate { /// The view model for SwiftUI views private var viewModel = ViewModel() + + /// Tb bar view for event routing + private weak var tabBarView: NSView? /// Titlebar tabs can't support the update accessory because of the way we layout /// the native tabs back into the menu bar. @@ -67,6 +70,30 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool viewModel.isMainWindow = false } + + override func sendEvent(_ event: NSEvent) { + guard let tabBarView, viewModel.hasTabBar else { + super.sendEvent(event) + return + } + + let isRightClick = + event.type == .rightMouseDown || + (event.type == .otherMouseDown && event.buttonNumber == 2) + + guard isRightClick else { + super.sendEvent(event) + return + } + let locationInTabBar = tabBarView.convert(event.locationInWindow, from: nil) + + if tabBarView.bounds.contains(locationInTabBar) { + tabBarView.rightMouseDown(with: event) + } else { + super.sendEvent(event) + } + } + // 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) { @@ -148,6 +175,8 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool let tabBar = findTabBar() else { return } + self.tabBarView = tabBar + // View model updates must happen on their own ticks. DispatchQueue.main.async { [weak self] in self?.viewModel.hasTabBar = true @@ -206,6 +235,7 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool // Remove the observer so we can call setup again. self.tabBarObserver = nil + self.tabBarView = nil // Wait a tick to let the new tab bars appear and then set them up. DispatchQueue.main.async { @@ -223,6 +253,7 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool // Clear our observations self.tabBarObserver = nil + self.tabBarView = nil } // MARK: NSToolbarDelegate From 969bcbe8e308a72aa96a5a8d47c53ffc6708bcb7 Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Sun, 7 Dec 2025 09:02:03 +0100 Subject: [PATCH 2/3] Update macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift --- .../Window Styles/TitlebarTabsTahoeTerminalWindow.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift index 802e98dc1..a58b8ba91 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift @@ -9,7 +9,7 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool /// The view model for SwiftUI views private var viewModel = ViewModel() - /// Tb bar view for event routing + /// Tab bar view for event routing private weak var tabBarView: NSView? /// Titlebar tabs can't support the update accessory because of the way we layout From 76c2de6088581c7d634679b67bec8d9f1b90576c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 10 Dec 2025 20:09:26 -0800 Subject: [PATCH 3/3] macos: remove the tabBarView variable we can search it --- .../TitlebarTabsTahoeTerminalWindow.swift | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift index a58b8ba91..5d910d2e0 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift @@ -8,9 +8,6 @@ import SwiftUI class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSToolbarDelegate { /// The view model for SwiftUI views private var viewModel = ViewModel() - - /// Tab bar view for event routing - private weak var tabBarView: NSView? /// Titlebar tabs can't support the update accessory because of the way we layout /// the native tabs back into the menu bar. @@ -71,27 +68,35 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool viewModel.isMainWindow = false } + /// On our Tahoe titlebar tabs, we need to fix up right click events because they don't work + /// naturally due to whatever mess we made. override func sendEvent(_ event: NSEvent) { - guard let tabBarView, viewModel.hasTabBar else { + guard viewModel.hasTabBar else { super.sendEvent(event) return } let isRightClick = event.type == .rightMouseDown || - (event.type == .otherMouseDown && event.buttonNumber == 2) - + (event.type == .otherMouseDown && event.buttonNumber == 2) || + (event.type == .leftMouseDown && event.modifierFlags.contains(.control)) guard isRightClick else { super.sendEvent(event) return } - let locationInTabBar = tabBarView.convert(event.locationInWindow, from: nil) - - if tabBarView.bounds.contains(locationInTabBar) { - tabBarView.rightMouseDown(with: event) - } else { + + guard let tabBarView = findTabBar() else { super.sendEvent(event) + return } + + let locationInTabBar = tabBarView.convert(event.locationInWindow, from: nil) + guard tabBarView.bounds.contains(locationInTabBar) else { + super.sendEvent(event) + return + } + + tabBarView.rightMouseDown(with: event) } // This is called by macOS for native tabbing in order to add the tab bar. We hook into @@ -175,8 +180,6 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool let tabBar = findTabBar() else { return } - self.tabBarView = tabBar - // View model updates must happen on their own ticks. DispatchQueue.main.async { [weak self] in self?.viewModel.hasTabBar = true @@ -235,7 +238,6 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool // Remove the observer so we can call setup again. self.tabBarObserver = nil - self.tabBarView = nil // Wait a tick to let the new tab bars appear and then set them up. DispatchQueue.main.async { @@ -253,7 +255,6 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool // Clear our observations self.tabBarObserver = nil - self.tabBarView = nil } // MARK: NSToolbarDelegate