Client: Don't freeze in QDrag::exec if there was no drag focus
002fade6 fixed a crash when starting a drag without a valid focus, but there is still a problem, because QDrag::exec will never return because it's waiting indefinitely in an event loop. - QWaylandDataDevice::startDrag can now fail by returning false. - When starting a drag fails, we cancel the drag through QWaylandDrag::cancelDrag wrapped in invokeMethod. - Also, don't unnecessarily create a data_source if we cannot start a drag. [ChangeLog][QPA plugin] Fixed a freeze that happened when starting a drag-and-drop operation without a valid source surface. Change-Id: Iea19b0c92c196a44d1274a966bee4ff519632d34 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
parent
d87b6d8231
commit
59486fdf3b
@ -102,19 +102,22 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
|
|||||||
return m_dragOffer.data();
|
return m_dragOffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
||||||
{
|
{
|
||||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
|
||||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
|
||||||
|
|
||||||
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
|
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
|
||||||
if (!origin)
|
if (!origin)
|
||||||
origin = m_display->currentInputDevice()->touchFocus();
|
origin = m_display->currentInputDevice()->touchFocus();
|
||||||
|
|
||||||
if (origin)
|
if (!origin) {
|
||||||
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
|
|
||||||
else
|
|
||||||
qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found.";
|
qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
||||||
|
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
||||||
|
|
||||||
|
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWaylandDataDevice::cancelDrag()
|
void QWaylandDataDevice::cancelDrag()
|
||||||
|
@ -89,7 +89,7 @@ public:
|
|||||||
|
|
||||||
#if QT_CONFIG(draganddrop)
|
#if QT_CONFIG(draganddrop)
|
||||||
QWaylandDataOffer *dragOffer() const;
|
QWaylandDataOffer *dragOffer() const;
|
||||||
void startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
||||||
void cancelDrag();
|
void cancelDrag();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -66,8 +66,13 @@ void QWaylandDrag::startDrag()
|
|||||||
{
|
{
|
||||||
QBasicDrag::startDrag();
|
QBasicDrag::startDrag();
|
||||||
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
|
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
|
||||||
m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon);
|
if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
|
||||||
icon->addAttachOffset(-drag()->hotSpot());
|
icon->addAttachOffset(-drag()->hotSpot());
|
||||||
|
} else {
|
||||||
|
// Cancelling immediately does not work, since the event loop for QDrag::exec is started
|
||||||
|
// after this function returns.
|
||||||
|
QMetaObject::invokeMethod(this, [this](){ cancelDrag(); }, Qt::QueuedConnection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWaylandDrag::cancel()
|
void QWaylandDrag::cancel()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user