Я хочу получить список названий окон для запущенных приложений.
В окнах есть EnumWndProc и GetWindowText.
В Linux у меня есть XGetWindowProperty и XFetchName.
Что такое собственный Mac-эквивалент?
Я хочу получить список названий окон для запущенных приложений.
В окнах есть EnumWndProc и GetWindowText.
В Linux у меня есть XGetWindowProperty и XFetchName.
Что такое собственный Mac-эквивалент?
Несколько полезных ссылок:
NSWindowList()
-launchedApplications
и +runningApplications
CGWindowListCreate()
и CGWindowListCopyWindowInfo()
(требуется 10.5)CGSGetWindowProperty()
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
Вы можете вызвать applescript из приложения, используя 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]
.
Заголовок 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);
Адаптация внешнего кода, вот способ повторения каждого заголовка окна. Я проверил это с 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);
}
Некоторые другие вещи, которые я обнаружил, включают следующее:
Итак, если вы хотите, чтобы это как C-строка, напишите что-нибудь вроде этого:
char *cTitle[127] = {0};
CFStringGetCString(titleValue,cTitle,127,kCFStringEncodingMacRoman);
Лично я бы рекомендовал сделать это таким образом, так как API Accessibility является полной болью и требует дополнительных разрешений.
Надеюсь, это поможет кому-то! Ура!