macOS: prevent native window drag by top region when titlebar hidden (#2523)

Currently `macos-titlebar-style = hidden` doesn't prevent the native
window drag gesture in the top region of the window- in the original PR
it did, but there were issues with how it went about it so it was
removed (see c6bbdfb). I figured out how to safely and simply remove the
gesture, and as a bonus it opens up potential future enhancements.

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 makes `macos-titlebar-style = hidden` a much nicer experience. The
window can still be resized, managed by the OS and third party window
managers, and dragged by the edges, but the native drag gesture in the
titlebar region is fully avoided.

### Future work
We may consider adjusting this to produce a `contentLayoutRect` that
doesn't include the padding area of the terminal grid(s), so that the
window can be dragged from a larger region around the edges (and not
just the resize region).
This commit is contained in:
Mitchell Hashimoto
2025-01-23 13:48:31 -08:00
committed by GitHub
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> = []
@ -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