diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 111c9aeef..ea866e430 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -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 = ""; }; A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = ""; }; A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = ""; }; + A5CBD0572C9F30860017A1AE /* Cursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = ""; }; A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputOverlay.swift; sourceTree = ""; }; A5CC36142C9CDA03004D6760 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = ""; }; A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrors.xib; sourceTree = ""; }; @@ -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 */, diff --git a/macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationView.swift b/macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationView.swift index 8a4f24678..1a7272e16 100644 --- a/macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationView.swift +++ b/macos/Sources/Features/ClipboardConfirmation/ClipboardConfirmationView.swift @@ -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.. 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..