OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/cocoa/info_bubble_window.h" | 5 #import "chrome/browser/cocoa/info_bubble_window.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/scoped_nsobject.h" | 8 #include "base/scoped_nsobject.h" |
9 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" | 9 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" |
10 | 10 |
11 namespace { | 11 namespace { |
12 const CGFloat kOrderInSlideOffset = 10; | 12 const CGFloat kOrderInSlideOffset = 10; |
13 const NSTimeInterval kOrderInAnimationDuration = 0.2; | 13 const NSTimeInterval kOrderInAnimationDuration = 0.2; |
14 const NSTimeInterval kOrderOutAnimationDuration = 0.15; | 14 const NSTimeInterval kOrderOutAnimationDuration = 0.15; |
| 15 // The minimum representable time interval. This can be used as the value |
| 16 // passed to +[NSAnimationContext setDuration:] to stop an in-progress |
| 17 // animation as quickly as possible. |
| 18 const NSTimeInterval kMinimumTimeInterval = |
| 19 std::numeric_limits<NSTimeInterval>::min(); |
15 } | 20 } |
16 | 21 |
17 @interface InfoBubbleWindow (Private) | 22 @interface InfoBubbleWindow(Private) |
| 23 - (void)appIsTerminating; |
18 - (void)finishCloseAfterAnimation; | 24 - (void)finishCloseAfterAnimation; |
19 @end | 25 @end |
20 | 26 |
21 // A delegate object for watching the alphaValue animation on InfoBubbleWindows. | 27 // A delegate object for watching the alphaValue animation on InfoBubbleWindows. |
22 // An InfoBubbleWindow instance cannot be the delegate for its own animation | 28 // An InfoBubbleWindow instance cannot be the delegate for its own animation |
23 // because CAAnimations retain their delegates, and since the InfoBubbleWindow | 29 // because CAAnimations retain their delegates, and since the InfoBubbleWindow |
24 // retains its animations a retain loop would be formed. | 30 // retains its animations a retain loop would be formed. |
25 @interface InfoBubbleWindowCloser : NSObject { | 31 @interface InfoBubbleWindowCloser : NSObject { |
26 @private | 32 @private |
27 InfoBubbleWindow* window_; // Weak. Window to close. | 33 InfoBubbleWindow* window_; // Weak. Window to close. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 // Notice that only the alphaValue Animation is replaced in case | 82 // Notice that only the alphaValue Animation is replaced in case |
77 // superclasses set up animations. | 83 // superclasses set up animations. |
78 CAAnimation* alphaAnimation = [CABasicAnimation animation]; | 84 CAAnimation* alphaAnimation = [CABasicAnimation animation]; |
79 scoped_nsobject<InfoBubbleWindowCloser> delegate( | 85 scoped_nsobject<InfoBubbleWindowCloser> delegate( |
80 [[InfoBubbleWindowCloser alloc] initWithWindow:self]); | 86 [[InfoBubbleWindowCloser alloc] initWithWindow:self]); |
81 [alphaAnimation setDelegate:delegate]; | 87 [alphaAnimation setDelegate:delegate]; |
82 NSMutableDictionary* animations = | 88 NSMutableDictionary* animations = |
83 [NSMutableDictionary dictionaryWithDictionary:[self animations]]; | 89 [NSMutableDictionary dictionaryWithDictionary:[self animations]]; |
84 [animations setObject:alphaAnimation forKey:@"alphaValue"]; | 90 [animations setObject:alphaAnimation forKey:@"alphaValue"]; |
85 [self setAnimations:animations]; | 91 [self setAnimations:animations]; |
| 92 |
| 93 [[NSNotificationCenter defaultCenter] |
| 94 addObserver:self |
| 95 selector:@selector(appIsTerminating) |
| 96 name:NSApplicationWillTerminateNotification |
| 97 object:[NSApplication sharedApplication]]; |
86 } | 98 } |
87 return self; | 99 return self; |
88 } | 100 } |
89 | 101 |
| 102 - (void)dealloc { |
| 103 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 104 [super dealloc]; |
| 105 } |
| 106 |
90 // According to | 107 // According to |
91 // http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953, | 108 // http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953, |
92 // NSBorderlessWindowMask windows cannot become key or main. In this | 109 // NSBorderlessWindowMask windows cannot become key or main. In this |
93 // case, this is not a desired behavior. As an example, the bubble could have | 110 // case, this is not a desired behavior. As an example, the bubble could have |
94 // buttons. | 111 // buttons. |
95 - (BOOL)canBecomeKeyWindow { | 112 - (BOOL)canBecomeKeyWindow { |
96 return YES; | 113 return YES; |
97 } | 114 } |
98 | 115 |
99 - (void)close { | 116 - (void)close { |
100 // Block the window from receiving events while it fades out. | 117 // Block the window from receiving events while it fades out. |
101 closing_ = YES; | 118 closing_ = YES; |
102 | 119 |
103 if (!delayOnClose_) { | 120 if (!delayOnClose_) { |
104 [self finishCloseAfterAnimation]; | 121 [self finishCloseAfterAnimation]; |
105 } else { | 122 } else { |
106 // Apply animations to hide self. | 123 // Apply animations to hide self. |
107 [NSAnimationContext beginGrouping]; | 124 [NSAnimationContext beginGrouping]; |
108 [[NSAnimationContext currentContext] | 125 [[NSAnimationContext currentContext] |
109 gtm_setDuration:kOrderOutAnimationDuration]; | 126 gtm_setDuration:kOrderOutAnimationDuration]; |
110 [[self animator] setAlphaValue:0.0]; | 127 [[self animator] setAlphaValue:0.0]; |
111 [NSAnimationContext endGrouping]; | 128 [NSAnimationContext endGrouping]; |
112 } | 129 } |
113 } | 130 } |
114 | 131 |
| 132 // If the app is terminating but the window is still fading out, cancel |
| 133 // the animation and close the window to prevent it from leaking. |
| 134 - (void)appIsTerminating { |
| 135 if (!delayOnClose_) |
| 136 return; // The close has already happened with no Core Animation. |
| 137 |
| 138 // Cancel the current animation so that it closes immediately, triggering |
| 139 // |finishCloseAfterAnimation|. |
| 140 [NSAnimationContext beginGrouping]; |
| 141 [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval]; |
| 142 [[self animator] setAlphaValue:0.0]; |
| 143 [NSAnimationContext endGrouping]; |
| 144 } |
| 145 |
115 // Called by InfoBubbleWindowCloser when the window is to be really closed | 146 // Called by InfoBubbleWindowCloser when the window is to be really closed |
116 // after the fading animation is complete. | 147 // after the fading animation is complete. |
117 - (void)finishCloseAfterAnimation { | 148 - (void)finishCloseAfterAnimation { |
118 if (closing_) | 149 if (closing_) |
119 [super close]; | 150 [super close]; |
120 } | 151 } |
121 | 152 |
122 // Adds animation for info bubbles being ordered to the front. | 153 // Adds animation for info bubbles being ordered to the front. |
123 - (void)orderWindow:(NSWindowOrderingMode)orderingMode | 154 - (void)orderWindow:(NSWindowOrderingMode)orderingMode |
124 relativeTo:(NSInteger)otherWindowNumber { | 155 relativeTo:(NSInteger)otherWindowNumber { |
(...skipping 27 matching lines...) Expand all Loading... |
152 - (void)sendEvent:(NSEvent*)theEvent { | 183 - (void)sendEvent:(NSEvent*)theEvent { |
153 if (!closing_) | 184 if (!closing_) |
154 [super sendEvent:theEvent]; | 185 [super sendEvent:theEvent]; |
155 } | 186 } |
156 | 187 |
157 - (BOOL)isClosing { | 188 - (BOOL)isClosing { |
158 return closing_; | 189 return closing_; |
159 } | 190 } |
160 | 191 |
161 @end | 192 @end |
OLD | NEW |