Chromium Code Reviews| 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(NULL,true)); |
|
sky
2013/07/29 15:31:05
nit: space after 'NULL,'
flackr
2013/07/29 22:49:11
NULL removed.
| |
| 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(false))); | |
| 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 |