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