diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-24 21:09:10 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-24 21:09:10 +0000 |
commit | 0f156d48f3a7f97b7d07ff83b98f614ff0a94857 (patch) | |
tree | 29068abaac8c5326d06f89d253443f73393a7928 /athena | |
parent | d7ab81a5eaa0c1001729515def342453b6997fd7 (diff) | |
download | chromium_src-0f156d48f3a7f97b7d07ff83b98f614ff0a94857.zip chromium_src-0f156d48f3a7f97b7d07ff83b98f614ff0a94857.tar.gz chromium_src-0f156d48f3a7f97b7d07ff83b98f614ff0a94857.tar.bz2 |
Introduce 'grab_inputs' property for athena container.
BUG=395655
R=oshima@chromium.org
TEST=athena_unittests
Review URL: https://codereview.chromium.org/414903002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285371 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'athena')
-rw-r--r-- | athena/home/home_card_impl.cc | 4 | ||||
-rw-r--r-- | athena/screen/public/screen_manager.h | 3 | ||||
-rw-r--r-- | athena/screen/screen_manager_impl.cc | 102 | ||||
-rw-r--r-- | athena/screen/screen_manager_unittest.cc | 177 | ||||
-rw-r--r-- | athena/test/DEPS | 1 | ||||
-rw-r--r-- | athena/test/athena_test_helper.cc | 14 |
6 files changed, 293 insertions, 8 deletions
diff --git a/athena/home/home_card_impl.cc b/athena/home/home_card_impl.cc index df3b0f6..9a71414 100644 --- a/athena/home/home_card_impl.cc +++ b/athena/home/home_card_impl.cc @@ -241,8 +241,10 @@ class HomeCardImpl : public HomeCard, // aura::client::ActivationChangeObserver: virtual void OnWindowActivated(aura::Window* gained_active, aura::Window* lost_active) OVERRIDE { - if (gained_active != home_card_widget_->GetNativeWindow()) + if (state_ != HIDDEN && + gained_active != home_card_widget_->GetNativeWindow()) { SetState(VISIBLE_MINIMIZED); + } } scoped_ptr<AppModelBuilder> model_builder_; diff --git a/athena/screen/public/screen_manager.h b/athena/screen/public/screen_manager.h index 9e87306..8a82f6c 100644 --- a/athena/screen/public/screen_manager.h +++ b/athena/screen/public/screen_manager.h @@ -35,6 +35,9 @@ class ATHENA_EXPORT ScreenManager { // True if the container can activate its child window. bool can_activate_children; + // True if the container will grab all of input events. + bool grab_inputs; + // Defines the z_order priority of the container. int z_order_priority; }; diff --git a/athena/screen/screen_manager_impl.cc b/athena/screen/screen_manager_impl.cc index 744f076..8522acf 100644 --- a/athena/screen/screen_manager_impl.cc +++ b/athena/screen/screen_manager_impl.cc @@ -16,6 +16,7 @@ #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" #include "ui/aura/window_property.h" +#include "ui/aura/window_targeter.h" #include "ui/aura/window_tree_host.h" #include "ui/wm/core/base_focus_rules.h" #include "ui/wm/core/capture_controller.h" @@ -29,6 +30,22 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams, ScreenManager* instance = NULL; +bool GrabsInput(aura::Window* container) { + ScreenManager::ContainerParams* params = + container->GetProperty(kContainerParamsKey); + return params && params->grab_inputs; +} + +// Returns the container which contains |window|. +aura::Window* GetContainer(aura::Window* window) { + // No containers for NULL or the root window itself. + if (!window || !window->parent()) + return NULL; + if (window->parent()->IsRootWindow()) + return window; + return GetContainer(window->parent()); +} + class AthenaFocusRules : public wm::BaseFocusRules { public: AthenaFocusRules() {} @@ -40,6 +57,22 @@ class AthenaFocusRules : public wm::BaseFocusRules { window->GetProperty(kContainerParamsKey); return params && params->can_activate_children; } + virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE { + // Check if containers of higher z-order than |window| have 'grab_inputs' + // fields. + if (window) { + const aura::Window::Windows& containers = + window->GetRootWindow()->children(); + aura::Window::Windows::const_iterator iter = + std::find(containers.begin(), containers.end(), GetContainer(window)); + DCHECK(iter != containers.end()); + for (++iter; iter != containers.end(); ++iter) { + if (GrabsInput(*iter)) + return false; + } + } + return BaseFocusRules::CanActivateWindow(window); + } private: DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules); @@ -101,6 +134,57 @@ class AthenaScreenPositionClient : public aura::client::ScreenPositionClient { DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient); }; +class AthenaEventTargeter : public aura::WindowTargeter, + public aura::WindowObserver { + public: + explicit AthenaEventTargeter(aura::Window* container) + : container_(container) { + container_->AddObserver(this); + } + + virtual ~AthenaEventTargeter() { + // Removed before the container is removed. + if (container_) + container_->RemoveObserver(this); + } + + private: + // aura::WindowTargeter: + virtual bool SubtreeCanAcceptEvent( + ui::EventTarget* target, + const ui::LocatedEvent& event) const OVERRIDE { + aura::Window* window = static_cast<aura::Window*>(target); + const aura::Window::Windows& containers = + container_->GetRootWindow()->children(); + aura::Window::Windows::const_iterator iter = + std::find(containers.begin(), containers.end(), container_); + DCHECK(iter != containers.end()); + for (; iter != containers.end(); ++iter) { + if ((*iter)->Contains(window)) + return true; + } + return false; + } + + // aura::WindowObserver: + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { + aura::Window* root_window = container_->GetRootWindow(); + DCHECK_EQ(window, container_); + DCHECK_EQ( + this, static_cast<ui::EventTarget*>(root_window)->GetEventTargeter()); + + container_->RemoveObserver(this); + container_ = NULL; + + // This will remove myself. + root_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>()); + } + + aura::Window* container_; + + DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter); +}; + class ScreenManagerImpl : public ScreenManager { public: explicit ScreenManagerImpl(aura::Window* root_window); @@ -208,6 +292,19 @@ aura::Window* ScreenManagerImpl::CreateContainer( #endif container->SetProperty(kContainerParamsKey, new ContainerParams(params)); + + // If another container is already grabbing the input, SetEventTargeter + // implicitly release the grabbing and remove the EventTargeter instance. + // TODO(mukai|oshima): think about the ideal behavior of multiple grabbing + // and implement it. + if (params.grab_inputs) { + DCHECK(std::find_if(children.begin(), children.end(), &GrabsInput) + == children.end()) + << "input has already been grabbed by another container"; + root_window_->SetEventTargeter( + scoped_ptr<ui::EventTargeter>(new AthenaEventTargeter(container))); + } + root_window_->AddChild(container); aura::Window::Windows::const_iterator iter = @@ -229,7 +326,10 @@ void ScreenManagerImpl::SetBackgroundImage(const gfx::ImageSkia& image) { ScreenManager::ContainerParams::ContainerParams(const std::string& n, int priority) - : name(n), can_activate_children(false), z_order_priority(priority) { + : name(n), + can_activate_children(false), + grab_inputs(false), + z_order_priority(priority) { } // static diff --git a/athena/screen/screen_manager_unittest.cc b/athena/screen/screen_manager_unittest.cc index 1a04ae8..d3b60c1 100644 --- a/athena/screen/screen_manager_unittest.cc +++ b/athena/screen/screen_manager_unittest.cc @@ -4,21 +4,40 @@ #include "athena/screen/public/screen_manager.h" +#include <algorithm> #include <string> +#include "athena/common/container_priorities.h" #include "athena/test/athena_test_base.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/test/test_window_delegate.h" #include "ui/aura/window.h" +#include "ui/wm/core/window_util.h" typedef athena::test::AthenaTestBase ScreenManagerTest; namespace athena { namespace { +const int kTestZOrderPriority = 10; + aura::Window* Create(const std::string& name, int z_order_priority) { ScreenManager::ContainerParams params(name, z_order_priority); return ScreenManager::Get()->CreateContainer(params); } +aura::Window* CreateTestWindow(aura::Window* container, + aura::WindowDelegate* delegate, + const gfx::Rect& bounds) { + aura::Window* window = new aura::Window(delegate); + window->SetType(ui::wm::WINDOW_TYPE_NORMAL); + window->Init(aura::WINDOW_LAYER_TEXTURED); + container->AddChild(window); + window->Show(); + window->SetBounds(bounds); + return window; +} + void CheckZOrder(aura::Window* w1, aura::Window* w2) { aura::Window* parent = w1->parent(); const aura::Window::Windows& children = parent->children(); @@ -36,6 +55,18 @@ void CheckZOrder(aura::Window* w1, aura::Window* w2) { } // namespace +TEST_F(ScreenManagerTest, CreateContainer) { + size_t num_containers = root_window()->children().size(); + + aura::Window* container = Create("test", kTestZOrderPriority); + EXPECT_EQ("test", container->name()); + + const aura::Window::Windows& containers = root_window()->children(); + EXPECT_EQ(num_containers + 1, containers.size()); + EXPECT_NE(containers.end(), + std::find(containers.begin(), containers.end(), container)); +} + TEST_F(ScreenManagerTest, Zorder) { aura::Window* window_10 = Create("test10", 10); aura::Window* window_11 = Create("test11", 11); @@ -59,4 +90,150 @@ TEST_F(ScreenManagerTest, Zorder) { } } +TEST_F(ScreenManagerTest, NonActivatableContainer) { + ScreenManager::ContainerParams non_activatable( + "non_activatable", kTestZOrderPriority); + non_activatable.can_activate_children = false; + aura::Window* no_activatable_container = + ScreenManager::Get()->CreateContainer(non_activatable); + + ScreenManager::ContainerParams activatable( + "activatable", kTestZOrderPriority + 1); + activatable.can_activate_children = true; + aura::Window* activatable_container = + ScreenManager::Get()->CreateContainer(activatable); + + scoped_ptr<aura::Window> window(CreateTestWindow( + no_activatable_container, NULL, gfx::Rect(0, 0, 100, 100))); + EXPECT_FALSE(wm::CanActivateWindow(window.get())); + + activatable_container->AddChild(window.get()); + EXPECT_TRUE(wm::CanActivateWindow(window.get())); +} + +TEST_F(ScreenManagerTest, GrabInputContainer) { + ScreenManager::ContainerParams normal_params( + "normal", kTestZOrderPriority); + normal_params.can_activate_children = true; + aura::Window* normal_container = + ScreenManager::Get()->CreateContainer(normal_params); + + aura::test::EventCountDelegate normal_delegate; + scoped_ptr<aura::Window> normal_window(CreateTestWindow( + normal_container, &normal_delegate, gfx::Rect(0, 0, 100, 100))); + + EXPECT_TRUE(wm::CanActivateWindow(normal_window.get())); + wm::ActivateWindow(normal_window.get()); + aura::test::EventGenerator event_generator(root_window()); + event_generator.MoveMouseTo(0, 0); + event_generator.ClickLeftButton(); + EXPECT_EQ("1 1", normal_delegate.GetMouseButtonCountsAndReset()); + event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); + event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE); + EXPECT_EQ("1 1", normal_delegate.GetKeyCountsAndReset()); + + ScreenManager::ContainerParams grab_params( + "grabbing", kTestZOrderPriority + 1); + grab_params.can_activate_children = true; + grab_params.grab_inputs = true; + aura::Window* grab_container = + ScreenManager::Get()->CreateContainer(grab_params); + + EXPECT_FALSE(wm::CanActivateWindow(normal_window.get())); + + aura::test::EventCountDelegate grab_delegate; + scoped_ptr<aura::Window> grab_window(CreateTestWindow( + grab_container, &grab_delegate, gfx::Rect(10, 10, 100, 100))); + EXPECT_TRUE(wm::CanActivateWindow(grab_window.get())); + + wm::ActivateWindow(grab_window.get()); + + // (0, 0) is still on normal_window, but the event should not go there + // because grabbing_container prevents it. + event_generator.MoveMouseTo(0, 0); + event_generator.ClickLeftButton(); + EXPECT_EQ("0 0", normal_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + + event_generator.MoveMouseTo(20, 20); + event_generator.ClickLeftButton(); + EXPECT_EQ("1 1", grab_delegate.GetMouseButtonCountsAndReset()); + + event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); + event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE); + EXPECT_EQ("0 0", normal_delegate.GetKeyCountsAndReset()); + EXPECT_EQ("1 1", grab_delegate.GetKeyCountsAndReset()); +} + +TEST_F(ScreenManagerTest, GrabShouldNotBlockVirtualKeyboard) { + ScreenManager::ContainerParams grab_params("grabbing", kTestZOrderPriority); + grab_params.can_activate_children = true; + grab_params.grab_inputs = true; + aura::Window* grab_container = + ScreenManager::Get()->CreateContainer(grab_params); + + aura::test::EventCountDelegate grab_delegate; + scoped_ptr<aura::Window> grab_window(CreateTestWindow( + grab_container, &grab_delegate, gfx::Rect(0, 0, 100, 100))); + EXPECT_TRUE(wm::CanActivateWindow(grab_window.get())); + + // Create a normal container appearing over the |grab_container|. This is + // essentially the case of virtual keyboard. + ScreenManager::ContainerParams vk_params( + "virtual keyboard", kTestZOrderPriority + 1); + vk_params.can_activate_children = true; + aura::Window* vk_container = ScreenManager::Get()->CreateContainer(vk_params); + + aura::test::EventCountDelegate vk_delegate; + scoped_ptr<aura::Window> vk_window(CreateTestWindow( + vk_container, &vk_delegate, gfx::Rect(0, 20, 100, 80))); + EXPECT_TRUE(wm::CanActivateWindow(vk_window.get())); + + aura::test::EventGenerator event_generator(root_window()); + event_generator.MoveMouseTo(10, 25); + event_generator.ClickLeftButton(); + EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("1 1", vk_delegate.GetMouseButtonCountsAndReset()); +} + +TEST_F(ScreenManagerTest, GrabAndMouseCapture) { + ScreenManager::ContainerParams normal_params( + "normal", kTestZOrderPriority); + normal_params.can_activate_children = true; + aura::Window* normal_container = + ScreenManager::Get()->CreateContainer(normal_params); + + aura::test::EventCountDelegate normal_delegate; + scoped_ptr<aura::Window> normal_window(CreateTestWindow( + normal_container, &normal_delegate, gfx::Rect(0, 0, 100, 100))); + + aura::test::EventGenerator event_generator(root_window()); + event_generator.MoveMouseTo(0, 0); + event_generator.PressLeftButton(); + + // Creating grabbing container while mouse pressing. + ScreenManager::ContainerParams grab_params( + "grabbing", kTestZOrderPriority + 1); + grab_params.can_activate_children = true; + grab_params.grab_inputs = true; + aura::Window* grab_container = + ScreenManager::Get()->CreateContainer(grab_params); + + aura::test::EventCountDelegate grab_delegate; + scoped_ptr<aura::Window> grab_window(CreateTestWindow( + grab_container, &grab_delegate, gfx::Rect(10, 10, 100, 100))); + + // Release event should be sent to |normal_window| because it captures the + // mouse event. + event_generator.ReleaseLeftButton(); + EXPECT_EQ("1 1", normal_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); + + // After release, further mouse events should not be sent to |normal_window| + // because grab_container grabs the input. + event_generator.ClickLeftButton(); + EXPECT_EQ("0 0", normal_delegate.GetMouseButtonCountsAndReset()); + EXPECT_EQ("0 0", grab_delegate.GetMouseButtonCountsAndReset()); +} + } // namespace athena diff --git a/athena/test/DEPS b/athena/test/DEPS index 24ed79d..69827ad 100644 --- a/athena/test/DEPS +++ b/athena/test/DEPS @@ -2,6 +2,7 @@ include_rules = [ "+athena/activity", "+athena/home/public", "+athena/main", + "+athena/screen/public", "+third_party/skia/include", "+ui/app_list", "+ui/aura", diff --git a/athena/test/athena_test_helper.cc b/athena/test/athena_test_helper.cc index 682e209..9adacc0 100644 --- a/athena/test/athena_test_helper.cc +++ b/athena/test/athena_test_helper.cc @@ -5,6 +5,7 @@ #include "athena/test/athena_test_helper.h" #include "athena/main/athena_launcher.h" +#include "athena/screen/public/screen_manager.h" #include "athena/test/sample_activity_factory.h" #include "athena/test/test_app_model_builder.h" #include "base/command_line.h" @@ -21,7 +22,7 @@ #include "ui/base/ime/input_method_initializer.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/gfx/screen.h" -#include "ui/wm/core/default_activation_client.h" +#include "ui/wm/core/focus_controller.h" #include "ui/wm/core/input_method_event_filter.h" #if defined(USE_X11) @@ -72,11 +73,12 @@ void AthenaTestHelper::SetUp(ui::ContextFactory* context_factory) { input_method_filter_->SetInputMethodPropertyInRootWindow( root_window()); - // TODO(oshima): Switch to athena implementation. - focus_client_.reset(new aura::test::TestFocusClient); - aura::client::SetFocusClient(root_window(), - focus_client_.get()); - new ::wm::DefaultActivationClient(root_window()); + wm::FocusController* focus_controller = + new wm::FocusController(ScreenManager::CreateFocusRules()); + aura::client::SetFocusClient(root_window(), focus_controller); + root_window()->AddPreTargetHandler(focus_controller); + aura::client::SetActivationClient(root_window(), focus_controller); + focus_client_.reset(focus_controller); root_window()->Show(); // Ensure width != height so tests won't confuse them. |