From c19d8de7a7b9dc504c329111b812c943a0bd1ec0 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sat, 17 Apr 2021 22:17:37 +0000 Subject: [PATCH] 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 --- shell/panelview.cpp | 102 ++++++++++++++++++++++++-------------------- shell/panelview.h | 1 + 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/shell/panelview.cpp b/shell/panelview.cpp index a699cc84c..243d5b539 100644 --- a/shell/panelview.cpp +++ b/shell/panelview.cpp @@ -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(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(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(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(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; diff --git a/shell/panelview.h b/shell/panelview.h index fb71824bf..06e5d048d 100644 --- a/shell/panelview.h +++ b/shell/panelview.h @@ -257,6 +257,7 @@ private: int m_rightPadding; bool m_initCompleted; bool m_containsMouse = false; + bool m_fakeEventPending = false; Qt::Alignment m_alignment; QPointer m_panelConfigView; ShellCorona *m_corona;