From 2842b18a3fc6de1b5ad6f15832a4f28419cd5051 Mon Sep 17 00:00:00 2001 From: Martin Emde Date: Sun, 11 Jan 2026 13:32:11 -0800 Subject: [PATCH] Only show drag handle on hovered surface --- .../Surface View/SurfaceGrabHandle.swift | 19 +++++++++++++------ .../Surface View/SurfaceView_AppKit.swift | 9 +++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/macos/Sources/Ghostty/Surface View/SurfaceGrabHandle.swift b/macos/Sources/Ghostty/Surface View/SurfaceGrabHandle.swift index a4f5dddda..b30acc066 100644 --- a/macos/Sources/Ghostty/Surface View/SurfaceGrabHandle.swift +++ b/macos/Sources/Ghostty/Surface View/SurfaceGrabHandle.swift @@ -3,11 +3,15 @@ import SwiftUI extension Ghostty { /// A grab handle overlay at the top of the surface for dragging the window. struct SurfaceGrabHandle: View { - let surfaceView: SurfaceView + @ObservedObject var surfaceView: SurfaceView @State private var isHovering: Bool = false @State private var isDragging: Bool = false + private var ellipsisVisible: Bool { + surfaceView.mouseOverSurface && surfaceView.cursorVisible + } + var body: some View { ZStack { SurfaceDragSource( @@ -18,11 +22,14 @@ extension Ghostty { .frame(width: 80, height: 12) .contentShape(Rectangle()) - Image(systemName: "ellipsis") - .font(.system(size: 10, weight: .semibold)) - .foregroundColor(.primary.opacity(isHovering ? 0.8 : 0.3)) - .offset(y: -2) - .allowsHitTesting(false) + if ellipsisVisible { + Image(systemName: "ellipsis") + .font(.system(size: 10, weight: .semibold)) + .foregroundColor(.primary.opacity(isHovering ? 0.8 : 0.3)) + .offset(y: -2) + .allowsHitTesting(false) + .transition(.opacity) + } } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) } diff --git a/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift index 6b3bfbfb4..e45480a20 100644 --- a/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift @@ -116,6 +116,12 @@ extension Ghostty { // Whether the pointer should be visible or not @Published private(set) var pointerStyle: CursorStyle = .horizontalText + // Whether the mouse is currently over this surface + @Published private(set) var mouseOverSurface: Bool = false + + // Whether the cursor is currently visible (not hidden by typing, etc.) + @Published private(set) var cursorVisible: Bool = true + /// The configuration derived from the Ghostty config so we don't need to rely on references. @Published private(set) var derivedConfig: DerivedConfig @@ -533,6 +539,7 @@ extension Ghostty { } func setCursorVisibility(_ visible: Bool) { + cursorVisible = visible // Technically this action could be called anytime we want to // change the mouse visibility but at the time of writing this // mouse-hide-while-typing is the only use case so this is the @@ -910,6 +917,7 @@ extension Ghostty { } override func mouseEntered(with event: NSEvent) { + mouseOverSurface = true super.mouseEntered(with: event) guard let surfaceModel else { return } @@ -928,6 +936,7 @@ extension Ghostty { } override func mouseExited(with event: NSEvent) { + mouseOverSurface = false guard let surfaceModel else { return } // If the mouse is being dragged then we don't have to emit