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 @@
#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"
namespace ash {
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:
......@@ -21,29 +55,45 @@ AshFocusRules::~AshFocusRules() {
////////////////////////////////////////////////////////////////////////////////
// AshFocusRules, views::corewm::FocusRules:
bool AshFocusRules::CanActivateWindow(aura::Window* window) {
return window && !!window->parent();
}
bool AshFocusRules::SupportsChildActivation(aura::Window* window) {
if (window->id() == internal::kShellWindowId_WorkspaceContainer)
return true;
bool AshFocusRules::CanFocusWindow(aura::Window* window) {
aura::Window* activatable = GetActivatableWindow(window);
return activatable->Contains(window) && window->CanFocus();
}
if (window->id() != internal::kShellWindowId_DefaultContainer)
return false;
aura::Window* AshFocusRules::GetActivatableWindow(aura::Window* window) {
return window;
for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
if (window->id() == kWindowContainerIds[i])
return true;
}
return false;
}
aura::Window* AshFocusRules::GetFocusableWindow(aura::Window* window) {
return window;
}
bool AshFocusRules::IsWindowConsideredVisibleForActivation(
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 NULL;
return window->TargetVisibility() && (window->parent()->id() ==
internal::kShellWindowId_WorkspaceContainer || window->parent()->id() ==
internal::kShellWindowId_LockScreenContainer);
}
aura::Window* AshFocusRules::GetNextFocusableWindow(aura::Window* ignore) {
return GetFocusableWindow(ignore->parent());
bool AshFocusRules::CanActivateWindow(aura::Window* window) {
if (!BaseFocusRules::CanActivateWindow(window))
return false;
if (Shell::GetInstance()->IsSystemModalWindowOpen()) {
return BelongsToContainerWithEqualOrGreaterId(
window, internal::kShellWindowId_SystemModalContainer);
}
return true;
}
} // namespace wm
......
......@@ -8,24 +8,22 @@
#include "ash/ash_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "ui/views/corewm/focus_rules.h"
#include "ui/views/corewm/base_focus_rules.h"
namespace ash {
namespace wm {
class ASH_EXPORT AshFocusRules : public views::corewm::FocusRules {
class ASH_EXPORT AshFocusRules : public views::corewm::BaseFocusRules {
public:
AshFocusRules();
virtual ~AshFocusRules();
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 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);
};
......
......@@ -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() {
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)
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;
......
......@@ -15,11 +15,16 @@ namespace corewm {
// A set of basic focus and activation rules. Specializations should most likely
// subclass this and call up to these methods rather than reimplementing them.
class VIEWS_EXPORT BaseFocusRules : public FocusRules {
public:
protected:
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:
virtual bool CanActivateWindow(aura::Window* window) OVERRIDE;
virtual bool CanFocusWindow(aura::Window* window) OVERRIDE;
......
......@@ -85,11 +85,15 @@ class TestFocusRules : public 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 {
// Restricting focus to a non-activatable child window means the activatable
// parent outside the focus restriction is activatable.
bool can_activate = CanFocusOrActivate(window) ||
window->Contains(GetActivatableWindow(focus_restriction_));
bool can_activate =
CanFocusOrActivate(window) || window->Contains(focus_restriction_);
return can_activate ? BaseFocusRules::CanActivateWindow(window) : false;
}
virtual bool CanFocusWindow(aura::Window* window) OVERRIDE {
......
......@@ -75,6 +75,11 @@ void SetModalParent(aura::Window* child, aura::Window* parent) {
child->SetProperty(kModalParentKey, parent);
}
aura::Window* GetModalTransientForActivatableWindow(
aura::Window* activatable) {
return GetModalTransientChild(activatable, activatable);
}
aura::Window* GetModalTransient(aura::Window* window) {
if (!window)
return NULL;
......
......@@ -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
// have any modal transient children.
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
// 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