macos: add reset zoom to all window titles

This commit is contained in:
Mitchell Hashimoto
2025-06-12 14:33:18 -07:00
parent 70029bf82a
commit 658ec2eb6f
4 changed files with 75 additions and 5 deletions

View File

@@ -758,6 +758,8 @@ class BaseTerminalController: NSWindowController,
}
}
func fullscreenDidChange() {}
// MARK: Clipboard Confirmation
@objc private func onConfirmClipboardRequest(notification: SwiftUI.Notification) {

View File

@@ -145,7 +145,9 @@ class TerminalController: BaseTerminalController {
}
func fullscreenDidChange() {
override func fullscreenDidChange() {
super.fullscreenDidChange()
// When our fullscreen state changes, we resync our appearance because some
// properties change when fullscreen or not.
guard let focusedSurface else { return }

View File

@@ -9,6 +9,9 @@ class TerminalWindow: NSWindow {
/// used by the manual float on top menu item feature.
static let defaultLevelKey: String = "TerminalDefaultLevel"
/// The view model for SwiftUI views
private var viewModel = ViewModel()
/// The configuration derived from the Ghostty config so we don't need to rely on references.
private(set) var derivedConfig: DerivedConfig?
@@ -19,6 +22,15 @@ class TerminalWindow: NSWindow {
// MARK: NSWindow Overrides
override var toolbar: NSToolbar? {
didSet {
DispatchQueue.main.async {
// When we have a toolbar, our SwiftUI view needs to know for layout
self.viewModel.hasToolbar = self.toolbar != nil
}
}
}
override func awakeFromNib() {
guard let appDelegate = NSApp.delegate as? AppDelegate else { return }
@@ -43,6 +55,18 @@ class TerminalWindow: NSWindow {
hideWindowButtons()
}
// Create our reset zoom titlebar accessory.
let resetZoomAccessory = NSTitlebarAccessoryViewController()
resetZoomAccessory.layoutAttribute = .right
resetZoomAccessory.view = NSHostingView(rootView: ResetZoomAccessoryView(
viewModel: viewModel,
action: { [weak self] in
guard let self else { return }
self.terminalController?.splitZoom(self)
}))
addTitlebarAccessoryViewController(resetZoomAccessory)
resetZoomAccessory.view.translatesAutoresizingMaskIntoConstraints = false
// Setup the accessory view for tabs that shows our keyboard shortcuts,
// zoomed state, etc. Note I tried to use SwiftUI here but ran into issues
// where buttons were not clickable.
@@ -115,6 +139,10 @@ class TerminalWindow: NSWindow {
// Show/hide our reset zoom button depending on if we're zoomed.
// We want to show it if we are zoomed.
resetZoomTabButton.isHidden = !surfaceIsZoomed
DispatchQueue.main.async {
self.viewModel.isSurfaceZoomed = self.surfaceIsZoomed
}
}
}
@@ -313,3 +341,37 @@ class TerminalWindow: NSWindow {
}
}
}
// MARK: SwiftUI View
extension TerminalWindow {
class ViewModel: ObservableObject {
@Published var isSurfaceZoomed: Bool = false
@Published var hasToolbar: Bool = false
}
struct ResetZoomAccessoryView: View {
@ObservedObject var viewModel: ViewModel
let action: () -> Void
var body: some View {
if viewModel.isSurfaceZoomed {
VStack {
Button(action: action) {
Image("ResetZoom")
.foregroundColor(.accentColor)
}
.buttonStyle(.plain)
.help("Reset Split Zoom")
.frame(width: 20, height: 20)
Spacer()
}
// With a toolbar, the window title is taller, so we need more padding
// to properly align.
.padding(.top, viewModel.hasToolbar ? 10 : 5)
// We always need space at the end of the titlebar
.padding(.trailing, 10)
}
}
}
}

View File

@@ -45,10 +45,6 @@ protocol FullscreenDelegate: AnyObject {
func fullscreenDidChange()
}
extension FullscreenDelegate {
func fullscreenDidChange() {}
}
/// The base class for fullscreen implementations, cannot be used as a FullscreenStyle on its own.
class FullscreenBase {
let window: NSWindow
@@ -269,6 +265,12 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
window.styleMask = savedState.styleMask
window.setFrame(window.frameRect(forContentRect: savedState.contentFrame), display: true)
// Removing the "titled" style also derefs all our accessory view controllers
// so we need to restore those.
for c in savedState.titlebarAccessoryViewControllers {
window.addTitlebarAccessoryViewController(c)
}
// This is a hack that I want to remove from this but for now, we need to
// fix up the titlebar tabs here before we do everything below.
if let window = window as? TitlebarTabsVenturaTerminalWindow, window.titlebarTabs {
@@ -383,6 +385,7 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
let tabGroupIndex: Int?
let contentFrame: NSRect
let styleMask: NSWindow.StyleMask
let titlebarAccessoryViewControllers: [NSTitlebarAccessoryViewController]
let dock: Bool
let menu: Bool
@@ -394,6 +397,7 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
self.tabGroupIndex = window.tabGroup?.windows.firstIndex(of: window)
self.contentFrame = window.convertToScreen(contentView.frame)
self.styleMask = window.styleMask
self.titlebarAccessoryViewControllers = window.titlebarAccessoryViewControllers
self.dock = window.screen?.hasDock ?? false
if let cgWindowId = window.cgWindowId {