1 // Copyright 2013 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/mru_window_tracker.h"
9 #include "ash/session_state_delegate.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/activation_controller.h"
13 #include "ash/wm/window_cycle_list.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/workspace_controller.h"
16 #include "ui/aura/root_window.h"
17 #include "ui/base/events/event.h"
18 #include "ui/base/events/event_handler.h"
24 // List of containers whose children we will allow switching to.
25 const int kContainerIds
[] = {
26 internal::kShellWindowId_DefaultContainer
,
27 internal::kShellWindowId_AlwaysOnTopContainer
30 // Adds the windows that can be cycled through for the specified window id to
32 void AddTrackedWindows(aura::RootWindow
* root
,
34 MruWindowTracker::WindowList
* windows
) {
35 aura::Window
* container
= Shell::GetContainer(root
, container_id
);
36 const MruWindowTracker::WindowList
& children(container
->children());
37 windows
->insert(windows
->end(), children
.begin(), children
.end());
40 // Returns a list of windows ordered by their stacking order.
41 // If |mru_windows| is passed, these windows are moved to the front of the list.
42 // If |top_most_at_end|, the list is returned in descending (bottom-most / least
43 // recently used) order.
44 MruWindowTracker::WindowList
BuildWindowListInternal(
45 const std::list
<aura::Window
*>* mru_windows
,
46 bool top_most_at_end
) {
47 MruWindowTracker::WindowList windows
;
48 Shell::RootWindowList root_windows
= Shell::GetAllRootWindows();
50 aura::RootWindow
* active_root
= Shell::GetActiveRootWindow();
51 for (Shell::RootWindowList::const_iterator iter
= root_windows
.begin();
52 iter
!= root_windows
.end(); ++iter
) {
53 if (*iter
== active_root
)
55 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
)
56 AddTrackedWindows(*iter
, kContainerIds
[i
], &windows
);
59 // Add windows in the active root windows last so that the topmost window
60 // in the active root window becomes the front of the list.
61 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
)
62 AddTrackedWindows(active_root
, kContainerIds
[i
], &windows
);
64 // Removes unfocusable windows.
65 MruWindowTracker::WindowList::iterator last
=
69 std::not1(std::ptr_fun(ash::wm::CanActivateWindow
)));
70 windows
.erase(last
, windows
.end());
72 // Put the windows in the mru_windows list at the head, if it's available.
74 // Iterate through the list backwards, so that we can move each window to
75 // the front of the windows list as we find them.
76 for (std::list
<aura::Window
*>::const_reverse_iterator ix
=
77 mru_windows
->rbegin();
78 ix
!= mru_windows
->rend(); ++ix
) {
79 MruWindowTracker::WindowList::iterator window
=
80 std::find(windows
.begin(), windows
.end(), *ix
);
81 if (window
!= windows
.end()) {
82 windows
.erase(window
);
83 windows
.push_back(*ix
);
88 // Window cycling expects the topmost window at the front of the list.
90 std::reverse(windows
.begin(), windows
.end());
97 //////////////////////////////////////////////////////////////////////////////
98 // MruWindowTracker, public:
100 MruWindowTracker::MruWindowTracker(
101 aura::client::ActivationClient
* activation_client
)
102 : activation_client_(activation_client
),
103 ignore_window_activations_(false) {
104 activation_client_
->AddObserver(this);
107 MruWindowTracker::~MruWindowTracker() {
108 Shell::RootWindowList root_windows
= Shell::GetAllRootWindows();
109 for (Shell::RootWindowList::const_iterator iter
= root_windows
.begin();
110 iter
!= root_windows
.end(); ++iter
) {
111 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
) {
112 aura::Window
* container
= Shell::GetContainer(*iter
, kContainerIds
[i
]);
114 container
->RemoveObserver(this);
118 activation_client_
->RemoveObserver(this);
122 MruWindowTracker::WindowList
MruWindowTracker::BuildWindowList(
123 bool top_most_at_end
) {
124 return BuildWindowListInternal(NULL
, top_most_at_end
);
127 MruWindowTracker::WindowList
MruWindowTracker::BuildMruWindowList() {
128 return BuildWindowListInternal(&mru_windows_
, false);
131 void MruWindowTracker::OnRootWindowAdded(aura::RootWindow
* root_window
) {
132 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
) {
133 aura::Window
* container
=
134 Shell::GetContainer(root_window
, kContainerIds
[i
]);
135 container
->AddObserver(this);
139 void MruWindowTracker::SetIgnoreActivations(bool ignore
) {
140 ignore_window_activations_
= ignore
;
142 // If no longer ignoring window activations, move currently active window
145 aura::Window
* active_window
= wm::GetActiveWindow();
146 mru_windows_
.remove(active_window
);
147 mru_windows_
.push_front(active_window
);
151 //////////////////////////////////////////////////////////////////////////////
152 // MruWindowTracker, private:
155 bool MruWindowTracker::IsTrackedContainer(aura::Window
* window
) {
158 for (size_t i
= 0; i
< arraysize(kContainerIds
); ++i
) {
159 if (window
->id() == kContainerIds
[i
])
165 void MruWindowTracker::OnWindowActivated(aura::Window
* gained_active
,
166 aura::Window
* lost_active
) {
167 if (gained_active
&& !ignore_window_activations_
&&
168 IsTrackedContainer(gained_active
->parent())) {
169 mru_windows_
.remove(gained_active
);
170 mru_windows_
.push_front(gained_active
);
174 void MruWindowTracker::OnWillRemoveWindow(aura::Window
* window
) {
175 mru_windows_
.remove(window
);
178 void MruWindowTracker::OnWindowDestroying(aura::Window
* window
) {
179 window
->RemoveObserver(this);