Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1104)

Unified Diff: services/window_manager/basic_focus_rules.cc

Issue 747163002: Port more focus controller unit tests and fix our focus rules. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Remove O(n) solution with O(1). Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « services/window_manager/basic_focus_rules.h ('k') | services/window_manager/focus_controller_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: services/window_manager/basic_focus_rules.cc
diff --git a/services/window_manager/basic_focus_rules.cc b/services/window_manager/basic_focus_rules.cc
index d3b1e0b2b54a9f12fa0736e9f1639eec69b992d5..b5dd91a4e35af598a0ec3c366e026fed5f4c591f 100644
--- a/services/window_manager/basic_focus_rules.cc
+++ b/services/window_manager/basic_focus_rules.cc
@@ -15,48 +15,156 @@ BasicFocusRules::BasicFocusRules(mojo::View* window_container)
BasicFocusRules::~BasicFocusRules() {}
+bool BasicFocusRules::SupportsChildActivation(mojo::View* view) const {
+ return true;
+}
+
bool BasicFocusRules::IsToplevelView(mojo::View* view) const {
- return view->parent() == window_container_;
+ if (!IsViewParentedToWindowContainer(view))
+ return false;
+
+ // The window must exist within a container that supports activation.
+ // The window cannot be blocked by a modal transient.
+ return SupportsChildActivation(view->parent());
}
bool BasicFocusRules::CanActivateView(mojo::View* view) const {
- // TODO(erg): This needs to check visibility, along with focus, and several
- // other things (see wm::BaseFocusRules).
- return view->parent() == window_container_;
+ if (!view)
+ return true;
+
+ // Only toplevel windows can be activated
+ if (!IsToplevelView(view))
+ return false;
+
+ // The view must be visible.
+ if (!view->visible())
+ return false;
+
+ // TODO(erg): The aura version of this class asks the aura::Window's
+ // ActivationDelegate whether the window is activatable.
+
+ // A window must be focusable to be activatable. We don't call
+ // CanFocusWindow() from here because it will call back to us via
+ // GetActivatableWindow().
+ if (!CanFocusViewImpl(view))
+ return false;
+
+ // TODO(erg): In the aura version, we also check whether the window is
+ // blocked by a modal transient window.
+
+ return true;
}
bool BasicFocusRules::CanFocusView(mojo::View* view) const {
- return true;
+ // It is possible to focus a NULL window, it is equivalent to clearing focus.
+ if (!view)
+ return true;
+
+ // The focused view is always inside the active view, so views that aren't
+ // activatable can't contain the focused view.
+ View* activatable = GetActivatableView(view);
+ if (!activatable || !activatable->Contains(view))
+ return false;
+ return CanFocusViewImpl(view);
}
mojo::View* BasicFocusRules::GetToplevelView(mojo::View* view) const {
- while (view->parent() != window_container_) {
- view = view->parent();
- // Unparented hierarchy, there is no "top level" window.
- if (!view)
- return nullptr;
+ View* parent = view->parent();
+ View* child = view;
+ while (parent) {
+ if (IsToplevelView(child))
+ return child;
+
+ parent = parent->parent();
+ child = child->parent();
}
- return view;
+ return nullptr;
}
mojo::View* BasicFocusRules::GetActivatableView(mojo::View* view) const {
- return GetToplevelView(view);
+ View* parent = view->parent();
+ View* child = view;
+ while (parent) {
+ if (CanActivateView(child))
+ return child;
+
+ // TODO(erg): In the aura version of this class, we have a whole bunch of
+ // checks to support modal transient windows, and transient parents.
+
+ parent = parent->parent();
+ child = child->parent();
+ }
+
+ return nullptr;
}
mojo::View* BasicFocusRules::GetFocusableView(mojo::View* view) const {
+ if (CanFocusView(view))
+ return view;
+
+ // |view| may be in a hierarchy that is non-activatable, in which case we
+ // need to cut over to the activatable hierarchy.
+ View* activatable = GetActivatableView(view);
+ if (!activatable) {
+ // There may not be a related activatable hierarchy to cut over to, in which
+ // case we try an unrelated one.
+ View* toplevel = GetToplevelView(view);
+ if (toplevel)
+ activatable = GetNextActivatableView(toplevel);
+ if (!activatable)
+ return nullptr;
+ }
+
+ if (!activatable->Contains(view)) {
+ // If there's already a child window focused in the activatable hierarchy,
+ // just use that (i.e. don't shift focus), otherwise we need to at least cut
+ // over to the activatable hierarchy.
+ View* focused = GetFocusableView(activatable);
+ return activatable->Contains(focused) ? focused : activatable;
+ }
+
+ while (view && !CanFocusView(view))
+ view = view->parent();
return view;
}
mojo::View* BasicFocusRules::GetNextActivatableView(
mojo::View* activatable) const {
- const mojo::View::Children& children = activatable->parent()->children();
- for (mojo::View::Children::const_reverse_iterator it = children.rbegin();
- it != children.rend(); ++it) {
- if (*it != activatable)
- return *it;
+ DCHECK(activatable);
+
+ // In the basic scenarios handled by BasicFocusRules, the pool of activatable
+ // windows is limited to the |ignore|'s siblings.
+ const View::Children& siblings = activatable->parent()->children();
+ DCHECK(!siblings.empty());
+
+ for (auto rit = siblings.rbegin(); rit != siblings.rend(); ++rit) {
+ View* cur = *rit;
+ if (cur == activatable)
+ continue;
+ if (CanActivateView(cur))
+ return cur;
}
return nullptr;
}
+// TODO(erg): aura::Window::CanFocus() exists. mojo::View::CanFocus() does
+// not. This is a hack that does everything that Window::CanFocus() currently
+// does that doesn't require a delegate or an EventClient.
+bool BasicFocusRules::CanFocusViewImpl(View* view) const {
+ // TODO(erg): In unit tests, views will never be drawn, so we can't rely on
+ // IsDrawn() here.
+ if (IsViewParentedToWindowContainer(view))
+ return view->visible();
+
+ // TODO(erg): Add the intermediary delegate and event client checks once we
+ // have those.
+
+ return CanFocusViewImpl(view->parent());
+}
+
+bool BasicFocusRules::IsViewParentedToWindowContainer(mojo::View* view) const {
+ return view->parent() == window_container_;
+}
+
} // namespace mojo
« no previous file with comments | « services/window_manager/basic_focus_rules.h ('k') | services/window_manager/focus_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698