macOS: add macos-titlebar-style = hidden

Hides titlebar without removing the other typical window frame elements
This commit is contained in:
Qwerasd
2024-09-20 16:11:51 -06:00
parent 761223f0f3
commit 16919488da
6 changed files with 101 additions and 15 deletions

View File

@ -72,6 +72,7 @@
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */; };
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */; };
A5FEB3002ABB69450068369E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FEB2FF2ABB69450068369E /* main.swift */; };
AEA619802C9E1DF7004B3751 /* EventSinkHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEA6197F2C9E1DE5004B3751 /* EventSinkHostingView.swift */; };
AEE8B3452B9AA39600260C5E /* NSPasteboard+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */; };
AEF9CE242B6AD07A0017E195 /* TerminalToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */; };
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
@ -142,6 +143,7 @@
A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationController.swift; sourceTree = "<group>"; };
A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationView.swift; sourceTree = "<group>"; };
A5FEB2FF2ABB69450068369E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
AEA6197F2C9E1DE5004B3751 /* EventSinkHostingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventSinkHostingView.swift; sourceTree = "<group>"; };
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSPasteboard+Extension.swift"; sourceTree = "<group>"; };
AEF9CE232B6AD07A0017E195 /* TerminalToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalToolbar.swift; sourceTree = "<group>"; };
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSColor+Extension.swift"; sourceTree = "<group>"; };
@ -214,6 +216,7 @@
8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */,
A59630962AEE163600D64628 /* HostingWindow.swift */,
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */,
AEA6197F2C9E1DE5004B3751 /* EventSinkHostingView.swift */,
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */,
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
@ -541,6 +544,7 @@
A55685E029A03A9F004303CE /* AppError.swift in Sources */,
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */,
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */,
AEA619802C9E1DF7004B3751 /* EventSinkHostingView.swift in Sources */,
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */,
A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */,
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */,

View File

@ -328,12 +328,48 @@ class TerminalController: NSWindowController, NSWindowDelegate,
}
// Initialize our content view to the SwiftUI root
window.contentView = NSHostingView(rootView: TerminalView(
window.contentView = EventSinkHostingView(rootView: TerminalView(
ghostty: self.ghostty,
viewModel: self,
delegate: self
))
// If our titlebar style is "hidden" we adjust the style appropriately
if (ghostty.config.macosTitlebarStyle == "hidden") {
window.styleMask = [
// We need `titled` in the mask to get the normal window frame
.titled,
// Full size content view so we can extend
// content in to the hidden titlebar's area
.fullSizeContentView,
.resizable,
.closable,
.miniaturizable,
]
// Hide the title
window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true
// Hide the traffic lights (window control buttons)
window.standardWindowButton(.closeButton)?.isHidden = true
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true
// Disallow tabbing if the titlebar is hidden, since that will (should) also hide the tab bar.
window.tabbingMode = .disallowed
// Nuke it from orbit -- hide the titlebar container entirely, just in case.
if let themeFrame = window.contentView?.superview {
// Hide the titlebar container
if let titleBarContainer = themeFrame.firstDescendant(withClassName: "NSTitlebarContainerView") {
titleBarContainer.isHidden = true
}
}
}
// In various situations, macOS automatically tabs new windows. Ghostty handles
// its own tabbing so we DONT want this behavior. This detects this scenario and undoes
// it.
@ -634,7 +670,7 @@ class TerminalController: NSWindowController, NSWindowDelegate,
// Custom toolbar-based title used when titlebar tabs are enabled.
if let toolbar = window.toolbar as? TerminalToolbar {
if (window.titlebarTabs) {
if (window.titlebarTabs || ghostty.config.macosTitlebarStyle == "hidden") {
// Updating the title text as above automatically reveals the
// native title view in macOS 15.0 and above. Since we're using
// a custom view instead, we need to re-hide it.

View File

@ -142,19 +142,24 @@ class TerminalManager {
// the macOS APIs only work on a visible window.
controller.showWindow(self)
// Add the window to the tab group and show it.
switch ghostty.config.windowNewTabPosition {
case "end":
// If we already have a tab group and we want the new tab to open at the end,
// then we use the last window in the tab group as the parent.
if let last = parent.tabGroup?.windows.last {
last.addTabbedWindow(window, ordered: .above)
} else {
fallthrough
// If we have the "hidden" titlebar style we want to create new
// tabs as windows instead, so just skip adding it to the parent.
if (ghostty.config.macosTitlebarStyle != "hidden") {
// Add the window to the tab group and show it.
switch ghostty.config.windowNewTabPosition {
case "end":
// If we already have a tab group and we want the new tab to open at the end,
// then we use the last window in the tab group as the parent.
if let last = parent.tabGroup?.windows.last {
last.addTabbedWindow(window, ordered: .above)
} else {
fallthrough
}
case "current": fallthrough
default:
parent.addTabbedWindow(window, ordered: .above)
}
case "current": fallthrough
default:
parent.addTabbedWindow(window, ordered: .above)
}
window.makeKeyAndOrderFront(self)

View File

@ -108,6 +108,8 @@ struct TerminalView<ViewModel: TerminalViewModel>: View {
self.delegate?.zoomStateDidChange(to: newValue ?? false)
}
}
// Ignore safe area to extend up in to the titlebar region if we have the "hidden" titlebar style
.ignoresSafeArea(.container, edges: ghostty.config.macosTitlebarStyle == "hidden" ? .top : [])
}
}
}

View File

@ -0,0 +1,33 @@
import SwiftUI
/// Custom subclass of NSHostingView which sinks events so that we can
/// stop the window from receiving events originating from within this view.
class EventSinkHostingView<Content: View>: NSHostingView<Content> {
override var acceptsFirstResponder: Bool {
return true
}
override func becomeFirstResponder() -> Bool {
return true
}
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
return true
}
override func mouseDown(with event: NSEvent) {
// Do nothing
}
override func mouseDragged(with event: NSEvent) {
// Do nothing
}
override func mouseUp(with event: NSEvent) {
// Do nothing
}
override var mouseDownCanMoveWindow: Bool {
return false
}
}

View File

@ -1304,7 +1304,7 @@ keybind: Keybinds = .{},
@"macos-non-native-fullscreen": NonNativeFullscreen = .false,
/// The style of the macOS titlebar. Available values are: "native",
/// "transparent", and "tabs".
/// "transparent", "tabs", and "hidden".
///
/// The "native" style uses the native macOS titlebar with zero customization.
/// The titlebar will match your window theme (see `window-theme`).
@ -1321,6 +1321,11 @@ keybind: Keybinds = .{},
/// macOS 14 does not have this issue and any other macOS version has not
/// been tested.
///
/// The "hidden" style hides the titlebar. Unlike `window-decoration = false`,
/// however, it does not remove the frame from the window or cause it to have
/// squared corners. Changing to or from this option at run-time may affect
/// existing windows in buggy ways.
///
/// The default value is "transparent". This is an opinionated choice
/// but its one I think is the most aesthetically pleasing and works in
/// most cases.
@ -4269,6 +4274,7 @@ pub const MacTitlebarStyle = enum {
native,
transparent,
tabs,
hidden,
};
/// See gtk-single-instance