Skip to content

Commit

Permalink
Introduce 'grab_inputs' property for athena container.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mukai@chromium.org committed Jul 24, 2014
1 parent d7ab81a commit 0f156d4
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 8 deletions.
4 changes: 3 additions & 1 deletion athena/home/home_card_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
3 changes: 3 additions & 0 deletions athena/screen/public/screen_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
102 changes: 101 additions & 1 deletion athena/screen/screen_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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() {}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 =
Expand All @@ -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
Expand Down
177 changes: 177 additions & 0 deletions athena/screen/screen_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
Expand All @@ -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
1 change: 1 addition & 0 deletions athena/test/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 0f156d4

Please sign in to comment.