summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-10 19:10:13 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-10 19:10:13 +0000
commitc17fe94be373a0934d0dca787b2601c4532f8a77 (patch)
treef07268a833b93f1933cd566bf6593a4c9e53f948 /chrome/browser/cocoa
parent27ceaa12686624111f122f746e04536a57adaa53 (diff)
downloadchromium_src-c17fe94be373a0934d0dca787b2601c4532f8a77.zip
chromium_src-c17fe94be373a0934d0dca787b2601c4532f8a77.tar.gz
chromium_src-c17fe94be373a0934d0dca787b2601c4532f8a77.tar.bz2
Allow windows with a single tab to be merged into other windows with drag and drop. When there is a single window with a single tab, we treat it like a window move.
BUG=15108 TEST=dragging out windows and merging them back in, dragging windows around to move them. Test windows of different types (incognito) as well. Review URL: http://codereview.chromium.org/199079 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25894 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/tab_view.mm79
1 files changed, 49 insertions, 30 deletions
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index a277627..6e741da 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/cocoa/tab_view.h"
+#import "chrome/browser/cocoa/tab_view.h"
+#include "base/logging.h"
#include "chrome/browser/cocoa/nsimage_cache.h"
-#include "chrome/browser/cocoa/tab_controller.h"
-#include "chrome/browser/cocoa/tab_window_controller.h"
+#import "chrome/browser/cocoa/tab_controller.h"
+#import "chrome/browser/cocoa/tab_window_controller.h"
// Constants for inset and control points for tab shape.
static const CGFloat kInsetMultiplier = 2.0/3.0;
@@ -142,6 +143,27 @@ static const NSTimeInterval kAnimationHideDuration = 0.4;
return YES;
}
+// Find all the windows that could be a target. It has to be of the
+// appropriate class, and visible (obviously). Note that the window cannot be
+// a target for itself.
+- (NSArray*)dropTargetsForController:(TabWindowController*)dragController {
+ NSMutableArray* targets = [NSMutableArray array];
+ NSWindow* dragWindow = [dragController window];
+ for (NSWindow* window in [NSApp windows]) {
+ if (window == dragWindow) continue;
+ if (![window isVisible]) continue;
+ NSWindowController *controller = [window windowController];
+ if ([controller isKindOfClass:[TabWindowController class]]) {
+ TabWindowController* realController =
+ static_cast<TabWindowController*>(controller);
+ if ([realController canReceiveFrom:dragController]) {
+ [targets addObject:controller];
+ }
+ }
+ }
+ return targets;
+}
+
// 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
@@ -193,13 +215,19 @@ static const CGFloat kRapidCloseDist = 2.5;
tearTime_ = 0.0;
draggingWithinTabStrip_ = YES;
- // We don't want to "tear off" a tab if there's only one in the window. Treat
- // it like we're dragging around a tab we've already detached. Note that
- // unit tests might have |-numberOfTabs| reporting zero since the model
- // won't be fully hooked up. We need to be prepared for that and not send
- // them into the "magnetic" codepath.
+ // If there's more than one potential window to be a drop target, we want to
+ // treat a drag of a tab just like dragging around a tab that's already
+ // detached. Note that unit tests might have |-numberOfTabs| reporting zero
+ // since the model won't be fully hooked up. We need to be prepared for that
+ // and not send them into the "magnetic" codepath.
+ NSArray* targets = [self dropTargetsForController:sourceController_];
moveWindowOnDrag_ =
- [sourceController_ numberOfTabs] <= 1 || ![self canBeDragged];
+ ([sourceController_ numberOfTabs] < 2 && ![targets count]) ||
+ ![self canBeDragged];
+ // If we are dragging a tab, a window with a single tab should immediately
+ // snap off and not drag within the tab strip.
+ if (!moveWindowOnDrag_)
+ draggingWithinTabStrip_ = [sourceController_ numberOfTabs] > 1;
dragOrigin_ = [NSEvent mouseLocation];
@@ -286,30 +314,13 @@ static const CGFloat kRapidCloseDist = 2.5;
// Do not start dragging until the user has "torn" the tab off by
// moving more than 3 pixels.
- NSDate* targetDwellDate = nil; // The date this target was first chosen
- NSMutableArray* targets = [NSMutableArray array];
+ NSDate* targetDwellDate = nil; // The date this target was first chosen.
NSPoint thisPoint = [NSEvent mouseLocation];
- // Find all the windows that could be a target. It has to be of the
- // appropriate class, and visible (obviously).
- if (![targets count]) {
- for (NSWindow* window in [NSApp windows]) {
- if (window == dragWindow_) continue;
- if (![window isVisible]) continue;
- NSWindowController *controller = [window windowController];
- if ([controller isKindOfClass:[TabWindowController class]]) {
- TabWindowController* realController =
- static_cast<TabWindowController*>(controller);
- if ([realController canReceiveFrom:sourceController_]) {
- [targets addObject:controller];
- }
- }
- }
- }
-
// Iterate over possible targets checking for the one the mouse is in.
// The mouse can be in either the tab or window frame.
+ NSArray* targets = [self dropTargetsForController:draggedController_];
TabWindowController* newTarget = nil;
for (TabWindowController* target in targets) {
NSRect windowFrame = [[target window] frame];
@@ -338,10 +349,18 @@ static const CGFloat kRapidCloseDist = 2.5;
// Create or identify the dragged controller.
if (!draggedController_) {
- // Detach from the current window and put it in a new window.
+ // Detach from the current window and put it in a new window. If there are
+ // no more tabs remaining after detaching, the source window is about to
+ // go away (it's been autoreleased) so we need to ensure we don't reference
+ // it any more. In that case the new controller becomes our source
+ // controller.
draggedController_ = [sourceController_ detachTabToNewWindow:self];
dragWindow_ = [draggedController_ window];
[dragWindow_ setAlphaValue:0.0];
+ if (![sourceController_ numberOfTabs]) {
+ sourceController_ = draggedController_;
+ sourceWindow_ = dragWindow_;
+ }
// If dragging the tab only moves the current window, do not show overlay
// so that sheets stay on top of the window.
@@ -398,7 +417,6 @@ static const CGFloat kRapidCloseDist = 2.5;
if (![[targetController_ window] isKeyWindow]) {
// && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) {
[[targetController_ window] orderFront:nil];
- [targets removeAllObjects];
targetDwellDate = nil;
}
@@ -458,6 +476,7 @@ static const CGFloat kRapidCloseDist = 2.5;
if (draggingWithinTabStrip_) {
if (tabWasDragged_) {
// Move tab to new location.
+ DCHECK([sourceController_ numberOfTabs]);
TabWindowController* dropController = sourceController_;
[dropController moveTabView:[dropController selectedTabView]
fromController:nil];