blob: 55e173de38a12dc6249ae8e787a19f0a34c1dde5 [file] [log] [blame]
// Copyright 2020 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 <linux/input-event-codes.h>
#include <wayland-server-protocol.h>
#include <wayland-server.h>
#include <wayland-util.h>
#include <xdg-shell-server-protocol.h>
#include <cstdint>
#include "base/notreached.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_data_device.h"
#include "ui/ozone/platform/wayland/host/wayland_screen.h"
#include "ui/ozone/platform/wayland/host/wayland_window.h"
#include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h"
#include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
#include "ui/ozone/platform/wayland/test/mock_pointer.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/scoped_wl_array.h"
#include "ui/ozone/platform/wayland/test/test_data_device.h"
#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
#include "ui/ozone/platform/wayland/test/test_data_offer.h"
#include "ui/ozone/platform/wayland/test/test_data_source.h"
#include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
#include "ui/ozone/test/mock_platform_window_delegate.h"
#include "ui/platform_window/extensions/wayland_extension.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/wm/wm_move_loop_handler.h"
using testing::_;
using testing::Mock;
namespace ui {
class WaylandWindowDragControllerTest : public WaylandDragDropTest {
public:
WaylandWindowDragControllerTest() = default;
~WaylandWindowDragControllerTest() override = default;
void SetUp() override {
WaylandDragDropTest::SetUp();
screen_ = std::make_unique<WaylandScreen>(connection_.get());
wl_seat_send_capabilities(server_.seat()->resource(),
WL_SEAT_CAPABILITY_POINTER);
Sync();
pointer_ = server_.seat()->pointer();
ASSERT_TRUE(pointer_);
EXPECT_FALSE(window_->has_pointer_focus());
EXPECT_EQ(State::kIdle, drag_controller()->state());
}
WaylandWindowDragController* drag_controller() const {
return connection_->window_drag_controller();
}
WaylandWindowManager* window_manager() const {
return connection_->wayland_window_manager();
}
protected:
using State = WaylandWindowDragController::State;
void SendPointerEnter(WaylandWindow* window,
MockPlatformWindowDelegate* delegate) {
auto* surface = server_.GetObject<wl::MockSurface>(
window->root_surface()->GetSurfaceId());
wl_pointer_send_enter(pointer_->resource(), NextSerial(),
surface->resource(), 0, 0);
EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
Sync();
EXPECT_EQ(window, window_manager()->GetCurrentFocusedWindow());
}
void SendPointerLeave(WaylandWindow* window,
MockPlatformWindowDelegate* delegate) {
auto* surface = server_.GetObject<wl::MockSurface>(
window->root_surface()->GetSurfaceId());
wl_pointer_send_leave(pointer_->resource(), NextSerial(),
surface->resource());
EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
Sync();
EXPECT_EQ(nullptr, window_manager()->GetCurrentFocusedWindow());
}
void SendPointerPress(WaylandWindow* window,
MockPlatformWindowDelegate* delegate,
int button) {
wl_pointer_send_button(pointer_->resource(), NextSerial(), NextTime(),
button, WL_POINTER_BUTTON_STATE_PRESSED);
EXPECT_CALL(*delegate, DispatchEvent(_)).Times(1);
Sync();
EXPECT_EQ(window, window_manager()->GetCurrentFocusedWindow());
}
void SendPointerMotion(WaylandWindow* window,
MockPlatformWindowDelegate* delegate,
gfx::Point location,
bool sync_and_ensure_dispatched = true) {
wl_fixed_t x = wl_fixed_from_int(location.x());
wl_fixed_t y = wl_fixed_from_int(location.y());
wl_pointer_send_motion(pointer_->resource(), NextTime(), x, y);
if (!sync_and_ensure_dispatched)
return;
EXPECT_CALL(*delegate, DispatchEvent(_)).WillOnce([](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
});
Sync();
EXPECT_EQ(window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint(location, {}));
}
// For the context of window drag, "drop" is detected through
// wl_data_source::cancelled in the regular case. Unless extended-drag
// protocol is available.
//
// TODO(crbug.com/1116431): Support extended-drag in test compositor.
void SendDndDrop() { SendDndCancelled(); }
// client objects
std::unique_ptr<WaylandScreen> screen_;
// server objects
wl::MockPointer* pointer_;
};
// Check the following flow works as expected:
// 1. With a single 1 window open,
// 2. Move pointer into it, press left button, move cursor a bit (drag),
// 3. Run move loop, drag it within the window bounds and drop.
TEST_P(WaylandWindowDragControllerTest, DragInsideWindowAndDrop) {
// Ensure there is no window currently focused
EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
// Set up an "interaction flow", start the drag session and run move loop:
// - Event dispatching and bounds changes are monitored
// - At each event, emulates a new event at server side and proceeds to the
// next test step.
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_EQ(State::kAttached, drag_controller()->state());
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
enum { kStarted, kDragging, kDropping, kDone } test_step = kStarted;
EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
switch (test_step) {
case kStarted:
EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
EXPECT_EQ(State::kDetached, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
// Drag it a bit more.
SendDndMotion({20, 20});
test_step = kDragging;
break;
case kDropping:
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
EXPECT_EQ(State::kDropped, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
test_step = kDone;
break;
case kDone:
EXPECT_EQ(ET_MOUSE_EXITED, event->type());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
break;
case kDragging:
default:
FAIL() << " event=" << event->GetName()
<< " state=" << drag_controller()->state()
<< " step=" << static_cast<int>(test_step);
return;
}
});
EXPECT_CALL(delegate_, OnBoundsChanged(_))
.WillOnce([&](const gfx::Rect& bounds) {
EXPECT_EQ(State::kDetached, drag_controller()->state());
EXPECT_EQ(kDragging, test_step);
EXPECT_EQ(gfx::Point(20, 20), bounds.origin());
SendDndDrop();
test_step = kDropping;
});
// RunMoveLoop() blocks until the dragging session ends, so resume test
// server's run loop until it returns.
server_.Resume();
move_loop_handler->RunMoveLoop({});
server_.Pause();
SendPointerEnter(window_.get(), &delegate_);
Sync();
EXPECT_EQ(State::kIdle, drag_controller()->state());
EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
// Check the following flow works as expected:
// 1. With only 1 window open;
// 2. Move pointer into it, press left button, move cursor a bit (drag);
// 3. Run move loop,
// 4. Drag pointer to outside the window and release the mouse button, and make
// sure RELEASE and EXIT mouse events are delivered even when the drop
// happens outside the bounds of any surface.
TEST_P(WaylandWindowDragControllerTest, DragExitWindowAndDrop) {
// Ensure there is no window currently focused
EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
Sync();
// Sets up an "interaction flow", start the drag session and run move loop:
// - Event dispatching and bounds changes are monitored
// - At each event, emulates a new event on server side and proceeds to the
// next test step.
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_EQ(State::kAttached, drag_controller()->state());
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
enum { kStarted, kDragging, kExitedDropping, kDone } test_step = kStarted;
EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
switch (test_step) {
case kStarted:
EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
EXPECT_EQ(State::kDetached, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
// Drag window a bit more.
SendDndMotion({20, 20});
test_step = kDragging;
break;
case kExitedDropping:
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
EXPECT_EQ(State::kDropped, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
test_step = kDone;
break;
case kDone:
EXPECT_EQ(ET_MOUSE_EXITED, event->type());
break;
case kDragging:
default:
FAIL() << " event=" << event->GetName()
<< " state=" << drag_controller()->state()
<< " step=" << static_cast<int>(test_step);
return;
}
});
EXPECT_CALL(delegate_, OnBoundsChanged(_))
.WillOnce([&](const gfx::Rect& bounds) {
EXPECT_EQ(State::kDetached, drag_controller()->state());
EXPECT_EQ(kDragging, test_step);
EXPECT_EQ(gfx::Point(20, 20), bounds.origin());
SendDndLeave();
SendDndDrop();
test_step = kExitedDropping;
});
// RunMoveLoop() blocks until the dragging sessions ends, so resume test
// server's run loop until it returns.
server_.Resume();
move_loop_handler->RunMoveLoop({});
server_.Pause();
SendPointerEnter(window_.get(), &delegate_);
Sync();
EXPECT_EQ(State::kIdle, drag_controller()->state());
EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
// Check the following flow works as expected:
// 1. With 2 windows open,
// 2. Focus window 1, starts dragging,
// 3. Run move loop,
// 4. Drag the pointer out of window 1 and then into window 2,
// 5. Drag it a bit more (within window 2) and then calls EndMoveLoop(),
// emulating a window snap), and then
// 6. With the window in "snapped" state, drag it further and then drop.
TEST_P(WaylandWindowDragControllerTest, DragToOtherWindowSnapDragDrop) {
// Init and open |target_window|.
PlatformWindowInitProperties properties{gfx::Rect{80, 80}};
properties.type = PlatformWindowType::kWindow;
EXPECT_CALL(delegate_, OnAcceleratedWidgetAvailable(_)).Times(1);
auto window_2 = WaylandWindow::Create(&delegate_, connection_.get(),
std::move(properties));
ASSERT_NE(gfx::kNullAcceleratedWidget, window_2->GetWidget());
Sync();
// Ensure there is no window currently focused
EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
auto* source_window = window_.get();
auto* target_window = window_2.get();
EXPECT_TRUE(source_window);
EXPECT_TRUE(target_window);
SendPointerEnter(source_window, &delegate_);
SendPointerPress(source_window, &delegate_, BTN_LEFT);
SendPointerMotion(source_window, &delegate_, {10, 10});
// Sets up an "interaction flow", start the drag session and run move loop:
// - Event dispatching and bounds changes are monitored
// - At each event, emulates a new event on server side and proceeds to the
// next test step.
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_EQ(State::kAttached, drag_controller()->state());
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
enum {
kStarted,
kDragging,
kEnteredTarget,
kSnapped,
kDone
} test_step = kStarted;
EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
switch (test_step) {
case kStarted:
EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
EXPECT_EQ(State::kDetached, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(source_window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
// Drag window a bit more.
SendDndMotion({50, 50});
test_step = kDragging;
break;
case kEnteredTarget:
EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
EXPECT_EQ(State::kDetached, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(target_window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
move_loop_handler->EndMoveLoop();
test_step = kSnapped;
break;
default:
FAIL() << " event=" << event->GetName()
<< " state=" << drag_controller()->state()
<< " step=" << static_cast<int>(test_step);
return;
}
});
EXPECT_CALL(delegate_, OnBoundsChanged(_))
.WillOnce([&](const gfx::Rect& bounds) {
EXPECT_EQ(State::kDetached, drag_controller()->state());
EXPECT_EQ(kDragging, test_step);
EXPECT_EQ(gfx::Point(50, 50), bounds.origin());
// Exit |source_window| and enter the |target_window|.
SendDndLeave();
SendDndEnter(target_window, {});
test_step = kEnteredTarget;
});
// RunMoveLoop() blocks until the dragging sessions ends, so resume test
// server's run loop until it returns.
server_.Resume();
move_loop_handler->RunMoveLoop({});
server_.Pause();
// Continue the dragging session after "snapping" the window. At this point,
// the DND session is expected to be still alive and responding normally to
// data object events.
EXPECT_EQ(State::kAttached, drag_controller()->state());
EXPECT_EQ(kSnapped, test_step);
// Drag the pointer a bit more within |target_window| and then releases the
// mouse button and ensures drag controller delivers the events properly and
// exit gracefully.
SendDndMotion({30, 30});
SendDndMotion({30, 33});
SendDndMotion({30, 36});
SendDndMotion({30, 39});
SendDndMotion({30, 42});
EXPECT_CALL(delegate_, DispatchEvent(_)).Times(5);
Sync();
EXPECT_EQ(gfx::Point(30, 42), screen_->GetCursorScreenPoint());
EXPECT_EQ(target_window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({50, 50}, {}));
// Emulates a pointer::leave event being sent before data_source::cancelled,
// what happens with some compositors, e.g: Exosphere. Even in these cases,
// WaylandWindowDragController must guarantee the mouse button release event
// (aka: drop) is delivered to the upper layer listeners.
SendPointerLeave(target_window, &delegate_);
SendDndDrop();
EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
switch (test_step) {
case kSnapped:
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
EXPECT_EQ(State::kDropped, drag_controller()->state());
EXPECT_EQ(target_window, window_manager()->GetCurrentFocusedWindow());
test_step = kDone;
break;
default:
FAIL() << " event=" << event->GetName()
<< " state=" << drag_controller()->state()
<< " step=" << static_cast<int>(test_step);
return;
}
});
Sync();
SendPointerEnter(target_window, &delegate_);
EXPECT_EQ(target_window, window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(target_window->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
// Verifies wl_data_device::leave events are properly handled and propagated
// while in window dragging "attached" mode.
TEST_P(WaylandWindowDragControllerTest, DragExitAttached) {
// Ensure there is no window currently focused
EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
Sync();
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
Sync();
Sync();
EXPECT_EQ(State::kAttached, drag_controller()->state());
// Emulate a [motion => leave] event sequence and make sure the correct
// ui::Events are dispatched in response.
SendDndMotion({50, 50});
EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
Sync();
SendDndLeave();
EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce([&](Event* event) {
EXPECT_EQ(ET_MOUSE_DRAGGED, event->type());
EXPECT_EQ(gfx::Point(50, -1).ToString(),
event->AsMouseEvent()->location().ToString());
});
Sync();
SendDndDrop();
EXPECT_CALL(delegate_, DispatchEvent(_)).Times(1);
Sync();
SendPointerEnter(window_.get(), &delegate_);
Sync();
EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
TEST_P(WaylandWindowDragControllerTest, RestoreDuringWindowDragSession) {
const gfx::Rect original_bounds = window_->GetBounds();
wl::ScopedWlArray states({XDG_TOPLEVEL_STATE_ACTIVATED});
// Maximize and check restored bounds is correctly set.
const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
EXPECT_CALL(delegate_, OnBoundsChanged(testing::Eq(maximized_bounds)));
window_->Maximize();
states.AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED);
SendConfigureEvent(surface_->xdg_surface(), maximized_bounds.width(),
maximized_bounds.height(), 1, states.get());
Sync();
auto restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(original_bounds, restored_bounds);
// Start a window drag session.
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {10, 10});
Sync();
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({10, 10}, {}));
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_EQ(WaylandWindowDragController::State::kAttached,
connection_->window_drag_controller()->state());
// Call restore and ensure it's no-op.
window_->Restore();
EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
}
// Check the following flow works as expected:
//
// 1. With a single 1 window open,
// 2. Move pointer into it, press left button, move cursor a bit (drag),
// 3. Run move loop, drag it from 200,200 location to 100,100
// 4. Send a few wl_pointer::motion events targeting 20,20 location and ensure
// they are ignored (i.e: window bounds keep unchanged) until drop happens.
//
// Verifies window drag controller is resistant to issues such as
// https://crbug.com/1148021.
TEST_P(WaylandWindowDragControllerTest, IgnorePointerEventsUntilDrop) {
// Ensure there is no window currently focused
EXPECT_FALSE(window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({200, 200}, {}));
SendPointerEnter(window_.get(), &delegate_);
SendPointerPress(window_.get(), &delegate_, BTN_LEFT);
SendPointerMotion(window_.get(), &delegate_, {200, 200});
// Set up an "interaction flow", start the drag session and run move loop:
// - Event dispatching and bounds changes are monitored
// - At each event, emulates a new event at server side and proceeds to the
// next test step.
auto* wayland_extension = GetWaylandExtension(*window_);
wayland_extension->StartWindowDraggingSessionIfNeeded();
EXPECT_EQ(State::kAttached, drag_controller()->state());
auto* move_loop_handler = GetWmMoveLoopHandler(*window_);
DCHECK(move_loop_handler);
enum { kStarted, kDragging, kDropping, kDone } test_step = kStarted;
EXPECT_CALL(delegate_, DispatchEvent(_)).WillRepeatedly([&](Event* event) {
EXPECT_TRUE(event->IsMouseEvent());
switch (test_step) {
case kStarted:
EXPECT_EQ(ET_MOUSE_ENTERED, event->type());
EXPECT_EQ(State::kDetached, drag_controller()->state());
// Ensure PlatformScreen keeps consistent.
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({200, 200}, {}));
// Drag it a bit more.
SendDndMotion({100, 100});
test_step = kDragging;
break;
case kDropping:
EXPECT_EQ(ET_MOUSE_RELEASED, event->type());
EXPECT_EQ(State::kDropped, drag_controller()->state());
// Ensure |window_|'s bounds did not change in response to 20,20
// wl_pointer::motion events sent at |kDragging| test step.
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({100, 100}, {}));
// Rather, only PlatformScreen's cursor position is updated accordingly.
EXPECT_EQ(gfx::Point(20, 20), screen_->GetCursorScreenPoint());
test_step = kDone;
break;
case kDone:
EXPECT_EQ(ET_MOUSE_EXITED, event->type());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({100, 100}, {}));
break;
case kDragging:
default:
FAIL() << " event=" << event->ToString()
<< " state=" << drag_controller()->state()
<< " step=" << static_cast<int>(test_step);
return;
}
});
EXPECT_CALL(delegate_, OnBoundsChanged(_))
.WillOnce([&](const gfx::Rect& bounds) {
EXPECT_EQ(State::kDetached, drag_controller()->state());
EXPECT_EQ(kDragging, test_step);
EXPECT_EQ(gfx::Point(100, 100), bounds.origin());
// Send a few wl_pointer::motion events skipping sync and dispatch
// checks, which will be done at |kDropping| test step handling.
SendPointerMotion(window_.get(), &delegate_, {30, 30},
/*sync_and_ensure_dispatched =*/false);
SendPointerMotion(window_.get(), &delegate_, {20, 20},
/*sync_and_ensure_dispatched =*/false);
SendDndDrop();
test_step = kDropping;
});
// RunMoveLoop() blocks until the dragging session ends, so resume test
// server's run loop until it returns.
server_.Resume();
move_loop_handler->RunMoveLoop({});
server_.Pause();
SendPointerEnter(window_.get(), &delegate_);
Sync();
EXPECT_EQ(State::kIdle, drag_controller()->state());
EXPECT_EQ(window_.get(), window_manager()->GetCurrentFocusedWindow());
EXPECT_EQ(window_->GetWidget(),
screen_->GetLocalProcessWidgetAtPoint({100, 100}, {}));
EXPECT_EQ(gfx::kNullAcceleratedWidget,
screen_->GetLocalProcessWidgetAtPoint({20, 20}, {}));
}
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandWindowDragControllerTest,
::testing::Values(kXdgShellStable));
INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
WaylandWindowDragControllerTest,
::testing::Values(kXdgShellV6));
} // namespace ui