macOS: Workaround for unresponsive main menu after reopen

Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
Roopesh Chander 2019-05-22 15:26:38 +05:30
parent e582155a10
commit 717bc8a26f
1 changed files with 42 additions and 6 deletions

View File

@ -13,6 +13,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var manageTunnelsRootVC: ManageTunnelsRootViewController? var manageTunnelsRootVC: ManageTunnelsRootViewController?
var manageTunnelsWindowObject: NSWindow? var manageTunnelsWindowObject: NSWindow?
var onAppDeactivation: (() -> Void)?
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path) Logger.configureGlobal(tagged: "APP", withFilePath: FileManager.logFileURL?.path)
@ -24,7 +25,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
} }
if !isLaunchedAtLogin { if !isLaunchedAtLogin {
NSApp.setActivationPolicy(.regular) setDockIconAndMainMenuVisibility(isVisible: true)
} }
NSApp.mainMenu = MainMenu() NSApp.mainMenu = MainMenu()
@ -121,9 +122,44 @@ class AppDelegate: NSObject, NSApplicationDelegate {
} }
func applicationShouldTerminateAfterLastWindowClosed(_ application: NSApplication) -> Bool { func applicationShouldTerminateAfterLastWindowClosed(_ application: NSApplication) -> Bool {
application.setActivationPolicy(.accessory) setDockIconAndMainMenuVisibility(isVisible: false)
return false return false
} }
private func setDockIconAndMainMenuVisibility(isVisible: Bool, completion: (() -> Void)? = nil) {
let currentActivationPolicy = NSApp.activationPolicy()
let newActivationPolicy: NSApplication.ActivationPolicy = isVisible ? .regular : .accessory
guard currentActivationPolicy != newActivationPolicy else {
if newActivationPolicy == .regular {
NSApp.activate(ignoringOtherApps: true)
}
completion?()
return
}
if newActivationPolicy == .regular && NSApp.isActive {
// To workaround a possible AppKit bug that causes the main menu to become unresponsive,
// we should deactivate the app first and then set the activation policy.
// NSApp.deactivate() doesn't always deactivate the app, so we instead use
// setActivationPolicy(.prohibited).
onAppDeactivation = {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
completion?()
}
NSApp.setActivationPolicy(.prohibited)
} else {
NSApp.setActivationPolicy(newActivationPolicy)
if newActivationPolicy == .regular {
NSApp.activate(ignoringOtherApps: true)
}
completion?()
}
}
func applicationDidResignActive(_ notification: Notification) {
onAppDeactivation?()
onAppDeactivation = nil
}
} }
extension AppDelegate { extension AppDelegate {
@ -159,11 +195,11 @@ extension AppDelegate: StatusMenuWindowDelegate {
manageTunnelsWindowObject = window manageTunnelsWindowObject = window
tunnelsTracker?.manageTunnelsRootVC = manageTunnelsRootVC tunnelsTracker?.manageTunnelsRootVC = manageTunnelsRootVC
} }
NSApp.setActivationPolicy(.regular) setDockIconAndMainMenuVisibility(isVisible: true) { [weak manageTunnelsWindowObject] in
NSApp.activate(ignoringOtherApps: true) manageTunnelsWindowObject?.makeKeyAndOrderFront(self)
manageTunnelsWindowObject!.makeKeyAndOrderFront(self)
completion?(manageTunnelsWindowObject) completion?(manageTunnelsWindowObject)
} }
}
} }
@discardableResult @discardableResult