1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ui/base/cocoa/tracking_area.h"
7 #include "base/logging.h"
9 // NSTrackingArea does not retain its |owner| so CrTrackingArea wraps the real
10 // owner in this proxy, which can stop forwarding messages to the owner when
11 // it is no longer |alive_|.
12 @interface CrTrackingAreaOwnerProxy : NSObject {
14 // Whether or not the owner is "alive" and should forward calls to the real
18 // The real object for which this is a proxy. Weak.
21 // The Class of |owner_|. When the actual object is no longer alive (and could
22 // be zombie), this allows for introspection.
25 @property(nonatomic, assign) BOOL alive;
26 - (instancetype)initWithOwner:(id)owner;
29 @implementation CrTrackingAreaOwnerProxy
31 @synthesize alive = alive_;
33 - (instancetype)initWithOwner:(id)owner {
34 if ((self = [super init])) {
37 ownerClass_ = [owner class];
42 - (void)forwardInvocation:(NSInvocation*)invocation {
45 [invocation invokeWithTarget:owner_];
48 - (NSMethodSignature*)methodSignatureForSelector:(SEL)sel {
49 // This can be called if |owner_| is not |alive_|, so use the Class to
50 // generate the signature. |-forwardInvocation:| will block the actual call.
51 return [ownerClass_ instanceMethodSignatureForSelector:sel];
54 - (BOOL)respondsToSelector:(SEL)aSelector {
55 return [ownerClass_ instancesRespondToSelector:aSelector];
60 // Private Interface ///////////////////////////////////////////////////////////
62 @interface CrTrackingArea (Private)
63 - (void)windowWillClose:(NSNotification*)notif;
66 ////////////////////////////////////////////////////////////////////////////////
68 @implementation CrTrackingArea
70 - (instancetype)initWithRect:(NSRect)rect
71 options:(NSTrackingAreaOptions)options
73 userInfo:(NSDictionary*)userInfo{
74 base::scoped_nsobject<CrTrackingAreaOwnerProxy> ownerProxy(
75 [[CrTrackingAreaOwnerProxy alloc] initWithOwner:owner]);
76 if ((self = [super initWithRect:rect
78 owner:ownerProxy.get()
79 userInfo:userInfo])) {
80 ownerProxy_.swap(ownerProxy);
87 [[NSNotificationCenter defaultCenter] removeObserver:self];
92 [ownerProxy_ setAlive:NO];
95 - (void)clearOwnerWhenWindowWillClose:(NSWindow*)window {
97 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
98 [center addObserver:self
99 selector:@selector(windowWillClose:)
100 name:NSWindowWillCloseNotification
104 - (void)windowWillClose:(NSNotification*)notif {
110 // Scoper //////////////////////////////////////////////////////////////////////
114 ScopedCrTrackingArea::ScopedCrTrackingArea(CrTrackingArea* tracking_area)
115 : tracking_area_(tracking_area) {
118 ScopedCrTrackingArea::~ScopedCrTrackingArea() {
119 [tracking_area_ clearOwner];
122 void ScopedCrTrackingArea::reset(CrTrackingArea* tracking_area) {
123 tracking_area_.reset(tracking_area);
126 CrTrackingArea* ScopedCrTrackingArea::get() const {
127 return tracking_area_.get();