#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
#include <algorithm>
#include <limits>
#include <optional>
#include <set>
#include <utility>
#include "base/auto_reset.h"
#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_auto_reset.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/sad_tab_helper.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/tabs/organization/metrics.h"
#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
#include "chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h"
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/chrome_widget_sublevel.h"
#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_slot_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout_helper.h"
#include "chrome/browser/ui/views/tabs/tab_strip_scroll_session.h"
#include "chrome/browser/ui/views/tabs/tab_style_views.h"
#include "chrome/browser/ui/views/tabs/window_finder.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
#include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "components/tab_groups/tab_group_id.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/presentation_time_recorder.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/drag_utils.h"
#include "ui/views/event_monitor.h"
#include "ui/views/interaction/element_tracker_views.h"
#include "ui/views/view_tracker.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/ui/base/window_properties.h"
#include "chromeos/ui/base/window_state_type.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/window_properties.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "base/debug/dump_without_crashing.h"
#include "base/strings/string_number_conversions.h"
#include "components/crash/core/common/crash_key.h"
#include "components/remote_cocoa/browser/window.h"
#endif
#if BUILDFLAG(IS_LINUX)
#include "ui/aura/client/drag_drop_client.h"
#endif
#if defined(USE_AURA)
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/wm/core/window_modality_controller.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
OpenURLParams;
WebContents;
static TabDragController* g_tab_drag_controller = …;
namespace {
constexpr int kMaximizedWindowInset = …;
bool PlatformProvidesAbsoluteWindowPositions() { … }
constexpr char kTabDraggingPresentationTimeHistogram[] = …;
constexpr char kTabDraggingPresentationTimeMaxHistogram[] = …;
constexpr char kDragAmongTabsPresentationTimeHistogram[] = …;
constexpr char kDragToNewBrowserPresentationTimeHistogram[] = …;
#if BUILDFLAG(IS_CHROMEOS)
aura::Window* GetWindowForTabDraggingProperties(const TabDragContext* context) {
return context ? context->GetWidget()->GetNativeWindow() : nullptr;
}
bool IsSnapped(const TabDragContext* context) {
DCHECK(context);
chromeos::WindowStateType type =
GetWindowForTabDraggingProperties(context)->GetProperty(
chromeos::kWindowStateTypeKey);
return type == chromeos::WindowStateType::kPrimarySnapped ||
type == chromeos::WindowStateType::kSecondarySnapped;
}
#else
bool IsSnapped(const TabDragContext* context) { … }
#endif
void SetCapture(TabDragContext* context) { … }
gfx::Rect GetTabstripScreenBounds(const TabDragContext* context) { … }
bool DoesRectContainVerticalPointExpanded(const gfx::Rect& bounds,
int vertical_adjustment,
int y) { … }
void OffsetX(int x_offset, std::vector<gfx::Rect>* rects) { … }
bool IsWindowDragUsingSystemDragDropAllowed() { … }
void UpdateSystemDnDDragImage(TabDragContext* attached_context,
const gfx::ImageSkia& image) { … }
}
class EventTracker : public ui::EventObserver { … };
class TabDragController::SourceTabStripEmptinessTracker
: public TabStripModelObserver { … };
class TabDragController::DraggedTabsClosedTracker
: public TabStripModelObserver { … };
TabDragController::TabDragData::TabDragData()
: … { … }
TabDragController::TabDragData::~TabDragData() = default;
TabDragController::TabDragData::TabDragData(TabDragData&&) = default;
const int TabDragController::kTouchVerticalDetachMagnetism = …;
const int TabDragController::kVerticalDetachMagnetism = …;
TabDragController::TabDragController()
: … { … }
TabDragController::~TabDragController() { … }
TabDragController::Liveness TabDragController::Init(
TabDragContext* source_context,
TabSlotView* source_view,
const std::vector<raw_ptr<TabSlotView, VectorExperimental>>& dragging_views,
const gfx::Point& mouse_offset,
int source_view_offset,
ui::ListSelectionModel initial_selection_model,
ui::mojom::DragEventSource event_source) { … }
bool TabDragController::IsAttachedTo(const TabDragContextBase* context) { … }
bool TabDragController::IsActive() { … }
bool TabDragController::IsSystemDragAndDropSessionRunning() { … }
void TabDragController::OnSystemDragAndDropUpdated(
const ui::DropTargetEvent& event) { … }
void TabDragController::OnSystemDragAndDropExited() { … }
void TabDragController::OnSystemDragAndDropEnded() { … }
TabDragContext* TabDragController::GetSourceContext() { … }
void TabDragController::TabWasAdded() { … }
void TabDragController::OnTabWillBeRemoved(content::WebContents* contents) { … }
bool TabDragController::CanRemoveTabDuringDrag(
content::WebContents* contents) const { … }
bool TabDragController::CanRestoreFullscreenWindowDuringDrag() const { … }
void TabDragController::Drag(const gfx::Point& point_in_screen) { … }
void TabDragController::EndDrag(EndDragReason reason) { … }
void TabDragController::SetDragLoopDoneCallbackForTesting(
base::OnceClosure callback) { … }
void TabDragController::InitDragData(TabSlotView* view,
TabDragData* drag_data) { … }
void TabDragController::OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) { … }
void TabDragController::OnWidgetDestroyed(views::Widget* widget) { … }
void TabDragController::OnSourceTabStripEmpty() { … }
void TabDragController::OnActiveStripWebContentsRemoved(
content::WebContents* contents) { … }
void TabDragController::OnActiveStripWebContentsReplaced(
content::WebContents* previous,
content::WebContents* next) { … }
void TabDragController::InitWindowCreatePoint() { … }
gfx::Point TabDragController::GetWindowCreatePoint(
const gfx::Point& origin) const { … }
void TabDragController::SaveFocus() { … }
void TabDragController::RestoreFocus() { … }
bool TabDragController::CanStartDrag(const gfx::Point& point_in_screen) const { … }
TabDragController::Liveness TabDragController::ContinueDragging(
const gfx::Point& point_in_screen) { … }
TabDragController::DragBrowserResultType
TabDragController::DragBrowserToNewTabStrip(TabDragContext* target_context,
const gfx::Point& point_in_screen) { … }
bool TabDragController::ShouldDragWindowUsingSystemDnD() { … }
gfx::ImageSkia TabDragController::GetDragImageForSystemDnD() { … }
TabDragController::Liveness TabDragController::StartSystemDnDSessionIfNecessary(
TabDragContext* context,
const gfx::Point& point_in_screen) { … }
gfx::Rect TabDragController::GetEnclosingRectForDraggedTabs() { … }
gfx::Point TabDragController::GetLastPointInScreen() { … }
bool TabDragController::IsDraggingTabState() { … }
views::View* TabDragController::GetAttachedContext() { … }
views::ScrollView* TabDragController::GetScrollView() { … }
void TabDragController::MoveAttached(const gfx::Point& point_in_screen,
bool just_attached) { … }
TabDragController::DetachPosition TabDragController::GetDetachPosition(
const gfx::Point& point_in_screen) { … }
void TabDragController::DetachAndAttachToNewContext(
ReleaseCapture release_capture,
TabDragContext* target_context,
const gfx::Point& point_in_screen,
bool set_capture) { … }
TabDragController::Liveness TabDragController::GetTargetTabStripForPoint(
const gfx::Point& point_in_screen,
TabDragContext** context) { … }
bool TabDragController::DoesTabStripContain(
TabDragContext* context,
const gfx::Point& point_in_screen) const { … }
void TabDragController::Attach(TabDragContext* attached_context,
const gfx::Point& point_in_screen,
std::unique_ptr<TabDragController> controller,
bool set_capture) { … }
std::unique_ptr<TabDragController> TabDragController::Detach(
ReleaseCapture release_capture) { … }
void TabDragController::DetachIntoNewBrowserAndRunMoveLoop(
const gfx::Point& point_in_screen) { … }
void TabDragController::RunMoveLoop(const gfx::Vector2d& drag_offset) { … }
gfx::Rect TabDragController::GetDraggedViewTabStripBounds(
const gfx::Point& tab_strip_point) { … }
gfx::Point TabDragController::GetAttachedDragPoint(
const gfx::Point& point_in_screen) { … }
std::vector<raw_ptr<TabSlotView, VectorExperimental>>
TabDragController::GetViewsMatchingDraggedContents(TabDragContext* context) { … }
void TabDragController::EndDragImpl(EndDragType type) { … }
void TabDragController::RevertDrag() { … }
void TabDragController::ResetSelection(TabStripModel* model) { … }
void TabDragController::RestoreInitialSelection() { … }
void TabDragController::RevertHeaderDrag(tab_groups::TabGroupId group_id) { … }
void TabDragController::RevertDragAt(size_t drag_index) { … }
void TabDragController::CompleteDrag() { … }
void TabDragController::MaximizeAttachedWindow() { … }
void TabDragController::BringWindowUnderPointToFront(
const gfx::Point& point_in_screen) { … }
bool TabDragController::IsDraggingTab(content::WebContents* contents) const { … }
views::Widget* TabDragController::GetAttachedBrowserWidget() { … }
bool TabDragController::AreTabsConsecutive() { … }
gfx::Rect TabDragController::CalculateDraggedBrowserBounds(
TabDragContext* source,
const gfx::Point& point_in_screen,
std::vector<gfx::Rect>* drag_bounds) { … }
gfx::Rect TabDragController::CalculateNonMaximizedDraggedBrowserBounds(
views::Widget* widget,
const gfx::Point& point_in_screen) { … }
void TabDragController::AdjustBrowserAndTabBoundsForDrag(
int previous_tab_area_width,
const gfx::Point& point_in_screen,
gfx::Vector2d* drag_offset,
std::vector<gfx::Rect>* drag_bounds) { … }
std::optional<webapps::AppId> TabDragController::GetControllingAppForDrag(
Browser* browser) { … }
Browser* TabDragController::CreateBrowserForDrag(
TabDragContext* source,
const gfx::Point& point_in_screen,
gfx::Vector2d* drag_offset,
std::vector<gfx::Rect>* drag_bounds) { … }
gfx::Point TabDragController::GetCursorScreenPoint() { … }
gfx::Vector2d TabDragController::GetWindowOffset(
const gfx::Point& point_in_screen) { … }
TabDragController::Liveness TabDragController::GetLocalProcessWindow(
const gfx::Point& screen_point,
bool exclude_dragged_view,
gfx::NativeWindow* window) { … }
void TabDragController::SetTabDraggingInfo() { … }
void TabDragController::ClearTabDraggingInfo() { … }
std::optional<tab_groups::TabGroupId>
TabDragController::CalculateGroupForDraggedTabs(int to_index) { … }
bool TabDragController::CanAttachTo(gfx::NativeWindow window) { … }
int TabDragController::GetOutOfBoundsYCoordinate() const { … }
void TabDragController::NotifyEventIfTabAddedToGroup() { … }
void TabDragController::MaybePauseTrackingSavedTabGroup() { … }
void TabDragController::MaybeResumeTrackingSavedTabGroup() { … }