I see pretty strange behaviour of NSRunningApplicationInstance.activate()
method.
Let's imagine that I have found app named "Finder". This app at the moment is:
Not active
and/or hidden
I have really simple code:
let activeOptions: NSApplication.ActivationOptions = [.activateAllWindows, .activateIgnoringOtherApps]
print("1. isActive: \(app.isActive); isHidden: \(app.isHidden)")
if (!app.isActive)
{
app.activate(options: activeOptions)
}
if ( app.isHidden )
{
app.unhide()
}
print("2. isActive: \(app.isActive); isHidden: \(app.isHidden)")
for finding needed app you can use the following code:
let app = NSWorkspace.shared.runningApplications.filter{ $0.localizedName = "NameOfApp"}
2 times runned code result:
- isActive: false; isHidden: false
- isActive: false; isHidden: false
- isActive: true; isHidden: false
- isActive: true; isHidden: false
If you will try it... :
BUT only on second code run! (Why?)
And I see similar behaviour with a lot of applications, not only with Finder.
As example SourceTree app.
Can somebody explain the logic and how do display window of the ANY of runned app by some code IN ANY CASE?
Here is working Playground module. The approach is to use KVO for observable properties to be informed when exactly desired state for target application occurs. Hope it would be helpful somehow.
import Cocoa
class AppActivator: NSObject {
private var application: NSRunningApplication!
private let filterName: String
init(appName: String) {
filterName = appName
}
func activate() {
guard let app = NSWorkspace.shared.runningApplications.filter ({
return $0.localizedName == self.filterName || $0.bundleIdentifier?.contains(self.filterName) ?? false
}).first else {
print("Application \(self.filterName) not found")
return
}
guard app.activationPolicy != .prohibited else {
print("Application \(self.filterName) prohibits activation")
return
}
self.application = app
self.unhideAppIfNeeded()
self.activateAppIfNeeded()
}
private func unhideAppIfNeeded() {
if application.isHidden {
application.addObserver(self, forKeyPath: "isHidden", options: .new, context: nil)
application.unhide()
}
}
private func activateAppIfNeeded() {
if !application.isHidden && !application.isActive {
application.addObserver(self, forKeyPath: "isActive", options: .new, context: nil)
application.activate(options: .activateIgnoringOtherApps)
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "isHidden" {
application.removeObserver(self, forKeyPath: "isHidden")
activateAppIfNeeded()
} else if keyPath == "isActive" {
application.removeObserver(self, forKeyPath: "isActive")
print("Application \(application.localizedName) - ACTIVATED!")
}
}
}
let activator = AppActivator(appName: "Finder")
activator.activate()