macos: unhide cursor on clipboard confirmation

This commit is contained in:
Mitchell Hashimoto
2024-09-21 09:59:19 -07:00
parent c01bdc6d7c
commit f9bd009ce5
4 changed files with 80 additions and 1 deletions

View File

@@ -34,6 +34,9 @@ struct ClipboardConfirmationView: View {
/// Optional delegate to get results. If this is nil, then this view will never close on its own.
weak var delegate: ClipboardConfirmationViewDelegate? = nil
/// Used to track if we should rehide on disappear
@State private var cursorHiddenCount: UInt = 0
var body: some View {
VStack {
HStack {
@@ -65,6 +68,25 @@ struct ClipboardConfirmationView: View {
}
.padding(.bottom)
}
.onAppear {
// I can't find a better way to handle this. There is no API to detect
// if the cursor is hidden and OTHER THINGS do unhide the cursor. So we
// try to unhide it completely here and hope for the best. Issue #1516.
cursorHiddenCount = Cursor.unhideCompletely()
// If we didn't unhide anything, we just send an unhide to be safe.
// I don't think the count can go negative on NSCursor so this handles
// scenarios cursor is hidden outside of our own NSCursor usage.
if (cursorHiddenCount == 0) {
_ = Cursor.unhide()
}
}
.onDisappear {
// Rehide if we unhid
for _ in 0..<cursorHiddenCount {
Cursor.hide()
}
}
}
private func onCancel() {

View File

@@ -59,6 +59,21 @@ extension Ghostty {
@EnvironmentObject private var ghostty: Ghostty.App
// The visibility state of the mouse pointer
private var pointerVisibililty: BackportVisibility {
// If our window or surface loses focus we always bring it back
if (!windowFocus || !surfaceFocus) {
return .visible
}
// If we have window focus then it depends on surface state
if (surfaceView.pointerVisible) {
return .visible
} else {
return .hidden
}
}
var body: some View {
let center = NotificationCenter.default
@@ -82,7 +97,7 @@ extension Ghostty {
.focusedValue(\.ghosttySurfaceView, surfaceView)
.focusedValue(\.ghosttySurfaceCellSize, surfaceView.cellSize)
#if canImport(AppKit)
.backport.pointerVisibility(surfaceView.pointerVisible ? .visible : .hidden)
.backport.pointerVisibility(pointerVisibililty)
.backport.pointerStyle(surfaceView.pointerStyle)
.onReceive(pubBecomeKey) { notification in
guard let window = notification.object as? NSWindow else { return }

View File

@@ -0,0 +1,38 @@
import Cocoa
/// This helps manage the stateful nature of NSCursor hiding and unhiding.
class Cursor {
private static var counter: UInt = 0
static var isVisible: Bool {
counter == 0
}
static func hide() {
counter += 1
NSCursor.hide()
}
/// Unhide the cursor. Returns true if the cursor was previously hidden.
static func unhide() -> Bool {
// Its always safe to call unhide when the counter is zero because it
// won't go negative.
NSCursor.unhide()
if (counter > 0) {
counter -= 1
return true
}
return false
}
static func unhideCompletely() -> UInt {
let counter = self.counter
for _ in 0..<counter {
assert(unhide())
}
assert(self.counter == 0)
return counter
}
}