From df9976c6300d0c8ddcce9f8c2e5189e88ec27e03 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 19:56:21 +0600 Subject: [PATCH 01/11] Suppress WebView mouse events tracking while loading --- DuckDuckGo/Tab/View/WebView.swift | 91 +++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index bc578f6d19..bf4816ad6f 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -17,6 +17,7 @@ // import Cocoa +import Combine import WebKit protocol WebViewContextMenuDelegate: AnyObject { @@ -34,6 +35,24 @@ final class WebView: WKWebView { weak var contextMenuDelegate: WebViewContextMenuDelegate? weak var interactionEventsDelegate: WebViewInteractionEventsDelegate? + private var isLoadingCancellable: Cancellable? + + override init(frame: CGRect, configuration: WKWebViewConfiguration) { + /// swizzle NSTrackingArea.init method to insert TrackingAreaSuppressor proxy owner + /// it will disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading + /// see https://app.asana.com/0/1177771139624306/1206990108527681/f + _=NSTrackingArea.swizzleStartStopAccessingSecurityScopedResourceOnce + super.init(frame: frame, configuration: configuration) + + // suppress Tracking Area events while loading + isLoadingCancellable = self.observe(\.isLoading, options: [.new]) { [weak suppressor=trackingAreas.first?.proxyOwner] _, c in + suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false + } + } + + required init?(coder: NSCoder) { + fatalError("\(Self.self): Bad initializer") + } override var isInFullScreenMode: Bool { if #available(macOS 13.0, *) { @@ -325,3 +344,75 @@ extension WebView /* _WKFindDelegate */ { } } + +/// used to suppress mouseEntered/mouseMoved/mouseExited events while Web View is loading +final private class TrackingAreaSuppressor { + + private weak var owner: AnyObject? + + var isSuppressingMouseEvents = false + + init(owner: AnyObject? = nil) { + self.owner = owner + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc(mouseEntered:) + func mouseEntered(with event: NSEvent) { + guard !isSuppressingMouseEvents else { return } + _=owner?.perform(#selector(mouseEntered), with: event) + } + + @objc(mouseExited:) + func mouseExited(with event: NSEvent) { + guard !isSuppressingMouseEvents else { return } + _=owner?.perform(#selector(mouseExited), with: event) + } + + @objc(mouseMoved:) + func mouseMoved(with event: NSEvent) { + guard !isSuppressingMouseEvents else { return } + _=owner?.perform(#selector(mouseMoved), with: event) + } + +} + +/// adding the TrackingAreaSuppressor proxy object as a WebView‘s Tracking Area owner +extension NSTrackingArea { + + private static let originalInitWithRectOptionsOwnerUserInfo = { + class_getInstanceMethod(NSTrackingArea.self, #selector(NSTrackingArea.init(rect:options:owner:userInfo:)))! + }() + private static let swizzledInitWithRectOptionsOwnerUserInfo = { + class_getInstanceMethod(NSTrackingArea.self, #selector(NSTrackingArea.swizzled_init(rect:options:owner:userInfo:)))! + }() + + fileprivate static let swizzleStartStopAccessingSecurityScopedResourceOnce: Void = { + method_exchangeImplementations(originalInitWithRectOptionsOwnerUserInfo, swizzledInitWithRectOptionsOwnerUserInfo) + }() + + @objc private dynamic func swizzled_init(rect: NSRect, options: NSTrackingArea.Options, owner: AnyObject?, userInfo: NSDictionary) -> AnyObject? { + var owner = owner + if owner?.className == "WKMouseTrackingObserver" { + let helper = TrackingAreaSuppressor(owner: owner) + self.proxyOwner = helper + owner = helper + } + + return self.swizzled_init(rect: rect, options: options, owner: owner, userInfo: userInfo) /* call original */ + } + + private static let proxyOwnerKey = UnsafeRawPointer(bitPattern: "proxyHandlerKey".hashValue)! + fileprivate private(set) var proxyOwner: TrackingAreaSuppressor? { + get { + objc_getAssociatedObject(self, Self.proxyOwnerKey) as? TrackingAreaSuppressor + } + set { + objc_setAssociatedObject(self, Self.proxyOwnerKey, newValue, .OBJC_ASSOCIATION_RETAIN) + } + } + +} From 4e53dc8d039aa52852290ea0b4c14727644221a1 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:11:17 +0600 Subject: [PATCH 02/11] fix naming --- DuckDuckGo/Tab/View/WebView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index bf4816ad6f..73ea78ad07 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -41,7 +41,7 @@ final class WebView: WKWebView { /// swizzle NSTrackingArea.init method to insert TrackingAreaSuppressor proxy owner /// it will disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading /// see https://app.asana.com/0/1177771139624306/1206990108527681/f - _=NSTrackingArea.swizzleStartStopAccessingSecurityScopedResourceOnce + _=NSTrackingArea.swizzleInitWithRectOptionsOwnerUserInfoOnce super.init(frame: frame, configuration: configuration) // suppress Tracking Area events while loading @@ -390,7 +390,7 @@ extension NSTrackingArea { class_getInstanceMethod(NSTrackingArea.self, #selector(NSTrackingArea.swizzled_init(rect:options:owner:userInfo:)))! }() - fileprivate static let swizzleStartStopAccessingSecurityScopedResourceOnce: Void = { + fileprivate static let swizzleInitWithRectOptionsOwnerUserInfoOnce: Void = { method_exchangeImplementations(originalInitWithRectOptionsOwnerUserInfo, swizzledInitWithRectOptionsOwnerUserInfo) }() From 0db3debc39f5ba10660bd1e317153bdbd177fb17 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:14:22 +0600 Subject: [PATCH 03/11] fix naming --- DuckDuckGo/Tab/View/WebView.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 73ea78ad07..1b1f973fbd 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -45,7 +45,8 @@ final class WebView: WKWebView { super.init(frame: frame, configuration: configuration) // suppress Tracking Area events while loading - isLoadingCancellable = self.observe(\.isLoading, options: [.new]) { [weak suppressor=trackingAreas.first?.proxyOwner] _, c in + let suppressor = suppressor=trackingAreas.first?.trackingAreaSuppressor + isLoadingCancellable = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false } } @@ -398,15 +399,15 @@ extension NSTrackingArea { var owner = owner if owner?.className == "WKMouseTrackingObserver" { let helper = TrackingAreaSuppressor(owner: owner) - self.proxyOwner = helper + self.trackingAreaSuppressor = helper owner = helper } return self.swizzled_init(rect: rect, options: options, owner: owner, userInfo: userInfo) /* call original */ } - private static let proxyOwnerKey = UnsafeRawPointer(bitPattern: "proxyHandlerKey".hashValue)! - fileprivate private(set) var proxyOwner: TrackingAreaSuppressor? { + private static let trackingAreaSuppressorKey = UnsafeRawPointer(bitPattern: "trackingAreaSuppressorKey".hashValue)! + fileprivate private(set) var trackingAreaSuppressor: TrackingAreaSuppressor? { get { objc_getAssociatedObject(self, Self.proxyOwnerKey) as? TrackingAreaSuppressor } From f5a00a5bcab55e8549a7317ef79dd16296ff6b72 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:15:46 +0600 Subject: [PATCH 04/11] fix --- DuckDuckGo/Tab/View/WebView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 1b1f973fbd..856fa3a741 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -409,10 +409,10 @@ extension NSTrackingArea { private static let trackingAreaSuppressorKey = UnsafeRawPointer(bitPattern: "trackingAreaSuppressorKey".hashValue)! fileprivate private(set) var trackingAreaSuppressor: TrackingAreaSuppressor? { get { - objc_getAssociatedObject(self, Self.proxyOwnerKey) as? TrackingAreaSuppressor + objc_getAssociatedObject(self, Self.trackingAreaSuppressorKey) as? TrackingAreaSuppressor } set { - objc_setAssociatedObject(self, Self.proxyOwnerKey, newValue, .OBJC_ASSOCIATION_RETAIN) + objc_setAssociatedObject(self, Self.trackingAreaSuppressorKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } From 3c5c1cdc732ab6cfe9f6d9f955dd12c371ac3272 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:16:48 +0600 Subject: [PATCH 05/11] cleanup --- DuckDuckGo/Tab/View/WebView.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 856fa3a741..a866862fc4 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -347,7 +347,7 @@ extension WebView /* _WKFindDelegate */ { } /// used to suppress mouseEntered/mouseMoved/mouseExited events while Web View is loading -final private class TrackingAreaSuppressor { +final private class TrackingAreaSuppressor: NSObject { private weak var owner: AnyObject? @@ -357,10 +357,6 @@ final private class TrackingAreaSuppressor { self.owner = owner } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - @objc(mouseEntered:) func mouseEntered(with event: NSEvent) { guard !isSuppressingMouseEvents else { return } From 4726073fb298cd6be38dd15acf047283f6eeaf50 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:17:38 +0600 Subject: [PATCH 06/11] cleanup --- DuckDuckGo/Tab/View/WebView.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index a866862fc4..4895c3b87f 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -17,7 +17,6 @@ // import Cocoa -import Combine import WebKit protocol WebViewContextMenuDelegate: AnyObject { @@ -35,7 +34,7 @@ final class WebView: WKWebView { weak var contextMenuDelegate: WebViewContextMenuDelegate? weak var interactionEventsDelegate: WebViewInteractionEventsDelegate? - private var isLoadingCancellable: Cancellable? + private var isLoadingObserver: Any? override init(frame: CGRect, configuration: WKWebViewConfiguration) { /// swizzle NSTrackingArea.init method to insert TrackingAreaSuppressor proxy owner @@ -46,7 +45,7 @@ final class WebView: WKWebView { // suppress Tracking Area events while loading let suppressor = suppressor=trackingAreas.first?.trackingAreaSuppressor - isLoadingCancellable = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in + isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false } } From 92c8032f7447aae2ea73199dfa2c3fa959f9e4b9 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 20:48:51 +0600 Subject: [PATCH 07/11] fix build --- DuckDuckGo/Tab/View/WebView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 4895c3b87f..941dae49f9 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -44,7 +44,7 @@ final class WebView: WKWebView { super.init(frame: frame, configuration: configuration) // suppress Tracking Area events while loading - let suppressor = suppressor=trackingAreas.first?.trackingAreaSuppressor + let suppressor = trackingAreas.first?.trackingAreaSuppressor isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false } From 71fe933405cc8f4d2b04afa0728731e8e97dd1a7 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 21:50:04 +0600 Subject: [PATCH 08/11] fix tests? --- DuckDuckGo/Tab/View/WebView.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 941dae49f9..64e0812cfb 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -392,12 +392,17 @@ extension NSTrackingArea { @objc private dynamic func swizzled_init(rect: NSRect, options: NSTrackingArea.Options, owner: AnyObject?, userInfo: NSDictionary) -> AnyObject? { var owner = owner + var trackingAreaSuppressor: TrackingAreaSuppressor? if owner?.className == "WKMouseTrackingObserver" { - let helper = TrackingAreaSuppressor(owner: owner) - self.trackingAreaSuppressor = helper - owner = helper + trackingAreaSuppressor = TrackingAreaSuppressor(owner: owner) + owner = trackingAreaSuppressor } + defer { + if let trackingAreaSuppressor { + self.trackingAreaSuppressor = trackingAreaSuppressor + } + } return self.swizzled_init(rect: rect, options: options, owner: owner, userInfo: userInfo) /* call original */ } From 3247f929bc4d3af2ac275d88de30835c36db52c5 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 22:11:13 +0600 Subject: [PATCH 09/11] redo without swizzling --- DuckDuckGo/Tab/View/WebView.swift | 75 ++++++++++--------------------- 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 64e0812cfb..5caba25d04 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -34,24 +34,39 @@ final class WebView: WKWebView { weak var contextMenuDelegate: WebViewContextMenuDelegate? weak var interactionEventsDelegate: WebViewInteractionEventsDelegate? + private var isLoadingObserver: Any? + private var trackingAreaSuppressor: TrackingAreaSuppressor? + private var proxiedTrackingArea: NSTrackingArea? - override init(frame: CGRect, configuration: WKWebViewConfiguration) { + override func addTrackingArea(_ trackingArea: NSTrackingArea) { + var trackingArea = trackingArea /// swizzle NSTrackingArea.init method to insert TrackingAreaSuppressor proxy owner /// it will disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading /// see https://app.asana.com/0/1177771139624306/1206990108527681/f - _=NSTrackingArea.swizzleInitWithRectOptionsOwnerUserInfoOnce - super.init(frame: frame, configuration: configuration) + if let mouseTrackingObserver = trackingArea.owner, mouseTrackingObserver.className == "WKMouseTrackingObserver" { + let suppressor = TrackingAreaSuppressor(owner: mouseTrackingObserver) + suppressor.isSuppressingMouseEvents = self.trackingAreaSuppressor?.isSuppressingMouseEvents ?? false + self.trackingAreaSuppressor = suppressor + + // suppress Tracking Area events while loading + isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in + suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false + } - // suppress Tracking Area events while loading - let suppressor = trackingAreas.first?.trackingAreaSuppressor - isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in - suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false + trackingArea = NSTrackingArea(rect: trackingArea.rect, options: trackingArea.options, owner: suppressor, userInfo: trackingArea.userInfo) + self.proxiedTrackingArea = trackingArea } + super.addTrackingArea(trackingArea) } - required init?(coder: NSCoder) { - fatalError("\(Self.self): Bad initializer") + override func removeTrackingArea(_ trackingArea: NSTrackingArea) { + var trackingArea = trackingArea + if trackingArea.owner?.className == "WKMouseTrackingObserver", let proxiedTrackingArea { + trackingArea = proxiedTrackingArea + self.proxiedTrackingArea = nil + } + super.removeTrackingArea(trackingArea) } override var isInFullScreenMode: Bool { @@ -375,45 +390,3 @@ final private class TrackingAreaSuppressor: NSObject { } } - -/// adding the TrackingAreaSuppressor proxy object as a WebView‘s Tracking Area owner -extension NSTrackingArea { - - private static let originalInitWithRectOptionsOwnerUserInfo = { - class_getInstanceMethod(NSTrackingArea.self, #selector(NSTrackingArea.init(rect:options:owner:userInfo:)))! - }() - private static let swizzledInitWithRectOptionsOwnerUserInfo = { - class_getInstanceMethod(NSTrackingArea.self, #selector(NSTrackingArea.swizzled_init(rect:options:owner:userInfo:)))! - }() - - fileprivate static let swizzleInitWithRectOptionsOwnerUserInfoOnce: Void = { - method_exchangeImplementations(originalInitWithRectOptionsOwnerUserInfo, swizzledInitWithRectOptionsOwnerUserInfo) - }() - - @objc private dynamic func swizzled_init(rect: NSRect, options: NSTrackingArea.Options, owner: AnyObject?, userInfo: NSDictionary) -> AnyObject? { - var owner = owner - var trackingAreaSuppressor: TrackingAreaSuppressor? - if owner?.className == "WKMouseTrackingObserver" { - trackingAreaSuppressor = TrackingAreaSuppressor(owner: owner) - owner = trackingAreaSuppressor - } - - defer { - if let trackingAreaSuppressor { - self.trackingAreaSuppressor = trackingAreaSuppressor - } - } - return self.swizzled_init(rect: rect, options: options, owner: owner, userInfo: userInfo) /* call original */ - } - - private static let trackingAreaSuppressorKey = UnsafeRawPointer(bitPattern: "trackingAreaSuppressorKey".hashValue)! - fileprivate private(set) var trackingAreaSuppressor: TrackingAreaSuppressor? { - get { - objc_getAssociatedObject(self, Self.trackingAreaSuppressorKey) as? TrackingAreaSuppressor - } - set { - objc_setAssociatedObject(self, Self.trackingAreaSuppressorKey, newValue, .OBJC_ASSOCIATION_RETAIN) - } - } - -} From abfe57b7f4cd5a3fef7a607fb225384816934801 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 22:14:55 +0600 Subject: [PATCH 10/11] fix comment --- DuckDuckGo/Tab/View/WebView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 5caba25d04..839a41bd91 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -41,7 +41,7 @@ final class WebView: WKWebView { override func addTrackingArea(_ trackingArea: NSTrackingArea) { var trackingArea = trackingArea - /// swizzle NSTrackingArea.init method to insert TrackingAreaSuppressor proxy owner + /// replace NSTrackingArea with owner proxied with TrackingAreaSuppressor. /// it will disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading /// see https://app.asana.com/0/1177771139624306/1206990108527681/f if let mouseTrackingObserver = trackingArea.owner, mouseTrackingObserver.className == "WKMouseTrackingObserver" { From 0f5e788c56f10423795e72b82d0d6f16a10413c6 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Fri, 12 Apr 2024 22:27:33 +0600 Subject: [PATCH 11/11] less code is better code --- DuckDuckGo/Tab/View/WebView.swift | 65 ++++++------------------------- 1 file changed, 12 insertions(+), 53 deletions(-) diff --git a/DuckDuckGo/Tab/View/WebView.swift b/DuckDuckGo/Tab/View/WebView.swift index 839a41bd91..b2c458cee0 100644 --- a/DuckDuckGo/Tab/View/WebView.swift +++ b/DuckDuckGo/Tab/View/WebView.swift @@ -36,37 +36,27 @@ final class WebView: WKWebView { weak var interactionEventsDelegate: WebViewInteractionEventsDelegate? private var isLoadingObserver: Any? - private var trackingAreaSuppressor: TrackingAreaSuppressor? - private var proxiedTrackingArea: NSTrackingArea? override func addTrackingArea(_ trackingArea: NSTrackingArea) { - var trackingArea = trackingArea - /// replace NSTrackingArea with owner proxied with TrackingAreaSuppressor. - /// it will disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading + /// disable mouseEntered/mouseMoved/mouseExited events passing to Web View while it‘s loading /// see https://app.asana.com/0/1177771139624306/1206990108527681/f - if let mouseTrackingObserver = trackingArea.owner, mouseTrackingObserver.className == "WKMouseTrackingObserver" { - let suppressor = TrackingAreaSuppressor(owner: mouseTrackingObserver) - suppressor.isSuppressingMouseEvents = self.trackingAreaSuppressor?.isSuppressingMouseEvents ?? false - self.trackingAreaSuppressor = suppressor - + if trackingArea.owner?.className == "WKMouseTrackingObserver" { // suppress Tracking Area events while loading - isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak suppressor] _, c in - suppressor?.isSuppressingMouseEvents = c.newValue /* isLoading */ ?? false + isLoadingObserver = self.observe(\.isLoading, options: [.new]) { [weak self, trackingArea] _, c in + if c.newValue /* isLoading */ ?? false { + guard let self, self.trackingAreas.contains(trackingArea) else { return } + removeTrackingArea(trackingArea) + } else { + guard let self, !self.trackingAreas.contains(trackingArea) else { return } + superAddTrackingArea(trackingArea) + } } - - trackingArea = NSTrackingArea(rect: trackingArea.rect, options: trackingArea.options, owner: suppressor, userInfo: trackingArea.userInfo) - self.proxiedTrackingArea = trackingArea } super.addTrackingArea(trackingArea) } - override func removeTrackingArea(_ trackingArea: NSTrackingArea) { - var trackingArea = trackingArea - if trackingArea.owner?.className == "WKMouseTrackingObserver", let proxiedTrackingArea { - trackingArea = proxiedTrackingArea - self.proxiedTrackingArea = nil - } - super.removeTrackingArea(trackingArea) + private func superAddTrackingArea(_ trackingArea: NSTrackingArea) { + super.addTrackingArea(trackingArea) } override var isInFullScreenMode: Bool { @@ -359,34 +349,3 @@ extension WebView /* _WKFindDelegate */ { } } - -/// used to suppress mouseEntered/mouseMoved/mouseExited events while Web View is loading -final private class TrackingAreaSuppressor: NSObject { - - private weak var owner: AnyObject? - - var isSuppressingMouseEvents = false - - init(owner: AnyObject? = nil) { - self.owner = owner - } - - @objc(mouseEntered:) - func mouseEntered(with event: NSEvent) { - guard !isSuppressingMouseEvents else { return } - _=owner?.perform(#selector(mouseEntered), with: event) - } - - @objc(mouseExited:) - func mouseExited(with event: NSEvent) { - guard !isSuppressingMouseEvents else { return } - _=owner?.perform(#selector(mouseExited), with: event) - } - - @objc(mouseMoved:) - func mouseMoved(with event: NSEvent) { - guard !isSuppressingMouseEvents else { return } - _=owner?.perform(#selector(mouseMoved), with: event) - } - -}