From d12f07ceda1e8afabe5cc0ee9bc4529ad013b12c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 21 Sep 2023 09:30:42 -0700 Subject: [PATCH 1/2] macos: mouse tracking area should always send Without this, non-first-responder views would not receive mouse entered/exit events. This would break some of our mouse hiding state. See comments for more info. --- macos/Sources/Ghostty/SurfaceView.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index 913b1cfb1..ec20c21d8 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -419,12 +419,13 @@ extension Ghostty { options: [ .mouseEnteredAndExited, .mouseMoved, + + // Only send mouse events that happen in our visible (not obscured) rect .inVisibleRect, - // It is possible this is incorrect when we have splits. This will make - // mouse events only happen while the terminal is focused. Is that what - // we want? - .activeWhenFirstResponder, + // We want active always because we want to still send mouse reports + // even if we're not focused or key. + .activeAlways, ], owner: self, userInfo: nil)) From 7f549c5b4101c3eb0af17da031840be8c52f8c83 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 21 Sep 2023 09:42:17 -0700 Subject: [PATCH 2/2] macos: detect mouseEntered/Exit on frame change --- macos/Sources/Ghostty/SurfaceView.swift | 47 +++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index ec20c21d8..95c662483 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -236,7 +236,7 @@ extension Ghostty { return } self.surface = surface; - + // Setup our tracking area so we get mouse moved events updateTrackingAreas() } @@ -283,6 +283,25 @@ extension Ghostty { // The size represents our final size we're going for. let scaledSize = self.convertToBacking(size) ghostty_surface_set_size(surface, UInt32(scaledSize.width), UInt32(scaledSize.height)) + + // Frame changes do not always call mouseEntered/mouseExited, so we do some + // calculations ourself to call those events. + if let window = self.window { + let mouseScreen = NSEvent.mouseLocation + let mouseWindow = window.convertPoint(fromScreen: mouseScreen) + let mouseView = self.convert(mouseWindow, from: nil) + let isEntered = self.isMousePoint(mouseView, in: bounds) + if (isEntered) { + mouseEntered(with: NSEvent()) + } else { + mouseExited(with: NSEvent()) + } + } else { + // If we don't have a window, then our mouse can NOT be in our view. + // When the window comes back, I believe this event fires again so + // we'll get a mouseEntered. + mouseExited(with: NSEvent()) + } } func setCursorShape(_ shape: ghostty_mouse_shape_e) { @@ -562,20 +581,18 @@ extension Ghostty { } override func cursorUpdate(with event: NSEvent) { - if (focused) { - switch (cursorVisible) { - case .visible, .hidden: - // Do nothing, stable state - break - - case .pendingHidden: - NSCursor.hide() - cursorVisible = .hidden - - case .pendingVisible: - NSCursor.unhide() - cursorVisible = .visible - } + switch (cursorVisible) { + case .visible, .hidden: + // Do nothing, stable state + break + + case .pendingHidden: + NSCursor.hide() + cursorVisible = .hidden + + case .pendingVisible: + NSCursor.unhide() + cursorVisible = .visible } cursor.set()