Chromium Code Reviews| Index: chrome/browser/ui/cocoa/tracking_area.mm |
| diff --git a/chrome/browser/ui/cocoa/tracking_area.mm b/chrome/browser/ui/cocoa/tracking_area.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..92f82ecce350c74f0d4166dbae83991fb528b4f9 |
| --- /dev/null |
| +++ b/chrome/browser/ui/cocoa/tracking_area.mm |
| @@ -0,0 +1,105 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#import "chrome/browser/ui/cocoa/tracking_area.h" |
| + |
| +#include "base/logging.h" |
| + |
| +// NSTrackingArea does not retain its |owner| so CrTrackingArea wraps the real |
| +// owner in this proxy, which can stop forwarding messages to the owner when |
| +// it is no longer |alive_|. |
| +@interface CrTrackingAreaOwnerProxy : NSObject { |
| + @private |
| + // Whether or not the owner is "alive" and should forward calls to the real |
| + // owner object. |
| + BOOL alive_; |
| + |
| + // The real object for which this is a proxy. Weak. |
| + id owner_; |
| + |
| + // The Class of |owner_|. When the actual object is no longer alive (and could |
| + // be zombie), this allows for introspection. |
| + Class ownerClass_; |
| +} |
| +@property(nonatomic, assign) BOOL alive; |
| +- (id)initWithOwner:(id)owner; |
| +@end |
| + |
| +@implementation CrTrackingAreaOwnerProxy |
| + |
| +@synthesize alive = alive_; |
| + |
| +- (id)initWithOwner:(id)owner { |
|
Scott Hess - ex-Googler
2011/02/14 21:13:45
OK, but now you need if ((self = [super init])) {.
|
| + alive_ = YES; |
| + owner_ = owner; |
| + ownerClass_ = [owner class]; |
| + return self; |
| +} |
| + |
| +- (void)forwardInvocation:(NSInvocation*)invocation { |
| + if (!alive_) |
| + return; |
| + [invocation invokeWithTarget:owner_]; |
| +} |
| + |
| +- (NSMethodSignature*)methodSignatureForSelector:(SEL)sel { |
| + // This can be called if |owner_| is not |alive_|, so use the Class to |
| + // generate the signature. |-forwardInvocation:| will block the actual call. |
| + return [ownerClass_ instanceMethodSignatureForSelector:sel]; |
| +} |
| + |
| +- (BOOL)respondsToSelector:(SEL)aSelector { |
| + return [ownerClass_ instancesRespondToSelector:aSelector]; |
| +} |
| + |
| +@end |
| + |
| +// Private Interface /////////////////////////////////////////////////////////// |
| + |
| +@interface CrTrackingArea (Private) |
| +- (void)windowWillClose:(NSNotification*)notif; |
| +@end |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +@implementation CrTrackingArea |
| + |
| +- (id)initWithRect:(NSRect)rect |
| + options:(NSTrackingAreaOptions)options |
| + owner:(id)owner |
| + userInfo:(NSDictionary*)userInfo { |
| + scoped_nsobject<CrTrackingAreaOwnerProxy> ownerProxy( |
| + [[CrTrackingAreaOwnerProxy alloc] initWithOwner:owner]); |
| + if ((self = static_cast<id>([super initWithRect:rect |
| + options:options |
| + owner:ownerProxy.get() |
| + userInfo:userInfo]))) { |
| + ownerProxy_.reset(ownerProxy.release()); |
|
Scott Hess - ex-Googler
2011/02/14 21:13:45
Suggest ownerProxy_.swap(ownerProxy);. I think yo
|
| + } |
| + return self; |
| +} |
| + |
| +- (void)dealloc { |
| + [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| + [super dealloc]; |
| +} |
| + |
| +- (void)clearOwner { |
| + [ownerProxy_ setAlive:NO]; |
| +} |
| + |
| +- (void)clearOwnerWhenWindowWillClose:(NSWindow*)window { |
| + DCHECK(window); |
| + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
| + [center addObserver:self |
| + selector:@selector(windowWillClose:) |
| + name:NSWindowWillCloseNotification |
| + object:window]; |
| +} |
| + |
| +- (void)windowWillClose:(NSNotification*)notif { |
| + [self clearOwner]; |
| +} |
| + |
| +@end |