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