ghostty/macos/Sources/Features/Terminal/TerminalManager.swift
2023-10-30 09:06:24 -07:00

112 lines
3.8 KiB
Swift

import Cocoa
import SwiftUI
/// Manages a set of terminal windows.
class TerminalManager {
struct Window {
let controller: TerminalController
}
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] = []
/// Returns the main window of the managed window stack. If there is no window
/// then an arbitrary window will be chosen.
private var mainWindow: Window? {
for window in windows {
if (window.controller.window?.isMainWindow ?? false) {
return window
}
}
// If we have no main window, just use the first window.
return windows.first
}
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.
func newWindow(withBaseConfig base: Ghostty.SurfaceConfiguration? = nil) {
let c = createWindow(withBaseConfig: base)
c.showWindow(self)
}
/// Creates a new tab in the current main window. If there are no windows, a window
/// is created.
func newTab(withBaseConfig base: Ghostty.SurfaceConfiguration? = nil) {
// If there is no main window, just create a new window
guard let parent = mainWindow?.controller.window else {
newWindow(withBaseConfig: base)
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)
window.makeKeyAndOrderFront(self)
}
/// Creates a window controller, adds it to our managed list, and returns it.
private func createWindow(withBaseConfig: Ghostty.SurfaceConfiguration?) -> TerminalController {
// Initialize our controller to load the window
let c = TerminalController(ghostty)
// Keep track of every window we manage
windows.append(Window(controller: c))
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)
}
}