info_bubble_window.mm revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// Use of this source code is governed by a BSD-style license that can be 3afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// found in the LICENSE file. 4afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 5afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#import "chrome/browser/ui/cocoa/info_bubble_window.h" 6afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 7afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "base/basictypes.h" 8afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "base/logging.h" 9afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "base/mac/scoped_nsobject.h" 10afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "chrome/browser/chrome_notification_types.h" 11afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "content/public/browser/notification_observer.h" 12afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "content/public/browser/notification_registrar.h" 13afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#include "content/public/browser/notification_service.h" 14afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" 15afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 16afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velunamespace { 17afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Veluconst CGFloat kOrderInSlideOffset = 10; 18afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Veluconst NSTimeInterval kOrderInAnimationDuration = 0.075; 19afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Veluconst NSTimeInterval kOrderOutAnimationDuration = 0.15; 20afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// The minimum representable time interval. This can be used as the value 21afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// passed to +[NSAnimationContext setDuration:] to stop an in-progress 22afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// animation as quickly as possible. 23afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Veluconst NSTimeInterval kMinimumTimeInterval = 24afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu std::numeric_limits<NSTimeInterval>::min(); 25afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} // namespace 26afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 27afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu@interface InfoBubbleWindow (Private) 28afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)appIsTerminating; 29afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)finishCloseAfterAnimation; 3060238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu@end 31afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 3276c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu// A helper class to proxy app notifications to the window. 33a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Veluclass AppNotificationBridge : public content::NotificationObserver { 34a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu public: 357d1ca6cfa8c1440ddc095faf7f4e6c8716629838Erwan Velu explicit AppNotificationBridge(InfoBubbleWindow* owner) : owner_(owner) { 36afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, 37afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu content::NotificationService::AllSources()); 38afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu } 39afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 40afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Overridden from content::NotificationObserver. 41afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu virtual void Observe( 4276c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu int type, 43e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu const content::NotificationSource& source, 44afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu const content::NotificationDetails& details) OVERRIDE { 45e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu switch (type) { 46afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu case chrome::NOTIFICATION_APP_TERMINATING: 47afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [owner_ appIsTerminating]; 48e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu break; 49afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu default: 50afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu NOTREACHED() << L"Unexpected notification"; 51e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu } 527d1ca6cfa8c1440ddc095faf7f4e6c8716629838Erwan Velu } 537d1ca6cfa8c1440ddc095faf7f4e6c8716629838Erwan Velu 54afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu private: 55afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // The object we need to inform when we get a notification. Weak. Owns us. 56afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu InfoBubbleWindow* owner_; 57e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu 5872fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu // Used for registering to receive notifications and automatic clean up. 59e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu content::NotificationRegistrar registrar_; 60afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 61afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu DISALLOW_COPY_AND_ASSIGN(AppNotificationBridge); 62e1c6f2e1ed79734328949dc91aa7ce84281e8112Erwan Velu}; 63afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 6460238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu// A delegate object for watching the alphaValue animation on InfoBubbleWindows. 65a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu// An InfoBubbleWindow instance cannot be the delegate for its own animation 66a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu// because CAAnimations retain their delegates, and since the InfoBubbleWindow 67a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu// retains its animations a retain loop would be formed. 68ca14375039856a8cb189a19c3381d88fe046d13dErwan Velu@interface InfoBubbleWindowCloser : NSObject { 69ca14375039856a8cb189a19c3381d88fe046d13dErwan Velu @private 70afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu InfoBubbleWindow* window_; // Weak. Window to close. 71afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 72afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (id)initWithWindow:(InfoBubbleWindow*)window; 73a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu@end 74afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 75afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu@implementation InfoBubbleWindowCloser 7660238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu 77afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (id)initWithWindow:(InfoBubbleWindow*)window { 7860238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu if ((self = [super init])) { 79afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu window_ = window; 8060238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu } 81afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return self; 8260238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu} 83afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 8460238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu// Callback for the alpha animation. Closes window_ if appropriate. 85afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag { 8660238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu // When alpha reaches zero, close window_. 87afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if ([window_ alphaValue] == 0.0) { 88afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [window_ finishCloseAfterAnimation]; 8960238f0e7c8bb689f31e3871a661741f2c5fd583Erwan Velu } 90afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 91afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 92afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu@end 93afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 94fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu 95fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu@implementation InfoBubbleWindow 967d1ca6cfa8c1440ddc095faf7f4e6c8716629838Erwan Velu 9772fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu@synthesize allowedAnimations = allowedAnimations_; 98afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu@synthesize canBecomeKeyWindow = canBecomeKeyWindow_; 9972fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu 10072fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu- (id)initWithContentRect:(NSRect)contentRect 10172fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu styleMask:(NSUInteger)aStyle 102d1415111eebe7a95d8de1af1ec61e80f9d534552Erwan Velu backing:(NSBackingStoreType)bufferingType 103afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu defer:(BOOL)flag { 10472fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu if ((self = [super initWithContentRect:contentRect 10572fe3ef10c1911b6f9ec84af99ba6f97112e216bErwan Velu styleMask:NSBorderlessWindowMask 10676c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu backing:bufferingType 10776c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu defer:flag])) { 10876c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu [self setBackgroundColor:[NSColor clearColor]]; 10976c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu [self setExcludedFromWindowsMenu:YES]; 11076c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu [self setOpaque:NO]; 111fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu [self setHasShadow:YES]; 11276c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu canBecomeKeyWindow_ = YES; 113fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu allowedAnimations_ = info_bubble::kAnimateOrderIn | 114fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu info_bubble::kAnimateOrderOut; 115fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu notificationBridge_.reset(new AppNotificationBridge(self)); 116fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu 117fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu // Start invisible. Will be made visible when ordered front. 118fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu [self setAlphaValue:0.0]; 119fdc0f3b646e417497849d4398029f780b0e5262fErwan Velu 120afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Set up alphaValue animation so that self is delegate for the animation. 121afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Setting up the delegate is required so that the 122afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // animationDidStop:finished: callback can be handled. 123afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Notice that only the alphaValue Animation is replaced in case 124afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // superclasses set up animations. 125afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu CAAnimation* alphaAnimation = [CABasicAnimation animation]; 126afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu base::scoped_nsobject<InfoBubbleWindowCloser> delegate( 127afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [[InfoBubbleWindowCloser alloc] initWithWindow:self]); 128afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [alphaAnimation setDelegate:delegate]; 129afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu NSMutableDictionary* animations = 130a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [NSMutableDictionary dictionaryWithDictionary:[self animations]]; 131a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [animations setObject:alphaAnimation forKey:@"alphaValue"]; 132afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [self setAnimations:animations]; 133afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu } 134afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return self; 135afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 136afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 137afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// According to 138afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953, 139afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// NSBorderlessWindowMask windows cannot become key or main. In this 140afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// case, this is not necessarily a desired behavior. As an example, the 141afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// bubble could have buttons. 142afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (BOOL)canBecomeKeyWindow { 143afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return canBecomeKeyWindow_; 144afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 145afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 146afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// Lets the traffic light buttons on the browser window keep their "active" 147afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// state while an info bubble is open. Only has an effect on 10.7. 148afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (BOOL)_sharesParentKeyState { 149afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return YES; 150afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 151afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 152afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)close { 153afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Block the window from receiving events while it fades out. 154afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu closing_ = YES; 155afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 156afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if ((allowedAnimations_ & info_bubble::kAnimateOrderOut) == 0) { 157afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [self finishCloseAfterAnimation]; 158afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu } else { 159afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Apply animations to hide self. 160afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [NSAnimationContext beginGrouping]; 161afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [[NSAnimationContext currentContext] 162afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu gtm_setDuration:kOrderOutAnimationDuration 163a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu eventMask:NSLeftMouseUpMask]; 164a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [[self animator] setAlphaValue:0.0]; 165afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [NSAnimationContext endGrouping]; 166afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu } 167afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 168afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 169afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// If the app is terminating but the window is still fading out, cancel the 170afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// animation and close the window to prevent it from leaking. 171afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// See http://crbug.com/37717 172afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)appIsTerminating { 173afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if ((allowedAnimations_ & info_bubble::kAnimateOrderOut) == 0) 174afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return; // The close has already happened with no Core Animation. 175afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 176afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Cancel the current animation so that it closes immediately, triggering 177afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // |finishCloseAfterAnimation|. 178afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [NSAnimationContext beginGrouping]; 179afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval]; 180afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [[self animator] setAlphaValue:0.0]; 181afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [NSAnimationContext endGrouping]; 182afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 183afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 184afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// Called by InfoBubbleWindowCloser when the window is to be really closed 185afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// after the fading animation is complete. 186afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)finishCloseAfterAnimation { 187afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if (closing_) 188afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [super close]; 189afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 190afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 191afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// Adds animation for info bubbles being ordered to the front. 192afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)orderWindow:(NSWindowOrderingMode)orderingMode 193afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu relativeTo:(NSInteger)otherWindowNumber { 194ca14375039856a8cb189a19c3381d88fe046d13dErwan Velu // According to the documentation '0' is the otherWindowNumber when the window 195afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // is ordered front. 196afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if (orderingMode == NSWindowAbove && otherWindowNumber == 0) { 197afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Order self appropriately assuming that its alpha is zero as set up 198afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // in the designated initializer. 199afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [super orderWindow:orderingMode relativeTo:otherWindowNumber]; 200afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 201afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Set up frame so it can be adjust down by a few pixels. 202afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu NSRect frame = [self frame]; 20376c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu NSPoint newOrigin = frame.origin; 20476c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu newOrigin.y += kOrderInSlideOffset; 20576c7c63e131a5f0068932c78b57eef51bc691810Erwan Velu [self setFrameOrigin:newOrigin]; 206afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 207afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // Apply animations to show and move self. 208afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [NSAnimationContext beginGrouping]; 209afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu // The star currently triggers on mouse down, not mouse up. 210afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu NSTimeInterval duration = 211a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu (allowedAnimations_ & info_bubble::kAnimateOrderIn) 212a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu ? kOrderInAnimationDuration : kMinimumTimeInterval; 213a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [[NSAnimationContext currentContext] 214a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu gtm_setDuration:duration 215a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu eventMask:NSLeftMouseUpMask | NSLeftMouseDownMask]; 216a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [[self animator] setAlphaValue:1.0]; 217a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [[self animator] setFrame:frame display:YES]; 218a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [NSAnimationContext endGrouping]; 219a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu } else { 220a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu [super orderWindow:orderingMode relativeTo:otherWindowNumber]; 221a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu } 222a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu} 223a74198375fe2120fa670e2164cc5b92a06c7dbf0Erwan Velu 224afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// If the window is currently animating a close, block all UI events to the 225afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu// window. 226afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (void)sendEvent:(NSEvent*)theEvent { 227afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu if (!closing_) 228afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu [super sendEvent:theEvent]; 229afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 230afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 231afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu- (BOOL)isClosing { 232afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu return closing_; 233afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu} 234afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu 235afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu@end 236afbbd646716a9e046bd6805f17214689d15a6ba6Erwan Velu