Commit 9de45ee8 authored by chinsenj's avatar chinsenj Committed by Commit Bot

cros: Fix window cycle list (alt-tab) resets if open during desk swap.

Original CL dc64daa2 was reverted by
a326c157 due to a container-overflow.
This CL fixes the container-flow.

Original commit message:

While the flag for limiting windows to the current active desk is
enabled, if a user swaps desks while the window cycle list is open, the
contents will not update to the new active desk.

This CL makes the window cycle list reset if it is open and a desk
swap occurs while the aforementioned flag is enabled.

Test: LimitedWindowCycleControllerTest.CycleShowsActiveDeskWindows
Bug: 1067327
Change-Id: I9dddd0e780db33f5b727770583e0517f12eecece
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2417213Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Commit-Queue: Jeremy Chinsen <chinsenj@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809160}
parent 7c54897b
......@@ -27,6 +27,7 @@
#include "ash/wm/overview/overview_item.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/window_cycle_controller.h"
#include "ash/wm/window_util.h"
#include "base/auto_reset.h"
#include "base/check_op.h"
......@@ -536,6 +537,13 @@ void DesksController::ActivateDeskInternal(const Desk* desk,
MaybeUpdateShelfItems(old_active->windows(), active_desk_->windows());
// If in the middle of a window cycle gesture, reset the window cycle list
// contents so it contains the new active desk's windows.
if (features::IsAltTabLimitedToActiveDesk()) {
auto* window_cycle_controller = Shell::Get()->window_cycle_controller();
window_cycle_controller->MaybeResetCycleList();
}
for (auto& observer : observers_)
observer.OnDeskActivationChanged(active_desk_, old_active);
}
......
......@@ -30,7 +30,8 @@ namespace {
// Returns the most recently active window from the |window_list| or nullptr
// if the list is empty.
aura::Window* GetActiveWindow(const WindowCycleList::WindowList& window_list) {
aura::Window* GetActiveWindow(
const WindowCycleController::WindowList& window_list) {
return window_list.empty() ? nullptr : window_list[0];
}
......@@ -95,18 +96,8 @@ void WindowCycleController::StartCycling() {
// (http://crbug.com/895265).
Shell::Get()->wallpaper_controller()->MaybeClosePreviewWallpaper();
WindowCycleList::WindowList window_list =
Shell::Get()->mru_window_tracker()->BuildWindowForCycleWithPipList(
features::IsAltTabLimitedToActiveDesk() ? kActiveDesk : kAllDesks);
// Window cycle list windows will handle showing their transient related
// windows, so if a window in |window_list| has a transient root also in
// |window_list|, we can remove it as the transient root will handle showing
// the window.
window_util::RemoveTransientDescendants(&window_list);
active_desk_container_id_before_cycle_ =
desks_util::GetActiveDeskContainerId();
active_window_before_window_cycle_ = GetActiveWindow(window_list);
WindowCycleController::WindowList window_list = CreateWindowList();
SaveCurrentActiveDeskAndWindow(window_list);
window_cycle_list_ = std::make_unique<WindowCycleList>(window_list);
event_filter_ = std::make_unique<WindowCycleEventFilter>();
......@@ -124,6 +115,17 @@ void WindowCycleController::CancelCycling() {
StopCycling();
}
void WindowCycleController::MaybeResetCycleList() {
if (!IsCycling())
return;
WindowCycleController::WindowList window_list = CreateWindowList();
SaveCurrentActiveDeskAndWindow(window_list);
DCHECK(window_cycle_list_);
window_cycle_list_->ReplaceWindows(window_list);
}
void WindowCycleController::StepToWindow(aura::Window* window) {
DCHECK(window_cycle_list_);
window_cycle_list_->StepToWindow(window);
......@@ -140,6 +142,25 @@ bool WindowCycleController::IsWindowListVisible() {
//////////////////////////////////////////////////////////////////////////////
// WindowCycleController, private:
WindowCycleController::WindowList WindowCycleController::CreateWindowList() {
WindowCycleController::WindowList window_list =
Shell::Get()->mru_window_tracker()->BuildWindowForCycleWithPipList(
features::IsAltTabLimitedToActiveDesk() ? kActiveDesk : kAllDesks);
// Window cycle list windows will handle showing their transient related
// windows, so if a window in |window_list| has a transient root also in
// |window_list|, we can remove it as the transient root will handle showing
// the window.
window_util::RemoveTransientDescendants(&window_list);
return window_list;
}
void WindowCycleController::SaveCurrentActiveDeskAndWindow(
const WindowCycleController::WindowList& window_list) {
active_desk_container_id_before_cycle_ =
desks_util::GetActiveDeskContainerId();
active_window_before_window_cycle_ = GetActiveWindow(window_list);
}
void WindowCycleController::Step(Direction direction) {
DCHECK(window_cycle_list_);
window_cycle_list_->Step(direction);
......
......@@ -34,6 +34,8 @@ class WindowCycleList;
// order.
class ASH_EXPORT WindowCycleController {
public:
using WindowList = std::vector<aura::Window*>;
enum Direction { FORWARD, BACKWARD };
WindowCycleController();
......@@ -60,6 +62,10 @@ class ASH_EXPORT WindowCycleController {
void CompleteCycling();
void CancelCycling();
// If the window cycle list is open, re-construct it. Do nothing if not
// cycling.
void MaybeResetCycleList();
// Skip window cycle list directly to |window|.
void StepToWindow(aura::Window* window);
......@@ -75,6 +81,16 @@ class ASH_EXPORT WindowCycleController {
}
private:
// Gets a list of windows from the currently open windows, removing windows
// with transient roots already in the list. The returned list of windows
// is used to populate the window cycle list.
WindowList CreateWindowList();
// Populates |active_desk_container_id_before_cycle_| and
// |active_window_before_window_cycle_| when the window cycle list is
// initialized.
void SaveCurrentActiveDeskAndWindow(const WindowList& window_list);
// Cycles to the next or previous window based on |direction|.
void Step(Direction direction);
......
......@@ -850,6 +850,20 @@ TEST_F(LimitedWindowCycleControllerTest, CycleShowsActiveDeskWindows) {
EXPECT_TRUE(base::Contains(cycle_windows, win1.get()));
cycle_controller->CompleteCycling();
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
// Swap desks while cycling, contents should update.
cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
cycle_windows = GetWindows(cycle_controller);
EXPECT_EQ(2u, cycle_windows.size());
EXPECT_TRUE(base::Contains(cycle_windows, win0.get()));
EXPECT_TRUE(base::Contains(cycle_windows, win1.get()));
ActivateDesk(desk_2);
EXPECT_TRUE(cycle_controller->IsCycling());
cycle_windows = GetWindows(cycle_controller);
EXPECT_EQ(1u, cycle_windows.size());
EXPECT_TRUE(base::Contains(cycle_windows, win2.get()));
cycle_controller->CompleteCycling();
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
}
class InteractiveWindowCycleControllerTest : public WindowCycleControllerTest {
......
......@@ -296,6 +296,24 @@ class WindowCycleView : public views::WidgetDelegateView,
WindowCycleView& operator=(const WindowCycleView&) = delete;
~WindowCycleView() override = default;
void UpdateWindows(const WindowCycleList::WindowList& windows) {
for (auto* window : windows) {
auto* view = mirror_container_->AddChildView(
std::make_unique<WindowCycleItemView>(window));
window_view_map_[window] = view;
no_previews_set_.insert(view);
}
// Resize the widget.
aura::Window* root_window = Shell::GetRootWindowForNewWindows();
gfx::Rect widget_rect = root_window->GetBoundsInScreen();
widget_rect.ClampToCenteredSize(GetPreferredSize());
GetWidget()->SetBounds(widget_rect);
SetTargetWindow(windows[0], /*should_layout=*/true);
}
void FadeInLayer() {
DCHECK(GetWidget());
......@@ -514,6 +532,20 @@ WindowCycleList::~WindowCycleList() {
Shell::Get()->frame_throttling_controller()->EndThrottling();
}
void WindowCycleList::ReplaceWindows(const WindowList& windows) {
if (windows.empty())
return;
RemoveAllWindows();
windows_ = windows;
for (auto* new_window : windows_)
new_window->AddObserver(this);
if (ShouldShowUi() && cycle_view_)
cycle_view_->UpdateWindows(windows_);
}
void WindowCycleList::Step(WindowCycleController::Direction direction) {
Step(direction == WindowCycleController::FORWARD ? 1 : -1,
/*should_layout=*/true);
......@@ -567,6 +599,7 @@ void WindowCycleList::OnWindowDestroying(aura::Window* window) {
auto* new_target_window =
windows_.empty() ? nullptr : windows_[current_index_];
cycle_view_->HandleWindowDestruction(window, new_target_window);
if (windows_.empty()) {
// This deletes us.
Shell::Get()->window_cycle_controller()->CancelCycling();
......@@ -589,6 +622,18 @@ void WindowCycleList::OnDisplayMetricsChanged(const display::Display& display,
}
}
void WindowCycleList::RemoveAllWindows() {
for (auto* window : windows_) {
window->RemoveObserver(this);
if (cycle_view_)
cycle_view_->HandleWindowDestruction(window, nullptr);
}
windows_.clear();
current_index_ = 0;
}
void WindowCycleList::InitWindowCycleView() {
if (cycle_view_)
return;
......
......@@ -42,6 +42,10 @@ class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
WindowCycleList& operator=(const WindowCycleList&) = delete;
~WindowCycleList() override;
// Removes the existing windows and replaces them with |windows|. If
// |windows| is empty, cancels cycling.
void ReplaceWindows(const WindowList& windows);
// Cycles to the next or previous window based on |direction| and re-layouts
// the window cycle list, scrolling the list.
void Step(WindowCycleController::Direction direction);
......@@ -80,6 +84,10 @@ class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
// Removes all windows from the window list. Also removes the windows from
// |cycle_view_| if |cycle_view_| exists.
void RemoveAllWindows();
// Initializes and shows |cycle_view_|.
void InitWindowCycleView();
......
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