Commit 8e6ef906 authored by Min Chen's avatar Min Chen Committed by Commit Bot

Drop the dragged window into overview on drag position.

Drop the dragged window into overview if the window has been dragged
further than half of the distance from top of the display to the top
of the new selector item in overview. Do not apply this rule if preview
area is shown or splitview is active.

Bug: 874508
Change-Id: Ib3faf6aadd8a49f2380b330fddd1b647bf63a9e7
Reviewed-on: https://chromium-review.googlesource.com/1192699
Commit-Queue: Min Chen <minch@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587224}
parent 4d4bba36
......@@ -725,43 +725,23 @@ void WindowGrid::OnWindowDragContinued(aura::Window* dragged_window,
}
void WindowGrid::OnWindowDragEnded(aura::Window* dragged_window,
const gfx::Point& location_in_screen) {
const gfx::Point& location_in_screen,
bool should_drop_window_into_overview) {
DCHECK_EQ(dragged_window->GetRootWindow(), root_window_);
DCHECK(new_selector_item_widget_.get());
// Check to see if the dragged window needs to be added to overview. If so,
// add it to overview without repositioning the grid. It will be done at the
// end of this function.
// Add the dragged window into new selector item area in overview if it has
// been dragged into it or |should_drop_window_into_overview| is true. Only
// consider |should_drop_window_into_overview| if SelectedWindow is false
// since tab dragging might drag the widnow to merge it into a browser window
// in overview.
if (SelectedWindow()) {
if (IsNewSelectorItemWindow(SelectedWindow()->GetWindow())) {
// Update the dragged window's bounds before adding it to overview. The
// dragged window might have resized to a smaller size if the drag
// happens on tab(s).
if (wm::IsDraggingTabs(dragged_window)) {
const gfx::Rect old_bounds = dragged_window->bounds();
// We need to temporarily disable the dragged window's ability to merge
// into another window when changing the dragged window's bounds, so
// that the dragged window doesn't merge into another window because of
// its changed bounds.
dragged_window->SetProperty(ash::kCanAttachToAnotherWindowKey, false);
TabletModeWindowState::UpdateWindowPosition(
wm::GetWindowState(dragged_window));
const gfx::Rect new_bounds = dragged_window->bounds();
if (old_bounds != new_bounds) {
// It's for smoother animation.
gfx::Transform transform =
ScopedTransformOverviewWindow::GetTransformForRect(new_bounds,
old_bounds);
dragged_window->SetTransform(transform);
}
dragged_window->ClearProperty(ash::kCanAttachToAnotherWindowKey);
}
window_selector_->AddItem(dragged_window, /*reposition=*/false,
/*animate=*/false);
}
if (IsNewSelectorItemWindow(SelectedWindow()->GetWindow()))
AddDraggedWindowIntoOverviewOnDragEnd(dragged_window);
SelectedWindow()->set_selected(false);
selection_widget_.reset();
} else if (should_drop_window_into_overview) {
AddDraggedWindowIntoOverviewOnDragEnd(dragged_window);
}
window_selector_->RemoveWindowSelectorItem(
......@@ -1488,4 +1468,37 @@ WindowGrid::GetWindowSelectorItemIterContainingWindow(aura::Window* window) {
});
}
void WindowGrid::AddDraggedWindowIntoOverviewOnDragEnd(
aura::Window* dragged_window) {
DCHECK(window_selector_);
if (window_selector_->IsWindowInOverview(dragged_window))
return;
// Update the dragged window's bounds before adding it to overview. The
// dragged window might have resized to a smaller size if the drag
// happens on tab(s).
if (wm::IsDraggingTabs(dragged_window)) {
const gfx::Rect old_bounds = dragged_window->bounds();
// We need to temporarily disable the dragged window's ability to merge
// into another window when changing the dragged window's bounds, so
// that the dragged window doesn't merge into another window because of
// its changed bounds.
dragged_window->SetProperty(ash::kCanAttachToAnotherWindowKey, false);
TabletModeWindowState::UpdateWindowPosition(
wm::GetWindowState(dragged_window));
const gfx::Rect new_bounds = dragged_window->bounds();
if (old_bounds != new_bounds) {
// It's for smoother animation.
gfx::Transform transform =
ScopedTransformOverviewWindow::GetTransformForRect(new_bounds,
old_bounds);
dragged_window->SetTransform(transform);
}
dragged_window->ClearProperty(ash::kCanAttachToAnotherWindowKey);
}
window_selector_->AddItem(dragged_window, /*reposition=*/false,
/*animate=*/false);
}
} // namespace ash
......@@ -138,7 +138,8 @@ class ASH_EXPORT WindowGrid : public aura::WindowObserver,
const gfx::Point& location_in_screen,
IndicatorState indicator_state);
void OnWindowDragEnded(aura::Window* dragged_window,
const gfx::Point& location_in_screen);
const gfx::Point& location_in_screen,
bool should_drop_window_into_overview);
// Returns true if |window| is the placeholder window from the new selector
// item.
......@@ -295,6 +296,10 @@ class ASH_EXPORT WindowGrid : public aura::WindowObserver,
std::vector<std::unique_ptr<WindowSelectorItem>>::iterator
GetWindowSelectorItemIterContainingWindow(aura::Window* window);
// Adds the |dragged_window| into overview on drag ended. Might need to update
// the window's bounds if it has been resized.
void AddDraggedWindowIntoOverviewOnDragEnd(aura::Window* dragged_window);
// Root window the grid is in.
aura::Window* root_window_;
......
......@@ -667,12 +667,14 @@ void WindowSelector::OnWindowDragContinued(aura::Window* dragged_window,
indicator_state);
}
void WindowSelector::OnWindowDragEnded(aura::Window* dragged_window,
const gfx::Point& location_in_screen) {
const gfx::Point& location_in_screen,
bool should_drop_window_into_overview) {
WindowGrid* target_grid =
GetGridWithRootWindow(dragged_window->GetRootWindow());
if (!target_grid)
return;
target_grid->OnWindowDragEnded(dragged_window, location_in_screen);
target_grid->OnWindowDragEnded(dragged_window, location_in_screen,
should_drop_window_into_overview);
}
void WindowSelector::PositionWindows(bool animate,
......
......@@ -147,7 +147,8 @@ class ASH_EXPORT WindowSelector : public display::DisplayObserver,
const gfx::Point& location_in_screen,
IndicatorState indicator_state);
void OnWindowDragEnded(aura::Window* dragged_window,
const gfx::Point& location_in_screen);
const gfx::Point& location_in_screen,
bool should_drop_window_into_overview);
// Positions all of the windows in the overview, except |ignored_item|.
void PositionWindows(bool animate,
......
......@@ -565,6 +565,10 @@ gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const {
return transform_window_.GetTargetBoundsInScreen();
}
gfx::Rect WindowSelectorItem::GetTransformedBounds() const {
return transform_window_.GetTransformedBounds();
}
void WindowSelectorItem::SetBounds(const gfx::Rect& target_bounds,
OverviewAnimationType animation_type) {
if (in_bounds_update_)
......
......@@ -108,6 +108,9 @@ class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
// descendants of the window returned by GetWindow()).
gfx::Rect GetTargetBoundsInScreen() const;
// Returns the transformed bound of |transform_window_|.
gfx::Rect GetTransformedBounds() const;
// Sets the bounds of this window selector item to |target_bounds| in the
// |root_window_| root window. The bounds change will be animated as specified
// by |animation_type|.
......
......@@ -1708,6 +1708,18 @@ class SplitViewTabDraggingTest : public SplitViewControllerTest {
work_area_bounds.height() * kIndicatorsThresholdRatio;
}
gfx::Rect GetNewSelectorItemBoundsDuringDrag(aura::Window* window) const {
WindowSelector* window_selector =
Shell::Get()->window_selector_controller()->window_selector();
DCHECK(window_selector);
WindowGrid* current_grid =
window_selector->GetGridWithRootWindow(window->GetRootWindow());
DCHECK(current_grid);
WindowSelectorItem* selector_item = current_grid->GetNewSelectorItem();
return selector_item->GetTransformedBounds();
}
private:
DISALLOW_COPY_AND_ASSIGN(SplitViewTabDraggingTest);
};
......@@ -2509,7 +2521,7 @@ TEST_F(SplitViewTabDraggingTest, AdjustOverviewBoundsDuringDragging) {
TEST_F(SplitViewTabDraggingTest, WindowBoundsUpdatedBeforeAddingToOverview) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateBrowserTypeWindow(bounds));
const gfx::Rect tablet_mode_bounds = window1->bounds();
gfx::Rect tablet_mode_bounds = window1->bounds();
EXPECT_NE(bounds, tablet_mode_bounds);
// Drag |window1|. Overview should open behind the dragged window.
......@@ -2522,8 +2534,10 @@ TEST_F(SplitViewTabDraggingTest, WindowBoundsUpdatedBeforeAddingToOverview) {
EXPECT_EQ(bounds, window1->bounds());
// Drop |window1| to the new selector item in overview.
WindowSelectorController* window_selector_controller =
Shell::Get()->window_selector_controller();
WindowSelector* window_selector =
Shell::Get()->window_selector_controller()->window_selector();
window_selector_controller->window_selector();
WindowGrid* current_grid =
window_selector->GetGridWithRootWindow(window1->GetRootWindow());
ASSERT_TRUE(current_grid);
......@@ -2531,7 +2545,7 @@ TEST_F(SplitViewTabDraggingTest, WindowBoundsUpdatedBeforeAddingToOverview) {
WindowSelectorItem* selector_item = current_grid->GetNewSelectorItem();
ASSERT_TRUE(selector_item);
const gfx::Rect item_bounds_during_drag = selector_item->target_bounds();
gfx::Rect item_bounds_during_drag = selector_item->target_bounds();
DragWindowTo(resizer.get(), item_bounds_during_drag.CenterPoint());
CompleteDrag(std::move(resizer));
......@@ -2544,6 +2558,95 @@ TEST_F(SplitViewTabDraggingTest, WindowBoundsUpdatedBeforeAddingToOverview) {
// The new window selector item's bounds should be the same during drag and
// after drag.
EXPECT_EQ(item_bounds_during_drag, selector_item->target_bounds());
ToggleOverview();
EXPECT_FALSE(window_selector_controller->IsSelecting());
// Drag |window1|. Overview should open behind the dragged window.
resizer = StartDrag(window1.get(), window1.get());
EXPECT_TRUE(window_selector_controller->IsSelecting());
// Change the |window1|'s bounds to simulate what might happen in reality.
window1->SetBounds(bounds);
EXPECT_EQ(bounds, window1->bounds());
// Drag the window to right bottom outside the new selector item, the
// window's bounds should also be updated before being dropped into overview.
item_bounds_during_drag = GetNewSelectorItemBoundsDuringDrag(window1.get());
DragWindowTo(resizer.get(),
item_bounds_during_drag.bottom_right() + gfx::Vector2d(10, 10));
CompleteDrag(std::move(resizer));
// |window1| should have been merged into overview.
EXPECT_TRUE(window_selector_controller->window_selector()->IsWindowInOverview(
window1.get()));
// |window1|'s bounds should have been updated to its tablet mode bounds.
EXPECT_EQ(tablet_mode_bounds, window1->bounds());
}
// Tests that window should be dropped into overview if has been dragged further
// than half of the distance from top of display to the top of new selector item
// in overview.
TEST_F(SplitViewTabDraggingTest, DropWindowIntoOverviewOnDragPositionTest) {
const gfx::Rect bounds(0, 0, 400, 400);
std::unique_ptr<aura::Window> window1(CreateBrowserTypeWindow(bounds));
wm::GetWindowState(window1.get())->Maximize();
std::unique_ptr<WindowResizer> resizer =
StartDrag(window1.get(), window1.get());
// Restore window back to maximized if it has been dragged less than the
// distance threshold.
gfx::Rect item_bounds_during_drag =
GetNewSelectorItemBoundsDuringDrag(window1.get());
DragWindowTo(
resizer.get(),
gfx::Point(200,
TabletModeWindowDragDelegate::kDragPositionToOverviewRatio *
item_bounds_during_drag.y() -
10));
CompleteDrag(std::move(resizer));
EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized());
// Drop window into overview if it has beenn dragged further than the distance
// threshold.
resizer = StartDrag(window1.get(), window1.get());
item_bounds_during_drag = GetNewSelectorItemBoundsDuringDrag(window1.get());
DragWindowTo(
resizer.get(),
gfx::Point(200,
TabletModeWindowDragDelegate::kDragPositionToOverviewRatio *
item_bounds_during_drag.y() +
10));
CompleteDrag(std::move(resizer));
WindowSelector* window_selector =
Shell::Get()->window_selector_controller()->window_selector();
EXPECT_TRUE(window_selector->IsWindowInOverview(window1.get()));
ToggleOverview();
// Do not consider the drag position if preview area is shown. Window should
// to be snapped in this case.
resizer = StartDrag(window1.get(), window1.get());
item_bounds_during_drag = GetNewSelectorItemBoundsDuringDrag(window1.get());
DragWindowTo(resizer.get(), gfx::Point(0, item_bounds_during_drag.y() + 10));
EXPECT_EQ(IndicatorState::kPreviewAreaLeft, GetIndicatorState(resizer.get()));
CompleteDrag(std::move(resizer));
EXPECT_TRUE(wm::GetWindowState(window1.get())->IsSnapped());
EXPECT_EQ(SplitViewController::LEFT_SNAPPED,
split_view_controller()->state());
// Should not consider the drag position if splitview is active. Window should
// still back to be snapped.
std::unique_ptr<aura::Window> window2(CreateBrowserTypeWindow(bounds));
split_view_controller()->SnapWindow(window2.get(),
SplitViewController::RIGHT);
EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
split_view_controller()->state());
resizer = StartDrag(window1.get(), window1.get());
item_bounds_during_drag = GetNewSelectorItemBoundsDuringDrag(window1.get());
DragWindowTo(resizer.get(), gfx::Point(0, item_bounds_during_drag.y() + 10));
EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive());
CompleteDrag(std::move(resizer));
EXPECT_EQ(SplitViewController::BOTH_SNAPPED,
split_view_controller()->state());
EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting());
}
// Tests that a dragged window should have the active window shadow during
......@@ -2768,7 +2871,7 @@ TEST_F(SplitViewAppDraggingTest, DragNoneActiveMaximizedWindow) {
gfx::Point start = gfx::Point(0, 0);
// Drag the window that cannot be snapped long enough, the window will be
// restored back to maximized.
// dropped into overview.
base::TimeTicks timestamp = base::TimeTicks::Now();
SendScrollStartAndUpdate(start, long_scroll_delta, timestamp, window.get());
WindowSelectorController* window_selector_controller =
......@@ -2778,9 +2881,10 @@ TEST_F(SplitViewAppDraggingTest, DragNoneActiveMaximizedWindow) {
window_selector_controller->window_selector()->IsWindowInOverview(
window.get()));
EndScrollSequence(start, long_scroll_delta, timestamp, window.get());
EXPECT_FALSE(window_selector_controller->IsSelecting());
EXPECT_TRUE(window_selector_controller->IsSelecting());
EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
EXPECT_TRUE(window_selector_controller->window_selector()->IsWindowInOverview(
window.get()));
}
// Tests the functionalities that are related to dragging a maximized window
......@@ -2896,14 +3000,11 @@ TEST_F(SplitViewAppDraggingTest, DisplayConfigurationChangeTest) {
std::unique_ptr<aura::Window> window = CreateTestWindowWithWidget();
EXPECT_TRUE(wm::GetWindowState(window.get())->IsMaximized());
gfx::Rect display_bounds =
split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window.get());
// Start to drag the window long enough to snap.
const float long_scroll_delta = display_bounds.height() / 4 + 5;
// Drag the window a small distance that will not drop the window into
// overview.
base::TimeTicks timestamp = base::TimeTicks::Now();
SendScrollStartAndUpdate(gfx::Point(0, 0), long_scroll_delta, timestamp,
window.get());
SendScrollStartAndUpdate(gfx::Point(0, 0), 10, timestamp, window.get());
WindowSelectorController* window_selector_controller =
Shell::Get()->window_selector_controller();
EXPECT_TRUE(window_selector_controller->IsSelecting());
......
......@@ -39,18 +39,24 @@ WindowSelector* GetWindowSelector() {
: nullptr;
}
// Gets the bounds of selected new selector item in overview grid that is
// displaying in the same root window as |dragged_window|.
gfx::Rect GetBoundsOfSelectedNewSelectorItem(aura::Window* dragged_window) {
if (!Shell::Get()->window_selector_controller()->IsSelecting())
return gfx::Rect();
// Returns the new selector item in overview during drag.
WindowSelectorItem* GetNewSelectorItem(aura::Window* dragged_window) {
if (!GetWindowSelector())
return nullptr;
WindowGrid* window_grid = GetWindowSelector()->GetGridWithRootWindow(
dragged_window->GetRootWindow());
if (!window_grid || window_grid->empty())
return gfx::Rect();
return nullptr;
WindowSelectorItem* new_selector_item = window_grid->GetNewSelectorItem();
return window_grid->GetNewSelectorItem();
}
// Gets the bounds of selected new selector item in overview grid that is
// displaying in the same root window as |dragged_window|. Note that the
// returned bounds is scaled-up.
gfx::Rect GetBoundsOfSelectedNewSelectorItem(aura::Window* dragged_window) {
WindowSelectorItem* new_selector_item = GetNewSelectorItem(dragged_window);
if (!new_selector_item)
return gfx::Rect();
......@@ -175,6 +181,24 @@ void TabletModeWindowDragDelegate::ContinueWindowDrag(
}
}
bool TabletModeWindowDragDelegate::ShouldDropWindowIntoOverviewOnDragPosition(
SplitViewController::SnapPosition snap_position,
int end_y_position_in_screen) const {
// |snap_position| is not NONE, which means the preview area is shown or
// splitview is active.
if (snap_position != SplitViewController::NONE)
return false;
WindowSelectorItem* new_selector_item = GetNewSelectorItem(dragged_window_);
if (!new_selector_item)
return false;
const gfx::Rect new_selector_item_bounds =
new_selector_item->GetTransformedBounds();
return end_y_position_in_screen >
kDragPositionToOverviewRatio * new_selector_item_bounds.y();
}
void TabletModeWindowDragDelegate::EndWindowDrag(
wm::WmToplevelWindowEventHandler::DragResult result,
const gfx::Point& location_in_screen) {
......@@ -189,8 +213,12 @@ void TabletModeWindowDragDelegate::EndWindowDrag(
// The window might merge into an overview window or become a new window item
// in overview mode.
if (GetWindowSelector())
GetWindowSelector()->OnWindowDragEnded(dragged_window_, location_in_screen);
if (GetWindowSelector()) {
GetWindowSelector()->OnWindowDragEnded(
dragged_window_, location_in_screen,
ShouldDropWindowIntoOverviewOnDragPosition(snap_position,
location_in_screen.y()));
}
split_view_controller_->OnWindowDragEnded(dragged_window_, snap_position,
location_in_screen);
split_view_drag_indicators_->SetIndicatorState(IndicatorState::kNone,
......
......@@ -26,6 +26,10 @@ class SplitViewDragIndicators;
// backdrop, interacts with overview and splitview, etc.
class TabletModeWindowDragDelegate {
public:
// The threshold to compute the end position of the dragged window to drop it
// into overview.
static constexpr float kDragPositionToOverviewRatio = 0.5f;
enum class UpdateDraggedWindowType {
UPDATE_BOUNDS,
UPDATE_TRANSFORM,
......@@ -88,6 +92,13 @@ class TabletModeWindowDragDelegate {
// Update the dragged window's transform during dragging.
void UpdateDraggedWindowTransform(const gfx::Point& location_in_screen);
// Returns true if |dragged_window_| has been dragged more than half of the
// distance from top of the display to the top of the new selector item in
// overview, except that preview area is shown or splitview is active.
bool ShouldDropWindowIntoOverviewOnDragPosition(
SplitViewController::SnapPosition snap_position,
int end_y_position_in_screen) const;
SplitViewController* const split_view_controller_;
// A widget to display the drag indicators and preview window.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment