diff options
author | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-03 17:56:24 +0000 |
---|---|---|
committer | flackr@chromium.org <flackr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-03 17:56:24 +0000 |
commit | 15e3a9dea581678a57e8b220295425b35fde03a4 (patch) | |
tree | b8e207a07701d0acfb342956597851b30afc7860 /ash | |
parent | 3b245cefd8507b6babf4d54bdcf3225adfb19b09 (diff) | |
download | chromium_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.cc | 77 | ||||
-rw-r--r-- | ash/wm/activation_controller.h | 16 | ||||
-rw-r--r-- | ash/wm/activation_controller_unittest.cc | 73 |
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) { |