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); |
} |