#include "ash/shelf/drag_window_from_shelf_controller.h"
#include <algorithm>
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/constants/ash_features.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/window_backdrop.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/root_window_controller.h"
#include "ash/screen_util.h"
#include "ash/shelf/hotseat_widget.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/window_scale_animation.h"
#include "ash/shell.h"
#include "ash/wallpaper/views/wallpaper_view.h"
#include "ash/wallpaper/views/wallpaper_widget_controller.h"
#include "ash/wallpaper/wallpaper_constants.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/float/float_controller.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_constants.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_utils.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 "ash/wm/window_properties.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_transient_descendant_iterator.h"
#include "ash/wm/window_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/compositor/presentation_time_recorder.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/transform_util.h"
#include "ui/views/animation/animation_builder.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/scoped_animation_disabler.h"
#include "ui/wm/core/window_util.h"
namespace ash {
namespace {
constexpr float kMinimumWindowScaleDuringDragging = 0.3f;
constexpr float kMinYDisplayHeightRatio = 0.125f;
constexpr base::TimeDelta kShowOverviewTimeWhenDragSuspend =
base::Milliseconds(40);
constexpr float kScrollUpdateOverviewThreshold = 2.f;
constexpr float kOtherWindowFullFadeHeightRatio = 8.f;
constexpr float kOtherWindowMaxScale = 0.9f;
constexpr char kDragWindowFromShelfHistogram[] =
"Ash.DragWindowFromShelf.PresentationTime";
constexpr char kDragWindowFromShelfMaxLatencyHistogram[] =
"Ash.DragWindowFromShelf.PresentationTime.MaxLatency";
class OtherWindowCopyAnimation {
public:
OtherWindowCopyAnimation(
std::unique_ptr<ui::LayerTreeOwner> other_window_copy,
bool show)
: other_window_copy_(std::move(other_window_copy)) {
ui::Layer* layer = other_window_copy_->root();
views::AnimationBuilder builder;
builder
.OnEnded(base::BindOnce(&OtherWindowCopyAnimation::OnAnimationEnded,
base::Unretained(this)))
.OnAborted(base::BindOnce(&OtherWindowCopyAnimation::OnAnimationEnded,
base::Unretained(this)))
.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
.Once()
.SetDuration(base::Milliseconds(350))
.SetOpacity(layer, show ? 1.f : 0.f, gfx::Tween::LINEAR);
if (show) {
builder.Once()
.SetDuration(base::Milliseconds(350))
.SetTransform(layer, gfx::Transform(), gfx::Tween::LINEAR);
}
}
OtherWindowCopyAnimation(const OtherWindowCopyAnimation&) = delete;
OtherWindowCopyAnimation& operator=(const OtherWindowCopyAnimation&) = delete;
~OtherWindowCopyAnimation() = default;
void OnAnimationEnded() { delete this; }
private:
std::unique_ptr<ui::LayerTreeOwner> other_window_copy_;
};
}
class DragWindowFromShelfController::WindowsHider
: public aura::WindowObserver {
public:
WindowsHider(aura::Window* dragged_window, aura::Window* other_window)
: dragged_window_(dragged_window) {
std::vector<raw_ptr<aura::Window, VectorExperimental>> windows =
Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
auto* split_view_controller = SplitViewController::Get(dragged_window);
for (aura::Window* window : windows) {
if (window == dragged_window_ || window == other_window ||
window == split_view_controller->primary_window() ||
window == split_view_controller->secondary_window()) {
continue;
}
if (::wm::GetTransientParent(window)) {
continue;
}
if (!window->IsVisible()) {
continue;
}
auto* overview_controller = Shell::Get()->overview_controller();
if (overview_controller->InOverviewSession() &&
overview_controller->overview_session()->IsWindowInOverview(window)) {
continue;
}
hidden_windows_.push_back(window);
window->AddObserver(this);
window->SetProperty(kHideDuringWindowDragging, true);
}
window_util::MinimizeAndHideWithoutAnimation(hidden_windows_);
}
WindowsHider(const WindowsHider&) = delete;
WindowsHider& operator=(const WindowsHider&) = delete;
~WindowsHider() override {
for (aura::Window* window : hidden_windows_) {
window->RemoveObserver(this);
window->ClearProperty(kHideDuringWindowDragging);
}
hidden_windows_.clear();
}
void RestoreWindowsVisibility() {
for (aura::Window* window : hidden_windows_) {
window->RemoveObserver(this);
wm::ScopedAnimationDisabler disabler(window);
window->Show();
window->ClearProperty(kHideDuringWindowDragging);
}
hidden_windows_.clear();
}
bool WindowsMinimized() {
return std::ranges::all_of(hidden_windows_, [](const aura::Window* w) {
return WindowState::Get(w)->IsMinimized();
});
}
void OnWindowDestroying(aura::Window* window) override {
window->RemoveObserver(this);
hidden_windows_.erase(std::ranges::find(hidden_windows_, window));
}
private:
raw_ptr<aura::Window, DanglingUntriaged> dragged_window_;
std::vector<raw_ptr<aura::Window, VectorExperimental>> hidden_windows_;
};
float DragWindowFromShelfController::GetReturnToMaximizedThreshold() {
return Shell::GetPrimaryRootWindowController()
->shelf()
->hotseat_widget()
->GetHotseatFullDragAmount();
}
DragWindowFromShelfController::DragWindowFromShelfController(
aura::Window* window,
const gfx::PointF& location_in_screen)
: window_(window) {
window_->AddObserver(this);
if (auto* floated_window = window_util::GetFloatedWindowForActiveDesk()) {
if (floated_window == window_) {
aura::Window* candidate_other_window =
window_util::GetTopNonFloatedWindow();
if (candidate_other_window &&
!WindowState::Get(candidate_other_window)->IsMinimized()) {
other_window_ = candidate_other_window;
}
} else {
other_window_ = floated_window;
}
if (other_window_) {
other_window_->AddObserver(this);
other_window_copy_ = wm::RecreateLayers(other_window_);
other_window_copy_->root()->SetVisible(true);
other_window_copy_->root()->SetOpacity(1.f);
if (other_window_ == floated_window) {
ui::Layer* new_parent = desks_util::GetActiveDeskContainerForRoot(
Shell::GetPrimaryRootWindow())
->layer();
new_parent->Add(other_window_copy_->root());
} else {
other_window_->layer()->parent()->StackAbove(other_window_copy_->root(),
other_window_->layer());
}
}
}
OnDragStarted(location_in_screen);
presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
window_->GetHost()->compositor(), kDragWindowFromShelfHistogram,
kDragWindowFromShelfMaxLatencyHistogram);
}
DragWindowFromShelfController::~DragWindowFromShelfController() {
CancelDrag();
if (window_)
window_->RemoveObserver(this);
ResetOtherWindow(std::nullopt);
}
void DragWindowFromShelfController::Drag(const gfx::PointF& location_in_screen,
float scroll_x,
float scroll_y) {
if (!window_)
return;
if (!drag_started_)
return;
presentation_time_recorder_->RequestNext();
UpdateDraggedWindow(location_in_screen);
DCHECK(windows_hider_);
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (std::abs(scroll_y) <= kOpenOverviewThreshold &&
windows_hider_->WindowsMinimized()) {
if (!overview_controller->InOverviewSession() &&
overview_controller->StartOverview(
OverviewStartAction::kDragWindowFromShelf,
OverviewEnterExitType::kImmediateEnter)) {
OnWindowDragStartedInOverview();
}
}
if (overview_controller->InOverviewSession()) {
const SnapPosition snap_position = GetSnapPosition(location_in_screen);
const SplitViewDragIndicators::WindowDraggingState window_dragging_state =
SplitViewDragIndicators::ComputeWindowDraggingState(
true,
SplitViewDragIndicators::WindowDraggingState::kFromShelf,
snap_position);
OverviewSession* overview_session = overview_controller->overview_session();
overview_session->UpdateSplitViewDragIndicatorsWindowDraggingStates(
Shell::GetPrimaryRootWindow(), window_dragging_state);
overview_session->OnWindowDragContinued(window_, location_in_screen,
window_dragging_state);
if (snap_position != SnapPosition::kNone) {
ShowOverviewDuringOrAfterDrag();
} else if (std::abs(scroll_x) > kShowOverviewThreshold ||
std::abs(scroll_y) > kShowOverviewThreshold) {
show_overview_timer_.Stop();
HideOverviewDuringDrag();
} else if (!show_overview_timer_.IsRunning() ||
std::abs(scroll_x) > kScrollUpdateOverviewThreshold ||
std::abs(scroll_y) > kScrollUpdateOverviewThreshold) {
show_overview_timer_.Start(
FROM_HERE, kShowOverviewTimeWhenDragSuspend, this,
&DragWindowFromShelfController::ShowOverviewDuringOrAfterDrag);
}
}
previous_location_in_screen_ = location_in_screen;
}
std::optional<ShelfWindowDragResult> DragWindowFromShelfController::EndDrag(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) {
if (!drag_started_)
return std::nullopt;
UpdateDraggedWindow(location_in_screen);
drag_started_ = false;
previous_location_in_screen_ = location_in_screen;
presentation_time_recorder_.reset();
OverviewController* overview_controller = Shell::Get()->overview_controller();
SplitViewController* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
const bool in_overview = overview_controller->InOverviewSession();
const bool in_splitview = split_view_controller->InSplitViewMode();
const bool drop_window_in_overview =
ShouldDropWindowInOverview(location_in_screen, velocity_y);
end_snap_position_ = GetSnapPositionOnDragEnd(location_in_screen, velocity_y);
window_drag_result_ = std::nullopt;
if (ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
DCHECK(!in_splitview);
if (in_overview) {
overview_controller->EndOverview(OverviewEndAction::kDragWindowFromShelf,
OverviewEnterExitType::kFadeOutExit);
}
window_drag_result_ = ShelfWindowDragResult::kGoToHomeScreen;
} else if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y)) {
window_drag_result_ = ShelfWindowDragResult::kRestoreToOriginalBounds;
} else if (!in_overview) {
window_drag_result_ = ShelfWindowDragResult::kGoToHomeScreen;
} else {
if (drop_window_in_overview) {
window_drag_result_ = ShelfWindowDragResult::kGoToOverviewMode;
} else if (end_snap_position_ != SnapPosition::kNone) {
window_drag_result_ = ShelfWindowDragResult::kGoToSplitviewMode;
}
WindowBackdrop::Get(window_)->RestoreBackdrop();
}
WindowState::Get(window_)->DeleteDragDetails();
if (window_drag_result_.has_value()) {
UMA_HISTOGRAM_ENUMERATION(kHandleDragWindowFromShelfHistogramName,
*window_drag_result_);
}
return window_drag_result_;
}
void DragWindowFromShelfController::CancelDrag() {
if (!drag_started_)
return;
UMA_HISTOGRAM_ENUMERATION(kHandleDragWindowFromShelfHistogramName,
ShelfWindowDragResult::kDragCanceled);
drag_started_ = false;
presentation_time_recorder_.reset();
window_->SetTransform(gfx::Transform());
WindowBackdrop::Get(window_)->RestoreBackdrop();
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (overview_controller->InOverviewSession()) {
overview_controller->EndOverview(OverviewEndAction::kDragWindowFromShelf,
OverviewEnterExitType::kImmediateExit);
}
ReshowHiddenWindowsOnDragEnd();
window_drag_result_ = ShelfWindowDragResult::kDragCanceled;
OnDragEnded(previous_location_in_screen_,
false,
initial_snap_position_);
WindowState::Get(window_)->DeleteDragDetails();
}
bool DragWindowFromShelfController::IsDraggedWindowAnimating() const {
return window_ && window_->layer()->GetAnimator()->is_animating();
}
void DragWindowFromShelfController::FinalizeDraggedWindow() {
if (!window_drag_result_.has_value()) {
started_in_overview_ = false;
return;
}
DCHECK(!drag_started_);
DCHECK(window_);
OnDragEnded(previous_location_in_screen_,
*window_drag_result_ == ShelfWindowDragResult::kGoToOverviewMode,
end_snap_position_);
}
void DragWindowFromShelfController::OnWindowDestroying(aura::Window* window) {
if (window == other_window_) {
ResetOtherWindow(std::nullopt);
return;
}
DCHECK_EQ(window_, window);
CancelDrag();
window_->RemoveObserver(this);
window_ = nullptr;
}
void DragWindowFromShelfController::OnDragStarted(
const gfx::PointF& location_in_screen) {
drag_started_ = true;
started_in_overview_ =
Shell::Get()->overview_controller()->InOverviewSession();
initial_location_in_screen_ = location_in_screen;
previous_location_in_screen_ = location_in_screen;
WindowState::Get(window_)->CreateDragDetails(
initial_location_in_screen_, HTCLIENT, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
WindowBackdrop::Get(window_)->DisableBackdrop();
windows_hider_ = std::make_unique<WindowsHider>(window_, other_window_);
Shell::Get()->app_list_controller()->OnWindowDragStarted();
SplitViewController* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
if (split_view_controller->IsWindowInSplitView(window_)) {
initial_snap_position_ =
split_view_controller->GetPositionOfSnappedWindow(window_);
}
split_view_controller->OnWindowDragStarted(window_);
if (Shell::Get()->overview_controller()->InOverviewSession())
OnWindowDragStartedInOverview();
}
void DragWindowFromShelfController::OnDragEnded(
const gfx::PointF& location_in_screen,
bool should_drop_window_in_overview,
SnapPosition snap_position) {
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (overview_controller->InOverviewSession()) {
ShowOverviewDuringOrAfterDrag();
OverviewSession* overview_session = overview_controller->overview_session();
overview_session->ResetSplitViewDragIndicatorsWindowDraggingStates();
if (!should_drop_window_in_overview)
overview_session->SuspendReposition();
overview_session->OnWindowDragEnded(
window_, location_in_screen, should_drop_window_in_overview,
snap_position != SnapPosition::kNone);
overview_session->ResumeReposition();
}
SplitViewController* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
if (split_view_controller->InSplitViewMode() ||
snap_position != SnapPosition::kNone) {
split_view_controller->OnWindowDragEnded(
window_, snap_position, gfx::ToRoundedPoint(location_in_screen),
WindowSnapActionSource::kDragUpFromShelfToSnap);
}
Shell::Get()->app_list_controller()->OnWindowDragEnded(true);
DCHECK(window_drag_result_.has_value());
switch (*window_drag_result_) {
case ShelfWindowDragResult::kGoToHomeScreen:
ScaleDownWindowAfterDrag();
windows_hider_.reset();
break;
case ShelfWindowDragResult::kRestoreToOriginalBounds:
ScaleUpToRestoreWindowAfterDrag();
break;
case ShelfWindowDragResult::kGoToOverviewMode:
case ShelfWindowDragResult::kGoToSplitviewMode:
case ShelfWindowDragResult::kDragCanceled:
windows_hider_.reset();
break;
}
ResetOtherWindow(*window_drag_result_ ==
ShelfWindowDragResult::kRestoreToOriginalBounds);
window_drag_result_.reset();
started_in_overview_ = false;
}
void DragWindowFromShelfController::UpdateDraggedWindow(
const gfx::PointF& location_in_screen) {
gfx::Rect bounds = window_->bounds();
wm::ConvertRectToScreen(window_->parent(), &bounds);
const gfx::Rect display_bounds =
display::Screen::Get()
->GetDisplayNearestPoint(gfx::ToRoundedPoint(location_in_screen))
.bounds();
const float min_y = display_bounds.y() +
display_bounds.height() * kMinYDisplayHeightRatio +
kMinimumWindowScaleDuringDragging * bounds.height();
float y_full =
std::min(initial_location_in_screen_.y(), (float)bounds.bottom()) - min_y;
float y_diff = location_in_screen.y() - min_y;
float scale = (1.0f - kMinimumWindowScaleDuringDragging) * y_diff / y_full +
kMinimumWindowScaleDuringDragging;
scale = std::clamp(scale, kMinimumWindowScaleDuringDragging,
1.f);
gfx::Transform transform;
transform.Translate(
(location_in_screen.x() - bounds.x()) -
(initial_location_in_screen_.x() - bounds.x()) * scale,
(location_in_screen.y() - bounds.y()) - bounds.height() * scale);
transform.Scale(scale, scale);
const gfx::Transform new_tranform =
TransformAboutPivot(gfx::PointF(window_->bounds().origin()), transform);
gfx::RectF transformed_bounds =
new_tranform.MapRect(gfx::RectF(window_->bounds()));
wm::TranslateRectToScreen(window_->parent(), &transformed_bounds);
if (transformed_bounds.y() < display_bounds.y()) {
transform.Translate(0,
(display_bounds.y() - transformed_bounds.y()) / scale);
} else if (transformed_bounds.bottom() > bounds.bottom()) {
DCHECK_EQ(1.f, scale);
transform.Translate(
0, (bounds.bottom() - transformed_bounds.bottom()) / scale);
}
window_util::SetTransform(window_, transform);
if (other_window_copy_) {
float copy_scale =
(bounds.bottom() - location_in_screen.y()) /
(display_bounds.height() / kOtherWindowFullFadeHeightRatio);
copy_scale = 1.f - std::clamp(copy_scale, 0.f, 1.f);
other_window_copy_->root()->SetOpacity(copy_scale);
CHECK(other_window_);
if (!WindowState::Get(other_window_)->IsFloated()) {
const float copy_transform_scale =
std::clamp(copy_scale, kOtherWindowMaxScale, 1.f);
const gfx::Transform copy_transform = gfx::GetScaleTransform(
other_window_copy_->root()->bounds().CenterPoint(),
copy_transform_scale);
other_window_copy_->root()->SetTransform(copy_transform);
}
}
}
SnapPosition DragWindowFromShelfController::GetSnapPosition(
const gfx::PointF& location_in_screen) const {
if (ShouldRestoreToOriginalBounds(location_in_screen, std::nullopt)) {
return SnapPosition::kNone;
}
aura::Window* root_window = Shell::GetPrimaryRootWindow();
SnapPosition snap_position = ::ash::GetSnapPosition(
root_window, window_, gfx::ToRoundedPoint(location_in_screen),
gfx::ToRoundedPoint(initial_location_in_screen_),
kDistanceFromEdge,
kMinDragDistance,
kScreenEdgeInsetForSnap,
kScreenEdgeInsetForSnap);
const bool is_landscape = IsCurrentScreenOrientationLandscape();
const bool is_primary = IsCurrentScreenOrientationPrimary();
if (!is_landscape &&
((is_primary && snap_position == SnapPosition::kSecondary) ||
(!is_primary && snap_position == SnapPosition::kPrimary))) {
snap_position = SnapPosition::kNone;
}
return snap_position;
}
bool DragWindowFromShelfController::ShouldRestoreToOriginalBounds(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const {
const gfx::Rect display_bounds =
display::Screen::Get()
->GetDisplayNearestPoint(gfx::ToRoundedPoint(location_in_screen))
.bounds();
gfx::RectF transformed_window_bounds =
window_util::GetTransformedBounds(window_, 0);
if (Shell::Get()->overview_controller()->InOverviewSession() &&
!show_overview_windows_ && velocity_y.has_value() &&
velocity_y.value() > 0) {
return true;
}
return (velocity_y.has_value() &&
velocity_y.value() >= kVelocityToRestoreBoundsThreshold) ||
transformed_window_bounds.bottom() >
display_bounds.bottom() - GetReturnToMaximizedThreshold();
}
bool DragWindowFromShelfController::ShouldGoToHomeScreen(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const {
if (location_in_screen.y() >=
Shelf::ForWindow(window_)->GetIdealBoundsForWorkAreaCalculation().y()) {
return false;
}
if (SplitViewController::Get(Shell::GetPrimaryRootWindow())
->InSplitViewMode()) {
return false;
}
if (Shell::Get()->overview_controller()->InOverviewSession() &&
!show_overview_windows_ &&
(!velocity_y.has_value() || velocity_y.value() <= 0)) {
return true;
}
return velocity_y.has_value() &&
velocity_y.value() <= -kVelocityToHomeScreenThreshold;
}
SnapPosition DragWindowFromShelfController::GetSnapPositionOnDragEnd(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const {
if (!Shell::Get()->overview_controller()->InOverviewSession() ||
ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
return SnapPosition::kNone;
}
if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y))
return initial_snap_position_;
return GetSnapPosition(location_in_screen);
}
bool DragWindowFromShelfController::ShouldDropWindowInOverview(
const gfx::PointF& location_in_screen,
std::optional<float> velocity_y) const {
if (!Shell::Get()->overview_controller()->InOverviewSession())
return false;
if (ShouldGoToHomeScreen(location_in_screen, velocity_y))
return false;
const bool in_splitview =
SplitViewController::Get(Shell::GetPrimaryRootWindow())
->InSplitViewMode();
if (!in_splitview &&
ShouldRestoreToOriginalBounds(location_in_screen, velocity_y)) {
return false;
}
if (in_splitview) {
if (velocity_y.has_value() &&
velocity_y.value() <= -kVelocityToOverviewThreshold) {
return true;
}
if (ShouldRestoreToOriginalBounds(location_in_screen, velocity_y))
return false;
}
return GetSnapPositionOnDragEnd(location_in_screen, velocity_y) ==
SnapPosition::kNone;
}
void DragWindowFromShelfController::ReshowHiddenWindowsOnDragEnd() {
windows_hider_->RestoreWindowsVisibility();
}
void DragWindowFromShelfController::ShowOverviewDuringOrAfterDrag() {
show_overview_timer_.Stop();
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (!overview_controller->InOverviewSession())
return;
show_overview_windows_ = true;
overview_controller->overview_session()->SetVisibleDuringWindowDragging(
true, true);
if (on_overview_shown_callback_for_testing_)
std::move(on_overview_shown_callback_for_testing_).Run();
}
void DragWindowFromShelfController::HideOverviewDuringDrag() {
show_overview_windows_ = false;
OverviewController* overview_controller = Shell::Get()->overview_controller();
if (!overview_controller->InOverviewSession())
return;
overview_controller->overview_session()->SetVisibleDuringWindowDragging(
false,
false);
}
void DragWindowFromShelfController::ScaleDownWindowAfterDrag() {
Shell::Get()->app_list_controller()->OnHomeLauncherPositionChanged(
100, display::Screen::Get()->GetPrimaryDisplay().id());
(new WindowScaleAnimation(
WindowScaleAnimation::WindowScaleType::kScaleDownToShelf,
base::BindOnce(
&DragWindowFromShelfController::OnWindowScaledDownAfterDrag,
weak_ptr_factory_.GetWeakPtr())))
->Start(window_);
}
void DragWindowFromShelfController::OnWindowScaledDownAfterDrag() {
AppListControllerImpl* app_list_controller =
Shell::Get()->app_list_controller();
if (!app_list_controller)
return;
app_list_controller->OnHomeLauncherAnimationComplete(
true, display::Screen::Get()->GetPrimaryDisplay().id());
}
void DragWindowFromShelfController::ScaleUpToRestoreWindowAfterDrag() {
(new WindowScaleAnimation(
WindowScaleAnimation::WindowScaleType::kScaleUpToRestore,
base::BindOnce(
&DragWindowFromShelfController::OnWindowRestoredToOriginalBounds,
weak_ptr_factory_.GetWeakPtr(),
!started_in_overview_)))
->Start(window_);
}
void DragWindowFromShelfController::OnWindowRestoredToOriginalBounds(
bool end_overview) {
base::AutoReset<bool> auto_reset(&during_window_restoration_, true);
if (end_overview && last_overview_drag_session_ptr_) {
Shell::Get()->overview_controller()->EndOverview(
OverviewEndAction::kDragWindowFromShelf,
OverviewEnterExitType::kImmediateExit);
}
ReshowHiddenWindowsOnDragEnd();
}
void DragWindowFromShelfController::OnWindowDragStartedInOverview() {
OverviewSession* overview_session =
Shell::Get()->overview_controller()->overview_session();
DCHECK(overview_session);
last_overview_drag_session_ptr_ = overview_session->GetWeakPtr();
overview_session->OnWindowDragStarted(window_, false);
if (ShouldAllowSplitView())
overview_session->SetSplitViewDragIndicatorsDraggedWindow(window_);
HideOverviewDuringDrag();
}
void DragWindowFromShelfController::ResetOtherWindow(std::optional<bool> show) {
if (other_window_) {
other_window_->RemoveObserver(this);
other_window_ = nullptr;
if (show.has_value()) {
DCHECK(other_window_copy_);
ui::Layer* layer = other_window_copy_->root();
if (show.value()) {
if (layer->GetTargetOpacity() != 1.f &&
layer->GetTargetTransform() != gfx::Transform()) {
new OtherWindowCopyAnimation(std::move(other_window_copy_),
true);
}
} else {
if (layer->GetTargetOpacity() != 0.f) {
new OtherWindowCopyAnimation(std::move(other_window_copy_),
false);
}
}
}
}
other_window_copy_.reset();
}
}