Commit 3ed97cc4 authored by Nick Diego Yamane's avatar Nick Diego Yamane Committed by Commit Bot

ozone/wayland: Fix input unresponsiveness after DND sessions

DragDropDelegate implementations, such as WebContents, require that the
DragLeave event is fired before DragFinished when the DnD session ends
with no actual data transfer (cancelled), e.g: the drop happens on top
of a widget that does not accept the data being dragged. Otherwise, it
might lead to issues like crbug.com/1109324, where the whole web
contents view becomes unresponsive. This patch fixes it by making sure
OnDragLeave() is called just before OnDragFinished() when the session
ends with a cancellation.

R=tonikitoo@igalia.com

Test: ozone_unittests --gtest_filter='*DragControllerTest.StartAndCancel*'
Bug: 1109324
Change-Id: Idcbdb93ef0187847e2e779f3e4ac568bc594b90d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2318511Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarAntonio Gomes (GMT-4) <tonikitoo@igalia.com>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Auto-Submit: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/master@{#792471}
parent 60fa9c04
...@@ -216,8 +216,14 @@ void WaylandDataDragController::OnDragDrop() { ...@@ -216,8 +216,14 @@ void WaylandDataDragController::OnDragDrop() {
void WaylandDataDragController::OnDataSourceFinish(bool completed) { void WaylandDataDragController::OnDataSourceFinish(bool completed) {
DCHECK(data_source_); DCHECK(data_source_);
if (origin_window_) DCHECK(origin_window_);
origin_window_->OnDragSessionClose(data_source_->dnd_action());
origin_window_->OnDragSessionClose(data_source_->dnd_action());
// DnD handlers expect DragLeave to be sent for drag sessions that end up
// with no data transfer (wl_data_source::cancelled event).
if (!completed)
origin_window_->OnDragLeave();
origin_window_ = nullptr; origin_window_ = nullptr;
data_source_.reset(); data_source_.reset();
......
...@@ -169,6 +169,24 @@ class WaylandDataDragControllerTest : public WaylandTest { ...@@ -169,6 +169,24 @@ class WaylandDataDragControllerTest : public WaylandTest {
Sync(); Sync();
} }
void ScheduleDragCancel() {
Sync();
if (!data_device_manager_->data_source()) {
// The data source is created asynchronously by the data drag controller.
// If it is null at this point, it means that the task for that has not
// yet executed, and we have to try again a bit later.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
base::Unretained(this)));
return;
}
data_device_manager_->data_source()->OnCancelled();
Sync();
}
protected: protected:
wl::TestDataDeviceManager* data_device_manager_; wl::TestDataDeviceManager* data_device_manager_;
std::unique_ptr<MockDropHandler> drop_handler_; std::unique_ptr<MockDropHandler> drop_handler_;
...@@ -444,6 +462,35 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) { ...@@ -444,6 +462,35 @@ TEST_P(WaylandDataDragControllerTest, ValidateDroppedXMozUrl) {
} }
} }
// Verifies the correct delegate functions are called when a drag session is
// started and cancelled within the same surface.
TEST_P(WaylandDataDragControllerTest, StartAndCancel) {
const bool restored_focus = window_->has_pointer_focus();
window_->SetPointerFocus(true);
ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
OSExchangeData os_exchange_data;
os_exchange_data.SetString(sample_text_for_dnd());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&WaylandDataDragControllerTest::ScheduleDragCancel,
base::Unretained(this)));
// DnD handlers expect DragLeave to be sent before DragFinished when drag
// sessions end up with no data transfer (cancelled). Otherwise, it might lead
// to issues like https://crbug.com/1109324.
EXPECT_CALL(*drop_handler_, OnDragLeave()).Times(1);
EXPECT_CALL(*drag_handler_delegate_, OnDragFinished(_)).Times(1);
static_cast<WaylandToplevelWindow*>(window_.get())
->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
drag_handler_delegate_.get());
Sync();
window_->SetPointerFocus(restored_focus);
}
INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest, INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
WaylandDataDragControllerTest, WaylandDataDragControllerTest,
::testing::Values(kXdgShellStable)); ::testing::Values(kXdgShellStable));
......
...@@ -46,7 +46,8 @@ class WM_PLATFORM_EXPORT WmDropHandler { ...@@ -46,7 +46,8 @@ class WM_PLATFORM_EXPORT WmDropHandler {
virtual void OnDragDrop(std::unique_ptr<ui::OSExchangeData> data, virtual void OnDragDrop(std::unique_ptr<ui::OSExchangeData> data,
int modifiers) = 0; int modifiers) = 0;
// Notifies that dragging is left. // Notifies that dragging is left. Must be called before
// WmDragHandler::OnDragFinished when the drag session gets cancelled.
virtual void OnDragLeave() = 0; virtual void OnDragLeave() = 0;
protected: protected:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment