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 cef209c92e27e64412c9b6c7c6c5a8a9745e465c..96511fbca8e47b4461452269e481ab7d16340fa9 100644 |
| --- a/components/mus/ws/focus_controller.cc |
| +++ b/components/mus/ws/focus_controller.cc |
| @@ -13,7 +13,7 @@ namespace mus { |
| namespace ws { |
| FocusController::FocusController(FocusControllerDelegate* delegate) |
| - : delegate_(delegate) {} |
| + : delegate_(delegate), focused_window_(nullptr), active_window_(nullptr) {} |
| FocusController::~FocusController() {} |
| @@ -25,7 +25,7 @@ void FocusController::SetFocusedWindow(ServerWindow* window) { |
| } |
| ServerWindow* FocusController::GetFocusedWindow() { |
| - return drawn_tracker_ ? drawn_tracker_->window() : nullptr; |
| + return focused_window_; |
| } |
| bool FocusController::CanBeFocused(ServerWindow* window) const { |
| @@ -38,41 +38,73 @@ bool FocusController::CanBeFocused(ServerWindow* window) const { |
| } |
| // |window| must be a descendent of an activatable window. |
| - for (ServerWindow* w = window; w; w = w->parent()) { |
| - if (CanBeActivated(w)) |
| - return true; |
| - } |
| - |
| - return false; |
| + return GetActivatableAncestorOf(window) != nullptr; |
| } |
| bool FocusController::CanBeActivated(ServerWindow* window) const { |
| + DCHECK(window); |
| + // The parent window must be allowed to have active children. |
| + if (!delegate_->CanHaveActiveChildren(window->parent())) |
| + return false; |
| + |
| // TODO(sad): Implement this. |
| return true; |
| } |
| +ServerWindow* FocusController::GetActivatableAncestorOf( |
| + ServerWindow* window) const { |
| + for (ServerWindow* w = window; w; w = w->parent()) { |
| + if (CanBeActivated(w)) |
| + return w; |
| + } |
| + return nullptr; |
| +} |
| + |
| void FocusController::SetFocusedWindowImpl(ServerWindow* window, |
| ChangeSource change_source) { |
| - if (window && !CanBeFocused(window)) |
| - return; |
| - ServerWindow* old = GetFocusedWindow(); |
| + if (window && !CanBeFocused(window)) { |
| + // Allow the old focused window to lose focus even if |window| cannot be |
| + // focused. |
|
Ben Goodger (Google)
2015/11/19 07:26:24
what's the reason for this policy?
sadrul
2015/11/19 19:33:34
Hm, I thought this is what we wanted to do. But I
Ben Goodger (Google)
2015/11/23 22:29:45
Yeah I was concerned you'd be left in a bad state
|
| + window = nullptr; |
| + } |
| + ServerWindow* old_focused = GetFocusedWindow(); |
| DCHECK(!window || window->IsDrawn()); |
| - // TODO(sad): Activate the closest activatable ancestor window. |
| - if (window) |
| - drawn_tracker_.reset(new ServerWindowDrawnTracker(window, this)); |
| - else |
| - drawn_tracker_.reset(); |
| + // 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). |
| + ServerWindow* old_active = active_window_; |
| + active_window_ = GetActivatableAncestorOf(window); |
| + if (old_active != active_window_) |
| + delegate_->OnActivationChanged(old_active, active_window_); |
| + focused_window_ = window; |
| if (change_source == CHANGE_SOURCE_DRAWN_STATE_CHANGED) |
| - delegate_->OnFocusChanged(old, window); |
| + delegate_->OnFocusChanged(old_focused, focused_window_); |
| + |
| + // We can currently use only a single ServerWindowDrawnTracker since focused |
| + // window is expected to be a direct descendant of the active window. |
| + if (focused_window_ && active_window_) { |
| + DCHECK(active_window_->Contains(focused_window_)); |
| + } |
| + ServerWindow* track_window = focused_window_; |
| + if (!track_window) |
| + track_window = active_window_; |
| + if (track_window) |
| + drawn_tracker_.reset(new ServerWindowDrawnTracker(track_window, this)); |
| + else |
| + drawn_tracker_.reset(); |
| } |
| void FocusController::OnDrawnStateChanged(ServerWindow* ancestor, |
| ServerWindow* window, |
| bool is_drawn) { |
| DCHECK(!is_drawn); // We only observe when drawn. |
| + // TODO(sad): If |window| is |focused_window_|, then move focus to the next |
| + // focusable window in |active_window_|, if |active_window_| is still visible. |
| + // If |active_window_| is invisible, or if |window| is |active_window_|, then |
| + // activate the next window that can be activated. |
| SetFocusedWindowImpl(ancestor, CHANGE_SOURCE_DRAWN_STATE_CHANGED); |
| } |