Fix menuitem actions in macOS 10.15.1 (#234)

This commit is contained in:
Yicheng 2019-10-31 21:03:22 +08:00 committed by GitHub
parent fcca7c970e
commit f698e58767
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 7 deletions

View File

@ -42,6 +42,7 @@
499A485C22ED793C00F6C675 /* NSView+Nib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A485B22ED793C00F6C675 /* NSView+Nib.swift */; };
499A485E22ED9B7C00F6C675 /* NSTableView+Reload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A485D22ED9B7C00F6C675 /* NSTableView+Reload.swift */; };
499A486522EEA3FD00F6C675 /* Array+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A486422EEA3FC00F6C675 /* Array+Safe.swift */; };
49ABB749236B0F9E00535CD7 /* UnsafePointer+bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49ABB748236B0F9E00535CD7 /* UnsafePointer+bridge.swift */; };
49B1086A216A356D0064FFCE /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49B10869216A356D0064FFCE /* String+Extension.swift */; };
49BC061C212931F4005A0FE7 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BC061B212931F4005A0FE7 /* AboutViewController.swift */; };
49C9EF64223E78F5005D8B6A /* ClashProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49C9EF63223E78F5005D8B6A /* ClashProxy.swift */; };
@ -141,6 +142,7 @@
499A485B22ED793C00F6C675 /* NSView+Nib.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+Nib.swift"; sourceTree = "<group>"; };
499A485D22ED9B7C00F6C675 /* NSTableView+Reload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Reload.swift"; sourceTree = "<group>"; };
499A486422EEA3FC00F6C675 /* Array+Safe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Safe.swift"; sourceTree = "<group>"; };
49ABB748236B0F9E00535CD7 /* UnsafePointer+bridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnsafePointer+bridge.swift"; sourceTree = "<group>"; };
49B10869216A356D0064FFCE /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
49BC061B212931F4005A0FE7 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
49C9EF63223E78F5005D8B6A /* ClashProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashProxy.swift; sourceTree = "<group>"; };
@ -324,6 +326,7 @@
4966E9E5211824F300A391FB /* NSImage+extension.swift */,
496BDEDF21196F1E00C5207F /* Logger.swift */,
49B10869216A356D0064FFCE /* String+Extension.swift */,
49ABB748236B0F9E00535CD7 /* UnsafePointer+bridge.swift */,
);
path = Basic;
sourceTree = "<group>";
@ -590,6 +593,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
49ABB749236B0F9E00535CD7 /* UnsafePointer+bridge.swift in Sources */,
499A485522ED707300F6C675 /* RemoteConfigViewController.swift in Sources */,
49CF3B5C20CE8068001EBF94 /* ClashResourceManager.swift in Sources */,
4952C3D02117027C004A4FA8 /* ConfigFileManager.swift in Sources */,

View File

@ -0,0 +1,15 @@
//
// UnsafePointer+bridge.swift
// ClashX
//
// Created by yicheng on 2019/10/31.
// Copyright © 2019 west2online. All rights reserved.
//
func bridge<T: AnyObject>(obj: T) -> UnsafeMutableRawPointer {
return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
func bridge<T: AnyObject>(ptr: UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

View File

@ -12,6 +12,9 @@ class ProxyGroupMenuItemView: NSView {
let groupNameLabel: NSTextField
let selectProxyLabel: NSTextField
let arrowImageView = NSTextField(labelWithString: "")
var isMouseInsideView = false
var isMenuOpen = false
init(group: ClashProxyName, targetProxy: ClashProxyName) {
groupNameLabel = NSTextField(labelWithString: group)
selectProxyLabel = NSTextField(labelWithString: targetProxy)
@ -55,6 +58,15 @@ class ProxyGroupMenuItemView: NSView {
fatalError("init(coder:) has not been implemented")
}
override func updateTrackingAreas() {
super.updateTrackingAreas()
if #available(macOS 10.15.1, *) {
trackingAreas.forEach { removeTrackingArea($0) }
enclosingMenuItem?.submenu?.delegate = self
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil))
}
}
override func viewDidMoveToSuperview() {
super.viewDidMoveToSuperview()
if #available(macOS 10.15, *) {} else {
@ -64,10 +76,30 @@ class ProxyGroupMenuItemView: NSView {
}
}
override func mouseEntered(with event: NSEvent) {
if #available(macOS 10.15.1, *) {
isMouseInsideView = true
setNeedsDisplay(bounds)
}
}
override func mouseExited(with event: NSEvent) {
if #available(macOS 10.15.1, *) {
isMouseInsideView = false
setNeedsDisplay(bounds)
}
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
guard let menu = enclosingMenuItem else { return }
if menu.isHighlighted {
let isHighlighted: Bool
if #available(macOS 10.15.1, *) {
isHighlighted = isMouseInsideView || isMenuOpen
} else {
isHighlighted = menu.isHighlighted
}
if isHighlighted {
NSColor.selectedMenuItemColor.setFill()
groupNameLabel.textColor = NSColor.white
selectProxyLabel.textColor = NSColor.white
@ -81,3 +113,19 @@ class ProxyGroupMenuItemView: NSView {
dirtyRect.fill()
}
}
extension ProxyGroupMenuItemView: NSMenuDelegate {
func menuWillOpen(_ menu: NSMenu) {
if #available(macOS 10.15.1, *) {
isMenuOpen = true
setNeedsDisplay(bounds)
}
}
func menuDidClose(_ menu: NSMenu) {
if #available(macOS 10.15.1, *) {
isMenuOpen = false
setNeedsDisplay(bounds)
}
}
}

