From 0613e8f4c9305aba3f6a5992ab36f32641a88585 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 11 Nov 2020 15:59:49 +0200 Subject: [PATCH] Safely end drag if the source data device gets destroyed We cannot end a drag after the destroyed() signal for the source data device is emitted because DataDeviceInterface and its d pointer are gone by that time. --- src/wayland/datadevice_interface.cpp | 1 + src/wayland/datadevice_interface.h | 1 + src/wayland/seat_interface.cpp | 30 +++++++++++++--------------- src/wayland/seat_interface_p.h | 1 + 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp index 29b6d8f49b..6ff8c13459 100644 --- a/src/wayland/datadevice_interface.cpp +++ b/src/wayland/datadevice_interface.cpp @@ -175,6 +175,7 @@ DataOfferInterface *DataDeviceInterfacePrivate::createDataOffer(AbstractDataSour void DataDeviceInterfacePrivate::data_device_destroy_resource(QtWaylandServer::wl_data_device::Resource *resource) { Q_UNUSED(resource) + emit q->aboutToBeDestroyed(); delete q; } diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h index 991220a23b..a0d6fe5a89 100644 --- a/src/wayland/datadevice_interface.h +++ b/src/wayland/datadevice_interface.h @@ -118,6 +118,7 @@ public: wl_client *client(); Q_SIGNALS: + void aboutToBeDestroyed(); void dragStarted(); void selectionChanged(KWaylandServer::DataSourceInterface*); void selectionCleared(); diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index a1e1d191a3..2c536eaaad 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -293,20 +293,15 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) } drag.source = dataDevice; drag.sourcePointer = interfaceForSurface(originSurface, pointers); - drag.destroyConnection = QObject::connect(dataDevice, &QObject::destroyed, q, + drag.destroyConnection = QObject::connect(dataDevice, &DataDeviceInterface::aboutToBeDestroyed, q, [this] { - endDrag(display->nextSerial()); + cancelDrag(display->nextSerial()); } ); if (dataDevice->dragSource()) { drag.dragSourceDestroyConnection = QObject::connect(dataDevice->dragSource(), &AbstractDataSource::aboutToBeDestroyed, q, [this] { - const auto serial = display->nextSerial(); - if (drag.target) { - drag.target->updateDragTarget(nullptr, serial); - drag.target = nullptr; - } - endDrag(serial); + cancelDrag(display->nextSerial()); } ); } else { @@ -395,6 +390,15 @@ void SeatInterface::Private::registerPrimarySelectionDevice(PrimarySelectionDevi } } +void SeatInterface::Private::cancelDrag(quint32 serial) +{ + if (drag.target) { + drag.target->updateDragTarget(nullptr, serial); + drag.target = nullptr; + } + endDrag(serial); +} + void SeatInterface::Private::endDrag(quint32 serial) { QObject::disconnect(drag.destroyConnection); @@ -1215,14 +1219,8 @@ void SeatInterface::cancelTouchSequence() (*it)->cancel(); } if (d->drag.mode == Private::Drag::Mode::Touch) { - // cancel the drag, don't drop. - if (d->drag.target) { - // remove the current target - d->drag.target->updateDragTarget(nullptr, 0); - d->drag.target = nullptr; - } - // and end the drag for the source, serial does not matter - d->endDrag(0); + // cancel the drag, don't drop. serial does not matter + d->cancelDrag(0); } d->globalTouch.ids.clear(); } diff --git a/src/wayland/seat_interface_p.h b/src/wayland/seat_interface_p.h index 81ebe4f9e3..9b16dd6fb5 100644 --- a/src/wayland/seat_interface_p.h +++ b/src/wayland/seat_interface_p.h @@ -42,6 +42,7 @@ public: void registerDataDevice(DataDeviceInterface *dataDevice); void registerDataControlDevice(DataControlDeviceV1Interface *dataDevice); void endDrag(quint32 serial); + void cancelDrag(quint32 serial); quint32 nextSerial() const; QString name;