macos: more robust cursor visibility handling

Fixes #519

The core issue here was that `mouseEntered` was called AFTER
`cursorUpdate` (by Cocoa) so we were messing up our NSCursor state. To
fix this more robustly, all cursor state should ONLY be handled by
cursorUpdate and mouseEntered/Exit goes through that system now.
This commit is contained in:
Mitchell Hashimoto
2023-09-22 15:41:36 -07:00
parent 510f0fe8f2
commit 1eb0dbb548

View File

@ -210,7 +210,7 @@ extension Ghostty {
// State machine for mouse cursor visibility because every call to
// NSCursor.hide/unhide must be balanced.
enum CursorVisibility {
enum CursorVisibility: String {
case visible
case hidden
case pendingVisible
@ -519,11 +519,9 @@ extension Ghostty {
mouseEntered = true
// If our cursor is hidden, we hide it on upon entry and we unhide
// it on exit (mouseExited)
if (cursorVisible == .hidden) {
NSCursor.hide()
}
// Update our cursor when we enter so we fully process our
// cursorVisible state.
cursorUpdate(with: NSEvent())
}
override func mouseExited(with event: NSEvent) {
@ -532,8 +530,17 @@ extension Ghostty {
mouseEntered = false
// If the mouse is currently hidden, we want to show it when we exit
// this view. We go through the cursorVisible dance so that only
// cursorUpdate manages cursor state.
if (cursorVisible == .hidden) {
NSCursor.unhide()
cursorVisible = .pendingVisible
cursorUpdate(with: NSEvent())
assert(cursorVisible == .visible)
// We set the state to pending hidden again for the next time
// we enter.
cursorVisible = .pendingHidden
}
}