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 <stddef.h>
9 
10 #include <memory>
11 #include <vector>
12 
13 #include "base/memory/weak_ptr.h"
14 #include "base/scoped_observer.h"
15 #include "base/timer/timer.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
17 #include "chrome/browser/ui/views/tabs/tab_drag_context.h"
18 #include "chrome/browser/ui/views/tabs/tab_strip_types.h"
19 #include "components/tab_groups/tab_group_visual_data.h"
20 #include "ui/base/models/list_selection_model.h"
21 #include "ui/gfx/geometry/rect.h"
22 #include "ui/gfx/native_widget_types.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/widget/widget_observer.h"
25 
26 namespace ui {
27 class ListSelectionModel;
28 }
29 namespace views {
30 class View;
31 class ViewTracker;
32 }
33 class Browser;
34 class KeyEventTracker;
35 class Tab;
36 class TabDragControllerTest;
37 class TabDragContext;
38 class TabSlotView;
39 class TabStripModel;
40 class WindowFinder;
41 
42 // TabDragController is responsible for managing the tab dragging session. When
43 // the user presses the mouse on a tab a new TabDragController is created and
44 // Drag() is invoked as the mouse is dragged. If the mouse is dragged far enough
45 // TabDragController starts a drag session. The drag session is completed when
46 // EndDrag() is invoked (or the TabDragController is destroyed).
47 //
48 // While dragging within a tab strip TabDragController sets the bounds of the
49 // tabs (this is referred to as attached). When the user drags far enough such
50 // that the tabs should be moved out of the tab strip a new Browser is created
51 // and RunMoveLoop() is invoked on the Widget to drag the browser around. This
52 // is the default on aura.
53 class TabDragController : public views::WidgetObserver {
54  public:
55   // What should happen as the mouse is dragged within the tabstrip.
56   enum MoveBehavior {
57     // Only the set of visible tabs should change. This is only applicable when
58     // using touch layout.
59     MOVE_VISIBLE_TABS,
60 
61     // Typical behavior where tabs are dragged around.
62     REORDER
63   };
64 
65   // Indicates the event source that initiated the drag.
66   enum EventSource {
67     EVENT_SOURCE_MOUSE,
68     EVENT_SOURCE_TOUCH,
69   };
70 
71   // Amount above or below the tabstrip the user has to drag before detaching.
72   static const int kTouchVerticalDetachMagnetism;
73   static const int kVerticalDetachMagnetism;
74 
75   TabDragController();
76   TabDragController(const TabDragController&) = delete;
77   TabDragController& operator=(const TabDragController&) = delete;
78   ~TabDragController() override;
79 
80   // Initializes TabDragController to drag the views in |dragging_views|
81   // originating from |source_context|. |source_view| is the view that
82   // initiated the drag and is either a Tab or a TabGroupHeader contained in
83   // |dragging_views|. |mouse_offset| is the distance of the mouse pointer from
84   // the origin of the first view in |dragging_views| and |source_view_offset|
85   // the offset from |source_view|. |source_view_offset| is the horizontal
86   // offset of |mouse_offset| relative to |source_view|.
87   // |initial_selection_model| is the selection model before the drag started
88   // and is only non-empty if the original selection isn't the same as the
89   // dragging set.
90   void Init(TabDragContext* source_context,
91             TabSlotView* source_view,
92             const std::vector<TabSlotView*>& dragging_views,
93             const gfx::Point& mouse_offset,
94             int source_view_offset,
95             ui::ListSelectionModel initial_selection_model,
96             MoveBehavior move_behavior,
97             EventSource event_source);
98 
99   // Returns true if there is a drag underway and the drag is attached to
100   // |tab_strip|.
101   // NOTE: this returns false if the TabDragController is in the process of
102   // finishing the drag.
103   static bool IsAttachedTo(const TabDragContext* tab_strip);
104 
105   // Returns true if there is a drag underway.
106   static bool IsActive();
107 
108   // Returns the pointer of |source_context_|.
109   static TabDragContext* GetSourceContext();
110 
111   // Sets the move behavior. Has no effect if started_drag() is true.
112   void SetMoveBehavior(MoveBehavior behavior);
113 
event_source()114   EventSource event_source() const { return event_source_; }
115 
116   // See description above fields for details on these.
active()117   bool active() const { return current_state_ != DragState::kStopped; }
attached_context()118   const TabDragContext* attached_context() const { return attached_context_; }
119 
120   // Returns true if a drag started.
started_drag()121   bool started_drag() const { return current_state_ != DragState::kNotStarted; }
122 
123   // Returns true if mutating the TabStripModel.
is_mutating()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.
is_dragging_window()128   bool is_dragging_window() const {
129     return current_state_ == DragState::kDraggingWindow;
130   }
131 
132   // Returns the tab group being dragged, if any. Will only return a value if
133   // the user is dragging a tab group header, not an individual tab or tabs from
134   // a group.
group()135   const base::Optional<tab_groups::TabGroupId>& group() const { return group_; }
136 
137   // Returns true if currently dragging a tab with |contents|.
138   bool IsDraggingTab(content::WebContents* contents);
139 
140   // Invoked to drag to the new location, in screen coordinates.
141   void Drag(const gfx::Point& point_in_screen);
142 
143   // Complete the current drag session.
144   void EndDrag(EndDragReason reason);
145 
146  private:
147   friend class TabDragControllerTest;
148 
149 #if defined(OS_CHROMEOS)
150   class DeferredTargetTabstripObserver;
151 #endif
152 
153   class SourceTabStripEmptinessTracker;
154 
155   class DraggedTabsClosedTracker;
156 
157   // Used to indicate the direction the mouse has moved when attached.
158   static const int kMovedMouseLeft  = 1 << 0;
159   static const int kMovedMouseRight = 1 << 1;
160 
161   enum class DragState {
162     // The drag has not yet started; the user has not dragged far enough to
163     // begin a session.
164     kNotStarted,
165     // The session is dragging a set of tabs within |attached_context_|.
166     kDraggingTabs,
167     // The session is dragging a window; |attached_context_| is that window's
168     // tabstrip.
169     kDraggingWindow,
170     // The session is waiting for the nested move loop to exit to transition
171     // to kDraggingTabs.  Not used on all platforms.
172     kWaitingToDragTabs,
173     // The session is waiting for the nested move loop to exit to end the drag.
174     kWaitingToStop,
175     // The drag session has completed or been canceled.
176     kStopped
177   };
178 
179   enum class Liveness {
180     ALIVE,
181     DELETED,
182   };
183 
184   // Enumeration of the ways a drag session can end.
185   enum EndDragType {
186     // Drag session exited normally: the user released the mouse.
187     NORMAL,
188 
189     // The drag session was canceled (alt-tab during drag, escape ...)
190     CANCELED,
191 
192     // The tab (NavigationController) was destroyed during the drag.
193     TAB_DESTROYED
194   };
195 
196   // Whether Detach() should release capture or not.
197   enum ReleaseCapture {
198     RELEASE_CAPTURE,
199     DONT_RELEASE_CAPTURE,
200   };
201 
202   // Enumeration of the possible positions the detached tab may detach from.
203   enum DetachPosition {
204     DETACH_BEFORE,
205     DETACH_AFTER,
206     DETACH_ABOVE_OR_BELOW
207   };
208 
209   // Specifies what should happen when a drag motion exits the tab strip region
210   // in an attempt to detach a tab.
211   enum DetachBehavior {
212     DETACHABLE,
213     NOT_DETACHABLE
214   };
215 
216   // Indicates what should happen after invoking DragBrowserToNewTabStrip().
217   enum DragBrowserResultType {
218     // The caller should return immediately. This return value is used if a
219     // nested run loop was created or we're in a nested run loop and
220     // need to exit it.
221     DRAG_BROWSER_RESULT_STOP,
222 
223     // The caller should continue.
224     DRAG_BROWSER_RESULT_CONTINUE,
225   };
226 
227   // Stores the date associated with a single tab that is being dragged.
228   struct TabDragData {
229     TabDragData();
230     TabDragData(const TabDragData&) = delete;
231     TabDragData& operator=(const TabDragData&) = delete;
232     ~TabDragData();
233     TabDragData(TabDragData&&);
234 
235     // The WebContents being dragged.
236     content::WebContents* contents;
237 
238     // There is a brief period of time when a tab is being moved from one tab
239     // strip to another [after Detach but before Attach] that the TabDragData
240     // owns the WebContents.
241     std::unique_ptr<content::WebContents> owned_contents;
242 
243     // This is the index of the tab in |source_context_| when the drag
244     // began. This is used to restore the previous state if the drag is aborted.
245     int source_model_index;
246 
247     // If attached this is the view in |attached_context_|.
248     TabSlotView* attached_view;
249 
250     // Is the tab pinned?
251     bool pinned;
252 
253     // Contains the information for the tab's group at the start of the drag.
254     struct TabGroupData {
255       tab_groups::TabGroupId group_id;
256       tab_groups::TabGroupVisualData group_visual_data;
257     };
258 
259     // Stores the information of the group the tab is in, or nullopt if tab is
260     // not grouped.
261     base::Optional<TabGroupData> tab_group_data;
262   };
263 
264   typedef std::vector<TabDragData> DragData;
265 
266   // Sets |drag_data| from |view|. This also registers for necessary
267   // notifications and resets the delegate of the WebContents.
268   void InitDragData(TabSlotView* view, TabDragData* drag_data);
269 
270   // Overriden from views::WidgetObserver:
271   void OnWidgetBoundsChanged(views::Widget* widget,
272                              const gfx::Rect& new_bounds) override;
273   void OnWidgetDestroyed(views::Widget* widget) override;
274 
275   // Forget the source tabstrip. It doesn't exist any more, so it doesn't
276   // make sense to insert dragged tabs back into it if the drag is reverted.
277   void OnSourceTabStripEmpty();
278 
279   // A tab was closed in the active tabstrip. Clean up if we were dragging it.
280   void OnActiveStripWebContentsRemoved(content::WebContents* contents);
281 
282   // Initialize the offset used to calculate the position to create windows
283   // in |GetWindowCreatePoint|. This should only be invoked from |Init|.
284   void InitWindowCreatePoint();
285 
286   // Returns the point where a detached window should be created given the
287   // current mouse position |origin|.
288   gfx::Point GetWindowCreatePoint(const gfx::Point& origin) const;
289 
290   void UpdateDockInfo(const gfx::Point& point_in_screen);
291 
292   // Saves focus in the window that the drag initiated from. Focus will be
293   // restored appropriately if the drag ends within this same window.
294   void SaveFocus();
295 
296   // Restore focus to the View that had focus before the drag was started, if
297   // the drag ends within the same Window as it began.
298   void RestoreFocus();
299 
300   // Tests whether |point_in_screen| is past a minimum elasticity threshold
301   // required to start a drag.
302   bool CanStartDrag(const gfx::Point& point_in_screen) const;
303 
304   // Invoked once a drag has started to determine the appropriate context to
305   // drag to (which may be the currently attached one).
306   Liveness ContinueDragging(const gfx::Point& point_in_screen)
307       WARN_UNUSED_RESULT;
308 
309   // Transitions dragging from |attached_context_| to |target_context|.
310   // |target_context| is NULL if the mouse is not over a valid tab strip.  See
311   // DragBrowserResultType for details of the return type.
312   DragBrowserResultType DragBrowserToNewTabStrip(
313       TabDragContext* target_context,
314       const gfx::Point& point_in_screen);
315 
316   // Handles dragging for a touch context when the tabs are stacked. Doesn't
317   // actually reorder the tabs in anyway, just changes what's visible.
318   void DragActiveTabStacked(const gfx::Point& point_in_screen);
319 
320   // Moves the active tab to the next/previous tab. Used when the next/previous
321   // tab is stacked.
322   void MoveAttachedToNextStackedIndex(const gfx::Point& point_in_screen);
323   void MoveAttachedToPreviousStackedIndex(const gfx::Point& point_in_screen);
324 
325   // Handles dragging tabs while the tabs are attached.
326   void MoveAttached(const gfx::Point& point_in_screen);
327 
328   // If necessary starts the |move_stacked_timer_|. The timer is started if
329   // close enough to an edge with stacked tabs.
330   void StartMoveStackedTimerIfNecessary(const gfx::Point& point_in_screen,
331                                         base::TimeDelta delay);
332 
333   // Returns the compatible TabDragContext to drag to at the
334   // specified point (screen coordinates), or nullptr if there is none.
335   Liveness GetTargetTabStripForPoint(const gfx::Point& point_in_screen,
336                                      TabDragContext** tab_strip);
337 
338   // Returns true if |context| contains the specified point in screen
339   // coordinates.
340   bool DoesTabStripContain(TabDragContext* context,
341                            const gfx::Point& point_in_screen) const;
342 
343   // Returns the DetachPosition given the specified location in screen
344   // coordinates.
345   DetachPosition GetDetachPosition(const gfx::Point& point_in_screen);
346 
347   // Attach the dragged Tab to the specified TabDragContext. If
348   // |set_capture| is true, the newly attached context will have capture.
349   void Attach(TabDragContext* attached_context,
350               const gfx::Point& point_in_screen,
351               bool set_capture = true);
352 
353   // Detach the dragged Tab from the current TabDragContext.
354   void Detach(ReleaseCapture release_capture);
355 
356   // Detaches the tabs being dragged, creates a new Browser to contain them and
357   // runs a nested move loop.
358   void DetachIntoNewBrowserAndRunMoveLoop(const gfx::Point& point_in_screen);
359 
360   // Runs a nested run loop that handles moving the current
361   // Browser. |drag_offset| is the offset from the window origin and is used in
362   // calculating the location of the window offset from the cursor while
363   // dragging.
364   void RunMoveLoop(const gfx::Vector2d& drag_offset);
365 
366   // Retrieves the bounds of the dragged tabs relative to the attached
367   // TabDragContext. |tab_strip_point| is in the attached
368   // TabDragContext's coordinate system.
369   gfx::Rect GetDraggedViewTabStripBounds(const gfx::Point& tab_strip_point);
370 
371   // Gets the position of the dragged tabs relative to the attached tab strip
372   // with the mirroring transform applied.
373   gfx::Point GetAttachedDragPoint(const gfx::Point& point_in_screen);
374 
375   // Finds the TabSlotViews within the specified TabDragContext that
376   // corresponds to the WebContents of the dragged views. Also finds the group
377   // header if it is dragging. Returns an empty vector if not attached.
378   std::vector<TabSlotView*> GetViewsMatchingDraggedContents(
379       TabDragContext* context);
380 
381   // Does the work for EndDrag(). If we actually started a drag and |how_end| is
382   // not TAB_DESTROYED then one of EndDrag() or RevertDrag() is invoked.
383   void EndDragImpl(EndDragType how_end);
384 
385   // Called after the drag ends and |deferred_target_context_| is not nullptr.
386   void PerformDeferredAttach();
387 
388   // Reverts a cancelled drag operation.
389   void RevertDrag();
390 
391   // Reverts the tab at |drag_index| in |drag_data_|.
392   void RevertDragAt(size_t drag_index);
393 
394   // Selects the dragged tabs in |model|. Does nothing if there are no longer
395   // any dragged contents (as happens when a WebContents is deleted out from
396   // under us).
397   void ResetSelection(TabStripModel* model);
398 
399   // Restores |initial_selection_model_| to the |source_context_|.
400   void RestoreInitialSelection();
401 
402   // Finishes a successful drag operation.
403   void CompleteDrag();
404 
405   // Maximizes the attached window.
406   void MaximizeAttachedWindow();
407 
408   // Hides the frame for the window that contains the TabDragContext
409   // the current drag session was initiated from.
410   void HideFrame();
411 
412   void BringWindowUnderPointToFront(const gfx::Point& point_in_screen);
413 
414   // Convenience for getting the TabDragData corresponding to the source view
415   // that the user started dragging.
source_view_drag_data()416   TabDragData* source_view_drag_data() {
417     return &(drag_data_[source_view_index_]);
418   }
419 
420   // Convenience for |source_view_drag_data()->contents|.
source_dragged_contents()421   content::WebContents* source_dragged_contents() {
422     return source_view_drag_data()->contents;
423   }
424 
425   // Returns the number of Tab views currently dragging.
426   // Excludes the TabGroupHeader view, if any.
num_dragging_tabs()427   int num_dragging_tabs() {
428     return header_drag_ ? drag_data_.size() - 1 : drag_data_.size();
429   }
430 
431   // Returns the index of the first Tab, since the first dragging view may
432   // instead be a TabGroupHeader.
first_tab_index()433   int first_tab_index() { return header_drag_ ? 1 : 0; }
434 
435   // Returns the Widget of the currently attached TabDragContext's
436   // BrowserView.
437   views::Widget* GetAttachedBrowserWidget();
438 
439   // Returns true if the tabs were originality one after the other in
440   // |source_context_|.
441   bool AreTabsConsecutive();
442 
443   // Calculates and returns new bounds for the dragged browser window.
444   // Takes into consideration current and restore bounds of |source| tab strip
445   // preventing the dragged size from being too small. Positions the new bounds
446   // such that the tab that was dragged remains under the |point_in_screen|.
447   // Offsets |drag_bounds| if necessary when dragging to the right from the
448   // source browser.
449   gfx::Rect CalculateDraggedBrowserBounds(TabDragContext* source,
450                                           const gfx::Point& point_in_screen,
451                                           std::vector<gfx::Rect>* drag_bounds);
452 
453   // Calculates and returns the dragged bounds for the non-maximize dragged
454   // browser window. Taks into consideration the initial drag offset so that
455   // the dragged tab remains under the |point_in_screen|.
456   gfx::Rect CalculateNonMaximizedDraggedBrowserBounds(
457       views::Widget* widget,
458       const gfx::Point& point_in_screen);
459 
460   // Calculates scaled |drag_bounds| for dragged tabs and sets the tabs bounds.
461   // Layout of the tabstrip is performed and a new tabstrip width calculated.
462   // When |last_tabstrip_width| is larger than the new tabstrip width the tabs
463   // in the attached tabstrip are scaled and the attached browser is positioned
464   // such that the tab that was dragged remains under the |point_in_screen|.
465   // |drag_offset| is the offset of |point_in_screen| from the origin of the
466   // dragging browser window, and will be updated when this method ends up with
467   // changing the origin of the attached browser window.
468   void AdjustBrowserAndTabBoundsForDrag(int last_tabstrip_width,
469                                         const gfx::Point& point_in_screen,
470                                         gfx::Vector2d* drag_offset,
471                                         std::vector<gfx::Rect>* drag_bounds);
472 
473   // Creates and returns a new Browser to handle the drag.
474   Browser* CreateBrowserForDrag(TabDragContext* source,
475                                 const gfx::Point& point_in_screen,
476                                 gfx::Vector2d* drag_offset,
477                                 std::vector<gfx::Rect>* drag_bounds);
478 
479   // Returns the location of the cursor. This is either the location of the
480   // mouse or the location of the current touch point.
481   gfx::Point GetCursorScreenPoint();
482 
483   // Returns the offset from the top left corner of the window to
484   // |point_in_screen|.
485   gfx::Vector2d GetWindowOffset(const gfx::Point& point_in_screen);
486 
487   // Returns true if moving the mouse only changes the visible tabs.
move_only()488   bool move_only() const {
489     return (move_behavior_ == MOVE_VISIBLE_TABS) != 0;
490   }
491 
492   // Returns the NativeWindow in |window| at the specified point. If
493   // |exclude_dragged_view| is true, then the dragged view is not considered.
494   Liveness GetLocalProcessWindow(const gfx::Point& screen_point,
495                                  bool exclude_dragged_view,
496                                  gfx::NativeWindow* window) WARN_UNUSED_RESULT;
497 
498   // Sets the dragging info for the current dragged context. On Chrome OS, the
499   // dragging info include two window properties: one is to indicate if the
500   // tab-dragging process starts/stops, and the other is to indicate which
501   // window initiates the dragging. This function is supposed to be called
502   // whenever the dragged tabs are attached to a new tabstrip.
503   void SetTabDraggingInfo();
504 
505   // Clears the tab dragging info for the current dragged context. This
506   // function is supposed to be called whenever the dragged tabs are detached
507   // from the old context or the tab dragging is ended.
508   void ClearTabDraggingInfo();
509 
510   // Sets |deferred_target_context_| and updates its corresponding window
511   // property. |location| is the location of the pointer when the deferred
512   // target is set.
513   void SetDeferredTargetTabstrip(TabDragContext* deferred_target_context);
514 
515   DragState current_state_;
516 
517   // Tests whether a drag can be attached to a |window|.  Drags may be
518   // disallowed for reasons such as the target: does not support tabs, is
519   // showing a modal, has a different profile, is a different browser type
520   // (NORMAL vs APP).
521   bool CanAttachTo(gfx::NativeWindow window);
522 
523   // Helper method for TabDragController::MoveAttached to update the tab group
524   // membership of selected tabs. UpdateGroupForDraggedTabs should be called
525   // after the tabs move in a drag so the first selected index is the target
526   // index of the move.
527   void UpdateGroupForDraggedTabs();
528 
529   // Helper method for TabDragController::UpdateGroupForDraggedTabs to decide if
530   // a dragged tab should stay in the tab group. Returns base::nullopt if the
531   // tab should not be in a group. Otherwise returns tab_groups::TabGroupId of
532   // the group the selected tabs should join.
533   base::Optional<tab_groups::TabGroupId> GetTabGroupForTargetIndex(
534       const std::vector<int>& selected);
535 
536   EventSource event_source_;
537 
538   // The TabDragContext the drag originated from. This is set to null
539   // if destroyed during the drag.
540   TabDragContext* source_context_;
541 
542   // The TabDragContext the dragged Tab is currently attached to, or
543   // null if the dragged Tab is detached.
544   TabDragContext* attached_context_;
545 
546 #if defined(OS_CHROMEOS)
547   // Observe the target TabDragContext to attach to after the drag
548   // ends. It's only possible to happen in Chrome OS tablet mode, if the dragged
549   // tabs are dragged over an overview window, we should wait until the drag
550   // ends to attach it.
551   std::unique_ptr<DeferredTargetTabstripObserver>
552       deferred_target_context_observer_;
553 #endif
554 
555   // Whether capture can be released during the drag. When false, capture should
556   // not be released when transferring capture between widgets and when starting
557   // the move loop.
558   bool can_release_capture_;
559 
560   // The position of the mouse (in screen coordinates) at the start of the drag
561   // operation. This is used to calculate minimum elasticity before a
562   // DraggedTabView is constructed.
563   gfx::Point start_point_in_screen_;
564 
565   // This is the offset of the mouse from the top left of the first Tab where
566   // dragging began. This is used to ensure that the dragged view is always
567   // positioned at the correct location during the drag, and to ensure that the
568   // detached window is created at the right location.
569   gfx::Point mouse_offset_;
570 
571   // Ratio of the x-coordinate of the |source_view_offset| to the width of the
572   // source view.
573   float offset_to_width_ratio_;
574 
575   // A hint to use when positioning new windows created by detaching Tabs. This
576   // is the distance of the mouse from the top left of the dragged tab as if it
577   // were the distance of the mouse from the top left of the first tab in the
578   // attached TabDragContext from the top left of the window.
579   gfx::Point window_create_point_;
580 
581   // Location of the first tab in the source tabstrip in screen coordinates.
582   // This is used to calculate |window_create_point_|.
583   gfx::Point first_source_tab_point_;
584 
585   // Used to track the view that had focus in the window containing
586   // |source_view_|. This is saved so that focus can be restored properly when
587   // a drag begins and ends within this same window.
588   std::unique_ptr<views::ViewTracker> old_focused_view_tracker_;
589 
590   // The horizontal position of the mouse cursor in screen coordinates at the
591   // time of the last re-order event.
592   int last_move_screen_loc_;
593 
594   // Timer used to bring the window under the cursor to front. If the user
595   // stops moving the mouse for a brief time over a browser window, it is
596   // brought to front.
597   base::OneShotTimer bring_to_front_timer_;
598 
599   // Timer used to move the stacked tabs. See comment aboue
600   // StartMoveStackedTimerIfNecessary().
601   base::OneShotTimer move_stacked_timer_;
602 
603   DragData drag_data_;
604 
605   // Index of the source view in |drag_data_|.
606   size_t source_view_index_;
607 
608   // The attached views. Also found in |drag_data_|, but cached for convenience.
609   std::vector<TabSlotView*> attached_views_;
610 
611   // Whether the drag originated from a group header.
612   bool header_drag_;
613 
614   // The group that is being dragged. Only set if the drag originated from a
615   // group header, indicating that the entire group is being dragged together.
616   base::Optional<tab_groups::TabGroupId> group_;
617 
618   // True until MoveAttached() is first invoked.
619   bool initial_move_;
620 
621   // The selection model before the drag started. See comment above Init() for
622   // details.
623   ui::ListSelectionModel initial_selection_model_;
624 
625   // The selection model of |attached_context_| before the tabs were attached.
626   ui::ListSelectionModel selection_model_before_attach_;
627 
628   // Initial x-coordinates of the tabs when the drag started. Only used for
629   // touch mode.
630   std::vector<int> initial_tab_positions_;
631 
632   // What should occur during ConinueDragging when a tab is attempted to be
633   // detached.
634   DetachBehavior detach_behavior_;
635 
636   MoveBehavior move_behavior_;
637 
638   // Updated as the mouse is moved when attached. Indicates whether the mouse
639   // has ever moved to the left. If the tabs are ever detached this is set to
640   // true.
641   bool mouse_has_ever_moved_left_;
642 
643   // Updated as the mouse is moved when attached. Indicates whether the mouse
644   // has ever moved to the right. If the tabs are ever detached this is set
645   // to true.
646   bool mouse_has_ever_moved_right_;
647 
648   // Last location used in screen coordinates.
649   gfx::Point last_point_in_screen_;
650 
651   // The following are needed when detaching into a browser
652   // (|detach_into_browser_| is true).
653 
654   // True if |attached_context_| is in a browser specifically created for
655   // the drag.
656   bool is_dragging_new_browser_;
657 
658   // True if |source_context_| was maximized before the drag.
659   bool was_source_maximized_;
660 
661   // True if |source_context_| was in immersive fullscreen before the drag.
662   bool was_source_fullscreen_;
663 
664   // True if the initial drag resulted in restoring the window (because it was
665   // maximized).
666   bool did_restore_window_;
667 
668   // The TabDragContext to attach to after the move loop completes.
669   TabDragContext* tab_strip_to_attach_to_after_exit_;
670 
671   // Non-null for the duration of RunMoveLoop.
672   views::Widget* move_loop_widget_;
673 
674   // See description above getter.
675   bool is_mutating_;
676 
677   // |attach_x_| and |attach_index_| are set to the x-coordinate of the mouse
678   // (in terms of the tabstrip) and the insertion index at the time tabs are
679   // dragged into a new browser (attached). They are used to ensure we don't
680   // shift the tabs around in the wrong direction. The two are only valid if
681   // |attach_index_| is not -1.
682   // See comment around use for more details.
683   int attach_x_;
684   int attach_index_;
685 
686   std::unique_ptr<KeyEventTracker> key_event_tracker_;
687 
688   std::unique_ptr<SourceTabStripEmptinessTracker>
689       source_context_emptiness_tracker_;
690 
691   std::unique_ptr<DraggedTabsClosedTracker>
692       attached_context_tabs_closed_tracker_;
693 
694   std::unique_ptr<WindowFinder> window_finder_;
695 
696   ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
697 
698   base::WeakPtrFactory<TabDragController> weak_factory_{this};
699 };
700 
701 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_DRAG_CONTROLLER_H_
702