| OLD | NEW |
| 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 |
| OLD | NEW |