mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
fix: Mac window becomes unmovable after pane rearrangement (#10133)
On main, after rearranging panes, the window becomes permanently immovable. Grab handles temporarily set `window.isMovable = false` on hover to prevent window dragging from interfering with pane drags (fixing [#10110](https://github.com/ghostty-org/ghostty/issues/10110)), but the restoration logic failed when views were destroyed during pane rearrangement (which happens each time a pane is rearranged). The previous approach managed `window.isMovable` state across the view lifecycle: 1. `mouseEntered` → saved and disabled `window.isMovable` 2. View removed during rearrangement → `mouseExited` never fired 3. `deinit` ran with `self.window` already nil → restoration failed 4. Window stuck with `isMovable = false` Instead of managing window state, prevent the mouseDown event from reaching the window's drag handler by overriding mouse event handling in the grab handle view. Per [Apple's Event Handling Guide](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html): > Custom NSView objects should not invoke super in their implementations of NSResponder mouse-event-handling methods such as mouseDown:, mouseDragged: and mouseUp: unless it is known that the inherited implementation provides some needed functionality. This eliminates all state management while solving both the original issue (#10110) and the new bug. AI disclosure: claude code found and wrote the fix. I tested it manually to see that it works. I pressed claude quite hard here to come up with the best fix, and looked at documentation to understand what the fix was doing. It seems like this is a better approach overall to preventing the main window from being dragged when grabbing the Surface Drag handle.
This commit is contained in:
@@ -105,22 +105,30 @@ extension Ghostty {
|
||||
/// Whether the current drag was cancelled by pressing escape.
|
||||
private var dragCancelledByEscape: Bool = false
|
||||
|
||||
/// Original value of `window.isMovable` to restore
|
||||
/// when the mouse exits.
|
||||
private var isWindowMovable: Bool?
|
||||
|
||||
deinit {
|
||||
if let escapeMonitor {
|
||||
NSEvent.removeMonitor(escapeMonitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
|
||||
// Ensure this view gets the mouse event before window dragging handlers
|
||||
return true
|
||||
}
|
||||
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
// Consume the mouseDown event to prevent it from propagating to the
|
||||
// window's drag handler. This fixes issue #10110 where grab handles
|
||||
// would drag the window instead of initiating pane drags.
|
||||
// Don't call super - the drag will be initiated in mouseDragged.
|
||||
}
|
||||
|
||||
override func updateTrackingAreas() {
|
||||
super.updateTrackingAreas()
|
||||
|
||||
|
||||
// To update our tracking area we just recreate it all.
|
||||
trackingAreas.forEach { removeTrackingArea($0) }
|
||||
|
||||
|
||||
// Add our tracking area for mouse events
|
||||
addTrackingArea(NSTrackingArea(
|
||||
rect: bounds,
|
||||
@@ -135,18 +143,10 @@ extension Ghostty {
|
||||
}
|
||||
|
||||
override func mouseEntered(with event: NSEvent) {
|
||||
// Temporarily disable `isMovable` to fix
|
||||
// https://github.com/ghostty-org/ghostty/issues/10110
|
||||
isWindowMovable = window?.isMovable
|
||||
window?.isMovable = false
|
||||
onHoverChanged?(true)
|
||||
}
|
||||
|
||||
override func mouseExited(with event: NSEvent) {
|
||||
if let isWindowMovable {
|
||||
window?.isMovable = isWindowMovable
|
||||
self.isWindowMovable = nil
|
||||
}
|
||||
onHoverChanged?(false)
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ extension Ghostty {
|
||||
NSEvent.removeMonitor(escapeMonitor)
|
||||
self.escapeMonitor = nil
|
||||
}
|
||||
|
||||
|
||||
if operation == [] && !dragCancelledByEscape {
|
||||
let endsInWindow = NSApplication.shared.windows.contains { window in
|
||||
window.isVisible && window.frame.contains(screenPoint)
|
||||
@@ -250,7 +250,7 @@ extension Ghostty {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isTracking = false
|
||||
onDragStateChanged?(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user