macOS: only show the update overlay if window doesn't support it

This commit is contained in:
Mitchell Hashimoto
2025-10-08 13:54:58 -07:00
parent 81e3ff90a3
commit f975ac8019
7 changed files with 73 additions and 12 deletions

View File

@@ -37,7 +37,7 @@ class QuickTerminalController: BaseTerminalController {
/// Tracks if we're currently handling a manual resize to prevent recursion /// Tracks if we're currently handling a manual resize to prevent recursion
private var isHandlingResize: Bool = false private var isHandlingResize: Bool = false
init(_ ghostty: Ghostty.App, init(_ ghostty: Ghostty.App,
position: QuickTerminalPosition = .top, position: QuickTerminalPosition = .top,
baseConfig base: Ghostty.SurfaceConfiguration? = nil, baseConfig base: Ghostty.SurfaceConfiguration? = nil,

View File

@@ -48,6 +48,9 @@ class BaseTerminalController: NSWindowController,
/// This can be set to show/hide the command palette. /// This can be set to show/hide the command palette.
@Published var commandPaletteIsShowing: Bool = false @Published var commandPaletteIsShowing: Bool = false
/// Set if the terminal view should show the update overlay.
@Published var updateOverlayIsVisible: Bool = false
/// Whether the terminal surface should focus when the mouse is over it. /// Whether the terminal surface should focus when the mouse is over it.
var focusFollowsMouse: Bool { var focusFollowsMouse: Bool {
@@ -818,7 +821,18 @@ class BaseTerminalController: NSWindowController,
} }
} }
func fullscreenDidChange() {} func fullscreenDidChange() {
guard let fullscreenStyle else { return }
// When we enter fullscreen, we want to show the update overlay so that it
// is easily visible. For native fullscreen this is visible by showing the
// menubar but we don't want to rely on that.
if fullscreenStyle.isFullscreen {
updateOverlayIsVisible = true
} else {
updateOverlayIsVisible = defaultUpdateOverlayVisibility()
}
}
// MARK: Clipboard Confirmation // MARK: Clipboard Confirmation
@@ -900,6 +914,28 @@ class BaseTerminalController: NSWindowController,
fullscreenStyle = NativeFullscreen(window) fullscreenStyle = NativeFullscreen(window)
fullscreenStyle?.delegate = self fullscreenStyle?.delegate = self
} }
// Set our update overlay state
updateOverlayIsVisible = defaultUpdateOverlayVisibility()
}
func defaultUpdateOverlayVisibility() -> Bool {
guard let window else { return true }
// No titlebar we always show the update overlay because it can't support
// updates in the titlebar
guard window.styleMask.contains(.titled) else {
return true
}
// If it's a non terminal window we can't trust it has an update accessory,
// so we always want to show the overlay.
guard let window = window as? TerminalWindow else {
return true
}
// Show the overlay if the window isn't.
return !window.supportsUpdateAccessory
} }
// MARK: NSWindowDelegate // MARK: NSWindowDelegate

View File

@@ -31,6 +31,9 @@ protocol TerminalViewModel: ObservableObject {
/// The command palette state. /// The command palette state.
var commandPaletteIsShowing: Bool { get set } var commandPaletteIsShowing: Bool { get set }
/// The update overlay should be visible.
var updateOverlayIsVisible: Bool { get }
} }
/// The main terminal view. This terminal view supports splits. /// The main terminal view. This terminal view supports splits.
@@ -111,7 +114,9 @@ struct TerminalView<ViewModel: TerminalViewModel>: View {
} }
// Show update information above all else. // Show update information above all else.
UpdateOverlay() if viewModel.updateOverlayIsVisible {
UpdateOverlay()
}
} }
} }
} }

View File

@@ -1,6 +1,9 @@
import AppKit import AppKit
class HiddenTitlebarTerminalWindow: TerminalWindow { class HiddenTitlebarTerminalWindow: TerminalWindow {
// No titlebar, we don't support accessories.
override var supportsUpdateAccessory: Bool { false }
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()

View File

@@ -20,12 +20,19 @@ class TerminalWindow: NSWindow {
/// The configuration derived from the Ghostty config so we don't need to rely on references. /// The configuration derived from the Ghostty config so we don't need to rely on references.
private(set) var derivedConfig: DerivedConfig = .init() private(set) var derivedConfig: DerivedConfig = .init()
/// Whether this window supports the update accessory. If this is false, then views within this
/// window should determine how to show update notifications.
var supportsUpdateAccessory: Bool {
// Native window supports it.
true
}
/// Gets the terminal controller from the window controller. /// Gets the terminal controller from the window controller.
var terminalController: TerminalController? { var terminalController: TerminalController? {
windowController as? TerminalController windowController as? TerminalController
} }
// MARK: NSWindow Overrides // MARK: NSWindow Overrides
override var toolbar: NSToolbar? { override var toolbar: NSToolbar? {
@@ -90,14 +97,16 @@ class TerminalWindow: NSWindow {
resetZoomAccessory.view.translatesAutoresizingMaskIntoConstraints = false resetZoomAccessory.view.translatesAutoresizingMaskIntoConstraints = false
// Create update notification accessory // Create update notification accessory
updateAccessory.layoutAttribute = .right if supportsUpdateAccessory {
updateAccessory.view = NSHostingView(rootView: UpdateAccessoryView( updateAccessory.layoutAttribute = .right
viewModel: viewModel, updateAccessory.view = NSHostingView(rootView: UpdateAccessoryView(
model: appDelegate.updateUIModel, viewModel: viewModel,
actions: appDelegate.updateActions model: appDelegate.updateUIModel,
)) actions: appDelegate.updateActions
addTitlebarAccessoryViewController(updateAccessory) ))
updateAccessory.view.translatesAutoresizingMaskIntoConstraints = false addTitlebarAccessoryViewController(updateAccessory)
updateAccessory.view.translatesAutoresizingMaskIntoConstraints = false
}
} }
// Setup the accessory view for tabs that shows our keyboard shortcuts, // Setup the accessory view for tabs that shows our keyboard shortcuts,

View File

@@ -8,6 +8,10 @@ import SwiftUI
class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSToolbarDelegate { class TitlebarTabsTahoeTerminalWindow: TransparentTitlebarTerminalWindow, NSToolbarDelegate {
/// The view model for SwiftUI views /// The view model for SwiftUI views
private var viewModel = ViewModel() private var viewModel = ViewModel()
/// Titlebar tabs can't support the update accessory because of the way we layout
/// the native tabs back into the menu bar.
override var supportsUpdateAccessory: Bool { false }
deinit { deinit {
tabBarObserver = nil tabBarObserver = nil

View File

@@ -2,6 +2,10 @@ import Cocoa
/// Titlebar tabs for macOS 13 to 15. /// Titlebar tabs for macOS 13 to 15.
class TitlebarTabsVenturaTerminalWindow: TerminalWindow { class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
/// Titlebar tabs can't support the update accessory because of the way we layout
/// the native tabs back into the menu bar.
override var supportsUpdateAccessory: Bool { false }
/// This is used to determine if certain elements should be drawn light or dark and should /// This is used to determine if certain elements should be drawn light or dark and should
/// be updated whenever the window background color or surrounding elements changes. /// be updated whenever the window background color or surrounding elements changes.
fileprivate var isLightTheme: Bool = false fileprivate var isLightTheme: Bool = false