开发者

How do I get a list of the window titles on the Mac OSX?

I want to get the list of w开发者_开发问答indow titles of the currently running applications.

On windows I have EnumWndProc and GetWindowText.

On Linux I have XGetWindowProperty and XFetchName.

What is the Native Mac equivalent?


A few potentially useful references:

  • NSWindowList()
  • NSWorkspace -launchedApplications and +runningApplications
  • CGWindowListCreate() and CGWindowListCopyWindowInfo() (requires 10.5)
  • CGSGetWindowProperty()

CGSGetWindowProperty is not officially documented, but I believe you can use it with the an item of NSWindowList() as follows (completely untested):

OSErr err;
CGSValue titleValue;
char *title;
CGSConnection connection = _CGSDefaultConnection();
int windowCount, *windows, i;

NSCountWindows(&windowCount);
windows = malloc(windowCount * sizeof(*windows));
if (windows) {
    NSWindowList(windowCount, windows);
    for (i=0; i < windowCount; ++i) {
        err = CGSGetWindowProperty(connection, windows[i], 
                    CGSCreateCStringNoCopy("kCGSWindowTitle"), 
                    &titleValue);
        title = CGSCStringValue(titleValue);
    }
    free(windows);
}

In AppleScript, it's really easy:

tell application "System Events" to get the title of every window of every process

You can call applescript from within an application using NSAppleScript or use appscript as an ObjC-AppleScript bridge. With Leopard, you can use the Scripting Bridge (more untested code):

SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:@"com.apple.systemevents"];
SBElementArray *processes = [systemEvents processes];
for (SystemEventsProcess* process in processes) {
    NSArray *titles = [[process windows] arrayByApplyingSelector:@selector(title)];
}

You could even try it in one long call, if you don't care about readability.

SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:@"com.apple.systemevents"];
NSArray *titles = [[[systemEvents processes] 
                     arrayByApplyingSelector:@selector(windows)] 
               arrayByApplyingSelector:@selector(arrayByApplyingSelector:) 
               withObject:@selector(title)];

The compiler will complain that @selector(title) is the wrong type, but it should work. Hand roll some delegation and you could turn the call into [[[systemEvents processes] windows] title].


The CGSPrivate.h header that's floating around isn't directly compatible with OS X 10.8 in that CGSGetWindowProperty() no longer exists (well, it does, but you can't link to it anymore). So add these two lines to the CGSPrivate.h file -- I went ahead and figured this out myself after many hours searching Google -- to get it to work:

extern CGSConnection CGSDefaultConnectionForThread(void);
extern CGError CGSCopyWindowProperty(const CGSConnection cid, NSInteger wid, CFStringRef key, CFStringRef *output);

Adapting outis's code, here's a way of iterating through each window title. I have tested this with clang 4.2 on Mountain Lion:

CFStringRef titleValue;
CGSConnection connection = CGSDefaultConnectionForThread();
NSInteger windowCount, *windows;

NSCountWindows(&windowCount);
windows = (NSInteger*) malloc(windowCount * sizeof(NSInteger));
if (windows) {
    NSWindowList(windowCount, windows);
    for (int i = 0; i < windowCount; ++i)
    {
        CGSCopyWindowProperty(connection, windows[i], CFSTR("kCGSWindowTitle"), &titleValue);

        if(!titleValue) //Not every window has a title
            continue;

        //Do something with titleValue here
    }
    free(windows);
}

Some other stuff I found out includes the following:

  1. No window title exceeds 127 bytes.
  2. Window titles are encoded with kCFStringEncodingMacRoman

So, if you want it as a C-string, write something like this:

char *cTitle[127] = {0};
CFStringGetCString(titleValue,cTitle,127,kCFStringEncodingMacRoman);

Personally, I'd recommend doing it this way since the Accessibility API is a total pain and requires extra permissions.

Hope this helps someone! Cheers!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