172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/dragged_tab_controller.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <math.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/rtl.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_function_dispatcher.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/user_metrics.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/tabs/tab_strip_model.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h"
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/frame/browser_view.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/base_tab.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/base_tab_strip.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/dragged_tab_view.h"
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/native_view_photobooth.h"
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/side_tab.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/side_tab_strip.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/tab.h"
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/tab_strip.h"
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/animation.h"
323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/animation_delegate.h"
333f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h"
3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h"
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/events/event.h"
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/screen.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget.h"
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window.h"
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_win.h"
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <gdk/gdk.h>  // NOLINT
4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <gdk/gdkkeysyms.h>  // NOLINT
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kHorizontalMoveThreshold = 16;  // Pixels.
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Distance in pixels the user must move the mouse before we consider moving
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// an attached vertical tab.
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kVerticalMoveThreshold = 8;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If non-null there is a drag underway.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic DraggedTabController* instance_;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Delay, in ms, during dragging before we bring a window to front.
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBringToFrontDelay = 750;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Radius of the rect drawn by DockView.
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRoundedRectRadius = 4;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Spacing between tab icons when DockView is showing a docking location that
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// contains more than one tab.
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTabSpacing = 4;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DockView is the view responsible for giving a visual indicator of where a
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dock is going to occur.
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DockView : public views::View {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit DockView(DockInfo::Type type) : type_(type) {}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual gfx::Size GetPreferredSize() {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return gfx::Size(DockInfo::popup_width(), DockInfo::popup_height());
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  virtual void OnPaintBackground(gfx::Canvas* canvas) {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkRect outer_rect = { SkIntToScalar(0), SkIntToScalar(0),
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          SkIntToScalar(width()),
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          SkIntToScalar(height()) };
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Fill the background rect.
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkPaint paint;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    paint.setColor(SkColorSetRGB(108, 108, 108));
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    paint.setStyle(SkPaint::kFill_Style);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->AsCanvasSkia()->drawRoundRect(
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        outer_rect, SkIntToScalar(kRoundedRectRadius),
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SkIntToScalar(kRoundedRectRadius), paint);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkBitmap* high_icon = rb.GetBitmapNamed(IDR_DOCK_HIGH);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkBitmap* wide_icon = rb.GetBitmapNamed(IDR_DOCK_WIDE);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    canvas->Save();
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool rtl_ui = base::i18n::IsRTL();
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rtl_ui) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Flip canvas to draw the mirrored tab images for RTL UI.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->TranslateInt(width(), 0);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->ScaleInt(-1, 1);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int x_of_active_tab = width() / 2 + kTabSpacing / 2;
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int x_of_inactive_tab = width() / 2 - high_icon->width() - kTabSpacing / 2;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (type_) {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::LEFT_OF_WINDOW:
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::LEFT_HALF:
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (!rtl_ui)
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          std::swap(x_of_active_tab, x_of_inactive_tab);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        canvas->DrawBitmapInt(*high_icon, x_of_active_tab,
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              (height() - high_icon->height()) / 2);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (type_ == DockInfo::LEFT_OF_WINDOW) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DrawBitmapWithAlpha(canvas, *high_icon, x_of_inactive_tab,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              (height() - high_icon->height()) / 2);
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::RIGHT_OF_WINDOW:
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::RIGHT_HALF:
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (rtl_ui)
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          std::swap(x_of_active_tab, x_of_inactive_tab);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        canvas->DrawBitmapInt(*high_icon, x_of_active_tab,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              (height() - high_icon->height()) / 2);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (type_ == DockInfo::RIGHT_OF_WINDOW) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         DrawBitmapWithAlpha(canvas, *high_icon, x_of_inactive_tab,
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             (height() - high_icon->height()) / 2);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::TOP_OF_WINDOW:
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        canvas->DrawBitmapInt(*wide_icon, (width() - wide_icon->width()) / 2,
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              height() / 2 - high_icon->height());
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::MAXIMIZE: {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SkBitmap* max_icon = rb.GetBitmapNamed(IDR_DOCK_MAX);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        canvas->DrawBitmapInt(*max_icon, (width() - max_icon->width()) / 2,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              (height() - max_icon->height()) / 2);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::BOTTOM_HALF:
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case DockInfo::BOTTOM_OF_WINDOW:
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        canvas->DrawBitmapInt(*wide_icon, (width() - wide_icon->width()) / 2,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              height() / 2 + kTabSpacing / 2);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (type_ == DockInfo::BOTTOM_OF_WINDOW) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DrawBitmapWithAlpha(canvas, *wide_icon,
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              (width() - wide_icon->width()) / 2,
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              height() / 2 - kTabSpacing / 2 - wide_icon->height());
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED();
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    canvas->Restore();
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void DrawBitmapWithAlpha(gfx::Canvas* canvas, const SkBitmap& image,
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           int x, int y) {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkPaint paint;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    paint.setAlpha(128);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->DrawBitmapInt(image, x, y, paint);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DockInfo::Type type_;
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(DockView);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Returns the the x-coordinate of |point| if the type of tabstrip is horizontal
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// otherwise returns the y-coordinate.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint MajorAxisValue(const gfx::Point& point, BaseTabStrip* tabstrip) {
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return (tabstrip->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) ?
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      point.x() : point.y();
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DockDisplayer
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DockDisplayer is responsible for giving the user a visual indication of a
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// possible dock position (as represented by DockInfo). DockDisplayer shows
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a window with a DockView in it. Two animations are used that correspond to
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the state of DockInfo::in_enable_area.
1953f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass DraggedTabController::DockDisplayer : public ui::AnimationDelegate {
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DockDisplayer(DraggedTabController* controller,
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                const DockInfo& info)
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : controller_(controller),
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        popup_(NULL),
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        popup_view_(NULL),
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)),
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hidden_(false),
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        in_enable_area_(info.in_enable_area()) {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // TODO(sky): This should "just work" on Gtk now.
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    params.transparent = true;
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    params.keep_on_top = true;
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    popup_ = views::Widget::CreateWidget(params);
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    popup_->SetOpacity(0x00);
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    popup_->Init(NULL, info.GetPopupRect());
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    popup_->SetContentsView(new DockView(info.type()));
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (info.in_enable_area())
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_.Reset(1);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_.Show();
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    popup_->Show();
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    popup_view_ = popup_->GetNativeView();
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~DockDisplayer() {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (controller_)
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_->DockDisplayerDestroyed(this);
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Updates the state based on |in_enable_area|.
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void UpdateInEnabledArea(bool in_enable_area) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (in_enable_area != in_enable_area_) {
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      in_enable_area_ = in_enable_area;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateLayeredAlpha();
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Resets the reference to the hosting DraggedTabController. This is invoked
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // when the DraggedTabController is destoryed.
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void clear_controller() { controller_ = NULL; }
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NativeView of the window we create.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeView popup_view() { return popup_view_; }
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Starts the hide animation. When the window is closed the
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DraggedTabController is notified by way of the DockDisplayerDestroyed
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // method
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Hide() {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (hidden_)
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!popup_) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete this;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hidden_ = true;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animation_.Hide();
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationProgressed(const ui::Animation* animation) {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UpdateLayeredAlpha();
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationEnded(const ui::Animation* animation) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!hidden_)
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<views::WidgetWin*>(popup_)->Close();
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete this;
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void UpdateLayeredAlpha() {
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double scale = in_enable_area_ ? 1 : .5;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<views::WidgetWin*>(popup_)->SetOpacity(
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<BYTE>(animation_.GetCurrentValue() * scale * 255.0));
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    popup_->GetRootView()->SchedulePaint();
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DraggedTabController that created us.
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DraggedTabController* controller_;
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Window we're showing.
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::Widget* popup_;
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NativeView of |popup_|. We cache this to avoid the possibility of
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // invoking a method on popup_ after we close it.
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeView popup_view_;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Animation for when first made visible.
2983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  ui::SlideAnimation animation_;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Have we been hidden?
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool hidden_;
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Value of DockInfo::in_enable_area.
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool in_enable_area_;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDraggedTabController::TabDragData::TabDragData()
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : contents(NULL),
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      original_delegate(NULL),
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      source_model_index(-1),
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      attached_tab(NULL),
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pinned(false) {
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDraggedTabController::TabDragData::~TabDragData() {
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, public:
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDraggedTabController::DraggedTabController()
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : source_tabstrip_(NULL),
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      attached_tabstrip_(NULL),
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      source_tab_offset_(0),
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_to_width_ratio_(0),
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      old_focused_view_(NULL),
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      last_move_screen_loc_(0),
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      started_drag_(false),
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      active_(true),
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      source_tab_index_(std::numeric_limits<size_t>::max()),
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      initial_move_(true) {
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  instance_ = this;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDraggedTabController::~DraggedTabController() {
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (instance_ == this)
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    instance_ = NULL;
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoopForUI::current()->RemoveObserver(this);
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Need to delete the view here manually _before_ we reset the dragged
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // contents to NULL, otherwise if the view is animating to its destination
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // bounds, it won't be able to clean up properly since its cleanup routine
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // uses GetIndexForDraggedContents, which will be invalid.
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  view_.reset(NULL);
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Reset the delegate of the dragged TabContents. This ends up doing nothing
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // if the drag was completed.
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResetDelegates();
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::Init(BaseTabStrip* source_tabstrip,
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                BaseTab* source_tab,
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                const std::vector<BaseTab*>& tabs,
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                const gfx::Point& mouse_offset,
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                int source_tab_offset) {
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!tabs.empty());
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end());
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_tabstrip_ = source_tabstrip;
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_tab_offset_ = source_tab_offset;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  start_screen_point_ = GetCursorScreenPoint();
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  mouse_offset_ = mouse_offset;
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data_.resize(tabs.size());
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i)
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    InitTabDragData(tabs[i], &(drag_data_[i]));
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_tab_index_ =
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::find(tabs.begin(), tabs.end(), source_tab) - tabs.begin();
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Listen for Esc key presses.
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MessageLoopForUI::current()->AddObserver(this);
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (source_tab->width() > 0) {
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    offset_to_width_ratio_ = static_cast<float>(source_tab_offset_) /
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        static_cast<float>(source_tab->width());
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InitWindowCreatePoint();
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DraggedTabController::IsAttachedTo(BaseTabStrip* tab_strip) {
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return instance_ && instance_->active_ &&
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      instance_->attached_tabstrip_ == tab_strip;
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::Drag() {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bring_to_front_timer_.Stop();
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!started_drag_) {
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!CanStartDrag())
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;  // User hasn't dragged far enough yet.
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    started_drag_ = true;
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SaveFocus();
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Attach(source_tabstrip_, gfx::Point());
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ContinueDragging();
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::EndDrag(bool canceled) {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EndDragImpl(canceled ? CANCELED : NORMAL);
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::InitTabDragData(BaseTab* tab,
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           TabDragData* drag_data) {
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data->source_model_index =
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      source_tabstrip_->GetModelIndexOfBaseTab(tab);
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data->contents = GetModel(source_tabstrip_)->GetTabContentsAt(
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data->source_model_index);
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data->pinned = source_tabstrip_->IsTabPinned(tab);
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar_.Add(this,
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 NotificationType::TAB_CONTENTS_DESTROYED,
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 Source<TabContents>(drag_data->contents->tab_contents()));
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We need to be the delegate so we receive messages about stuff, otherwise
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // our dragged TabContents may be replaced and subsequently
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // collected/destroyed while the drag is in process, leading to nasty crashes.
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data->original_delegate =
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data->contents->tab_contents()->delegate();
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data->contents->tab_contents()->set_delegate(this);
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, PageNavigator implementation:
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::OpenURLFromTab(TabContents* source,
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const GURL& url,
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const GURL& referrer,
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          WindowOpenDisposition disposition,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          PageTransition::Type transition) {
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (source_tab_drag_data()->original_delegate) {
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (disposition == CURRENT_TAB)
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      disposition = NEW_WINDOW;
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    source_tab_drag_data()->original_delegate->OpenURLFromTab(
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        source, url, referrer, disposition, transition);
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, TabContentsDelegate implementation:
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::NavigationStateChanged(const TabContents* source,
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  unsigned changed_flags) {
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (view_.get())
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    view_->Update();
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::AddNewContents(TabContents* source,
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          TabContents* new_contents,
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          WindowOpenDisposition disposition,
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const gfx::Rect& initial_pos,
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool user_gesture) {
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(CURRENT_TAB, disposition);
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Theoretically could be called while dragging if the page tries to
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // spawn a window. Route this message back to the browser in most cases.
458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (source_tab_drag_data()->original_delegate) {
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    source_tab_drag_data()->original_delegate->AddNewContents(
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        source, new_contents, disposition, initial_pos, user_gesture);
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::ActivateContents(TabContents* contents) {
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ignored.
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid DraggedTabController::DeactivateContents(TabContents* contents) {
4693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Ignored.
4703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::LoadingStateChanged(TabContents* source) {
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It would be nice to respond to this message by changing the
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // screen shot in the dragged tab.
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (view_.get())
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    view_->Update();
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::CloseContents(TabContents* source) {
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Theoretically could be called by a window. Should be ignored
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // because window.close() is ignored (usually, even though this
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // method gets called.)
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::MoveContents(TabContents* source,
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const gfx::Rect& pos) {
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Theoretically could be called by a web page trying to move its
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // own window. Should be ignored since we're moving the window...
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::UpdateTargetURL(TabContents* source,
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const GURL& url) {
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ignored.
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DraggedTabController::ShouldSuppressDialogs() {
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // When a dialog is about to be shown we revert the drag. Otherwise a modal
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // dialog might appear and attempt to parent itself to a hidden tabcontents.
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EndDragImpl(CANCELED);
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, NotificationObserver implementation:
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::Observe(NotificationType type,
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const NotificationSource& source,
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const NotificationDetails& details) {
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(type.value, NotificationType::TAB_CONTENTS_DESTROYED);
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabContents* destroyed_contents = Source<TabContents>(source).ptr();
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (drag_data_[i].contents->tab_contents() == destroyed_contents) {
513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // One of the tabs we're dragging has been destroyed. Cancel the drag.
514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (destroyed_contents->delegate() == this)
515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        destroyed_contents->set_delegate(NULL);
516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data_[i].contents = NULL;
517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data_[i].original_delegate = NULL;
518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EndDragImpl(TAB_DESTROYED);
519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If we get here it means we got notification for a tab we don't know about.
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NOTREACHED();
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, MessageLoop::Observer implementation:
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::WillProcessMessage(const MSG& msg) {
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::DidProcessMessage(const MSG& msg) {
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the user presses ESC during a drag, we need to abort and revert things
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to the way they were. This is the most reliable way to do this since no
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // single view or window reliably receives events throughout all the various
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // kinds of tab dragging.
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EndDrag(true);
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::WillProcessEvent(GdkEvent* event) {
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::DidProcessEvent(GdkEvent* event) {
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->type == GDK_KEY_PRESS &&
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reinterpret_cast<GdkEventKey*>(event)->keyval == GDK_Escape) {
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EndDrag(true);
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DraggedTabController, private:
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::InitWindowCreatePoint() {
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // window_create_point_ is only used in CompleteDrag() (through
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GetWindowCreatePoint() to get the start point of the docked window) when
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the attached_tabstrip_ is NULL and all the window's related bound
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // information are obtained from source_tabstrip_. So, we need to get the
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // first_tab based on source_tabstrip_, not attached_tabstrip_. Otherwise,
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the window_create_point_ is not in the correct coordinate system. Please
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // refer to http://crbug.com/6223 comment #15 for detailed information.
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View* first_tab = source_tabstrip_->base_tab_at_tab_index(0);
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View::ConvertPointToWidget(first_tab, &first_source_tab_point_);
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  window_create_point_ = first_source_tab_point_;
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  window_create_point_.Offset(mouse_offset_.x(), mouse_offset_.y());
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point DraggedTabController::GetWindowCreatePoint() const {
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point cursor_point = GetCursorScreenPoint();
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (dock_info_.type() != DockInfo::NONE && dock_info_.in_enable_area()) {
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we're going to dock, we need to return the exact coordinate,
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // otherwise we may attempt to maximize on the wrong monitor.
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return cursor_point;
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
57772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // If the cursor is outside the monitor area, move it inside. For example,
57872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // dropping a tab onto the task bar on Windows produces this situation.
57972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  gfx::Rect work_area = views::Screen::GetMonitorWorkAreaNearestPoint(
58072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cursor_point);
58172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!work_area.IsEmpty()) {
58272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (cursor_point.x() < work_area.x())
58372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cursor_point.set_x(work_area.x());
58472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (cursor_point.x() > work_area.right())
58572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cursor_point.set_x(work_area.right());
58672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (cursor_point.y() < work_area.y())
58772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cursor_point.set_y(work_area.y());
58872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (cursor_point.y() > work_area.bottom())
58972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      cursor_point.set_y(work_area.bottom());
59072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Point(cursor_point.x() - window_create_point_.x(),
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    cursor_point.y() - window_create_point_.y());
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::UpdateDockInfo(const gfx::Point& screen_point) {
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the DockInfo for the current mouse coordinates.
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DockInfo dock_info = GetDockInfoAtPoint(screen_point);
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (source_tabstrip_->type() == BaseTabStrip::VERTICAL_TAB_STRIP &&
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ((dock_info.type() == DockInfo::LEFT_OF_WINDOW &&
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !base::i18n::IsRTL()) ||
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       (dock_info.type() == DockInfo::RIGHT_OF_WINDOW &&
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        base::i18n::IsRTL()))) {
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // For side tabs it's way to easy to trigger to docking along the left/right
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // edge, so we disable it.
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_info = DockInfo();
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dock_info.equals(dock_info_)) {
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // DockInfo for current position differs.
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (dock_info_.type() != DockInfo::NONE &&
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !dock_controllers_.empty()) {
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Hide old visual indicator.
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dock_controllers_.back()->Hide();
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_info_ = dock_info;
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (dock_info_.type() != DockInfo::NONE) {
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Show new docking position.
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DockDisplayer* controller = new DockDisplayer(this, dock_info_);
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (controller->popup_view()) {
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        dock_controllers_.push_back(controller);
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        dock_windows_.insert(controller->popup_view());
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        delete controller;
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (dock_info_.type() != DockInfo::NONE &&
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             !dock_controllers_.empty()) {
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Current dock position is the same as last, update the controller's
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // in_enable_area state as it may have changed.
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_controllers_.back()->UpdateInEnabledArea(dock_info_.in_enable_area());
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::SaveFocus() {
634ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!old_focused_view_);  // This should only be invoked once.
635ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  old_focused_view_ = source_tabstrip_->GetFocusManager()->GetFocusedView();
636ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_tabstrip_->GetFocusManager()->SetFocusedView(source_tabstrip_);
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::RestoreFocus() {
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (old_focused_view_ && attached_tabstrip_ == source_tabstrip_)
641dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    old_focused_view_->GetFocusManager()->SetFocusedView(old_focused_view_);
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  old_focused_view_ = NULL;
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DraggedTabController::CanStartDrag() const {
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Determine if the mouse has moved beyond a minimum elasticity distance in
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // any direction from the starting point.
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kMinimumDragDistance = 10;
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point screen_point = GetCursorScreenPoint();
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int x_offset = abs(screen_point.x() - start_screen_point_.x());
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int y_offset = abs(screen_point.y() - start_screen_point_.y());
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return sqrt(pow(static_cast<float>(x_offset), 2) +
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              pow(static_cast<float>(y_offset), 2)) > kMinimumDragDistance;
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::ContinueDragging() {
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note that the coordinates given to us by |drag_event| are basically
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // useless, since they're in source_tab_ coordinates. On the surface, you'd
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // think we could just convert them to screen coordinates, however in the
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // situation where we're dragging the last tab in a window when multiple
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windows are open, the coordinates of |source_tab_| are way off in
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // hyperspace since the window was moved there instead of being closed so
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that we'd keep receiving events. And our ConvertPointToScreen methods
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // aren't really multi-screen aware. So really it's just safer to get the
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // actual position of the mouse cursor directly from Windows here, which is
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // guaranteed to be correct regardless of monitor config.
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point screen_point = GetCursorScreenPoint();
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
669ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_LINUX)
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't allow detaching in chrome os.
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTabStrip* target_tabstrip = source_tabstrip_;
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Determine whether or not we have dragged over a compatible TabStrip in
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // another browser window. If we have, we should attach to it and start
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // dragging within it.
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTabStrip* target_tabstrip = GetTabStripForPoint(screen_point);
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (target_tabstrip != attached_tabstrip_) {
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make sure we're fully detached from whatever TabStrip we're attached to
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (if any).
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (attached_tabstrip_)
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Detach();
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (target_tabstrip)
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Attach(target_tabstrip, screen_point);
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!target_tabstrip) {
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bring_to_front_timer_.Start(
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        base::TimeDelta::FromMilliseconds(kBringToFrontDelay), this,
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &DraggedTabController::BringWindowUnderMouseToFront);
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateDockInfo(screen_point);
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_)
695ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MoveAttached(screen_point);
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MoveDetached(screen_point);
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::MoveAttached(const gfx::Point& screen_point) {
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(attached_tabstrip_);
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!view_.get());
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
704ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Point dragged_view_point = GetAttachedDragPoint(screen_point);
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int threshold = kVerticalMoveThreshold;
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabStrip* tab_strip = static_cast<TabStrip*>(attached_tabstrip_);
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Determine the horizontal move threshold. This is dependent on the width
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // of tabs. The smaller the tabs compared to the standard size, the smaller
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the threshold.
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double unselected, selected;
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_strip->GetCurrentTabWidths(&unselected, &selected);
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double ratio = unselected / Tab::GetStandardSize().width();
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    threshold = static_cast<int>(ratio * kHorizontalMoveThreshold);
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
719ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> tabs(drag_data_.size());
720ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i)
721ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs[i] = drag_data_[i].attached_tab;
722ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
723ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool did_layout = false;
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the model, moving the TabContents from one index to another. Do this
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // only if we have moved a minimum distance since the last reorder (to prevent
726ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // jitter) or if this the first move and the tabs are not consecutive.
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (abs(MajorAxisValue(screen_point, attached_tabstrip_) -
728ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          last_move_screen_loc_) > threshold ||
729ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      (initial_move_ && !AreTabsConsecutive())) {
730ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TabStripModel* attached_model = GetModel(attached_tabstrip_);
731ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point);
732ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int to_index = GetInsertionIndexForDraggedBounds(bounds);
733ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TabContentsWrapper* last_contents =
734ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        drag_data_[drag_data_.size() - 1].contents;
735ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int index_of_last_item =
736ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          attached_model->GetIndexOfTabContents(last_contents);
737ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (initial_move_) {
738ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // TabStrip determines if the tabs needs to be animated based on model
739ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // position. This means we need to invoke LayoutDraggedTabsAt before
740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // changing the model.
741ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      attached_tabstrip_->LayoutDraggedTabsAt(
742ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          tabs, source_tab_drag_data()->attached_tab, dragged_view_point,
743ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          initial_move_);
744ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      did_layout = true;
745ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
746ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_model->MoveSelectedTabsTo(to_index);
747ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Move may do nothing in certain situations (such as when dragging pinned
748ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // tabs). Make sure the tabstrip actually changed before updating
749ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // last_move_screen_loc_.
750ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (index_of_last_item !=
751ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        attached_model->GetIndexOfTabContents(last_contents)) {
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      last_move_screen_loc_ = MajorAxisValue(screen_point, attached_tabstrip_);
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
756ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!did_layout) {
757ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_tabstrip_->LayoutDraggedTabsAt(
758ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        tabs, source_tab_drag_data()->attached_tab, dragged_view_point,
759ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        initial_move_);
760ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
761ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
762ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  initial_move_ = false;
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
765ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::MoveDetached(const gfx::Point& screen_point) {
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!attached_tabstrip_);
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(view_.get());
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Move the View. There are no changes to the model if we're detached.
770ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  view_->MoveTo(screen_point);
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDockInfo DraggedTabController::GetDockInfoAtPoint(
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Point& screen_point) {
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_) {
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the mouse is over a tab strip, don't offer a dock position.
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return DockInfo();
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dock_info_.IsValidForPoint(screen_point)) {
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // It's possible any given screen coordinate has multiple docking
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // positions. Check the current info first to avoid having the docking
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // position bounce around.
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return dock_info_;
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeView dragged_hwnd = view_->GetWidget()->GetNativeView();
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dock_windows_.insert(dragged_hwnd);
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DockInfo info = DockInfo::GetDockInfoAtPoint(screen_point, dock_windows_);
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dock_windows_.erase(dragged_hwnd);
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return info;
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTabStrip* DraggedTabController::GetTabStripForPoint(
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Point& screen_point) {
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeView dragged_view = NULL;
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (view_.get()) {
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dragged_view = view_->GetWidget()->GetNativeView();
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_windows_.insert(dragged_view);
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeWindow local_window =
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DockInfo::GetLocalProcessWindowAtPoint(screen_point, dock_windows_);
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dragged_view)
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_windows_.erase(dragged_view);
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!local_window)
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserView* browser =
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BrowserView::GetBrowserViewForNativeWindow(local_window);
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't allow drops on windows that don't have tabstrips.
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser ||
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !browser->browser()->SupportsWindowFeature(Browser::FEATURE_TABSTRIP))
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
814ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This cast seems ugly, but the controller and the view are tighly coupled at
815ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // creation time, so it will be okay.
816ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BaseTabStrip* other_tabstrip =
817ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<BaseTabStrip*>(browser->tabstrip());
818ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!other_tabstrip->controller()->IsCompatibleWith(source_tabstrip_))
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return NULL;
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetTabStripIfItContains(other_tabstrip, screen_point);
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTabStrip* DraggedTabController::GetTabStripIfItContains(
825ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BaseTabStrip* tabstrip,
826ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const gfx::Point& screen_point) const {
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kVerticalDetachMagnetism = 15;
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kHorizontalDetachMagnetism = 15;
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure the specified screen point is actually within the bounds of the
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // specified tabstrip...
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect tabstrip_bounds = GetViewScreenBounds(tabstrip);
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tabstrip->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (screen_point.x() < tabstrip_bounds.right() &&
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        screen_point.x() >= tabstrip_bounds.x()) {
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(beng): make this be relative to the start position of the mouse
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // for the source TabStrip.
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int upper_threshold = tabstrip_bounds.bottom() + kVerticalDetachMagnetism;
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int lower_threshold = tabstrip_bounds.y() - kVerticalDetachMagnetism;
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (screen_point.y() >= lower_threshold &&
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_point.y() <= upper_threshold) {
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return tabstrip;
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (screen_point.y() < tabstrip_bounds.bottom() &&
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        screen_point.y() >= tabstrip_bounds.y()) {
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int upper_threshold = tabstrip_bounds.right() +
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          kHorizontalDetachMagnetism;
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int lower_threshold = tabstrip_bounds.x() - kHorizontalDetachMagnetism;
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (screen_point.x() >= lower_threshold &&
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_point.x() <= upper_threshold) {
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return tabstrip;
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::Attach(BaseTabStrip* attached_tabstrip,
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const gfx::Point& screen_point) {
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!attached_tabstrip_);  // We should already have detached by the time
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                // we get here.
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  attached_tabstrip_ = attached_tabstrip;
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // And we don't need the dragged view.
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  view_.reset();
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
869ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> tabs =
870ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetTabsMatchingDraggedContents(attached_tabstrip_);
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
872ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (tabs.empty()) {
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // There is no Tab in |attached_tabstrip| that corresponds to the dragged
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TabContents. We must now create one.
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Remove ourselves as the delegate now that the dragged TabContents is
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // being inserted back into a Browser.
878ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < drag_data_.size(); ++i) {
879ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data_[i].contents->tab_contents()->set_delegate(NULL);
880ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data_[i].original_delegate = NULL;
881ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Return the TabContents' to normalcy.
884ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    source_dragged_contents()->tab_contents()->set_capturing_contents(false);
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Inserting counts as a move. We don't want the tabs to jitter when the
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // user moves the tab immediately after attaching it.
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    last_move_screen_loc_ = MajorAxisValue(screen_point, attached_tabstrip);
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Figure out where to insert the tab based on the bounds of the dragged
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // representation and the ideal bounds of the other Tabs already in the
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // strip. ("ideal bounds" are stable even if the Tabs' actual bounds are
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // changing due to animation).
894ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Point tab_strip_point(screen_point);
895ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_strip_point);
896ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab_strip_point.set_x(
897ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        attached_tabstrip_->GetMirroredXInView(tab_strip_point.x()));
898ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab_strip_point.Offset(-mouse_offset_.x(), -mouse_offset_.y());
899ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Rect bounds = GetDraggedViewTabStripBounds(tab_strip_point);
900ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int index = GetInsertionIndexForDraggedBounds(bounds);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    attached_tabstrip_->set_attaching_dragged_tab(true);
902ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < drag_data_.size(); ++i) {
903ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      int add_types = TabStripModel::ADD_NONE;
904ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (drag_data_[i].pinned)
905ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        add_types |= TabStripModel::ADD_PINNED;
906ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetModel(attached_tabstrip_)->InsertTabContentsAt(
907ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          index + i, drag_data_[i].contents, add_types);
908ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    attached_tabstrip_->set_attaching_dragged_tab(false);
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
911ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs = GetTabsMatchingDraggedContents(attached_tabstrip_);
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
913ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(tabs.size(), drag_data_.size());
914ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i)
915ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drag_data_[i].attached_tab = tabs[i];
916ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
917ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  attached_tabstrip_->StartedDraggingTabs(tabs);
918ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResetSelection(GetModel(attached_tabstrip_));
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The size of the dragged tab may have changed. Adjust the x offset so that
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // ratio of mouse_offset_ to original width is maintained.
924ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<BaseTab*> tabs_to_source(tabs);
925ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs_to_source.erase(tabs_to_source.begin() + source_tab_index_ + 1,
926ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         tabs_to_source.end());
927ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int new_x = attached_tabstrip_->GetSizeNeededForTabs(tabs_to_source) -
928ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        tabs[source_tab_index_]->width() +
929ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        static_cast<int>(offset_to_width_ratio_ *
930ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         tabs[source_tab_index_]->width());
931ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    mouse_offset_.set_x(new_x);
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Move the corresponding window to the front.
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  attached_tabstrip_->GetWindow()->Activate();
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::Detach() {
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Prevent the TabContents' HWND from being hidden by any of the model
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // operations performed during the drag.
941ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_dragged_contents()->tab_contents()->set_capturing_contents(true);
942ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
943ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Calculate the drag bounds.
944ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<gfx::Rect> drag_bounds;
945ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> attached_tabs;
946ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i)
947ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_tabs.push_back(drag_data_[i].attached_tab);
948ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  attached_tabstrip_->CalculateBoundsForDraggedTabs(attached_tabs,
949ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                    &drag_bounds);
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* attached_model = GetModel(attached_tabstrip_);
952ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<TabRendererData> tab_data;
953ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
954ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab_data.push_back(drag_data_[i].attached_tab->data());
955ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int index = attached_model->GetIndexOfTabContents(drag_data_[i].contents);
956ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK_NE(-1, index);
957ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
958ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Hide the tab so that the user doesn't see it animate closed.
959ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drag_data_[i].attached_tab->SetVisible(false);
960ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
961ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_model->DetachTabContentsAt(index);
962ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
963ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Detaching resets the delegate, but we still want to be the delegate.
964ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drag_data_[i].contents->tab_contents()->set_delegate(this);
965ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
966ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Detaching may end up deleting the tab, drop references to it.
967ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drag_data_[i].attached_tab = NULL;
968ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we've removed the last Tab from the TabStrip, hide the frame now.
971731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (attached_model->empty())
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HideFrame();
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create the dragged view.
975ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CreateDraggedView(tab_data, drag_bounds);
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  attached_tabstrip_ = NULL;
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint DraggedTabController::GetInsertionIndexForDraggedBounds(
981ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const gfx::Rect& dragged_bounds) const {
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int right_tab_x = 0;
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bottom_tab_y = 0;
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int index = -1;
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < attached_tabstrip_->tab_count(); ++i) {
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Rect& ideal_bounds = attached_tabstrip_->ideal_bounds(i);
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gfx::Rect left_half = ideal_bounds;
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      left_half.set_width(left_half.width() / 2);
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gfx::Rect right_half = ideal_bounds;
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      right_half.set_width(ideal_bounds.width() - left_half.width());
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      right_half.set_x(left_half.right());
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      right_tab_x = right_half.right();
994ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (dragged_bounds.x() >= right_half.x() &&
995ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          dragged_bounds.x() < right_half.right()) {
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index = i + 1;
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
998ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else if (dragged_bounds.x() >= left_half.x() &&
999ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 dragged_bounds.x() < left_half.right()) {
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index = i;
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Vertical tab strip.
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int max_y = ideal_bounds.bottom();
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int mid_y = ideal_bounds.y() + ideal_bounds.height() / 2;
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bottom_tab_y = max_y;
1008ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (dragged_bounds.y() < mid_y) {
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index = i;
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1011ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else if (dragged_bounds.y() >= mid_y && dragged_bounds.y() < max_y) {
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        index = i + 1;
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == -1) {
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP &&
1019ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         dragged_bounds.right() > right_tab_x) ||
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (attached_tabstrip_->type() == BaseTabStrip::VERTICAL_TAB_STRIP &&
1021ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         dragged_bounds.y() >= bottom_tab_y)) {
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index = GetModel(attached_tabstrip_)->count();
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      index = 0;
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1028ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!drag_data_[0].attached_tab) {
1029ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // If 'attached_tab' is NULL, it means we're in the process of attaching and
1030ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // don't need to constrain the index.
1031ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return index;
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1033ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1034ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int max_index = GetModel(attached_tabstrip_)->count() -
1035ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<int>(drag_data_.size());
1036ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return std::max(0, std::min(max_index, index));
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect DraggedTabController::GetDraggedViewTabStripBounds(
1040ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const gfx::Point& tab_strip_point) {
1041ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // attached_tab is NULL when inserting into a new tabstrip.
1042ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (source_tab_drag_data()->attached_tab) {
1043ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(),
1044ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     source_tab_drag_data()->attached_tab->width(),
1045ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     source_tab_drag_data()->attached_tab->height());
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double sel_width, unselected_width;
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<TabStrip*>(attached_tabstrip_)->GetCurrentTabWidths(
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &sel_width, &unselected_width);
1052ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(),
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     static_cast<int>(sel_width),
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     Tab::GetStandardSize().height());
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1057ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(),
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   attached_tabstrip_->width(),
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   SideTab::GetPreferredHeight());
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1062ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsengfx::Point DraggedTabController::GetAttachedDragPoint(
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const gfx::Point& screen_point) {
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(attached_tabstrip_);  // The tab must be attached.
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1066ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Point tab_loc(screen_point);
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View::ConvertPointToView(NULL, attached_tabstrip_, &tab_loc);
1068ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int x =
1069ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      attached_tabstrip_->GetMirroredXInView(tab_loc.x()) - mouse_offset_.x();
1070ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = tab_loc.y() - mouse_offset_.y();
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1072ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO: consider caching this.
1073ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> attached_tabs;
1074ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i)
1075ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_tabs.push_back(drag_data_[i].attached_tab);
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1077ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int size = attached_tabstrip_->GetSizeNeededForTabs(attached_tabs);
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_->type() == BaseTabStrip::HORIZONTAL_TAB_STRIP) {
1080ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int max_x = attached_tabstrip_->width() - size;
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x = std::min(std::max(x, 0), max_x);
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    y = 0;
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x = SideTabStrip::kTabStripInset;
1085ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int max_y = attached_tabstrip_->height() - size;
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    y = std::min(std::max(y, SideTabStrip::kTabStripInset), max_y);
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Point(x, y);
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1091ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::vector<BaseTab*> DraggedTabController::GetTabsMatchingDraggedContents(
1092ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BaseTabStrip* tabstrip) {
1093ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabStripModel* model = GetModel(attached_tabstrip_);
1094ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> tabs;
1095ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
1096ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int model_index = model->GetIndexOfTabContents(drag_data_[i].contents);
1097ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (model_index == TabStripModel::kNoTab)
1098ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return std::vector<BaseTab*>();
1099ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs.push_back(tabstrip->GetBaseTabAtModelIndex(model_index));
1100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return tabs;
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::EndDragImpl(EndDragType type) {
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  active_ = false;
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bring_to_front_timer_.Stop();
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Hide the current dock controllers.
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < dock_controllers_.size(); ++i) {
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Be sure and clear the controller first, that way if Hide ends up
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // deleting the controller it won't call us back.
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_controllers_[i]->clear_controller();
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_controllers_[i]->Hide();
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dock_controllers_.clear();
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dock_windows_.clear();
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type != TAB_DESTROYED) {
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We only finish up the drag if we were actually dragging. If start_drag_
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // is false, the user just clicked and released and didn't move the mouse
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // enough to trigger a drag.
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (started_drag_) {
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      RestoreFocus();
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (type == CANCELED)
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        RevertDrag();
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      else
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CompleteDrag();
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (drag_data_.size() > 1) {
1131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RevertDrag();
1132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }  // else case the only tab we were dragging was deleted. Nothing to do.
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResetDelegates();
1135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Clear out drag data so we don't attempt to do anything with it.
1137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_data_.clear();
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  source_tabstrip_->DestroyDragController();
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::RevertDrag() {
1143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> tabs;
1144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
1145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (drag_data_[i].contents) {
1146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Contents is NULL if a tab was destroyed while the drag was under way.
1147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tabs.push_back(drag_data_[i].attached_tab);
1148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RevertDragAt(i);
1149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool restore_frame = attached_tabstrip_ != source_tabstrip_;
1153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (attached_tabstrip_ && attached_tabstrip_ == source_tabstrip_)
1154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    source_tabstrip_->StoppedDraggingTabs(tabs);
1155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  attached_tabstrip_ = source_tabstrip_;
1157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResetSelection(GetModel(attached_tabstrip_));
1159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If we're not attached to any TabStrip, or attached to some other TabStrip,
1161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // we need to restore the bounds of the original TabStrip's frame, in case
1162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // it has been hidden.
1163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (restore_frame) {
1164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!restore_bounds_.IsEmpty()) {
1165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
1166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      HWND frame_hwnd = source_tabstrip_->GetWidget()->GetNativeView();
1167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      MoveWindow(frame_hwnd, restore_bounds_.x(), restore_bounds_.y(),
1168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 restore_bounds_.width(), restore_bounds_.height(), TRUE);
1169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
1170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NOTIMPLEMENTED();
1171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
1172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::ResetSelection(TabStripModel* model) {
1177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(model);
1178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabStripSelectionModel selection_model;
1179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool has_one_valid_tab = false;
1180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
1181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // |contents| is NULL if a tab was deleted out from under us.
1182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (drag_data_[i].contents) {
1183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      int index = model->GetIndexOfTabContents(drag_data_[i].contents);
1184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      DCHECK_NE(-1, index);
1185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      selection_model.AddIndexToSelection(index);
1186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!has_one_valid_tab || i == source_tab_index_) {
1187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // Reset the active/lead to the first tab. If the source tab is still
1188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        // valid we'll reset these again later on.
1189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        selection_model.set_active(index);
1190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        selection_model.set_anchor(index);
1191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        has_one_valid_tab = true;
1192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
1193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!has_one_valid_tab)
1196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
1197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model->SetSelectionFromModel(selection_model);
1199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::RevertDragAt(size_t drag_index) {
1202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(started_drag_);
1203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TabDragData* data = &(drag_data_[drag_index]);
1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_) {
1206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int index =
1207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        GetModel(attached_tabstrip_)->GetIndexOfTabContents(data->contents);
1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (attached_tabstrip_ != source_tabstrip_) {
1209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The Tab was inserted into another TabStrip. We need to put it back
1210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // into the original one.
1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetModel(attached_tabstrip_)->DetachTabContentsAt(index);
1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(beng): (Cleanup) seems like we should use Attach() for this
1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //             somehow.
1214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetModel(source_tabstrip_)->InsertTabContentsAt(
1215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          data->source_model_index, data->contents,
1216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          (data->pinned ? TabStripModel::ADD_PINNED : 0));
1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The Tab was moved within the TabStrip where the drag was initiated.
1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Move it back to the starting location.
1220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetModel(source_tabstrip_)->MoveTabContentsAt(
1221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          index, data->source_model_index, false);
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The Tab was detached from the TabStrip where the drag began, and has not
1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // been attached to any other TabStrip. We need to put it back into the
1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // source TabStrip.
1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetModel(source_tabstrip_)->InsertTabContentsAt(
1228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        data->source_model_index, data->contents,
1229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        (data->pinned ? TabStripModel::ADD_PINNED : 0));
1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::CompleteDrag() {
1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(started_drag_);
1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (attached_tabstrip_) {
1237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    attached_tabstrip_->StoppedDraggingTabs(
1238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        GetTabsMatchingDraggedContents(attached_tabstrip_));
1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (dock_info_.type() != DockInfo::NONE) {
1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Profile* profile = GetModel(source_tabstrip_)->profile();
1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      switch (dock_info_.type()) {
1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::LEFT_OF_WINDOW:
1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Left"),
1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::RIGHT_OF_WINDOW:
1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Right"),
1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::BOTTOM_OF_WINDOW:
1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Bottom"),
1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::TOP_OF_WINDOW:
1259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Top"),
1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::MAXIMIZE:
1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_Maximize"),
1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::LEFT_HALF:
1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(UserMetricsAction("DockingWindow_LeftHalf"),
1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile);
1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::RIGHT_HALF:
1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(
1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              UserMetricsAction("DockingWindow_RightHalf"),
1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              profile);
1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case DockInfo::BOTTOM_HALF:
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UserMetrics::RecordAction(
1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              UserMetricsAction("DockingWindow_BottomHalf"),
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              profile);
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        default:
1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NOTREACHED();
1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Compel the model to construct a new window for the detached TabContents.
12913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    views::Window* window = source_tabstrip_->GetWindow();
12923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    gfx::Rect window_bounds(window->GetNormalBounds());
12933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    window_bounds.set_origin(GetWindowCreatePoint());
1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // When modifying the following if statement, please make sure not to
1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // introduce issue listed in http://crbug.com/6223 comment #11.
1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool rtl_ui = base::i18n::IsRTL();
1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_dock_position = (dock_info_.type() != DockInfo::NONE);
1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (rtl_ui && has_dock_position) {
1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Mirror X axis so the docked tab is aligned using the mouse click as
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // the top-right corner.
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      window_bounds.set_x(window_bounds.x() - window_bounds.width());
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* new_browser =
1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GetModel(source_tabstrip_)->delegate()->CreateNewStripWithContents(
1305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            drag_data_[0].contents, window_bounds, dock_info_,
1306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            window->IsMaximized());
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabStripModel* new_model = new_browser->tabstrip_model();
1308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    new_model->SetTabPinned(
1309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        new_model->GetIndexOfTabContents(drag_data_[0].contents),
1310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        drag_data_[0].pinned);
1311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 1; i < drag_data_.size(); ++i) {
1312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      new_model->InsertTabContentsAt(
1313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          static_cast<int>(i),
1314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          drag_data_[i].contents,
1315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          drag_data_[i].pinned ? TabStripModel::ADD_PINNED :
1316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                 TabStripModel::ADD_NONE);
1317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ResetSelection(new_browser->tabstrip_model());
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_browser->window()->Show();
1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CleanUpHiddenFrame();
1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::ResetDelegates() {
1326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
1327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (drag_data_[i].contents &&
1328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        drag_data_[i].contents->tab_contents()->delegate() == this) {
1329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      drag_data_[i].contents->tab_contents()->set_delegate(
1330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          drag_data_[i].original_delegate);
1331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DraggedTabController::CreateDraggedView(
1336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<TabRendererData>& data,
1337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<gfx::Rect>& renderer_bounds) {
1338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!view_.get());
1339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(data.size(), drag_data_.size());
1340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Set up the photo booth to start capturing the contents of the dragged
1342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TabContents.
1343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NativeViewPhotobooth* photobooth =
1344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NativeViewPhotobooth::Create(
1345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          source_dragged_contents()->tab_contents()->GetNativeView());
1346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect content_bounds;
1348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  source_dragged_contents()->tab_contents()->GetContainerBounds(
1349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &content_bounds);
1350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<views::View*> renderers;
1352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < drag_data_.size(); ++i) {
1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* renderer = source_tabstrip_->CreateTabForDragging();
1354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    renderer->SetData(data[i]);
1355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    renderers.push_back(renderer);
1356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // DraggedTabView takes ownership of the renderers.
1358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  view_.reset(new DraggedTabView(renderers, renderer_bounds, mouse_offset_,
1359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                 content_bounds.size(), photobooth));
1360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point DraggedTabController::GetCursorScreenPoint() const {
1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DWORD pos = GetMessagePos();
1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Point(pos);
1366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gint x, y;
1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Point(x, y);
1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect DraggedTabController::GetViewScreenBounds(views::View* view) const {
1374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point view_topleft;
1375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  views::View::ConvertPointToScreen(view, &view_topleft);
137672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  gfx::Rect view_screen_bounds = view->GetLocalBounds();
1377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  view_screen_bounds.Offset(view_topleft.x(), view_topleft.y());
1378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return view_screen_bounds;
1379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::HideFrame() {
1382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
1383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't actually hide the window, rather we just move it way off-screen.
1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we actually hide it, we stop receiving drag events.
1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HWND frame_hwnd = source_tabstrip_->GetWidget()->GetNativeView();
1386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RECT wr;
1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetWindowRect(frame_hwnd, &wr);
1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MoveWindow(frame_hwnd, 0xFFFF, 0xFFFF, wr.right - wr.left,
1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             wr.bottom - wr.top, TRUE);
1390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We also save the bounds of the window prior to it being moved, so that if
1392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the drag session is aborted we can restore them.
1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  restore_bounds_ = gfx::Rect(wr);
1394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
1395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTIMPLEMENTED();
1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
1397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::CleanUpHiddenFrame() {
1400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the model we started dragging from is now empty, we must ask the
1401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // delegate to close the frame.
1402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (GetModel(source_tabstrip_)->empty())
1403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetModel(source_tabstrip_)->delegate()->CloseFrameAfterDragSession();
1404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::DockDisplayerDestroyed(
1407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DockDisplayer* controller) {
1408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DockWindows::iterator dock_i =
1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      dock_windows_.find(controller->popup_view());
1410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dock_i != dock_windows_.end())
1411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_windows_.erase(dock_i);
1412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
1414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<DockDisplayer*>::iterator i =
1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::find(dock_controllers_.begin(), dock_controllers_.end(),
1417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                controller);
1418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i != dock_controllers_.end())
1419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_controllers_.erase(i);
1420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
1421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
1422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DraggedTabController::BringWindowUnderMouseToFront() {
1425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we're going to dock to another window, bring it to the front.
1426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::NativeWindow window = dock_info_.window();
1427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!window) {
1428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::NativeView dragged_view = view_->GetWidget()->GetNativeView();
1429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_windows_.insert(dragged_view);
1430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    window = DockInfo::GetLocalProcessWindowAtPoint(GetCursorScreenPoint(),
1431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                    dock_windows_);
1432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dock_windows_.erase(dragged_view);
1433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (window) {
1435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
1436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Move the window to the front.
1437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetWindowPos(window, HWND_TOP, 0, 0, 0, 0,
1438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The previous call made the window appear on top of the dragged window,
1441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // move the dragged window to the front.
1442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetWindowPos(view_->GetWidget()->GetNativeView(), HWND_TOP, 0, 0, 0, 0,
1443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
1445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
1446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
1447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1450c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabStripModel* DraggedTabController::GetModel(BaseTabStrip* tabstrip) const {
1451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return static_cast<BrowserTabStripController*>(tabstrip->controller())->
1452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model();
1453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DraggedTabController::AreTabsConsecutive() {
1456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 1; i < drag_data_.size(); ++i) {
1457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (drag_data_[i - 1].source_model_index + 1 !=
1458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        drag_data_[i].source_model_index) {
1459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return false;
1460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
1462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
1463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
1464