| Index: mojo/services/window_manager/basic_focus_rules.cc
 | 
| diff --git a/mojo/services/window_manager/basic_focus_rules.cc b/mojo/services/window_manager/basic_focus_rules.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..5ba49afb6f99870f794b5826cb7073899c7c1366
 | 
| --- /dev/null
 | 
| +++ b/mojo/services/window_manager/basic_focus_rules.cc
 | 
| @@ -0,0 +1,171 @@
 | 
| +// Copyright 2014 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "mojo/services/window_manager/basic_focus_rules.h"
 | 
| +
 | 
| +#include "base/macros.h"
 | 
| +#include "third_party/mojo_services/src/view_manager/public/cpp/view.h"
 | 
| +
 | 
| +using mojo::View;
 | 
| +
 | 
| +namespace window_manager {
 | 
| +
 | 
| +BasicFocusRules::BasicFocusRules(View* window_container)
 | 
| +    : window_container_(window_container) {
 | 
| +}
 | 
| +
 | 
| +BasicFocusRules::~BasicFocusRules() {}
 | 
| +
 | 
| +bool BasicFocusRules::SupportsChildActivation(View* view) const {
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool BasicFocusRules::IsToplevelView(View* view) const {
 | 
| +  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(View* view) const {
 | 
| +  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(View* view) const {
 | 
| +  // 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);
 | 
| +}
 | 
| +
 | 
| +View* BasicFocusRules::GetToplevelView(View* view) const {
 | 
| +  View* parent = view->parent();
 | 
| +  View* child = view;
 | 
| +  while (parent) {
 | 
| +    if (IsToplevelView(child))
 | 
| +      return child;
 | 
| +
 | 
| +    parent = parent->parent();
 | 
| +    child = child->parent();
 | 
| +  }
 | 
| +
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
| +View* BasicFocusRules::GetActivatableView(View* view) const {
 | 
| +  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;
 | 
| +}
 | 
| +
 | 
| +View* BasicFocusRules::GetFocusableView(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;
 | 
| +}
 | 
| +
 | 
| +View* BasicFocusRules::GetNextActivatableView(View* activatable) const {
 | 
| +  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. 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(View* view) const {
 | 
| +  return view->parent() == window_container_;
 | 
| +}
 | 
| +
 | 
| +}  // namespace mojo
 | 
| 
 |