1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/window_cycle_list.h"
8 #include "ash/wm/mru_window_tracker.h"
9 #include "ash/wm/window_animations.h"
10 #include "ash/wm/window_state.h"
11 #include "ash/wm/window_util.h"
12 #include "ui/aura/window.h"
16 // Returns the window immediately below |window| in the current container.
17 aura::Window
* GetWindowBelow(aura::Window
* window
) {
18 aura::Window
* parent
= window
->parent();
21 aura::Window::Windows::const_iterator iter
=
22 std::find(parent
->children().begin(), parent
->children().end(), window
);
23 CHECK(*iter
== window
);
24 if (iter
!= parent
->children().begin())
30 // This class restores and moves a window to the front of the stacking order for
31 // the duration of the class's scope.
32 class ScopedShowWindow
: public aura::WindowObserver
{
35 ~ScopedShowWindow() override
;
37 // Show |window| at the top of the stacking order.
38 void Show(aura::Window
* window
);
40 // Cancel restoring the window on going out of scope.
44 // aura::WindowObserver:
45 void OnWillRemoveWindow(aura::Window
* window
) override
;
47 // The window being shown.
48 aura::Window
* window_
;
50 // The window immediately below where window_ belongs.
51 aura::Window
* stack_window_above_
;
53 // If true, minimize window_ on going out of scope.
56 DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow
);
59 ScopedShowWindow::ScopedShowWindow()
61 stack_window_above_(NULL
),
65 ScopedShowWindow::~ScopedShowWindow() {
67 window_
->parent()->RemoveObserver(this);
69 // Restore window's stacking position.
70 if (stack_window_above_
)
71 window_
->parent()->StackChildAbove(window_
, stack_window_above_
);
73 window_
->parent()->StackChildAtBottom(window_
);
75 // Restore minimized state.
77 wm::GetWindowState(window_
)->Minimize();
81 void ScopedShowWindow::Show(aura::Window
* window
) {
84 stack_window_above_
= GetWindowBelow(window
);
85 minimized_
= wm::GetWindowState(window
)->IsMinimized();
86 window_
->parent()->AddObserver(this);
88 wm::GetWindowState(window_
)->Activate();
91 void ScopedShowWindow::CancelRestore() {
94 window_
->parent()->RemoveObserver(this);
95 window_
= stack_window_above_
= NULL
;
98 void ScopedShowWindow::OnWillRemoveWindow(aura::Window
* window
) {
99 if (window
== window_
) {
101 } else if (window
== stack_window_above_
) {
102 // If the window this window was above is removed, use the next window down
103 // as the restore marker.
104 stack_window_above_
= GetWindowBelow(stack_window_above_
);
108 WindowCycleList::WindowCycleList(const WindowList
& windows
)
111 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
113 for (auto* window
: windows_
)
114 window
->AddObserver(this);
117 WindowCycleList::~WindowCycleList() {
118 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false);
119 for (auto* window
: windows_
) {
120 // TODO(oshima): Remove this once crbug.com/483491 is fixed.
122 window
->RemoveObserver(this);
125 showing_window_
->CancelRestore();
128 void WindowCycleList::Step(WindowCycleController::Direction direction
) {
129 if (windows_
.empty())
132 // When there is only one window, we should give feedback to the user. If the
133 // window is minimized, we should also show it.
134 if (windows_
.size() == 1) {
135 ::wm::AnimateWindow(windows_
[0], ::wm::WINDOW_ANIMATION_TYPE_BOUNCE
);
137 wm::GetWindowState(windows_
[0])->Activate();
141 DCHECK(static_cast<size_t>(current_index_
) < windows_
.size());
143 // We're in a valid cycle, so step forward or backward.
144 current_index_
+= direction
== WindowCycleController::FORWARD
? 1 : -1;
146 // Wrap to window list size.
147 current_index_
= (current_index_
+ windows_
.size()) % windows_
.size();
148 DCHECK(windows_
[current_index_
]);
150 // Make sure the next window is visible.
151 showing_window_
.reset(new ScopedShowWindow
);
152 showing_window_
->Show(windows_
[current_index_
]);
155 void WindowCycleList::OnWindowDestroying(aura::Window
* window
) {
156 window
->RemoveObserver(this);
158 WindowList::iterator i
= std::find(windows_
.begin(), windows_
.end(), window
);
159 // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed.
160 CHECK(i
!= windows_
.end());
161 int removed_index
= static_cast<int>(i
- windows_
.begin());
163 if (current_index_
> removed_index
||
164 current_index_
== static_cast<int>(windows_
.size())) {