Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Unified Diff: chrome/browser/ui/cocoa/status_bubble_mac.mm

Issue 164333006: Fix the Mac status bubble. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: nits Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/cocoa/status_bubble_mac.h ('k') | chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/cocoa/status_bubble_mac.mm
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
index c772f4818d909eebbf3d382e9dd1fef493a75c20..ddf00ace198ee221a7d3f76e1661053113d40bcc 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -9,6 +9,8 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/mac/mac_util.h"
+#include "base/mac/scoped_block.h"
+#include "base/mac/sdk_forward_declarations.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
@@ -38,9 +40,6 @@ const int kMousePadding = 20;
const int kTextPadding = 3;
-// The animation key used for fade-in and fade-out transitions.
-NSString* const kFadeAnimationKey = @"alphaValue";
-
// The status bubble's maximum opacity, when fully faded in.
const CGFloat kBubbleOpacity = 1.0;
@@ -65,15 +64,10 @@ const CGFloat kExpansionDurationSeconds = 0.125;
@interface StatusBubbleAnimationDelegate : NSObject {
@private
- StatusBubbleMac* statusBubble_; // weak; owns us indirectly
+ base::mac::ScopedBlock<void (^)(void)> completionHandler_;
}
-- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble;
-
-// Invalidates this object so that no further calls will be made to
-// statusBubble_. This should be called when statusBubble_ is released, to
-// prevent attempts to call into the released object.
-- (void)invalidate;
+- (id)initWithCompletionHandler:(void (^)(void))completionHandler;
// CAAnimation delegate method
- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished;
@@ -81,21 +75,69 @@ const CGFloat kExpansionDurationSeconds = 0.125;
@implementation StatusBubbleAnimationDelegate
-- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble {
+- (id)initWithCompletionHandler:(void (^)(void))completionHandler {
if ((self = [super init])) {
- statusBubble_ = statusBubble;
+ completionHandler_.reset(completionHandler, base::scoped_policy::RETAIN);
}
return self;
}
-- (void)invalidate {
- statusBubble_ = NULL;
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
+ completionHandler_.get()();
}
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
- if (statusBubble_)
- statusBubble_->AnimationDidStop(animation, finished);
+@end
+
+@interface StatusBubbleWindow : NSWindow {
+ @private
+ void (^completionHandler_)(void);
+}
+
+- (id)animationForKey:(NSString *)key;
+- (void)runAnimationGroup:(void (^)(NSAnimationContext *context))changes
+ completionHandler:(void (^)(void))completionHandler;
+@end
+
+@implementation StatusBubbleWindow
+
+- (id)animationForKey:(NSString *)key {
+ CAAnimation* animation = [super animationForKey:key];
+ // If completionHandler_ isn't nil, then this is the first of (potentially)
+ // multiple animations in a grouping; give it the completion handler. If
+ // completionHandler_ is nil, then some other animation was tagged with the
+ // completion handler.
+ if (completionHandler_) {
+ DCHECK(![NSAnimationContext respondsToSelector:
+ @selector(runAnimationGroup:completionHandler:)]);
+ StatusBubbleAnimationDelegate* animation_delegate =
+ [[StatusBubbleAnimationDelegate alloc]
+ initWithCompletionHandler:completionHandler_];
+ [animation setDelegate:animation_delegate];
+ completionHandler_ = nil;
+ }
+ return animation;
+}
+
+- (void)runAnimationGroup:(void (^)(NSAnimationContext *context))changes
+ completionHandler:(void (^)(void))completionHandler {
+ if ([NSAnimationContext respondsToSelector:
+ @selector(runAnimationGroup:completionHandler:)]) {
+ [NSAnimationContext runAnimationGroup:changes
+ completionHandler:completionHandler];
+ } else {
+ // Mac OS 10.6 does not have completion handler callbacks at the Cocoa
+ // level, only at the CoreAnimation level. So intercept calls made to
+ // -animationForKey: and tag one of the animations with a delegate that will
+ // execute the completion handler.
+ completionHandler_ = completionHandler;
+ [NSAnimationContext beginGrouping];
+ changes([NSAnimationContext currentContext]);
+ // At this point, -animationForKey should have been called by CoreAnimation
+ // to set up the animation to run. Verify this.
+ DCHECK(completionHandler_ == nil);
+ [NSAnimationContext endGrouping];
+ }
}
@end
@@ -103,6 +145,7 @@ const CGFloat kExpansionDurationSeconds = 0.125;
StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
: timer_factory_(this),
expand_timer_factory_(this),
+ completion_handler_factory_(this),
parent_(parent),
delegate_(delegate),
window_(nil),
@@ -120,7 +163,7 @@ StatusBubbleMac::~StatusBubbleMac() {
Hide();
- [[[window_ animationForKey:kFadeAnimationKey] delegate] invalidate];
+ completion_handler_factory_.InvalidateWeakPtrs();
Detach();
[window_ release];
window_ = nil;
@@ -237,10 +280,7 @@ void StatusBubbleMac::Hide() {
// An animation is in progress. Cancel it by starting a new animation.
// Use kMinimumTimeInterval to set the opacity as rapidly as possible.
fade_out = true;
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
- [[window_ animator] setAlphaValue:0.0];
- [NSAnimationContext endGrouping];
+ AnimateWindowAlpha(0.0, kMinimumTimeInterval);
}
}
@@ -364,10 +404,11 @@ void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
void StatusBubbleMac::Create() {
DCHECK(!window_);
- window_ = [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES];
+ window_ = [[StatusBubbleWindow alloc]
+ initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
[window_ setMovableByWindowBackground:NO];
[window_ setBackgroundColor:[NSColor clearColor]];
[window_ setLevel:NSNormalWindowLevel];
@@ -388,21 +429,6 @@ void StatusBubbleMac::Create() {
[window_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole
forAttribute:NSAccessibilityRoleAttribute];
- // Set a delegate for the fade-in and fade-out transitions to be notified
- // when fades are complete. The ownership model is for window_ to own
- // animation_dictionary, which owns animation, which owns
- // animation_delegate.
- CAAnimation* animation = [[window_ animationForKey:kFadeAnimationKey] copy];
- [animation autorelease];
- StatusBubbleAnimationDelegate* animation_delegate =
- [[StatusBubbleAnimationDelegate alloc] initWithStatusBubble:this];
- [animation_delegate autorelease];
- [animation setDelegate:animation_delegate];
- NSMutableDictionary* animation_dictionary =
- [NSMutableDictionary dictionaryWithDictionary:[window_ animations]];
- [animation_dictionary setObject:animation forKey:kFadeAnimationKey];
- [window_ setAnimations:animation_dictionary];
-
[view setCornerFlags:kRoundedTopRightCorner];
MouseMoved(gfx::Point(), false);
}
@@ -427,23 +453,17 @@ void StatusBubbleMac::Detach() {
[[window_ contentView] setThemeProvider:nil];
}
-void StatusBubbleMac::AnimationDidStop(CAAnimation* animation, bool finished) {
+void StatusBubbleMac::AnimationDidStop() {
DCHECK([NSThread isMainThread]);
DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut);
DCHECK(is_attached());
- if (finished) {
- // Because of the mechanism used to interrupt animations, this is never
- // actually called with finished set to false. If animations ever become
- // directly interruptible, the check will ensure that state_ remains
- // properly synchronized.
- if (state_ == kBubbleShowingFadeIn) {
- DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity);
- SetState(kBubbleShown);
- } else {
- DCHECK_EQ([[window_ animator] alphaValue], 0.0);
- SetState(kBubbleHidden);
- }
+ if (state_ == kBubbleShowingFadeIn) {
+ DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity);
+ SetState(kBubbleShown);
+ } else {
+ DCHECK_EQ([[window_ animator] alphaValue], 0.0);
+ SetState(kBubbleHidden);
}
}
@@ -506,13 +526,24 @@ void StatusBubbleMac::Fade(bool show) {
if (duration == 0.0)
duration = kMinimumTimeInterval;
- // This will cancel an in-progress transition and replace it with this fade.
- [NSAnimationContext beginGrouping];
- // Don't use the GTM additon for the "Steve" slowdown because this can happen
- // async from user actions and the effects could be a surprise.
- [[NSAnimationContext currentContext] setDuration:duration];
- [[window_ animator] setAlphaValue:opacity];
- [NSAnimationContext endGrouping];
+ // Cancel an in-progress transition and replace it with this fade.
+ AnimateWindowAlpha(opacity, duration);
+}
+
+void StatusBubbleMac::AnimateWindowAlpha(CGFloat alpha,
+ NSTimeInterval duration) {
+ completion_handler_factory_.InvalidateWeakPtrs();
+ base::WeakPtr<StatusBubbleMac> weak_ptr(
+ completion_handler_factory_.GetWeakPtr());
+ [window_
+ runAnimationGroup:^(NSAnimationContext* context) {
+ [context setDuration:duration];
+ [[window_ animator] setAlphaValue:alpha];
+ }
+ completionHandler:^{
+ if (weak_ptr)
+ weak_ptr->AnimationDidStop();
+ }];
}
void StatusBubbleMac::StartTimer(int64 delay_ms) {
« no previous file with comments | « chrome/browser/ui/cocoa/status_bubble_mac.h ('k') | chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698