Monitoring Any Window in OS X

Guides | Tutorial By 6 years ago

In a project I’ve been working on recently I need to interact with other process’ windows on the Mac. The application lets you drag windows around that will ‘bolt-on’ to another application’s window and follow it around the screen.

Unfortunately unless you know how to do this, finding out information on how it’s done can be difficult (like most things). Initially my solution was to use Applescript. It worked ok, but was slow and wouldn’t tell me when a window was actively moving (if you were dragging it around the screen), only when the window was stationary. My Applescript solution was only compatible with Cocoa applicataions as well. On my quest to find a better solution I came across the very primitive CGWindowListCopyWindowInfo method. This will give you a massive list of all windows (including menu bars, the dock, etc etc) and a lot of information about them.

NSArray* windows = (id)CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID);
NSLog(@"%@", windows);
[windows release];
windows = nil;

Output:

{
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 1024;
        Width = 1680;
        X = 4;
        Y = 22;
    };
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 976400;
    kCGWindowName = iTunes;
    kCGWindowNumber = 309;
    kCGWindowOwnerName = iTunes;
    kCGWindowOwnerPID = 3588;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
},
    {
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 109;
        Width = 240;
        X = 1440;
        Y = 70;
    };
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 75280;
    kCGWindowName = "";
    kCGWindowNumber = 199;
    kCGWindowOwnerName = Safari;
    kCGWindowOwnerPID = 446;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
},
    {
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 22;
        Width = 1680;
        X = 0;
        Y = 0;
    };
    kCGWindowLayer = 24;
    kCGWindowMemoryUsage = 5648;
    kCGWindowNumber = 194;
    kCGWindowOwnerName = SystemUIServer;
    kCGWindowOwnerPID = 363;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
},

Note that unlike the lower-left origin that you use when positioning NSWindow‘s, this user upper-left coordinates.

From the list above you can obtain the kCGWindowNumber (datatype: CGWindowID) and use the same function above specifying the window id to obtain information for just one window.

CGWindowListCopyWindowInfo(kCGWindowListOptionIncludingWindow, windowID);

This will give back an array with one element, being the window’s information