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

@ -59,6 +59,7 @@
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */; };
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36142C9CDA03004D6760 /* View+Extension.swift */; };
A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */; };
@ -128,6 +129,7 @@
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = "<group>"; };
A5CBD0572C9F30860017A1AE /* Cursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = "<group>"; };
A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputOverlay.swift; sourceTree = "<group>"; };
A5CC36142C9CDA03004D6760 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = "<group>"; };
A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrors.xib; sourceTree = "<group>"; };
@ -212,6 +214,7 @@
children = (
A5CEAFFE29C2410700646FDA /* Backport.swift */,
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */,
A5CBD0572C9F30860017A1AE /* Cursor.swift */,
A5D0AF3C2B37804400D21823 /* CodableBridge.swift */,
8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */,
A59630962AEE163600D64628 /* HostingWindow.swift */,
@ -527,6 +530,7 @@
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */,
AEE8B3452B9AA39600260C5E /* NSPasteboard+Extension.swift in Sources */,
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */,
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,

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
}
}