perf: do all mouse interactions globally instead of local tracking

This commit is contained in:
lwouis committed 2026-02-11 21:35:36 +01:00
1 parent d525d350fc
commit d89bc29425
6 files changed
+116 -57

No files matched your search

+4 -3
View File
@@ -45,6 +45,9 @@ class CursorEvents {
private static let handleEvent: CGEventTapCallBack = { _, type, cgEvent, _ in
if type == .mouseMoved {
updateDeadzoneSituation(cgEvent)
if isAllowedToMouseHover {
App.app.thumbnailsPanel.tilesView.thumbnailOverView.updateHover()
}
} else if (type == .tapDisabledByUserInput || type == .tapDisabledByTimeout) && shouldBeEnabled {
CGEvent.tapEnable(tap: eventTap!, enable: true)
}
@@ -64,8 +67,6 @@ class CursorEvents {
let deltaY = event.locationInWindow.y - deadZoneInitialPosition.y
let d = hypot(deltaX, deltaY)
isAllowedToMouseHover = d > 25
if isAllowedToMouseHover {
App.app.thumbnailsPanel.tilesView.thumbnailOverView.updateHover()
}
}
}
+65 -1
View File
@@ -4,6 +4,8 @@ import Carbon.HIToolbox.Events
class MouseEvents {
private static var eventTap: CFMachPort!
private static var shouldBeEnabled: Bool!
private static var mouseDownTileView: TileView?
private static var mouseDownButton: TrafficLightButton?
static func observe() {
observe_()
@@ -18,7 +20,7 @@ class MouseEvents {
}
private static func observe_() {
let eventMask = [CGEventType.leftMouseDown, CGEventType.leftMouseUp].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
let eventMask = [CGEventType.leftMouseDown, CGEventType.leftMouseUp, CGEventType.otherMouseUp].reduce(CGEventMask(0), { $0 | (1 << $1.rawValue) })
// CGEvent.tapCreate returns nil if ensureAccessibilityCheckboxIsChecked() didn't pass
eventTap = CGEvent.tapCreate(
tap: .cgSessionEventTap,
@@ -42,11 +44,41 @@ class MouseEvents {
if !isPointerInsideUi() {
return nil // focused app won't receive the event
}
if let button = findButtonUnderPointer() {
mouseDownButton = button
button.isHighlighted = true
button.setNeedsDisplay()
return nil // swallow - we handle button clicks centrally
}
mouseDownTileView = findTileViewUnderPointer()
return nil // swallow - we handle tile clicks centrally
} else if type == .leftMouseUp && cgEvent.getIntegerValueField(.mouseEventClickState) >= 1 {
if !isPointerInsideUi() {
App.app.hideUi()
return nil // focused app won't receive the event
}
if let button = mouseDownButton {
mouseDownButton = nil
button.isHighlighted = false
button.setNeedsDisplay()
if findButtonUnderPointer() === button {
button.onClick()
}
return nil
}
if let target = mouseDownTileView {
mouseDownTileView = nil
if isPointerOverTileView(target) {
target.mouseUpCallback()
}
return nil
}
} else if type == .otherMouseUp {
guard isPointerInsideUi() else { return Unmanaged.passUnretained(cgEvent) }
if cgEvent.getIntegerValueField(.mouseEventButtonNumber) == 2 {
handleMiddleClick()
return nil
}
} else if (type == .tapDisabledByUserInput || type == .tapDisabledByTimeout) && shouldBeEnabled {
CGEvent.tapEnable(tap: eventTap!, enable: true)
}
@@ -56,4 +88,36 @@ class MouseEvents {
private static func isPointerInsideUi() -> Bool {
return App.app.thumbnailsPanel.contentLayoutRect.contains(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream)
}
private static func findButtonUnderPointer() -> TrafficLightButton? {
let panel = App.app.thumbnailsPanel!
let overlay = panel.tilesView.thumbnailOverView
let windowLocation = panel.mouseLocationOutsideOfEventStream
let overlayLocation = overlay.convert(windowLocation, from: nil)
return overlay.findButton(overlayLocation)
}
private static func findTileViewUnderPointer() -> TileView? {
let panel = App.app.thumbnailsPanel!
let overlay = panel.tilesView.thumbnailOverView
let windowLocation = panel.mouseLocationOutsideOfEventStream
let overlayLocation = overlay.convert(windowLocation, from: nil)
return overlay.findTarget(overlayLocation)
}
private static func isPointerOverTileView(_ tileView: TileView) -> Bool {
let panel = App.app.thumbnailsPanel!
let windowLocation = panel.mouseLocationOutsideOfEventStream
let localPoint = tileView.convert(windowLocation, from: nil)
return tileView.bounds.contains(localPoint)
}
private static func handleMiddleClick() {
guard let target = findTileViewUnderPointer(), let window = target.window_ else { return }
if window.isWindowlessApp {
window.application.quit()
} else {
window.close()
}
}
}
@@ -13,7 +13,6 @@ class TrafficLightButton: NSButton {
self.type = type
target = self
action = #selector(onClick)
addTrackingArea(NSTrackingArea(rect: .zero, options: [.mouseEnteredAndExited, .activeInKeyWindow, .inVisibleRect], owner: self, userInfo: nil))
toolTip = tooltip
appearance = NSAppearance(named: .aqua)
}
@@ -34,16 +33,6 @@ class TrafficLightButton: NSButton {
}
}
override func mouseEntered(with event: NSEvent) {
isMouseOver = true
setNeedsDisplay()
}
override func mouseExited(with event: NSEvent) {
isMouseOver = false
setNeedsDisplay()
}
override func draw(_ dirtyRect: NSRect) {
let (diskBackgroundColor, diskStrokeColor, symbolColor) = colors()
let disk = drawDisk(diskBackgroundColor, diskStrokeColor)
+46 -1
View File
@@ -8,6 +8,7 @@ class TileOverView: FlippedView {
var isShowingWindowControls = false
weak var scrollView: ScrollView?
var previousTarget: TileView?
private var previousHoveredButton: TrafficLightButton?
var windowControlButtons: [TrafficLightButton] { [quitButton, closeButton, minimizeButton, maximizeButton] }
@@ -37,6 +38,7 @@ class TileOverView: FlippedView {
func updateHover() {
guard let scrollView, !scrollView.isCurrentlyScrolling else { return }
let location = convert(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream, from: nil)
updateButtonHover(location)
let newTarget = findTarget(location)
guard newTarget !== previousTarget else { return }
caTransaction {
@@ -44,6 +46,10 @@ class TileOverView: FlippedView {
hideWindowControls()
newTarget.mouseMoved()
showWindowControls(for: newTarget)
let statusFrame = newTarget.convert(newTarget.statusIcons.frame, to: superview)
if statusFrame.contains(location) {
newTarget.statusIcons.ensureTooltipsInstalled()
}
} else {
resetHoveredWindow()
}
@@ -51,7 +57,42 @@ class TileOverView: FlippedView {
}
}
private func findTarget(_ location: NSPoint) -> TileView? {
/// Find the TrafficLightButton at the given point (in TileOverView's coordinate space)
func findButton(_ location: NSPoint) -> TrafficLightButton? {
guard isShowingWindowControls else { return nil }
for button in windowControlButtons where !button.isHidden {
let buttonPoint = button.convert(location, from: self)
if button.bounds.contains(buttonPoint) {
return button
}
}
return nil
}
private func updateButtonHover(_ location: NSPoint) {
var newHoveredButton: TrafficLightButton?
if isShowingWindowControls {
for button in windowControlButtons where !button.isHidden {
let buttonPoint = button.convert(location, from: self)
if button.bounds.contains(buttonPoint) {
newHoveredButton = button
break
}
}
}
guard newHoveredButton !== previousHoveredButton else { return }
if let old = previousHoveredButton {
old.isMouseOver = false
old.setNeedsDisplay()
}
if let new = newHoveredButton {
new.isMouseOver = true
new.setNeedsDisplay()
}
previousHoveredButton = newHoveredButton
}
func findTarget(_ location: NSPoint) -> TileView? {
guard let documentView = superview else { return nil }
for case let view as TileView in documentView.subviews {
let frame = view.frame
@@ -107,6 +148,10 @@ class TileOverView: FlippedView {
func hideWindowControls() {
guard isShowingWindowControls else { return }
isShowingWindowControls = false
if let old = previousHoveredButton {
old.isMouseOver = false
previousHoveredButton = nil
}
for button in windowControlButtons {
button.isHidden = true
}
-4
View File
@@ -31,10 +31,6 @@ class TileTitleView: NSTextField {
frame.size.width = width
}
override func mouseMoved(with event: NSEvent) {
// no-op here prevents tooltips from disappearing on mouseMoved
}
func updateTruncationModeIfNeeded() {
let newLineBreakMode = getTruncationMode()
if lineBreakMode != newLineBreakMode {
+1 -37
View File
@@ -25,8 +25,6 @@ class TileView: FlippedView {
var indexInRow = 0
var numberOfViewsInRow = 0
var receivedMouseDown = false
// for VoiceOver cursor
override var canBecomeKeyView: Bool { true }
override var acceptsFirstResponder: Bool { true }
@@ -72,32 +70,6 @@ class TileView: FlippedView {
return open != nil
}
override func mouseDown(with event: NSEvent) {
receivedMouseDown = true
}
override func mouseUp(with event: NSEvent) {
if receivedMouseDown {
if bounds.contains(convert(event.locationInWindow, from: nil)) {
mouseUpCallback()
}
receivedMouseDown = false
}
}
override func otherMouseUp(with event: NSEvent) {
// middle-click
if event.buttonNumber == 2 {
if let window_ {
if window_.isWindowlessApp {
window_.application.quit()
} else {
window_.close()
}
}
}
}
func mouseMoved() {
updateLabelTooltipIfNeeded()
mouseMovedCallback()
@@ -582,7 +554,6 @@ class StatusIconsView: FlippedView {
let measure = NSAttributedString(string: Symbols.circledNumber0.rawValue, attributes: attrs)
iconCellSize = measure.size()
super.init(frame: frame)
addTrackingArea(NSTrackingArea(rect: .zero, options: [.mouseEnteredAndExited, .activeAlways, .inVisibleRect], owner: self, userInfo: nil))
}
required init?(coder: NSCoder) { fatalError() }
@@ -623,11 +594,7 @@ class StatusIconsView: FlippedView {
needsDisplay = true
}
override func mouseEntered(with event: NSEvent) {
ensureTooltipsInstalled()
}
private func ensureTooltipsInstalled() {
func ensureTooltipsInstalled() {
guard tooltipsDirty else { return }
tooltipsDirty = false
removeAllToolTips()
@@ -661,7 +628,4 @@ class StatusIconsView: FlippedView {
}
}
override func mouseMoved(with event: NSEvent) {
// no-op prevents tooltips from disappearing on mouseMoved
}
}