macOS: prevent native window drag by top region when titlebar hidden

The native window drag region is driven ultimately by the window's
`contentLayoutRect`, so we can just override it in `TerminalWindow`
to return a rect the size of the full window, disabling the gesture
without causing any side effects by altering the responder chain.
This commit is contained in:
Qwerasd
2024-10-28 18:41:53 -04:00
committed by Mitchell Hashimoto
parent cd57612059
commit 5477eb87c1
3 changed files with 32 additions and 14 deletions

View File

@ -22,7 +22,7 @@ class TerminalController: BaseTerminalController {
private var restorable: Bool = true private var restorable: Bool = true
/// 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 var derivedConfig: DerivedConfig private(set) var derivedConfig: DerivedConfig
/// The notification cancellable for focused surface property changes. /// The notification cancellable for focused surface property changes.
private var surfaceAppearanceCancellables: Set<AnyCancellable> = [] private var surfaceAppearanceCancellables: Set<AnyCancellable> = []
@ -315,28 +315,28 @@ class TerminalController: BaseTerminalController {
window.styleMask = [ window.styleMask = [
// We need `titled` in the mask to get the normal window frame // We need `titled` in the mask to get the normal window frame
.titled, .titled,
// Full size content view so we can extend // Full size content view so we can extend
// content in to the hidden titlebar's area // content in to the hidden titlebar's area
.fullSizeContentView, .fullSizeContentView,
.resizable, .resizable,
.closable, .closable,
.miniaturizable, .miniaturizable,
] ]
// Hide the title // Hide the title
window.titleVisibility = .hidden window.titleVisibility = .hidden
window.titlebarAppearsTransparent = true window.titlebarAppearsTransparent = true
// Hide the traffic lights (window control buttons) // Hide the traffic lights (window control buttons)
window.standardWindowButton(.closeButton)?.isHidden = true window.standardWindowButton(.closeButton)?.isHidden = true
window.standardWindowButton(.miniaturizeButton)?.isHidden = true window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true window.standardWindowButton(.zoomButton)?.isHidden = true
// Disallow tabbing if the titlebar is hidden, since that will (should) also hide the tab bar. // Disallow tabbing if the titlebar is hidden, since that will (should) also hide the tab bar.
window.tabbingMode = .disallowed window.tabbingMode = .disallowed
// Nuke it from orbit -- hide the titlebar container entirely, just in case. There are // Nuke it from orbit -- hide the titlebar container entirely, just in case. There are
// some operations that appear to bring back the titlebar visibility so this ensures // some operations that appear to bring back the titlebar visibility so this ensures
// it is gone forever. // it is gone forever.
@ -345,7 +345,7 @@ class TerminalController: BaseTerminalController {
titleBarContainer.isHidden = true titleBarContainer.isHidden = true
} }
} }
override func windowDidLoad() { override func windowDidLoad() {
super.windowDidLoad() super.windowDidLoad()
guard let window = window as? TerminalWindow else { return } guard let window = window as? TerminalWindow else { return }
@ -776,7 +776,7 @@ class TerminalController: BaseTerminalController {
toggleFullscreen(mode: fullscreenMode) toggleFullscreen(mode: fullscreenMode)
} }
private struct DerivedConfig { struct DerivedConfig {
let backgroundColor: Color let backgroundColor: Color
let macosTitlebarStyle: String let macosTitlebarStyle: String

View File

@ -115,6 +115,21 @@ class TerminalWindow: NSWindow {
} }
} }
// We override this so that with the hidden titlebar style the titlebar
// area is not draggable.
override var contentLayoutRect: CGRect {
var rect = super.contentLayoutRect
// If we are using a hidden titlebar style, the content layout is the
// full frame making it so that it is not draggable.
if let controller = windowController as? TerminalController,
controller.derivedConfig.macosTitlebarStyle == "hidden" {
rect.origin.y = 0
rect.size.height = self.frame.height
}
return rect
}
// The window theme configuration from Ghostty. This is used to control some // The window theme configuration from Ghostty. This is used to control some
// behaviors that don't look quite right in certain situations. // behaviors that don't look quite right in certain situations.
var windowTheme: TerminalWindowTheme? var windowTheme: TerminalWindowTheme?

View File

@ -1816,9 +1816,12 @@ keybind: Keybinds = .{},
/// The "hidden" style hides the titlebar. Unlike `window-decoration = false`, /// 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 /// 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 /// squared corners. Changing to or from this option at run-time may affect
/// existing windows in buggy ways. The top titlebar area of the window will /// existing windows in buggy ways.
/// continue to drag the window around and you will not be able to use ///
/// the mouse for terminal events in this space. /// When "hidden", the top titlebar area can no longer be used for dragging
/// the window. To drag the window, you can use option+click on the resizable
/// areas of the frame to drag the window. This is a standard macOS behavior
/// and not something Ghostty enables.
/// ///
/// The default value is "transparent". This is an opinionated choice /// The default value is "transparent". This is an opinionated choice
/// but its one I think is the most aesthetically pleasing and works in /// but its one I think is the most aesthetically pleasing and works in