Chromium Code Reviews| Index: ui/views/corewm/base_focus_rules.cc |
| =================================================================== |
| --- ui/views/corewm/base_focus_rules.cc (revision 170885) |
| +++ ui/views/corewm/base_focus_rules.cc (working copy) |
| @@ -4,14 +4,26 @@ |
| #include "ui/views/corewm/base_focus_rules.h" |
| +#include "ui/aura/client/activation_delegate.h" |
| +#include "ui/aura/client/focus_client.h" |
| #include "ui/aura/root_window.h" |
| #include "ui/aura/window.h" |
| +#include "ui/views/corewm/window_modality_controller.h" |
| namespace views { |
| namespace corewm { |
| +namespace { |
| +aura::Window* GetFocusedWindow(aura::Window* context) { |
| + aura::client::FocusClient* focus_client = |
| + aura::client::GetFocusClient(context); |
| + return focus_client ? focus_client->GetFocusedWindow() : NULL; |
| +} |
| + |
| +} // namespace |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| -// BaseFocusRules, public: |
| +// BaseFocusRules, protected: |
| BaseFocusRules::BaseFocusRules() { |
| } |
| @@ -19,33 +31,87 @@ |
| BaseFocusRules::~BaseFocusRules() { |
| } |
| +bool BaseFocusRules::IsWindowConsideredVisibleForActivation( |
| + aura::Window* window) { |
| + return window->IsVisible(); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // BaseFocusRules, FocusRules implementation: |
| bool BaseFocusRules::CanActivateWindow(aura::Window* window) { |
| - return !window || |
| - (window->IsVisible() && window->parent() == window->GetRootWindow()); |
| + // It is possible to activate a NULL window, it is equivalent to clearing |
| + // activation. |
| + if (!window) |
|
sadrul
2012/12/04 16:19:40
The doc claims the window needs to be non-NULL. Bu
|
| + return true; |
| + |
| + // The window must in a valid hierarchy. |
| + if (!window->GetRootWindow()) |
| + return false; |
| + |
| + // The window must be visible. |
| + if (!IsWindowConsideredVisibleForActivation(window)) |
| + return false; |
| + |
| + // The window's activation delegate must allow this window to be activated. |
| + if (aura::client::GetActivationDelegate(window) && |
| + !aura::client::GetActivationDelegate(window)->ShouldActivate()) { |
| + return false; |
| + } |
| + |
| + // The window must exist within a container that supports activation. |
| + // The window cannot be blocked by a modal transient. |
| + return SupportsChildActivation(window->parent()) && |
| + !GetModalTransientForActivatableWindow(window); |
| } |
| bool BaseFocusRules::CanFocusWindow(aura::Window* window) { |
| - // See FocusRules: NULL is a valid focusable window (when clearing focus). |
| - return !window || window->CanFocus(); |
| + // It is possible to focus a NULL window, it is equivalent to clearing focus. |
| + if (!window) |
| + return true; |
| + |
| + // The focused window is always inside the active window, so windows that |
| + // aren't activatable can't contain the focused window. |
| + aura::Window* activatable = GetActivatableWindow(window); |
| + if (!activatable->Contains(window)) |
| + return false; |
| + return window->CanFocus(); |
| } |
| aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) { |
| - // BasicFocusRules considers only direct children of the RootWindow as |
| - // activatable. |
| aura::Window* parent = window->parent(); |
| - aura::Window* activatable = window; |
| - aura::RootWindow* root_window = window->GetRootWindow(); |
| - while (parent != root_window) { |
| - activatable = parent; |
| + aura::Window* child = window; |
| + while (parent) { |
| + if (CanActivateWindow(child)) |
| + return child; |
| + |
| + if (child->transient_parent()) |
| + return GetActivatableWindow(child->transient_parent()); |
| + |
| parent = parent->parent(); |
| + child = child->parent(); |
| } |
| - return activatable; |
| + return NULL; |
| } |
| aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) { |
| + if (CanFocusWindow(window)) |
| + return window; |
| + |
| + // |window| may be in a hierarchy that is non-activatable, in which case we |
| + // need to cut over to the activatable hierarchy. |
| + aura::Window* activatable = GetActivatableWindow(window); |
| + if (!activatable) |
| + return GetFocusedWindow(window); |
| + |
| + if (!activatable->Contains(window)) { |
| + // 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. |
| + aura::Window* focused = GetFocusedWindow(activatable); |
| + return activatable->Contains(focused) ? focused : activatable; |
| + } |
| + |
| while (window && !CanFocusWindow(window)) |
| window = window->parent(); |
| return window; |