Z-order of all active windows / applications?

System Events lists application windows in their z-order, but I wonder if the the z-order of all active windows is accessible ?

The Core Graphics framework puts a fair amount of useful information about windows within direct reach of KM Execute ... Script actions, but I don’t think that includes their z order. Any thoughts ?

JavaScript for Automation:

(() => {
    'use strict';

    ObjC.import('CoreGraphics')

    // CORE GRAPHICS KEYS ----------------------------------------------------
    const ks = [
        'kCGWindowLayer', 'kCGWindowAlpha', 'kCGWindowMemoryUsage',
        'kCGWindowIsOnscreen', 'kCGWindowSharingState', 'kCGWindowOwnerPID',
        'kCGWindowNumber', 'kCGWindowOwnerName', 'kCGWindowStoreType',
        'kCGWindowBounds', 'kCGWindowName'
    ];


    // GENERIC FUNCTIONS -----------------------------------------------------

    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        (x, y) => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // headDef :: [a] -> a
    const headDef = xs => xs.length ? xs[0] : undefined;


    // show :: Int -> a -> Indented String
    // show :: a -> String
    const show = (...x) =>
        JSON.stringify.apply(
            null, x.length > 1 ? [x[1], null, x[0]] : x
        );

    // INFORMATION ON ACTIVE WINDOWS -----------------------------------------
    return show(2,
        ObjC.deepUnwrap(
            $.CGWindowListCopyWindowInfo(
                $.kCGWindowListOptionOnScreenOnly +
                $.kCGWindowListExcludeDesktopElements,
                $.kCGNullWindowID
            )
        )
        .map(
            x => [
                'kCGWindowOwnerName',
                'kCGWindowName',
                'kCGWindowBounds',
                'kCGWindowNumber'
            ].map(k => x[k])
        )
        .sort(comparing(headDef))
    );
})();

As a macro, for refce:

winInfo.kmmacros (19.4 KB)

Ah … OK, I think Core Graphics does indeed reveal the zOrder across applications (we just have to prune out the menu bar apps etc)

JavaScript for Automation

Front first:

(() => {
    'use strict';

    ObjC.import('CoreGraphics')


    // GENERIC FUNCTIONS -----------------------------------------------------

    // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) =>
        xs.length > 0 ? [].concat.apply([], xs.map(f)) : [];

    // show :: Int -> a -> Indented String
    // show :: a -> String
    const show = (...x) =>
        JSON.stringify.apply(
            null, x.length > 1 ? [x[1], null, x[0]] : x
        );

    // INFORMATION ON ACTIVE WINDOWS -----------------------------------------
    return show(2,
        concatMap(
            w => {
                const xywh = w.kCGWindowBounds;
                return xywh.Y >= 22 ? [{
                    app: w.kCGWindowOwnerName,
                    title:  w.kCGWindowName,
                    xywh: xywh
                }] : [];
            },
            ObjC.deepUnwrap(
                $.CGWindowListCopyWindowInfo(
                    $.kCGWindowListOptionOnScreenOnly +
                    $.kCGWindowListExcludeDesktopElements,
                    $.kCGNullWindowID
                )
            )
        )
    );
})();

In AppleScript FWIW, we can certainly get as far as:

use framework "Foundation"
use framework "CoreGraphics"
use scripting additions

on run

    set ca to current application
    (ca's CGWindowListCopyWindowInfo(ca's kCGWindowListOptionOnScreenOnly, ca's kCGNullWindowID))

    --> «class cptr» id «data gptr0000000000058507006000007B5F5F434641727261793D7D00»
    
end run

But after that AS doesn’t provide an ObjC.deepUnwrap method, and is seems to be harder than in JS to coerce the returned reference to an AS data-type. Perhaps there’s a trick that I don’t know ?

Hey Rob,

Well done!  :smile:

And fast!

-Chris

I’m finding it useful :slight_smile:

Any idea of how we could convert that value returned to AppleScript by the ObjC FFI ?