From e1a146806873879c380486f084a990936c5fa537 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 10 May 2024 13:20:30 +0200 Subject: [PATCH 58/59] Fix race condition in drag and drop The data source may be deleted by libwayland while we hold a reference to it. This could cause crashes when dragging and dropping repeatedly and very rapidly between two components. Tapping into sourceDestroyed() for this as well allows us to recover more gracefully. This also required adding some null pointer checks to the code, since it wasn't really prepared for the data source disappearing. Pick-to: 5.15 6.2 6.5 6.7 6.8 Fixes: QTBUG-124502 Change-Id: Ic3df8bf70176c5424ac5c693f8456f61e7b2762b Reviewed-by: Paul Olav Tvete (cherry picked from commit 792bd8510e3bc6b47bcaedfb1386390ce3a10a3a) --- src/compositor/wayland_wrapper/qwldatadevice.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/compositor/wayland_wrapper/qwldatadevice.cpp b/src/compositor/wayland_wrapper/qwldatadevice.cpp index a3a795f9..f301678e 100644 --- a/src/compositor/wayland_wrapper/qwldatadevice.cpp +++ b/src/compositor/wayland_wrapper/qwldatadevice.cpp @@ -76,6 +76,9 @@ void DataDevice::sourceDestroyed(DataSource *source) { if (m_selectionSource == source) m_selectionSource = nullptr; + + if (m_dragDataSource == source) + m_dragDataSource = nullptr; } #if QT_CONFIG(draganddrop) @@ -105,9 +108,11 @@ void DataDevice::setDragFocus(QWaylandSurface *focus, const QPointF &localPositi if (m_dragDataSource && !offer) return; - send_enter(resource->handle, serial, focus->resource(), - wl_fixed_from_double(localPosition.x()), wl_fixed_from_double(localPosition.y()), - offer->resource()->handle); + if (offer) { + send_enter(resource->handle, serial, focus->resource(), + wl_fixed_from_double(localPosition.x()), wl_fixed_from_double(localPosition.y()), + offer->resource()->handle); + } m_dragFocus = focus; m_dragFocusResource = resource; @@ -139,7 +144,7 @@ void DataDevice::drop() if (m_dragFocusResource) { send_drop(m_dragFocusResource->handle); setDragFocus(nullptr, QPoint()); - } else { + } else if (m_dragDataSource) { m_dragDataSource->cancel(); } m_dragOrigin = nullptr; @@ -155,6 +160,8 @@ void DataDevice::data_device_start_drag(Resource *resource, struct ::wl_resource { m_dragClient = resource->client(); m_dragDataSource = source ? DataSource::fromResource(source) : nullptr; + if (m_dragDataSource) + m_dragDataSource->setDevice(this); m_dragOrigin = QWaylandSurface::fromResource(origin); QWaylandDrag *drag = m_seat->drag(); setDragIcon(icon ? QWaylandSurface::fromResource(icon) : nullptr); -- 2.46.0