mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: unhide cursor on clipboard confirmation
This commit is contained in:
@ -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 */,
|
||||
|
@ -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() {
|
||||
|
@ -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 }
|
||||
|
38
macos/Sources/Helpers/Cursor.swift
Normal file
38
macos/Sources/Helpers/Cursor.swift
Normal 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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user