View File

@ -6,6 +6,7 @@
// Copyright © 2019 west2online. All rights reserved.
//
import Carbon
import Cocoa
class ProxyGroupSpeedTestMenuItem: NSMenuItem {
@ -41,8 +42,10 @@ class ProxyGroupSpeedTestMenuItem: NSMenuItem {
}
fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
let label: NSTextField
let font = NSFont.menuFont(ofSize: 14)
private let label: NSTextField
private let font = NSFont.menuFont(ofSize: 14)
private var isMouseInsideView = false
private var eventHandler: EventHandlerRef?
init(_ title: String) {
label = NSTextField(labelWithString: title)
@ -60,11 +63,12 @@ fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
}
private func startBenchmark() {
guard let group = (enclosingMenuItem as? ProxyGroupSpeedTestMenuItem)?.proxyGroup else { return }
guard let group = (enclosingMenuItem as? ProxyGroupSpeedTestMenuItem)?.proxyGroup
else { return }
let testGroup = DispatchGroup()
label.stringValue = NSLocalizedString("Testing", comment: "")
enclosingMenuItem?.isEnabled = false
setNeedsDisplay(bounds)
for proxyName in group.speedtestAble {
testGroup.enter()
ApiRequest.getProxyDelay(proxyName: proxyName) { delay in
@ -82,6 +86,60 @@ fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
self.label.stringValue = menu.title
self.label.textColor = NSColor.labelColor
menu.isEnabled = true
self.setNeedsDisplay(self.bounds)
}
}
override func updateTrackingAreas() {
super.updateTrackingAreas()
if #available(macOS 10.15.1, *) {
trackingAreas.forEach { removeTrackingArea($0) }
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil))
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil))
}
}
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
if #available(macOS 10.15.1, *) {
setupCarbon()
}
}
// https://gist.github.com/p0deje/da5e5cfda6be8cb87c2e7caad3a3df63
// https://stackoverflow.com/questions/53273191/custom-carbon-key-event-handler-fails-after-mouse-events
@available(macOS 10.15.1, *)
private func setupCarbon() {
if window != nil {
if let dispatcher = GetEventDispatcherTarget() {
let eventHandlerCallback: EventHandlerUPP = { eventHandlerCallRef, eventRef, userData in
guard let userData = userData else { return 0 }
let itemView: ProxyGroupSpeedTestMenuItemView = bridge(ptr: userData)
itemView.startBenchmark()
let response = CallNextEventHandler(eventHandlerCallRef, eventRef!)
return response
}
let eventSpecs = [EventTypeSpec(eventClass: OSType(kEventClassMouse), eventKind: UInt32(kEventMouseUp))]
InstallEventHandler(dispatcher, eventHandlerCallback, 1, eventSpecs, bridge(obj: self), &eventHandler)
}
} else {
RemoveEventHandler(eventHandler)
}
}
override func mouseEntered(with event: NSEvent) {
if #available(macOS 10.15.1, *) {
isMouseInsideView = true
setNeedsDisplay(bounds)
}
}
override func mouseExited(with event: NSEvent) {
if #available(macOS 10.15.1, *) {
isMouseInsideView = false
setNeedsDisplay(bounds)
}
}
@ -93,13 +151,22 @@ fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
}
override func mouseUp(with event: NSEvent) {
startBenchmark()
if #available(macOS 10.15.1, *) {} else {
startBenchmark()
}
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
guard let menu = enclosingMenuItem else { return }
if menu.isHighlighted {
let isHighlighted: Bool
if #available(macOS 10.15.1, *) {
isHighlighted = isMouseInsideView
} else {
isHighlighted = menu.isHighlighted
}
if isHighlighted && menu.isEnabled {
NSColor.selectedMenuItemColor.setFill()
label.textColor = NSColor.white
} else {