wayland: Send wl_pointer leave before data_device enter

SeatInterface currently has a separation of kwin's focus scope to
pointer input with early return guards in notifyPointerEnter and
notifyPointerLeave where clients don't get pointer events.

However we don't update the initial state when a drag is started, this
patch notifies sends a pointer leave to the new drag target before the
data_device enter so things are consistent.

This also brings it in line with Weston and Mutter.

notifyPointerLeave has it's early return removed as for wayland windows
as we know nothing will have pointer focus.
This commit is contained in:
David Edmundson 2024-01-18 14:54:35 +00:00
parent 8a9cb06b41
commit 5386360928
3 changed files with 27 additions and 18 deletions

View file

@ -274,8 +274,6 @@ void TestDragAndDrop::testPointerDragAndDrop()
// verify that we did not get any further input events
QVERIFY(pointerMotionSpy.isEmpty());
// the release event is sent primarily for xwayland
QCOMPARE(buttonPressSpy.count(), 2);
}
void TestDragAndDrop::testTouchDragAndDrop()
@ -390,6 +388,8 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
QVERIFY(buttonPressSpy.wait());
QCOMPARE(buttonPressSpy.first().at(1).value<quint32>(), quint32(2));
QSignalSpy pointerLeftSpy(m_pointer, &KWayland::Client::Pointer::left);
// add some signal spies for client side
QSignalSpy dragEnteredSpy(m_dataDevice, &KWayland::Client::DataDevice::dragEntered);
QSignalSpy dragMotionSpy(m_dataDevice, &KWayland::Client::DataDevice::dragMotion);
@ -401,11 +401,13 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
m_dataSource->setDragAndDropActions(KWayland::Client::DataDeviceManager::DnDAction::Copy | KWayland::Client::DataDeviceManager::DnDAction::Move);
m_dataDevice->startDrag(buttonPressSpy.first().first().value<quint32>(), m_dataSource, s.get());
QVERIFY(dragStartedSpy.wait());
QCOMPARE(m_seatInterface->dragSurface(), serverSurface);
QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4());
QVERIFY(!m_seatInterface->dragIcon());
QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, buttonPressSpy.first().first().value<quint32>());
QVERIFY(dragEnteredSpy.wait());
QVERIFY(pointerLeftSpy.wait());
QVERIFY(dragEnteredSpy.count() || dragEnteredSpy.wait());
QCOMPARE(dragEnteredSpy.count(), 1);
QCOMPARE(dragEnteredSpy.first().first().value<quint32>(), m_display->serial());
QCOMPARE(dragEnteredSpy.first().last().toPointF(), QPointF(0, 0));
@ -452,7 +454,6 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource()
// verify that we did not get any further input events
QVERIFY(pointerMotionSpy.isEmpty());
QCOMPARE(buttonPressSpy.count(), 2);
}
void TestDragAndDrop::testPointerEventsIgnored()
@ -533,9 +534,7 @@ void TestDragAndDrop::testPointerEventsIgnored()
QCOMPARE(axisSpy.count(), 1);
QCOMPARE(pointerMotionSpy.count(), 1);
QCOMPARE(pointerEnteredSpy.count(), 1);
QVERIFY(pointerLeftSpy.isEmpty());
// the release event is sent primary for xwayland, see BUG 465444
QCOMPARE(buttonSpy.count(), 2);
QCOMPARE(pointerLeftSpy.count(), 1);
}
QTEST_GUILESS_MAIN(TestDragAndDrop)

View file

@ -268,6 +268,15 @@ void SeatInterfacePrivate::cancelDrag()
Q_EMIT q->dragEnded();
}
bool SeatInterfacePrivate::dragInhibitsPointer(SurfaceInterface *surface) const
{
if (drag.mode != SeatInterfacePrivate::Drag::Mode::Pointer) {
return false;
}
const bool targetHasDataDevice = !dataDevicesForSurface(surface).isEmpty();
return targetHasDataDevice;
}
void SeatInterfacePrivate::endDrag()
{
QObject::disconnect(drag.dragSourceDestroyConnection);
@ -445,11 +454,8 @@ void SeatInterface::notifyPointerMotion(const QPointF &pos)
if (!focusedSurface) {
return;
}
if (isDragPointer()) {
// data device will handle it directly
// for xwayland cases we still want to send pointer events
if (!d->dataDevicesForSurface(focusedSurface).isEmpty())
return;
if (d->dragInhibitsPointer(focusedSurface)) {
return;
}
if (focusedSurface->lockedPointer() && focusedSurface->lockedPointer()->isLocked()) {
return;
@ -520,6 +526,9 @@ void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
surfaceInputTransformation.scale(surface->scaleOverride());
d->drag.surface = surface;
d->drag.transformation = surfaceInputTransformation;
if (d->dragInhibitsPointer(surface)) {
notifyPointerLeave();
}
d->drag.target->updateDragTarget(surface, serial);
} else {
d->drag.surface = nullptr;
@ -558,7 +567,7 @@ void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF
if (!d->pointer) {
return;
}
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
if (d->dragInhibitsPointer(surface)) {
// ignore
return;
}
@ -597,10 +606,6 @@ void SeatInterface::notifyPointerLeave()
if (!d->pointer) {
return;
}
if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
// ignore
return;
}
if (d->globalPointer.focus.surface) {
disconnect(d->globalPointer.focus.destroyConnection);
@ -1352,6 +1357,7 @@ void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *
// no implicit grab, abort drag
return;
}
d->drag.dragImplicitGrabSerial = dragSerial;
// set initial drag target to ourself
@ -1369,7 +1375,10 @@ void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *
d->drag.target = d->dataDevicesForSurface(originSurface)[0];
}
if (d->drag.target) {
d->drag.target->updateDragTarget(originSurface, dragSerial);
if (d->dragInhibitsPointer(originSurface)) {
notifyPointerLeave();
}
d->drag.target->updateDragTarget(originSurface, display()->nextSerial());
}
Q_EMIT dragStarted();
Q_EMIT dragSurfaceChanged();

View file

@ -44,6 +44,7 @@ public:
void registerDataControlDevice(DataControlDeviceV1Interface *dataDevice);
void endDrag();
void cancelDrag();
bool dragInhibitsPointer(SurfaceInterface *surface) const;
SeatInterface *q;
QPointer<Display> display;