mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: handle the "+" button automatically adding the window to the tabs
Fixes #1010
This commit is contained in:
@ -167,15 +167,18 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
delegate: self
|
delegate: self
|
||||||
))
|
))
|
||||||
|
|
||||||
// If the user tabbing preference is always, then macOS automatically tabs
|
// In various situations, macOS automatically tabs new windows. Ghostty handles
|
||||||
// all new windows. Ghostty handles its own tabbing so we DONT want this behavior.
|
// its own tabbing so we DONT want this behavior. This detects this scenario and undoes
|
||||||
// This detects this scenario and undoes it.
|
// it.
|
||||||
|
//
|
||||||
|
// Example scenarios where this happens:
|
||||||
|
// - When the system user tabbing preference is "always"
|
||||||
|
// - When the "+" button in the tab bar is clicked
|
||||||
//
|
//
|
||||||
// We don't run this logic in fullscreen because in fullscreen this will end up
|
// We don't run this logic in fullscreen because in fullscreen this will end up
|
||||||
// removing the window and putting it into its own dedicated fullscreen, which is not
|
// removing the window and putting it into its own dedicated fullscreen, which is not
|
||||||
// the expected or desired behavior of anyone I've found.
|
// the expected or desired behavior of anyone I've found.
|
||||||
if (NSWindow.userTabbingPreference == .always &&
|
if (!window.styleMask.contains(.fullScreen)) {
|
||||||
!window.styleMask.contains(.fullScreen)) {
|
|
||||||
// If we have more than 1 window in our tab group we know we're a new window.
|
// If we have more than 1 window in our tab group we know we're a new window.
|
||||||
// Since Ghostty manages tabbing manually this will never be more than one
|
// Since Ghostty manages tabbing manually this will never be more than one
|
||||||
// at this point in the AppKit lifecycle (we add to the group after this).
|
// at this point in the AppKit lifecycle (we add to the group after this).
|
||||||
@ -189,21 +192,7 @@ class TerminalController: NSWindowController, NSWindowDelegate,
|
|||||||
override func newWindowForTab(_ sender: Any?) {
|
override func newWindowForTab(_ sender: Any?) {
|
||||||
// Trigger the ghostty core event logic for a new tab.
|
// Trigger the ghostty core event logic for a new tab.
|
||||||
guard let surface = self.focusedSurface?.surface else { return }
|
guard let surface = self.focusedSurface?.surface else { return }
|
||||||
|
ghostty.newTab(surface: surface)
|
||||||
// This is necessary due to a really strange issue on macOS that I was never
|
|
||||||
// able to figure out: if we create a new tab in this function directly, then
|
|
||||||
// it is incorrectly added to the wrong index in `tabGroup.windows`. The macOS
|
|
||||||
// `tabGroup.windows` documentation says that will always be in visual order
|
|
||||||
// of the tab but I was finding that not to be true. By introducing a small delay,
|
|
||||||
// I noticed everything works. I can't explain it and I'd rather not do this so
|
|
||||||
// if someone can figure this out that'd be great.
|
|
||||||
//
|
|
||||||
// See: https://github.com/mitchellh/ghostty/issues/1010
|
|
||||||
// Last reproduced on macOS 14.1
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { [weak self] in
|
|
||||||
guard let s = self else { return }
|
|
||||||
s.ghostty.newTab(surface: surface)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - NSWindowDelegate
|
//MARK: - NSWindowDelegate
|
||||||
|
@ -90,14 +90,33 @@ class TerminalManager {
|
|||||||
|
|
||||||
private func newTab(to parent: NSWindow, withBaseConfig base: Ghostty.SurfaceConfiguration?) {
|
private func newTab(to parent: NSWindow, withBaseConfig base: Ghostty.SurfaceConfiguration?) {
|
||||||
// Create a new window and add it to the parent
|
// Create a new window and add it to the parent
|
||||||
let window = createWindow(withBaseConfig: base).window!
|
let controller = createWindow(withBaseConfig: base)
|
||||||
|
let window = controller.window!
|
||||||
|
|
||||||
// If the parent is miniaturized, then macOS exhibits really strange behaviors
|
// If the parent is miniaturized, then macOS exhibits really strange behaviors
|
||||||
// so we have to bring it back out.
|
// so we have to bring it back out.
|
||||||
if (parent.isMiniaturized) { parent.deminiaturize(self) }
|
if (parent.isMiniaturized) { parent.deminiaturize(self) }
|
||||||
|
|
||||||
|
// If our parent tab group already has this window, macOS added it and
|
||||||
|
// we need to remove it so we can set the correct order in the next line.
|
||||||
|
// If we don't do this, macOS gets really confused and the tabbedWindows
|
||||||
|
// state becomes incorrect.
|
||||||
|
//
|
||||||
|
// At the time of writing this code, the only known case this happens
|
||||||
|
// is when the "+" button is clicked in the tab bar.
|
||||||
|
if let tg = parent.tabGroup, tg.windows.firstIndex(of: window) != nil {
|
||||||
|
tg.removeWindow(window)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the window to the tab group and show it
|
||||||
parent.addTabbedWindow(window, ordered: .above)
|
parent.addTabbedWindow(window, ordered: .above)
|
||||||
window.makeKeyAndOrderFront(self)
|
window.makeKeyAndOrderFront(self)
|
||||||
|
|
||||||
|
// It takes an event loop cycle until the macOS tabGroup state becomes
|
||||||
|
// consistent which causes our tab labeling to be off when the "+" button
|
||||||
|
// is used in the tab bar. This fixes that. If we can find a more robust
|
||||||
|
// solution we should do that.
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { controller.relabelTabs() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a window controller, adds it to our managed list, and returns it.
|
/// Creates a window controller, adds it to our managed list, and returns it.
|
||||||
|
Reference in New Issue
Block a user