123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- // Copyright 2019 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/shelf/drag_window_from_shelf_controller.h"
- #include "ash/app_list/app_list_controller_impl.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/scoped_animation_disabler.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/wallpaper_constants.h"
- #include "ash/wallpaper/wallpaper_view.h"
- #include "ash/wallpaper/wallpaper_widget_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/bind.h"
- #include "base/callback_helpers.h"
- #include "base/cxx17_backports.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/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/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- // The minimum window scale factor when dragging a window from shelf.
- constexpr float kMinimumWindowScaleDuringDragging = 0.3f;
- // The ratio in display height at which point the dragged window shrinks to its
- // minimum scale kMinimumWindowScaleDuringDragging.
- constexpr float kMinYDisplayHeightRatio = 0.125f;
- // Amount of time to wait to show overview after the user slows down or stops
- // window dragging.
- constexpr base::TimeDelta kShowOverviewTimeWhenDragSuspend =
- base::Milliseconds(40);
- // The scroll update threshold to restart the show overview timer.
- constexpr float kScrollUpdateOverviewThreshold = 2.f;
- // Presentation time histogram names.
- constexpr char kDragWindowFromShelfHistogram[] =
- "Ash.DragWindowFromShelf.PresentationTime";
- constexpr char kDragWindowFromShelfMaxLatencyHistogram[] =
- "Ash.DragWindowFromShelf.PresentationTime.MaxLatency";
- } // namespace
- // Hide all visible windows expect the dragged windows or the window showing in
- // splitview during dragging.
- class DragWindowFromShelfController::WindowsHider
- : public aura::WindowObserver {
- public:
- explicit WindowsHider(aura::Window* dragged_window)
- : dragged_window_(dragged_window) {
- std::vector<aura::Window*> windows =
- Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
- for (auto* window : windows) {
- if (window == dragged_window_)
- continue;
- if (::wm::HasTransientAncestor(window, dragged_window_))
- continue;
- if (!window->IsVisible())
- continue;
- if (SplitViewController::Get(window)->IsWindowInSplitView(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 (auto* window : hidden_windows_) {
- window->RemoveObserver(this);
- window->ClearProperty(kHideDuringWindowDragging);
- }
- hidden_windows_.clear();
- }
- void RestoreWindowsVisibility() {
- for (auto* window : hidden_windows_) {
- window->RemoveObserver(this);
- ScopedAnimationDisabler disabler(window);
- window->Show();
- window->ClearProperty(kHideDuringWindowDragging);
- }
- hidden_windows_.clear();
- }
- // Even though we explicitly minimize the windows, some (i.e. ARC apps)
- // minimize asynchronously so they may not be truly minimized after |this| is
- // constructed.
- bool WindowsMinimized() {
- return std::all_of(hidden_windows_.begin(), hidden_windows_.end(),
- [](const aura::Window* w) {
- return WindowState::Get(w)->IsMinimized();
- });
- }
- // aura::WindowObserver:
- void OnWindowDestroying(aura::Window* window) override {
- window->RemoveObserver(this);
- hidden_windows_.erase(
- std::find(hidden_windows_.begin(), hidden_windows_.end(), window));
- }
- private:
- aura::Window* dragged_window_;
- std::vector<aura::Window*> hidden_windows_;
- };
- // static
- 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);
- OnDragStarted(location_in_screen);
- presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
- window_->GetHost()->compositor(), kDragWindowFromShelfHistogram,
- kDragWindowFromShelfMaxLatencyHistogram);
- }
- DragWindowFromShelfController::~DragWindowFromShelfController() {
- CancelDrag();
- if (window_)
- window_->RemoveObserver(this);
- }
- void DragWindowFromShelfController::Drag(const gfx::PointF& location_in_screen,
- float scroll_x,
- float scroll_y) {
- // |window_| might have been destroyed during dragging.
- if (!window_)
- return;
- if (!drag_started_)
- return;
- presentation_time_recorder_->RequestNext();
- UpdateDraggedWindow(location_in_screen);
- // Open overview if the window has been dragged far enough and the scroll
- // delta has decreased to kOpenOverviewThreshold. Wait until all windows are
- // minimized or they will not show up in overview.
- DCHECK(windows_hider_);
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (std::abs(scroll_y) <= kOpenOverviewThreshold &&
- !overview_controller->InOverviewSession() &&
- windows_hider_->WindowsMinimized()) {
- overview_controller->StartOverview(
- OverviewStartAction::kDragWindowFromShelf,
- OverviewEnterExitType::kImmediateEnter);
- OnWindowDragStartedInOverview();
- }
- // If overview is active, update its splitview indicator during dragging if
- // splitview is allowed in current configuration.
- if (overview_controller->InOverviewSession()) {
- const SplitViewController::SnapPosition snap_position =
- GetSnapPosition(location_in_screen);
- const SplitViewDragIndicators::WindowDraggingState window_dragging_state =
- SplitViewDragIndicators::ComputeWindowDraggingState(
- /*is_dragging=*/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 != SplitViewController::NONE) {
- // If the dragged window is in snap preview area, make sure overview is
- // visible.
- ShowOverviewDuringOrAfterDrag();
- } else if (std::abs(scroll_x) > kShowOverviewThreshold ||
- std::abs(scroll_y) > kShowOverviewThreshold) {
- // If the dragging velocity is large enough, hide overview windows.
- show_overview_timer_.Stop();
- HideOverviewDuringDrag();
- } else if (!show_overview_timer_.IsRunning() ||
- std::abs(scroll_x) > kScrollUpdateOverviewThreshold ||
- std::abs(scroll_y) > kScrollUpdateOverviewThreshold) {
- // Otherwise start the |show_overview_timer_| to show and update
- // overview when the dragging slows down or stops. Note if the window is
- // still being dragged with scroll rate more than
- // kScrollUpdateOverviewThreshold, we restart the show overview timer.
- show_overview_timer_.Start(
- FROM_HERE, kShowOverviewTimeWhenDragSuspend, this,
- &DragWindowFromShelfController::ShowOverviewDuringOrAfterDrag);
- }
- }
- previous_location_in_screen_ = location_in_screen;
- }
- absl::optional<ShelfWindowDragResult> DragWindowFromShelfController::EndDrag(
- const gfx::PointF& location_in_screen,
- absl::optional<float> velocity_y) {
- if (!drag_started_)
- return absl::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_ = absl::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) {
- // if overview is not active during the entire drag process, scale down the
- // dragged window to go to home screen.
- window_drag_result_ = ShelfWindowDragResult::kGoToHomeScreen;
- } else {
- if (drop_window_in_overview)
- window_drag_result_ = ShelfWindowDragResult::kGoToOverviewMode;
- else if (end_snap_position_ != SplitViewController::NONE)
- window_drag_result_ = ShelfWindowDragResult::kGoToSplitviewMode;
- // For window that may drop in overview or snap in split screen, restore its
- // original backdrop mode.
- 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();
- // Reset the window's transform to identity transform.
- window_->SetTransform(gfx::Transform());
- WindowBackdrop::Get(window_)->RestoreBackdrop();
- // End overview if it was opened during dragging.
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (overview_controller->InOverviewSession()) {
- overview_controller->EndOverview(OverviewEndAction::kDragWindowFromShelf,
- OverviewEnterExitType::kImmediateExit);
- }
- ReshowHiddenWindowsOnDragEnd();
- window_drag_result_ = ShelfWindowDragResult::kDragCanceled;
- // When the drag is cancelled, the window should restore to its original snap
- // position.
- OnDragEnded(previous_location_in_screen_,
- /*should_drop_window_in_overview=*/false,
- /*snap_position=*/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) {
- DCHECK_EQ(window_, window);
- CancelDrag();
- window_->RemoveObserver(this);
- window_ = nullptr;
- }
- void DragWindowFromShelfController::AddObserver(
- DragWindowFromShelfController::Observer* observer) {
- observers_.AddObserver(observer);
- }
- void DragWindowFromShelfController::RemoveObserver(
- DragWindowFromShelfController::Observer* observer) {
- observers_.RemoveObserver(observer);
- }
- 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);
- // Disable the backdrop on the dragged window during dragging.
- WindowBackdrop::Get(window_)->DisableBackdrop();
- // Hide all visible windows behind the dragged window during dragging.
- windows_hider_ = std::make_unique<WindowsHider>(window_);
- // Hide the home launcher until it's eligible to show it.
- Shell::Get()->app_list_controller()->OnWindowDragStarted();
- // Use the same dim and blur as in overview during dragging.
- RootWindowController::ForWindow(window_->GetRootWindow())
- ->wallpaper_widget_controller()
- ->SetWallpaperBlur(wallpaper_constants::kOverviewBlur);
- // If the dragged window is one of the snapped window in splitview, it needs
- // to be detached from splitview before start dragging.
- SplitViewController* split_view_controller =
- SplitViewController::Get(Shell::GetPrimaryRootWindow());
- // Preserve initial snap position
- if (split_view_controller->IsWindowInSplitView(window_)) {
- initial_snap_position_ =
- split_view_controller->GetPositionOfSnappedWindow(window_);
- }
- split_view_controller->OnWindowDragStarted(window_);
- // Note SplitViewController::OnWindowDragStarted() may open overview.
- if (Shell::Get()->overview_controller()->InOverviewSession())
- OnWindowDragStartedInOverview();
- }
- void DragWindowFromShelfController::OnDragEnded(
- const gfx::PointF& location_in_screen,
- bool should_drop_window_in_overview,
- SplitViewController::SnapPosition snap_position) {
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (overview_controller->InOverviewSession()) {
- // Make sure overview is visible after drag ends.
- ShowOverviewDuringOrAfterDrag();
- OverviewSession* overview_session = overview_controller->overview_session();
- overview_session->ResetSplitViewDragIndicatorsWindowDraggingStates();
- // No need to reposition overview windows if we are not dropping the dragged
- // window into overview. Overview will either be exited or unchanged, and
- // the extra movement from existing window will just add unnecessary
- // movement which will also slow down our dragged window animation.
- if (!should_drop_window_in_overview)
- overview_session->SuspendReposition();
- overview_session->OnWindowDragEnded(
- window_, location_in_screen, should_drop_window_in_overview,
- /*snap=*/snap_position != SplitViewController::NONE);
- overview_session->ResumeReposition();
- }
- SplitViewController* split_view_controller =
- SplitViewController::Get(Shell::GetPrimaryRootWindow());
- if (split_view_controller->InSplitViewMode() ||
- snap_position != SplitViewController::NONE) {
- WindowState::Get(window_)->set_snap_action_source(
- WindowSnapActionSource::kDragUpFromShelfToSnap);
- split_view_controller->OnWindowDragEnded(
- window_, snap_position, gfx::ToRoundedPoint(location_in_screen));
- }
- // Scale-in-to-show home screen if home screen should be shown after drag
- // ends.
- Shell::Get()->app_list_controller()->OnWindowDragEnded(/*animate=*/true);
- // Clear the wallpaper dim and blur if not in overview after drag ends.
- // If in overview, the dim and blur will be cleared after overview ends.
- if (!overview_controller->InOverviewSession()) {
- RootWindowController::ForWindow(window_->GetRootWindow())
- ->wallpaper_widget_controller()
- ->SetWallpaperBlur(wallpaper_constants::kClear);
- }
- DCHECK(window_drag_result_.has_value());
- switch (*window_drag_result_) {
- case ShelfWindowDragResult::kGoToHomeScreen:
- ScaleDownWindowAfterDrag();
- windows_hider_.reset();
- break;
- case ShelfWindowDragResult::kRestoreToOriginalBounds:
- ScaleUpToRestoreWindowAfterDrag();
- // Do not reset |windows_hider_| here because
- // |ScaleUpToRestoreWindowAfterDrag()| ends up using |windows_hider_| in
- // an async manner.
- break;
- case ShelfWindowDragResult::kGoToOverviewMode:
- case ShelfWindowDragResult::kGoToSplitviewMode:
- case ShelfWindowDragResult::kDragCanceled:
- windows_hider_.reset();
- break;
- }
- 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);
- // Calculate the window's transform based on the location.
- // For scale, at |initial_location_in_screen_| or bounds.bottom(), the scale
- // is 1.0, and at the |min_y| position of its bounds, it reaches to its
- // minimum scale |kMinimumWindowScaleDuringDragging|. Calculate the desired
- // scale based on the current y position.
- const gfx::Rect display_bounds =
- display::Screen::GetScreen()
- ->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 = base::clamp(scale, /*min=*/kMinimumWindowScaleDuringDragging,
- /*max=*/1.f);
- // Calculate the desired translation so that the dragged window stays under
- // the finger during the dragging.
- // Since vertical drag doesn't start until after passing the top of the shelf,
- // the y calculations should be relative to the window bounds instead of
- // |initial_location_in_screen| (which is on the shelf)
- 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);
- // The dragged window cannot exceed the top or bottom of the display. So
- // calculate the expected transformed bounds and then adjust the transform if
- // needed.
- gfx::RectF transformed_bounds(window_->bounds());
- gfx::Transform new_tranform = TransformAboutPivot(
- gfx::ToRoundedPoint(transformed_bounds.origin()), transform);
- new_tranform.TransformRect(&transformed_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);
- }
- SetTransform(window_, transform);
- }
- SplitViewController::SnapPosition
- DragWindowFromShelfController::GetSnapPosition(
- const gfx::PointF& location_in_screen) const {
- // if |location_in_screen| is close to the bottom of the screen and is
- // inside of GetReturnToMaximizedThreshold() threshold, we should not try to
- // snap the window.
- if (ShouldRestoreToOriginalBounds(location_in_screen, absl::nullopt))
- return SplitViewController::NONE;
- aura::Window* root_window = Shell::GetPrimaryRootWindow();
- SplitViewController::SnapPosition snap_position = ::ash::GetSnapPosition(
- root_window, window_, gfx::ToRoundedPoint(location_in_screen),
- gfx::ToRoundedPoint(initial_location_in_screen_),
- /*snap_distance_from_edge=*/kDistanceFromEdge,
- /*minimum_drag_distance=*/kMinDragDistance,
- /*horizontal_edge_inset=*/kScreenEdgeInsetForSnap,
- /*vertical_edge_inset=*/kScreenEdgeInsetForSnap);
- // For portrait mode, since the drag starts from the bottom of the screen,
- // we should only allow the window to snap to the top of the screen.
- const bool is_landscape = IsCurrentScreenOrientationLandscape();
- const bool is_primary = IsCurrentScreenOrientationPrimary();
- if (!is_landscape &&
- ((is_primary && snap_position == SplitViewController::RIGHT) ||
- (!is_primary && snap_position == SplitViewController::LEFT))) {
- snap_position = SplitViewController::NONE;
- }
- return snap_position;
- }
- bool DragWindowFromShelfController::ShouldRestoreToOriginalBounds(
- const gfx::PointF& location_in_screen,
- absl::optional<float> velocity_y) const {
- const gfx::Rect display_bounds =
- display::Screen::GetScreen()
- ->GetDisplayNearestPoint(gfx::ToRoundedPoint(location_in_screen))
- .bounds();
- gfx::RectF transformed_window_bounds =
- window_util::GetTransformedBounds(window_, /*top_inset=*/0);
- // If overview is invisible when the drag ends with downward velocity, we
- // should restore to original bounds.
- if (Shell::Get()->overview_controller()->InOverviewSession() &&
- !show_overview_windows_ && velocity_y.has_value() &&
- velocity_y.value() > 0) {
- return true;
- }
- // Otherwise restore the bounds if the downward vertical velocity exceeds the
- // threshold, or if the bottom of the dragged window is within the
- // GetReturnToMaximizedThreshold() threshold.
- 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,
- absl::optional<float> velocity_y) const {
- // If the drag ends below the shelf, do not go to home screen (theoretically
- // it may happen in kExtended hotseat case when drag can start and end below
- // the shelf).
- if (location_in_screen.y() >=
- Shelf::ForWindow(window_)->GetIdealBoundsForWorkAreaCalculation().y()) {
- return false;
- }
- // Do not go home if we're in split screen.
- if (SplitViewController::Get(Shell::GetPrimaryRootWindow())
- ->InSplitViewMode()) {
- return false;
- }
- // If overview is invisible when the drag ends with upward velocity or no
- // velocity, we should go to home screen.
- if (Shell::Get()->overview_controller()->InOverviewSession() &&
- !show_overview_windows_ &&
- (!velocity_y.has_value() || velocity_y.value() <= 0)) {
- return true;
- }
- // Otherwise go home if the upward vertical velocity exceeds the threshold.
- return velocity_y.has_value() &&
- velocity_y.value() <= -kVelocityToHomeScreenThreshold;
- }
- SplitViewController::SnapPosition
- DragWindowFromShelfController::GetSnapPositionOnDragEnd(
- const gfx::PointF& location_in_screen,
- absl::optional<float> velocity_y) const {
- if (!Shell::Get()->overview_controller()->InOverviewSession() ||
- ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
- return SplitViewController::NONE;
- }
- // When dragging ends but restore to original bounds, we should restore
- // window's initial snap position
- 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,
- absl::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) ==
- SplitViewController::NONE;
- }
- 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(
- /*visible=*/true, /*animate=*/true);
- for (Observer& observer : observers_)
- observer.OnOverviewVisibilityChanged(true);
- }
- void DragWindowFromShelfController::HideOverviewDuringDrag() {
- show_overview_windows_ = false;
- OverviewController* overview_controller = Shell::Get()->overview_controller();
- if (!overview_controller->InOverviewSession())
- return;
- overview_controller->overview_session()->SetVisibleDuringWindowDragging(
- /*visible=*/false,
- /*animate=*/false);
- for (Observer& observer : observers_)
- observer.OnOverviewVisibilityChanged(false);
- }
- void DragWindowFromShelfController::ScaleDownWindowAfterDrag() {
- // Notify home screen controller that the home screen is about to be shown, so
- // home screen and shelf start updating their state as the window is
- // minimizing.
- Shell::Get()->app_list_controller()->OnHomeLauncherPositionChanged(
- /*percent_shown=*/100,
- display::Screen::GetScreen()->GetPrimaryDisplay().id());
- (new WindowScaleAnimation(
- window_, WindowScaleAnimation::WindowScaleType::kScaleDownToShelf,
- base::BindOnce(
- &DragWindowFromShelfController::OnWindowScaledDownAfterDrag,
- weak_ptr_factory_.GetWeakPtr())))
- ->Start();
- }
- void DragWindowFromShelfController::OnWindowScaledDownAfterDrag() {
- AppListControllerImpl* app_list_controller =
- Shell::Get()->app_list_controller();
- if (!app_list_controller)
- return;
- app_list_controller->OnHomeLauncherAnimationComplete(
- /*shown=*/true, display::Screen::GetScreen()->GetPrimaryDisplay().id());
- }
- void DragWindowFromShelfController::ScaleUpToRestoreWindowAfterDrag() {
- (new WindowScaleAnimation(
- window_, WindowScaleAnimation::WindowScaleType::kScaleUpToRestore,
- base::BindOnce(
- &DragWindowFromShelfController::OnWindowRestoredToOrignalBounds,
- weak_ptr_factory_.GetWeakPtr(),
- /*should_end_overview=*/!started_in_overview_)))
- ->Start();
- }
- void DragWindowFromShelfController::OnWindowRestoredToOrignalBounds(
- bool end_overview) {
- base::AutoReset<bool> auto_reset(&during_window_restoration_callback_, true);
- if (end_overview) {
- 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);
- overview_session->OnWindowDragStarted(window_, /*animate=*/false);
- if (ShouldAllowSplitView())
- overview_session->SetSplitViewDragIndicatorsDraggedWindow(window_);
- // Hide overview windows first and fade in the windows after delaying
- // kShowOverviewTimeWhenDragSuspend.
- HideOverviewDuringDrag();
- }
- } // namespace ash
|