And with AppKit's help we can simplify it a bit, and speed it up more than somewhat:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
set theApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
set thePred to current application's NSPredicate's predicateWithFormat:"activationPolicy == %@" argumentArray:{0}
set foregroundBundleIDs to ((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleIdentifier") as list
Thanks. I was thinking about NSWorkspaceâs runningApplications but wasnât aware of
NSApplicationActivationPolicy.
Extending that slightly, and a bit off topic, but we can produce a potentially useful script that separates running bundle IDs according to background, menubar or foreground that belong to 3rd party processes (this has already helped me troubleshoot a problem for someone else):
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
set nonAppleForeground to {}
set nonAppleMenubar to {}
set nonAppleBackground to {}
on excludeAppleIDs:ids
set returnList to {}
repeat with ident in ids
if ident does not contain "com.apple" and ident does not contain missing value then
set end of returnList to ident as text
end if
end repeat
return returnList
end excludeAppleIDs:
set theApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
repeat with i from 0 to 2
set thePred to (current application's NSPredicate's predicateWithFormat:"activationPolicy == %@" argumentArray:{i})
if i is equal to 0 then
set nonAppleForeground to (my excludeAppleIDs:(((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleIdentifier") as list))
else if i is equal to 1 then
set nonAppleMenubar to (my excludeAppleIDs:(((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleIdentifier") as list))
else
set nonAppleBackground to (my excludeAppleIDs:(((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleIdentifier") as list))
end if
end repeat
You can do that in the predicate. You can also use it to skip processes that donât have a bundle ID:
set thePred to (current application's NSPredicate's predicateWithFormat:"activationPolicy == %@ AND bundleIdentifier != %@ AND NOT bundleIdentifier BEGINSWITH %@" argumentArray:{i, missing value, "com.apple"})
And for a bit more code parsimony, you could set the result variables by list:
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
set theApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
set theBundleIDs to current application's NSMutableArray's new()
repeat with i from 0 to 2
set thePred to (current application's NSPredicate's predicateWithFormat:"activationPolicy == %@ AND NOT (bundleIdentifier == NIL OR bundleIdentifier BEGINSWITH 'com.apple')" argumentArray:{i})
tell theBundleIDs to addObject:((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleIdentifier")
end repeat
set {nonAppleForeground, nonAppleMenubar, nonAppleBackground} to theBundleIDs as list
Is it possible to set the predicate to filter apps that are scriptable?
For now, Iâm using this (improved by your activationPolicy snippet):
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
set theApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
set thePred to current application's NSPredicate's predicateWithFormat:"activationPolicy == 0"
set appsURL to ((theApps's filteredArrayUsingPredicate:thePred)'s valueForKey:"bundleURL")
set scriptableApps to current application's NSMutableArray's new()
repeat with anURL in appsURL
set {hasResult, theResult} to (anURL's getResourceValue:(reference) forKey:(current application's NSURLApplicationIsScriptableKey) |error|:(missing value))
if theResult as boolean then
set aBundle to ((current application's NSBundle's bundleWithURL:anURL)'s bundleIdentifier())
(scriptableApps's addObject:aBundle)
end if
end repeat
scriptableApps as list