summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorflackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-03 17:56:24 +0000
committerflackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-03 17:56:24 +0000
commit15e3a9dea581678a57e8b220295425b35fde03a4 (patch)
treeb8e207a07701d0acfb342956597851b30afc7860 /ash
parent3b245cefd8507b6babf4d54bdcf3225adfb19b09 (diff)
downloadchromium_src-15e3a9dea581678a57e8b220295425b35fde03a4.zip
chromium_src-15e3a9dea581678a57e8b220295425b35fde03a4.tar.gz
chromium_src-15e3a9dea581678a57e8b220295425b35fde03a4.tar.bz2
Activate windows in higher containers if they exist.
BUG=116239 TEST=Open a system modal dialog, lock and unlock the screen. The system modal dialog should get focus back. Review URL: https://chromiumcodereview.appspot.com/9568045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@124867 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/wm/activation_controller.cc77
-rw-r--r--ash/wm/activation_controller.h16
-rw-r--r--ash/wm/activation_controller_unittest.cc73
3 files changed, 127 insertions, 39 deletions
diff --git a/ash/wm/activation_controller.cc b/ash/wm/activation_controller.cc
index c90846a..8777aa1 100644
--- a/ash/wm/activation_controller.cc
+++ b/ash/wm/activation_controller.cc
@@ -21,6 +21,23 @@ namespace ash {
namespace internal {
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[] = {
+ kShellWindowId_LockSystemModalContainer,
+ kShellWindowId_LockScreenContainer,
+ kShellWindowId_SystemModalContainer,
+ kShellWindowId_AlwaysOnTopContainer,
+ 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.
+ kShellWindowId_PanelContainer,
+ kShellWindowId_LauncherContainer,
+ kShellWindowId_StatusContainer,
+};
+
aura::Window* GetContainer(int id) {
return Shell::GetInstance()->GetContainer(id);
}
@@ -28,14 +45,11 @@ aura::Window* GetContainer(int id) {
// Returns true if children of |window| can be activated.
// These are the only containers in which windows can receive focus.
bool SupportsChildActivation(aura::Window* window) {
- return window->id() == kShellWindowId_DefaultContainer ||
- window->id() == kShellWindowId_AlwaysOnTopContainer ||
- window->id() == kShellWindowId_PanelContainer ||
- window->id() == kShellWindowId_SystemModalContainer ||
- window->id() == kShellWindowId_StatusContainer ||
- window->id() == kShellWindowId_LauncherContainer ||
- window->id() == kShellWindowId_LockScreenContainer ||
- window->id() == kShellWindowId_LockSystemModalContainer;
+ for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
+ if (window->id() == kWindowContainerIds[i])
+ return true;
+ }
+ return false;
}
// Returns true if |window| can be activated or deactivated.
@@ -69,8 +83,7 @@ void StackTransientParentsBelowModalWindow(aura::Window* window) {
// ActivationController, public:
ActivationController::ActivationController()
- : updating_activation_(false),
- default_container_for_test_(NULL) {
+ : updating_activation_(false) {
aura::client::SetActivationClient(Shell::GetRootWindow(), this);
aura::Env::GetInstance()->AddObserver(this);
Shell::GetRootWindow()->AddRootWindowObserver(this);
@@ -208,21 +221,39 @@ void ActivationController::ActivateNextWindow(aura::Window* window) {
aura::Window* ActivationController::GetTopmostWindowToActivate(
aura::Window* ignore) const {
- const aura::Window* container =
- default_container_for_test_ ? default_container_for_test_ :
- GetContainer(kShellWindowId_DefaultContainer);
- // When destructing an active window that is in a container destructed after
- // the default container during shell shutdown, |container| would be NULL
- // because default container is destructed at this point.
- if (container) {
- for (aura::Window::Windows::const_reverse_iterator i =
- container->children().rbegin();
- i != container->children().rend();
- ++i) {
- if (*i != ignore && CanActivateWindow(*i))
- return *i;
+ size_t current_container_index = 0;
+ // If the container of the window losing focus is in the list, start from that
+ // container.
+ for (size_t i = 0; ignore && i < arraysize(kWindowContainerIds); i++) {
+ aura::Window* container = GetContainer(kWindowContainerIds[i]);
+ if (container && container->Contains(ignore)) {
+ current_container_index = i;
+ break;
}
}
+
+ // Look for windows to focus in that container and below.
+ aura::Window* window = NULL;
+ for (; !window && current_container_index < arraysize(kWindowContainerIds);
+ current_container_index++) {
+ aura::Window* container =
+ GetContainer(kWindowContainerIds[current_container_index]);
+ if (container)
+ window = GetTopmostWindowToActivateInContainer(container, ignore);
+ }
+ return window;
+}
+
+aura::Window* ActivationController::GetTopmostWindowToActivateInContainer(
+ aura::Window* container,
+ aura::Window* ignore) const {
+ for (aura::Window::Windows::const_reverse_iterator i =
+ container->children().rbegin();
+ i != container->children().rend();
+ ++i) {
+ if (*i != ignore && CanActivateWindow(*i))
+ return *i;
+ }
return NULL;
}
diff --git a/ash/wm/activation_controller.h b/ash/wm/activation_controller.h
index 6292add..b798b66 100644
--- a/ash/wm/activation_controller.h
+++ b/ash/wm/activation_controller.h
@@ -49,10 +49,6 @@ class ASH_EXPORT ActivationController
// Overridden from aura::RootWindowObserver:
virtual void OnWindowFocused(aura::Window* window) OVERRIDE;
- void set_default_container_for_test(aura::Window* window) {
- default_container_for_test_ = window;
- }
-
private:
// Shifts activation to the next window, ignoring |window|.
void ActivateNextWindow(aura::Window* window);
@@ -60,16 +56,16 @@ class ASH_EXPORT ActivationController
// Returns the next window that should be activated, ignoring |ignore|.
aura::Window* GetTopmostWindowToActivate(aura::Window* ignore) const;
+ // Returns the next window that should be activated in |container| ignoring
+ // the window |ignore|.
+ aura::Window* GetTopmostWindowToActivateInContainer(
+ aura::Window* container,
+ aura::Window* ignore) const;
+
// True inside ActivateWindow(). Used to prevent recursion of focus
// change notifications causing activation.
bool updating_activation_;
- // For tests that are not running with a Shell instance,
- // ActivationController's attempts to locate the next active window in
- // GetTopmostWindowToActivate() will crash, so we provide this way for such
- // tests to specify a default container.
- aura::Window* default_container_for_test_;
-
DISALLOW_COPY_AND_ASSIGN(ActivationController);
};
diff --git a/ash/wm/activation_controller_unittest.cc b/ash/wm/activation_controller_unittest.cc
index 87393cf..32e12b1 100644
--- a/ash/wm/activation_controller_unittest.cc
+++ b/ash/wm/activation_controller_unittest.cc
@@ -5,6 +5,7 @@
#include "ash/wm/activation_controller.h"
#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/test_activation_delegate.h"
#include "ash/wm/window_util.h"
@@ -21,6 +22,15 @@
#endif
#endif
+namespace {
+
+// Containers used for the tests.
+const int c1 = ash::internal::kShellWindowId_DefaultContainer;
+const int c2 = ash::internal::kShellWindowId_AlwaysOnTopContainer;
+const int c3 = ash::internal::kShellWindowId_LockScreenContainer;
+
+} // namespace
+
namespace ash {
namespace test {
@@ -48,6 +58,9 @@ class GetTopmostWindowToActivateTest : public ActivationControllerTest {
aura::Window* w2() { return w2_.get(); }
aura::Window* w3() { return w3_.get(); }
aura::Window* w4() { return w4_.get(); }
+ aura::Window* w5() { return w5_.get(); }
+ aura::Window* w6() { return w6_.get(); }
+ aura::Window* w7() { return w7_.get(); }
void DestroyWindow2() {
w2_.reset();
@@ -57,15 +70,23 @@ class GetTopmostWindowToActivateTest : public ActivationControllerTest {
void CreateWindows() {
// Create four windows, the first and third are not activatable, the second
// and fourth are.
- w1_.reset(CreateWindow(1, &ad_1_));
- w2_.reset(CreateWindow(2, &ad_2_));
- w3_.reset(CreateWindow(3, &ad_3_));
- w4_.reset(CreateWindow(4, &ad_4_));
+ w1_.reset(CreateWindow(1, &ad_1_, c1));
+ w2_.reset(CreateWindow(2, &ad_2_, c1));
+ w3_.reset(CreateWindow(3, &ad_3_, c1));
+ w4_.reset(CreateWindow(4, &ad_4_, c1));
+ w5_.reset(CreateWindow(5, &ad_5_, c2));
+ w6_.reset(CreateWindow(6, &ad_6_, c2));
+ w7_.reset(CreateWindow(7, &ad_7_, c3));
}
- aura::Window* CreateWindow(int id, TestActivationDelegate* delegate) {
+ aura::Window* CreateWindow(int id,
+ TestActivationDelegate* delegate,
+ int container_id) {
aura::Window* window = aura::test::CreateTestWindowWithDelegate(
- &delegate_, id, gfx::Rect(), NULL);
+ &delegate_,
+ id,
+ gfx::Rect(),
+ Shell::GetInstance()->GetContainer(container_id));
delegate->SetWindow(window);
return window;
}
@@ -75,6 +96,9 @@ class GetTopmostWindowToActivateTest : public ActivationControllerTest {
w2_.reset();
w3_.reset();
w4_.reset();
+ w5_.reset();
+ w6_.reset();
+ w7_.reset();
}
aura::test::TestWindowDelegate delegate_;
@@ -82,10 +106,16 @@ class GetTopmostWindowToActivateTest : public ActivationControllerTest {
TestActivationDelegate ad_2_;
TestActivationDelegate ad_3_;
TestActivationDelegate ad_4_;
+ TestActivationDelegate ad_5_;
+ TestActivationDelegate ad_6_;
+ TestActivationDelegate ad_7_;
scoped_ptr<aura::Window> w1_; // Non-activatable.
scoped_ptr<aura::Window> w2_; // Activatable.
scoped_ptr<aura::Window> w3_; // Non-activatable.
scoped_ptr<aura::Window> w4_; // Activatable.
+ scoped_ptr<aura::Window> w5_; // Activatable - Always on top.
+ scoped_ptr<aura::Window> w6_; // Activatable - Always on top.
+ scoped_ptr<aura::Window> w7_; // Activatable - Lock screen window.
DISALLOW_COPY_AND_ASSIGN(GetTopmostWindowToActivateTest);
};
@@ -120,6 +150,37 @@ TEST_F(GetTopmostWindowToActivateTest, DeactivateActivatesNext) {
EXPECT_TRUE(wm::IsActiveWindow(w4()));
}
+// Test that hiding a window in a higher container will activate another window
+// in that container.
+TEST_F(GetTopmostWindowToActivateTest, HideActivatesSameContainer) {
+ wm::ActivateWindow(w6());
+ EXPECT_TRUE(wm::IsActiveWindow(w6()));
+
+ w6()->Hide();
+ EXPECT_TRUE(wm::IsActiveWindow(w5()));
+}
+
+// Test that hiding the lock window will activate a window from the next highest
+// container.
+TEST_F(GetTopmostWindowToActivateTest, UnlockActivatesNextHighestContainer) {
+ wm::ActivateWindow(w7());
+ EXPECT_TRUE(wm::IsActiveWindow(w7()));
+
+ w7()->Hide();
+ EXPECT_TRUE(wm::IsActiveWindow(w6()));
+}
+
+// Test that hiding a window in a higher container with no other windows will
+// activate a window in a lower container.
+TEST_F(GetTopmostWindowToActivateTest, HideActivatesNextHighestContainer) {
+ w5()->Hide();
+ wm::ActivateWindow(w6());
+ EXPECT_TRUE(wm::IsActiveWindow(w6()));
+
+ w6()->Hide();
+ EXPECT_TRUE(wm::IsActiveWindow(w4()));
+}
+
// Test if the clicking on a menu picks the transient parent as activatable
// window.
TEST_F(ActivationControllerTest, ClickOnMenu) {