Reputation: 155
I want to launch a file with a specified application, and I want the launched program to immediately become the frontmost window.
I know that I can do this as follows:
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName];
Then, if I can get the PID of that launched application, I can then do this to make that application frontmost:
NSRunningApplication* app = [NSRunningApplication
runningApplicationWithProcessIdentifier: PID];
[app activateWithOptions: NSApplicationActivateAllWindows];
The question I have is this: what is the simplest, quickest, and most reliable way to get this application's PID right after launching, so I can make sure that this application is frontmost?
This is not as straightforward as it might appear at first glance. For example, I need a process name in order to get the PID using Carbon calls, or via the application dictionary that is accessible via NSRunningApplication
. However, in the general case, I don't always know what the process name is, and in some cases, the process name is an empty string.
Furthermore, I might have other instances of this same application already running, and I want to always get the PID of the specific instance of the application that I just launched.
Can anyone suggest a definitive, 100-percent reliable way to get the currently launched application's PID?
Or alternatively, is there a way to launch a given file with a specified application such that the application always opens as the frontmost app?
Upvotes: 5
Views: 1950
Reputation: 16463
It is definitely not easy to get the PID of an application. And that's how Apple likes it.. Those cheeky bastards.
I had to write this beast just to get the PID from a full path of an app I knew was running.. Hey it's easier than parsing ps aux
!
Sorry if there are some of my own private functions in there but you can get the idea of how I went about it and what I tried to avoid along the way.
+ (NSUInteger)pidFromAppPath:(NSString*)path
{
NSRunningApplication *n = [[[NSWorkspace sharedWorkspace]runningApplications] filterOne:^BOOL(NSRunningApplication *runner) {
// optional: avoid totally faceless apps and "Desk Accesory"-type background apps.
if (runner.activationPolicy == NSApplicationActivationPolicyProhibited) ||
runner.activationPolicy == NSApplicationActivationPolicyAccessory)
return nil;
id runPath = [runner valueForKeyPath:@"bundleURL"];
NSString *runString = [runPath isKindOfClass:[NSString class]]
? runPath
: [runPath isKindOfClass:NSURL.class] ? [((NSURL*)runPath) path]
: nil;
// optional: filter out Google Chrome's mockery of a once sane process-table
if ( !runString
|| [[runString lastPathComponent]contains:@"Google Chrome Helper.app"]
|| [[runString lastPathComponent]contains:@"Google Chrome Worker.app"]
|| [[runString lastPathComponent]contains:@"Google Chrome Renderer.app"] )
return nil;
return [runString isEqualToString:path] ?: nil; // This is where you actually test to see if it's the same as the string passed in, lol.
}];
return n ? [n processIdentifier] : 11000; // if 11000 you messed up.
}
And voilá... NSLOG: Pid of /Applications/Utilities/Terminal.app is 46152
Upvotes: 1
Reputation: 4348
Have you tried using the other version of openFile which will allow you to deactivate your application, allowing the new application to take focus?
[[NSWorkspace sharedWorkspace] openFile:fileName withApplication:appName andDeactivate:YES];
Upvotes: 1