summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 15:30:28 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 15:30:28 +0000
commit3d1104f27426048f4a951a614507b047fc7fd416 (patch)
tree559ee421338ba8fd85ea072bcde1003602086f30 /chrome/browser/cocoa
parent10f2e7c37e44d513524f816a230d47b503362460 (diff)
downloadchromium_src-3d1104f27426048f4a951a614507b047fc7fd416.zip
chromium_src-3d1104f27426048f4a951a614507b047fc7fd416.tar.gz
chromium_src-3d1104f27426048f4a951a614507b047fc7fd416.tar.bz2
Allow live tabs to be dragged out of a window. Change TabStripModel such that
the caller must now explicitly show the newly created browser rather than it happening automatically. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12550 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm35
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h3
-rw-r--r--chrome/browser/cocoa/tab_view.mm22
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h14
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm34
5 files changed, 87 insertions, 21 deletions
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index 95452b2..06c629a 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -5,10 +5,12 @@
#import "chrome/app/chrome_dll_resource.h" // IDC_*
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#import "chrome/browser/cocoa/browser_window_cocoa.h"
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/tab_strip_view.h"
#import "chrome/browser/cocoa/tab_strip_controller.h"
+#import "chrome/browser/cocoa/tab_view.h"
@implementation BrowserWindowController
@@ -205,8 +207,34 @@
}
- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
- NOTIMPLEMENTED();
- return NULL;
+ // Fetch the tab contents for the tab being dragged
+ int index = [tabStripController_ indexForTabView:tabView];
+ TabContents* contents = browser_->tabstrip_model()->GetTabContentsAt(index);
+
+ // Set the window size. Need to do this before we detach the tab so it's
+ // still in the window.
+ NSRect windowRect = [[tabView window] frame];
+ gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
+ windowRect.size.width, windowRect.size.height);
+
+ // Create the new window with a single tab in its model, the one being
+ // dragged.
+ DockInfo dockInfo;
+ Browser* newBrowser =
+ browser_->tabstrip_model()->TearOffTabContents(contents,
+ browserRect,
+ dockInfo);
+
+ // Get the new controller by asking the new window for its delegate.
+ TabWindowController* controller =
+ [newBrowser->window()->GetNativeHandle() delegate];
+ DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
+
+ // Detach it from the source window, which just updates the model without
+ // deleting the tab contents.
+ browser_->tabstrip_model()->DetachTabContentsAt(index);
+
+ return controller;
}
- (void)insertPlaceholderForTab:(TabView*)tab atLocation:(NSInteger)xLocation {
@@ -226,5 +254,8 @@
[tabStripController_ toggleBookmarkBar];
}
+- (NSInteger)numberOfTabs {
+ return browser_->tabstrip_model()->count();
+}
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index 0bd7df4..1d6686a 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -88,6 +88,9 @@ class ToolbarModel;
// Turn on or off the bookmark bar for *ALL* tabs.
- (void)toggleBookmarkBar;
+// Given a tab view in the strip, return its index. Returns -1 if not present.
+- (NSInteger)indexForTabView:(NSView*)view;
+
@end
#endif // CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index 5fee1d5..16446ac 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -64,7 +64,9 @@
TabWindowController* draggedController = nil;
TabWindowController* targetController = nil;
- BOOL isLastTab = NO; // TODO(alcor)
+ // 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.
+ BOOL isLastRemainingTab = [sourceController numberOfTabs] == 1;
NSWindow* dragWindow = nil;
NSWindow* dragOverlay = nil;
@@ -88,7 +90,7 @@
// appropriate class, and visible (obviously).
if (![targets count]) {
for (NSWindow* window in [NSApp windows]) {
- if (window == sourceWindow && isLastTab) continue;
+ if (window == sourceWindow && isLastRemainingTab) continue;
if (window == dragWindow) continue;
if (![window isVisible]) continue;
NSWindowController *controller = [window windowController];
@@ -121,11 +123,9 @@
NSEventType type = [theEvent type];
if (type == NSLeftMouseDragged) {
-#if 0
- // TODO(alcor): get this working...
moved = YES;
if (!draggedController) {
- if (isLastTab) {
+ if (isLastRemainingTab) {
draggedController = sourceController;
dragWindow = [draggedController window];
} else {
@@ -144,7 +144,7 @@
}
// Bring the target window to the front and make sure it has a border.
- [[draggedController window] setLevel:NSFloatingWindowLevel];
+ [dragWindow setLevel:NSFloatingWindowLevel];
[dragWindow orderFront:nil];
[dragWindow makeMainWindow];
[draggedController showOverlay];
@@ -162,7 +162,7 @@
// If we're not hovering over any window, make the window is fully
// opaque. Otherwise, find where the tab might be dropped and insert
// a placeholder so it appears like it's part of that window.
- if (!targetContoller) {
+ if (!targetController) {
[[dragWindow animator] setAlphaValue:1.0];
} else {
if (![[targetController window] isKeyWindow]) {
@@ -179,7 +179,7 @@
[sourceWindow convertBaseToScreen:
[self convertPointToBase:NSZeroPoint]];
int x = NSWidth([self bounds]) / 2 + point.x - dropTabFrame.origin.x;
- [targetController insertPlaceholderForTab:tab_ atLocation:x];
+ [targetController insertPlaceholderForTab:self atLocation:x];
[targetController arrangeTabs];
if (!targetController)
@@ -190,7 +190,6 @@
setAlphaValue:targetController ? 0.85 : 1.0];
// [setAlphaValue:targetController ? 0.0 : 0.6];
}
-#endif
} else if (type == NSLeftMouseUp) {
// Mouse up, break out of the drag event tracking loop
dragging = NO;
@@ -203,6 +202,8 @@
if (moved) {
TabWindowController *dropController = targetController;
if (dropController) {
+#if 0
+// TODO(alcor/pinkerton): hookup drops on existing windows
NSRect adjustedFrame = [self bounds];
NSRect dropTabFrame = [[dropController tabStripView] frame];
adjustedFrame.origin = [self convertPointToBase:NSZeroPoint];
@@ -220,11 +221,12 @@
[dropController arrangeTabs];
[draggedController close];
[dropController showWindow:nil];
+#endif
} else {
[[dragWindow animator] setAlphaValue:1.0];
[dragOverlay setHasShadow:NO];
[draggedController removeOverlayAfterDelay:
- [[NSAnimationContext currentContext] duration]];
+ [[NSAnimationContext currentContext] duration]];
[dragWindow makeKeyAndOrderFront:nil];
[[draggedController window] setLevel:NSNormalWindowLevel];
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
index fee790a..f0fcb524 100644
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ b/chrome/browser/cocoa/tab_window_controller.h
@@ -19,9 +19,14 @@
@interface TabWindowController : NSWindowController {
@private
- IBOutlet NSBox* contentBox_;
+ IBOutlet NSBox* contentBox_; // Only valid at window creation time, used
+ // to position the tab strip. nil afterwards.
+ // TODO(pinkerton): get rid of this.
IBOutlet TabStripView* tabStripView_;
- NSWindow* overlayWindow_; // used during dragging
+ NSWindow* overlayWindow_; // Used during dragging for window opacity tricks
+ NSView* cachedContentView_; // Used during dragging for identifying which
+ // view is the proper content area in the overlay
+ // (weak)
}
@property(readonly, nonatomic) TabStripView* tabStripView;
@@ -30,6 +35,7 @@
- (void)showOverlay;
- (void)removeOverlay;
- (void)removeOverlayAfterDelay:(NSTimeInterval)delay;
+- (NSWindow*)overlayWindow;
// A collection of methods, stubbed out in this base class, that provide
// the implementation of tab dragging based on whatever model is most
@@ -50,6 +56,10 @@
// Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|.
- (void)removePlaceholder;
+// Number of tabs in the tab strip. Useful, for example, to know if we're
+// dragging the only tab in the window.
+- (NSInteger)numberOfTabs;
+
@end
#endif // CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm
index 0729c37..691095f 100644
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ b/chrome/browser/cocoa/tab_window_controller.mm
@@ -22,6 +22,10 @@
tabFrame.size.height = NSHeight([tabStripView_ frame]);
[tabStripView_ setFrame:tabFrame];
[[[[self window] contentView] superview] addSubview:tabStripView_];
+
+ // tab switching will destroy the content area, so nil this out to ensure
+ // that nobody tries to use it.
+ contentBox_ = nil;
}
- (void)removeOverlay {
@@ -41,11 +45,17 @@
[self setUseOverlay:YES];
}
+// If |useOverlay| is YES, creates a new overlay window and puts the tab strip
+// and the content area inside of it. This allows it to have a different opacity
+// from the title bar. If NO, returns everything to the previous state and
+// destroys the overlay window until it's needed again. The tab strip and window
+// contents are returned to the original window.
- (void)setUseOverlay:(BOOL)useOverlay {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(removeOverlay)
object:nil];
if (useOverlay && !overlayWindow_) {
+ DCHECK(!cachedContentView_);
overlayWindow_ = [[NSPanel alloc] initWithContentRect:[[self window] frame]
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
@@ -55,27 +65,31 @@
[overlayWindow_ setOpaque:NO];
NSView *contentView = [overlayWindow_ contentView];
[contentView addSubview:[self tabStripView]];
- [contentView addSubview:contentBox_];
+ cachedContentView_ = [[self window] contentView];
+ [contentView addSubview:cachedContentView_];
[overlayWindow_ setHasShadow:YES];
[[self window] addChildWindow:overlayWindow_ ordered:NSWindowAbove];
[overlayWindow_ orderFront:nil];
-
[[self window] setHasShadow:NO];
} else if (!useOverlay && overlayWindow_) {
- NSResponder *responder = [overlayWindow_ firstResponder];
+ DCHECK(cachedContentView_);
[[self window] setHasShadow:YES];
- NSView *contentView = [[self window] contentView];
- [contentView addSubview:contentBox_];
- [[contentView superview] addSubview:[self tabStripView]];
- [[self window] makeFirstResponder:responder];
+ [[self window] setContentView:cachedContentView_];
+ [[cachedContentView_ superview] addSubview:[self tabStripView]];
+ [[self window] makeFirstResponder:cachedContentView_];
[[self window] display];
[[self window] removeChildWindow:overlayWindow_];
[overlayWindow_ orderOut:nil];
[overlayWindow_ release];
overlayWindow_ = nil;
+ cachedContentView_ = nil;
}
}
+- (NSWindow*)overlayWindow {
+ return overlayWindow_;
+}
+
- (void)arrangeTabs {
// subclass must implement
NOTIMPLEMENTED();
@@ -97,4 +111,10 @@
NOTIMPLEMENTED();
}
+- (NSInteger)numberOfTabs {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return 0;
+}
+
@end