Chromium Code Reviews| Index: components/mus/ws/focus_controller.cc |
| diff --git a/components/mus/ws/focus_controller.cc b/components/mus/ws/focus_controller.cc |
| index 5cf98446e9a526548a9dd4164bbcb01010906942..c7cf231eabcad15156e4929bf7c48c63137a0a0a 100644 |
| --- a/components/mus/ws/focus_controller.cc |
| +++ b/components/mus/ws/focus_controller.cc |
| @@ -18,7 +18,7 @@ namespace { |
| ServerWindow* GetDeepestFirstDescendant(ServerWindow* window) { |
|
sky
2016/01/05 16:42:38
Update function name to reflect new meaning.
|
| while (!window->children().empty()) |
| - window = window->children()[0]; |
| + window = window->children().back(); |
| return window; |
| } |
| @@ -37,11 +37,11 @@ class WindowTreeIterator { |
| ServerWindow* parent = window->parent(); |
| if (parent) { |
| const ServerWindow::Windows& siblings = parent->children(); |
| - ServerWindow::Windows::const_iterator iter = |
| - std::find(siblings.begin(), siblings.end(), window); |
| - DCHECK(iter != siblings.end()); |
| + ServerWindow::Windows::const_reverse_iterator iter = |
| + std::find(siblings.rbegin(), siblings.rend(), window); |
| + DCHECK(iter != siblings.rend()); |
| ++iter; |
| - if (iter != siblings.end()) |
| + if (iter != siblings.rend()) |
| return GetDeepestFirstDescendant(*iter); |
| } |
| @@ -62,7 +62,8 @@ FocusController::FocusController(FocusControllerDelegate* delegate, |
| : delegate_(delegate), |
| root_(root), |
| focused_window_(nullptr), |
| - active_window_(nullptr) { |
| + active_window_(nullptr), |
| + activation_reason_(ActivationChangeReason::UNKNONW) { |
| DCHECK(delegate_); |
| DCHECK(root_); |
| } |
| @@ -83,10 +84,27 @@ ServerWindow* FocusController::GetFocusedWindow() { |
| void FocusController::ActivateNextWindow() { |
| WindowTreeIterator iter(root_); |
| ServerWindow* activate = active_window_; |
| - do { |
| + while (true) { |
| activate = iter.GetNext(activate); |
| - } while (activate != active_window_ && !CanBeActivated(activate)); |
| - SetActiveWindow(activate); |
| + if (activation_reason_ == ActivationChangeReason::CYCLE) { |
| + if (activate == active_window_) { |
| + // We have cycled over all the activatable windows. Remove the oldest |
| + // window that was cycled. |
| + if (!cycle_windows_.empty()) { |
| + cycle_windows_.erase(cycle_windows_.begin()); |
| + continue; |
| + } |
| + } else if (std::find(cycle_windows_.begin(), cycle_windows_.end(), |
| + activate->id()) != cycle_windows_.end()) { |
| + // We are cycling between activated windows, and this window has already |
| + // been through the cycle. So skip over it. |
| + continue; |
| + } |
| + } |
| + if (activate == active_window_ || CanBeActivated(activate)) |
| + break; |
| + } |
| + SetActiveWindow(activate, ActivationChangeReason::CYCLE); |
| if (active_window_) { |
| // Do not shift focus if the focused window already lives in the active |
| @@ -113,16 +131,26 @@ void FocusController::RemoveObserver(FocusControllerObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| -void FocusController::SetActiveWindow(ServerWindow* window) { |
| +void FocusController::SetActiveWindow(ServerWindow* window, |
| + ActivationChangeReason reason) { |
| DCHECK(!window || CanBeActivated(window)); |
| if (active_window_ == window) |
| return; |
| + if (reason != ActivationChangeReason::CYCLE) { |
| + cycle_windows_.clear(); |
| + } else if (activation_reason_ != ActivationChangeReason::CYCLE) { |
| + DCHECK(cycle_windows_.empty()); |
| + if (active_window_) |
| + cycle_windows_.push_back(active_window_->id()); |
| + } |
| + |
| ServerWindow* old_active = active_window_; |
| active_window_ = window; |
| - if (old_active != active_window_) { |
| - FOR_EACH_OBSERVER(FocusControllerObserver, observers_, |
| - OnActivationChanged(old_active, active_window_)); |
| - } |
| + activation_reason_ = reason; |
| + FOR_EACH_OBSERVER(FocusControllerObserver, observers_, |
| + OnActivationChanged(old_active, active_window_)); |
| + if (active_window_ && activation_reason_ == ActivationChangeReason::CYCLE) |
| + cycle_windows_.push_back(active_window_->id()); |
| } |
| bool FocusController::CanBeFocused(ServerWindow* window) const { |
| @@ -187,7 +215,8 @@ void FocusController::SetFocusedWindowImpl( |
| // Activate the closest activatable ancestor window. |
| // TODO(sad): The window to activate doesn't necessarily have to be a direct |
| // ancestor (e.g. could be a transient parent). |
| - SetActiveWindow(GetActivatableAncestorOf(window)); |
| + SetActiveWindow(GetActivatableAncestorOf(window), |
| + ActivationChangeReason::FOCUS); |
| FOR_EACH_OBSERVER(FocusControllerObserver, observers_, |
| OnFocusChanged(change_source, old_focused, window)); |
| @@ -229,7 +258,7 @@ void FocusController::OnDrawnStateWillChange(ServerWindow* ancestor, |
| (will_be_hidden(activate) || !CanBeActivated(activate))); |
| if (activate == window) |
| activate = nullptr; |
| - SetActiveWindow(activate); |
| + SetActiveWindow(activate, ActivationChangeReason::DRAWN_STATE_CHANGED); |
| // Now make sure focus is in the active window. |
| ServerWindow* focus = nullptr; |