1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ 6 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ 7 8 #include <vector> 9 10 #include "base/memory/weak_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/timer/timer.h" 13 #include "chrome/browser/ui/host_desktop.h" 14 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" 15 #include "chrome/browser/ui/views/tabs/tab_strip_types.h" 16 #include "content/public/browser/notification_observer.h" 17 #include "content/public/browser/notification_registrar.h" 18 #include "content/public/browser/web_contents_delegate.h" 19 #include "ui/base/models/list_selection_model.h" 20 #include "ui/gfx/rect.h" 21 #include "ui/views/widget/widget_observer.h" 22 23 namespace gfx { 24 class Screen; 25 } 26 namespace ui { 27 class EventHandler; 28 class ListSelectionModel; 29 } 30 namespace views { 31 class View; 32 } 33 class Browser; 34 class Tab; 35 struct TabRendererData; 36 class TabStrip; 37 class TabStripModel; 38 39 // TabDragController is responsible for managing the tab dragging session. When 40 // the user presses the mouse on a tab a new TabDragController is created and 41 // Drag() is invoked as the mouse is dragged. If the mouse is dragged far enough 42 // TabDragController starts a drag session. The drag session is completed when 43 // EndDrag() is invoked (or the TabDragController is destroyed). 44 // 45 // While dragging within a tab strip TabDragController sets the bounds of the 46 // tabs (this is referred to as attached). When the user drags far enough such 47 // that the tabs should be moved out of the tab strip a new Browser is created 48 // and RunMoveLoop() is invoked on the Widget to drag the browser around. This 49 // is the default on aura. 50 class TabDragController : public content::WebContentsDelegate, 51 public content::NotificationObserver, 52 public views::WidgetObserver, 53 public TabStripModelObserver { 54 public: 55 enum DetachBehavior { 56 DETACHABLE, 57 NOT_DETACHABLE 58 }; 59 60 // What should happen as the mouse is dragged within the tabstrip. 61 enum MoveBehavior { 62 // Only the set of visible tabs should change. This is only applicable when 63 // using touch layout. 64 MOVE_VISIBILE_TABS, 65 66 // Typical behavior where tabs are dragged around. 67 REORDER 68 }; 69 70 // Indicates the event source that initiated the drag. 71 enum EventSource { 72 EVENT_SOURCE_MOUSE, 73 EVENT_SOURCE_TOUCH, 74 }; 75 76 // Amount above or below the tabstrip the user has to drag before detaching. 77 static const int kTouchVerticalDetachMagnetism; 78 static const int kVerticalDetachMagnetism; 79 80 TabDragController(); 81 virtual ~TabDragController(); 82 83 // Initializes TabDragController to drag the tabs in |tabs| originating from 84 // |source_tabstrip|. |source_tab| is the tab that initiated the drag and is 85 // contained in |tabs|. |mouse_offset| is the distance of the mouse pointer 86 // from the origin of the first tab in |tabs| and |source_tab_offset| the 87 // offset from |source_tab|. |source_tab_offset| is the horizontal offset of 88 // |mouse_offset| relative to |source_tab|. |initial_selection_model| is the 89 // selection model before the drag started and is only non-empty if 90 // |source_tab| was not initially selected. 91 void Init(TabStrip* source_tabstrip, 92 Tab* source_tab, 93 const std::vector<Tab*>& tabs, 94 const gfx::Point& mouse_offset, 95 int source_tab_offset, 96 const ui::ListSelectionModel& initial_selection_model, 97 DetachBehavior detach_behavior, 98 MoveBehavior move_behavior, 99 EventSource event_source); 100 101 // Returns true if there is a drag underway and the drag is attached to 102 // |tab_strip|. 103 // NOTE: this returns false if the TabDragController is in the process of 104 // finishing the drag. 105 static bool IsAttachedTo(const TabStrip* tab_strip); 106 107 // Returns true if there is a drag underway. 108 static bool IsActive(); 109 110 // Sets the move behavior. Has no effect if started_drag() is true. 111 void SetMoveBehavior(MoveBehavior behavior); 112 MoveBehavior move_behavior() const { return move_behavior_; } 113 114 EventSource event_source() const { return event_source_; } 115 116 // See description above fields for details on these. 117 bool active() const { return active_; } 118 const TabStrip* attached_tabstrip() const { return attached_tabstrip_; } 119 120 // Returns true if a drag started. 121 bool started_drag() const { return started_drag_; } 122 123 // Returns true if mutating the TabStripModel. 124 bool is_mutating() const { return is_mutating_; } 125 126 // Returns true if we've detached from a tabstrip and are running a nested 127 // move message loop. 128 bool is_dragging_window() const { return is_dragging_window_; } 129 130 // Invoked to drag to the new location, in screen coordinates. 131 void Drag(const gfx::Point& point_in_screen); 132 133 // Complete the current drag session. 134 void EndDrag(EndDragReason reason); 135 136 private: 137 // Used to indicate the direction the mouse has moved when attached. 138 static const int kMovedMouseLeft = 1 << 0; 139 static const int kMovedMouseRight = 1 << 1; 140 141 // Enumeration of the ways a drag session can end. 142 enum EndDragType { 143 // Drag session exited normally: the user released the mouse. 144 NORMAL, 145 146 // The drag session was canceled (alt-tab during drag, escape ...) 147 CANCELED, 148 149 // The tab (NavigationController) was destroyed during the drag. 150 TAB_DESTROYED 151 }; 152 153 // Whether Detach() should release capture or not. 154 enum ReleaseCapture { 155 RELEASE_CAPTURE, 156 DONT_RELEASE_CAPTURE, 157 }; 158 159 // Specifies what should happen when RunMoveLoop completes. 160 enum EndRunLoopBehavior { 161 // Indicates the drag should end. 162 END_RUN_LOOP_STOP_DRAGGING, 163 164 // Indicates the drag should continue. 165 END_RUN_LOOP_CONTINUE_DRAGGING 166 }; 167 168 // Enumeration of the possible positions the detached tab may detach from. 169 enum DetachPosition { 170 DETACH_BEFORE, 171 DETACH_AFTER, 172 DETACH_ABOVE_OR_BELOW 173 }; 174 175 // Indicates what should happen after invoking DragBrowserToNewTabStrip(). 176 enum DragBrowserResultType { 177 // The caller should return immediately. This return value is used if a 178 // nested message loop was created or we're in a nested message loop and 179 // need to exit it. 180 DRAG_BROWSER_RESULT_STOP, 181 182 // The caller should continue. 183 DRAG_BROWSER_RESULT_CONTINUE, 184 }; 185 186 // Stores the date associated with a single tab that is being dragged. 187 struct TabDragData { 188 TabDragData(); 189 ~TabDragData(); 190 191 // The WebContents being dragged. 192 content::WebContents* contents; 193 194 // content::WebContentsDelegate for |contents| before it was detached from 195 // the browser window. We store this so that we can forward certain delegate 196 // notifications back to it if we can't handle them locally. 197 content::WebContentsDelegate* original_delegate; 198 199 // This is the index of the tab in |source_tabstrip_| when the drag 200 // began. This is used to restore the previous state if the drag is aborted. 201 int source_model_index; 202 203 // If attached this is the tab in |attached_tabstrip_|. 204 Tab* attached_tab; 205 206 // Is the tab pinned? 207 bool pinned; 208 }; 209 210 typedef std::vector<TabDragData> DragData; 211 212 // Sets |drag_data| from |tab|. This also registers for necessary 213 // notifications and resets the delegate of the WebContents. 214 void InitTabDragData(Tab* tab, TabDragData* drag_data); 215 216 // Overridden from content::WebContentsDelegate: 217 virtual content::WebContents* OpenURLFromTab( 218 content::WebContents* source, 219 const content::OpenURLParams& params) OVERRIDE; 220 virtual void NavigationStateChanged(const content::WebContents* source, 221 unsigned changed_flags) OVERRIDE; 222 virtual void AddNewContents(content::WebContents* source, 223 content::WebContents* new_contents, 224 WindowOpenDisposition disposition, 225 const gfx::Rect& initial_pos, 226 bool user_gesture, 227 bool* was_blocked) OVERRIDE; 228 virtual bool ShouldSuppressDialogs() OVERRIDE; 229 virtual content::JavaScriptDialogManager* 230 GetJavaScriptDialogManager() OVERRIDE; 231 virtual void RequestMediaAccessPermission( 232 content::WebContents* web_contents, 233 const content::MediaStreamRequest& request, 234 const content::MediaResponseCallback& callback) OVERRIDE; 235 236 // Overridden from content::NotificationObserver: 237 virtual void Observe(int type, 238 const content::NotificationSource& source, 239 const content::NotificationDetails& details) OVERRIDE; 240 241 // Overriden from views::WidgetObserver: 242 virtual void OnWidgetBoundsChanged(views::Widget* widget, 243 const gfx::Rect& new_bounds) OVERRIDE; 244 245 // Overriden from TabStripModelObserver: 246 virtual void TabStripEmpty() OVERRIDE; 247 248 // Initialize the offset used to calculate the position to create windows 249 // in |GetWindowCreatePoint|. This should only be invoked from |Init|. 250 void InitWindowCreatePoint(); 251 252 // Returns the point where a detached window should be created given the 253 // current mouse position |origin|. 254 gfx::Point GetWindowCreatePoint(const gfx::Point& origin) const; 255 256 void UpdateDockInfo(const gfx::Point& point_in_screen); 257 258 // Saves focus in the window that the drag initiated from. Focus will be 259 // restored appropriately if the drag ends within this same window. 260 void SaveFocus(); 261 262 // Restore focus to the View that had focus before the drag was started, if 263 // the drag ends within the same Window as it began. 264 void RestoreFocus(); 265 266 // Tests whether |point_in_screen| is past a minimum elasticity threshold 267 // required to start a drag. 268 bool CanStartDrag(const gfx::Point& point_in_screen) const; 269 270 // Invoked once a drag has started to determine the appropriate tabstrip to 271 // drag to (which may be the currently attached one). 272 void ContinueDragging(const gfx::Point& point_in_screen); 273 274 // Transitions dragging from |attached_tabstrip_| to |target_tabstrip|. 275 // |target_tabstrip| is NULL if the mouse is not over a valid tab strip. See 276 // DragBrowserResultType for details of the return type. 277 DragBrowserResultType DragBrowserToNewTabStrip( 278 TabStrip* target_tabstrip, 279 const gfx::Point& point_in_screen); 280 281 // Handles dragging for a touch tabstrip when the tabs are stacked. Doesn't 282 // actually reorder the tabs in anyway, just changes what's visible. 283 void DragActiveTabStacked(const gfx::Point& point_in_screen); 284 285 // Moves the active tab to the next/previous tab. Used when the next/previous 286 // tab is stacked. 287 void MoveAttachedToNextStackedIndex(const gfx::Point& point_in_screen); 288 void MoveAttachedToPreviousStackedIndex(const gfx::Point& point_in_screen); 289 290 // Handles dragging tabs while the tabs are attached. 291 void MoveAttached(const gfx::Point& point_in_screen); 292 293 // If necessary starts the |move_stacked_timer_|. The timer is started if 294 // close enough to an edge with stacked tabs. 295 void StartMoveStackedTimerIfNecessary( 296 const gfx::Point& point_in_screen, 297 int delay_ms); 298 299 // Returns the TabStrip for the specified window, or NULL if one doesn't exist 300 // or isn't compatible. 301 TabStrip* GetTabStripForWindow(gfx::NativeWindow window); 302 303 // Returns the compatible TabStrip to drag to at the specified point (screen 304 // coordinates), or NULL if there is none. 305 TabStrip* GetTargetTabStripForPoint(const gfx::Point& point_in_screen); 306 307 // Returns true if |tabstrip| contains the specified point in screen 308 // coordinates. 309 bool DoesTabStripContain(TabStrip* tabstrip, 310 const gfx::Point& point_in_screen) const; 311 312 // Returns the DetachPosition given the specified location in screen 313 // coordinates. 314 DetachPosition GetDetachPosition(const gfx::Point& point_in_screen); 315 316 // Attach the dragged Tab to the specified TabStrip. 317 void Attach(TabStrip* attached_tabstrip, const gfx::Point& point_in_screen); 318 319 // Detach the dragged Tab from the current TabStrip. 320 void Detach(ReleaseCapture release_capture); 321 322 // Detaches the tabs being dragged, creates a new Browser to contain them and 323 // runs a nested move loop. 324 void DetachIntoNewBrowserAndRunMoveLoop(const gfx::Point& point_in_screen); 325 326 // Runs a nested message loop that handles moving the current 327 // Browser. |drag_offset| is the offset from the window origin and is used in 328 // calculating the location of the window offset from the cursor while 329 // dragging. 330 void RunMoveLoop(const gfx::Vector2d& drag_offset); 331 332 // Determines the index to insert tabs at. |dragged_bounds| is the bounds of 333 // the tabs being dragged, |start| the index of the tab to start looking from. 334 // The search proceeds to the end of the strip. 335 int GetInsertionIndexFrom(const gfx::Rect& dragged_bounds, int start) const; 336 337 // Like GetInsertionIndexFrom(), but searches backwards from |start| to the 338 // beginning of the strip. 339 int GetInsertionIndexFromReversed(const gfx::Rect& dragged_bounds, 340 int start) const; 341 342 // Returns the index where the dragged WebContents should be inserted into 343 // |attached_tabstrip_| given the DraggedTabView's bounds |dragged_bounds| in 344 // coordinates relative to |attached_tabstrip_| and has had the mirroring 345 // transformation applied. 346 // NOTE: this is invoked from Attach() before the tabs have been inserted. 347 int GetInsertionIndexForDraggedBounds(const gfx::Rect& dragged_bounds) const; 348 349 // Returns true if |dragged_bounds| is close enough to the next stacked tab 350 // so that the active tab should be dragged there. 351 bool ShouldDragToNextStackedTab(const gfx::Rect& dragged_bounds, 352 int index) const; 353 354 // Returns true if |dragged_bounds| is close enough to the previous stacked 355 // tab so that the active tab should be dragged there. 356 bool ShouldDragToPreviousStackedTab(const gfx::Rect& dragged_bounds, 357 int index) const; 358 359 // Used by GetInsertionIndexForDraggedBounds() when the tabstrip is stacked. 360 int GetInsertionIndexForDraggedBoundsStacked( 361 const gfx::Rect& dragged_bounds) const; 362 363 // Retrieve the bounds of the DraggedTabView relative to the attached 364 // TabStrip. |tab_strip_point| is in the attached TabStrip's coordinate 365 // system. 366 gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& tab_strip_point); 367 368 // Get the position of the dragged tab view relative to the attached tab 369 // strip with the mirroring transform applied. 370 gfx::Point GetAttachedDragPoint(const gfx::Point& point_in_screen); 371 372 // Finds the Tabs within the specified TabStrip that corresponds to the 373 // WebContents of the dragged tabs. Returns an empty vector if not attached. 374 std::vector<Tab*> GetTabsMatchingDraggedContents(TabStrip* tabstrip); 375 376 // Returns the bounds for the tabs based on the attached tab strip. 377 std::vector<gfx::Rect> CalculateBoundsForDraggedTabs(); 378 379 // Does the work for EndDrag(). If we actually started a drag and |how_end| is 380 // not TAB_DESTROYED then one of EndDrag() or RevertDrag() is invoked. 381 void EndDragImpl(EndDragType how_end); 382 383 // Reverts a cancelled drag operation. 384 void RevertDrag(); 385 386 // Reverts the tab at |drag_index| in |drag_data_|. 387 void RevertDragAt(size_t drag_index); 388 389 // Selects the dragged tabs in |model|. Does nothing if there are no longer 390 // any dragged contents (as happens when a WebContents is deleted out from 391 // under us). 392 void ResetSelection(TabStripModel* model); 393 394 // Restores |initial_selection_model_| to the |source_tabstrip_|. 395 void RestoreInitialSelection(); 396 397 // Finishes a succesful drag operation. 398 void CompleteDrag(); 399 400 // Maximizes the attached window. 401 void MaximizeAttachedWindow(); 402 403 // Resets the delegates of the WebContents. 404 void ResetDelegates(); 405 406 // Returns the bounds (in screen coordinates) of the specified View. 407 gfx::Rect GetViewScreenBounds(views::View* tabstrip) const; 408 409 // Hides the frame for the window that contains the TabStrip the current 410 // drag session was initiated from. 411 void HideFrame(); 412 413 // Closes a hidden frame at the end of a drag session. 414 void CleanUpHiddenFrame(); 415 416 void BringWindowUnderPointToFront(const gfx::Point& point_in_screen); 417 418 // Convenience for getting the TabDragData corresponding to the tab the user 419 // started dragging. 420 TabDragData* source_tab_drag_data() { 421 return &(drag_data_[source_tab_index_]); 422 } 423 424 // Convenience for |source_tab_drag_data()->contents|. 425 content::WebContents* source_dragged_contents() { 426 return source_tab_drag_data()->contents; 427 } 428 429 // Returns the Widget of the currently attached TabStrip's BrowserView. 430 views::Widget* GetAttachedBrowserWidget(); 431 432 // Returns true if the tabs were originality one after the other in 433 // |source_tabstrip_|. 434 bool AreTabsConsecutive(); 435 436 // Calculates and returns new bounds for the dragged browser window. 437 // Takes into consideration current and restore bounds of |source| tab strip 438 // preventing the dragged size from being too small. Positions the new bounds 439 // such that the tab that was dragged remains under the |point_in_screen|. 440 // Offsets |drag_bounds| if necessary when dragging to the right from the 441 // source browser. 442 gfx::Rect CalculateDraggedBrowserBounds(TabStrip* source, 443 const gfx::Point& point_in_screen, 444 std::vector<gfx::Rect>* drag_bounds); 445 446 // Calculates scaled |drag_bounds| for dragged tabs and sets the tabs bounds. 447 // Layout of the tabstrip is performed and a new tabstrip width calculated. 448 // When |last_tabstrip_width| is larger than the new tabstrip width the tabs 449 // in attached tabstrip are scaled and the attached browser is positioned such 450 // that the tab that was dragged remains under the |point_in_screen|. 451 void AdjustBrowserAndTabBoundsForDrag(int last_tabstrip_width, 452 const gfx::Point& point_in_screen, 453 std::vector<gfx::Rect>* drag_bounds); 454 455 // Creates and returns a new Browser to handle the drag. 456 Browser* CreateBrowserForDrag(TabStrip* source, 457 const gfx::Point& point_in_screen, 458 gfx::Vector2d* drag_offset, 459 std::vector<gfx::Rect>* drag_bounds); 460 461 // Returns the TabStripModel for the specified tabstrip. 462 TabStripModel* GetModel(TabStrip* tabstrip) const; 463 464 // Returns the location of the cursor. This is either the location of the 465 // mouse or the location of the current touch point. 466 gfx::Point GetCursorScreenPoint(); 467 468 // Returns the offset from the top left corner of the window to 469 // |point_in_screen|. 470 gfx::Vector2d GetWindowOffset(const gfx::Point& point_in_screen); 471 472 // Returns true if moving the mouse only changes the visible tabs. 473 bool move_only() const { 474 return (move_behavior_ == MOVE_VISIBILE_TABS) != 0; 475 } 476 477 // Returns the NativeWindow at the specified point. If |exclude_dragged_view| 478 // is true, then the dragged view is not considered. 479 gfx::NativeWindow GetLocalProcessWindow(const gfx::Point& screen_point, 480 bool exclude_dragged_view); 481 482 // If true detaching creates a new browser and enters a nested message loop. 483 bool detach_into_browser_; 484 485 // Handles registering for notifications. 486 content::NotificationRegistrar registrar_; 487 488 EventSource event_source_; 489 490 // The TabStrip the drag originated from. 491 TabStrip* source_tabstrip_; 492 493 // The TabStrip the dragged Tab is currently attached to, or NULL if the 494 // dragged Tab is detached. 495 TabStrip* attached_tabstrip_; 496 497 // The screen that this drag is associated with. Cached, because other UI 498 // elements are NULLd at various points during the lifetime of this object. 499 gfx::Screen* screen_; 500 501 // The desktop type that this drag is associated with. Cached, because other 502 // UI elements are NULLd at various points during the lifetime of this 503 // object. 504 chrome::HostDesktopType host_desktop_type_; 505 506 // Aura mouse capture and release is used on Ash platforms as well as on 507 // Linux to ensure that pointer grab is not released prematurely. 508 bool use_aura_capture_policy_; 509 510 // The position of the mouse (in screen coordinates) at the start of the drag 511 // operation. This is used to calculate minimum elasticity before a 512 // DraggedTabView is constructed. 513 gfx::Point start_point_in_screen_; 514 515 // This is the offset of the mouse from the top left of the first Tab where 516 // dragging began. This is used to ensure that the dragged view is always 517 // positioned at the correct location during the drag, and to ensure that the 518 // detached window is created at the right location. 519 gfx::Point mouse_offset_; 520 521 // Ratio of the x-coordinate of the |source_tab_offset| to the width of the 522 // tab. 523 float offset_to_width_ratio_; 524 525 // A hint to use when positioning new windows created by detaching Tabs. This 526 // is the distance of the mouse from the top left of the dragged tab as if it 527 // were the distance of the mouse from the top left of the first tab in the 528 // attached TabStrip from the top left of the window. 529 gfx::Point window_create_point_; 530 531 // Location of the first tab in the source tabstrip in screen coordinates. 532 // This is used to calculate |window_create_point_|. 533 gfx::Point first_source_tab_point_; 534 535 // The bounds of the browser window before the last Tab was detached. When 536 // the last Tab is detached, rather than destroying the frame (which would 537 // abort the drag session), the frame is moved off-screen. If the drag is 538 // aborted (e.g. by the user pressing Esc, or capture being lost), the Tab is 539 // attached to the hidden frame and the frame moved back to these bounds. 540 gfx::Rect restore_bounds_; 541 542 // Storage ID in ViewStorage where the last view that had focus in the window 543 // containing |source_tab_| is saved. This is saved so that focus can be 544 // restored properly when a drag begins and ends within this same window. 545 const int old_focused_view_id_; 546 547 // The horizontal position of the mouse cursor in screen coordinates at the 548 // time of the last re-order event. 549 int last_move_screen_loc_; 550 551 // Timer used to bring the window under the cursor to front. If the user 552 // stops moving the mouse for a brief time over a browser window, it is 553 // brought to front. 554 base::OneShotTimer<TabDragController> bring_to_front_timer_; 555 556 // Timer used to move the stacked tabs. See comment aboue 557 // StartMoveStackedTimerIfNecessary(). 558 base::OneShotTimer<TabDragController> move_stacked_timer_; 559 560 // Did the mouse move enough that we started a drag? 561 bool started_drag_; 562 563 // Is the drag active? 564 bool active_; 565 566 DragData drag_data_; 567 568 // Index of the source tab in |drag_data_|. 569 size_t source_tab_index_; 570 571 // True until MoveAttached() is first invoked. 572 bool initial_move_; 573 574 // The selection model before the drag started. See comment above Init() for 575 // details. 576 ui::ListSelectionModel initial_selection_model_; 577 578 // The selection model of |attached_tabstrip_| before the tabs were attached. 579 ui::ListSelectionModel selection_model_before_attach_; 580 581 // Initial x-coordinates of the tabs when the drag started. Only used for 582 // touch mode. 583 std::vector<int> initial_tab_positions_; 584 585 DetachBehavior detach_behavior_; 586 MoveBehavior move_behavior_; 587 588 // Updated as the mouse is moved when attached. Indicates whether the mouse 589 // has ever moved to the left or right. If the tabs are ever detached this 590 // is set to kMovedMouseRight | kMovedMouseLeft. 591 int mouse_move_direction_; 592 593 // Last location used in screen coordinates. 594 gfx::Point last_point_in_screen_; 595 596 // The following are needed when detaching into a browser 597 // (|detach_into_browser_| is true). 598 599 // See description above getter. 600 bool is_dragging_window_; 601 602 // True if |attached_tabstrip_| is in a browser specifically created for 603 // the drag. 604 bool is_dragging_new_browser_; 605 606 // True if |source_tabstrip_| was maximized before the drag. 607 bool was_source_maximized_; 608 609 // True if |source_tabstrip_| was in immersive fullscreen before the drag. 610 bool was_source_fullscreen_; 611 612 // True if the initial drag resulted in restoring the window (because it was 613 // maximized). 614 bool did_restore_window_; 615 616 EndRunLoopBehavior end_run_loop_behavior_; 617 618 // If true, we're waiting for a move loop to complete. 619 bool waiting_for_run_loop_to_exit_; 620 621 // The TabStrip to attach to after the move loop completes. 622 TabStrip* tab_strip_to_attach_to_after_exit_; 623 624 // Non-null for the duration of RunMoveLoop. 625 views::Widget* move_loop_widget_; 626 627 // See description above getter. 628 bool is_mutating_; 629 630 // |attach_x_| and |attach_index_| are set to the x-coordinate of the mouse 631 // (in terms of the tabstrip) and the insertion index at the time tabs are 632 // dragged into a new browser (attached). They are used to ensure we don't 633 // shift the tabs around in the wrong direction. The two are only valid if 634 // |attach_index_| is not -1. 635 // See comment around use for more details. 636 int attach_x_; 637 int attach_index_; 638 639 scoped_ptr<ui::EventHandler> escape_tracker_; 640 641 base::WeakPtrFactory<TabDragController> weak_factory_; 642 643 DISALLOW_COPY_AND_ASSIGN(TabDragController); 644 }; 645 646 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_ 647