On Big Sur at least, @CJK's very helpful (application prototype extension) code lets us generate a JSON listing of windows for named applications in this kind of Keyboard Maestro pattern:
Windows listed for named applications.kmmacros (4.0 KB)
Expand disclosure triangle to view JS Source
(() => {
"use strict";
// Rough sketch by Rob Trew,
// using CJK's Application prototype extension code.
// Ver 0.2 (fixed a Width ⇄ Height swap)
const main = () => {
const
appNames = Application("Keyboard Maestro Engine")
.getvariable("appNames");
return (
extendPrototype(),
JSON.stringify(
lines(appNames).map(
k => ({
appName: k,
windowList: Application(
k.trim()
).getWindowList()
})
), null, 2
)
);
};
// ----------------------- JXA -----------------------
// Using code by CJK
const extendPrototype = () =>
Application.prototype.getWindowList = function() {
ObjC.import("CoreGraphics");
const
pids = Application("com.apple.systemevents")
.processes
.whose({"bundleIdentifier": this.id()})
.unixId();
return ObjC.deepUnwrap(
ObjC.castRefToObject(
$.CGWindowListCopyWindowInfo(16, 0)
)
)
.filter(
e => pids.includes(e.kCGWindowOwnerPID) &&
e.kCGWindowLayer === 0 &&
e.kCGWindowAlpha === 1 &&
e.kCGWindowStoreType === 1
)
.map(x => ({id: x.kCGWindowNumber,
name: x.kCGWindowName,
bounds: [
"X", "Y",
"Width",
"Height"
].map(z => x.kCGWindowBounds[z])})
);
};
// --------------------- GENERIC ---------------------
// lines :: String -> [String]
const lines = s =>
// A list of strings derived from a single string
// which is delimited by \n or by \r\n or \r.
Boolean(s.length) ? (
s.split(/\r\n|\n|\r/u)
) : [];
// MAIN ---
return main();
})();