From 3f6683df026801f604e7988bcfdd99ff67958400 Mon Sep 17 00:00:00 2001 From: Nicholas Ochoa Date: Sun, 29 Mar 2026 14:22:49 -0500 Subject: [PATCH] macos: add support for middle-click tab close --- .../Window Styles/TerminalWindow.swift | 26 +++++++++++++++++++ .../TitlebarTabsTahoeTerminalWindow.swift | 3 +++ .../TitlebarTabsVenturaTerminalWindow.swift | 5 ++++ 3 files changed, 34 insertions(+) diff --git a/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift index e19d6711f..6605bf9ef 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift @@ -840,3 +840,29 @@ extension TerminalWindow: TabTitleEditorDelegate { makeFirstResponder(focusedSurface) } } + +// MARK: - Tab Clicks + +extension TerminalWindow { + /// Handles a middle-click event to close the tab under the cursor + /// + /// Returns true if the event was handled and should be consumed + func handleTabBarMiddleClick(_ event: NSEvent) -> Bool { + // Require middle click + guard event.type == .otherMouseDown && event.buttonNumber == 2 else { return false } + + // Require tab hit + let screenPoint = convertPoint(toScreen: event.locationInWindow) + guard let hit = tabButtonHit(atScreenPoint: screenPoint) else { return false } + + // Require we have tabs and the index is valid + guard let tabbedWindows = tabbedWindows, + hit.index < tabbedWindows.count else { return false } + + // Find the controller and close it + let targetWindow = tabbedWindows[hit.index] + guard let controller = targetWindow.windowController as? TerminalController else { return false } + controller.closeTab(nil) + return true + } +} diff --git a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift index 6df1b14bc..9e7bbc1c3 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift @@ -76,6 +76,9 @@ class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSTool return } + // Handle middle-click to close tabs if configured + if handleTabBarMiddleClick(event) { return } + let isRightClick = event.type == .rightMouseDown || (event.type == .otherMouseDown && event.buttonNumber == 2) || diff --git a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift index fe83fc5fd..25a0acc91 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift @@ -69,6 +69,11 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow { tab.attributedTitle = attributedTitle } + override func sendEvent(_ event: NSEvent) { + if tabBarView != nil && handleTabBarMiddleClick(event) { return } + super.sendEvent(event) + } + override func layoutIfNeeded() { super.layoutIfNeeded()