Fix crash in QMacPanGestureRecognizer
The reason it crashed was this: 1. Button was pressed => _panTimer started with the graphics view as destination. 2. Button was released => the graphicsview is destroyed 3. 300 ms later: Qt tries to deliver TimerEvent from _panTimer to the graphics view. Unfortunately, the graphics view is deleted, but Qt doesn't know that... (*crash*) We therefore chose to start the timer with a destination we are controlling the lifetime of: the QMacPanGestureRecognizer. Inside the timerEvent of that we can check if the actual target is already destroyed. Task-number: QTBUG-60404 Change-Id: Iff8f5b7217de42c4c5cf551ca507f0cff1c99a78 Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
This commit is contained in:
parent
364bd6ca74
commit
c1ead32a84
@ -43,6 +43,7 @@
|
|||||||
#include "qevent.h"
|
#include "qevent.h"
|
||||||
#include "qwidget.h"
|
#include "qwidget.h"
|
||||||
#include "qdebug.h"
|
#include "qdebug.h"
|
||||||
|
#include <QtCore/qcoreapplication.h>
|
||||||
|
|
||||||
#ifndef QT_NO_GESTURES
|
#ifndef QT_NO_GESTURES
|
||||||
|
|
||||||
@ -181,6 +182,16 @@ QGesture *QMacPanGestureRecognizer::create(QObject *target)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QMacPanGestureRecognizer::timerEvent(QTimerEvent *ev)
|
||||||
|
{
|
||||||
|
if (ev->timerId() == _panTimer.timerId()) {
|
||||||
|
if (_panTimer.isActive())
|
||||||
|
_panTimer.stop();
|
||||||
|
if (_target)
|
||||||
|
QCoreApplication::sendEvent(_target, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QGestureRecognizer::Result
|
QGestureRecognizer::Result
|
||||||
QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *event)
|
QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *event)
|
||||||
{
|
{
|
||||||
@ -195,7 +206,8 @@ QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *
|
|||||||
if (ev->touchPoints().size() == 1) {
|
if (ev->touchPoints().size() == 1) {
|
||||||
reset(gesture);
|
reset(gesture);
|
||||||
_startPos = QCursor::pos();
|
_startPos = QCursor::pos();
|
||||||
_panTimer.start(panBeginDelay, target);
|
_target = target;
|
||||||
|
_panTimer.start(panBeginDelay, this);
|
||||||
_panCanceled = false;
|
_panCanceled = false;
|
||||||
return QGestureRecognizer::MayBeGesture;
|
return QGestureRecognizer::MayBeGesture;
|
||||||
}
|
}
|
||||||
@ -242,7 +254,6 @@ QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *
|
|||||||
case QEvent::Timer: {
|
case QEvent::Timer: {
|
||||||
QTimerEvent *ev = static_cast<QTimerEvent *>(event);
|
QTimerEvent *ev = static_cast<QTimerEvent *>(event);
|
||||||
if (ev->timerId() == _panTimer.timerId()) {
|
if (ev->timerId() == _panTimer.timerId()) {
|
||||||
_panTimer.stop();
|
|
||||||
if (_panCanceled)
|
if (_panCanceled)
|
||||||
break;
|
break;
|
||||||
// Begin new pan session!
|
// Begin new pan session!
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
#include "qtimer.h"
|
#include "qtimer.h"
|
||||||
#include "qpoint.h"
|
#include "qpoint.h"
|
||||||
#include "qgesturerecognizer.h"
|
#include "qgesturerecognizer.h"
|
||||||
|
#include <QtCore/qpointer.h>
|
||||||
|
|
||||||
#ifndef QT_NO_GESTURES
|
#ifndef QT_NO_GESTURES
|
||||||
|
|
||||||
@ -88,10 +89,13 @@ public:
|
|||||||
QGesture *create(QObject *target);
|
QGesture *create(QObject *target);
|
||||||
QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event);
|
QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event);
|
||||||
void reset(QGesture *gesture);
|
void reset(QGesture *gesture);
|
||||||
|
protected:
|
||||||
|
void timerEvent(QTimerEvent *ev) override;
|
||||||
private:
|
private:
|
||||||
QPointF _startPos;
|
QPointF _startPos;
|
||||||
QBasicTimer _panTimer;
|
QBasicTimer _panTimer;
|
||||||
bool _panCanceled;
|
bool _panCanceled;
|
||||||
|
QPointer<QObject> _target;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -331,6 +331,9 @@ private slots:
|
|||||||
void graphicsViewParentPropagation();
|
void graphicsViewParentPropagation();
|
||||||
void panelPropagation();
|
void panelPropagation();
|
||||||
void panelStacksBehindParent();
|
void panelStacksBehindParent();
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
void deleteMacPanGestureRecognizerTargetWidget();
|
||||||
|
#endif
|
||||||
void deleteGestureTargetWidget();
|
void deleteGestureTargetWidget();
|
||||||
void deleteGestureTargetItem_data();
|
void deleteGestureTargetItem_data();
|
||||||
void deleteGestureTargetItem();
|
void deleteGestureTargetItem();
|
||||||
@ -1807,6 +1810,31 @@ void tst_Gestures::panelStacksBehindParent()
|
|||||||
QCOMPARE(panel->gestureOverrideEventsReceived, 0);
|
QCOMPARE(panel->gestureOverrideEventsReceived, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
void tst_Gestures::deleteMacPanGestureRecognizerTargetWidget()
|
||||||
|
{
|
||||||
|
QWidget window;
|
||||||
|
window.resize(400,400);
|
||||||
|
QGraphicsScene scene;
|
||||||
|
QGraphicsView *view = new QGraphicsView(&scene, &window);
|
||||||
|
view->resize(400, 400);
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
QVERIFY(QTest::qWaitForWindowExposed(&window));
|
||||||
|
QTouchDevice *device = QTest::createTouchDevice();
|
||||||
|
// QMacOSPenGestureRecognizer will start a timer on a touch press event
|
||||||
|
QTest::touchEvent(&window, device).press(1, QPoint(100, 100), &window);
|
||||||
|
delete view;
|
||||||
|
|
||||||
|
// wait until after that the QMacOSPenGestureRecognizer timer (300ms) is triggered.
|
||||||
|
// This is needed so that the whole test does not finish before the timer triggers
|
||||||
|
// and to make sure it crashes while executing *this* function. (otherwise it might give the
|
||||||
|
// impression that some of the subsequent test function caused the crash...)
|
||||||
|
|
||||||
|
QTest::qWait(400); // DO NOT CRASH while waiting
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void tst_Gestures::deleteGestureTargetWidget()
|
void tst_Gestures::deleteGestureTargetWidget()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user