Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: ash/wm/mru_window_tracker.cc

Issue 20708005: Refactor most recently used window tracking into a separate class. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/wm/window_cycle_controller.h" 5 #include "ash/wm/mru_window_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "ash/session_state_delegate.h" 9 #include "ash/session_state_delegate.h"
10 #include "ash/shell.h" 10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h" 11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/activation_controller.h" 12 #include "ash/wm/activation_controller.h"
13 #include "ash/wm/window_cycle_list.h" 13 #include "ash/wm/window_cycle_list.h"
14 #include "ash/wm/window_util.h" 14 #include "ash/wm/window_util.h"
15 #include "ash/wm/workspace_controller.h" 15 #include "ash/wm/workspace_controller.h"
16 #include "ui/aura/root_window.h" 16 #include "ui/aura/root_window.h"
17 #include "ui/base/events/event.h" 17 #include "ui/base/events/event.h"
18 #include "ui/base/events/event_handler.h" 18 #include "ui/base/events/event_handler.h"
19 19
20 namespace ash { 20 namespace ash {
21 21
22 namespace { 22 namespace {
23 23
24 // List of containers whose children we will cycle through. 24 // List of containers whose children we will allow switching to.
25 const int kContainerIds[] = { 25 const int kContainerIds[] = {
26 internal::kShellWindowId_DefaultContainer, 26 internal::kShellWindowId_DefaultContainer,
27 internal::kShellWindowId_AlwaysOnTopContainer 27 internal::kShellWindowId_AlwaysOnTopContainer
28 }; 28 };
29 29
30 // Filter to watch for the termination of a keyboard gesture to cycle through
31 // multiple windows.
32 class WindowCycleEventFilter : public ui::EventHandler {
33 public:
34 WindowCycleEventFilter();
35 virtual ~WindowCycleEventFilter();
36
37 // Overridden from ui::EventHandler:
38 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
39 private:
40 DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter);
41 };
42
43 // Watch for all keyboard events by filtering the root window.
44 WindowCycleEventFilter::WindowCycleEventFilter() {
45 }
46
47 WindowCycleEventFilter::~WindowCycleEventFilter() {
48 }
49
50 void WindowCycleEventFilter::OnKeyEvent(ui::KeyEvent* event) {
51 // Views uses VKEY_MENU for both left and right Alt keys.
52 if (event->key_code() == ui::VKEY_MENU &&
53 event->type() == ui::ET_KEY_RELEASED) {
54 Shell::GetInstance()->window_cycle_controller()->AltKeyReleased();
55 // Warning: |this| will be deleted from here on.
56 }
57 }
58
59 // Adds all the children of |window| to |windows|. 30 // Adds all the children of |window| to |windows|.
60 void AddAllChildren(aura::Window* window, 31 void AddAllChildren(aura::Window* window,
61 WindowCycleList::WindowList* windows) { 32 MruWindowTracker::WindowList* windows) {
62 const WindowCycleList::WindowList& children(window->children()); 33 const MruWindowTracker::WindowList& children(window->children());
63 windows->insert(windows->end(), children.begin(), children.end()); 34 windows->insert(windows->end(), children.begin(), children.end());
64 } 35 }
65 36
66 // Adds all the children of all of |window|s children to |windows|. 37 // Adds all the children of all of |window|s children to |windows|.
67 void AddWorkspaceChildren(aura::Window* window, 38 void AddWorkspaceChildren(aura::Window* window,
68 WindowCycleList::WindowList* windows) { 39 MruWindowTracker::WindowList* windows) {
69 for (size_t i = 0; i < window->children().size(); ++i) 40 for (size_t i = 0; i < window->children().size(); ++i)
70 AddAllChildren(window->children()[i], windows); 41 AddAllChildren(window->children()[i], windows);
71 } 42 }
72 43
73 // Adds the windows that can be cycled through for the specified window id to 44 // Adds the windows that can be cycled through for the specified window id to
74 // |windows|. 45 // |windows|.
75 void AddCycleWindows(aura::RootWindow* root, 46 void AddTrackedWindows(aura::RootWindow* root,
76 int container_id, 47 int container_id,
77 WindowCycleList::WindowList* windows) { 48 MruWindowTracker::WindowList* windows) {
78 aura::Window* container = Shell::GetContainer(root, container_id); 49 aura::Window* container = Shell::GetContainer(root, container_id);
79 if (container_id == internal::kShellWindowId_DefaultContainer) 50 if (container_id == internal::kShellWindowId_DefaultContainer)
80 AddWorkspaceChildren(container, windows); 51 AddWorkspaceChildren(container, windows);
81 else 52 else
82 AddAllChildren(container, windows); 53 AddAllChildren(container, windows);
83 } 54 }
84 55
85 } // namespace 56 } // namespace
86 57
87 ////////////////////////////////////////////////////////////////////////////// 58 //////////////////////////////////////////////////////////////////////////////
88 // WindowCycleController, public: 59 // MruWindowTracker, public:
89 60
90 WindowCycleController::WindowCycleController( 61 MruWindowTracker::MruWindowTracker(
91 aura::client::ActivationClient* activation_client) 62 aura::client::ActivationClient* activation_client)
92 : activation_client_(activation_client) { 63 : activation_client_(activation_client),
64 ignore_window_activations_(false) {
93 activation_client_->AddObserver(this); 65 activation_client_->AddObserver(this);
94 } 66 }
95 67
96 WindowCycleController::~WindowCycleController() { 68 MruWindowTracker::~MruWindowTracker() {
97 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 69 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
98 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); 70 for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
99 iter != root_windows.end(); ++iter) { 71 iter != root_windows.end(); ++iter) {
100 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { 72 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
101 aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]); 73 aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]);
102 if (container) 74 if (container)
103 container->RemoveObserver(this); 75 container->RemoveObserver(this);
104 } 76 }
105 aura::Window* default_container = 77 aura::Window* default_container =
106 Shell::GetContainer(*iter, internal::kShellWindowId_DefaultContainer); 78 Shell::GetContainer(*iter, internal::kShellWindowId_DefaultContainer);
107 if (default_container) { 79 if (default_container) {
108 for (size_t i = 0; i < default_container->children().size(); ++i) { 80 for (size_t i = 0; i < default_container->children().size(); ++i) {
109 aura::Window* workspace_window = default_container->children()[i]; 81 aura::Window* workspace_window = default_container->children()[i];
110 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer, 82 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer,
111 workspace_window->id()); 83 workspace_window->id());
112 workspace_window->RemoveObserver(this); 84 workspace_window->RemoveObserver(this);
113 } 85 }
114 } 86 }
115 } 87 }
116 88
117 activation_client_->RemoveObserver(this); 89 activation_client_->RemoveObserver(this);
118 StopCycling();
119 } 90 }
120 91
121 // static 92 // static
122 bool WindowCycleController::CanCycle() { 93 MruWindowTracker::WindowList MruWindowTracker::BuildWindowList(
123 // Don't allow window cycling if the screen is locked or a modal dialog is
124 // open.
125 return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
126 !Shell::GetInstance()->IsSystemModalWindowOpen();
127 }
128
129 void WindowCycleController::HandleCycleWindow(Direction direction,
130 bool is_alt_down) {
131 if (!CanCycle())
132 return;
133
134 if (is_alt_down) {
135 if (!IsCycling()) {
136 // This is the start of an alt-tab cycle through multiple windows, so
137 // listen for the alt key being released to stop cycling.
138 StartCycling();
139 Step(direction);
140 InstallEventFilter();
141 } else {
142 // We're in the middle of an alt-tab cycle, just step forward.
143 Step(direction);
144 }
145 } else {
146 // This is a simple, single-step window cycle.
147 StartCycling();
148 Step(direction);
149 StopCycling();
150 }
151 }
152
153 void WindowCycleController::HandleLinearCycleWindow() {
154 if (!CanCycle() || IsCycling())
155 return;
156
157 // Use the reversed list of windows to prevent a 2-cycle of the most recent
158 // windows occurring.
159 WindowCycleList cycle_list(BuildWindowList(NULL,true));
160 cycle_list.Step(WindowCycleList::FORWARD);
161 }
162
163 void WindowCycleController::AltKeyReleased() {
164 StopCycling();
165 }
166
167 // static
168 std::vector<aura::Window*> WindowCycleController::BuildWindowList(
169 const std::list<aura::Window*>* mru_windows, 94 const std::list<aura::Window*>* mru_windows,
170 bool top_most_at_end) { 95 bool top_most_at_end) {
171 WindowCycleList::WindowList windows; 96 MruWindowTracker::WindowList windows;
172 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 97 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
173 98
174 aura::RootWindow* active_root = Shell::GetActiveRootWindow(); 99 aura::RootWindow* active_root = Shell::GetActiveRootWindow();
175 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); 100 for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
176 iter != root_windows.end(); ++iter) { 101 iter != root_windows.end(); ++iter) {
177 if (*iter == active_root) 102 if (*iter == active_root)
178 continue; 103 continue;
179 for (size_t i = 0; i < arraysize(kContainerIds); ++i) 104 for (size_t i = 0; i < arraysize(kContainerIds); ++i)
180 AddCycleWindows(*iter, kContainerIds[i], &windows); 105 AddTrackedWindows(*iter, kContainerIds[i], &windows);
181 } 106 }
182 107
183 // Add windows in the active root windows last so that the topmost window 108 // Add windows in the active root windows last so that the topmost window
184 // in the active root window becomes the front of the list. 109 // in the active root window becomes the front of the list.
185 for (size_t i = 0; i < arraysize(kContainerIds); ++i) 110 for (size_t i = 0; i < arraysize(kContainerIds); ++i)
186 AddCycleWindows(active_root, kContainerIds[i], &windows); 111 AddTrackedWindows(active_root, kContainerIds[i], &windows);
187 112
188 // Removes unfocusable windows. 113 // Removes unfocusable windows.
189 WindowCycleList::WindowList::iterator last = 114 MruWindowTracker::WindowList::iterator last =
190 std::remove_if( 115 std::remove_if(
191 windows.begin(), 116 windows.begin(),
192 windows.end(), 117 windows.end(),
193 std::not1(std::ptr_fun(ash::wm::CanActivateWindow))); 118 std::not1(std::ptr_fun(ash::wm::CanActivateWindow)));
194 windows.erase(last, windows.end()); 119 windows.erase(last, windows.end());
195 120
196 // Put the windows in the mru_windows list at the head, if it's available. 121 // Put the windows in the mru_windows list at the head, if it's available.
197 if (mru_windows) { 122 if (mru_windows) {
198 // Iterate through the list backwards, so that we can move each window to 123 // Iterate through the list backwards, so that we can move each window to
199 // the front of the windows list as we find them. 124 // the front of the windows list as we find them.
200 for (std::list<aura::Window*>::const_reverse_iterator ix = 125 for (std::list<aura::Window*>::const_reverse_iterator ix =
201 mru_windows->rbegin(); 126 mru_windows->rbegin();
202 ix != mru_windows->rend(); ++ix) { 127 ix != mru_windows->rend(); ++ix) {
203 WindowCycleList::WindowList::iterator window = 128 MruWindowTracker::WindowList::iterator window =
204 std::find(windows.begin(), windows.end(), *ix); 129 std::find(windows.begin(), windows.end(), *ix);
205 if (window != windows.end()) { 130 if (window != windows.end()) {
206 windows.erase(window); 131 windows.erase(window);
207 windows.push_back(*ix); 132 windows.push_back(*ix);
208 } 133 }
209 } 134 }
210 } 135 }
211 136
212 // Window cycling expects the topmost window at the front of the list. 137 // Window cycling expects the topmost window at the front of the list.
213 if (!top_most_at_end) 138 if (!top_most_at_end)
214 std::reverse(windows.begin(), windows.end()); 139 std::reverse(windows.begin(), windows.end());
215 140
216 return windows; 141 return windows;
217 } 142 }
218 143
219 void WindowCycleController::OnRootWindowAdded(aura::RootWindow* root_window) { 144 MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList(
145 bool top_most_at_end) {
146 return BuildWindowList(&mru_windows_, top_most_at_end);
147 }
148
149 void MruWindowTracker::OnRootWindowAdded(aura::RootWindow* root_window) {
220 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { 150 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
221 aura::Window* container = 151 aura::Window* container =
222 Shell::GetContainer(root_window, kContainerIds[i]); 152 Shell::GetContainer(root_window, kContainerIds[i]);
223 container->AddObserver(this); 153 container->AddObserver(this);
224 } 154 }
225 155
226 aura::Window* default_container = 156 aura::Window* default_container =
227 Shell::GetContainer(root_window, 157 Shell::GetContainer(root_window,
228 internal::kShellWindowId_DefaultContainer); 158 internal::kShellWindowId_DefaultContainer);
229 for (size_t i = 0; i < default_container->children().size(); ++i) { 159 for (size_t i = 0; i < default_container->children().size(); ++i) {
230 aura::Window* workspace_window = default_container->children()[i]; 160 aura::Window* workspace_window = default_container->children()[i];
231 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer, 161 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer,
232 workspace_window->id()); 162 workspace_window->id());
233 workspace_window->AddObserver(this); 163 workspace_window->AddObserver(this);
234 } 164 }
235 } 165 }
236 166
167 void MruWindowTracker::IgnoreActivations(bool ignore) {
168 ignore_window_activations_ = ignore;
169
170 // If no longer ignoring window activations, move currently active window
171 // to front.
172 if (!ignore) {
173 aura::Window* active_window = wm::GetActiveWindow();
174 mru_windows_.remove(active_window);
175 mru_windows_.push_front(active_window);
176 }
177 }
178
237 ////////////////////////////////////////////////////////////////////////////// 179 //////////////////////////////////////////////////////////////////////////////
238 // WindowCycleController, private: 180 // MruWindowTracker, private:
239
240 void WindowCycleController::StartCycling() {
241 windows_.reset(new WindowCycleList(BuildWindowList(&mru_windows_, false)));
242 }
243
244 void WindowCycleController::Step(Direction direction) {
245 DCHECK(windows_.get());
246 windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD :
247 WindowCycleList::BACKWARD);
248 }
249
250 void WindowCycleController::StopCycling() {
251 windows_.reset();
252 // Remove our key event filter.
253 if (event_handler_) {
254 Shell::GetInstance()->RemovePreTargetHandler(event_handler_.get());
255 event_handler_.reset();
256 }
257
258 // Add the currently focused window to the MRU list
259 aura::Window* active_window = wm::GetActiveWindow();
260 mru_windows_.remove(active_window);
261 mru_windows_.push_front(active_window);
262 }
263 181
264 // static 182 // static
265 bool WindowCycleController::IsTrackedContainer(aura::Window* window) { 183 bool MruWindowTracker::IsTrackedContainer(aura::Window* window) {
266 if (!window) 184 if (!window)
267 return false; 185 return false;
268 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { 186 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
269 if (window->id() == kContainerIds[i]) { 187 if (window->id() == kContainerIds[i]) {
270 return true; 188 return true;
271 } 189 }
272 } 190 }
273 return window->id() == internal::kShellWindowId_WorkspaceContainer; 191 return window->id() == internal::kShellWindowId_WorkspaceContainer;
274 } 192 }
275 193
276 void WindowCycleController::InstallEventFilter() { 194 void MruWindowTracker::OnWindowActivated(aura::Window* gained_active,
277 event_handler_.reset(new WindowCycleEventFilter()); 195 aura::Window* lost_active) {
278 Shell::GetInstance()->AddPreTargetHandler(event_handler_.get()); 196 if (gained_active && !ignore_window_activations_ &&
279 }
280
281 void WindowCycleController::OnWindowActivated(aura::Window* gained_active,
282 aura::Window* lost_active) {
283 if (gained_active && !IsCycling() &&
284 IsTrackedContainer(gained_active->parent())) { 197 IsTrackedContainer(gained_active->parent())) {
285 mru_windows_.remove(gained_active); 198 mru_windows_.remove(gained_active);
286 mru_windows_.push_front(gained_active); 199 mru_windows_.push_front(gained_active);
287 } 200 }
288 } 201 }
289 202
290 void WindowCycleController::OnWindowAdded(aura::Window* window) { 203 void MruWindowTracker::OnWindowAdded(aura::Window* window) {
291 if (window->id() == internal::kShellWindowId_WorkspaceContainer) 204 if (window->id() == internal::kShellWindowId_WorkspaceContainer)
292 window->AddObserver(this); 205 window->AddObserver(this);
293 } 206 }
294 207
295 void WindowCycleController::OnWillRemoveWindow(aura::Window* window) { 208 void MruWindowTracker::OnWillRemoveWindow(aura::Window* window) {
296 mru_windows_.remove(window); 209 mru_windows_.remove(window);
297 if (window->id() == internal::kShellWindowId_WorkspaceContainer) 210 if (window->id() == internal::kShellWindowId_WorkspaceContainer)
298 window->RemoveObserver(this); 211 window->RemoveObserver(this);
299 } 212 }
300 213
301 void WindowCycleController::OnWindowDestroying(aura::Window* window) { 214 void MruWindowTracker::OnWindowDestroying(aura::Window* window) {
302 window->RemoveObserver(this); 215 window->RemoveObserver(this);
303 } 216 }
304 217
305 } // namespace ash 218 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698