OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/window_cycle_controller.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/mru_window_tracker.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. | |
25 const int kContainerIds[] = { | |
26 internal::kShellWindowId_DefaultContainer, | |
27 internal::kShellWindowId_AlwaysOnTopContainer | |
28 }; | |
29 | |
30 // Filter to watch for the termination of a keyboard gesture to cycle through | 24 // Filter to watch for the termination of a keyboard gesture to cycle through |
31 // multiple windows. | 25 // multiple windows. |
32 class WindowCycleEventFilter : public ui::EventHandler { | 26 class WindowCycleEventFilter : public ui::EventHandler { |
33 public: | 27 public: |
34 WindowCycleEventFilter(); | 28 WindowCycleEventFilter(); |
35 virtual ~WindowCycleEventFilter(); | 29 virtual ~WindowCycleEventFilter(); |
36 | 30 |
37 // Overridden from ui::EventHandler: | 31 // Overridden from ui::EventHandler: |
38 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE; | 32 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE; |
39 private: | 33 private: |
40 DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter); | 34 DISALLOW_COPY_AND_ASSIGN(WindowCycleEventFilter); |
41 }; | 35 }; |
42 | 36 |
43 // Watch for all keyboard events by filtering the root window. | 37 // Watch for all keyboard events by filtering the root window. |
44 WindowCycleEventFilter::WindowCycleEventFilter() { | 38 WindowCycleEventFilter::WindowCycleEventFilter() { |
45 } | 39 } |
46 | 40 |
47 WindowCycleEventFilter::~WindowCycleEventFilter() { | 41 WindowCycleEventFilter::~WindowCycleEventFilter() { |
48 } | 42 } |
49 | 43 |
50 void WindowCycleEventFilter::OnKeyEvent(ui::KeyEvent* event) { | 44 void WindowCycleEventFilter::OnKeyEvent(ui::KeyEvent* event) { |
51 // Views uses VKEY_MENU for both left and right Alt keys. | 45 // Views uses VKEY_MENU for both left and right Alt keys. |
52 if (event->key_code() == ui::VKEY_MENU && | 46 if (event->key_code() == ui::VKEY_MENU && |
53 event->type() == ui::ET_KEY_RELEASED) { | 47 event->type() == ui::ET_KEY_RELEASED) { |
54 Shell::GetInstance()->window_cycle_controller()->AltKeyReleased(); | 48 Shell::GetInstance()->window_cycle_controller()->AltKeyReleased(); |
55 // Warning: |this| will be deleted from here on. | 49 // Warning: |this| will be deleted from here on. |
56 } | 50 } |
57 } | 51 } |
58 | 52 |
59 // Adds all the children of |window| to |windows|. | |
60 void AddAllChildren(aura::Window* window, | |
61 WindowCycleList::WindowList* windows) { | |
62 const WindowCycleList::WindowList& children(window->children()); | |
63 windows->insert(windows->end(), children.begin(), children.end()); | |
64 } | |
65 | |
66 // Adds all the children of all of |window|s children to |windows|. | |
67 void AddWorkspaceChildren(aura::Window* window, | |
68 WindowCycleList::WindowList* windows) { | |
69 for (size_t i = 0; i < window->children().size(); ++i) | |
70 AddAllChildren(window->children()[i], windows); | |
71 } | |
72 | |
73 // Adds the windows that can be cycled through for the specified window id to | |
74 // |windows|. | |
75 void AddCycleWindows(aura::RootWindow* root, | |
76 int container_id, | |
77 WindowCycleList::WindowList* windows) { | |
78 aura::Window* container = Shell::GetContainer(root, container_id); | |
79 if (container_id == internal::kShellWindowId_DefaultContainer) | |
80 AddWorkspaceChildren(container, windows); | |
81 else | |
82 AddAllChildren(container, windows); | |
83 } | |
84 | |
85 } // namespace | 53 } // namespace |
86 | 54 |
87 ////////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////////// |
88 // WindowCycleController, public: | 56 // WindowCycleController, public: |
89 | 57 |
90 WindowCycleController::WindowCycleController( | 58 WindowCycleController::WindowCycleController() { |
91 aura::client::ActivationClient* activation_client) | |
92 : activation_client_(activation_client) { | |
93 activation_client_->AddObserver(this); | |
94 } | 59 } |
95 | 60 |
96 WindowCycleController::~WindowCycleController() { | 61 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(); | 62 StopCycling(); |
119 } | 63 } |
120 | 64 |
121 // static | 65 // static |
122 bool WindowCycleController::CanCycle() { | 66 bool WindowCycleController::CanCycle() { |
123 // Don't allow window cycling if the screen is locked or a modal dialog is | 67 // Don't allow window cycling if the screen is locked or a modal dialog is |
124 // open. | 68 // open. |
125 return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() && | 69 return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() && |
126 !Shell::GetInstance()->IsSystemModalWindowOpen(); | 70 !Shell::GetInstance()->IsSystemModalWindowOpen(); |
127 } | 71 } |
(...skipping 21 matching lines...) Expand all Loading... |
149 StopCycling(); | 93 StopCycling(); |
150 } | 94 } |
151 } | 95 } |
152 | 96 |
153 void WindowCycleController::HandleLinearCycleWindow() { | 97 void WindowCycleController::HandleLinearCycleWindow() { |
154 if (!CanCycle() || IsCycling()) | 98 if (!CanCycle() || IsCycling()) |
155 return; | 99 return; |
156 | 100 |
157 // Use the reversed list of windows to prevent a 2-cycle of the most recent | 101 // Use the reversed list of windows to prevent a 2-cycle of the most recent |
158 // windows occurring. | 102 // windows occurring. |
159 WindowCycleList cycle_list(BuildWindowList(NULL,true)); | 103 WindowCycleList cycle_list(MruWindowTracker::BuildWindowList(true)); |
160 cycle_list.Step(WindowCycleList::FORWARD); | 104 cycle_list.Step(WindowCycleList::FORWARD); |
161 } | 105 } |
162 | 106 |
163 void WindowCycleController::AltKeyReleased() { | 107 void WindowCycleController::AltKeyReleased() { |
164 StopCycling(); | 108 StopCycling(); |
165 } | 109 } |
166 | 110 |
167 // static | |
168 std::vector<aura::Window*> WindowCycleController::BuildWindowList( | |
169 const std::list<aura::Window*>* mru_windows, | |
170 bool top_most_at_end) { | |
171 WindowCycleList::WindowList windows; | |
172 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); | |
173 | |
174 aura::RootWindow* active_root = Shell::GetActiveRootWindow(); | |
175 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); | |
176 iter != root_windows.end(); ++iter) { | |
177 if (*iter == active_root) | |
178 continue; | |
179 for (size_t i = 0; i < arraysize(kContainerIds); ++i) | |
180 AddCycleWindows(*iter, kContainerIds[i], &windows); | |
181 } | |
182 | |
183 // 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. | |
185 for (size_t i = 0; i < arraysize(kContainerIds); ++i) | |
186 AddCycleWindows(active_root, kContainerIds[i], &windows); | |
187 | |
188 // Removes unfocusable windows. | |
189 WindowCycleList::WindowList::iterator last = | |
190 std::remove_if( | |
191 windows.begin(), | |
192 windows.end(), | |
193 std::not1(std::ptr_fun(ash::wm::CanActivateWindow))); | |
194 windows.erase(last, windows.end()); | |
195 | |
196 // Put the windows in the mru_windows list at the head, if it's available. | |
197 if (mru_windows) { | |
198 // Iterate through the list backwards, so that we can move each window to | |
199 // the front of the windows list as we find them. | |
200 for (std::list<aura::Window*>::const_reverse_iterator ix = | |
201 mru_windows->rbegin(); | |
202 ix != mru_windows->rend(); ++ix) { | |
203 WindowCycleList::WindowList::iterator window = | |
204 std::find(windows.begin(), windows.end(), *ix); | |
205 if (window != windows.end()) { | |
206 windows.erase(window); | |
207 windows.push_back(*ix); | |
208 } | |
209 } | |
210 } | |
211 | |
212 // Window cycling expects the topmost window at the front of the list. | |
213 if (!top_most_at_end) | |
214 std::reverse(windows.begin(), windows.end()); | |
215 | |
216 return windows; | |
217 } | |
218 | |
219 void WindowCycleController::OnRootWindowAdded(aura::RootWindow* root_window) { | |
220 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
221 aura::Window* container = | |
222 Shell::GetContainer(root_window, kContainerIds[i]); | |
223 container->AddObserver(this); | |
224 } | |
225 | |
226 aura::Window* default_container = | |
227 Shell::GetContainer(root_window, | |
228 internal::kShellWindowId_DefaultContainer); | |
229 for (size_t i = 0; i < default_container->children().size(); ++i) { | |
230 aura::Window* workspace_window = default_container->children()[i]; | |
231 DCHECK_EQ(internal::kShellWindowId_WorkspaceContainer, | |
232 workspace_window->id()); | |
233 workspace_window->AddObserver(this); | |
234 } | |
235 } | |
236 | |
237 ////////////////////////////////////////////////////////////////////////////// | 111 ////////////////////////////////////////////////////////////////////////////// |
238 // WindowCycleController, private: | 112 // WindowCycleController, private: |
239 | 113 |
240 void WindowCycleController::StartCycling() { | 114 void WindowCycleController::StartCycling() { |
241 windows_.reset(new WindowCycleList(BuildWindowList(&mru_windows_, false))); | 115 windows_.reset(new WindowCycleList(ash::Shell::GetInstance()-> |
| 116 mru_window_tracker()->BuildMruWindowList())); |
242 } | 117 } |
243 | 118 |
244 void WindowCycleController::Step(Direction direction) { | 119 void WindowCycleController::Step(Direction direction) { |
245 DCHECK(windows_.get()); | 120 DCHECK(windows_.get()); |
246 windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD : | 121 windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD : |
247 WindowCycleList::BACKWARD); | 122 WindowCycleList::BACKWARD); |
248 } | 123 } |
249 | 124 |
250 void WindowCycleController::StopCycling() { | 125 void WindowCycleController::StopCycling() { |
251 windows_.reset(); | 126 windows_.reset(); |
252 // Remove our key event filter. | 127 // Remove our key event filter. |
253 if (event_handler_) { | 128 if (event_handler_) { |
254 Shell::GetInstance()->RemovePreTargetHandler(event_handler_.get()); | 129 Shell::GetInstance()->RemovePreTargetHandler(event_handler_.get()); |
255 event_handler_.reset(); | 130 event_handler_.reset(); |
256 } | 131 } |
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 | |
264 // static | |
265 bool WindowCycleController::IsTrackedContainer(aura::Window* window) { | |
266 if (!window) | |
267 return false; | |
268 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
269 if (window->id() == kContainerIds[i]) { | |
270 return true; | |
271 } | |
272 } | |
273 return window->id() == internal::kShellWindowId_WorkspaceContainer; | |
274 } | 132 } |
275 | 133 |
276 void WindowCycleController::InstallEventFilter() { | 134 void WindowCycleController::InstallEventFilter() { |
277 event_handler_.reset(new WindowCycleEventFilter()); | 135 event_handler_.reset(new WindowCycleEventFilter()); |
278 Shell::GetInstance()->AddPreTargetHandler(event_handler_.get()); | 136 Shell::GetInstance()->AddPreTargetHandler(event_handler_.get()); |
279 } | 137 } |
280 | 138 |
281 void WindowCycleController::OnWindowActivated(aura::Window* gained_active, | |
282 aura::Window* lost_active) { | |
283 if (gained_active && !IsCycling() && | |
284 IsTrackedContainer(gained_active->parent())) { | |
285 mru_windows_.remove(gained_active); | |
286 mru_windows_.push_front(gained_active); | |
287 } | |
288 } | |
289 | |
290 void WindowCycleController::OnWindowAdded(aura::Window* window) { | |
291 if (window->id() == internal::kShellWindowId_WorkspaceContainer) | |
292 window->AddObserver(this); | |
293 } | |
294 | |
295 void WindowCycleController::OnWillRemoveWindow(aura::Window* window) { | |
296 mru_windows_.remove(window); | |
297 if (window->id() == internal::kShellWindowId_WorkspaceContainer) | |
298 window->RemoveObserver(this); | |
299 } | |
300 | |
301 void WindowCycleController::OnWindowDestroying(aura::Window* window) { | |
302 window->RemoveObserver(this); | |
303 } | |
304 | |
305 } // namespace ash | 139 } // namespace ash |
OLD | NEW |