Как получить список заголовков окон на Mac OSX? - PullRequest
17 голосов
/ 22 октября 2009

Я хочу получить список заголовков окон запущенных в данный момент приложений.

В Windows у меня есть EnumWndProc и GetWindowText.

В Linux у меня есть XGetWindowProperty и XFetchName.

Что такое эквивалент Native Mac?

Ответы [ 2 ]

12 голосов
/ 22 октября 2009

Несколько потенциально полезных ссылок:

CGSGetWindowProperty - это , официально не документированный , но я думаю, вы можете использовать его с элементом NSWindowList() следующим образом (полностью не проверено):

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);
}

В AppleScript это действительно просто:

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

Вы можете вызывать яблочный скрипт из приложения, используя NSAppleScript или использовать appscript в качестве моста ObjC-AppleScript. С Leopard вы можете использовать Scripting Bridge (более непроверенный код):

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

Вы даже можете попробовать его за один длинный звонок, если вам не важна читабельность.

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

Компилятор будет жаловаться, что @selector(title) неправильный тип, но он должен работать. Вручную сверните делегирование, и вы сможете превратить вызов в [[[systemEvents processes] windows] title].

8 голосов
/ 06 марта 2013

Заголовок CGSPrivate.h, который плавает вокруг, не совместим напрямую с OS X 10.8, так как CGSGetWindowProperty () больше не существует (ну, он есть, но вы больше не можете ссылаться на него). Итак, добавьте эти две строки в файл CGSPrivate.h - я решил сам и после многих часов поиска в Google - выяснил, как это работает:

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

Адаптируя код outis, вот способ перебора каждого заголовка окна. Я проверил это с помощью clang 4.2 на 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);
}

Некоторые другие вещи, которые я обнаружил, включают следующее:

  1. Ни один заголовок окна не превышает 127 байт.
  2. Заголовки окон кодируются с помощью kCFStringEncodingMacRoman

Итак, если вы хотите, чтобы это была C-строка, напишите что-то вроде этого:

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

Лично я бы порекомендовал сделать это таким образом, поскольку API-интерфейс Accessibility представляет собой сложную задачу и требует дополнительных разрешений.

Надеюсь, это кому-нибудь поможет! Ура!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...