| Index: chrome/browser/cocoa/tab_view.mm
|
| ===================================================================
|
| --- chrome/browser/cocoa/tab_view.mm (revision 27606)
|
| +++ chrome/browser/cocoa/tab_view.mm (working copy)
|
| @@ -49,6 +49,8 @@
|
| }
|
|
|
| - (void)dealloc {
|
| + // Cancel any delayed requests that may still be pending (drags or hover).
|
| + [NSObject cancelPreviousPerformRequestsWithTarget:self];
|
| // [self gtm_unregisterForThemeNotifications];
|
| [closeButton_ removeTrackingArea:closeTrackingArea_.get()];
|
| [super dealloc];
|
| @@ -164,6 +166,16 @@
|
| return targets;
|
| }
|
|
|
| +// Call to clear out transient weak references we hold during drags.
|
| +- (void)resetDragControllers {
|
| + draggedController_ = nil;
|
| + dragWindow_ = nil;
|
| + dragOverlay_ = nil;
|
| + sourceController_ = nil;
|
| + sourceWindow_ = nil;
|
| + targetController_ = nil;
|
| +}
|
| +
|
| // Handle clicks and drags in this button. We get here because we have
|
| // overridden acceptsFirstMouse: and the click is within our bounds.
|
| // TODO(pinkerton/alcor): This routine needs *a lot* of work to marry Cole's
|
| @@ -198,6 +210,8 @@
|
| [[controller_ target] performSelector:[controller_ action]
|
| withObject:self];
|
|
|
| + [self resetDragControllers];
|
| +
|
| // Resolve overlay back to original window.
|
| sourceWindow_ = [self window];
|
| if ([sourceWindow_ isKindOfClass:[NSPanel class]]) {
|
| @@ -207,10 +221,6 @@
|
| sourceWindowFrame_ = [sourceWindow_ frame];
|
| sourceTabFrame_ = [self frame];
|
| sourceController_ = [sourceWindow_ windowController];
|
| - draggedController_ = nil;
|
| - dragWindow_ = nil;
|
| - dragOverlay_ = nil;
|
| - targetController_ = nil;
|
| tabWasDragged_ = NO;
|
| tearTime_ = 0.0;
|
| draggingWithinTabStrip_ = YES;
|
| @@ -378,8 +388,18 @@
|
| tearOrigin_ = sourceWindowFrame_.origin;
|
| }
|
|
|
| + DCHECK(draggedController_);
|
| + DCHECK(sourceController_);
|
| +
|
| + // When the user first tears off the window, we want slide the window to
|
| + // the current mouse location (to reduce the jarring appearance). We do this
|
| + // by calling ourselves back with additional mouseDragged calls (not actual
|
| + // events). |tearProgress| is a normalized measure of how far through this
|
| + // tear "animation" (of length kTearDuration) we are and has values [0..1].
|
| + // We use sqrt() so the animation is non-linear (slow down near the end
|
| + // point).
|
| float tearProgress = [NSDate timeIntervalSinceReferenceDate] - tearTime_;
|
| - tearProgress /= kTearDuration;
|
| + tearProgress /= kTearDuration; // Normalize.
|
| tearProgress = sqrtf(MAX(MIN(tearProgress, 1.0), 0.0));
|
|
|
| // Move the dragged window to the right place on the screen.
|
| @@ -389,13 +409,16 @@
|
|
|
| if (tearProgress < 1) {
|
| // If the tear animation is not complete, call back to ourself with the
|
| - // same event to animate even if the mouse isn't moving.
|
| + // same event to animate even if the mouse isn't moving. We need to make
|
| + // sure these get cancelled in mouseUp:.
|
| [NSObject cancelPreviousPerformRequestsWithTarget:self];
|
| [self performSelector:@selector(mouseDragged:)
|
| withObject:theEvent
|
| afterDelay:1.0f/30.0f];
|
|
|
| - origin.x = (1 - tearProgress) * tearOrigin_.x + tearProgress * origin.x;
|
| + // Set the current window origin based on how far we've progressed through
|
| + // the tear animation.
|
| + origin.x = (1 - tearProgress) * tearOrigin_.x + tearProgress * origin.x;
|
| origin.y = (1 - tearProgress) * tearOrigin_.y + tearProgress * origin.y;
|
| }
|
|
|
| @@ -443,18 +466,19 @@
|
| BOOL chromeShouldBeVisible = targetController_ == nil;
|
|
|
| if (chromeIsVisible_ != chromeShouldBeVisible) {
|
| + // TODO(pinkerton): There appears to be a race-condition in CoreAnimation
|
| + // where if we use animators to set the alpha values, we can't guarantee
|
| + // that we cancel them. This has the side effect of sometimes leaving
|
| + // the dragged window translucent or invisible. We should re-visit this,
|
| + // but for now, don't animate the alpha change.
|
| [dragWindow_ setHasShadow:YES];
|
| + [[draggedController_ overlayWindow] setAlphaValue:1.0];
|
| if (targetController_) {
|
| - [NSAnimationContext beginGrouping];
|
| - [[NSAnimationContext currentContext] setDuration:0.00001];
|
| - [[dragWindow_ animator] setAlphaValue:0.0];
|
| - [NSAnimationContext endGrouping];
|
| + [dragWindow_ setAlphaValue:0.0];
|
| [[draggedController_ overlayWindow] setHasShadow:YES];
|
| - [[[draggedController_ overlayWindow] animator] setAlphaValue:1.0];
|
| } else {
|
| - [[draggedController_ overlayWindow] setAlphaValue:1.0];
|
| + [dragWindow_ setAlphaValue:0.5];
|
| [[draggedController_ overlayWindow] setHasShadow:NO];
|
| - [[dragWindow_ animator] setAlphaValue:0.5];
|
| }
|
| chromeIsVisible_ = chromeShouldBeVisible;
|
| }
|
| @@ -468,6 +492,9 @@
|
| if (moveWindowOnDrag_)
|
| return;
|
|
|
| + // Cancel any delayed -mouseDragged: requests that may still be pending.
|
| + [NSObject cancelPreviousPerformRequestsWithTarget:self];
|
| +
|
| // We are now free to re-display the new tab button in the window we're
|
| // dragging. It will show when the next call to -layoutTabs (which happens
|
| // indrectly by several of the calls below, such as removing the placeholder).
|
| @@ -490,7 +517,8 @@
|
| fromController:draggedController_];
|
| [targetController_ showWindow:nil];
|
| } else {
|
| - // Tab dragging did move window only.
|
| + // Only move the window around on screen. Make sure it's set back to
|
| + // normal state (fully opaque, has shadow, has key, etc).
|
| [draggedController_ removeOverlay];
|
| // Don't want to re-show the window if it was closed during the drag.
|
| if ([dragWindow_ isVisible]) {
|
| @@ -504,6 +532,8 @@
|
| }
|
| [sourceController_ removePlaceholder];
|
| chromeIsVisible_ = YES;
|
| +
|
| + [self resetDragControllers];
|
| }
|
|
|
| - (void)otherMouseUp:(NSEvent*)theEvent {
|
|
|