blob: c176a845132250297fd18d9dbd2cf765c13c3f33 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/drag_drop/tab_drag_drop_delegate.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/screen_util.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/wm/splitview/split_view_constants.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_drag_indicators.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "base/no_destructor.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/gfx/geometry/rect.h"
namespace ash {
namespace {
// The following distances are copied from tablet_mode_window_drag_delegate.cc.
// TODO(https://crbug.com/1069869): share these constants.
// Items dragged to within |kDistanceFromEdgeDp| of the screen will get snapped
// even if they have not moved by |kMinimumDragToSnapDistanceDp|.
constexpr float kDistanceFromEdgeDp = 16.f;
// The minimum distance that an item must be moved before it is snapped. This
// prevents accidental snaps.
constexpr float kMinimumDragToSnapDistanceDp = 96.f;
} // namespace
// static
bool TabDragDropDelegate::IsChromeTabDrag(const ui::OSExchangeData& drag_data) {
if (!features::IsWebUITabStripTabDragIntegrationEnabled())
return false;
base::Pickle pickle;
drag_data.GetPickledData(ui::ClipboardFormatType::GetWebCustomDataType(),
&pickle);
base::PickleIterator iter(pickle);
uint32_t entry_count = 0;
if (!iter.ReadUInt32(&entry_count))
return false;
for (uint32_t i = 0; i < entry_count; ++i) {
base::StringPiece16 type;
base::StringPiece16 data;
if (!iter.ReadStringPiece16(&type) || !iter.ReadStringPiece16(&data))
return false;
// TODO(https://crbug.com/1069869): share this constant between Ash
// and Chrome instead of hardcoding it in both places.
static const base::NoDestructor<base::string16> chrome_tab_type(
base::ASCIIToUTF16("application/vnd.chromium.tab"));
if (type == *chrome_tab_type)
return true;
}
return false;
}
TabDragDropDelegate::TabDragDropDelegate(
aura::Window* root_window,
aura::Window* source_window,
const gfx::Point& start_location_in_screen)
: root_window_(root_window),
source_window_(source_window),
start_location_in_screen_(start_location_in_screen) {
split_view_drag_indicators_ =
std::make_unique<SplitViewDragIndicators>(root_window_);
}
TabDragDropDelegate::~TabDragDropDelegate() = default;
void TabDragDropDelegate::DragUpdate(const gfx::Point& location_in_screen) {
const gfx::Rect area =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
root_window_);
SplitViewController::SnapPosition snap_position =
::ash::GetSnapPositionForLocation(
Shell::GetPrimaryRootWindow(), location_in_screen,
start_location_in_screen_,
/*snap_distance_from_edge=*/kDistanceFromEdgeDp,
/*minimum_drag_distance=*/kMinimumDragToSnapDistanceDp,
/*horizontal_edge_inset=*/area.width() *
kHighlightScreenPrimaryAxisRatio +
kHighlightScreenEdgePaddingDp,
/*vertical_edge_inset=*/area.height() *
kHighlightScreenPrimaryAxisRatio +
kHighlightScreenEdgePaddingDp);
split_view_drag_indicators_->SetWindowDraggingState(
SplitViewDragIndicators::ComputeWindowDraggingState(
true, SplitViewDragIndicators::WindowDraggingState::kFromTop,
snap_position));
// TODO(https://crbug.com/1069869): scale source window up/down similar to
// |TabletModeBrowserWindowDragDelegate::UpdateSourceWindow()|.
}
void TabDragDropDelegate::Drop(const gfx::Point& location_in_screen,
const ui::OSExchangeData& drop_data) {
aura::Window* const new_window =
Shell::Get()->shell_delegate()->CreateBrowserForTabDrop(source_window_,
drop_data);
const gfx::Rect area =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
root_window_);
SplitViewController::SnapPosition snap_position = ash::GetSnapPosition(
root_window_, new_window, location_in_screen, start_location_in_screen_,
/*snap_distance_from_edge=*/kDistanceFromEdgeDp,
/*minimum_drag_distance=*/kMinimumDragToSnapDistanceDp,
/*horizontal_edge_inset=*/area.width() *
kHighlightScreenPrimaryAxisRatio +
kHighlightScreenEdgePaddingDp,
/*vertical_edge_inset=*/area.height() * kHighlightScreenPrimaryAxisRatio +
kHighlightScreenEdgePaddingDp);
if (snap_position == SplitViewController::SnapPosition::NONE)
return;
SplitViewController::Get(new_window)->SnapWindow(new_window, snap_position);
}
} // namespace ash