Reputation: 678
Can anyone think of a workaround for the osascript index-by-name bottle-neck in its reference to multiple instances of the same application ?
If we obtain two process ids – one for each of two different instances of the same application, osascript returns the same instance in exchange for either pid - as if it first maps the pid to an application name, and then retrieves the first application process with that name.
For example, start two different instances of VLC.app, playing two different video files, with something like:
open -na /Applications/VLC.app ~/fileA.m4v
open -na /Applications/VLC.app ~/fileB.m4v
then obtain the two separate application process ids with, for example:
echo "$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')"
We can then use Applescript or Yosemite JXA Javascript to get a reference to an application object from either pid.
It turns out, however, that whichever process id we supply, we are always returned a reference to the same instance, running the same video file, as if osascript simply translates a pid to an application name, and then always returns the first process which matches that name.
Yosemite Javascript for applications:
function run() {
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var lstVLC = app.doShellScript(
"echo \"$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')\""
).split(/[\r\n]/).map(Number).map(Application);
return {
firstInstance: lstVLC[0].windows[0].name(),
secondInstance: lstVLC[1].windows[0].name()
};
}
Applescript:
on run {}
set strCMD to "echo \"$(ps -ceo pid=,comm= | awk '/VLC/ { print $1}')\""
set lstNum to paragraphs of (do shell script strCMD)
repeat with i from 1 to length of lstNum
set item i of lstNum to (item i of lstNum) as number
end repeat
tell application "System Events"
set oProcA to first application process where unix id = (item 1 of lstNum)
set oProcB to first application process where unix id = (item 2 of lstNum)
end tell
return [name of first window of oProcA, name of first window of oProcB]
end run
Any thoughts on a route to scripting each instance separately ?
Upvotes: 2
Views: 723
Reputation: 254
This seems to have been fixed in El Capitan, as your JavaScript code ran fine on my machine.
Upvotes: 1
Reputation: 3259
JXA is a bundle of bugs and defective design. Its failure to do stuff like this right is depressing, but entirely unsurprising (the AS team has form).
As for AppleScript, it's never provided a direct way to target apps by PID. In the past I may have cheated it by enabling Remote Apple Events and targeting the process with an eppc://USER@HOST/APPNAME?pid=PID
URL, but trying it just now on 10.10 damned if I could get it to work as it always returned a "remote access not allowed" error.
Appscript could do this stuff in its sleep, but I dropped public support for it due to Apple's War on Carbon and crappy "replacement" Cocoa APIs forcing it into "legacy" status, so you're on your own there.
The one officially supported option that may work is OS X's Scripting Bridge framework, which provides a method for targeting processes by PID. Though like JXA it's riddled with design flaws, missing features, and application compatibility problems, so YMWV.
Upvotes: 0
Reputation: 678
Using jackjr300's approach in Javascript, to get at least to UI scripting (though not to the Application object interface):
function run() {
var appSE = Application("System Events");
app = Application.currentApplication();
app.includeStandardAdditions = true;
function uiWidgets(lngID) {
return appSE.processes.whose({
unixId: lngID
})[0].windows[0].uiElements();
}
var lstWidgets = app.doShellScript(
"ps -ceo pid=,comm= | awk '/VLC/ { print $1}'"
).split(/\r/).map(Number).map(uiWidgets);
return lstWidgets;
}
Upvotes: 0
Reputation: 7191
For each instance, ask the name of the window from the same line as the specific process, like this :
set windowNames to {}
set lstNum to paragraphs of (do shell script "ps -ceo pid=,comm= | awk '/VLC/ { print $1}'")
tell application "System Events" to repeat with i in lstNum
set end of windowNames to name of first window of (first application process where unix id = i)
end repeat
return windowNames
Upvotes: 2