Commit 21f65c05 authored by ben@chromium.org's avatar ben@chromium.org

Fleshes out the basic set of focus rules a bit more.

http://crbug.com/162100
R=sadrul@chromium.org
Review URL: https://codereview.chromium.org/11414304

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170988 0039d316-1c4b-4281-b951-d872f2087c98
parent 55155ac9
...@@ -4,10 +4,44 @@ ...@@ -4,10 +4,44 @@
#include "ash/wm/ash_focus_rules.h" #include "ash/wm/ash_focus_rules.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/window_util.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
namespace ash { namespace ash {
namespace wm { namespace wm {
namespace {
// These are the list of container ids of containers which may contain windows
// that need to be activated in the order that they should be activated.
const int kWindowContainerIds[] = {
internal::kShellWindowId_LockSystemModalContainer,
internal::kShellWindowId_SettingBubbleContainer,
internal::kShellWindowId_LockScreenContainer,
internal::kShellWindowId_SystemModalContainer,
internal::kShellWindowId_AlwaysOnTopContainer,
internal::kShellWindowId_AppListContainer,
internal::kShellWindowId_DefaultContainer,
// Panel, launcher and status are intentionally checked after other
// containers even though these layers are higher. The user expects their
// windows to be focused before these elements.
internal::kShellWindowId_PanelContainer,
internal::kShellWindowId_LauncherContainer,
internal::kShellWindowId_StatusContainer,
};
bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
int container_id) {
for (; window; window = window->parent()) {
if (window->id() >= container_id)
return true;
}
return false;
}
} // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, public: // AshFocusRules, public:
...@@ -21,29 +55,45 @@ AshFocusRules::~AshFocusRules() { ...@@ -21,29 +55,45 @@ AshFocusRules::~AshFocusRules() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, views::corewm::FocusRules: // AshFocusRules, views::corewm::FocusRules:
bool AshFocusRules::CanActivateWindow(aura::Window* window) { bool AshFocusRules::SupportsChildActivation(aura::Window* window) {
return window && !!window->parent(); if (window->id() == internal::kShellWindowId_WorkspaceContainer)
} return true;
bool AshFocusRules::CanFocusWindow(aura::Window* window) { if (window->id() != internal::kShellWindowId_DefaultContainer)
aura::Window* activatable = GetActivatableWindow(window); return false;
return activatable->Contains(window) && window->CanFocus();
}
aura::Window* AshFocusRules::GetActivatableWindow(aura::Window* window) { for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
return window; if (window->id() == kWindowContainerIds[i])
return true;
}
return false;
} }
aura::Window* AshFocusRules::GetFocusableWindow(aura::Window* window) { bool AshFocusRules::IsWindowConsideredVisibleForActivation(
return window; aura::Window* window) {
} if (BaseFocusRules::IsWindowConsideredVisibleForActivation(window))
return true;
// Minimized windows are hidden in their minimized state, but they can always
// be activated.
if (wm::IsWindowMinimized(window))
return true;
aura::Window* AshFocusRules::GetNextActivatableWindow(aura::Window* ignore) { return window->TargetVisibility() && (window->parent()->id() ==
return NULL; internal::kShellWindowId_WorkspaceContainer || window->parent()->id() ==
internal::kShellWindowId_LockScreenContainer);
} }
aura::Window* AshFocusRules::GetNextFocusableWindow(aura::Window* ignore) { bool AshFocusRules::CanActivateWindow(aura::Window* window) {
return GetFocusableWindow(ignore->parent()); if (!BaseFocusRules::CanActivateWindow(window))
return false;
if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
return BelongsToContainerWithEqualOrGreaterId(
window, internal::kShellWindowId_SystemModalContainer);
}
return true;
} }
} // namespace wm } // namespace wm
......
...@@ -8,24 +8,22 @@ ...@@ -8,24 +8,22 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "ui/views/corewm/focus_rules.h" #include "ui/views/corewm/base_focus_rules.h"
namespace ash { namespace ash {
namespace wm { namespace wm {
class ASH_EXPORT AshFocusRules : public views::corewm::FocusRules { class ASH_EXPORT AshFocusRules : public views::corewm::BaseFocusRules {
public: public:
AshFocusRules(); AshFocusRules();
virtual ~AshFocusRules(); virtual ~AshFocusRules();
private: private:
// Overridden from views::corewm::FocusRules: // Overridden from views::corewm::BaseFocusRules:
virtual bool SupportsChildActivation(aura::Window* window) OVERRIDE;
virtual bool IsWindowConsideredVisibleForActivation(
aura::Window* window) OVERRIDE;
virtual bool CanActivateWindow(aura::Window* window) OVERRIDE; virtual bool CanActivateWindow(aura::Window* window) OVERRIDE;
virtual bool CanFocusWindow(aura::Window* window) OVERRIDE;
virtual aura::Window* GetActivatableWindow(aura::Window* window) OVERRIDE;
virtual aura::Window* GetFocusableWindow(aura::Window* window) OVERRIDE;
virtual aura::Window* GetNextActivatableWindow(aura::Window* ignore) OVERRIDE;
virtual aura::Window* GetNextFocusableWindow(aura::Window* ignore) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(AshFocusRules); DISALLOW_COPY_AND_ASSIGN(AshFocusRules);
}; };
......
...@@ -4,14 +4,26 @@ ...@@ -4,14 +4,26 @@
#include "ui/views/corewm/base_focus_rules.h" #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/root_window.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/views/corewm/window_modality_controller.h"
namespace views { namespace views {
namespace corewm { 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() { BaseFocusRules::BaseFocusRules() {
} }
...@@ -19,33 +31,87 @@ BaseFocusRules::BaseFocusRules() { ...@@ -19,33 +31,87 @@ BaseFocusRules::BaseFocusRules() {
BaseFocusRules::~BaseFocusRules() { BaseFocusRules::~BaseFocusRules() {
} }
bool BaseFocusRules::IsWindowConsideredVisibleForActivation(
aura::Window* window) {
return window->IsVisible();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// BaseFocusRules, FocusRules implementation: // BaseFocusRules, FocusRules implementation:
bool BaseFocusRules::CanActivateWindow(aura::Window* window) { bool BaseFocusRules::CanActivateWindow(aura::Window* window) {
return !window || // It is possible to activate a NULL window, it is equivalent to clearing
(window->IsVisible() && window->parent() == window->GetRootWindow()); // activation.
if (!window)
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) { bool BaseFocusRules::CanFocusWindow(aura::Window* window) {
// See FocusRules: NULL is a valid focusable window (when clearing focus). // It is possible to focus a NULL window, it is equivalent to clearing focus.
return !window || window->CanFocus(); 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) { aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) {
// BasicFocusRules considers only direct children of the RootWindow as
// activatable.
aura::Window* parent = window->parent(); aura::Window* parent = window->parent();
aura::Window* activatable = window; aura::Window* child = window;
aura::RootWindow* root_window = window->GetRootWindow(); while (parent) {
while (parent != root_window) { if (CanActivateWindow(child))
activatable = parent; return child;
if (child->transient_parent())
return GetActivatableWindow(child->transient_parent());
parent = parent->parent(); parent = parent->parent();
child = child->parent();
} }
return activatable; return NULL;
} }
aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) { 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)) while (window && !CanFocusWindow(window))
window = window->parent(); window = window->parent();
return window; return window;
......
...@@ -15,11 +15,16 @@ namespace corewm { ...@@ -15,11 +15,16 @@ namespace corewm {
// A set of basic focus and activation rules. Specializations should most likely // A set of basic focus and activation rules. Specializations should most likely
// subclass this and call up to these methods rather than reimplementing them. // subclass this and call up to these methods rather than reimplementing them.
class VIEWS_EXPORT BaseFocusRules : public FocusRules { class VIEWS_EXPORT BaseFocusRules : public FocusRules {
public: protected:
BaseFocusRules(); BaseFocusRules();
virtual ~BaseFocusRules(); virtual ~BaseFocusRules();
protected: // Returns true if the children of |window| can be activated.
virtual bool SupportsChildActivation(aura::Window* window) = 0;
// Returns true if |window| is considered visible for activation purposes.
virtual bool IsWindowConsideredVisibleForActivation(aura::Window* window);
// Overridden from FocusRules: // Overridden from FocusRules:
virtual bool CanActivateWindow(aura::Window* window) OVERRIDE; virtual bool CanActivateWindow(aura::Window* window) OVERRIDE;
virtual bool CanFocusWindow(aura::Window* window) OVERRIDE; virtual bool CanFocusWindow(aura::Window* window) OVERRIDE;
......
...@@ -85,11 +85,15 @@ class TestFocusRules : public BaseFocusRules { ...@@ -85,11 +85,15 @@ class TestFocusRules : public BaseFocusRules {
} }
// Overridden from BaseFocusRules: // Overridden from BaseFocusRules:
virtual bool SupportsChildActivation(aura::Window* window) OVERRIDE {
// In FocusControllerTests, only the RootWindow has activatable children.
return window->GetRootWindow() == window;
}
virtual bool CanActivateWindow(aura::Window* window) OVERRIDE { virtual bool CanActivateWindow(aura::Window* window) OVERRIDE {
// Restricting focus to a non-activatable child window means the activatable // Restricting focus to a non-activatable child window means the activatable
// parent outside the focus restriction is activatable. // parent outside the focus restriction is activatable.
bool can_activate = CanFocusOrActivate(window) || bool can_activate =
window->Contains(GetActivatableWindow(focus_restriction_)); CanFocusOrActivate(window) || window->Contains(focus_restriction_);
return can_activate ? BaseFocusRules::CanActivateWindow(window) : false; return can_activate ? BaseFocusRules::CanActivateWindow(window) : false;
} }
virtual bool CanFocusWindow(aura::Window* window) OVERRIDE { virtual bool CanFocusWindow(aura::Window* window) OVERRIDE {
......
...@@ -75,6 +75,11 @@ void SetModalParent(aura::Window* child, aura::Window* parent) { ...@@ -75,6 +75,11 @@ void SetModalParent(aura::Window* child, aura::Window* parent) {
child->SetProperty(kModalParentKey, parent); child->SetProperty(kModalParentKey, parent);
} }
aura::Window* GetModalTransientForActivatableWindow(
aura::Window* activatable) {
return GetModalTransientChild(activatable, activatable);
}
aura::Window* GetModalTransient(aura::Window* window) { aura::Window* GetModalTransient(aura::Window* window) {
if (!window) if (!window)
return NULL; return NULL;
......
...@@ -26,6 +26,8 @@ VIEWS_EXPORT void SetModalParent(aura::Window* child, aura::Window* parent); ...@@ -26,6 +26,8 @@ VIEWS_EXPORT void SetModalParent(aura::Window* child, aura::Window* parent);
// Returns the modal transient child of |window|, or NULL if |window| does not // Returns the modal transient child of |window|, or NULL if |window| does not
// have any modal transient children. // have any modal transient children.
VIEWS_EXPORT aura::Window* GetModalTransient(aura::Window* window); VIEWS_EXPORT aura::Window* GetModalTransient(aura::Window* window);
// |activatable| must be activatable.
aura::Window* GetModalTransientForActivatableWindow(aura::Window* activatable);
// WindowModalityController is an event filter that consumes events sent to // WindowModalityController is an event filter that consumes events sent to
// windows that are the transient parents of window-modal windows. This filter // windows that are the transient parents of window-modal windows. This filter
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment