diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-12 22:10:51 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-12 22:10:51 +0000 |
commit | 9b10d2a051ec36c4e7f012d31b8214221db16eaa (patch) | |
tree | b6242231f0674978d51071f02f511c81370a022c /ui/aura_shell | |
parent | 178520e30cfa28c3e33dd24a1868a06332975de4 (diff) | |
download | chromium_src-9b10d2a051ec36c4e7f012d31b8214221db16eaa.zip chromium_src-9b10d2a051ec36c4e7f012d31b8214221db16eaa.tar.gz chromium_src-9b10d2a051ec36c4e7f012d31b8214221db16eaa.tar.bz2 |
Move the concept of Activation to the Shell.
The Active Window is now stored in a property on the RootWindow. Classes wishing to observe changes to this can implement WindowObserver and attach to the RootWindow to be notified of changes in this property.
We provide an ActivationClient interface in Aura for customers to use to set/get the active window, and deactivate a window. This is because setting the active window involves more than just changing the property, there is some additional book-keeping that must be done. The ActivationClient is stored in a property on the RootWindow.
We also provide an ActivationDelegate interface in Aura that window owners can use to be notified of changes in activation state, and to specify whether or not a window can be activated. The ActivationDelegate should be stored on the relevant window in a property.
I moved a lot of Activation-related functionality out of Aura, including all of the unit tests, now on ActivationController, and the associated WindowDelegate implementations which have now become a single TestActivationDelegate implementation.
BUG=none
TEST=unit tests
Review URL: http://codereview.chromium.org/8894018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114095 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura_shell')
27 files changed, 857 insertions, 213 deletions
diff --git a/ui/aura_shell/activation_controller.cc b/ui/aura_shell/activation_controller.cc new file mode 100644 index 0000000..dfa1b00 --- /dev/null +++ b/ui/aura_shell/activation_controller.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura_shell/activation_controller.h" + +#include "base/auto_reset.h" +#include "ui/aura/client/activation_delegate.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/aura_shell/shell.h" +#include "ui/aura_shell/shell_window_ids.h" +#include "ui/aura_shell/window_util.h" + +namespace aura_shell { +namespace internal { +namespace { + +aura::Window* GetContainer(int id) { + return Shell::GetInstance()->GetContainer(id); +} + +// Returns true if children of |window| can be activated. +bool SupportsChildActivation(aura::Window* window) { + return window->id() == kShellWindowId_DefaultContainer || + window->id() == kShellWindowId_AlwaysOnTopContainer || + window->id() == kShellWindowId_ModalContainer || + window->id() == kShellWindowId_LockModalContainer; +} + +// Returns true if |window| can be activated or deactivated. +// A window manager typically defines some notion of "top level window" that +// supports activation/deactivation. +bool CanActivateWindow(aura::Window* window) { + return window && + window->IsVisible() && + (!aura::ActivationDelegate::GetActivationDelegate(window) || + aura::ActivationDelegate::GetActivationDelegate(window)-> + ShouldActivate(NULL)) && + SupportsChildActivation(window->parent()); +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ActivationController, public: + +ActivationController::ActivationController() + : updating_activation_(false), + default_container_for_test_(NULL) { + aura::ActivationClient::SetActivationClient(this); + aura::RootWindow::GetInstance()->AddRootWindowObserver(this); +} + +ActivationController::~ActivationController() { + aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this); +} + +// static +aura::Window* ActivationController::GetActivatableWindow(aura::Window* window) { + aura::Window* parent = window->parent(); + aura::Window* child = window; + while (parent) { + if (SupportsChildActivation(parent)) + return child; + // If |child| isn't activatable, but has transient parent, trace + // that path instead. + if (child->transient_parent()) + return GetActivatableWindow(child->transient_parent()); + parent = parent->parent(); + child = child->parent(); + } + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// StackingController, aura::ActivationClient implementation: + +void ActivationController::ActivateWindow(aura::Window* window) { + // Prevent recursion when called from focus. + if (updating_activation_) + return; + + AutoReset<bool> in_activate_window(&updating_activation_, true); + if (!window) + return; + // Nothing may actually have changed. + aura::Window* old_active = GetActiveWindow(); + if (old_active == window) + return; + // The stacking client may impose rules on what window configurations can be + // activated or deactivated. + if (!CanActivateWindow(window)) + return; + + if (!window->Contains(window->GetFocusManager()->GetFocusedWindow())) + window->GetFocusManager()->SetFocusedWindow(window); + aura::RootWindow::GetInstance()->SetProperty(aura::kRootWindowActiveWindow, + window); + // Invoke OnLostActive after we've changed the active window. That way if the + // delegate queries for active state it doesn't think the window is still + // active. + if (old_active && aura::ActivationDelegate::GetActivationDelegate(old_active)) + aura::ActivationDelegate::GetActivationDelegate(old_active)->OnLostActive(); + if (window) { + window->parent()->StackChildAtTop(window); + if (aura::ActivationDelegate::GetActivationDelegate(window)) + aura::ActivationDelegate::GetActivationDelegate(window)->OnActivated(); + } +} + +void ActivationController::DeactivateWindow(aura::Window* window) { + if (window) + ActivateNextWindow(window); +} + +aura::Window* ActivationController::GetActiveWindow() { + return reinterpret_cast<aura::Window*>( + aura::RootWindow::GetInstance()->GetProperty( + aura::kRootWindowActiveWindow)); +} + +bool ActivationController::CanFocusWindow(aura::Window* window) const { + return CanActivateWindow(GetActivatableWindow(window)); +} + +//////////////////////////////////////////////////////////////////////////////// +// ActivationController, aura::WindowObserver implementation: + +void ActivationController::OnWindowVisibilityChanged(aura::Window* window, + bool visible) { + if (!visible) + ActivateNextWindow(window); +} + +void ActivationController::OnWindowDestroyed(aura::Window* window) { + if (IsActiveWindow(window)) { + // Clear the property before activating something else, since + // ActivateWindow() will attempt to notify the window stored in this value + // otherwise. + aura::RootWindow::GetInstance()->SetProperty(aura::kRootWindowActiveWindow, + NULL); + ActivateWindow(GetTopmostWindowToActivate(window)); + } + window->RemoveObserver(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// ActivationController, aura::RootWindowObserver implementation: + +void ActivationController::OnWindowInitialized(aura::Window* window) { + window->AddObserver(this); +} + +void ActivationController::OnWindowFocused(aura::Window* window) { + ActivateWindow(GetActivatableWindow(window)); +} + +//////////////////////////////////////////////////////////////////////////////// +// ActivationController, private: + +void ActivationController::ActivateNextWindow(aura::Window* window) { + if (IsActiveWindow(window)) + ActivateWindow(GetTopmostWindowToActivate(window)); +} + +aura::Window* ActivationController::GetTopmostWindowToActivate( + aura::Window* ignore) const { + const aura::Window* container = + default_container_for_test_ ? default_container_for_test_ : + GetContainer(kShellWindowId_DefaultContainer); + 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; +} + +} // namespace internal +} // namespace aura_shell diff --git a/ui/aura_shell/activation_controller.h b/ui/aura_shell/activation_controller.h new file mode 100644 index 0000000..226c26c --- /dev/null +++ b/ui/aura_shell/activation_controller.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_SHELL_ACTIVATION_CONTROLLER_H_ +#define UI_AURA_SHELL_ACTIVATION_CONTROLLER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/client/activation_client.h" +#include "ui/aura/root_window_observer.h" +#include "ui/aura/window_observer.h" + +namespace aura_shell { +namespace internal { + +class ActivationController : public aura::ActivationClient, + public aura::WindowObserver, + public aura::RootWindowObserver { + public: + ActivationController(); + virtual ~ActivationController(); + + // Returns true if |window| exists within a container that supports + // activation. + static aura::Window* GetActivatableWindow(aura::Window* window); + + // Overridden from aura::ActivationClient: + virtual void ActivateWindow(aura::Window* window) OVERRIDE; + virtual void DeactivateWindow(aura::Window* window) OVERRIDE; + virtual aura::Window* GetActiveWindow() OVERRIDE; + virtual bool CanFocusWindow(aura::Window* window) const OVERRIDE; + + // Overridden from aura::WindowObserver: + virtual void OnWindowVisibilityChanged(aura::Window* window, + bool visible) OVERRIDE; + virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE; + + // Overridden from aura::RootWindowObserver: + virtual void OnWindowInitialized(aura::Window* window) OVERRIDE; + virtual void OnWindowFocused(aura::Window* window) OVERRIDE; + +#if defined(UNIT_TEST) + void set_default_container_for_test(aura::Window* window) { + default_container_for_test_ = window; + } +#endif + + private: + // Shifts activation to the next window, ignoring |window|. + void ActivateNextWindow(aura::Window* window); + + // Returns the next window that should be activated, ignoring |ignore|. + aura::Window* GetTopmostWindowToActivate(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); +}; + +} // namespace internal +} // namespace aura_shell + +#endif // UI_AURA_SHELL_ACTIVATION_CONTROLLER_H_ diff --git a/ui/aura_shell/activation_controller_unittest.cc b/ui/aura_shell/activation_controller_unittest.cc new file mode 100644 index 0000000..b5529cd --- /dev/null +++ b/ui/aura_shell/activation_controller_unittest.cc @@ -0,0 +1,281 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura_shell/activation_controller.h" + +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/focus_manager.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/test/test_windows.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/aura_shell/test/aura_shell_test_base.h" +#include "ui/aura_shell/test/test_activation_delegate.h" +#include "ui/aura_shell/window_util.h" + +#if defined(OS_WIN) +// Windows headers define macros for these function names which screw with us. +#if defined(CreateWindow) +#undef CreateWindow +#endif +#endif + +namespace aura_shell { +namespace test { + +typedef test::AuraShellTestBase ActivationControllerTest; + +// Utilities for a set of tests that test +// ActivationController::GetTopmostWindowToActivate(). +class GetTopmostWindowToActivateTest : public ActivationControllerTest { + public: + GetTopmostWindowToActivateTest() : ad_1_(false), ad_3_(false) {} + virtual ~GetTopmostWindowToActivateTest() {} + + // Overridden from ActivationControllerTest: + virtual void SetUp() OVERRIDE { + ActivationControllerTest::SetUp(); + CreateWindows(); + } + virtual void TearDown() OVERRIDE { + DestroyWindows(); + ActivationControllerTest::TearDown(); + } + + protected: + aura::Window* w1() { return w1_.get(); } + aura::Window* w2() { return w2_.get(); } + aura::Window* w3() { return w3_.get(); } + aura::Window* w4() { return w4_.get(); } + + void DestroyWindow2() { + w2_.reset(); + } + + private: + 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_)); + } + + aura::Window* CreateWindow(int id, TestActivationDelegate* delegate) { + aura::Window* window = aura::test::CreateTestWindowWithDelegate( + &delegate_, id, gfx::Rect(), NULL); + delegate->SetWindow(window); + return window; + } + + void DestroyWindows() { + w1_.reset(); + w2_.reset(); + w3_.reset(); + w4_.reset(); + } + + aura::test::TestWindowDelegate delegate_; + TestActivationDelegate ad_1_; + TestActivationDelegate ad_2_; + TestActivationDelegate ad_3_; + TestActivationDelegate ad_4_; + 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. + + DISALLOW_COPY_AND_ASSIGN(GetTopmostWindowToActivateTest); +}; + +// Hiding the active window should activate the next valid activatable window. +TEST_F(GetTopmostWindowToActivateTest, HideActivatesNext) { + ActivateWindow(w2()); + EXPECT_TRUE(IsActiveWindow(w2())); + + w2()->Hide(); + EXPECT_TRUE(IsActiveWindow(w4())); +} + +// Destroying the active window should activate the next valid activatable +// window. +TEST_F(GetTopmostWindowToActivateTest, DestroyActivatesNext) { + ActivateWindow(w2()); + EXPECT_TRUE(IsActiveWindow(w2())); + + DestroyWindow2(); + EXPECT_EQ(NULL, w2()); + EXPECT_TRUE(IsActiveWindow(w4())); +} + +// Deactivating the active window should activate the next valid activatable +// window. +TEST_F(GetTopmostWindowToActivateTest, DeactivateActivatesNext) { + ActivateWindow(w2()); + EXPECT_TRUE(IsActiveWindow(w2())); + + DeactivateWindow(w2()); + EXPECT_TRUE(IsActiveWindow(w4())); +} + +// Test if the clicking on a menu picks the transient parent as activatable +// window. +TEST_F(ActivationControllerTest, ClickOnMenu) { + aura::test::TestWindowDelegate wd; + TestActivationDelegate ad1; + TestActivationDelegate ad2(false); + + scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( + &wd, 1, gfx::Rect(100, 100), NULL)); + ad1.SetWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(NULL)); + + // Clicking on an activatable window activtes the window. + aura::test::EventGenerator generator(w1.get()); + generator.ClickLeftButton(); + EXPECT_TRUE(IsActiveWindow(w1.get())); + + // Creates a menu that covers the transient parent. + scoped_ptr<aura::Window> menu(aura::test::CreateTestWindowWithDelegateAndType( + &wd, aura::WINDOW_TYPE_MENU, 2, gfx::Rect(100, 100), NULL)); + ad2.SetWindow(menu.get()); + w1->AddTransientChild(menu.get()); + + // Clicking on a menu whose transient parent is active window shouldn't + // change the active window. + generator.ClickLeftButton(); + EXPECT_TRUE(IsActiveWindow(w1.get())); +} + +// Various assertions for activating/deactivating. +TEST_F(ActivationControllerTest, Deactivate) { + aura::test::TestWindowDelegate d1; + aura::test::TestWindowDelegate d2; + scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( + &d1, 1, gfx::Rect(), NULL)); + scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( + &d2, 2, gfx::Rect(), NULL)); + aura::Window* parent = w1->parent(); + parent->Show(); + ASSERT_TRUE(parent); + ASSERT_EQ(2u, parent->children().size()); + // Activate w2 and make sure it's active and frontmost. + ActivateWindow(w2.get()); + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_FALSE(IsActiveWindow(w1.get())); + EXPECT_EQ(w2.get(), parent->children()[1]); + + // Activate w1 and make sure it's active and frontmost. + ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_FALSE(IsActiveWindow(w2.get())); + EXPECT_EQ(w1.get(), parent->children()[1]); + + // Deactivate w1 and make sure w2 becomes active and frontmost. + DeactivateWindow(w1.get()); + EXPECT_FALSE(IsActiveWindow(w1.get())); + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_EQ(w2.get(), parent->children()[1]); +} + +// Verifies that when WindowDelegate::OnLostActive is invoked the window is not +// active. +TEST_F(ActivationControllerTest, NotActiveInLostActive) { + TestActivationDelegate ad1; + aura::test::TestWindowDelegate wd; + scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( + &wd, 1, gfx::Rect(10, 10, 50, 50), NULL)); + ad1.SetWindow(w1.get()); + scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( + NULL, 1, gfx::Rect(10, 10, 50, 50), NULL)); + + // Activate w1. + ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + + // Should not have gotten a OnLostActive yet. + EXPECT_EQ(0, ad1.lost_active_count()); + + // ActivateWindow(NULL) should not change the active window. + ActivateWindow(NULL); + EXPECT_TRUE(IsActiveWindow(w1.get())); + + // Now activate another window. + ActivateWindow(w2.get()); + + // Should have gotten OnLostActive and w1 should not have been active at that + // time. + EXPECT_EQ(1, ad1.lost_active_count()); + EXPECT_FALSE(ad1.window_was_active()); +} + +// Verifies that focusing another window or its children causes it to become +// active. +TEST_F(ActivationControllerTest, FocusTriggersActivation) { + aura::test::TestWindowDelegate wd; + scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( + &wd, -1, gfx::Rect(50, 50), NULL)); + scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( + &wd, -2, gfx::Rect(50, 50), NULL)); + scoped_ptr<aura::Window> w21(aura::test::CreateTestWindowWithDelegate( + &wd, -21, gfx::Rect(50, 50), w2.get())); + + ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); + + w2->Focus(); + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_TRUE(w2->HasFocus()); + + ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); + + w21->Focus(); + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_TRUE(w21->HasFocus()); +} + +// Verifies that we prevent all attempts to focus a child of a non-activatable +// window from claiming focus to that window. +TEST_F(ActivationControllerTest, PreventFocusToNonActivatableWindow) { + aura::test::TestWindowDelegate wd; + scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( + &wd, -1, gfx::Rect(50, 50), NULL)); + // The RootWindow itself is a non-activatable parent. + scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( + &wd, -2, gfx::Rect(50, 50), aura::RootWindow::GetInstance())); + scoped_ptr<aura::Window> w21(aura::test::CreateTestWindowWithDelegate( + &wd, -21, gfx::Rect(50, 50), w2.get())); + + ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); + + // Try activating |w2|. It's not a child of an activatable container, so it + // should neither be activated nor get focus. + ActivateWindow(w2.get()); + EXPECT_FALSE(IsActiveWindow(w2.get())); + EXPECT_FALSE(w2->HasFocus()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); + + // Try focusing |w2|. Same rules apply. + w2->Focus(); + EXPECT_FALSE(IsActiveWindow(w2.get())); + EXPECT_FALSE(w2->HasFocus()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); + + // Try focusing |w21|. Same rules apply. + EXPECT_FALSE(IsActiveWindow(w2.get())); + EXPECT_FALSE(w21->HasFocus()); + EXPECT_TRUE(IsActiveWindow(w1.get())); + EXPECT_TRUE(w1->HasFocus()); +} + +} // namespace test +} // namespace aura_shell diff --git a/ui/aura_shell/aura_shell.gyp b/ui/aura_shell/aura_shell.gyp index fc4f0d1..23bd5b1 100644 --- a/ui/aura_shell/aura_shell.gyp +++ b/ui/aura_shell/aura_shell.gyp @@ -33,6 +33,8 @@ ], 'sources': [ # All .cc, .h under views, except unittests + 'activation_controller.cc', + 'activation_controller.h', 'always_on_top_controller.cc', 'always_on_top_controller.h', 'app_list.cc', @@ -143,6 +145,7 @@ 'aura_shell', ], 'sources': [ + 'activation_controller_unittest.cc', 'default_container_layout_manager_unittest.cc', 'root_window_event_filter_unittest.cc', 'drag_drop_controller_unittest.cc', @@ -155,11 +158,12 @@ 'shadow_controller_unittest.cc', 'shell_accelerator_controller_unittest.cc', 'shell_unittest.cc', - 'stacking_controller_unittest.cc', 'test_suite.cc', 'test_suite.h', 'test/aura_shell_test_base.cc', 'test/aura_shell_test_base.h', + 'test/test_activation_delegate.cc', + 'test/test_activation_delegate.h', 'toplevel_layout_manager_unittest.cc', 'toplevel_window_event_filter_unittest.cc', 'workspace_controller_unittest.cc', diff --git a/ui/aura_shell/default_container_event_filter.cc b/ui/aura_shell/default_container_event_filter.cc index 725beb8..2f9481c 100644 --- a/ui/aura_shell/default_container_event_filter.cc +++ b/ui/aura_shell/default_container_event_filter.cc @@ -7,8 +7,8 @@ #include "ui/aura/event.h" #include "ui/aura/window.h" #include "ui/aura_shell/default_container_layout_manager.h" -#include "ui/aura_shell/stacking_controller.h" #include "ui/aura_shell/window_frame.h" +#include "ui/aura_shell/window_util.h" #include "ui/base/hit_test.h" namespace { @@ -77,7 +77,7 @@ bool DefaultContainerEventFilter::PreHandleMouseEvent(aura::Window* target, } break; case ui::ET_MOUSE_ENTERED: - UpdateHoveredWindow(StackingController::GetActivatableWindow(target)); + UpdateHoveredWindow(GetActivatableWindow(target)); break; case ui::ET_MOUSE_EXITED: UpdateHoveredWindow(NULL); diff --git a/ui/aura_shell/default_container_layout_manager.cc b/ui/aura_shell/default_container_layout_manager.cc index a9a93be..f3a77e9 100644 --- a/ui/aura_shell/default_container_layout_manager.cc +++ b/ui/aura_shell/default_container_layout_manager.cc @@ -13,6 +13,7 @@ #include "ui/aura/window_types.h" #include "ui/aura_shell/property_util.h" #include "ui/aura_shell/show_state_controller.h" +#include "ui/aura_shell/window_util.h" #include "ui/aura_shell/workspace/workspace.h" #include "ui/aura_shell/workspace/workspace_manager.h" #include "ui/base/ui_base_types.h" @@ -105,7 +106,7 @@ void DefaultContainerLayoutManager::OnWindowAddedToLayout(aura::Window* child) { Workspace* workspace = workspace_manager_->GetActiveWorkspace(); if (workspace) { - aura::Window* active = aura::RootWindow::GetInstance()->active_window(); + aura::Window* active = aura_shell::GetActiveWindow(); // Active window may not be in the default container layer. if (!workspace->Contains(active)) active = NULL; diff --git a/ui/aura_shell/examples/aura_shell_main.cc b/ui/aura_shell/examples/aura_shell_main.cc index d0429c9..0700047 100644 --- a/ui/aura_shell/examples/aura_shell_main.cc +++ b/ui/aura_shell/examples/aura_shell_main.cc @@ -13,6 +13,7 @@ #include "ui/aura_shell/shell.h" #include "ui/aura_shell/shell_delegate.h" #include "ui/aura_shell/shell_factory.h" +#include "ui/aura_shell/window_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" #include "ui/gfx/canvas.h" @@ -74,7 +75,7 @@ class ShellDelegateImpl : public aura_shell::ShellDelegate { virtual void LauncherItemClicked( const aura_shell::LauncherItem& item) OVERRIDE { - item.window->Activate(); + aura_shell::ActivateWindow(item.window); } virtual bool ConfigureLauncherItem(aura_shell::LauncherItem* item) OVERRIDE { diff --git a/ui/aura_shell/modal_container_layout_manager.cc b/ui/aura_shell/modal_container_layout_manager.cc index 9a29337..ccf5f7d 100644 --- a/ui/aura_shell/modal_container_layout_manager.cc +++ b/ui/aura_shell/modal_container_layout_manager.cc @@ -11,7 +11,7 @@ #include "ui/aura/window.h" #include "ui/aura_shell/modality_event_filter.h" #include "ui/aura_shell/shell.h" -#include "ui/aura_shell/stacking_controller.h" +#include "ui/aura_shell/window_util.h" #include "ui/gfx/canvas.h" #include "ui/gfx/compositor/layer.h" #include "ui/gfx/compositor/layer_animator.h" @@ -126,7 +126,7 @@ void ModalContainerLayoutManager::OnLayerAnimationScheduled( bool ModalContainerLayoutManager::CanWindowReceiveEvents( aura::Window* window) { - return StackingController::GetActivatableWindow(window) == modal_window(); + return GetActivatableWindow(window) == modal_window(); } //////////////////////////////////////////////////////////////////////////////// @@ -135,8 +135,6 @@ bool ModalContainerLayoutManager::CanWindowReceiveEvents( void ModalContainerLayoutManager::AddModalWindow(aura::Window* window) { modal_windows_.push_back(window); CreateModalScreen(); - container_->StackChildAtTop(window); - window->Activate(); } void ModalContainerLayoutManager::RemoveModalWindow(aura::Window* window) { @@ -148,7 +146,7 @@ void ModalContainerLayoutManager::RemoveModalWindow(aura::Window* window) { if (modal_windows_.empty()) HideModalScreen(); else - modal_window()->Activate(); + aura_shell::ActivateWindow(modal_window()); } void ModalContainerLayoutManager::CreateModalScreen() { diff --git a/ui/aura_shell/modal_container_layout_manager_unittest.cc b/ui/aura_shell/modal_container_layout_manager_unittest.cc index 6adcce0..228b853 100644 --- a/ui/aura_shell/modal_container_layout_manager_unittest.cc +++ b/ui/aura_shell/modal_container_layout_manager_unittest.cc @@ -11,6 +11,7 @@ #include "ui/aura_shell/shell.h" #include "ui/aura_shell/shell_window_ids.h" #include "ui/aura_shell/test/aura_shell_test_base.h" +#include "ui/aura_shell/window_util.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -81,7 +82,7 @@ class TransientWindowObserver : public aura::WindowObserver { } // namespace -typedef aura_shell::test::AuraShellTestBase ModalContainerLayoutManagerTest; +typedef AuraShellTestBase ModalContainerLayoutManagerTest; TEST_F(ModalContainerLayoutManagerTest, NonModalTransient) { scoped_ptr<aura::Window> parent(TestWindow::OpenTestWindow(NULL, false)); @@ -100,7 +101,7 @@ TEST_F(ModalContainerLayoutManagerTest, NonModalTransient) { TEST_F(ModalContainerLayoutManagerTest, ModalTransient) { scoped_ptr<aura::Window> parent(TestWindow::OpenTestWindow(NULL, false)); // parent should be active. - EXPECT_EQ(parent.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(parent.get())); aura::Window* t1 = TestWindow::OpenTestWindow(parent.get(), true); TransientWindowObserver do1; @@ -110,19 +111,19 @@ TEST_F(ModalContainerLayoutManagerTest, ModalTransient) { EXPECT_EQ(GetModalContainer(), t1->parent()); // t1 should now be active. - EXPECT_EQ(t1, aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(t1)); // Attempting to click the parent should result in no activation change. aura::test::EventGenerator e1(parent.get()); e1.ClickLeftButton(); - EXPECT_EQ(t1, aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(t1)); // Now open another modal transient parented to the original modal transient. aura::Window* t2 = TestWindow::OpenTestWindow(t1, true); TransientWindowObserver do2; t2->AddObserver(&do2); - EXPECT_EQ(t2, aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(t2)); EXPECT_EQ(t1, t2->transient_parent()); EXPECT_EQ(GetModalContainer(), t2->parent()); @@ -130,7 +131,7 @@ TEST_F(ModalContainerLayoutManagerTest, ModalTransient) { // t2 should still be active, even after clicking on t1. aura::test::EventGenerator e2(t1); e2.ClickLeftButton(); - EXPECT_EQ(t2, aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(t2)); // Both transients should be destroyed with parent. parent.reset(); @@ -145,28 +146,28 @@ TEST_F(ModalContainerLayoutManagerTest, CanActivateAfterEndModalSession) { unrelated->SetBounds(gfx::Rect(100, 100, 50, 50)); scoped_ptr<aura::Window> parent(TestWindow::OpenTestWindow(NULL, false)); // parent should be active. - EXPECT_EQ(parent.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(parent.get())); scoped_ptr<aura::Window> transient( TestWindow::OpenTestWindow(parent.get(), true)); // t1 should now be active. - EXPECT_EQ(transient.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(transient.get())); // Attempting to click the parent should result in no activation change. aura::test::EventGenerator e1(parent.get()); e1.ClickLeftButton(); - EXPECT_EQ(transient.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(transient.get())); // Now close the transient. transient.reset(); // parent should now be active again. - EXPECT_EQ(parent.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(parent.get())); // Attempting to click unrelated should activate it. aura::test::EventGenerator e2(unrelated.get()); e2.ClickLeftButton(); - EXPECT_EQ(unrelated.get(), aura::RootWindow::GetInstance()->active_window()); + EXPECT_TRUE(IsActiveWindow(unrelated.get())); } } // namespace test diff --git a/ui/aura_shell/root_window_event_filter.cc b/ui/aura_shell/root_window_event_filter.cc index 9d1f3db..b627341 100644 --- a/ui/aura_shell/root_window_event_filter.cc +++ b/ui/aura_shell/root_window_event_filter.cc @@ -8,8 +8,9 @@ #include "ui/aura/focus_manager.h" #include "ui/aura/root_window.h" #include "ui/aura/window_delegate.h" +#include "ui/aura_shell/activation_controller.h" #include "ui/aura_shell/shell.h" -#include "ui/aura_shell/stacking_controller.h" +#include "ui/aura_shell/window_util.h" #include "ui/base/hit_test.h" namespace aura_shell { @@ -79,7 +80,7 @@ bool RootWindowEventFilter::PreHandleMouseEvent(aura::Window* target, return true; if (event->type() == ui::ET_MOUSE_PRESSED) - ActivateIfNecessary(target, event); + target->GetFocusManager()->SetFocusedWindow(target); return false; } @@ -92,24 +93,13 @@ ui::TouchStatus RootWindowEventFilter::PreHandleTouchEvent( return status; if (event->type() == ui::ET_TOUCH_PRESSED) - ActivateIfNecessary(target, event); + target->GetFocusManager()->SetFocusedWindow(target); return ui::TOUCH_STATUS_UNKNOWN; } //////////////////////////////////////////////////////////////////////////////// // RootWindowEventFilter, private: -void RootWindowEventFilter::ActivateIfNecessary(aura::Window* window, - aura::Event* event) { - aura::Window* activatable = StackingController::GetActivatableWindow(window); - if (activatable == aura::RootWindow::GetInstance()->active_window()) { - // |window| is a descendant of the active window, no need to activate. - window->GetFocusManager()->SetFocusedWindow(window); - } else { - aura::RootWindow::GetInstance()->SetActiveWindow(activatable, window); - } -} - void RootWindowEventFilter::UpdateCursor(aura::Window* target, aura::MouseEvent* event) { gfx::NativeCursor cursor = target->GetCursor(event->location()); diff --git a/ui/aura_shell/root_window_event_filter.h b/ui/aura_shell/root_window_event_filter.h index 20afc03..8392aa4 100644 --- a/ui/aura_shell/root_window_event_filter.h +++ b/ui/aura_shell/root_window_event_filter.h @@ -40,14 +40,11 @@ class AURA_SHELL_EXPORT RootWindowEventFilter : public aura::EventFilter { aura::TouchEvent* event) OVERRIDE; private: - // If necessary, activates |window| and changes focus. - void ActivateIfNecessary(aura::Window* window, aura::Event* event); - // Updates the cursor if the target provides a custom one, and provides // default resize cursors for window edges. void UpdateCursor(aura::Window* target, aura::MouseEvent* event); - // Dispatches event to addtional filters. Returns false or + // Dispatches event to additional filters. Returns false or // ui::TOUCH_STATUS_UNKNOWN if event is consumed. bool FilterKeyEvent(aura::Window* target, aura::KeyEvent* event); bool FilterMouseEvent(aura::Window* target, aura::MouseEvent* event); diff --git a/ui/aura_shell/root_window_event_filter_unittest.cc b/ui/aura_shell/root_window_event_filter_unittest.cc index 0f4302b..d53cdc8 100644 --- a/ui/aura_shell/root_window_event_filter_unittest.cc +++ b/ui/aura_shell/root_window_event_filter_unittest.cc @@ -4,6 +4,8 @@ #include "ui/aura_shell/root_window_event_filter.h" +#include "ui/aura/client/activation_delegate.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/cursor.h" #include "ui/aura/event.h" #include "ui/aura/root_window.h" @@ -13,7 +15,10 @@ #include "ui/aura/test/test_event_filter.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_stacking_client.h" +#include "ui/aura_shell/activation_controller.h" #include "ui/aura_shell/shell_window_ids.h" +#include "ui/aura_shell/test/test_activation_delegate.h" +#include "ui/aura_shell/window_util.h" #include "ui/base/hit_test.h" #include "ui/gfx/screen.h" @@ -31,12 +36,17 @@ class RootWindowEventFilterTest : public aura::test::AuraTestBase { aura::RootWindow::GetInstance()->stacking_client()); stacking_client->default_container()->set_id( internal::kShellWindowId_DefaultContainer); + activation_controller_.reset(new internal::ActivationController); + activation_controller_->set_default_container_for_test( + stacking_client->default_container()); } virtual ~RootWindowEventFilterTest() { aura::RootWindow::GetInstance()->SetEventFilter(NULL); } private: + scoped_ptr<internal::ActivationController> activation_controller_; + DISALLOW_COPY_AND_ASSIGN(RootWindowEventFilterTest); }; @@ -124,63 +134,72 @@ TEST_F(RootWindowEventFilterTest, Focus) { TEST_F(RootWindowEventFilterTest, ActivateOnMouse) { aura::RootWindow* root_window = aura::RootWindow::GetInstance(); - aura::test::ActivateWindowDelegate d1; + TestActivationDelegate d1; + aura::test::TestWindowDelegate wd; scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( - &d1, 1, gfx::Rect(10, 10, 50, 50), NULL)); - aura::test::ActivateWindowDelegate d2; + &wd, 1, gfx::Rect(10, 10, 50, 50), NULL)); + d1.SetWindow(w1.get()); + TestActivationDelegate d2; scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( - &d2, 2, gfx::Rect(70, 70, 50, 50), NULL)); + &wd, 2, gfx::Rect(70, 70, 50, 50), NULL)); + d2.SetWindow(w2.get()); + aura::internal::FocusManager* focus_manager = w1->GetFocusManager(); d1.Clear(); d2.Clear(); // Activate window1. - root_window->SetActiveWindow(w1.get(), NULL); - EXPECT_EQ(w1.get(), root_window->active_window()); + aura_shell::ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); EXPECT_EQ(0, d1.lost_active_count()); d1.Clear(); - // Click on window2. - gfx::Point press_point = w2->bounds().CenterPoint(); - aura::Window::ConvertPointToWindow(w2->parent(), root_window, &press_point); - aura::test::EventGenerator generator(press_point); - generator.ClickLeftButton(); - - // Window2 should have become active. - EXPECT_EQ(w2.get(), root_window->active_window()); - EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); - EXPECT_EQ(0, d1.activated_count()); - EXPECT_EQ(1, d1.lost_active_count()); - EXPECT_EQ(1, d2.activated_count()); - EXPECT_EQ(0, d2.lost_active_count()); - d1.Clear(); - d2.Clear(); - - // Click back on window1, but set it up so w1 doesn't activate on click. - press_point = w1->bounds().CenterPoint(); - aura::Window::ConvertPointToWindow(w1->parent(), root_window, &press_point); - d1.set_activate(false); - generator.ClickLeftButton(); + { + // Click on window2. + gfx::Point press_point = w2->bounds().CenterPoint(); + aura::Window::ConvertPointToWindow(w2->parent(), root_window, &press_point); + aura::test::EventGenerator generator(press_point); + generator.ClickLeftButton(); + + // Window2 should have become active. + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); + EXPECT_EQ(0, d1.activated_count()); + EXPECT_EQ(1, d1.lost_active_count()); + EXPECT_EQ(1, d2.activated_count()); + EXPECT_EQ(0, d2.lost_active_count()); + d1.Clear(); + d2.Clear(); + } - // Window2 should still be active and focused. - EXPECT_EQ(w2.get(), root_window->active_window()); - EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); - EXPECT_EQ(0, d1.activated_count()); - EXPECT_EQ(0, d1.lost_active_count()); - EXPECT_EQ(0, d2.activated_count()); - EXPECT_EQ(0, d2.lost_active_count()); - d1.Clear(); - d2.Clear(); + { + // Click back on window1, but set it up so w1 doesn't activate on click. + gfx::Point press_point = w1->bounds().CenterPoint(); + aura::Window::ConvertPointToWindow(w1->parent(), root_window, &press_point); + aura::test::EventGenerator generator(press_point); + d1.set_activate(false); + generator.ClickLeftButton(); + + // Window2 should still be active and focused. + EXPECT_TRUE(IsActiveWindow(w2.get())); + EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); + EXPECT_EQ(0, d1.activated_count()); + EXPECT_EQ(0, d1.lost_active_count()); + EXPECT_EQ(0, d2.activated_count()); + EXPECT_EQ(0, d2.lost_active_count()); + d1.Clear(); + d2.Clear(); + } // Destroy window2, this should make window1 active. d1.set_activate(true); w2.reset(); EXPECT_EQ(0, d2.activated_count()); EXPECT_EQ(0, d2.lost_active_count()); - EXPECT_EQ(w1.get(), root_window->active_window()); + EXPECT_TRUE(IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); EXPECT_EQ(0, d1.lost_active_count()); @@ -190,20 +209,24 @@ TEST_F(RootWindowEventFilterTest, ActivateOnMouse) { TEST_F(RootWindowEventFilterTest, ActivateOnTouch) { aura::RootWindow* root_window = aura::RootWindow::GetInstance(); - aura::test::ActivateWindowDelegate d1; + TestActivationDelegate d1; + aura::test::TestWindowDelegate wd; scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( - &d1, -1, gfx::Rect(10, 10, 50, 50), NULL)); - aura::test::ActivateWindowDelegate d2; + &wd, -1, gfx::Rect(10, 10, 50, 50), NULL)); + d1.SetWindow(w1.get()); + TestActivationDelegate d2; scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( - &d2, -2, gfx::Rect(70, 70, 50, 50), NULL)); + &wd, -2, gfx::Rect(70, 70, 50, 50), NULL)); + d2.SetWindow(w2.get()); + aura::internal::FocusManager* focus_manager = w1->GetFocusManager(); d1.Clear(); d2.Clear(); // Activate window1. - root_window->SetActiveWindow(w1.get(), NULL); - EXPECT_EQ(w1.get(), root_window->active_window()); + aura_shell::ActivateWindow(w1.get()); + EXPECT_TRUE(IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); EXPECT_EQ(0, d1.lost_active_count()); @@ -216,7 +239,7 @@ TEST_F(RootWindowEventFilterTest, ActivateOnTouch) { root_window->DispatchTouchEvent(&touchev1); // Window2 should have become active. - EXPECT_EQ(w2.get(), root_window->active_window()); + EXPECT_TRUE(IsActiveWindow(w2.get())); EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(0, d1.activated_count()); EXPECT_EQ(1, d1.lost_active_count()); @@ -233,7 +256,7 @@ TEST_F(RootWindowEventFilterTest, ActivateOnTouch) { root_window->DispatchTouchEvent(&touchev2); // Window2 should still be active and focused. - EXPECT_EQ(w2.get(), root_window->active_window()); + EXPECT_TRUE(IsActiveWindow(w2.get())); EXPECT_EQ(w2.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(0, d1.activated_count()); EXPECT_EQ(0, d1.lost_active_count()); @@ -247,7 +270,7 @@ TEST_F(RootWindowEventFilterTest, ActivateOnTouch) { w2.reset(); EXPECT_EQ(0, d2.activated_count()); EXPECT_EQ(0, d2.lost_active_count()); - EXPECT_EQ(w1.get(), root_window->active_window()); + EXPECT_TRUE(IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_manager->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); EXPECT_EQ(0, d1.lost_active_count()); @@ -329,9 +352,11 @@ TEST_F(RootWindowEventFilterTest, TransformActivate) { transform.ConcatTranslate(size.width(), 0); root_window->SetTransform(transform); - aura::test::ActivateWindowDelegate d1; + TestActivationDelegate d1; + aura::test::TestWindowDelegate wd; scoped_ptr<aura::Window> w1( - CreateTestWindowWithDelegate(&d1, 1, gfx::Rect(0, 10, 50, 50), NULL)); + CreateTestWindowWithDelegate(&wd, 1, gfx::Rect(0, 10, 50, 50), NULL)); + d1.SetWindow(w1.get()); w1->Show(); gfx::Point miss_point(5, 5); @@ -352,7 +377,7 @@ TEST_F(RootWindowEventFilterTest, TransformActivate) { hit_point, ui::EF_LEFT_BUTTON_DOWN); root_window->DispatchMouseEvent(&mouseev2); - EXPECT_EQ(w1.get(), root_window->active_window()); + EXPECT_TRUE(IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), w1->GetFocusManager()->GetFocusedWindow()); } @@ -362,7 +387,7 @@ TEST_F(RootWindowEventFilterTest, AdditionalFilters) { // Creates a window and make it active scoped_ptr<aura::Window> w1(aura::test::CreateTestWindow( SK_ColorWHITE, -1, gfx::Rect(0, 0, 100, 100), NULL)); - root_window->SetActiveWindow(w1.get(), NULL); + aura_shell::ActivateWindow(w1.get()); // Creates two addition filters scoped_ptr<aura::test::TestEventFilter> f1( diff --git a/ui/aura_shell/shadow_controller.cc b/ui/aura_shell/shadow_controller.cc index b93876e..46670ff 100644 --- a/ui/aura_shell/shadow_controller.cc +++ b/ui/aura_shell/shadow_controller.cc @@ -19,7 +19,7 @@ namespace aura_shell { namespace internal { ShadowController::ShadowController() { - aura::RootWindow::GetInstance()->AddObserver(this); + aura::RootWindow::GetInstance()->AddRootWindowObserver(this); } ShadowController::~ShadowController() { @@ -27,7 +27,7 @@ ShadowController::~ShadowController() { it != window_shadows_.end(); ++it) { it->first->RemoveObserver(this); } - aura::RootWindow::GetInstance()->RemoveObserver(this); + aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this); } void ShadowController::OnWindowInitialized(aura::Window* window) { diff --git a/ui/aura_shell/shell.cc b/ui/aura_shell/shell.cc index cf55c7bb..87be5ac 100644 --- a/ui/aura_shell/shell.cc +++ b/ui/aura_shell/shell.cc @@ -13,6 +13,7 @@ #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" #include "ui/aura/window_types.h" +#include "ui/aura_shell/activation_controller.h" #include "ui/aura_shell/app_list.h" #include "ui/aura_shell/default_container_event_filter.h" #include "ui/aura_shell/default_container_layout_manager.h" @@ -178,6 +179,8 @@ void Shell::Init() { aura::RootWindow* root_window = aura::RootWindow::GetInstance(); root_window->SetCursor(aura::kCursorPointer); + activation_controller_.reset(new internal::ActivationController); + aura::Window::Windows containers; CreateSpecialContainers(&containers); aura::Window::Windows::const_iterator i; diff --git a/ui/aura_shell/shell.h b/ui/aura_shell/shell.h index a877863..cbb904e 100644 --- a/ui/aura_shell/shell.h +++ b/ui/aura_shell/shell.h @@ -32,6 +32,7 @@ class ShellDelegate; class ShellTooltipManager; namespace internal { +class ActivationController; class AppList; class DragDropController; class ShadowController; @@ -109,6 +110,7 @@ class AURA_SHELL_EXPORT Shell { scoped_ptr<internal::AppList> app_list_; + scoped_ptr<internal::ActivationController> activation_controller_; scoped_ptr<internal::DragDropController> drag_drop_controller_; scoped_ptr<internal::WorkspaceController> workspace_controller_; scoped_ptr<internal::ShadowController> shadow_controller_; diff --git a/ui/aura_shell/stacking_controller.cc b/ui/aura_shell/stacking_controller.cc index 08c7da8..dba6da1 100644 --- a/ui/aura_shell/stacking_controller.cc +++ b/ui/aura_shell/stacking_controller.cc @@ -19,14 +19,6 @@ aura::Window* GetContainer(int id) { return Shell::GetInstance()->GetContainer(id); } -// Returns true if children of |window| can be activated. -bool SupportsChildActivation(aura::Window* window) { - return window->id() == kShellWindowId_DefaultContainer || - window->id() == kShellWindowId_AlwaysOnTopContainer || - window->id() == kShellWindowId_ModalContainer || - window->id() == kShellWindowId_LockModalContainer; -} - bool IsWindowModal(aura::Window* window) { return window->transient_parent() && window->GetIntProperty(aura::kModalKey); } @@ -50,23 +42,6 @@ void StackingController::Init() { GetContainer(internal::kShellWindowId_AlwaysOnTopContainer)); } -// static -aura::Window* StackingController::GetActivatableWindow(aura::Window* window) { - aura::Window* parent = window->parent(); - aura::Window* child = window; - while (parent) { - if (SupportsChildActivation(parent)) - return child; - // If |child| isn't activatable, but has transient parent, trace - // that path instead. - if (child->transient_parent()) - return GetActivatableWindow(child->transient_parent()); - parent = parent->parent(); - child = child->parent(); - } - return NULL; -} - //////////////////////////////////////////////////////////////////////////////// // StackingController, aura::StackingClient implementation: @@ -93,24 +68,6 @@ void StackingController::AddChildToDefaultParent(aura::Window* window) { parent->AddChild(window); } -bool StackingController::CanActivateWindow(aura::Window* window) const { - return window && SupportsChildActivation(window->parent()); -} - -aura::Window* StackingController::GetTopmostWindowToActivate( - aura::Window* ignore) const { - const aura::Window* container = GetContainer(kShellWindowId_DefaultContainer); - for (aura::Window::Windows::const_reverse_iterator i = - container->children().rbegin(); - i != container->children().rend(); - ++i) { - if (*i != ignore && (*i)->CanActivate()) - return *i; - } - return NULL; -} - - //////////////////////////////////////////////////////////////////////////////// // StackingController, private: diff --git a/ui/aura_shell/stacking_controller.h b/ui/aura_shell/stacking_controller.h index 7be9966..d7b2edd 100644 --- a/ui/aura_shell/stacking_controller.h +++ b/ui/aura_shell/stacking_controller.h @@ -24,15 +24,8 @@ class StackingController : public aura::StackingClient { // Initializes this controller. void Init(); - // Returns true if |window| exists within a container that supports - // activation. - static aura::Window* GetActivatableWindow(aura::Window* window); - // Overridden from aura::StackingClient: virtual void AddChildToDefaultParent(aura::Window* window) OVERRIDE; - virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE; - virtual aura::Window* GetTopmostWindowToActivate( - aura::Window* ignore) const OVERRIDE; private: // Returns corresponding modal container for a modal window. diff --git a/ui/aura_shell/stacking_controller_unittest.cc b/ui/aura_shell/stacking_controller_unittest.cc index 5b8fa09..e69de29 100644 --- a/ui/aura_shell/stacking_controller_unittest.cc +++ b/ui/aura_shell/stacking_controller_unittest.cc @@ -1,59 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/aura_shell/stacking_controller.h" - -#include "ui/aura/root_window.h" -#include "ui/aura/test/event_generator.h" -#include "ui/aura/test/test_windows.h" -#include "ui/aura/test/test_window_delegate.h" -#include "ui/aura_shell/test/aura_shell_test_base.h" - -namespace aura_shell { -namespace test { - -typedef aura_shell::test::AuraShellTestBase StackingControllerTest; - -TEST_F(StackingControllerTest, GetTopmostWindowToActivate) { - aura::test::ActivateWindowDelegate activate; - aura::test::ActivateWindowDelegate non_activate(false); - - scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( - &non_activate, 1, gfx::Rect(), NULL)); - scoped_ptr<aura::Window> w2(aura::test::CreateTestWindowWithDelegate( - &activate, 2, gfx::Rect(), NULL)); - scoped_ptr<aura::Window> w3(aura::test::CreateTestWindowWithDelegate( - &non_activate, 3, gfx::Rect(), NULL)); - EXPECT_EQ(w2.get(), aura::RootWindow::GetInstance()->stacking_client()-> - GetTopmostWindowToActivate(NULL)); -} - -// Test if the clicking on a menu picks the transient parent as activatable -// window. -TEST_F(StackingControllerTest, ClickOnMenu) { - aura::test::ActivateWindowDelegate activate; - aura::test::ActivateWindowDelegate non_activate(false); - - scoped_ptr<aura::Window> w1(aura::test::CreateTestWindowWithDelegate( - &activate, 1, gfx::Rect(100, 100), NULL)); - EXPECT_EQ(NULL, aura::RootWindow::GetInstance()->active_window()); - - // Clicking on an activatable window activtes the window. - aura::test::EventGenerator generator(w1.get()); - generator.ClickLeftButton(); - EXPECT_EQ(w1.get(), aura::RootWindow::GetInstance()->active_window()); - - // Creates a menu that covers the transient parent. - scoped_ptr<aura::Window> menu(aura::test::CreateTestWindowWithDelegateAndType( - &non_activate, aura::WINDOW_TYPE_MENU, 2, gfx::Rect(100, 100), NULL)); - w1->AddTransientChild(menu.get()); - - // Clicking on a menu whose transient parent is active window shouldn't - // change the active window. - generator.ClickLeftButton(); - EXPECT_EQ(w1.get(), aura::RootWindow::GetInstance()->active_window()); -} - -} // namespace test -} // namespace aura_shell diff --git a/ui/aura_shell/test/test_activation_delegate.cc b/ui/aura_shell/test/test_activation_delegate.cc new file mode 100644 index 0000000..ac63bdb --- /dev/null +++ b/ui/aura_shell/test/test_activation_delegate.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/aura_shell/test/test_activation_delegate.h" + +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" +#include "ui/aura_shell/window_util.h" + +namespace aura_shell { +namespace test { + +//////////////////////////////////////////////////////////////////////////////// +// TestActivationDelegate + +TestActivationDelegate::TestActivationDelegate() + : window_(NULL), + window_was_active_(false), + activate_(true), + activated_count_(0), + lost_active_count_(0), + should_activate_count_(0) { +} + +TestActivationDelegate::TestActivationDelegate(bool activate) + : window_(NULL), + window_was_active_(false), + activate_(activate), + activated_count_(0), + lost_active_count_(0), + should_activate_count_(0) { +} + +void TestActivationDelegate::SetWindow(aura::Window* window) { + window_ = window; + aura::ActivationDelegate::SetActivationDelegate(window, this); +} + +bool TestActivationDelegate::ShouldActivate(aura::Event* event) { + should_activate_count_++; + return activate_; +} +void TestActivationDelegate::OnActivated() { + activated_count_++; +} +void TestActivationDelegate::OnLostActive() { + if (lost_active_count_++ == 0) + window_was_active_ = IsActiveWindow(window_); +} + +} // namespace test +} // namespace aura_shell diff --git a/ui/aura_shell/test/test_activation_delegate.h b/ui/aura_shell/test/test_activation_delegate.h new file mode 100644 index 0000000..d3f1c85 --- /dev/null +++ b/ui/aura_shell/test/test_activation_delegate.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_AURA_SHELL_TEST_TEST_ACTIVATION_DELEGATE_H_ +#define UI_AURA_SHELL_TEST_TEST_ACTIVATION_DELEGATE_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "ui/aura/client/activation_delegate.h" + +namespace aura { +class Window; +} + +namespace aura_shell { +namespace test { + +// A test ActivationDelegate that can be used to track activation changes for +// an aura::Window. +class TestActivationDelegate : public aura::ActivationDelegate { + public: + TestActivationDelegate(); + explicit TestActivationDelegate(bool activate); + + // Associates this delegate with a Window. + void SetWindow(aura::Window* window); + + bool window_was_active() const { return window_was_active_; } + void set_activate(bool v) { activate_ = v; } + int activated_count() const { return activated_count_; } + int lost_active_count() const { return lost_active_count_; } + int should_activate_count() const { return should_activate_count_; } + void Clear() { + activated_count_ = lost_active_count_ = should_activate_count_ = 0; + window_was_active_ = false; + } + + // Overridden from ActivationDelegate: + virtual bool ShouldActivate(aura::Event* event) OVERRIDE; + virtual void OnActivated() OVERRIDE; + virtual void OnLostActive() OVERRIDE; + + private: + aura::Window* window_; + bool window_was_active_; + bool activate_; + int activated_count_; + int lost_active_count_; + int should_activate_count_; + + DISALLOW_COPY_AND_ASSIGN(TestActivationDelegate); +}; + +} // namespace test +} // namespace aura_shell + +#endif // UI_AURA_SHELL_TEST_TEST_ACTIVATION_DELEGATE_H_ diff --git a/ui/aura_shell/window_util.cc b/ui/aura_shell/window_util.cc index 68fcab7..82e9875 100644 --- a/ui/aura_shell/window_util.cc +++ b/ui/aura_shell/window_util.cc @@ -4,8 +4,11 @@ #include "ui/aura_shell/window_util.h" -#include "ui/aura/window.h" +#include "ui/aura/client/activation_client.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/aura_shell/activation_controller.h" #include "ui/base/ui_base_types.h" namespace aura_shell { @@ -15,4 +18,24 @@ bool IsWindowMaximized(aura::Window* window) { ui::SHOW_STATE_MAXIMIZED; } +void ActivateWindow(aura::Window* window) { + aura::ActivationClient::GetActivationClient()->ActivateWindow(window); +} + +void DeactivateWindow(aura::Window* window) { + aura::ActivationClient::GetActivationClient()->DeactivateWindow(window); +} + +bool IsActiveWindow(aura::Window* window) { + return GetActiveWindow() == window; +} + +aura::Window* GetActiveWindow() { + return aura::ActivationClient::GetActivationClient()->GetActiveWindow(); +} + +aura::Window* GetActivatableWindow(aura::Window* window) { + return internal::ActivationController::GetActivatableWindow(window); +} + } // namespace aura_shell diff --git a/ui/aura_shell/window_util.h b/ui/aura_shell/window_util.h index 1550510..0c95912 100644 --- a/ui/aura_shell/window_util.h +++ b/ui/aura_shell/window_util.h @@ -17,6 +17,19 @@ namespace aura_shell { // Returns true if |window| is in the maximized state. AURA_SHELL_EXPORT bool IsWindowMaximized(aura::Window* window); +// Convenience setters/getters for |aura::kRootWindowActiveWindow|. +AURA_SHELL_EXPORT void ActivateWindow(aura::Window* window); +AURA_SHELL_EXPORT void DeactivateWindow(aura::Window* window); +AURA_SHELL_EXPORT bool IsActiveWindow(aura::Window* window); +AURA_SHELL_EXPORT aura::Window* GetActiveWindow(); + +// Retrieves the activatable window for |window|. If |window| is activatable, +// this will just return it, otherwise it will climb the parent/transient parent +// chain looking for a window that is activatable, per the ActivationController. +// If you're looking for a function to get the activatable "top level" window, +// this is probably what you're looking for. +AURA_SHELL_EXPORT aura::Window* GetActivatableWindow(aura::Window* window); + } // namespace aura_shell #endif // UI_AURA_SHELL_WINDOW_UTIL_H_ diff --git a/ui/aura_shell/workspace/workspace.cc b/ui/aura_shell/workspace/workspace.cc index ba25771..be969b8 100644 --- a/ui/aura_shell/workspace/workspace.cc +++ b/ui/aura_shell/workspace/workspace.cc @@ -11,6 +11,7 @@ #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura_shell/property_util.h" +#include "ui/aura_shell/window_util.h" #include "ui/aura_shell/workspace/workspace_manager.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/compositor/layer.h" @@ -95,7 +96,7 @@ bool Workspace::Contains(aura::Window* window) const { aura::Window* Workspace::FindRotateWindowForLocation( const gfx::Point& position) { - aura::Window* active = aura::RootWindow::GetInstance()->active_window(); + aura::Window* active = aura_shell::GetActiveWindow(); if (GetTotalWindowsWidth() < bounds_.width()) { // If all windows fit to the width of the workspace, it returns the // window which contains |position|'s x coordinate. diff --git a/ui/aura_shell/workspace/workspace_manager_unittest.cc b/ui/aura_shell/workspace/workspace_manager_unittest.cc index d54fb2d..91e72b5 100644 --- a/ui/aura_shell/workspace/workspace_manager_unittest.cc +++ b/ui/aura_shell/workspace/workspace_manager_unittest.cc @@ -10,6 +10,8 @@ #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_stacking_client.h" #include "ui/aura/window.h" +#include "ui/aura_shell/activation_controller.h" +#include "ui/aura_shell/shell_window_ids.h" #include "ui/aura_shell/workspace/workspace.h" #include "ui/aura_shell/workspace/workspace_observer.h" #include "ui/base/ui_base_types.h" @@ -77,7 +79,16 @@ namespace internal { class WorkspaceManagerTestBase : public aura::test::AuraTestBase { public: - WorkspaceManagerTestBase() {} + WorkspaceManagerTestBase() { + aura::test::TestStackingClient* stacking_client = + static_cast<aura::test::TestStackingClient*>( + aura::RootWindow::GetInstance()->stacking_client()); + stacking_client->default_container()->set_id( + internal::kShellWindowId_DefaultContainer); + activation_controller_.reset(new internal::ActivationController); + activation_controller_->set_default_container_for_test( + stacking_client->default_container()); + } virtual ~WorkspaceManagerTestBase() {} virtual void SetUp() OVERRIDE { @@ -102,6 +113,8 @@ class WorkspaceManagerTestBase : public aura::test::AuraTestBase { scoped_ptr<WorkspaceManager> manager_; private: + scoped_ptr<internal::ActivationController> activation_controller_; + DISALLOW_COPY_AND_ASSIGN(WorkspaceManagerTestBase); }; diff --git a/ui/aura_shell/workspace_controller.cc b/ui/aura_shell/workspace_controller.cc index b8c8bf1..39dbaf1 100644 --- a/ui/aura_shell/workspace_controller.cc +++ b/ui/aura_shell/workspace_controller.cc @@ -4,12 +4,14 @@ #include "ui/aura_shell/workspace_controller.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura_shell/default_container_layout_manager.h" #include "ui/aura_shell/launcher/launcher.h" #include "ui/aura_shell/launcher/launcher_model.h" #include "ui/aura_shell/shell.h" +#include "ui/aura_shell/window_util.h" #include "ui/aura_shell/workspace/workspace.h" #include "ui/aura_shell/workspace/workspace_manager.h" @@ -21,6 +23,7 @@ WorkspaceController::WorkspaceController(aura::Window* viewport) launcher_model_(NULL), ignore_move_event_(false) { workspace_manager_->AddObserver(this); + aura::RootWindow::GetInstance()->AddRootWindowObserver(this); aura::RootWindow::GetInstance()->AddObserver(this); } @@ -29,6 +32,7 @@ WorkspaceController::~WorkspaceController() { if (launcher_model_) launcher_model_->RemoveObserver(this); aura::RootWindow::GetInstance()->RemoveObserver(this); + aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this); } void WorkspaceController::ToggleOverview() { @@ -48,11 +52,18 @@ void WorkspaceController::OnRootWindowResized(const gfx::Size& new_size) { workspace_manager_->SetWorkspaceSize(new_size); } -void WorkspaceController::OnActiveWindowChanged(aura::Window* active) { - // FindBy handles NULL. - Workspace* workspace = workspace_manager_->FindBy(active); - if (workspace) - workspace->Activate(); +//////////////////////////////////////////////////////////////////////////////// +// WorkspaceController, aura::WindowObserver overrides: + +void WorkspaceController::OnWindowPropertyChanged(aura::Window* window, + const char* key, + void* old) { + if (key == aura::kRootWindowActiveWindow) { + // FindBy handles NULL. + Workspace* workspace = workspace_manager_->FindBy(GetActiveWindow()); + if (workspace) + workspace->Activate(); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/ui/aura_shell/workspace_controller.h b/ui/aura_shell/workspace_controller.h index e41899e..fd9e311 100644 --- a/ui/aura_shell/workspace_controller.h +++ b/ui/aura_shell/workspace_controller.h @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "ui/aura/root_window_observer.h" +#include "ui/aura/window_observer.h" #include "ui/aura_shell/aura_shell_export.h" #include "ui/aura_shell/launcher/launcher_model_observer.h" #include "ui/aura_shell/workspace/workspace_observer.h" @@ -33,6 +34,7 @@ class WorkspaceManager; // a move event between Laucher and Workspace. class AURA_SHELL_EXPORT WorkspaceController : public aura::RootWindowObserver, + public aura::WindowObserver, public aura_shell::internal::WorkspaceObserver, public aura_shell::LauncherModelObserver { public: @@ -48,9 +50,13 @@ class AURA_SHELL_EXPORT WorkspaceController : return workspace_manager_.get(); } - // RootWindowObserver overrides: + // aura::RootWindowObserver overrides: virtual void OnRootWindowResized(const gfx::Size& new_size) OVERRIDE; - virtual void OnActiveWindowChanged(aura::Window* active) OVERRIDE; + + // aura::WindowObserver overrides: + virtual void OnWindowPropertyChanged(aura::Window* window, + const char* key, + void* old) OVERRIDE; // WorkspaceObserver overrides: virtual void WindowMoved(WorkspaceManager* manager, diff --git a/ui/aura_shell/workspace_controller_unittest.cc b/ui/aura_shell/workspace_controller_unittest.cc index 7128a40..ab009d2 100644 --- a/ui/aura_shell/workspace_controller_unittest.cc +++ b/ui/aura_shell/workspace_controller_unittest.cc @@ -7,6 +7,9 @@ #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_stacking_client.h" #include "ui/aura/window.h" +#include "ui/aura_shell/activation_controller.h" +#include "ui/aura_shell/shell_window_ids.h" +#include "ui/aura_shell/window_util.h" #include "ui/aura_shell/workspace/workspace.h" #include "ui/aura_shell/workspace/workspace_manager.h" @@ -23,10 +26,17 @@ class WorkspaceControllerTest : public aura::test::AuraTestBase { virtual void SetUp() OVERRIDE { aura::test::AuraTestBase::SetUp(); contents_view_ = GetTestStackingClient()->default_container(); + // Activatable windows need to be in a container the ActivationController + // recognizes. + contents_view_->set_id( + aura_shell::internal::kShellWindowId_DefaultContainer); + activation_controller_.reset(new ActivationController); + activation_controller_->set_default_container_for_test(contents_view_); controller_.reset(new WorkspaceController(contents_view_)); } virtual void TearDown() OVERRIDE { + activation_controller_.reset(); controller_.reset(); aura::test::AuraTestBase::TearDown(); } @@ -39,7 +49,7 @@ class WorkspaceControllerTest : public aura::test::AuraTestBase { return window; } - aura::Window * contents_view() { + aura::Window* contents_view() { return contents_view_; } @@ -52,6 +62,8 @@ class WorkspaceControllerTest : public aura::test::AuraTestBase { private: aura::Window* contents_view_; + scoped_ptr<ActivationController> activation_controller_; + DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest); }; @@ -69,7 +81,7 @@ TEST_F(WorkspaceControllerTest, Overview) { EXPECT_TRUE(ws2->AddWindowAfter(w2.get(), NULL)); // Activating a window switches the active workspace. - w2->Activate(); + aura_shell::ActivateWindow(w2.get()); EXPECT_EQ(ws2, workspace_manager()->GetActiveWorkspace()); // The size of contents_view() is now ws1(500) + ws2(500) + margin(50). @@ -83,7 +95,7 @@ TEST_F(WorkspaceControllerTest, Overview) { // Activating window w1 switches the active window and // the mode back to normal mode. - w1->Activate(); + aura_shell::ActivateWindow(w1.get()); EXPECT_EQ(ws1, workspace_manager()->GetActiveWorkspace()); EXPECT_FALSE(workspace_manager()->is_overview()); |