Skip to content
This repository has been archived by the owner on May 19, 2018. It is now read-only.

Commit

Permalink
Merge pull request #19 from numist/numist/element-delegate
Browse files Browse the repository at this point in the history
RFC: Initial implementation of HAXElement delegate support.
  • Loading branch information
robrix committed Jul 2, 2013
2 parents 10587af + 0c31a4b commit eeb7e10
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Classes/HAXElement.h
Expand Up @@ -4,6 +4,13 @@

#import <Foundation/Foundation.h>

@protocol HAXElementDelegate;

@interface HAXElement : NSObject
@property (nonatomic, weak) id<HAXElementDelegate> delegate;
@end

@protocol HAXElementDelegate <NSObject>
@optional
- (void)elementWasDestroyed:(HAXElement *)element;
@end
58 changes: 58 additions & 0 deletions Classes/HAXElement.m
Expand Up @@ -5,6 +5,7 @@
#import "HAXElement+Protected.h"

@interface HAXElement ()
@property (nonatomic, strong) AXObserverRef observer __attribute__((NSObject));
@property (nonatomic, assign) AXUIElementRef _elementRef;
@end

Expand All @@ -20,6 +21,7 @@ +(instancetype)elementWithElementRef:(AXUIElementRef)elementRef {
-(instancetype)initWithElementRef:(AXUIElementRef)elementRef {
if((self = [super init])) {
_elementRef = CFRetain(elementRef);
[self addAXObserver];
}
return self;
}
Expand All @@ -29,6 +31,9 @@ -(void)dealloc {
CFRelease(_elementRef);
_elementRef = NULL;
}
if (_observer) {
[self removeAXObserver];
}
}


Expand Down Expand Up @@ -91,4 +96,57 @@ -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error
return result;
}


- (void)addAXObserver
{
AXObserverRef observer;
AXError err;
pid_t pid;

err = AXUIElementGetPid(self.elementRef, &pid);
if (err != kAXErrorSuccess) { return; }

err = AXObserverCreate(pid, axCallback, &observer);
if (err != kAXErrorSuccess) { return; }

err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self));
if (err != kAXErrorSuccess) {
CFRelease(observer);
observer = NULL;
return;
}

CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode);

self.observer = observer;
CFRelease(observer);
}

static void axCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *refcon) {
[(__bridge HAXElement *)refcon didObserveNotification:(__bridge NSString *)notification];
}

- (void)didObserveNotification:(NSString *)notification
{
id<HAXElementDelegate> delegate = self.delegate;

if ([notification isEqualToString:(__bridge NSString *)kAXUIElementDestroyedNotification] && [delegate respondsToSelector:@selector(elementWasDestroyed:)]) {
[delegate elementWasDestroyed:self];
}
}

- (void)removeAXObserver
{
if (!self.observer) { return; }

(void)AXObserverRemoveNotification(self.observer, self.elementRef, kAXUIElementDestroyedNotification);

CFRunLoopSourceRef observerRunLoopSource = AXObserverGetRunLoopSource(self.observer);
if (observerRunLoopSource) {
CFRunLoopRemoveSource([[NSRunLoop mainRunLoop] getCFRunLoop], observerRunLoopSource, kCFRunLoopDefaultMode);
}

self.observer = NULL;
}

@end

0 comments on commit eeb7e10

Please sign in to comment.