blob: 623fdbe02e1a79b93364028a7f5b334383fb51bf [file] [log] [blame]
// Copyright 2015 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 "components/exo/pointer.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_positioning_utils.h"
#include "base/bind.h"
#include "base/run_loop.h"
#include "components/exo/buffer.h"
#include "components/exo/pointer_delegate.h"
#include "components/exo/shell_surface.h"
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/widget/widget.h"
namespace exo {
namespace {
viz::SurfaceManager* GetSurfaceManager() {
return aura::Env::GetInstance()
->context_factory_private()
->GetFrameSinkManager()
->surface_manager();
}
class MockPointerDelegate : public PointerDelegate {
public:
MockPointerDelegate() {}
// Overridden from PointerDelegate:
MOCK_METHOD1(OnPointerDestroying, void(Pointer*));
MOCK_CONST_METHOD1(CanAcceptPointerEventsForSurface, bool(Surface*));
MOCK_METHOD3(OnPointerEnter, void(Surface*, const gfx::PointF&, int));
MOCK_METHOD1(OnPointerLeave, void(Surface*));
MOCK_METHOD2(OnPointerMotion, void(base::TimeTicks, const gfx::PointF&));
MOCK_METHOD3(OnPointerButton, void(base::TimeTicks, int, bool));
MOCK_METHOD3(OnPointerScroll,
void(base::TimeTicks, const gfx::Vector2dF&, bool));
MOCK_METHOD1(OnPointerScrollStop, void(base::TimeTicks));
MOCK_METHOD0(OnPointerFrame, void());
};
class PointerTest : public test::ExoTestBase {
public:
PointerTest() = default;
void SetUp() override {
test::ExoTestBase::SetUp();
// Sometimes underlying infra (i.e. X11 / Xvfb) may emit pointer events
// which can break MockPointerDelegate's expectations, so they should be
// consumed before starting. See https://crbug.com/854674.
base::RunLoop().RunUntilIdle();
}
private:
DISALLOW_COPY_AND_ASSIGN(PointerTest);
};
TEST_F(PointerTest, SetCursor) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
std::unique_ptr<Surface> pointer_surface(new Surface);
std::unique_ptr<Buffer> pointer_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
pointer_surface->Attach(pointer_buffer.get());
pointer_surface->Commit();
// Set pointer surface.
pointer->SetCursor(pointer_surface.get(), gfx::Point(5, 5));
base::RunLoop().RunUntilIdle();
const viz::RenderPass* last_render_pass;
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = GetSurfaceManager();
ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
const viz::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
frame.render_pass_list.back()->output_rect);
last_render_pass = frame.render_pass_list.back().get();
}
// Adjust hotspot.
pointer->SetCursor(pointer_surface.get(), gfx::Point());
base::RunLoop().RunUntilIdle();
// Verify that adjustment to hotspot resulted in new frame.
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = GetSurfaceManager();
ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
const viz::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_TRUE(frame.render_pass_list.back().get() != last_render_pass);
}
// Unset pointer surface.
pointer->SetCursor(nullptr, gfx::Point());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, SetCursorNull) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
pointer->SetCursor(nullptr, gfx::Point());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, SetCursorType) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
pointer->SetCursorType(ui::CursorType::kIBeam);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
EXPECT_EQ(ui::CursorType::kIBeam, cursor_client->GetCursor().native_type());
// Set the pointer with surface after setting pointer type.
std::unique_ptr<Surface> pointer_surface(new Surface);
std::unique_ptr<Buffer> pointer_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
pointer_surface->Attach(pointer_buffer.get());
pointer_surface->Commit();
pointer->SetCursor(pointer_surface.get(), gfx::Point());
base::RunLoop().RunUntilIdle();
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = GetSurfaceManager();
ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
const viz::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
frame.render_pass_list.back()->output_rect);
}
// Set the pointer type after the pointer surface is specified.
pointer->SetCursorType(ui::CursorType::kCross);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
EXPECT_EQ(ui::CursorType::kCross, cursor_client->GetCursor().native_type());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, SetCursorTypeOutsideOfSurface) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() -
gfx::Vector2d(1, 1));
pointer->SetCursorType(ui::CursorType::kIBeam);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
// The cursor type shouldn't be the specified one, since the pointer is
// located outside of the surface.
EXPECT_NE(ui::CursorType::kIBeam, cursor_client->GetCursor().native_type());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, SetCursorAndSetCursorType) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
std::unique_ptr<Surface> pointer_surface(new Surface);
std::unique_ptr<Buffer> pointer_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
pointer_surface->Attach(pointer_buffer.get());
pointer_surface->Commit();
// Set pointer surface.
pointer->SetCursor(pointer_surface.get(), gfx::Point());
EXPECT_EQ(1u, pointer->GetActivePresentationCallbacksForTesting().size());
base::RunLoop().RunUntilIdle();
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = GetSurfaceManager();
ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
const viz::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
frame.render_pass_list.back()->output_rect);
}
// Set the cursor type to the kNone through SetCursorType.
pointer->SetCursorType(ui::CursorType::kNone);
EXPECT_TRUE(pointer->GetActivePresentationCallbacksForTesting().empty());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
// Set the same pointer surface again.
pointer->SetCursor(pointer_surface.get(), gfx::Point());
EXPECT_EQ(1u, pointer->GetActivePresentationCallbacksForTesting().size());
auto& list =
pointer->GetActivePresentationCallbacksForTesting().begin()->second;
base::RunLoop runloop;
list.push_back(base::BindRepeating(
[](base::Closure callback, const gfx::PresentationFeedback&) {
callback.Run();
},
runloop.QuitClosure()));
runloop.Run();
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = GetSurfaceManager();
ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
const viz::CompositorFrame& frame =
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
frame.render_pass_list.back()->output_rect);
}
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, SetCursorNullAndSetCursorType) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
// Set nullptr surface.
pointer->SetCursor(nullptr, gfx::Point());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
// Set the cursor type.
pointer->SetCursorType(ui::CursorType::kIBeam);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
EXPECT_EQ(ui::CursorType::kIBeam, cursor_client->GetCursor().native_type());
// Set nullptr surface again.
pointer->SetCursor(nullptr, gfx::Point());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, pointer->root_surface());
EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerEnter) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerLeave) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(4);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().bottom_right());
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
shell_surface.reset();
surface.reset();
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerMotion) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(6);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(1, 1));
std::unique_ptr<Surface> sub_surface(new Surface);
std::unique_ptr<SubSurface> sub(
new SubSurface(sub_surface.get(), surface.get()));
surface->SetSubSurfacePosition(sub_surface.get(), gfx::Point(5, 5));
gfx::Size sub_buffer_size(5, 5);
std::unique_ptr<Buffer> sub_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(sub_buffer_size)));
sub_surface->Attach(sub_buffer.get());
sub_surface->Commit();
surface->Commit();
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(sub_surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
EXPECT_CALL(delegate, OnPointerEnter(sub_surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
generator.MoveMouseTo(sub_surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(1, 1));
std::unique_ptr<Surface> child_surface(new Surface);
std::unique_ptr<ShellSurface> child_shell_surface(
new ShellSurface(child_surface.get(), gfx::Point(9, 9), true, false,
ash::desks_util::GetActiveDeskContainerId()));
child_shell_surface->DisableMovement();
child_shell_surface->SetParent(shell_surface.get());
gfx::Size child_buffer_size(15, 15);
std::unique_ptr<Buffer> child_buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size)));
child_surface->Attach(child_buffer.get());
child_surface->Commit();
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(child_surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerLeave(sub_surface.get()));
EXPECT_CALL(delegate, OnPointerEnter(child_surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(10, 10)));
generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin() +
gfx::Vector2d(10, 10));
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerButton) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(3);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false));
generator.ClickLeftButton();
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerScroll) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
gfx::Point location = surface->window()->GetBoundsInScreen().origin();
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(3);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(location);
{
// Expect fling stop followed by scroll and scroll stop.
testing::InSequence sequence;
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
}
generator.ScrollSequence(location, base::TimeDelta(), 1, 1, 1, 1);
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerScrollWithThreeFinger) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
gfx::Point location = surface->window()->GetBoundsInScreen().origin();
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(2);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(location);
{
// Expect no scroll.
testing::InSequence sequence;
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
}
// Three fingers scroll.
generator.ScrollSequence(location, base::TimeDelta(), 1, 1, 1,
3 /* num_fingers */);
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, OnPointerScrollDiscrete) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
gfx::Size buffer_size(10, 10);
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
surface->Attach(buffer.get());
surface->Commit();
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, OnPointerFrame()).Times(2);
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1, 1), true));
generator.MoveMouseWheel(1, 1);
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, RegisterPointerEventsOnModal) {
// Create modal surface.
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(
new ShellSurface(surface.get(), gfx::Point(), true, false,
ash::kShellWindowId_SystemModalContainer));
shell_surface->DisableMovement();
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
surface->Attach(buffer.get());
surface->Commit();
ash::wm::CenterWindow(shell_surface->GetWidget()->GetNativeWindow());
// Make the window modal.
shell_surface->SetSystemModal(true);
EXPECT_TRUE(ash::Shell::IsSystemModalWindowOpen());
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, OnPointerFrame()).Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
// Pointer events on modal window should be registered.
gfx::Point origin = surface->window()->GetBoundsInScreen().origin();
{
testing::InSequence sequence;
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(origin);
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
generator.MoveMouseTo(origin + gfx::Vector2d(1, 1));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false));
generator.ClickLeftButton();
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
generator.ScrollSequence(origin, base::TimeDelta(), 1, 1, 1, 1);
}
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, IgnorePointerEventsOnNonModalWhenModalIsOpen) {
// Create surface for non-modal window.
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10))));
surface->Attach(buffer.get());
surface->Commit();
// Create surface for modal window.
std::unique_ptr<Surface> surface2(new Surface);
std::unique_ptr<ShellSurface> shell_surface2(
new ShellSurface(surface2.get(), gfx::Point(), true, false,
ash::kShellWindowId_SystemModalContainer));
shell_surface2->DisableMovement();
std::unique_ptr<Buffer> buffer2(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
surface2->Attach(buffer2.get());
surface2->Commit();
ash::wm::CenterWindow(shell_surface2->GetWidget()->GetNativeWindow());
// Make the window modal.
shell_surface2->SetSystemModal(true);
EXPECT_TRUE(ash::Shell::IsSystemModalWindowOpen());
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, OnPointerFrame()).Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface2.get()))
.WillRepeatedly(testing::Return(true));
// Check if pointer events on non-modal window are ignored.
gfx::Point nonModalOrigin = surface->window()->GetBoundsInScreen().origin();
{
testing::InSequence sequence;
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0))
.Times(0);
generator.MoveMouseTo(nonModalOrigin);
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)))
.Times(0);
generator.MoveMouseTo(nonModalOrigin + gfx::Vector2d(1, 1));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true))
.Times(0);
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false))
.Times(0);
generator.ClickLeftButton();
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false))
.Times(0);
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_)).Times(0);
generator.ScrollSequence(nonModalOrigin, base::TimeDelta(), 1, 1, 1, 1);
EXPECT_CALL(delegate, OnPointerLeave(surface.get())).Times(0);
generator.MoveMouseTo(
surface->window()->GetBoundsInScreen().bottom_right());
}
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, IgnorePointerLeaveOnModal) {
// Create modal surface.
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(
new ShellSurface(surface.get(), gfx::Point(), true, false,
ash::kShellWindowId_SystemModalContainer));
shell_surface->DisableMovement();
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
surface->Attach(buffer.get());
surface->Commit();
ash::wm::CenterWindow(shell_surface->GetWidget()->GetNativeWindow());
// Make the window modal.
shell_surface->SetSystemModal(true);
EXPECT_TRUE(ash::Shell::IsSystemModalWindowOpen());
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, OnPointerFrame()).Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
gfx::Point origin = surface->window()->GetBoundsInScreen().origin();
{
testing::InSequence sequence;
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(origin);
// OnPointerLeave should not be called on the modal surface when the pointer
// moves out of its bounds.
EXPECT_CALL(delegate, OnPointerLeave(surface.get())).Times(0);
generator.MoveMouseTo(
surface->window()->GetBoundsInScreen().bottom_right());
}
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
TEST_F(PointerTest, RegisterPointerEventsOnNonModal) {
// Create surface for non-modal window.
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
std::unique_ptr<Buffer> buffer(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10))));
surface->Attach(buffer.get());
surface->Commit();
// Create another surface for a non-modal window.
std::unique_ptr<Surface> surface2(new Surface);
std::unique_ptr<ShellSurface> shell_surface2(
new ShellSurface(surface2.get(), gfx::Point(), true, false,
ash::kShellWindowId_SystemModalContainer));
shell_surface2->DisableMovement();
std::unique_ptr<Buffer> buffer2(
new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(5, 5))));
surface2->Attach(buffer2.get());
surface2->Commit();
ash::wm::CenterWindow(shell_surface2->GetWidget()->GetNativeWindow());
MockPointerDelegate delegate;
std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
EXPECT_CALL(delegate, OnPointerFrame()).Times(testing::AnyNumber());
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface2.get()))
.WillRepeatedly(testing::Return(true));
// Ensure second window is non-modal.
shell_surface2->SetSystemModal(false);
EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen());
// Check if pointer events on first non-modal window are registered.
gfx::Point firstWindowOrigin =
surface->window()->GetBoundsInScreen().origin();
{
testing::InSequence sequence;
EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
generator.MoveMouseTo(firstWindowOrigin);
EXPECT_CALL(delegate, OnPointerMotion(testing::_, gfx::PointF(1, 1)));
generator.MoveMouseTo(firstWindowOrigin + gfx::Vector2d(1, 1));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, true));
EXPECT_CALL(delegate,
OnPointerButton(testing::_, ui::EF_LEFT_MOUSE_BUTTON, false));
generator.ClickLeftButton();
EXPECT_CALL(delegate,
OnPointerScroll(testing::_, gfx::Vector2dF(1.2, 1.2), false));
EXPECT_CALL(delegate, OnPointerScrollStop(testing::_));
generator.ScrollSequence(firstWindowOrigin, base::TimeDelta(), 1, 1, 1, 1);
EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
generator.MoveMouseTo(
surface->window()->GetBoundsInScreen().bottom_right());
}
EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
pointer.reset();
}
} // namespace
} // namespace exo