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

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: Address comments. Created 7 years, 4 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
« no previous file with comments | « ash/wm/mru_window_tracker.h ('k') | ash/wm/window_cycle_controller.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Returns a list of windows ordered by their stacking order.
86 57 // If |mru_windows| is passed, these windows are moved to the front of the list.
87 ////////////////////////////////////////////////////////////////////////////// 58 // If |top_most_at_end|, the list is returned in descending (bottom-most / least
88 // WindowCycleController, public: 59 // recently used) order.
89 60 MruWindowTracker::WindowList BuildWindowListInternal(
90 WindowCycleController::WindowCycleController(
91 aura::client::ActivationClient* activation_client)
92 : activation_client_(activation_client) {
93 activation_client_->AddObserver(this);
94 }
95
96 WindowCycleController::~WindowCycleController() {
97 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
98 for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
99 iter != root_windows.end(); ++iter) {
100 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
101 aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]);
102 if (container)
103 container->RemoveObserver(this);
104 }
105 aura::Window* default_container =
106 Shell::GetContainer(*iter, internal::kShellWindowId_DefaultContainer);
107 if (default_container) {
108 for (size_t i = 0; i < default_container->children().size(); ++i) {
109 aura::Window* workspace_window = default_container->children()[i];
110 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer,
111 workspace_window->id());
112 workspace_window->RemoveObserver(this);
113 }
114 }
115 }
116
117 activation_client_->RemoveObserver(this);
118 StopCycling();
119 }
120
121 // static
122 bool WindowCycleController::CanCycle() {
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, 61 const std::list<aura::Window*>* mru_windows,
170 bool top_most_at_end) { 62 bool top_most_at_end) {
171 WindowCycleList::WindowList windows; 63 MruWindowTracker::WindowList windows;
172 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 64 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
173 65
174 aura::RootWindow* active_root = Shell::GetActiveRootWindow(); 66 aura::RootWindow* active_root = Shell::GetActiveRootWindow();
175 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); 67 for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
176 iter != root_windows.end(); ++iter) { 68 iter != root_windows.end(); ++iter) {
177 if (*iter == active_root) 69 if (*iter == active_root)
178 continue; 70 continue;
179 for (size_t i = 0; i < arraysize(kContainerIds); ++i) 71 for (size_t i = 0; i < arraysize(kContainerIds); ++i)
180 AddCycleWindows(*iter, kContainerIds[i], &windows); 72 AddTrackedWindows(*iter, kContainerIds[i], &windows);
181 } 73 }
182 74
183 // Add windows in the active root windows last so that the topmost window 75 // 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. 76 // in the active root window becomes the front of the list.
185 for (size_t i = 0; i < arraysize(kContainerIds); ++i) 77 for (size_t i = 0; i < arraysize(kContainerIds); ++i)
186 AddCycleWindows(active_root, kContainerIds[i], &windows); 78 AddTrackedWindows(active_root, kContainerIds[i], &windows);
187 79
188 // Removes unfocusable windows. 80 // Removes unfocusable windows.
189 WindowCycleList::WindowList::iterator last = 81 MruWindowTracker::WindowList::iterator last =
190 std::remove_if( 82 std::remove_if(
191 windows.begin(), 83 windows.begin(),
192 windows.end(), 84 windows.end(),
193 std::not1(std::ptr_fun(ash::wm::CanActivateWindow))); 85 std::not1(std::ptr_fun(ash::wm::CanActivateWindow)));
194 windows.erase(last, windows.end()); 86 windows.erase(last, windows.end());
195 87
196 // Put the windows in the mru_windows list at the head, if it's available. 88 // Put the windows in the mru_windows list at the head, if it's available.
197 if (mru_windows) { 89 if (mru_windows) {
198 // Iterate through the list backwards, so that we can move each window to 90 // Iterate through the list backwards, so that we can move each window to
199 // the front of the windows list as we find them. 91 // the front of the windows list as we find them.
200 for (std::list<aura::Window*>::const_reverse_iterator ix = 92 for (std::list<aura::Window*>::const_reverse_iterator ix =
201 mru_windows->rbegin(); 93 mru_windows->rbegin();
202 ix != mru_windows->rend(); ++ix) { 94 ix != mru_windows->rend(); ++ix) {
203 WindowCycleList::WindowList::iterator window = 95 MruWindowTracker::WindowList::iterator window =
204 std::find(windows.begin(), windows.end(), *ix); 96 std::find(windows.begin(), windows.end(), *ix);
205 if (window != windows.end()) { 97 if (window != windows.end()) {
206 windows.erase(window); 98 windows.erase(window);
207 windows.push_back(*ix); 99 windows.push_back(*ix);
208 } 100 }
209 } 101 }
210 } 102 }
211 103
212 // Window cycling expects the topmost window at the front of the list. 104 // Window cycling expects the topmost window at the front of the list.
213 if (!top_most_at_end) 105 if (!top_most_at_end)
214 std::reverse(windows.begin(), windows.end()); 106 std::reverse(windows.begin(), windows.end());
215 107
216 return windows; 108 return windows;
217 } 109 }
218 110
219 void WindowCycleController::OnRootWindowAdded(aura::RootWindow* root_window) { 111 } // namespace
112
113 //////////////////////////////////////////////////////////////////////////////
114 // MruWindowTracker, public:
115
116 MruWindowTracker::MruWindowTracker(
117 aura::client::ActivationClient* activation_client)
118 : activation_client_(activation_client),
119 ignore_window_activations_(false) {
120 activation_client_->AddObserver(this);
121 }
122
123 MruWindowTracker::~MruWindowTracker() {
124 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
125 for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
126 iter != root_windows.end(); ++iter) {
127 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
128 aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]);
129 if (container)
130 container->RemoveObserver(this);
131 }
132 aura::Window* default_container =
133 Shell::GetContainer(*iter, internal::kShellWindowId_DefaultContainer);
134 if (default_container) {
135 for (size_t i = 0; i < default_container->children().size(); ++i) {
136 aura::Window* workspace_window = default_container->children()[i];
137 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer,
138 workspace_window->id());
139 workspace_window->RemoveObserver(this);
140 }
141 }
142 }
143
144 activation_client_->RemoveObserver(this);
145 }
146
147 // static
148 MruWindowTracker::WindowList MruWindowTracker::BuildWindowList(
149 bool top_most_at_end) {
150 return BuildWindowListInternal(NULL, top_most_at_end);
151 }
152
153 MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() {
154 return BuildWindowListInternal(&mru_windows_, false);
155 }
156
157 void MruWindowTracker::OnRootWindowAdded(aura::RootWindow* root_window) {
220 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { 158 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
221 aura::Window* container = 159 aura::Window* container =
222 Shell::GetContainer(root_window, kContainerIds[i]); 160 Shell::GetContainer(root_window, kContainerIds[i]);
223 container->AddObserver(this); 161 container->AddObserver(this);
224 } 162 }
225 163
226 aura::Window* default_container = 164 aura::Window* default_container =
227 Shell::GetContainer(root_window, 165 Shell::GetContainer(root_window,
228 internal::kShellWindowId_DefaultContainer); 166 internal::kShellWindowId_DefaultContainer);
229 for (size_t i = 0; i < default_container->children().size(); ++i) { 167 for (size_t i = 0; i < default_container->children().size(); ++i) {
230 aura::Window* workspace_window = default_container->children()[i]; 168 aura::Window* workspace_window = default_container->children()[i];
231 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer, 169 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer,
232 workspace_window->id()); 170 workspace_window->id());
233 workspace_window->AddObserver(this); 171 workspace_window->AddObserver(this);
234 } 172 }
235 } 173 }
236 174
175 void MruWindowTracker::SetIgnoreActivations(bool ignore) {
176 ignore_window_activations_ = ignore;
177
178 // If no longer ignoring window activations, move currently active window
179 // to front.
180 if (!ignore) {
181 aura::Window* active_window = wm::GetActiveWindow();
182 mru_windows_.remove(active_window);
183 mru_windows_.push_front(active_window);
184 }
185 }
186
237 ////////////////////////////////////////////////////////////////////////////// 187 //////////////////////////////////////////////////////////////////////////////
238 // WindowCycleController, private: 188 // 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 189
264 // static 190 // static
265 bool WindowCycleController::IsTrackedContainer(aura::Window* window) { 191 bool MruWindowTracker::IsTrackedContainer(aura::Window* window) {
266 if (!window) 192 if (!window)
267 return false; 193 return false;
268 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { 194 for (size_t i = 0; i < arraysize(kContainerIds); ++i) {
269 if (window->id() == kContainerIds[i]) { 195 if (window->id() == kContainerIds[i]) {
270 return true; 196 return true;
271 } 197 }
272 } 198 }
273 return window->id() == internal::kShellWindowId_WorkspaceContainer; 199 return window->id() == internal::kShellWindowId_WorkspaceContainer;
274 } 200 }
275 201
276 void WindowCycleController::InstallEventFilter() { 202 void MruWindowTracker::OnWindowActivated(aura::Window* gained_active,
277 event_handler_.reset(new WindowCycleEventFilter()); 203 aura::Window* lost_active) {
278 Shell::GetInstance()->AddPreTargetHandler(event_handler_.get()); 204 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())) { 205 IsTrackedContainer(gained_active->parent())) {
285 mru_windows_.remove(gained_active); 206 mru_windows_.remove(gained_active);
286 mru_windows_.push_front(gained_active); 207 mru_windows_.push_front(gained_active);
287 } 208 }
288 } 209 }
289 210
290 void WindowCycleController::OnWindowAdded(aura::Window* window) { 211 void MruWindowTracker::OnWindowAdded(aura::Window* window) {
291 if (window->id() == internal::kShellWindowId_WorkspaceContainer) 212 if (window->id() == internal::kShellWindowId_WorkspaceContainer)
292 window->AddObserver(this); 213 window->AddObserver(this);
293 } 214 }
294 215
295 void WindowCycleController::OnWillRemoveWindow(aura::Window* window) { 216 void MruWindowTracker::OnWillRemoveWindow(aura::Window* window) {
296 mru_windows_.remove(window); 217 mru_windows_.remove(window);
297 if (window->id() == internal::kShellWindowId_WorkspaceContainer) 218 if (window->id() == internal::kShellWindowId_WorkspaceContainer)
298 window->RemoveObserver(this); 219 window->RemoveObserver(this);
299 } 220 }
300 221
301 void WindowCycleController::OnWindowDestroying(aura::Window* window) { 222 void MruWindowTracker::OnWindowDestroying(aura::Window* window) {
302 window->RemoveObserver(this); 223 window->RemoveObserver(this);
303 } 224 }
304 225
305 } // namespace ash 226 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/mru_window_tracker.h ('k') | ash/wm/window_cycle_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698