==
сравнивает ссылки на объекты в Java и не является исключением для объектов String
.
Для сравнения фактического содержимого объектов (в том числе String
) необходимо использовать equals
.
Если сравнение двух объектов String
с использованием ==
оказывается true
, это связано с тем, что объекты String
были интернированы, а виртуальная машина Java имеет несколько ссылки указывают на тот же экземпляр String
. Не следует ожидать сравнения одного объекта String
, содержащего то же содержимое, что и другой объект String
, используя ==
для оценки как true
.
Вам нужно будет использовать API специальных возможностей, которые представляют собой простой C, расположенный внутри инфраструктуры ApplicationServices. Например:
Сначала вы создаете объект приложения:
AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );
Затем вы получаете окно из этого. Вы можете запросить список окон и перечислить, или вы можете получить самое переднее окно (посмотрите в AXAttributeConstants.h все имена атрибутов, которые вы бы использовали).
AXUIElementRef frontWindow = NULL;
AXError err = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, &frontWindow );
if ( err != kAXErrorSuccess )
// it failed -- maybe no main window (yet)
Теперь вы можете запросить уведомление через функцию обратного вызова C, когда свойство это окно меняется. Это четырехэтапный процесс:
Сначала вам понадобится функция обратного вызова для получения уведомлений:
void MyAXObserverCallback( AXObserverRef observer, AXUIElementRef element,
CFStringRef notificationName, void * contextData )
{
// handle the notification appropriately
// when using ObjC, your contextData might be an object, therefore you can do:
SomeObject * obj = (SomeObject *) contextData;
// now do something with obj
}
Затем вам понадобится AXObserverRef, который управляет процедурой обратного вызова. Для этого требуется тот же идентификатор процесса, который вы использовали для создания элемента 'app' выше:
AXObserverRef observer = NULL;
AXError err = AXObserverCreate( applicationProcessID, MyObserverCallback, &observer );
if ( err != kAXErrorSuccess )
// handle the error
После получения вашего наблюдателя следующим шагом будет запрос уведомления об определенных вещах. См. Полный список в AXNotificationConstants.h, но для изменений окна вам, вероятно, понадобятся только эти два:
AXObserverAddNotification( observer, frontWindow, kAXMovedNotification, self );
AXObserverAddNotification( observer, frontWindow, kAXResizedNotification, self );
Обратите внимание, что последний параметр здесь передает предполагаемый объект «self» в качестве contextData. Это не сохраняется, поэтому важно вызвать AXObserverRemoveNotification
, когда этот объект исчезнет.
Получив наблюдателя и добавив запросы на уведомление, вы теперь хотите прикрепить наблюдателя к циклу выполнения, чтобы вас можно было отправить эти уведомления асинхронно (или вообще не используются):
CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop],
AXObserverGetRunLoopSource(observer),
kCFRunLoopDefaultMode );
AXUIElementRef
являются объектами в стиле CoreFoundation, поэтому вам нужно использовать CFRelease ()
для их аккуратного удаления. Например, для обеспечения чистоты можно использовать CFRelease (app)
после получения элемента frontWindow, поскольку приложение больше не понадобится.
Примечание о сборке мусора: чтобы сохранить AXUIElementRef в качестве переменной-члена, объявите ее следующим образом:
__strong AXUIElementRef frontWindow;
Это указывает сборщику мусора отслеживать эту ссылку на него. При назначении для совместимости с GC и не-GC используйте это:
frontWindow = (AXUIElementRef) CFMakeCollectable( CFRetain(theElement) );
Дальнейшие исследования показали "Quartz Display Services"
Интересная функция для моих нужд - CGRegisterScreenRefreshCallback.