diff --git a/macos/Sources/AppDelegate.swift b/macos/Sources/AppDelegate.swift index 26afa3f21..a508622df 100644 --- a/macos/Sources/AppDelegate.swift +++ b/macos/Sources/AppDelegate.swift @@ -233,8 +233,7 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, GhosttyApp } private func focusedSurface() -> ghostty_surface_t? { - guard let window = NSApp.keyWindow as? PrimaryWindow else { return nil } - return window.focusedSurfaceWrapper.surface + return terminalManager.focusedSurface?.surface } private func splitMoveFocus(direction: Ghostty.SplitFocusDirection) { diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index d8a0c0d64..80bb0a7f0 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -9,6 +9,9 @@ class TerminalController: NSWindowController, NSWindowDelegate, TerminalViewDele /// The app instance that this terminal view will represent. let ghostty: Ghostty.AppState + /// The currently focused surface. + var focusedSurface: Ghostty.SurfaceView? = nil + init(_ ghostty: Ghostty.AppState) { self.ghostty = ghostty super.init(window: nil) @@ -49,6 +52,13 @@ class TerminalController: NSWindowController, NSWindowDelegate, TerminalViewDele )) } + // Shows the "+" button in the tab bar, responds to that click. + override func newWindowForTab(_ sender: Any?) { + // Trigger the ghostty core event logic for a new tab. + guard let surface = self.focusedSurface?.surface else { return } + ghostty.newTab(surface: surface) + } + //MARK: - NSWindowDelegate func windowWillClose(_ notification: Notification) { @@ -56,6 +66,10 @@ class TerminalController: NSWindowController, NSWindowDelegate, TerminalViewDele //MARK: - TerminalViewDelegate + func focusedSurfaceDidChange(to: Ghostty.SurfaceView?) { + self.focusedSurface = to + } + func titleDidChange(to: String) { self.window?.title = to } diff --git a/macos/Sources/Features/Terminal/TerminalManager.swift b/macos/Sources/Features/Terminal/TerminalManager.swift index 35eb054bb..ca0c0d3fe 100644 --- a/macos/Sources/Features/Terminal/TerminalManager.swift +++ b/macos/Sources/Features/Terminal/TerminalManager.swift @@ -1,4 +1,5 @@ import Cocoa +import SwiftUI /// Manages a set of terminal windows. class TerminalManager { @@ -8,6 +9,9 @@ class TerminalManager { let ghostty: Ghostty.AppState + /// The currently focused surface of the main window. + var focusedSurface: Ghostty.SurfaceView? { mainWindow?.controller.focusedSurface } + /// The set of windows we currently have. private var windows: [Window] = [] @@ -26,6 +30,30 @@ class TerminalManager { init(_ ghostty: Ghostty.AppState) { self.ghostty = ghostty + + let center = NotificationCenter.default + center.addObserver( + self, + selector: #selector(onNewTab), + name: Ghostty.Notification.ghosttyNewTab, + object: nil) + center.addObserver( + self, + selector: #selector(onNewWindow), + name: Ghostty.Notification.ghosttyNewWindow, + object: nil) + } + + deinit { + let center = NotificationCenter.default; + center.removeObserver( + self, + name: Ghostty.Notification.ghosttyNewTab, + object: nil) + center.removeObserver( + self, + name: Ghostty.Notification.ghosttyNewWindow, + object: nil) } /// Create a new terminal window. @@ -43,6 +71,11 @@ class TerminalManager { return } + // Create a new window and add it to the parent + newTab(to: parent, withBaseConfig: base) + } + + private func newTab(to parent: NSWindow, withBaseConfig base: Ghostty.SurfaceConfiguration?) { // Create a new window and add it to the parent let window = createWindow(withBaseConfig: base).window! parent.addTabbedWindow(window, ordered: .above) @@ -50,7 +83,7 @@ class TerminalManager { } /// Creates a window controller, adds it to our managed list, and returns it. - func createWindow(withBaseConfig: Ghostty.SurfaceConfiguration?) -> TerminalController { + private func createWindow(withBaseConfig: Ghostty.SurfaceConfiguration?) -> TerminalController { // Initialize our controller to load the window let c = TerminalController(ghostty) @@ -59,4 +92,20 @@ class TerminalManager { return c } + + @objc private func onNewWindow(notification: SwiftUI.Notification) { + let configAny = notification.userInfo?[Ghostty.Notification.NewSurfaceConfigKey] + let config = configAny as? Ghostty.SurfaceConfiguration + self.newWindow(withBaseConfig: config) + } + + @objc private func onNewTab(notification: SwiftUI.Notification) { + guard let surfaceView = notification.object as? Ghostty.SurfaceView else { return } + guard let window = surfaceView.window else { return } + + let configAny = notification.userInfo?[Ghostty.Notification.NewSurfaceConfigKey] + let config = configAny as? Ghostty.SurfaceConfiguration + + self.newTab(to: window, withBaseConfig: config) + } }