Commit c19d8de7 authored by Alois Wohlschlager's avatar Alois Wohlschlager 🌾 Committed by David Edmundson
Browse files

Fix crash on drag-and-drop over panel

The fake drag-and-drop events caused by the panel reuse the real event's
mimeData, and were handled asynchronously. By the time the fake event
has been dispatched from the event loop, the mimeData may already have
been freed. Send the fake events synchronously again.

A guard is added to avoid the original potential bug of infinite recursion.

BUG: 398440
parent fa0efcf7
......@@ -912,16 +912,18 @@ bool PanelView::event(QEvent *e)
// first, don't mess with position if the cursor is actually outside the view:
// somebody is doing a click and drag that must not break when the cursor i outside
if (geometry().contains(QCursor::pos(screenToFollow()))) {
if (!containmentContainsPosition(me->windowPos())) {
auto me2 = new QMouseEvent(me->type(),
positionAdjustedForContainment(me->windowPos()),
positionAdjustedForContainment(me->windowPos()),
positionAdjustedForContainment(me->windowPos()) + position(),
me->button(),
me->buttons(),
me->modifiers());
QCoreApplication::postEvent(this, me2);
if (!containmentContainsPosition(me->windowPos()) && !m_fakeEventPending) {
QMouseEvent me2(me->type(),
positionAdjustedForContainment(me->windowPos()),
positionAdjustedForContainment(me->windowPos()),
positionAdjustedForContainment(me->windowPos()) + position(),
me->button(),
me->buttons(),
me->modifiers());
m_fakeEventPending = true;
QCoreApplication::sendEvent(this, &me2);
m_fakeEventPending = false;
return true;
}
} else {
......@@ -934,18 +936,20 @@ bool PanelView::event(QEvent *e)
case QEvent::Wheel: {
QWheelEvent *we = static_cast<QWheelEvent *>(e);
if (!containmentContainsPosition(we->pos())) {
auto we2 = new QWheelEvent(positionAdjustedForContainment(we->pos()),
positionAdjustedForContainment(we->pos()) + position(),
we->pixelDelta(),
we->angleDelta(),
we->angleDelta().y(),
we->orientation(),
we->buttons(),
we->modifiers(),
we->phase());
QCoreApplication::postEvent(this, we2);
if (!containmentContainsPosition(we->pos()) && !m_fakeEventPending) {
QWheelEvent we2(positionAdjustedForContainment(we->pos()),
positionAdjustedForContainment(we->pos()) + position(),
we->pixelDelta(),
we->angleDelta(),
we->angleDelta().y(),
we->orientation(),
we->buttons(),
we->modifiers(),
we->phase());
m_fakeEventPending = true;
QCoreApplication::sendEvent(this, &we2);
m_fakeEventPending = false;
return true;
}
break;
......@@ -953,14 +957,16 @@ bool PanelView::event(QEvent *e)
case QEvent::DragEnter: {
QDragEnterEvent *de = static_cast<QDragEnterEvent *>(e);
if (!containmentContainsPosition(de->pos())) {
auto de2 = new QDragEnterEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
QCoreApplication::postEvent(this, de2);
if (!containmentContainsPosition(de->pos()) && !m_fakeEventPending) {
QDragEnterEvent de2(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
m_fakeEventPending = true;
QCoreApplication::sendEvent(this, &de2);
m_fakeEventPending = false;
return true;
}
break;
......@@ -970,28 +976,32 @@ bool PanelView::event(QEvent *e)
break;
case QEvent::DragMove: {
QDragMoveEvent *de = static_cast<QDragMoveEvent *>(e);
if (!containmentContainsPosition(de->pos())) {
auto de2 = new QDragMoveEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
QCoreApplication::postEvent(this, de2);
if (!containmentContainsPosition(de->pos()) && !m_fakeEventPending) {
QDragMoveEvent de2(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
m_fakeEventPending = true;
QCoreApplication::sendEvent(this, &de2);
m_fakeEventPending = false;
return true;
}
break;
}
case QEvent::Drop: {
QDropEvent *de = static_cast<QDropEvent *>(e);
if (!containmentContainsPosition(de->pos())) {
auto de2 = new QDropEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
QCoreApplication::postEvent(this, de2);
if (!containmentContainsPosition(de->pos()) && !m_fakeEventPending) {
QDropEvent de2(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
m_fakeEventPending = true;
QCoreApplication::sendEvent(this, &de2);
m_fakeEventPending = false;
return true;
}
break;
......
......@@ -257,6 +257,7 @@ private:
int m_rightPadding;
bool m_initCompleted;
bool m_containsMouse = false;
bool m_fakeEventPending = false;
Qt::Alignment m_alignment;
QPointer<PlasmaQuick::ConfigView> m_panelConfigView;
ShellCorona *m_corona;
......
Supports Markdown
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