diff options
Diffstat (limited to 'chrome/browser/cocoa/popup_blocked_animation_mac.mm')
-rw-r--r-- | chrome/browser/cocoa/popup_blocked_animation_mac.mm | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/popup_blocked_animation_mac.mm b/chrome/browser/cocoa/popup_blocked_animation_mac.mm new file mode 100644 index 0000000..cee6812 --- /dev/null +++ b/chrome/browser/cocoa/popup_blocked_animation_mac.mm @@ -0,0 +1,160 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/popup_blocked_animation.h" + +#import <Cocoa/Cocoa.h> +#import <QuartzCore/QuartzCore.h> + +#import "base/nsimage_cache_mac.h" +#import "chrome/browser/cocoa/animatable_image.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" + +class PopupBlockedAnimationObserver; + +// A class for managing the Core Animation popup blocked animation. +@interface PopupBlockedAnimationMac : NSObject { + @private + // The observer for the TabContents we are drawing on. + scoped_ptr<PopupBlockedAnimationObserver> observer_; + AnimatableImage* animation_; +}; + +// Called by our the Observer if the tab is hidden or closed. +- (void)animationComplete; + +@end + +// A helper class to monitor tab hidden and closed notifications. If we receive +// such a notification, we stop the animation. +class PopupBlockedAnimationObserver : public NotificationObserver { + public: + PopupBlockedAnimationObserver(PopupBlockedAnimationMac* owner, + TabContents* tab_contents) + : owner_(owner), + tab_contents_(tab_contents) { + registrar_.Add(this, + NotificationType::TAB_CONTENTS_HIDDEN, + Source<TabContents>(tab_contents_)); + registrar_.Add(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_contents_)); + } + + // Runs when a tab is hidden or destroyed. Let our owner know we should end + // the animation. + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + // This ends up deleting us. + [owner_ animationComplete]; + } + + private: + // The object we need to inform when we get a notification. Weak. + PopupBlockedAnimationMac* owner_; + + // The tab we are observing. Weak. + TabContents* tab_contents_; + + // Used for registering to receive notifications and automatic clean up. + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(PopupBlockedAnimationObserver); +}; + +@implementation PopupBlockedAnimationMac + +- (id)initWithTabContents:(TabContents*)tabContents { + if ((self = [super init])) { + NSImage* image = nsimage_cache::ImageNamed(@"popup_window_animation.pdf"); + CGFloat imageWidth = [image size].width; + CGFloat imageHeight = [image size].height; + + NSView* tabContentsView = tabContents->GetNativeView(); + NSWindow* parentWindow = [tabContentsView window]; + if (!parentWindow) { + // The tab is no longer frontmost. + [self release]; + return nil; + } + + NSRect windowFrame = [parentWindow frame]; + + // Sanity check the size in case there's no room to display the animation. + if (imageWidth >= NSWidth(windowFrame) || + imageHeight >= NSHeight(windowFrame)) { + [self release]; + return nil; + } + + // Create the animation window to be the top-right quadrant of the window. + // The animation travels from the center of the window to the blocked + // content section of the Omnibox. This will release itself. + NSRect animationFrame = windowFrame; + CGFloat dX = NSWidth(animationFrame) / 2 - imageWidth / 2; + CGFloat dY = NSHeight(animationFrame) / 2 - imageHeight / 2; + animationFrame.origin.x += dX; + animationFrame.origin.y += dY; + animationFrame.size.width -= dX; + animationFrame.size.height -= dY; + animation_ = [[AnimatableImage alloc] initWithImage:image + animationFrame:animationFrame]; + [parentWindow addChildWindow:animation_ ordered:NSWindowAbove]; + + // Start the animation from the center of the window. + NSRect contentFrame = [[animation_ contentView] frame]; + [animation_ setStartFrame:CGRectMake(0, + imageHeight / 2, + imageWidth, + imageHeight)]; + + // Set the end frame to be small (a la the actual blocked icon) and inset + // slightly to the Omnibox. While the geometry won't align perfectly, it's + // close enough for the user to take note of the new icon. These numbers + // come from measuring the Omnibox without any page actions. + [animation_ setEndFrame:CGRectMake(animationFrame.size.width - 115, + animationFrame.size.height - 50, + 16, 16)]; + [animation_ setStartOpacity:1.0]; + [animation_ setEndOpacity:0.2]; + [animation_ setDuration:0.7]; + + observer_.reset(new PopupBlockedAnimationObserver(self, tabContents)); + + // When the window is about to close, release this object and remove the + // animation from the parent window. + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:animation_]; + [animation_ startAnimation]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)windowWillClose:(NSNotification*)notification { + DCHECK([[notification object] isEqual:animation_]); + [self animationComplete]; +} + +- (void)animationComplete { + [[animation_ parentWindow] removeChildWindow:animation_]; + [self release]; +} + +@end + +void PopupBlockedAnimation::Show(TabContents* tab_contents) { + // The object will clean up itself at the end of the animation. + [[PopupBlockedAnimationMac alloc] initWithTabContents:tab_contents]; +} |