Commit 208266a8 authored by Avery Musbach's avatar Avery Musbach Committed by Commit Bot

split view: Reinsert split view window to overview at correct position

When a split view window is reinserted to overview, it shall go to the
correct position to maintain the MRU ordering of the overview grid.

Fixed: 1038396
Change-Id: I4cac7963610eb6a4b7022d2bc0e983e1f587a8cc
Bug: 1038396
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1984723Reviewed-by: default avatarSammie Quon <sammiequon@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Commit-Queue: Avery Musbach <amusbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728314}
parent f6ccee0f
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "ash/wm/desks/desk_mini_view.h" #include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desks_bar_view.h" #include "ash/wm/desks/desks_bar_view.h"
#include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/desks_util.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/cleanup_animation_observer.h" #include "ash/wm/overview/cleanup_animation_observer.h"
#include "ash/wm/overview/drop_target_view.h" #include "ash/wm/overview/drop_target_view.h"
#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_constants.h"
...@@ -557,6 +558,11 @@ void OverviewGrid::AppendItem(aura::Window* window, ...@@ -557,6 +558,11 @@ void OverviewGrid::AppendItem(aura::Window* window,
window_list_.size(), use_spawn_animation); window_list_.size(), use_spawn_animation);
} }
void OverviewGrid::AddItemInMruOrder(aura::Window* window, bool animate) {
AddItem(window, /*reposition=*/true, animate, /*ignored_items=*/{},
FindInsertionIndex(window));
}
void OverviewGrid::RemoveItem(OverviewItem* overview_item, void OverviewGrid::RemoveItem(OverviewItem* overview_item,
bool item_destroying, bool item_destroying,
bool reposition) { bool reposition) {
...@@ -1835,6 +1841,24 @@ size_t OverviewGrid::GetOverviewItemIndex(OverviewItem* item) const { ...@@ -1835,6 +1841,24 @@ size_t OverviewGrid::GetOverviewItemIndex(OverviewItem* item) const {
return iter - window_list_.begin(); return iter - window_list_.begin();
} }
size_t OverviewGrid::FindInsertionIndex(const aura::Window* window) {
DCHECK(!GetDropTarget());
size_t index = 0u;
for (aura::Window* mru_window :
Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk)) {
if (index == window_list_.size() || mru_window == window)
return index;
// As we iterate over the whole MRU window list, the windows in this grid
// will be encountered in the same order, but possibly with other windows in
// between. Ignore those other windows, and only increment |index| when we
// reach the next window in this grid.
if (mru_window == window_list_[index]->GetWindow())
++index;
}
NOTREACHED();
return 0u;
}
void OverviewGrid::AddDraggedWindowIntoOverviewOnDragEnd( void OverviewGrid::AddDraggedWindowIntoOverviewOnDragEnd(
aura::Window* dragged_window) { aura::Window* dragged_window) {
DCHECK(overview_session_); DCHECK(overview_session_);
......
...@@ -93,10 +93,6 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver, ...@@ -93,10 +93,6 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
// overview is already active, it will use a special spawn animation on its // overview is already active, it will use a special spawn animation on its
// first position in the grid. |use_spawn_animation| has no effect if either // first position in the grid. |use_spawn_animation| has no effect if either
// |animate| or |reposition| are false. // |animate| or |reposition| are false.
//
// Note: This function should only be called by |OverviewSession::AddItem| and
// |OverviewGrid::AppendItem|. |overview_session_| keeps count of all overview
// items, but this function does not update the tally.
void AddItem(aura::Window* window, void AddItem(aura::Window* window,
bool reposition, bool reposition,
bool animate, bool animate,
...@@ -105,23 +101,21 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver, ...@@ -105,23 +101,21 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
bool use_spawn_animation = false); bool use_spawn_animation = false);
// Similar to the above function, but adds the window to the end of the grid. // Similar to the above function, but adds the window to the end of the grid.
// Note: This function should only be called by |OverviewSession::AppendItem|.
// |overview_session_| keeps count of all overview items, but this function
// does not update the tally.
void AppendItem(aura::Window* window, void AppendItem(aura::Window* window,
bool reposition, bool reposition,
bool animate, bool animate,
bool use_spawn_animation = false); bool use_spawn_animation = false);
// Adds |window| at the correct position according to MRU order. |window|
// cannot already be on the grid. Repositions all items. If |animate| is true,
// animates the repositioning.
void AddItemInMruOrder(aura::Window* window, bool animate);
// Removes |overview_item| from the grid. |overview_item| cannot already be // Removes |overview_item| from the grid. |overview_item| cannot already be
// absent from the grid. If |item_destroying| is true, we may want to notify // absent from the grid. If |item_destroying| is true, we may want to notify
// |overview_session_| that this grid has become empty. If |item_destroying| // |overview_session_| that this grid has become empty. If |item_destroying|
// and |reposition| are both true, all items are repositioned with animation. // and |reposition| are both true, all items are repositioned with animation.
// |reposition| has no effect if |item_destroying| is false. // |reposition| has no effect if |item_destroying| is false.
//
// Note: This function should only be called by |OverviewSession::RemoveItem|
// and |OverviewGrid::Shutdown|. |overview_session_| keeps count of all
// overview items, but this function does not update the tally.
void RemoveItem(OverviewItem* overview_item, void RemoveItem(OverviewItem* overview_item,
bool item_destroying = false, bool item_destroying = false,
bool reposition = false); bool reposition = false);
...@@ -419,6 +413,10 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver, ...@@ -419,6 +413,10 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
// Returns the index of |item| in |window_list_|. // Returns the index of |item| in |window_list_|.
size_t GetOverviewItemIndex(OverviewItem* item) const; size_t GetOverviewItemIndex(OverviewItem* item) const;
// Returns the index where |window| can be inserted into |window_list_| based
// on MRU order.
size_t FindInsertionIndex(const aura::Window* window);
// Adds the |dragged_window| into overview on drag ended. Might need to update // Adds the |dragged_window| into overview on drag ended. Might need to update
// the window's bounds if it has been resized. // the window's bounds if it has been resized.
void AddDraggedWindowIntoOverviewOnDragEnd(aura::Window* dragged_window); void AddDraggedWindowIntoOverviewOnDragEnd(aura::Window* dragged_window);
......
...@@ -403,14 +403,7 @@ void OverviewSession::AddItem( ...@@ -403,14 +403,7 @@ void OverviewSession::AddItem(
return; return;
grid->AddItem(window, reposition, animate, ignored_items, index); grid->AddItem(window, reposition, animate, ignored_items, index);
++num_items_; OnItemAdded();
UpdateNoWindowsWidget();
// Transfer focus from |window| to |overview_focus_widget_| to match the
// behavior of entering overview mode in the beginning.
DCHECK(overview_focus_widget_);
wm::ActivateWindow(GetOverviewFocusWindow());
} }
void OverviewSession::AppendItem(aura::Window* window, void OverviewSession::AppendItem(aura::Window* window,
...@@ -422,14 +415,17 @@ void OverviewSession::AppendItem(aura::Window* window, ...@@ -422,14 +415,17 @@ void OverviewSession::AppendItem(aura::Window* window,
return; return;
grid->AppendItem(window, reposition, animate, /*use_spawn_animation=*/true); grid->AppendItem(window, reposition, animate, /*use_spawn_animation=*/true);
++num_items_; OnItemAdded();
}
UpdateNoWindowsWidget(); void OverviewSession::AddItemInMruOrder(aura::Window* window, bool animate) {
// Early exit if a grid already contains |window|.
OverviewGrid* grid = GetGridWithRootWindow(window->GetRootWindow());
if (!grid || grid->GetOverviewItemContaining(window))
return;
// Transfer focus from |window| to |overview_focus_widget_| to match the grid->AddItemInMruOrder(window, animate);
// behavior of entering overview mode in the beginning. OnItemAdded();
DCHECK(overview_focus_widget_);
wm::ActivateWindow(GetOverviewFocusWindow());
} }
void OverviewSession::RemoveItem(OverviewItem* overview_item) { void OverviewSession::RemoveItem(OverviewItem* overview_item) {
...@@ -1097,4 +1093,13 @@ void OverviewSession::RefreshNoWindowsWidgetBounds(bool animate) { ...@@ -1097,4 +1093,13 @@ void OverviewSession::RefreshNoWindowsWidgetBounds(bool animate) {
animate); animate);
} }
void OverviewSession::OnItemAdded() {
++num_items_;
UpdateNoWindowsWidget();
// Transfer focus from |window| to |overview_focus_widget_| to match the
// behavior of entering overview mode in the beginning.
DCHECK(overview_focus_widget_);
wm::ActivateWindow(GetOverviewFocusWindow());
}
} // namespace ash } // namespace ash
...@@ -174,6 +174,10 @@ class ASH_EXPORT OverviewSession : public display::DisplayObserver, ...@@ -174,6 +174,10 @@ class ASH_EXPORT OverviewSession : public display::DisplayObserver,
// TODO(afakhry): Expose |use_spawn_animation| if needed. // TODO(afakhry): Expose |use_spawn_animation| if needed.
void AppendItem(aura::Window* window, bool reposition, bool animate); void AppendItem(aura::Window* window, bool reposition, bool animate);
// Similar to |AddItem| with reposition=true, but adds the window at the
// correct position according to MRU order.
void AddItemInMruOrder(aura::Window* window, bool animate);
// Removes |overview_item| from the corresponding grid. No items are // Removes |overview_item| from the corresponding grid. No items are
// repositioned. // repositioned.
void RemoveItem(OverviewItem* overview_item); void RemoveItem(OverviewItem* overview_item);
...@@ -362,6 +366,8 @@ class ASH_EXPORT OverviewSession : public display::DisplayObserver, ...@@ -362,6 +366,8 @@ class ASH_EXPORT OverviewSession : public display::DisplayObserver,
void RefreshNoWindowsWidgetBounds(bool animate); void RefreshNoWindowsWidgetBounds(bool animate);
void OnItemAdded();
// Tracks observed windows. // Tracks observed windows.
base::flat_set<aura::Window*> observed_windows_; base::flat_set<aura::Window*> observed_windows_;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
#include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/desks_util.h"
#include "ash/wm/drag_window_resizer.h" #include "ash/wm/drag_window_resizer.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_constants.h" #include "ash/wm/overview/overview_constants.h"
#include "ash/wm/overview/overview_controller.h" #include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h" #include "ash/wm/overview/overview_grid.h"
...@@ -5015,6 +5016,74 @@ TEST_P(SplitViewOverviewSessionTest, ...@@ -5015,6 +5016,74 @@ TEST_P(SplitViewOverviewSessionTest,
EXPECT_FALSE(wm::IsActiveWindow(window1.get())); EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
} }
// Verify that if overview mode is active and the split view divider is dragged
// all the way to the opposite edge, then the split view window is reinserted
// into the overview grid at the correct position according to MRU order.
TEST_P(
SplitViewOverviewSessionTest,
SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenSplitViewIsEnded) {
const gfx::Rect bounds(400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
ToggleOverview();
DragWindowTo(GetOverviewItemForWindow(window1.get()), gfx::PointF());
DragWindowTo(GetOverviewItemForWindow(window2.get()),
gfx::PointF(799.f, 0.f));
EXPECT_EQ(window1.get(), split_view_controller()->left_window());
EXPECT_EQ(window2.get(), split_view_controller()->right_window());
ToggleOverview();
// Drag the divider to the left edge.
const gfx::Rect divider_bounds =
GetSplitViewDividerBounds(/*is_dragging=*/false);
GetEventGenerator()->set_current_screen_location(
divider_bounds.CenterPoint());
GetEventGenerator()->DragMouseTo(0, 0);
SkipDividerSnapAnimation();
ASSERT_TRUE(InOverviewSession());
const std::vector<aura::Window*> expected_mru_list = {window2.get(),
window1.get()};
const std::vector<aura::Window*> expected_overview_list = {window2.get(),
window1.get()};
EXPECT_EQ(
expected_mru_list,
Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk));
EXPECT_EQ(expected_overview_list,
overview_controller()->GetWindowsListInOverviewGridsForTest());
}
// Verify that if a window is dragged from overview and snapped in place of
// another split view window, then the old split view window is reinserted into
// the overview grid at the correct position according to MRU order.
TEST_P(
SplitViewOverviewSessionTest,
SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenAnotherWindowTakesItsPlace) {
const gfx::Rect bounds(400, 400);
std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
ToggleOverview();
DragWindowTo(GetOverviewItemForWindow(window1.get()), gfx::PointF());
DragWindowTo(GetOverviewItemForWindow(window2.get()),
gfx::PointF(799.f, 0.f));
EXPECT_EQ(window1.get(), split_view_controller()->left_window());
EXPECT_EQ(window2.get(), split_view_controller()->right_window());
ToggleOverview();
DragWindowTo(GetOverviewItemForWindow(window3.get()), gfx::PointF());
EXPECT_EQ(window3.get(), split_view_controller()->left_window());
ASSERT_TRUE(InOverviewSession());
const std::vector<aura::Window*> expected_mru_list = {
window3.get(), window2.get(), window1.get()};
const std::vector<aura::Window*> expected_overview_list = {window2.get(),
window1.get()};
EXPECT_EQ(
expected_mru_list,
Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk));
EXPECT_EQ(expected_overview_list,
overview_controller()->GetWindowsListInOverviewGridsForTest());
}
// Verify that if the split view divider is dragged close to the edge, the grid // Verify that if the split view divider is dragged close to the edge, the grid
// bounds will be fixed to a third of the work area width and start sliding off // bounds will be fixed to a third of the work area width and start sliding off
// the screen instead of continuing to shrink. // the screen instead of continuing to shrink.
......
...@@ -1749,7 +1749,7 @@ void SplitViewController::InsertWindowToOverview(aura::Window* window, ...@@ -1749,7 +1749,7 @@ void SplitViewController::InsertWindowToOverview(aura::Window* window,
bool animate) { bool animate) {
if (!window || !GetOverviewSession()) if (!window || !GetOverviewSession())
return; return;
GetOverviewSession()->AddItem(window, /*reposition=*/true, animate); GetOverviewSession()->AddItemInMruOrder(window, animate);
} }
void SplitViewController::FinishWindowResizing(aura::Window* window) { void SplitViewController::FinishWindowResizing(aura::Window* 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