Merge pull request #2276 from qwerasd205/macos-titlebar-hidden

macOS: add `macos-titlebar-style = hidden`
This commit is contained in:
Mitchell Hashimoto
2024-09-20 20:50:27 -07:00
committed by GitHub
7 changed files with 122 additions and 18 deletions

View File

@ -58,6 +58,7 @@
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */; };
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36142C9CDA03004D6760 /* View+Extension.swift */; };
A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */; };
@ -72,6 +73,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 */; };
@ -126,6 +128,7 @@
A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; };
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = "<group>"; };
A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputOverlay.swift; sourceTree = "<group>"; };
A5CC36142C9CDA03004D6760 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = "<group>"; };
A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrors.xib; sourceTree = "<group>"; };
@ -142,6 +145,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 +218,8 @@
8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */,
A59630962AEE163600D64628 /* HostingWindow.swift */,
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */,
AEA6197F2C9E1DE5004B3751 /* EventSinkHostingView.swift */,
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */,
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */,
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
@ -517,6 +523,7 @@
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */,
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */,
C1F26EE92B76CBFC00404083 /* VibrantLayer.m in Sources */,
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */,
A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */,
@ -541,6 +548,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,40 @@ 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
}
// 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 +662,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,6 +142,9 @@ class TerminalManager {
// the macOS APIs only work on a visible window.
controller.showWindow(self)
// 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":
@ -155,6 +158,8 @@ class TerminalManager {
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,19 @@
import Cocoa
import SwiftUI
struct DraggableWindowView: NSViewRepresentable {
func makeNSView(context: Context) -> DraggableWindowNSView {
return DraggableWindowNSView()
}
func updateNSView(_ nsView: DraggableWindowNSView, context: Context) {
// No need to update anything here
}
}
class DraggableWindowNSView: NSView {
override func mouseDown(with event: NSEvent) {
guard let window = self.window else { return }
window.performDrag(with: event)
}
}

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

@ -223,7 +223,7 @@ const c = @cImport({
@"font-codepoint-map": RepeatableCodepointMap = .{},
/// Draw fonts with a thicker stroke, if supported. This is only supported
/// currently on MacOS.
/// currently on macOS.
@"font-thicken": bool = false,
/// All of the configurations behavior adjust various metrics determined by the
@ -845,13 +845,16 @@ keybind: Keybinds = .{},
///
/// * `true`
/// * `false` - windows won't have native decorations, i.e. titlebar and
/// borders. On MacOS this also disables tabs and tab overview.
/// borders. On macOS this also disables tabs and tab overview.
///
/// The "toggle_window_decoration" keybind action can be used to create
/// a keybinding to toggle this setting at runtime.
///
/// Changing this configuration in your configuration and reloading will
/// only affect new windows. Existing windows will not be affected.
///
/// macOS: To hide the titlebar without removing the native window borders
/// or rounded corners, use `macos-titlebar-style = hidden` instead.
@"window-decoration": bool = true,
/// The font that will be used for the application's window and tab titles.
@ -1304,7 +1307,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 +1324,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 +4277,7 @@ pub const MacTitlebarStyle = enum {
native,
transparent,
tabs,
hidden,
};
/// See gtk-single-instance