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/shell.h" | 9 #include "ash/shell.h" |
10 #include "ash/shell_delegate.h" | 10 #include "ash/shell_delegate.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/window_cycle_list.h" | 13 #include "ash/wm/window_cycle_list.h" |
13 #include "ash/wm/window_util.h" | 14 #include "ash/wm/window_util.h" |
14 #include "ui/aura/event.h" | 15 #include "ui/aura/event.h" |
15 #include "ui/aura/event_filter.h" | 16 #include "ui/aura/event_filter.h" |
16 #include "ui/aura/root_window.h" | 17 #include "ui/aura/root_window.h" |
17 | 18 |
18 namespace ash { | 19 namespace ash { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
23 // List of containers whose children we will cycle through. | |
24 const int kContainerIds[] = { | |
25 internal::kShellWindowId_DefaultContainer, | |
26 internal::kShellWindowId_AlwaysOnTopContainer | |
27 }; | |
28 | |
22 // Filter to watch for the termination of a keyboard gesture to cycle through | 29 // Filter to watch for the termination of a keyboard gesture to cycle through |
23 // multiple windows. | 30 // multiple windows. |
24 class WindowCycleEventFilter : public aura::EventFilter { | 31 class WindowCycleEventFilter : public aura::EventFilter { |
25 public: | 32 public: |
26 WindowCycleEventFilter(); | 33 WindowCycleEventFilter(); |
27 virtual ~WindowCycleEventFilter(); | 34 virtual ~WindowCycleEventFilter(); |
28 | 35 |
29 // Overridden from aura::EventFilter: | 36 // Overridden from aura::EventFilter: |
30 virtual bool PreHandleKeyEvent(aura::Window* target, | 37 virtual bool PreHandleKeyEvent(aura::Window* target, |
31 aura::KeyEvent* event) OVERRIDE; | 38 aura::KeyEvent* event) OVERRIDE; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 aura::Window* target, | 82 aura::Window* target, |
76 aura::GestureEvent* event) { | 83 aura::GestureEvent* event) { |
77 return ui::GESTURE_STATUS_UNKNOWN; // Not handled. | 84 return ui::GESTURE_STATUS_UNKNOWN; // Not handled. |
78 } | 85 } |
79 | 86 |
80 } // namespace | 87 } // namespace |
81 | 88 |
82 ////////////////////////////////////////////////////////////////////////////// | 89 ////////////////////////////////////////////////////////////////////////////// |
83 // WindowCycleController, public: | 90 // WindowCycleController, public: |
84 | 91 |
85 WindowCycleController::WindowCycleController() { | 92 WindowCycleController::WindowCycleController() : mru_ignore_(false) { |
93 Shell::GetInstance()->activation_controller()->AddObserver(this); | |
86 } | 94 } |
87 | 95 |
88 WindowCycleController::~WindowCycleController() { | 96 WindowCycleController::~WindowCycleController() { |
97 Shell::GetInstance()->activation_controller()->RemoveObserver(this); | |
89 StopCycling(); | 98 StopCycling(); |
sky
2012/07/24 03:53:31
Doesn't this need to remove observers from all the
Zachary Kuznia
2012/07/30 07:49:48
No. The containers get the OnWindowDestroying not
| |
90 } | 99 } |
91 | 100 |
92 // static | 101 // static |
93 bool WindowCycleController::CanCycle() { | 102 bool WindowCycleController::CanCycle() { |
94 // Don't allow window cycling if the screen is locked or a modal dialog is | 103 // Don't allow window cycling if the screen is locked or a modal dialog is |
95 // open. | 104 // open. |
96 return !Shell::GetInstance()->IsScreenLocked() && | 105 return !Shell::GetInstance()->IsScreenLocked() && |
97 !Shell::GetInstance()->IsModalWindowOpen(); | 106 !Shell::GetInstance()->IsModalWindowOpen(); |
98 } | 107 } |
99 | 108 |
100 void WindowCycleController::HandleCycleWindow(Direction direction, | 109 void WindowCycleController::HandleCycleWindow(Direction direction, |
101 bool is_alt_down) { | 110 bool is_alt_down) { |
102 if (!CanCycle()) | 111 if (!CanCycle()) |
103 return; | 112 return; |
104 | 113 |
105 if (is_alt_down) { | 114 if (is_alt_down) { |
106 if (!IsCycling()) { | 115 if (!IsCycling()) { |
116 mru_ignore_ = true; | |
107 // This is the start of an alt-tab cycle through multiple windows, so | 117 // This is the start of an alt-tab cycle through multiple windows, so |
108 // listen for the alt key being released to stop cycling. | 118 // listen for the alt key being released to stop cycling. |
109 StartCycling(); | 119 StartCycling(); |
sky
2012/07/24 03:53:31
Wouldn't it make more sense to set mru_ignore_ in
Zachary Kuznia
2012/07/30 07:49:48
Done.
| |
110 Step(direction); | 120 Step(direction); |
111 InstallEventFilter(); | 121 InstallEventFilter(); |
112 } else { | 122 } else { |
113 // We're in the middle of an alt-tab cycle, just step forward. | 123 // We're in the middle of an alt-tab cycle, just step forward. |
114 Step(direction); | 124 Step(direction); |
115 } | 125 } |
116 } else { | 126 } else { |
117 // This is a simple, single-step window cycle. | 127 // This is a simple, single-step window cycle. |
118 StartCycling(); | 128 StartCycling(); |
119 Step(direction); | 129 Step(direction); |
120 StopCycling(); | 130 StopCycling(); |
121 } | 131 } |
122 } | 132 } |
123 | 133 |
124 void WindowCycleController::AltKeyReleased() { | 134 void WindowCycleController::AltKeyReleased() { |
125 StopCycling(); | 135 StopCycling(); |
136 | |
137 // Add the currently focused window to the MRU list, and stop ignoring | |
138 // activations. | |
139 mru_ignore_ = false; | |
140 aura::Window* active_window = wm::GetActiveWindow(); | |
141 mru_windows_.remove(active_window); | |
142 mru_windows_.push_front(active_window); | |
126 } | 143 } |
127 | 144 |
128 // static | 145 // static |
129 std::vector<aura::Window*> WindowCycleController::BuildWindowList() { | 146 std::vector<aura::Window*> WindowCycleController::BuildWindowList( |
147 std::list<aura::Window*>* mru_windows) { | |
sky
2012/07/24 03:53:31
const std::list&
Zachary Kuznia
2012/07/30 07:49:48
Changed to const. It needs to be a pointer, thoug
| |
148 | |
sky
2012/07/24 03:53:31
remove newline
Zachary Kuznia
2012/07/30 07:49:48
Done.
| |
130 WindowCycleList::WindowList windows; | 149 WindowCycleList::WindowList windows; |
131 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); | 150 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
132 | 151 |
133 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); | 152 for (Shell::RootWindowList::const_iterator iter = root_windows.begin(); |
134 iter != root_windows.end(); ++iter) { | 153 iter != root_windows.end(); ++iter) { |
135 if (*iter == Shell::GetActiveRootWindow()) | 154 if (*iter == Shell::GetActiveRootWindow()) |
136 continue; | 155 continue; |
137 aura::Window* default_container = Shell::GetContainer( | 156 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { |
138 *iter, internal::kShellWindowId_DefaultContainer); | 157 aura::Window* container = Shell::GetContainer(*iter, kContainerIds[i]); |
139 WindowCycleList::WindowList children = default_container->children(); | 158 WindowCycleList::WindowList children = container->children(); |
159 windows.insert(windows.end(), children.begin(), children.end()); | |
160 } | |
161 } | |
162 | |
163 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
164 aura::Window* container = | |
165 Shell::GetContainer(Shell::GetActiveRootWindow(), kContainerIds[i]); | |
166 | |
167 WindowCycleList::WindowList children = container->children(); | |
140 windows.insert(windows.end(), children.begin(), children.end()); | 168 windows.insert(windows.end(), children.begin(), children.end()); |
141 } | 169 } |
142 // Add windows in the active root windows last so that the topmost window | |
143 // in the active root window becomes the front of the list. | |
144 aura::Window* default_container = Shell::GetContainer( | |
145 Shell::GetActiveRootWindow(), | |
146 internal::kShellWindowId_DefaultContainer); | |
147 | |
148 WindowCycleList::WindowList children = default_container->children(); | |
149 windows.insert(windows.end(), children.begin(), children.end()); | |
150 | 170 |
151 // Removes unfocusable windows. | 171 // Removes unfocusable windows. |
152 WindowCycleList::WindowList::iterator last = | 172 WindowCycleList::WindowList::iterator last = |
153 std::remove_if( | 173 std::remove_if( |
154 windows.begin(), | 174 windows.begin(), |
155 windows.end(), | 175 windows.end(), |
156 std::not1(std::ptr_fun(ash::wm::CanActivateWindow))); | 176 std::not1(std::ptr_fun(ash::wm::CanActivateWindow))); |
157 windows.erase(last, windows.end()); | 177 windows.erase(last, windows.end()); |
178 | |
179 // Put the windows in the mru_windows list at the head, if it's available. | |
sky
2012/07/24 03:53:31
Document why this uses a reverse iterator.
Zachary Kuznia
2012/07/30 07:49:48
Done.
| |
180 if (mru_windows) { | |
181 for (std::list<aura::Window*>::const_reverse_iterator ix = | |
182 mru_windows->rbegin(); | |
183 ix != mru_windows->rend(); ++ix) { | |
184 WindowCycleList::WindowList::iterator window = | |
185 std::find(windows.begin(), windows.end(), *ix); | |
186 if (window != windows.end()) { | |
187 windows.erase(window); | |
188 windows.push_back(*ix); | |
189 } | |
190 } | |
191 } | |
192 | |
158 // Window cycling expects the topmost window at the front of the list. | 193 // Window cycling expects the topmost window at the front of the list. |
159 std::reverse(windows.begin(), windows.end()); | 194 std::reverse(windows.begin(), windows.end()); |
195 | |
160 return windows; | 196 return windows; |
161 } | 197 } |
162 | 198 |
199 void WindowCycleController::OnRootWindowAdded(aura::RootWindow* root_window) { | |
200 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
201 aura::Window* container = | |
202 Shell::GetContainer(root_window, kContainerIds[i]); | |
203 container->AddObserver(this); | |
204 } | |
205 } | |
206 | |
163 ////////////////////////////////////////////////////////////////////////////// | 207 ////////////////////////////////////////////////////////////////////////////// |
164 // WindowCycleController, private: | 208 // WindowCycleController, private: |
165 | 209 |
166 void WindowCycleController::StartCycling() { | 210 void WindowCycleController::StartCycling() { |
167 windows_.reset(new WindowCycleList(BuildWindowList())); | 211 windows_.reset(new WindowCycleList(BuildWindowList(&mru_windows_))); |
168 } | 212 } |
169 | 213 |
170 void WindowCycleController::Step(Direction direction) { | 214 void WindowCycleController::Step(Direction direction) { |
171 DCHECK(windows_.get()); | 215 DCHECK(windows_.get()); |
172 windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD : | 216 windows_->Step(direction == FORWARD ? WindowCycleList::FORWARD : |
173 WindowCycleList::BACKWARD); | 217 WindowCycleList::BACKWARD); |
174 } | 218 } |
175 | 219 |
176 void WindowCycleController::StopCycling() { | 220 void WindowCycleController::StopCycling() { |
177 windows_.reset(); | 221 windows_.reset(); |
178 // Remove our key event filter. | 222 // Remove our key event filter. |
179 if (event_filter_.get()) { | 223 if (event_filter_.get()) { |
180 Shell::GetInstance()->RemoveEnvEventFilter(event_filter_.get()); | 224 Shell::GetInstance()->RemoveEnvEventFilter(event_filter_.get()); |
181 event_filter_.reset(); | 225 event_filter_.reset(); |
182 } | 226 } |
183 } | 227 } |
184 | 228 |
185 void WindowCycleController::InstallEventFilter() { | 229 void WindowCycleController::InstallEventFilter() { |
186 event_filter_.reset(new WindowCycleEventFilter()); | 230 event_filter_.reset(new WindowCycleEventFilter()); |
187 Shell::GetInstance()->AddEnvEventFilter(event_filter_.get()); | 231 Shell::GetInstance()->AddEnvEventFilter(event_filter_.get()); |
188 } | 232 } |
189 | 233 |
234 void WindowCycleController::OnWindowActivated(aura::Window* active, | |
235 aura::Window* old_active) { | |
236 if (active) { | |
237 if (!active->parent()) | |
sky
2012/07/24 03:53:31
This code would be easier to read if you made a fu
Zachary Kuznia
2012/07/30 07:49:48
Done.
| |
238 return; | |
239 | |
240 bool ignore = true; | |
241 for (size_t i = 0; i < arraysize(kContainerIds); ++i) { | |
242 if (active->parent()->id() == kContainerIds[i]) { | |
243 ignore = false; | |
244 break; | |
245 } | |
246 } | |
247 if (ignore) | |
248 return; | |
249 | |
250 if (!mru_ignore_) { | |
sky
2012/07/24 03:53:31
Move this check early on.
Zachary Kuznia
2012/07/30 07:49:48
Done.
| |
251 mru_windows_.remove(active); | |
252 mru_windows_.push_front(active); | |
253 } | |
254 } | |
255 } | |
256 | |
257 void WindowCycleController::OnWillRemoveWindow(aura::Window* window) { | |
258 mru_windows_.remove(window); | |
259 } | |
260 | |
261 void WindowCycleController::OnWindowDestroying(aura::Window* window) { | |
262 window->RemoveObserver(this); | |
263 } | |
264 | |
190 } // namespace ash | 265 } // namespace ash |
OLD | NEW |