Roll src/third_party/WebKit 4526c29:30f3df0 (svn 190187:190189)
[chromium-blink-merge.git] / ui / base / cocoa / tracking_area.mm
bloba137794858dadde365a481306ab11816f9fcd31a
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 {
13  @private
14   // Whether or not the owner is "alive" and should forward calls to the real
15   // owner object.
16   BOOL alive_;
18   // The real object for which this is a proxy. Weak.
19   id owner_;
21   // The Class of |owner_|. When the actual object is no longer alive (and could
22   // be zombie), this allows for introspection.
23   Class ownerClass_;
25 @property(nonatomic, assign) BOOL alive;
26 - (id)initWithOwner:(id)owner;
27 @end
29 @implementation CrTrackingAreaOwnerProxy
31 @synthesize alive = alive_;
33 - (id)initWithOwner:(id)owner {
34   if ((self = [super init])) {
35     alive_ = YES;
36     owner_ = owner;
37     ownerClass_ = [owner class];
38   }
39   return self;
42 - (void)forwardInvocation:(NSInvocation*)invocation {
43   if (!alive_)
44     return;
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];
58 @end
60 // Private Interface ///////////////////////////////////////////////////////////
62 @interface CrTrackingArea (Private)
63 - (void)windowWillClose:(NSNotification*)notif;
64 @end
66 ////////////////////////////////////////////////////////////////////////////////
68 @implementation CrTrackingArea
70 - (id)initWithRect:(NSRect)rect
71                         options:(NSTrackingAreaOptions)options
72                           owner:(id)owner
73                        userInfo:(NSDictionary*)userInfo {
74   base::scoped_nsobject<CrTrackingAreaOwnerProxy> ownerProxy(
75       [[CrTrackingAreaOwnerProxy alloc] initWithOwner:owner]);
76   if ((self = [super initWithRect:rect
77                           options:options
78                             owner:ownerProxy.get()
79                          userInfo:userInfo])) {
80     ownerProxy_.swap(ownerProxy);
81   }
82   return self;
85 - (void)dealloc {
86   [self clearOwner];
87   [[NSNotificationCenter defaultCenter] removeObserver:self];
88   [super dealloc];
91 - (void)clearOwner {
92   [ownerProxy_ setAlive:NO];
95 - (void)clearOwnerWhenWindowWillClose:(NSWindow*)window {
96   DCHECK(window);
97   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
98   [center addObserver:self
99              selector:@selector(windowWillClose:)
100                  name:NSWindowWillCloseNotification
101                object:window];
104 - (void)windowWillClose:(NSNotification*)notif {
105   [self clearOwner];
108 @end
110 // Scoper //////////////////////////////////////////////////////////////////////
112 namespace ui {
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();
130 }  // namespace ui