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.
43 aura::Window
* window() { return window_
; }
45 // aura::WindowObserver:
46 void OnWillRemoveWindow(aura::Window
* window
) override
;
49 // The window being shown.
50 aura::Window
* window_
;
52 // The window immediately below where window_ belongs.
53 aura::Window
* stack_window_above_
;
55 // If true, minimize window_ on going out of scope.
58 DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow
);
61 ScopedShowWindow::ScopedShowWindow()
63 stack_window_above_(NULL
),
67 ScopedShowWindow::~ScopedShowWindow() {
69 window_
->parent()->RemoveObserver(this);
71 // Restore window's stacking position.
72 if (stack_window_above_
)
73 window_
->parent()->StackChildAbove(window_
, stack_window_above_
);
75 window_
->parent()->StackChildAtBottom(window_
);
77 // Restore minimized state.
79 wm::GetWindowState(window_
)->Minimize();
83 void ScopedShowWindow::Show(aura::Window
* window
) {
86 stack_window_above_
= GetWindowBelow(window
);
87 minimized_
= wm::GetWindowState(window
)->IsMinimized();
88 window_
->parent()->AddObserver(this);
90 wm::GetWindowState(window_
)->Activate();
93 void ScopedShowWindow::CancelRestore() {
96 window_
->parent()->RemoveObserver(this);
97 window_
= stack_window_above_
= NULL
;
100 void ScopedShowWindow::OnWillRemoveWindow(aura::Window
* window
) {
101 if (window
== window_
) {
103 } else if (window
== stack_window_above_
) {
104 // If the window this window was above is removed, use the next window down
105 // as the restore marker.
106 stack_window_above_
= GetWindowBelow(stack_window_above_
);
110 WindowCycleList::WindowCycleList(const WindowList
& windows
)
113 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
115 for (WindowList::const_iterator i
= windows_
.begin(); i
!= windows_
.end();
117 (*i
)->AddObserver(this);
121 WindowCycleList::~WindowCycleList() {
122 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(false);
123 for (WindowList::const_iterator i
= windows_
.begin(); i
!= windows_
.end();
125 (*i
)->RemoveObserver(this);
128 showing_window_
->CancelRestore();
131 void WindowCycleList::Step(WindowCycleController::Direction direction
) {
132 if (windows_
.empty())
135 // When there is only one window, we should give feedback to the user. If the
136 // window is minimized, we should also show it.
137 if (windows_
.size() == 1) {
138 ::wm::AnimateWindow(windows_
[0], ::wm::WINDOW_ANIMATION_TYPE_BOUNCE
);
140 wm::GetWindowState(windows_
[0])->Activate();
144 DCHECK(static_cast<size_t>(current_index_
) < windows_
.size());
146 // We're in a valid cycle, so step forward or backward.
147 current_index_
+= direction
== WindowCycleController::FORWARD
? 1 : -1;
149 // Wrap to window list size.
150 current_index_
= (current_index_
+ windows_
.size()) % windows_
.size();
151 DCHECK(windows_
[current_index_
]);
153 // Make sure the next window is visible.
154 showing_window_
.reset(new ScopedShowWindow
);
155 showing_window_
->Show(windows_
[current_index_
]);
158 void WindowCycleList::OnWindowDestroyed(aura::Window
* window
) {
159 window
->RemoveObserver(this);
161 WindowList::iterator i
= std::find(windows_
.begin(), windows_
.end(), window
);
162 DCHECK(i
!= windows_
.end());
163 int removed_index
= static_cast<int>(i
- windows_
.begin());
165 if (current_index_
> removed_index
||
166 current_index_
== static_cast<int>(windows_
.size())) {