tab_drag_controller.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
11cf93952f404c0d786cd590799eb437ed6f3ae6eGordon Henriksen// Copyright (c) 2012 The Chromium Authors. All rights reserved. 28ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Use of this source code is governed by a BSD-style license that can be 38ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// found in the LICENSE file. 48ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 58ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/views/tabs/tab_drag_controller.h" 68ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 78ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include <math.h> 88ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include <set> 98ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 108ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "base/auto_reset.h" 118ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "base/callback.h" 128ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "base/command_line.h" 138ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "base/i18n/rtl.h" 14344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen#include "chrome/browser/chrome_notification_types.h" 158ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/profiles/profile.h" 164468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h" 174468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/browser_list.h" 188ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/browser_window.h" 194468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/media_utils.h" 205371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar#include "chrome/browser/ui/tabs/tab_strip_model.h" 218ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" 228ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/views/frame/browser_view.h" 234468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h" 248ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h" 254468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/views/tabs/tab.h" 264468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "chrome/browser/ui/views/tabs/tab_strip.h" 278ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/browser/ui/views/tabs/window_finder.h" 288ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "chrome/common/chrome_switches.h" 298ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "content/public/browser/invalidate_type.h" 304468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/notification_details.h" 314468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/notification_service.h" 324468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/notification_source.h" 334468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/notification_types.h" 344468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/user_metrics.h" 354468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/web_contents.h" 364468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "content/public/browser/web_contents_view.h" 374468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "extensions/browser/extension_function_dispatcher.h" 384468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "ui/aura/env.h" 394468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "ui/base/resource/resource_bundle.h" 408ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/events/event_constants.h" 418ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/events/event_utils.h" 424468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "ui/gfx/geometry/point_conversions.h" 434468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "ui/gfx/screen.h" 444468440a2a92fecd57f002b1b9c0683d2b9c4aeaGordon Henriksen#include "ui/views/focus/view_storage.h" 458ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/views/widget/root_view.h" 468ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/views/widget/widget.h" 478ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 488ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#if defined(USE_ASH) 498ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ash/accelerators/accelerator_commands.h" 508ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ash/wm/coordinate_conversion.h" 515371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar#include "ash/wm/window_state.h" 52d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen#include "ui/aura/env.h" 538ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/aura/window.h" 548ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#include "ui/aura/window_event_dispatcher.h" 55a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#include "ui/events/gestures/gesture_recognizer.h" 56a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#endif 57a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 58a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#if defined(OS_WIN) 59a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#include "ui/aura/window.h" 60a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#include "ui/events/gestures/gesture_recognizer.h" 61a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen#endif 62a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 63a353ffa7e556bfd2864474911174da691117f691Gordon Henriksenusing base::UserMetricsAction; 64a353ffa7e556bfd2864474911174da691117f691Gordon Henriksenusing content::OpenURLParams; 65a353ffa7e556bfd2864474911174da691117f691Gordon Henriksenusing content::WebContents; 66a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 67a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen// If non-null there is a drag underway. 68a353ffa7e556bfd2864474911174da691117f691Gordon Henriksenstatic TabDragController* instance_ = NULL; 69a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 70a353ffa7e556bfd2864474911174da691117f691Gordon Henriksennamespace { 71a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 72a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen// Delay, in ms, during dragging before we bring a window to front. 73a353ffa7e556bfd2864474911174da691117f691Gordon Henriksenconst int kBringToFrontDelay = 750; 748ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 758ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Initial delay before moving tabs when the dragged tab is close to the edge of 768ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// the stacked tabs. 778ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenconst int kMoveAttachedInitialDelay = 600; 788ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 798ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Delay for moving tabs after the initial delay has passed. 8046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenconst int kMoveAttachedSubsequentDelay = 300; 81404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen 828ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenconst int kHorizontalMoveThreshold = 16; // Pixels. 838ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 848ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Distance from the next/previous stacked before before we consider the tab 858ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// close enough to trigger moving. 8646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenconst int kStackedDistance = 36; 87404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen 888ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenvoid SetWindowPositionManaged(gfx::NativeWindow window, bool value) { 898ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#if defined(USE_ASH) 908ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen ash::wm::GetWindowState(window)->set_window_position_managed(value); 918ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#endif 9246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 938ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 948ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Returns true if |tab_strip| browser window is docked. 958ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenbool IsDockedOrSnapped(const TabStrip* tab_strip) { 968ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#if defined(USE_ASH) 97957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen DCHECK(tab_strip); 9846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen ash::wm::WindowState* window_state = 998ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen ash::wm::GetWindowState(tab_strip->GetWidget()->GetNativeWindow()); 1008ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return window_state->IsDocked() || window_state->IsSnapped(); 1018ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen#else 1028ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return false; 10346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen#endif 104404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen} 1058ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 1068ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// Returns true if |bounds| contains the y-coordinate |y|. The y-coordinate 1078ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// of |bounds| is adjusted by |vertical_adjustment|. 1088ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenbool DoesRectContainVerticalPointExpanded( 10946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Rect& bounds, 110404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen int vertical_adjustment, 1118ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen int y) { 1128ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen int upper_threshold = bounds.bottom() + vertical_adjustment; 1138ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen int lower_threshold = bounds.y() - vertical_adjustment; 1148ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return y >= lower_threshold && y <= upper_threshold; 115957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen} 11646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 117404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen// Adds |x_offset| to all the rectangles in |rects|. 1188ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenvoid OffsetX(int x_offset, std::vector<gfx::Rect>* rects) { 1198ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (x_offset == 0) 1208ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return; 1218ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 1228ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen for (size_t i = 0; i < rects->size(); ++i) 1238ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen (*rects)[i].set_x((*rects)[i].x() + x_offset); 124957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen} 125957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen 12646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen// WidgetObserver implementation that resets the window position managed 1278ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// property on Show. 1288ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// We're forced to do this here since BrowserFrameAsh resets the 'window 1298ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// position managed' property during a show and we need the property set to 1308ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// false before WorkspaceLayoutManager sees the visibility change. 1318ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenclass WindowPositionManagedUpdater : public views::WidgetObserver { 132957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen public: 13346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen virtual void OnWidgetVisibilityChanged(views::Widget* widget, 1348ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen bool visible) OVERRIDE { 1358ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen SetWindowPositionManaged(widget->GetNativeView(), false); 136404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen } 1378ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen}; 13857cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen 13957cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen// EscapeTracker installs itself as a pre-target handler on aura::Env and runs a 14057cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen// callback when it receives the escape key. 14157cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksenclass EscapeTracker : public ui::EventHandler { 14257cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen public: 14357cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen explicit EscapeTracker(const base::Closure& callback) 14457cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen : escape_callback_(callback) { 145404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen aura::Env::GetInstance()->AddPreTargetHandler(this); 14657cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen } 14757cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen 14857cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen virtual ~EscapeTracker() { 149ef989a275c1191f583178c6934f3594e7a9fd3a6Christopher Lamb aura::Env::GetInstance()->RemovePreTargetHandler(this); 15057cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen } 15157cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen 15257cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen private: 15357cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen // ui::EventHandler: 15457cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen virtual void OnKeyEvent(ui::KeyEvent* key) OVERRIDE { 15557cebeec7ba08b55f29f5bf98ad0a3a17e9d0c71Gordon Henriksen if (key->type() == ui::ET_KEY_PRESSED && 1568ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen key->key_code() == ui::VKEY_ESCAPE) { 1578ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen escape_callback_.Run(); 1588ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 1598ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 160957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen 16146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::Closure escape_callback_; 1628ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 1638ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen DISALLOW_COPY_AND_ASSIGN(EscapeTracker); 1648ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen}; 1658ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 1668ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} // namespace 1678ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 168957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon HenriksenTabDragController::TabDragData::TabDragData() 16946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen : contents(NULL), 1708ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen original_delegate(NULL), 171957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen source_model_index(-1), 17246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tab(NULL), 17346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen pinned(false) { 17446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 17546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 176957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon HenriksenTabDragController::TabDragData::~TabDragData() { 17746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 1781cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen 1791cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen/////////////////////////////////////////////////////////////////////////////// 1801cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen// TabDragController, public: 1811cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen 1821cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen// static 1831cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksenconst int TabDragController::kTouchVerticalDetachMagnetism = 50; 1841cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen 1851cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen// static 1861cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksenconst int TabDragController::kVerticalDetachMagnetism = 15; 1871cf08fddc7413076dedad58dbb8d8d67e69a490fGordon Henriksen 1881cf08fddc7413076dedad58dbb8d8d67e69a490fGordon HenriksenTabDragController::TabDragController() 1898ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen : detach_into_browser_(true), 1908ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen event_source_(EVENT_SOURCE_MOUSE), 191344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen source_tabstrip_(NULL), 192344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen attached_tabstrip_(NULL), 193344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen screen_(NULL), 194344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE), 195344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen use_aura_capture_policy_(false), 196344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen offset_to_width_ratio_(0), 197e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen old_focused_view_id_( 198344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen views::ViewStorage::GetInstance()->CreateStorageID()), 199344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen last_move_screen_loc_(0), 200344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen started_drag_(false), 201344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen active_(true), 202344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen source_tab_index_(std::numeric_limits<size_t>::max()), 203344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen initial_move_(true), 204344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen detach_behavior_(DETACHABLE), 205e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen move_behavior_(REORDER), 206344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen mouse_move_direction_(0), 207344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen is_dragging_window_(false), 208344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen is_dragging_new_browser_(false), 209344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen was_source_maximized_(false), 210344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen was_source_fullscreen_(false), 211344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen did_restore_window_(false), 212e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen end_run_loop_behavior_(END_RUN_LOOP_STOP_DRAGGING), 213344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen waiting_for_run_loop_to_exit_(false), 214344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen tab_strip_to_attach_to_after_exit_(NULL), 215344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen move_loop_widget_(NULL), 21645d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar is_mutating_(false), 21745d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar attach_x_(-1), 21845d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar attach_index_(-1), 21945d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar weak_factory_(this) { 22045d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar instance_ = this; 22145d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar} 22245d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar 223344be5fbecec9908bab611eafeae0549ba3be6d7Gordon HenriksenTabDragController::~TabDragController() { 224344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen views::ViewStorage::GetInstance()->RemoveView(old_focused_view_id_); 225344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 226e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen if (instance_ == this) 227344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen instance_ = NULL; 228957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen 229344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen if (move_loop_widget_) { 230344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen move_loop_widget_->RemoveObserver(this); 231344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen SetWindowPositionManaged(move_loop_widget_->GetNativeView(), true); 232e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen } 233e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen 234344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen if (source_tabstrip_ && detach_into_browser_) 235957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen GetModel(source_tabstrip_)->RemoveObserver(this); 236344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 237e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen // Reset the delegate of the dragged WebContents. This ends up doing nothing 238e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen // if the drag was completed. 23945d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar if (!detach_into_browser_) 240e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen ResetDelegates(); 241e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen 242e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen if (event_source_ == EVENT_SOURCE_TOUCH) { 243e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen TabStrip* capture_tabstrip = (attached_tabstrip_ && detach_into_browser_) ? 244e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen attached_tabstrip_ : source_tabstrip_; 245e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen capture_tabstrip->GetWidget()->ReleaseCapture(); 246e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen } 247e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen} 24845d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar 24945d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaarvoid TabDragController::Init( 25045d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar TabStrip* source_tabstrip, 25145d6ac2cc13f7881687c2d7f03f9b9892fd85e6eErick Tryzelaar Tab* source_tab, 252e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen const std::vector<Tab*>& tabs, 253e62a8a353c3b21b551c00b9025800d3352e5349eGordon Henriksen const gfx::Point& mouse_offset, 254344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen int source_tab_offset, 255e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen const ui::ListSelectionModel& initial_selection_model, 256e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen DetachBehavior detach_behavior, 257e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen MoveBehavior move_behavior, 258e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen EventSource event_source) { 259344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen DCHECK(!tabs.empty()); 260dce5e74162e7ad16dc787057941a7b9147a70117Daniel Dunbar DCHECK(std::find(tabs.begin(), tabs.end(), source_tab) != tabs.end()); 261344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen source_tabstrip_ = source_tabstrip; 262344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen was_source_maximized_ = source_tabstrip->GetWidget()->IsMaximized(); 263e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen was_source_fullscreen_ = source_tabstrip->GetWidget()->IsFullscreen(); 264344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen screen_ = gfx::Screen::GetScreenFor( 265957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen source_tabstrip->GetWidget()->GetNativeView()); 266344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen host_desktop_type_ = chrome::GetHostDesktopTypeForNativeView( 267dce5e74162e7ad16dc787057941a7b9147a70117Daniel Dunbar source_tabstrip->GetWidget()->GetNativeView()); 268344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen#if defined(OS_LINUX) 269344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen use_aura_capture_policy_ = true; 270e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen#else 271e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen use_aura_capture_policy_ = 272344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen (host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH); 273957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen#endif 2745371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar start_point_in_screen_ = gfx::Point(source_tab_offset, mouse_offset.y()); 275890484984bd0d3a5f9d80808b0d251424c7ddf7aChris Lattner views::View::ConvertPointToScreen(source_tab, &start_point_in_screen_); 276344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen event_source_ = event_source; 277344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen mouse_offset_ = mouse_offset; 2785371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar detach_behavior_ = detach_behavior; 279344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen move_behavior_ = move_behavior; 2805371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar last_point_in_screen_ = start_point_in_screen_; 281344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen last_move_screen_loc_ = start_point_in_screen_.x(); 282344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen initial_tab_positions_ = source_tabstrip->GetTabXCoordinates(); 283344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen if (detach_behavior == NOT_DETACHABLE) 284344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen detach_into_browser_ = false; 285344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 2865371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar if (detach_into_browser_) 2875371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar GetModel(source_tabstrip_)->AddObserver(this); 288344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 289344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen drag_data_.resize(tabs.size()); 290344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen for (size_t i = 0; i < tabs.size(); ++i) 291344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen InitTabDragData(tabs[i], &(drag_data_[i])); 292344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen source_tab_index_ = 293e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen std::find(tabs.begin(), tabs.end(), source_tab) - tabs.begin(); 294344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 295344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen // Listen for Esc key presses. 296344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen escape_tracker_.reset( 297344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen new EscapeTracker(base::Bind(&TabDragController::EndDrag, 298344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen weak_factory_.GetWeakPtr(), 299e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen END_DRAG_CANCEL))); 300344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen 301344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen if (source_tab->width() > 0) { 3024647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen offset_to_width_ratio_ = static_cast<float>( 3034647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen source_tab->GetMirroredXInView(source_tab_offset)) / 3044647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen static_cast<float>(source_tab->width()); 3054647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen } 3064647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen InitWindowCreatePoint(); 3074647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen initial_selection_model_.Copy(initial_selection_model); 3084647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3094647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen // Gestures don't automatically do a capture. We don't allow multiple drags at 3104647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen // the same time, so we explicitly capture. 3114647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (event_source == EVENT_SOURCE_TOUCH) 3124647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen source_tabstrip_->GetWidget()->SetCapture(source_tabstrip_); 3134647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen} 3144647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3154647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen// static 3164647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksenbool TabDragController::IsAttachedTo(const TabStrip* tab_strip) { 3174647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return (instance_ && instance_->active() && 3184647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen instance_->attached_tabstrip() == tab_strip); 3194647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen} 3204647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3214647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen// static 322957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksenbool TabDragController::IsActive() { 323e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen return instance_ && instance_->active(); 3244647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen} 325e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen 3264647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksenvoid TabDragController::SetMoveBehavior(MoveBehavior behavior) { 3274647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (started_drag()) 3284647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return; 3294647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3304647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen move_behavior_ = behavior; 3314647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen} 3324647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3334647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksenvoid TabDragController::Drag(const gfx::Point& point_in_screen) { 3344647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen TRACE_EVENT1("views", "TabDragController::Drag", 3354647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen "point_in_screen", point_in_screen.ToString()); 3364647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3374647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen bring_to_front_timer_.Stop(); 3384647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen move_stacked_timer_.Stop(); 3394647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3404647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (waiting_for_run_loop_to_exit_) 3414647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return; 342404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen 343404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen if (!started_drag_) { 3444647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (!CanStartDrag(point_in_screen)) 3454647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return; // User hasn't dragged far enough yet. 3464647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3474647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen // On windows SaveFocus() may trigger a capture lost, which destroys us. 3484647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen { 3494647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); 3504647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen SaveFocus(); 3514647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (!ref) 3524647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return; 3534647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen } 3544647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen started_drag_ = true; 3554647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen Attach(source_tabstrip_, gfx::Point()); 3564647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (detach_into_browser_ && static_cast<int>(drag_data_.size()) == 3574647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen GetModel(source_tabstrip_)->count()) { 3584647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (was_source_maximized_ || was_source_fullscreen_) { 359957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen did_restore_window_ = true; 3604647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen // When all tabs in a maximized browser are dragged the browser gets 3614647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen // restored during the drag and maximized back when the drag ends. 3624647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen views::Widget* widget = GetAttachedBrowserWidget(); 3634647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen const int last_tabstrip_width = attached_tabstrip_->tab_area_width(); 3644647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(); 3654647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds); 3664647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen gfx::Rect new_bounds(CalculateDraggedBrowserBounds(source_tabstrip_, 3674647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen point_in_screen, 3684647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen &drag_bounds)); 3694647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen new_bounds.Offset(-widget->GetRestoredBounds().x() + 3704647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen point_in_screen.x() - 371957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen mouse_offset_.x(), 0); 372e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen widget->SetVisibilityChangedAnimationsEnabled(false); 3734647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen widget->Restore(); 3744647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen widget->SetBounds(new_bounds); 3754647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen AdjustBrowserAndTabBoundsForDrag(last_tabstrip_width, 3764647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen point_in_screen, 3774647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen &drag_bounds); 3784647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen widget->SetVisibilityChangedAnimationsEnabled(true); 3794647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen } 3804647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen RunMoveLoop(GetWindowOffset(point_in_screen)); 3814647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen return; 3824647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen } 3834647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen } 3844647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3854647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen ContinueDragging(point_in_screen); 386957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen} 3874647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 3884647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksenvoid TabDragController::EndDrag(EndDragReason reason) { 389404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen TRACE_EVENT0("views", "TabDragController::EndDrag"); 390e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen 391e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen // If we're dragging a window ignore capture lost since it'll ultimately 392e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen // trigger the move loop to end and we'll revert the drag when RunMoveLoop() 393e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen // finishes. 3944647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen if (reason == END_DRAG_CAPTURE_LOST && is_dragging_window_) 395e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen return; 3964647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen EndDragImpl(reason != END_DRAG_COMPLETE && source_tabstrip_ ? 3974647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen CANCELED : NORMAL); 398e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen} 3994647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksen 4004647569fe7706e76135a08ca0e5f90a447ccc5b4Gordon Henriksenvoid TabDragController::InitTabDragData(Tab* tab, 401e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen TabDragData* drag_data) { 402e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen TRACE_EVENT0("views", "TabDragController::InitTabDragData"); 403957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen drag_data->source_model_index = 404344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen source_tabstrip_->GetModelIndexOfTab(tab); 405344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen drag_data->contents = GetModel(source_tabstrip_)->GetWebContentsAt( 4068ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data->source_model_index); 4078ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data->pinned = source_tabstrip_->IsTabPinned(tab); 4088ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen registrar_.Add( 4098ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen this, 410e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 4118ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen content::Source<WebContents>(drag_data->contents)); 4128ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4138ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (!detach_into_browser_) { 4148ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data->original_delegate = drag_data->contents->GetDelegate(); 4158ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data->contents->SetDelegate(this); 4168ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 4178ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4188ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4198ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen/////////////////////////////////////////////////////////////////////////////// 4208ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// TabDragController, PageNavigator implementation: 4218ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4228ef426baa36639458f6777309db25c1768dc9c8aGordon HenriksenWebContents* TabDragController::OpenURLFromTab( 4238ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen WebContents* source, 424404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen const OpenURLParams& params) { 425404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen if (source_tab_drag_data()->original_delegate) { 4268ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen OpenURLParams forward_params = params; 4278ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (params.disposition == CURRENT_TAB) 4288ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen forward_params.disposition = NEW_WINDOW; 4298ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4308ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return source_tab_drag_data()->original_delegate->OpenURLFromTab( 4318ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen source, forward_params); 4328ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 4338ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return NULL; 4348ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4358ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4368ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen/////////////////////////////////////////////////////////////////////////////// 4378ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen// TabDragController, content::WebContentsDelegate implementation: 438404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen 439404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksenvoid TabDragController::NavigationStateChanged(const WebContents* source, 4408ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen unsigned changed_flags) { 4418ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (attached_tabstrip_ || 4428ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen changed_flags == content::INVALIDATE_TYPE_PAGE_ACTIONS) { 4438ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) { 4448ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (drag_data_[i].contents == source) { 4458ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // Pass the NavigationStateChanged call to the original delegate so 4468ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // that the title is updated. Do this only when we are attached as 4478ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // otherwise the Tab isn't in the TabStrip (except for page action 4488ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // updates). 4498ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data_[i].original_delegate->NavigationStateChanged(source, 4508ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen changed_flags); 4518ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen break; 4528ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 453e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen } 4548ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 4558ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4568ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4578ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenvoid TabDragController::AddNewContents(WebContents* source, 4586d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen WebContents* new_contents, 4598ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen WindowOpenDisposition disposition, 4608ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen const gfx::Rect& initial_pos, 4616d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen bool user_gesture, 4626d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen bool* was_blocked) { 4636d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen DCHECK_NE(CURRENT_TAB, disposition); 4646d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen 4656d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksen // Theoretically could be called while dragging if the page tries to 4668ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // spawn a window. Route this message back to the browser in most cases. 4678ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (source_tab_drag_data()->original_delegate) { 4688ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen source_tab_drag_data()->original_delegate->AddNewContents( 4698ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen source, new_contents, disposition, initial_pos, user_gesture, 4708ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen was_blocked); 4718ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen } 4728ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4738ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4748ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenbool TabDragController::ShouldSuppressDialogs() { 4758ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // When a dialog is about to be shown we revert the drag. Otherwise a modal 4768ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // dialog might appear and attempt to parent itself to a hidden tabcontents. 4778ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen EndDragImpl(CANCELED); 4788ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return false; 4798ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4808ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4818ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksencontent::JavaScriptDialogManager* 4828ef426baa36639458f6777309db25c1768dc9c8aGordon HenriksenTabDragController::GetJavaScriptDialogManager() { 4838ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen return GetJavaScriptDialogManagerInstance(); 4848ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen} 4858ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 4868ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksenvoid TabDragController::RequestMediaAccessPermission( 487344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen content::WebContents* web_contents, 4888ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen const content::MediaStreamRequest& request, 489c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen const content::MediaResponseCallback& callback) { 490c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen ::RequestMediaAccessPermission( 491c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen web_contents, 492c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen Profile::FromBrowserContext(web_contents->GetBrowserContext()), 493c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen request, 494c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen callback); 495c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen} 496c84c16be9b29b4f805b92bfc2d93e2dfaa952f8fGordon Henriksen 4974733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen/////////////////////////////////////////////////////////////////////////////// 4984733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen// TabDragController, content::NotificationObserver implementation: 4994733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 5005371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaarvoid TabDragController::Observe( 5014733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen int type, 5024733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen const content::NotificationSource& source, 5034733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen const content::NotificationDetails& details) { 5044733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type); 5054733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen WebContents* destroyed_web_contents = 5064733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen content::Source<WebContents>(source).ptr(); 5074733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) { 5084733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (drag_data_[i].contents == destroyed_web_contents) { 5094733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // One of the tabs we're dragging has been destroyed. Cancel the drag. 5104733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (destroyed_web_contents->GetDelegate() == this) 5114733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen destroyed_web_contents->SetDelegate(NULL); 5124733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen drag_data_[i].contents = NULL; 5134733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen drag_data_[i].original_delegate = NULL; 5144733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen EndDragImpl(TAB_DESTROYED); 5154733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen return; 5164733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 5174733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 5184733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // If we get here it means we got notification for a tab we don't know about. 5194733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen NOTREACHED(); 5204733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen} 5214733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 5224733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksenvoid TabDragController::OnWidgetBoundsChanged(views::Widget* widget, 5234733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen const gfx::Rect& new_bounds) { 5248ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen TRACE_EVENT1("views", "TabDragController::OnWidgetBoundsChanged", 5258ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen "new_bounds", new_bounds.ToString()); 52646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 52746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen Drag(GetCursorScreenPoint()); 52846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 529957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen 5306d6203dff3560a2cc3ac8ec620ac3b105b0c7cc7Gordon Henriksenvoid TabDragController::TabStripEmpty() { 53146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK(detach_into_browser_); 53246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen GetModel(source_tabstrip_)->RemoveObserver(this); 53346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // NULL out source_tabstrip_ so that we don't attempt to add back to it (in 534dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // the case of a revert). 535dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen source_tabstrip_ = NULL; 536dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen} 537dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen 538dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen/////////////////////////////////////////////////////////////////////////////// 539dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen// TabDragController, private: 540dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen 541dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksenvoid TabDragController::InitWindowCreatePoint() { 542dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // window_create_point_ is only used in CompleteDrag() (through 543dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // GetWindowCreatePoint() to get the start point of the docked window) when 544dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // the attached_tabstrip_ is NULL and all the window's related bound 545dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // information are obtained from source_tabstrip_. So, we need to get the 546dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // first_tab based on source_tabstrip_, not attached_tabstrip_. Otherwise, 54746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // the window_create_point_ is not in the correct coordinate system. Please 54846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // refer to http://crbug.com/6223 comment #15 for detailed information. 54946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::View* first_tab = source_tabstrip_->tab_at(0); 55046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::View::ConvertPointToWidget(first_tab, &first_source_tab_point_); 55146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen window_create_point_ = first_source_tab_point_; 55246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen window_create_point_.Offset(mouse_offset_.x(), mouse_offset_.y()); 55346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 55446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 55546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksengfx::Point TabDragController::GetWindowCreatePoint( 55646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& origin) const { 55746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // If the cursor is outside the monitor area, move it inside. For example, 55846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // dropping a tab onto the task bar on Windows produces this situation. 55946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Rect work_area = screen_->GetDisplayNearestPoint(origin).work_area(); 5605371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar gfx::Point create_point(origin); 56146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!work_area.IsEmpty()) { 56246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (create_point.x() < work_area.x()) 56346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen create_point.set_x(work_area.x()); 56446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen else if (create_point.x() > work_area.right()) 56546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen create_point.set_x(work_area.right()); 56646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (create_point.y() < work_area.y()) 56746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen create_point.set_y(work_area.y()); 56846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen else if (create_point.y() > work_area.bottom()) 56946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen create_point.set_y(work_area.bottom()); 57046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 57146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return gfx::Point(create_point.x() - window_create_point_.x(), 57246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen create_point.y() - window_create_point_.y()); 57346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 5745371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar 57546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenvoid TabDragController::SaveFocus() { 57646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK(source_tabstrip_); 57746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::View* focused_view = 57846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen source_tabstrip_->GetFocusManager()->GetFocusedView(); 57946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (focused_view) 5801475142b93a618da72ec471e5ad7c1510c2feb37Gordon Henriksen views::ViewStorage::GetInstance()->StoreView(old_focused_view_id_, 5811475142b93a618da72ec471e5ad7c1510c2feb37Gordon Henriksen focused_view); 5821475142b93a618da72ec471e5ad7c1510c2feb37Gordon Henriksen source_tabstrip_->GetFocusManager()->SetFocusedView(source_tabstrip_); 5835371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // WARNING: we may have been deleted. 58480a75bfae980df96f969f1c05b0c4a80ce975240Gordon Henriksen} 5855eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen 58680a75bfae980df96f969f1c05b0c4a80ce975240Gordon Henriksenvoid TabDragController::RestoreFocus() { 58780a75bfae980df96f969f1c05b0c4a80ce975240Gordon Henriksen if (attached_tabstrip_ != source_tabstrip_) { 58880a75bfae980df96f969f1c05b0c4a80ce975240Gordon Henriksen if (is_dragging_new_browser_) { 5895eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen content::WebContents* active_contents = source_dragged_contents(); 5905eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen if (active_contents && !active_contents->FocusLocationBarByDefault()) 5915eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen active_contents->GetView()->Focus(); 5925eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen } 5935eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen return; 5945eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen } 5955371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar views::View* old_focused_view = 5964733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen views::ViewStorage::GetInstance()->RetrieveView(old_focused_view_id_); 5974733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (!old_focused_view) 5984733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen return; 5995371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar old_focused_view->GetFocusManager()->SetFocusedView(old_focused_view); 6004733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen} 6014733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6024733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksenbool TabDragController::CanStartDrag(const gfx::Point& point_in_screen) const { 6034733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // Determine if the mouse has moved beyond a minimum elasticity distance in 6044733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // any direction from the starting point. 6054733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen static const int kMinimumDragDistance = 10; 6064733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen int x_offset = abs(point_in_screen.x() - start_point_in_screen_.x()); 6074733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen int y_offset = abs(point_in_screen.y() - start_point_in_screen_.y()); 6084733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen return sqrt(pow(static_cast<float>(x_offset), 2) + 6094733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen pow(static_cast<float>(y_offset), 2)) > kMinimumDragDistance; 6104733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen} 6114733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6124733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksenvoid TabDragController::ContinueDragging(const gfx::Point& point_in_screen) { 6134733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen TRACE_EVENT1("views", "TabDragController::ContinueDragging", 6144733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen "point_in_screen", point_in_screen.ToString()); 6154733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6164733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen DCHECK(!detach_into_browser_ || attached_tabstrip_); 6174733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6184733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen TabStrip* target_tabstrip = detach_behavior_ == DETACHABLE ? 6194733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen GetTargetTabStripForPoint(point_in_screen) : source_tabstrip_; 6204733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen bool tab_strip_changed = (target_tabstrip != attached_tabstrip_); 6214733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6224733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (attached_tabstrip_) { 6234733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen int move_delta = point_in_screen.x() - last_point_in_screen_.x(); 6244733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (move_delta > 0) 6254733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen mouse_move_direction_ |= kMovedMouseRight; 6264733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen else if (move_delta < 0) 6274733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen mouse_move_direction_ |= kMovedMouseLeft; 6284733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 6295371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar last_point_in_screen_ = point_in_screen; 6304733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6314733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (tab_strip_changed) { 6324733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen is_dragging_new_browser_ = false; 6334733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen did_restore_window_ = false; 6344733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (detach_into_browser_ && 6354733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen DragBrowserToNewTabStrip(target_tabstrip, point_in_screen) == 6364733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen DRAG_BROWSER_RESULT_STOP) { 6374733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen return; 6384733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } else if (!detach_into_browser_) { 6394733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (attached_tabstrip_) 6404733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen Detach(RELEASE_CAPTURE); 6414733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (target_tabstrip) 642e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands Attach(target_tabstrip, point_in_screen); 643e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands } 644e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands } 645e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands if (is_dragging_window_) { 646e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands static_cast<base::Timer*>(&bring_to_front_timer_)->Start(FROM_HERE, 647e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands base::TimeDelta::FromMilliseconds(kBringToFrontDelay), 648e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands base::Bind(&TabDragController::BringWindowUnderPointToFront, 6494733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen base::Unretained(this), point_in_screen)); 6504733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 6514733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 6524733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (!is_dragging_window_ && attached_tabstrip_) { 6534733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (move_only()) { 6544733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen DragActiveTabStacked(point_in_screen); 6554733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } else { 6564733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen MoveAttached(point_in_screen); 6574733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (tab_strip_changed) { 6584733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // Move the corresponding window to the front. We do this after the 6594733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // move as on windows activate triggers a synchronous paint. 6604733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen attached_tabstrip_->GetWidget()->Activate(); 6614733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 6624733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 6634733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 66480a75bfae980df96f969f1c05b0c4a80ce975240Gordon Henriksen} 66546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 66646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon HenriksenTabDragController::DragBrowserResultType 66746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon HenriksenTabDragController::DragBrowserToNewTabStrip( 66846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TabStrip* target_tabstrip, 66946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& point_in_screen) { 670957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen TRACE_EVENT1("views", "TabDragController::DragBrowserToNewTabStrip", 67146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen "point_in_screen", point_in_screen.ToString()); 67246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 67346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!target_tabstrip) { 67446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DetachIntoNewBrowserAndRunMoveLoop(point_in_screen); 67546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return DRAG_BROWSER_RESULT_STOP; 67646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 67746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (is_dragging_window_) { 6785371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // ReleaseCapture() is going to result in calling back to us (because it 67946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // results in a move). That'll cause all sorts of problems. Reset the 68046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // observer so we don't get notified and process the event. 68146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (use_aura_capture_policy_) { 68246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen move_loop_widget_->RemoveObserver(this); 68346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen move_loop_widget_ = NULL; 68446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 68546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::Widget* browser_widget = GetAttachedBrowserWidget(); 68646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Need to release the drag controller before starting the move loop as it's 68746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // going to trigger capture lost, which cancels drag. 68846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tabstrip_->ReleaseDragController(); 6892618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen target_tabstrip->OwnDragController(this); 6902618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen // Disable animations so that we don't see a close animation on aero. 69146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen browser_widget->SetVisibilityChangedAnimationsEnabled(false); 6925371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // For aura we can't release capture, otherwise it'll cancel a gesture. 6935371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // Instead we have to directly change capture. 69446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (use_aura_capture_policy_) 69546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_); 69646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen else 69746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen browser_widget->ReleaseCapture(); 69846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen#if defined(OS_WIN) 69946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // The Gesture recognizer does not work well currently when capture changes 7005371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // while a touch gesture is in progress. So we need to manually transfer 70146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // gesture sequence and the GR's touch events queue to the new window. This 70246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // should really be done somewhere in capture change code and or inside the 70346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // GR. But we currently do not have a consistent way for doing it that would 70446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // work in all cases. Hence this hack. 70546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen ui::GestureRecognizer::Get()->TransferEventsTo( 70646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen browser_widget->GetNativeView(), 70746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen target_tabstrip->GetWidget()->GetNativeView()); 7085371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar#endif 70946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 71046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // The window is going away. Since the drag is still on going we don't want 7114733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // that to effect the position of any windows. 7124733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen SetWindowPositionManaged(browser_widget->GetNativeView(), false); 7134733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 7145371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar#if !defined(OS_LINUX) || defined(OS_CHROMEOS) 7154733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // EndMoveLoop is going to snap the window back to its original location. 7164733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // Hide it so users don't see this. Hiding a window in Linux aura causes 7174733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // it to lose capture so skip it. 7184733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen browser_widget->Hide(); 7194733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen#endif 7204733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen browser_widget->EndMoveLoop(); 7214733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 7224733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // Ideally we would always swap the tabs now, but on non-ash it seems that 7234733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // running the move loop implicitly activates the window when done, leading 7244733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // to all sorts of flicker. So, on non-ash, instead we process the move 7254733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // after the loop completes. But on chromeos, we can do tab swapping now to 7264733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // avoid the tab flashing issue(crbug.com/116329). 7274733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen if (use_aura_capture_policy_) { 7284733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen is_dragging_window_ = false; 7294733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen Detach(DONT_RELEASE_CAPTURE); 7304733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen Attach(target_tabstrip, point_in_screen); 7314733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen // Move the tabs into position. 7324733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen MoveAttached(point_in_screen); 7334733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen attached_tabstrip_->GetWidget()->Activate(); 7344733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } else { 7354733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen tab_strip_to_attach_to_after_exit_ = target_tabstrip; 7364733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen } 7374733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen 7384733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen waiting_for_run_loop_to_exit_ = true; 73946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen end_run_loop_behavior_ = END_RUN_LOOP_CONTINUE_DRAGGING; 74046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return DRAG_BROWSER_RESULT_STOP; 7411d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen } 7421d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen Detach(DONT_RELEASE_CAPTURE); 7431d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen Attach(target_tabstrip, point_in_screen); 7441d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen return DRAG_BROWSER_RESULT_CONTINUE; 7455371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar} 7461d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7471d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksenvoid TabDragController::DragActiveTabStacked( 7481d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen const gfx::Point& point_in_screen) { 7495371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar if (attached_tabstrip_->tab_count() != 7501d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen static_cast<int>(initial_tab_positions_.size())) 7511d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen return; // TODO: should cancel drag if this happens. 7521d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7531d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen int delta = point_in_screen.x() - start_point_in_screen_.x(); 7541d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen attached_tabstrip_->DragActiveTab(initial_tab_positions_, delta); 7551d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen} 7561d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7571d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksenvoid TabDragController::MoveAttachedToNextStackedIndex( 7581d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen const gfx::Point& point_in_screen) { 7591d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen int index = attached_tabstrip_->touch_layout_->active_index(); 7601d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen if (index + 1 >= attached_tabstrip_->tab_count()) 7611d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen return; 7621d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7631d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen GetModel(attached_tabstrip_)->MoveSelectedTabsTo(index + 1); 7641d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen StartMoveStackedTimerIfNecessary(point_in_screen, 7651d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen kMoveAttachedSubsequentDelay); 7661d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen} 7671d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7681d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksenvoid TabDragController::MoveAttachedToPreviousStackedIndex( 7691d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen const gfx::Point& point_in_screen) { 7701d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen int index = attached_tabstrip_->touch_layout_->active_index(); 7711d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen if (index <= attached_tabstrip_->GetMiniTabCount()) 7721d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen return; 7731d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 7741d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen GetModel(attached_tabstrip_)->MoveSelectedTabsTo(index - 1); 77546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen StartMoveStackedTimerIfNecessary(point_in_screen, 77646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen kMoveAttachedSubsequentDelay); 77746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 77846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 77946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenvoid TabDragController::MoveAttached(const gfx::Point& point_in_screen) { 780dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen DCHECK(attached_tabstrip_); 781dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen DCHECK(!is_dragging_window_); 7825371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar 783dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen gfx::Point dragged_view_point = GetAttachedDragPoint(point_in_screen); 784dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen 785dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // Determine the horizontal move threshold. This is dependent on the width 786dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // of tabs. The smaller the tabs compared to the standard size, the smaller 787dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // the threshold. 788dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen int threshold = kHorizontalMoveThreshold; 789dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen if (!attached_tabstrip_->touch_layout_.get()) { 7905371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar double unselected, selected; 791dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen attached_tabstrip_->GetCurrentTabWidths(&unselected, &selected); 792dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen double ratio = unselected / Tab::GetStandardSize().width(); 793dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen threshold = static_cast<int>(ratio * kHorizontalMoveThreshold); 794dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen } 795dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen // else case: touch tabs never shrink. 796dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen 797dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen std::vector<Tab*> tabs(drag_data_.size()); 798dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) 799dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen tabs[i] = drag_data_[i].attached_tab; 800dc1ce7bdc6e32e7a4c4a110caa32834730183c1bGordon Henriksen 80146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen bool did_layout = false; 80246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Update the model, moving the WebContents from one index to another. Do this 80346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // only if we have moved a minimum distance since the last reorder (to prevent 80446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // jitter) or if this the first move and the tabs are not consecutive. 805957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen if ((abs(point_in_screen.x() - last_move_screen_loc_) > threshold || 80646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen (initial_move_ && !AreTabsConsecutive()))) { 8075371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar TabStripModel* attached_model = GetModel(attached_tabstrip_); 80846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point); 80946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen int to_index = GetInsertionIndexForDraggedBounds(bounds); 81046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen bool do_move = true; 81146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // While dragging within a tabstrip the expectation is the insertion index 812957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen // is based on the left edge of the tabs being dragged. OTOH when dragging 81346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // into a new tabstrip (attaching) the expectation is the insertion index is 8145371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // based on the cursor. This proves problematic as insertion may change the 81546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // size of the tabs, resulting in the index calculated before the insert 81646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // differing from the index calculated after the insert. To alleviate this 81746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // the index is chosen before insertion, and subsequently a new index is 81846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // only used once the mouse moves enough such that the index changes based 81946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // on the direction the mouse moved relative to |attach_x_| (smaller 82046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // x-coordinate should yield a smaller index or larger x-coordinate yields a 8215371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // larger index). 82246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (attach_index_ != -1) { 82346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Point tab_strip_point(point_in_screen); 82446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::View::ConvertPointFromScreen(attached_tabstrip_, &tab_strip_point); 82546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const int new_x = 82646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tabstrip_->GetMirroredXInView(tab_strip_point.x()); 82746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (new_x < attach_x_) 82846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen to_index = std::min(to_index, attach_index_); 82946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen else 83046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen to_index = std::max(to_index, attach_index_); 83146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (to_index != attach_index_) 83246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attach_index_ = -1; // Once a valid move is detected, don't constrain. 83346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen else 8345371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar do_move = false; 83546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 83646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (do_move) { 83746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen WebContents* last_contents = drag_data_[drag_data_.size() - 1].contents; 83846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen int index_of_last_item = 83946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_model->GetIndexOfWebContents(last_contents); 84046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (initial_move_) { 84146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // TabStrip determines if the tabs needs to be animated based on model 8425371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // position. This means we need to invoke LayoutDraggedTabsAt before 84346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // changing the model. 84446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tabstrip_->LayoutDraggedTabsAt( 84546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen tabs, source_tab_drag_data()->attached_tab, dragged_view_point, 84646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen initial_move_); 84721491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen did_layout = true; 84821491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen } 84921491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen attached_model->MoveSelectedTabsTo(to_index); 85021491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen 85121491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen // Move may do nothing in certain situations (such as when dragging pinned 85221491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen // tabs). Make sure the tabstrip actually changed before updating 8535371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // last_move_screen_loc_. 85421491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen if (index_of_last_item != 8555371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar attached_model->GetIndexOfWebContents(last_contents)) { 8565371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar last_move_screen_loc_ = point_in_screen.x(); 85721491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen } 85821491edbf4027df4db559eb1a9aa8fbf3779cfabGordon Henriksen } 85946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 86046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 86146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!did_layout) { 86246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tabstrip_->LayoutDraggedTabsAt( 86346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen tabs, source_tab_drag_data()->attached_tab, dragged_view_point, 86446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen initial_move_); 8655371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar } 86646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 86746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen StartMoveStackedTimerIfNecessary(point_in_screen, kMoveAttachedInitialDelay); 86846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 86946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen initial_move_ = false; 87046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 87146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 87246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenvoid TabDragController::StartMoveStackedTimerIfNecessary( 8735371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar const gfx::Point& point_in_screen, 87446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen int delay_ms) { 87546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK(attached_tabstrip_); 87646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 87746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen StackedTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get(); 87846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!touch_layout) 87946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return; 88046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 8815371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar gfx::Point dragged_view_point = GetAttachedDragPoint(point_in_screen); 88246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Rect bounds = GetDraggedViewTabStripBounds(dragged_view_point); 88346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen int index = touch_layout->active_index(); 88446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (ShouldDragToNextStackedTab(bounds, index)) { 88546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen static_cast<base::Timer*>(&move_stacked_timer_)->Start( 88646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen FROM_HERE, 8875371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar base::TimeDelta::FromMilliseconds(delay_ms), 88846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::Bind(&TabDragController::MoveAttachedToNextStackedIndex, 88946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::Unretained(this), point_in_screen)); 89046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } else if (ShouldDragToPreviousStackedTab(bounds, index)) { 89146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen static_cast<base::Timer*>(&move_stacked_timer_)->Start( 89246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen FROM_HERE, 89346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::TimeDelta::FromMilliseconds(delay_ms), 89446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::Bind(&TabDragController::MoveAttachedToPreviousStackedIndex, 89546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::Unretained(this), point_in_screen)); 89646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 89746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 89846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 89946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon HenriksenTabDragController::DetachPosition TabDragController::GetDetachPosition( 90046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& point_in_screen) { 90146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK(attached_tabstrip_); 90246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Point attached_point(point_in_screen); 90346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen views::View::ConvertPointFromScreen(attached_tabstrip_, &attached_point); 90446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (attached_point.x() < 0) 90546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return DETACH_BEFORE; 90646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (attached_point.x() >= attached_tabstrip_->width()) 90746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return DETACH_AFTER; 90846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return DETACH_ABOVE_OR_BELOW; 90946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 91046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 91146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon HenriksenTabStrip* TabDragController::GetTargetTabStripForPoint( 91246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& point_in_screen) { 91346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TRACE_EVENT1("views", "TabDragController::GetTargetTabStripForPoint", 91446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen "point_in_screen", point_in_screen.ToString()); 91546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 91646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (move_only() && attached_tabstrip_) { 91746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK_EQ(DETACHABLE, detach_behavior_); 91846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // move_only() is intended for touch, in which case we only want to detach 91946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // if the touch point moves significantly in the vertical distance. 92046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Rect tabstrip_bounds = GetViewScreenBounds(attached_tabstrip_); 92146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (DoesRectContainVerticalPointExpanded(tabstrip_bounds, 92246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen kTouchVerticalDetachMagnetism, 9232618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen point_in_screen.y())) 9242618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen return attached_tabstrip_; 92546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 92646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::NativeWindow local_window = 92746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen GetLocalProcessWindow(point_in_screen, is_dragging_window_); 92846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TabStrip* tab_strip = GetTabStripForWindow(local_window); 9295371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar if (tab_strip && DoesTabStripContain(tab_strip, point_in_screen)) 93046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return tab_strip; 9316b018979da52c9760363b8b74951bbe259044ea8Dan Gohman return is_dragging_window_ ? attached_tabstrip_ : NULL; 93246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 9336b018979da52c9760363b8b74951bbe259044ea8Dan Gohman 93446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon HenriksenTabStrip* TabDragController::GetTabStripForWindow(gfx::NativeWindow window) { 93546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!window) 93646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return NULL; 93746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen BrowserView* browser_view = 93846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen BrowserView::GetBrowserViewForNativeWindow(window); 93946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // We don't allow drops on windows that don't have tabstrips. 94046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!browser_view || 94146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen !browser_view->browser()->SupportsWindowFeature( 94246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen Browser::FEATURE_TABSTRIP)) 94346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return NULL; 94446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 94546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TabStrip* other_tabstrip = browser_view->tabstrip(); 94646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TabStrip* tab_strip = 9472618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_; 9482618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen DCHECK(tab_strip); 94946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 95046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return other_tabstrip->controller()->IsCompatibleWith(tab_strip) ? 95146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen other_tabstrip : NULL; 952957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen} 95346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 95446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenbool TabDragController::DoesTabStripContain( 95546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TabStrip* tabstrip, 95646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& point_in_screen) const { 95746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Make sure the specified screen point is actually within the bounds of the 95846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // specified tabstrip... 95946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen gfx::Rect tabstrip_bounds = GetViewScreenBounds(tabstrip); 96046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen return point_in_screen.x() < tabstrip_bounds.right() && 96146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen point_in_screen.x() >= tabstrip_bounds.x() && 96246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DoesRectContainVerticalPointExpanded(tabstrip_bounds, 96346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen kVerticalDetachMagnetism, 96446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen point_in_screen.y()); 96546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen} 96646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 96746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksenvoid TabDragController::Attach(TabStrip* attached_tabstrip, 96846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen const gfx::Point& point_in_screen) { 96946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen TRACE_EVENT1("views", "TabDragController::Attach", 97046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen "point_in_screen", point_in_screen.ToString()); 97146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 97246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen DCHECK(!attached_tabstrip_); // We should already have detached by the time 97346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // we get here. 97446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 97546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen attached_tabstrip_ = attached_tabstrip; 97646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 97746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen std::vector<Tab*> tabs = 97846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen GetTabsMatchingDraggedContents(attached_tabstrip_); 97946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 98046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (tabs.empty()) { 98146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Transitioning from detached to attached to a new tabstrip. Add tabs to 98246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // the new model. 98346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 98446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen selection_model_before_attach_.Copy(attached_tabstrip->GetSelectionModel()); 98546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 98646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (!detach_into_browser_) { 987404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen // Remove ourselves as the delegate now that the dragged WebContents is 988404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen // being inserted back into a Browser. 989404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) { 990404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen drag_data_[i].contents->SetDelegate(NULL); 99146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen drag_data_[i].original_delegate = NULL; 99246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 99346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 994cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen // Return the WebContents to normalcy. 995cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen source_dragged_contents()->DecrementCapturerCount(); 99646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 99746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 99846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Inserting counts as a move. We don't want the tabs to jitter when the 99946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // user moves the tab immediately after attaching it. 10002618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen last_move_screen_loc_ = point_in_screen.x(); 100107cabf6102800aa701bc4d1bd282fafb63b8a416Gordon Henriksen 100246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Figure out where to insert the tab based on the bounds of the dragged 1003cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen // representation and the ideal bounds of the other Tabs already in the 1004cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen // strip. ("ideal bounds" are stable even if the Tabs' actual bounds are 1005cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen // changing due to animation). 1006cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen gfx::Point tab_strip_point(point_in_screen); 100707cabf6102800aa701bc4d1bd282fafb63b8a416Gordon Henriksen views::View::ConvertPointFromScreen(attached_tabstrip_, &tab_strip_point); 100807cabf6102800aa701bc4d1bd282fafb63b8a416Gordon Henriksen tab_strip_point.set_x( 100907cabf6102800aa701bc4d1bd282fafb63b8a416Gordon Henriksen attached_tabstrip_->GetMirroredXInView(tab_strip_point.x())); 1010e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands tab_strip_point.Offset(0, -mouse_offset_.y()); 1011e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands gfx::Rect bounds = GetDraggedViewTabStripBounds(tab_strip_point); 1012e149e9960ba0726f4b084763f7ef95afa12d9a88Duncan Sands int index = GetInsertionIndexForDraggedBounds(bounds); 1013cc0928ff22d9f3e8f2930874f6727db8c700ec35Gordon Henriksen attach_index_ = index; 1014404a1942e43ca967700cc2608eb97b863add2677Gordon Henriksen attach_x_ = tab_strip_point.x(); 101546abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen base::AutoReset<bool> setter(&is_mutating_, true); 101646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) { 1017957f9fe1cce0957bcde4a1093da83e17aaec6764Gordon Henriksen int add_types = TabStripModel::ADD_NONE; 101846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (attached_tabstrip_->touch_layout_.get()) { 101946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // StackedTabStripLayout positions relative to the active tab, if we 102046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // don't add the tab as active things bounce around. 10212618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen DCHECK_EQ(1u, drag_data_.size()); 10222618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen add_types |= TabStripModel::ADD_ACTIVE; 1023e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen } 1024e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen if (drag_data_[i].pinned) 1025e3b989d4a4ba47f77d5d38c35ff17e9673d9f87bGordon Henriksen add_types |= TabStripModel::ADD_PINNED; 102646abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen GetModel(attached_tabstrip_)->InsertWebContentsAt( 102746abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen index + i, drag_data_[i].contents, add_types); 102846abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 102946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen 103046abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen tabs = GetTabsMatchingDraggedContents(attached_tabstrip_); 10312618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen } 10322618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen DCHECK_EQ(tabs.size(), drag_data_.size()); 10332618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) 10342618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen drag_data_[i].attached_tab = tabs[i]; 10352618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen 10362618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen attached_tabstrip_->StartedDraggingTabs(tabs); 10372618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen 10382618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen ResetSelection(GetModel(attached_tabstrip_)); 10392618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen 10402618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen // The size of the dragged tab may have changed. Adjust the x offset so that 10415371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // ratio of mouse_offset_ to original width is maintained. 10425371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar std::vector<Tab*> tabs_to_source(tabs); 10435371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar tabs_to_source.erase(tabs_to_source.begin() + source_tab_index_ + 1, 10442618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen tabs_to_source.end()); 10452618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen int new_x = attached_tabstrip_->GetSizeNeededForTabs(tabs_to_source) - 10462618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen tabs[source_tab_index_]->width() + 10472618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen static_cast<int>(offset_to_width_ratio_ * 10482618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen tabs[source_tab_index_]->width()); 10492618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen mouse_offset_.set_x(new_x); 10502618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen 10512618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen // Transfer ownership of us to the new tabstrip as well as making sure the 105246abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // window has capture. This is important so that if activation changes the 105346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // drag isn't prematurely canceled. 105446abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen if (detach_into_browser_) { 10551ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen attached_tabstrip_->GetWidget()->SetCapture(attached_tabstrip_); 10561ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen attached_tabstrip_->OwnDragController(this); 10571ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen } 10585371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar 1059da1435f86ebc9886dd7704294e01d192d79e069cGordon Henriksen // Redirect all mouse events to the TabStrip so that the tab that originated 1060da1435f86ebc9886dd7704294e01d192d79e069cGordon Henriksen // the drag can safely be deleted. 10611ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen if (detach_into_browser_ || attached_tabstrip_ == source_tabstrip_) { 10621ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen static_cast<views::internal::RootView*>( 1063d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen attached_tabstrip_->GetWidget()->GetRootView())->SetMouseHandler( 1064d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen attached_tabstrip_); 1065d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen } 1066d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen} 1067d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 1068d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksenvoid TabDragController::Detach(ReleaseCapture release_capture) { 1069d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen TRACE_EVENT1("views", "TabDragController::Detach", 1070d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen "release_capture", release_capture); 1071d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 1072d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen attach_index_ = -1; 1073d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 1074d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen // When the user detaches we assume they want to reorder. 1075d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen move_behavior_ = REORDER; 1076d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 10775371aa2a1c9a4eeecffdb9ab7b2175732e49475bErick Tryzelaar // Release ownership of the drag controller and mouse capture. When we 1078d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen // reattach ownership is transfered. 1079d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen if (detach_into_browser_) { 1080d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen attached_tabstrip_->ReleaseDragController(); 1081d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen if (release_capture == RELEASE_CAPTURE) 1082d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen attached_tabstrip_->GetWidget()->ReleaseCapture(); 1083d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen } 1084d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 1085d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen mouse_move_direction_ = kMovedMouseLeft | kMovedMouseRight; 1086d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen 10878ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // Prevent the WebContents HWND from being hidden by any of the model 10888ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // operations performed during the drag. 10898ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen if (!detach_into_browser_) 10902618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen source_dragged_contents()->IncrementCapturerCount(gfx::Size()); 10912618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen 10922618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(); 10932618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen TabStripModel* attached_model = GetModel(attached_tabstrip_); 10942618a6c1122d5d2007787fb56156be44b21ab32aGordon Henriksen std::vector<TabRendererData> tab_data; 10958ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen for (size_t i = 0; i < drag_data_.size(); ++i) { 10968ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen tab_data.push_back(drag_data_[i].attached_tab->data()); 10978ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen int index = attached_model->GetIndexOfWebContents(drag_data_[i].contents); 1098d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen DCHECK_NE(-1, index); 10998ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 11008ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // Hide the tab so that the user doesn't see it animate closed. 11018ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data_[i].attached_tab->SetVisible(false); 11028ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 11038ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen attached_model->DetachWebContentsAt(index); 1104a353ffa7e556bfd2864474911174da691117f691Gordon Henriksen 11058ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen // Detaching resets the delegate, but we still want to be the delegate. 1106344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen if (!detach_into_browser_) 11078ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen drag_data_[i].contents->SetDelegate(this); 11088ef426baa36639458f6777309db25c1768dc9c8aGordon Henriksen 110946abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // Detaching may end up deleting the tab, drop references to it. 11104733be38930ae81716bba9ae75a8281bcb180634Gordon Henriksen drag_data_[i].attached_tab = NULL; 111146abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen } 11121d21395f4ce152e7bf14d9ba6ea23549de6badd4Gordon Henriksen 111346abf91f7378fb7bb118d66fe6d69b5d3af1e9d5Gordon Henriksen // If we've removed the last Tab from the TabStrip, hide the frame now. 11141ae6135fa37eb061499d079b9b33dc82dcc1283fGordon Henriksen if (!attached_model->empty()) { 1115d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen if (!selection_model_before_attach_.empty() && 1116d78c0f5a7255e4347cbd82f7435c51401096652cGordon Henriksen selection_model_before_attach_.active() >= 0 && 1117344be5fbecec9908bab611eafeae0549ba3be6d7Gordon Henriksen selection_model_before_attach_.active() < attached_model->count()) { 1118 // Restore the selection. 1119 attached_model->SetSelectionFromModel(selection_model_before_attach_); 1120 } else if (attached_tabstrip_ == source_tabstrip_ && 1121 !initial_selection_model_.empty()) { 1122 RestoreInitialSelection(); 1123 } 1124 } 1125 1126 attached_tabstrip_->DraggedTabsDetached(); 1127 attached_tabstrip_ = NULL; 1128} 1129 1130void TabDragController::DetachIntoNewBrowserAndRunMoveLoop( 1131 const gfx::Point& point_in_screen) { 1132 if (GetModel(attached_tabstrip_)->count() == 1133 static_cast<int>(drag_data_.size())) { 1134 // All the tabs in a browser are being dragged but all the tabs weren't 1135 // initially being dragged. For this to happen the user would have to 1136 // start dragging a set of tabs, the other tabs close, then detach. 1137 RunMoveLoop(GetWindowOffset(point_in_screen)); 1138 return; 1139 } 1140 1141 const int last_tabstrip_width = attached_tabstrip_->tab_area_width(); 1142 std::vector<gfx::Rect> drag_bounds = CalculateBoundsForDraggedTabs(); 1143 OffsetX(GetAttachedDragPoint(point_in_screen).x(), &drag_bounds); 1144 1145 gfx::Vector2d drag_offset; 1146 Browser* browser = CreateBrowserForDrag( 1147 attached_tabstrip_, point_in_screen, &drag_offset, &drag_bounds); 1148#if defined(OS_WIN) 1149 gfx::NativeView attached_native_view = 1150 attached_tabstrip_->GetWidget()->GetNativeView(); 1151#endif 1152 Detach(use_aura_capture_policy_ ? DONT_RELEASE_CAPTURE : RELEASE_CAPTURE); 1153 BrowserView* dragged_browser_view = 1154 BrowserView::GetBrowserViewForBrowser(browser); 1155 views::Widget* dragged_widget = dragged_browser_view->GetWidget(); 1156#if defined(OS_WIN) 1157 // The Gesture recognizer does not work well currently when capture changes 1158 // while a touch gesture is in progress. So we need to manually transfer 1159 // gesture sequence and the GR's touch events queue to the new window. This 1160 // should really be done somewhere in capture change code and or inside the 1161 // GR. But we currently do not have a consistent way for doing it that would 1162 // work in all cases. Hence this hack. 1163 ui::GestureRecognizer::Get()->TransferEventsTo( 1164 attached_native_view, 1165 dragged_widget->GetNativeView()); 1166#endif 1167 dragged_widget->SetVisibilityChangedAnimationsEnabled(false); 1168 Attach(dragged_browser_view->tabstrip(), gfx::Point()); 1169 AdjustBrowserAndTabBoundsForDrag(last_tabstrip_width, 1170 point_in_screen, 1171 &drag_bounds); 1172 WindowPositionManagedUpdater updater; 1173 dragged_widget->AddObserver(&updater); 1174 browser->window()->Show(); 1175 dragged_widget->RemoveObserver(&updater); 1176 dragged_widget->SetVisibilityChangedAnimationsEnabled(true); 1177 // Activate may trigger a focus loss, destroying us. 1178 { 1179 base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); 1180 browser->window()->Activate(); 1181 if (!ref) 1182 return; 1183 } 1184 RunMoveLoop(drag_offset); 1185} 1186 1187void TabDragController::RunMoveLoop(const gfx::Vector2d& drag_offset) { 1188 // If the user drags the whole window we'll assume they are going to attach to 1189 // another window and therefore want to reorder. 1190 move_behavior_ = REORDER; 1191 1192 move_loop_widget_ = GetAttachedBrowserWidget(); 1193 DCHECK(move_loop_widget_); 1194 move_loop_widget_->AddObserver(this); 1195 is_dragging_window_ = true; 1196 base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr()); 1197 // Running the move loop releases mouse capture on non-ash, which triggers 1198 // destroying the drag loop. Release mouse capture ourself before this while 1199 // the DragController isn't owned by the TabStrip. 1200 if (host_desktop_type_ != chrome::HOST_DESKTOP_TYPE_ASH) { 1201 attached_tabstrip_->ReleaseDragController(); 1202 attached_tabstrip_->GetWidget()->ReleaseCapture(); 1203 attached_tabstrip_->OwnDragController(this); 1204 } 1205 const views::Widget::MoveLoopSource move_loop_source = 1206 event_source_ == EVENT_SOURCE_MOUSE ? 1207 views::Widget::MOVE_LOOP_SOURCE_MOUSE : 1208 views::Widget::MOVE_LOOP_SOURCE_TOUCH; 1209 const views::Widget::MoveLoopEscapeBehavior escape_behavior = 1210 is_dragging_new_browser_ ? 1211 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE : 1212 views::Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE; 1213 views::Widget::MoveLoopResult result = 1214 move_loop_widget_->RunMoveLoop( 1215 drag_offset, move_loop_source, escape_behavior); 1216 content::NotificationService::current()->Notify( 1217 chrome::NOTIFICATION_TAB_DRAG_LOOP_DONE, 1218 content::NotificationService::AllBrowserContextsAndSources(), 1219 content::NotificationService::NoDetails()); 1220 1221 if (!ref) 1222 return; 1223 // Under chromeos we immediately set the |move_loop_widget_| to NULL. 1224 if (move_loop_widget_) { 1225 move_loop_widget_->RemoveObserver(this); 1226 move_loop_widget_ = NULL; 1227 } 1228 is_dragging_window_ = false; 1229 waiting_for_run_loop_to_exit_ = false; 1230 if (end_run_loop_behavior_ == END_RUN_LOOP_CONTINUE_DRAGGING) { 1231 end_run_loop_behavior_ = END_RUN_LOOP_STOP_DRAGGING; 1232 if (tab_strip_to_attach_to_after_exit_) { 1233 gfx::Point point_in_screen(GetCursorScreenPoint()); 1234 Detach(DONT_RELEASE_CAPTURE); 1235 Attach(tab_strip_to_attach_to_after_exit_, point_in_screen); 1236 // Move the tabs into position. 1237 MoveAttached(point_in_screen); 1238 attached_tabstrip_->GetWidget()->Activate(); 1239 // Activate may trigger a focus loss, destroying us. 1240 if (!ref) 1241 return; 1242 tab_strip_to_attach_to_after_exit_ = NULL; 1243 } 1244 DCHECK(attached_tabstrip_); 1245 attached_tabstrip_->GetWidget()->SetCapture(attached_tabstrip_); 1246 } else if (active_) { 1247 EndDrag(result == views::Widget::MOVE_LOOP_CANCELED ? 1248 END_DRAG_CANCEL : END_DRAG_COMPLETE); 1249 } 1250} 1251 1252int TabDragController::GetInsertionIndexFrom(const gfx::Rect& dragged_bounds, 1253 int start, 1254 int delta) const { 1255 for (int i = start, tab_count = attached_tabstrip_->tab_count(); 1256 i >= 0 && i < tab_count; i += delta) { 1257 const gfx::Rect& ideal_bounds = attached_tabstrip_->ideal_bounds(i); 1258 gfx::Rect left_half, right_half; 1259 ideal_bounds.SplitVertically(&left_half, &right_half); 1260 if (dragged_bounds.x() >= right_half.x() && 1261 dragged_bounds.x() < right_half.right()) { 1262 return i + 1; 1263 } else if (dragged_bounds.x() >= left_half.x() && 1264 dragged_bounds.x() < left_half.right()) { 1265 return i; 1266 } 1267 } 1268 return -1; 1269} 1270 1271int TabDragController::GetInsertionIndexForDraggedBounds( 1272 const gfx::Rect& dragged_bounds) const { 1273 int index = -1; 1274 if (attached_tabstrip_->touch_layout_.get()) { 1275 index = GetInsertionIndexForDraggedBoundsStacked(dragged_bounds); 1276 if (index != -1) { 1277 // Only move the tab to the left/right if the user actually moved the 1278 // mouse that way. This is necessary as tabs with stacked tabs 1279 // before/after them have multiple drag positions. 1280 int active_index = attached_tabstrip_->touch_layout_->active_index(); 1281 if ((index < active_index && 1282 (mouse_move_direction_ & kMovedMouseLeft) == 0) || 1283 (index > active_index && 1284 (mouse_move_direction_ & kMovedMouseRight) == 0)) { 1285 index = active_index; 1286 } 1287 } 1288 } else { 1289 index = GetInsertionIndexFrom(dragged_bounds, 0, 1); 1290 } 1291 if (index == -1) { 1292 int tab_count = attached_tabstrip_->tab_count(); 1293 int right_tab_x = tab_count == 0 ? 0 : 1294 attached_tabstrip_->ideal_bounds(tab_count - 1).right(); 1295 if (dragged_bounds.right() > right_tab_x) { 1296 index = GetModel(attached_tabstrip_)->count(); 1297 } else { 1298 index = 0; 1299 } 1300 } 1301 1302 if (!drag_data_[0].attached_tab) { 1303 // If 'attached_tab' is NULL, it means we're in the process of attaching and 1304 // don't need to constrain the index. 1305 return index; 1306 } 1307 1308 int max_index = GetModel(attached_tabstrip_)->count() - 1309 static_cast<int>(drag_data_.size()); 1310 return std::max(0, std::min(max_index, index)); 1311} 1312 1313bool TabDragController::ShouldDragToNextStackedTab( 1314 const gfx::Rect& dragged_bounds, 1315 int index) const { 1316 if (index + 1 >= attached_tabstrip_->tab_count() || 1317 !attached_tabstrip_->touch_layout_->IsStacked(index + 1) || 1318 (mouse_move_direction_ & kMovedMouseRight) == 0) 1319 return false; 1320 1321 int active_x = attached_tabstrip_->ideal_bounds(index).x(); 1322 int next_x = attached_tabstrip_->ideal_bounds(index + 1).x(); 1323 int mid_x = std::min(next_x - kStackedDistance, 1324 active_x + (next_x - active_x) / 4); 1325 return dragged_bounds.x() >= mid_x; 1326} 1327 1328bool TabDragController::ShouldDragToPreviousStackedTab( 1329 const gfx::Rect& dragged_bounds, 1330 int index) const { 1331 if (index - 1 < attached_tabstrip_->GetMiniTabCount() || 1332 !attached_tabstrip_->touch_layout_->IsStacked(index - 1) || 1333 (mouse_move_direction_ & kMovedMouseLeft) == 0) 1334 return false; 1335 1336 int active_x = attached_tabstrip_->ideal_bounds(index).x(); 1337 int previous_x = attached_tabstrip_->ideal_bounds(index - 1).x(); 1338 int mid_x = std::max(previous_x + kStackedDistance, 1339 active_x - (active_x - previous_x) / 4); 1340 return dragged_bounds.x() <= mid_x; 1341} 1342 1343int TabDragController::GetInsertionIndexForDraggedBoundsStacked( 1344 const gfx::Rect& dragged_bounds) const { 1345 StackedTabStripLayout* touch_layout = attached_tabstrip_->touch_layout_.get(); 1346 int active_index = touch_layout->active_index(); 1347 // Search from the active index to the front of the tabstrip. Do this as tabs 1348 // overlap each other from the active index. 1349 int index = GetInsertionIndexFrom(dragged_bounds, active_index, -1); 1350 if (index != active_index) 1351 return index; 1352 if (index == -1) 1353 return GetInsertionIndexFrom(dragged_bounds, active_index + 1, 1); 1354 1355 // The position to drag to corresponds to the active tab. If the next/previous 1356 // tab is stacked, then shorten the distance used to determine insertion 1357 // bounds. We do this as GetInsertionIndexFrom() uses the bounds of the 1358 // tabs. When tabs are stacked the next/previous tab is on top of the tab. 1359 if (active_index + 1 < attached_tabstrip_->tab_count() && 1360 touch_layout->IsStacked(active_index + 1)) { 1361 index = GetInsertionIndexFrom(dragged_bounds, active_index + 1, 1); 1362 if (index == -1 && ShouldDragToNextStackedTab(dragged_bounds, active_index)) 1363 index = active_index + 1; 1364 else if (index == -1) 1365 index = active_index; 1366 } else if (ShouldDragToPreviousStackedTab(dragged_bounds, active_index)) { 1367 index = active_index - 1; 1368 } 1369 return index; 1370} 1371 1372gfx::Rect TabDragController::GetDraggedViewTabStripBounds( 1373 const gfx::Point& tab_strip_point) { 1374 // attached_tab is NULL when inserting into a new tabstrip. 1375 if (source_tab_drag_data()->attached_tab) { 1376 return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), 1377 source_tab_drag_data()->attached_tab->width(), 1378 source_tab_drag_data()->attached_tab->height()); 1379 } 1380 1381 double sel_width, unselected_width; 1382 attached_tabstrip_->GetCurrentTabWidths(&sel_width, &unselected_width); 1383 return gfx::Rect(tab_strip_point.x(), tab_strip_point.y(), 1384 static_cast<int>(sel_width), 1385 Tab::GetStandardSize().height()); 1386} 1387 1388gfx::Point TabDragController::GetAttachedDragPoint( 1389 const gfx::Point& point_in_screen) { 1390 DCHECK(attached_tabstrip_); // The tab must be attached. 1391 1392 gfx::Point tab_loc(point_in_screen); 1393 views::View::ConvertPointFromScreen(attached_tabstrip_, &tab_loc); 1394 const int x = 1395 attached_tabstrip_->GetMirroredXInView(tab_loc.x()) - mouse_offset_.x(); 1396 1397 // TODO: consider caching this. 1398 std::vector<Tab*> attached_tabs; 1399 for (size_t i = 0; i < drag_data_.size(); ++i) 1400 attached_tabs.push_back(drag_data_[i].attached_tab); 1401 const int size = attached_tabstrip_->GetSizeNeededForTabs(attached_tabs); 1402 const int max_x = attached_tabstrip_->width() - size; 1403 return gfx::Point(std::min(std::max(x, 0), max_x), 0); 1404} 1405 1406std::vector<Tab*> TabDragController::GetTabsMatchingDraggedContents( 1407 TabStrip* tabstrip) { 1408 TabStripModel* model = GetModel(attached_tabstrip_); 1409 std::vector<Tab*> tabs; 1410 for (size_t i = 0; i < drag_data_.size(); ++i) { 1411 int model_index = model->GetIndexOfWebContents(drag_data_[i].contents); 1412 if (model_index == TabStripModel::kNoTab) 1413 return std::vector<Tab*>(); 1414 tabs.push_back(tabstrip->tab_at(model_index)); 1415 } 1416 return tabs; 1417} 1418 1419std::vector<gfx::Rect> TabDragController::CalculateBoundsForDraggedTabs() { 1420 std::vector<gfx::Rect> drag_bounds; 1421 std::vector<Tab*> attached_tabs; 1422 for (size_t i = 0; i < drag_data_.size(); ++i) 1423 attached_tabs.push_back(drag_data_[i].attached_tab); 1424 attached_tabstrip_->CalculateBoundsForDraggedTabs(attached_tabs, 1425 &drag_bounds); 1426 return drag_bounds; 1427} 1428 1429void TabDragController::EndDragImpl(EndDragType type) { 1430 DCHECK(active_); 1431 active_ = false; 1432 1433 bring_to_front_timer_.Stop(); 1434 move_stacked_timer_.Stop(); 1435 1436 if (is_dragging_window_) { 1437 waiting_for_run_loop_to_exit_ = true; 1438 1439 if (type == NORMAL || (type == TAB_DESTROYED && drag_data_.size() > 1)) { 1440 SetWindowPositionManaged(GetAttachedBrowserWidget()->GetNativeView(), 1441 true); 1442 } 1443 1444 // End the nested drag loop. 1445 GetAttachedBrowserWidget()->EndMoveLoop(); 1446 } 1447 1448 if (type != TAB_DESTROYED) { 1449 // We only finish up the drag if we were actually dragging. If start_drag_ 1450 // is false, the user just clicked and released and didn't move the mouse 1451 // enough to trigger a drag. 1452 if (started_drag_) { 1453 RestoreFocus(); 1454 if (type == CANCELED) 1455 RevertDrag(); 1456 else 1457 CompleteDrag(); 1458 } 1459 } else if (drag_data_.size() > 1) { 1460 initial_selection_model_.Clear(); 1461 RevertDrag(); 1462 } // else case the only tab we were dragging was deleted. Nothing to do. 1463 1464 if (!detach_into_browser_) 1465 ResetDelegates(); 1466 1467 // Clear out drag data so we don't attempt to do anything with it. 1468 drag_data_.clear(); 1469 1470 TabStrip* owning_tabstrip = (attached_tabstrip_ && detach_into_browser_) ? 1471 attached_tabstrip_ : source_tabstrip_; 1472 owning_tabstrip->DestroyDragController(); 1473} 1474 1475void TabDragController::RevertDrag() { 1476 std::vector<Tab*> tabs; 1477 for (size_t i = 0; i < drag_data_.size(); ++i) { 1478 if (drag_data_[i].contents) { 1479 // Contents is NULL if a tab was destroyed while the drag was under way. 1480 tabs.push_back(drag_data_[i].attached_tab); 1481 RevertDragAt(i); 1482 } 1483 } 1484 1485 bool restore_frame = !detach_into_browser_ && 1486 attached_tabstrip_ != source_tabstrip_; 1487 if (attached_tabstrip_) { 1488 if (did_restore_window_) 1489 MaximizeAttachedWindow(); 1490 if (attached_tabstrip_ == source_tabstrip_) { 1491 source_tabstrip_->StoppedDraggingTabs( 1492 tabs, initial_tab_positions_, move_behavior_ == MOVE_VISIBILE_TABS, 1493 false); 1494 } else { 1495 attached_tabstrip_->DraggedTabsDetached(); 1496 } 1497 } 1498 1499 if (initial_selection_model_.empty()) 1500 ResetSelection(GetModel(source_tabstrip_)); 1501 else 1502 GetModel(source_tabstrip_)->SetSelectionFromModel(initial_selection_model_); 1503 1504 // If we're not attached to any TabStrip, or attached to some other TabStrip, 1505 // we need to restore the bounds of the original TabStrip's frame, in case 1506 // it has been hidden. 1507 if (restore_frame && !restore_bounds_.IsEmpty()) 1508 source_tabstrip_->GetWidget()->SetBounds(restore_bounds_); 1509 1510 if (detach_into_browser_ && source_tabstrip_) 1511 source_tabstrip_->GetWidget()->Activate(); 1512 1513 // Return the WebContents to normalcy. If the tab was attached to a 1514 // TabStrip before the revert, the decrement has already occurred. 1515 // If the tab was destroyed, don't attempt to dereference the 1516 // WebContents pointer. 1517 if (!detach_into_browser_ && !attached_tabstrip_ && source_dragged_contents()) 1518 source_dragged_contents()->DecrementCapturerCount(); 1519} 1520 1521void TabDragController::ResetSelection(TabStripModel* model) { 1522 DCHECK(model); 1523 ui::ListSelectionModel selection_model; 1524 bool has_one_valid_tab = false; 1525 for (size_t i = 0; i < drag_data_.size(); ++i) { 1526 // |contents| is NULL if a tab was deleted out from under us. 1527 if (drag_data_[i].contents) { 1528 int index = model->GetIndexOfWebContents(drag_data_[i].contents); 1529 DCHECK_NE(-1, index); 1530 selection_model.AddIndexToSelection(index); 1531 if (!has_one_valid_tab || i == source_tab_index_) { 1532 // Reset the active/lead to the first tab. If the source tab is still 1533 // valid we'll reset these again later on. 1534 selection_model.set_active(index); 1535 selection_model.set_anchor(index); 1536 has_one_valid_tab = true; 1537 } 1538 } 1539 } 1540 if (!has_one_valid_tab) 1541 return; 1542 1543 model->SetSelectionFromModel(selection_model); 1544} 1545 1546void TabDragController::RestoreInitialSelection() { 1547 // First time detaching from the source tabstrip. Reset selection model to 1548 // initial_selection_model_. Before resetting though we have to remove all 1549 // the tabs from initial_selection_model_ as it was created with the tabs 1550 // still there. 1551 ui::ListSelectionModel selection_model; 1552 selection_model.Copy(initial_selection_model_); 1553 for (DragData::const_reverse_iterator i(drag_data_.rbegin()); 1554 i != drag_data_.rend(); ++i) { 1555 selection_model.DecrementFrom(i->source_model_index); 1556 } 1557 // We may have cleared out the selection model. Only reset it if it 1558 // contains something. 1559 if (selection_model.empty()) 1560 return; 1561 1562 // The anchor/active may have been among the tabs that were dragged out. Force 1563 // the anchor/active to be valid. 1564 if (selection_model.anchor() == ui::ListSelectionModel::kUnselectedIndex) 1565 selection_model.set_anchor(selection_model.selected_indices()[0]); 1566 if (selection_model.active() == ui::ListSelectionModel::kUnselectedIndex) 1567 selection_model.set_active(selection_model.selected_indices()[0]); 1568 GetModel(source_tabstrip_)->SetSelectionFromModel(selection_model); 1569} 1570 1571void TabDragController::RevertDragAt(size_t drag_index) { 1572 DCHECK(started_drag_); 1573 DCHECK(source_tabstrip_); 1574 1575 base::AutoReset<bool> setter(&is_mutating_, true); 1576 TabDragData* data = &(drag_data_[drag_index]); 1577 if (attached_tabstrip_) { 1578 int index = 1579 GetModel(attached_tabstrip_)->GetIndexOfWebContents(data->contents); 1580 if (attached_tabstrip_ != source_tabstrip_) { 1581 // The Tab was inserted into another TabStrip. We need to put it back 1582 // into the original one. 1583 GetModel(attached_tabstrip_)->DetachWebContentsAt(index); 1584 // TODO(beng): (Cleanup) seems like we should use Attach() for this 1585 // somehow. 1586 GetModel(source_tabstrip_)->InsertWebContentsAt( 1587 data->source_model_index, data->contents, 1588 (data->pinned ? TabStripModel::ADD_PINNED : 0)); 1589 } else { 1590 // The Tab was moved within the TabStrip where the drag was initiated. 1591 // Move it back to the starting location. 1592 GetModel(source_tabstrip_)->MoveWebContentsAt( 1593 index, data->source_model_index, false); 1594 } 1595 } else { 1596 // The Tab was detached from the TabStrip where the drag began, and has not 1597 // been attached to any other TabStrip. We need to put it back into the 1598 // source TabStrip. 1599 GetModel(source_tabstrip_)->InsertWebContentsAt( 1600 data->source_model_index, data->contents, 1601 (data->pinned ? TabStripModel::ADD_PINNED : 0)); 1602 } 1603} 1604 1605void TabDragController::CompleteDrag() { 1606 DCHECK(started_drag_); 1607 1608 if (attached_tabstrip_) { 1609 if (is_dragging_new_browser_ || did_restore_window_) { 1610 if (IsDockedOrSnapped(attached_tabstrip_)) { 1611 was_source_maximized_ = false; 1612 was_source_fullscreen_ = false; 1613 } 1614 1615 // If source window was maximized - maximize the new window as well. 1616 if (was_source_maximized_ || was_source_fullscreen_) 1617 MaximizeAttachedWindow(); 1618 } 1619 attached_tabstrip_->StoppedDraggingTabs( 1620 GetTabsMatchingDraggedContents(attached_tabstrip_), 1621 initial_tab_positions_, 1622 move_behavior_ == MOVE_VISIBILE_TABS, 1623 true); 1624 } else { 1625 // Compel the model to construct a new window for the detached 1626 // WebContentses. 1627 views::Widget* widget = source_tabstrip_->GetWidget(); 1628 gfx::Rect window_bounds(widget->GetRestoredBounds()); 1629 window_bounds.set_origin(GetWindowCreatePoint(last_point_in_screen_)); 1630 1631 base::AutoReset<bool> setter(&is_mutating_, true); 1632 1633 std::vector<TabStripModelDelegate::NewStripContents> contentses; 1634 for (size_t i = 0; i < drag_data_.size(); ++i) { 1635 TabStripModelDelegate::NewStripContents item; 1636 item.web_contents = drag_data_[i].contents; 1637 item.add_types = drag_data_[i].pinned ? TabStripModel::ADD_PINNED 1638 : TabStripModel::ADD_NONE; 1639 contentses.push_back(item); 1640 } 1641 1642 Browser* new_browser = 1643 GetModel(source_tabstrip_)->delegate()->CreateNewStripWithContents( 1644 contentses, window_bounds, widget->IsMaximized()); 1645 ResetSelection(new_browser->tab_strip_model()); 1646 new_browser->window()->Show(); 1647 1648 // Return the WebContents to normalcy. 1649 if (!detach_into_browser_) 1650 source_dragged_contents()->DecrementCapturerCount(); 1651 } 1652 1653 CleanUpHiddenFrame(); 1654} 1655 1656void TabDragController::MaximizeAttachedWindow() { 1657 GetAttachedBrowserWidget()->Maximize(); 1658#if defined(USE_ASH) 1659 if (was_source_fullscreen_ && 1660 host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH) { 1661 // In fullscreen mode it is only possible to get here if the source 1662 // was in "immersive fullscreen" mode, so toggle it back on. 1663 ash::accelerators::ToggleFullscreen(); 1664 } 1665#endif 1666} 1667 1668void TabDragController::ResetDelegates() { 1669 DCHECK(!detach_into_browser_); 1670 for (size_t i = 0; i < drag_data_.size(); ++i) { 1671 if (drag_data_[i].contents && 1672 drag_data_[i].contents->GetDelegate() == this) { 1673 drag_data_[i].contents->SetDelegate( 1674 drag_data_[i].original_delegate); 1675 } 1676 } 1677} 1678 1679gfx::Rect TabDragController::GetViewScreenBounds( 1680 views::View* view) const { 1681 gfx::Point view_topleft; 1682 views::View::ConvertPointToScreen(view, &view_topleft); 1683 gfx::Rect view_screen_bounds = view->GetLocalBounds(); 1684 view_screen_bounds.Offset(view_topleft.x(), view_topleft.y()); 1685 return view_screen_bounds; 1686} 1687 1688void TabDragController::CleanUpHiddenFrame() { 1689 // If the model we started dragging from is now empty, we must ask the 1690 // delegate to close the frame. 1691 if (!detach_into_browser_ && GetModel(source_tabstrip_)->empty()) 1692 GetModel(source_tabstrip_)->delegate()->CloseFrameAfterDragSession(); 1693} 1694 1695void TabDragController::BringWindowUnderPointToFront( 1696 const gfx::Point& point_in_screen) { 1697 aura::Window* window = GetLocalProcessWindow(point_in_screen, true); 1698 1699 // Only bring browser windows to front - only windows with a TabStrip can 1700 // be tab drag targets. 1701 if (!GetTabStripForWindow(window)) 1702 return; 1703 1704 if (window) { 1705 views::Widget* widget_window = views::Widget::GetWidgetForNativeView( 1706 window); 1707 if (!widget_window) 1708 return; 1709 1710#if defined(USE_ASH) 1711 if (host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH) { 1712 // TODO(varkha): The code below ensures that the phantom drag widget 1713 // is shown on top of browser windows. The code should be moved to ash/ 1714 // and the phantom should be able to assert its top-most state on its own. 1715 // One strategy would be for DragWindowController to 1716 // be able to observe stacking changes to the phantom drag widget's 1717 // siblings in order to keep it on top. One way is to implement a 1718 // notification that is sent to a window parent's observers when a 1719 // stacking order is changed among the children of that same parent. 1720 // Note that OnWindowStackingChanged is sent only to the child that is the 1721 // argument of one of the Window::StackChildX calls and not to all its 1722 // siblings affected by the stacking change. 1723 aura::Window* browser_window = widget_window->GetNativeView(); 1724 // Find a topmost non-popup window and stack the recipient browser above 1725 // it in order to avoid stacking the browser window on top of the phantom 1726 // drag widget created by DragWindowController in a second display. 1727 for (aura::Window::Windows::const_reverse_iterator it = 1728 browser_window->parent()->children().rbegin(); 1729 it != browser_window->parent()->children().rend(); ++it) { 1730 // If the iteration reached the recipient browser window then it is 1731 // already topmost and it is safe to return with no stacking change. 1732 if (*it == browser_window) 1733 return; 1734 if ((*it)->type() != ui::wm::WINDOW_TYPE_POPUP) { 1735 widget_window->StackAbove(*it); 1736 break; 1737 } 1738 } 1739 } else { 1740 widget_window->StackAtTop(); 1741 } 1742#else 1743 widget_window->StackAtTop(); 1744#endif 1745 1746 // The previous call made the window appear on top of the dragged window, 1747 // move the dragged window to the front. 1748 if (is_dragging_window_) 1749 attached_tabstrip_->GetWidget()->StackAtTop(); 1750 } 1751} 1752 1753TabStripModel* TabDragController::GetModel( 1754 TabStrip* tabstrip) const { 1755 return static_cast<BrowserTabStripController*>(tabstrip->controller())-> 1756 model(); 1757} 1758 1759views::Widget* TabDragController::GetAttachedBrowserWidget() { 1760 return attached_tabstrip_->GetWidget(); 1761} 1762 1763bool TabDragController::AreTabsConsecutive() { 1764 for (size_t i = 1; i < drag_data_.size(); ++i) { 1765 if (drag_data_[i - 1].source_model_index + 1 != 1766 drag_data_[i].source_model_index) { 1767 return false; 1768 } 1769 } 1770 return true; 1771} 1772 1773gfx::Rect TabDragController::CalculateDraggedBrowserBounds( 1774 TabStrip* source, 1775 const gfx::Point& point_in_screen, 1776 std::vector<gfx::Rect>* drag_bounds) { 1777 gfx::Point center(0, source->height() / 2); 1778 views::View::ConvertPointToWidget(source, ¢er); 1779 gfx::Rect new_bounds(source->GetWidget()->GetRestoredBounds()); 1780 if (source->GetWidget()->IsMaximized()) { 1781 // If the restore bounds is really small, we don't want to honor it 1782 // (dragging a really small window looks wrong), instead make sure the new 1783 // window is at least 50% the size of the old. 1784 const gfx::Size max_size( 1785 source->GetWidget()->GetWindowBoundsInScreen().size()); 1786 new_bounds.set_width( 1787 std::max(max_size.width() / 2, new_bounds.width())); 1788 new_bounds.set_height( 1789 std::max(max_size.height() / 2, new_bounds.height())); 1790 } 1791 new_bounds.set_y(point_in_screen.y() - center.y()); 1792 switch (GetDetachPosition(point_in_screen)) { 1793 case DETACH_BEFORE: 1794 new_bounds.set_x(point_in_screen.x() - center.x()); 1795 new_bounds.Offset(-mouse_offset_.x(), 0); 1796 break; 1797 case DETACH_AFTER: { 1798 gfx::Point right_edge(source->width(), 0); 1799 views::View::ConvertPointToWidget(source, &right_edge); 1800 new_bounds.set_x(point_in_screen.x() - right_edge.x()); 1801 new_bounds.Offset(drag_bounds->back().right() - mouse_offset_.x(), 0); 1802 OffsetX(-(*drag_bounds)[0].x(), drag_bounds); 1803 break; 1804 } 1805 default: 1806 break; // Nothing to do for DETACH_ABOVE_OR_BELOW. 1807 } 1808 1809 // To account for the extra vertical on restored windows that is absent on 1810 // maximized windows, add an additional vertical offset extracted from the tab 1811 // strip. 1812 if (source->GetWidget()->IsMaximized()) 1813 new_bounds.Offset(0, -source->button_v_offset()); 1814 return new_bounds; 1815} 1816 1817void TabDragController::AdjustBrowserAndTabBoundsForDrag( 1818 int last_tabstrip_width, 1819 const gfx::Point& point_in_screen, 1820 std::vector<gfx::Rect>* drag_bounds) { 1821 attached_tabstrip_->InvalidateLayout(); 1822 attached_tabstrip_->DoLayout(); 1823 const int dragged_tabstrip_width = attached_tabstrip_->tab_area_width(); 1824 1825 // If the new tabstrip is smaller than the old resize the tabs. 1826 if (dragged_tabstrip_width < last_tabstrip_width) { 1827 const float leading_ratio = 1828 drag_bounds->front().x() / static_cast<float>(last_tabstrip_width); 1829 *drag_bounds = CalculateBoundsForDraggedTabs(); 1830 1831 if (drag_bounds->back().right() < dragged_tabstrip_width) { 1832 const int delta_x = 1833 std::min(static_cast<int>(leading_ratio * dragged_tabstrip_width), 1834 dragged_tabstrip_width - 1835 (drag_bounds->back().right() - 1836 drag_bounds->front().x())); 1837 OffsetX(delta_x, drag_bounds); 1838 } 1839 1840 // Reposition the restored window such that the tab that was dragged remains 1841 // under the mouse cursor. 1842 gfx::Point offset( 1843 static_cast<int>((*drag_bounds)[source_tab_index_].width() * 1844 offset_to_width_ratio_) + 1845 (*drag_bounds)[source_tab_index_].x(), 0); 1846 views::View::ConvertPointToWidget(attached_tabstrip_, &offset); 1847 gfx::Rect bounds = GetAttachedBrowserWidget()->GetWindowBoundsInScreen(); 1848 bounds.set_x(point_in_screen.x() - offset.x()); 1849 GetAttachedBrowserWidget()->SetBounds(bounds); 1850 } 1851 attached_tabstrip_->SetTabBoundsForDrag(*drag_bounds); 1852} 1853 1854Browser* TabDragController::CreateBrowserForDrag( 1855 TabStrip* source, 1856 const gfx::Point& point_in_screen, 1857 gfx::Vector2d* drag_offset, 1858 std::vector<gfx::Rect>* drag_bounds) { 1859 gfx::Rect new_bounds(CalculateDraggedBrowserBounds(source, 1860 point_in_screen, 1861 drag_bounds)); 1862 *drag_offset = point_in_screen - new_bounds.origin(); 1863 1864 Profile* profile = 1865 Profile::FromBrowserContext(drag_data_[0].contents->GetBrowserContext()); 1866 Browser::CreateParams create_params(Browser::TYPE_TABBED, 1867 profile, 1868 host_desktop_type_); 1869 create_params.initial_bounds = new_bounds; 1870 Browser* browser = new Browser(create_params); 1871 is_dragging_new_browser_ = true; 1872 SetWindowPositionManaged(browser->window()->GetNativeWindow(), false); 1873 // If the window is created maximized then the bounds we supplied are ignored. 1874 // We need to reset them again so they are honored. 1875 browser->window()->SetBounds(new_bounds); 1876 1877 return browser; 1878} 1879 1880gfx::Point TabDragController::GetCursorScreenPoint() { 1881#if defined(USE_ASH) 1882 if (host_desktop_type_ == chrome::HOST_DESKTOP_TYPE_ASH && 1883 event_source_ == EVENT_SOURCE_TOUCH && 1884 aura::Env::GetInstance()->is_touch_down()) { 1885 views::Widget* widget = GetAttachedBrowserWidget(); 1886 DCHECK(widget); 1887 aura::Window* widget_window = widget->GetNativeWindow(); 1888 DCHECK(widget_window->GetRootWindow()); 1889 gfx::PointF touch_point_f; 1890 bool got_touch_point = ui::GestureRecognizer::Get()-> 1891 GetLastTouchPointForTarget(widget_window, &touch_point_f); 1892 // TODO(tdresser): Switch to using gfx::PointF. See crbug.com/337824. 1893 gfx::Point touch_point = gfx::ToFlooredPoint(touch_point_f); 1894 DCHECK(got_touch_point); 1895 ash::wm::ConvertPointToScreen(widget_window->GetRootWindow(), &touch_point); 1896 return touch_point; 1897 } 1898#endif 1899 return screen_->GetCursorScreenPoint(); 1900} 1901 1902gfx::Vector2d TabDragController::GetWindowOffset( 1903 const gfx::Point& point_in_screen) { 1904 TabStrip* owning_tabstrip = (attached_tabstrip_ && detach_into_browser_) ? 1905 attached_tabstrip_ : source_tabstrip_; 1906 views::View* toplevel_view = owning_tabstrip->GetWidget()->GetContentsView(); 1907 1908 gfx::Point point = point_in_screen; 1909 views::View::ConvertPointFromScreen(toplevel_view, &point); 1910 return point.OffsetFromOrigin(); 1911} 1912 1913gfx::NativeWindow TabDragController::GetLocalProcessWindow( 1914 const gfx::Point& screen_point, 1915 bool exclude_dragged_view) { 1916 std::set<aura::Window*> exclude; 1917 if (exclude_dragged_view) { 1918 aura::Window* dragged_window = 1919 attached_tabstrip_->GetWidget()->GetNativeView(); 1920 if (dragged_window) 1921 exclude.insert(dragged_window); 1922 } 1923#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 1924 // Exclude windows which are pending deletion via Browser::TabStripEmpty(). 1925 // These windows can be returned in the Linux Aura port because the browser 1926 // window which was used for dragging is not hidden once all of its tabs are 1927 // attached to another browser window in DragBrowserToNewTabStrip(). 1928 // TODO(pkotwicz): Fix this properly (crbug.com/358482) 1929 BrowserList* browser_list = BrowserList::GetInstance( 1930 chrome::HOST_DESKTOP_TYPE_NATIVE); 1931 for (BrowserList::const_iterator it = browser_list->begin(); 1932 it != browser_list->end(); ++it) { 1933 if ((*it)->tab_strip_model()->empty()) 1934 exclude.insert((*it)->window()->GetNativeWindow()); 1935 } 1936#endif 1937 return GetLocalProcessWindowAtPoint(host_desktop_type_, 1938 screen_point, 1939 exclude); 1940 1941} 1942