Skip to content

Instantly share code, notes, and snippets.

@pudquick
Created March 29, 2017 22:57
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save pudquick/eebc4d569100c8e3039bf3eae56bee4c to your computer and use it in GitHub Desktop.
Save pudquick/eebc4d569100c8e3039bf3eae56bee4c to your computer and use it in GitHub Desktop.
Getting the list of visible apps (think: Force Quit) in macOS via python and pyobjc
from Foundation import NSBundle
import objc
CoreServices = NSBundle.bundleWithIdentifier_('com.apple.CoreServices')
functions = [
('_LSCopyRunningApplicationArray', '@I'),
('_LSCopyApplicationInformation', '@I@@'),
]
constants = [
('_kLSApplicationTypeKey', '@'),
('_kLSApplicationForegroundTypeKey', '@'),
('_kLSDisplayNameKey', '@')
]
objc.loadBundleFunctions(CoreServices, globals(), functions)
objc.loadBundleVariables(CoreServices, globals(), constants)
apps = _LSCopyRunningApplicationArray(0xfffffffe)
app_infos = [_LSCopyApplicationInformation(0xffffffff, x, None) for x in apps]
visible_app_infos = [x for x in app_infos if x.get(_kLSApplicationTypeKey, None) == _kLSApplicationForegroundTypeKey]
visible_apps = sorted([x.get(_kLSDisplayNameKey) for x in visible_app_infos])
@amomchilov
Copy link

I figured out a few things about these APIs that can come in handy.

_LSCopyRunningApplicationArray

I don't have a source for this, but I'm fairly certain the prototype is:

CFArray _LSCopyRunningApplicationArray(LSSessionID sessionID);
  • LSSessionID is a C enum with one known values (as seen in the WebKit source):

    enum LSSessionID {
        kLSDefaultSessionID = -2,
    };

    The -2 is equivalent to 0xfffffffe. The example above also uses 0xffffffff, which is probably another case, kLSCurrentSessionID = -1, but I haven't been able to verify that. It's mentioned in manpage of lsappinfo, but not its value, or how its different.

  • The returned result is an array of LSASNRefs, described below.

_LSCopyApplicationInformation

Here's the prototype from darling:

CFDictionaryRef _LSCopyApplicationInformation(LSSessionID sessionID, CFTypeRef asn, int);

I think the type is actually more like:

CFDictionaryRef _LSCopyApplicationInformation(LSSessionID sessionID, LSASNRef asn, CFString key);

Where:

  • LSSessionID is the same as above

  • LSASNRef is defined by WebKit as:

    typedef const struct CF_BRIDGED_TYPE(id) __LSASN* LSASNRef;

    A common value is the result of _LSGetCurrentApplicationASN(), or as in this example, the elements returned by _LSCopyRunningApplicationArray().

    struct __LSASN" itself is some opaque structure. I don't know anything about its fields/layout.

  • CFString key is an optional key that picks which property to retrieve (all other properties would be null). It's probably quicker to fetch one field if you know what you need, but I haven't benchmarked it.

    If null, all properties are retrieved.

Here's a new-and-improved version, which gives name to the LSSessionID magic numbers, and updates the script for Python 3: https://gist.github.com/amomchilov/096ce5ceb9f4fca942ae0dd37066bc11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment