125 lines
3.9 KiB
Swift
125 lines
3.9 KiB
Swift
import AppKit
|
|
import Combine
|
|
import SwiftUI
|
|
|
|
@MainActor
|
|
final class WindowToolbarController: NSObject, NSToolbarDelegate {
|
|
private let commandItemIdentifier = NSToolbarItem.Identifier("cmux.focusedCommand")
|
|
|
|
private weak var tabManager: TabManager?
|
|
|
|
private var commandLabels: [ObjectIdentifier: NSTextField] = [:]
|
|
private var observers: [NSObjectProtocol] = []
|
|
|
|
override init() {
|
|
super.init()
|
|
}
|
|
|
|
deinit {
|
|
for observer in observers {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
}
|
|
}
|
|
|
|
func start(tabManager: TabManager) {
|
|
self.tabManager = tabManager
|
|
attachToExistingWindows()
|
|
installObservers()
|
|
updateFocusedCommandText()
|
|
}
|
|
|
|
private func installObservers() {
|
|
let center = NotificationCenter.default
|
|
observers.append(center.addObserver(
|
|
forName: .ghosttyDidSetTitle,
|
|
object: nil,
|
|
queue: .main
|
|
) { [weak self] _ in
|
|
self?.updateFocusedCommandText()
|
|
})
|
|
|
|
observers.append(center.addObserver(
|
|
forName: .ghosttyDidFocusTab,
|
|
object: nil,
|
|
queue: .main
|
|
) { [weak self] _ in
|
|
self?.updateFocusedCommandText()
|
|
})
|
|
|
|
observers.append(center.addObserver(
|
|
forName: NSWindow.didBecomeMainNotification,
|
|
object: nil,
|
|
queue: .main
|
|
) { [weak self] notification in
|
|
guard let window = notification.object as? NSWindow else { return }
|
|
Task { @MainActor in
|
|
self?.attach(to: window)
|
|
}
|
|
})
|
|
}
|
|
|
|
private func attachToExistingWindows() {
|
|
for window in NSApp.windows {
|
|
attach(to: window)
|
|
}
|
|
}
|
|
|
|
private func attach(to window: NSWindow) {
|
|
guard window.toolbar == nil else { return }
|
|
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("cmux.toolbar"))
|
|
toolbar.delegate = self
|
|
toolbar.displayMode = .iconOnly
|
|
toolbar.sizeMode = .small
|
|
toolbar.allowsUserCustomization = false
|
|
toolbar.autosavesConfiguration = false
|
|
toolbar.showsBaselineSeparator = false
|
|
window.toolbar = toolbar
|
|
window.toolbarStyle = .unifiedCompact
|
|
window.titleVisibility = .hidden
|
|
}
|
|
|
|
private func updateFocusedCommandText() {
|
|
guard let tabManager else { return }
|
|
let text: String
|
|
if let selectedId = tabManager.selectedTabId,
|
|
let tab = tabManager.tabs.first(where: { $0.id == selectedId }) {
|
|
let title = tab.title.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
text = title.isEmpty ? "Cmd: —" : "Cmd: \(title)"
|
|
} else {
|
|
text = "Cmd: —"
|
|
}
|
|
|
|
for label in commandLabels.values {
|
|
label.stringValue = text
|
|
}
|
|
}
|
|
|
|
// MARK: - NSToolbarDelegate
|
|
|
|
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
|
[commandItemIdentifier, .flexibleSpace]
|
|
}
|
|
|
|
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
|
[commandItemIdentifier, .flexibleSpace]
|
|
}
|
|
|
|
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
|
if itemIdentifier == commandItemIdentifier {
|
|
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
|
|
let label = NSTextField(labelWithString: "Cmd: —")
|
|
label.font = NSFont.systemFont(ofSize: 12, weight: .medium)
|
|
label.textColor = .secondaryLabelColor
|
|
label.lineBreakMode = .byTruncatingMiddle
|
|
label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
item.view = label
|
|
commandLabels[ObjectIdentifier(toolbar)] = label
|
|
updateFocusedCommandText()
|
|
return item
|
|
}
|
|
|
|
|
|
return nil
|
|
}
|
|
|
|
}
|