Synchronize QEventDispatcherWin32::processEvents() with QCoreApplication
QCoreApplication has a special internal mechanism to control whether the event dispatcher should block after delivering the posted events. To handle queued connections in nested loops properly, we should use that functionality. Pick-to: 5.15 Fixes: QTBUG-85981 Change-Id: I124179a23b26a995cf95ed379e97bfa62c95f42a Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>bb10
parent
5449bddb04
commit
fe4b246446
|
|
@ -529,6 +529,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||
// QCoreApplication::sendPostedEvents() takes care about recursions.
|
||||
sendPostedEvents();
|
||||
|
||||
auto threadData = d->threadData.loadRelaxed();
|
||||
bool canWait;
|
||||
bool retVal = false;
|
||||
do {
|
||||
|
|
@ -599,7 +600,8 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||
// wait for message
|
||||
canWait = (!retVal
|
||||
&& !d->interrupt.loadRelaxed()
|
||||
&& (flags & QEventLoop::WaitForMoreEvents));
|
||||
&& flags.testFlag(QEventLoop::WaitForMoreEvents)
|
||||
&& threadData->canWaitLocked());
|
||||
if (canWait) {
|
||||
emit aboutToBlock();
|
||||
MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ private slots:
|
|||
void sendPostedEvents_data();
|
||||
void sendPostedEvents();
|
||||
void processEventsOnlySendsQueuedEvents();
|
||||
void postedEventsPingPong();
|
||||
void eventLoopExit();
|
||||
};
|
||||
|
||||
|
|
@ -349,6 +350,31 @@ void tst_QEventDispatcher::processEventsOnlySendsQueuedEvents()
|
|||
QCOMPARE(object.eventsReceived, 4);
|
||||
}
|
||||
|
||||
void tst_QEventDispatcher::postedEventsPingPong()
|
||||
{
|
||||
QEventLoop mainLoop;
|
||||
|
||||
// We need to have at least two levels of nested loops
|
||||
// for the posted event to get stuck (QTBUG-85981).
|
||||
QMetaObject::invokeMethod(this, [this, &mainLoop]() {
|
||||
QMetaObject::invokeMethod(this, [&mainLoop]() {
|
||||
// QEventLoop::quit() should be invoked on the next
|
||||
// iteration of mainLoop.exec().
|
||||
QMetaObject::invokeMethod(&mainLoop, &QEventLoop::quit,
|
||||
Qt::QueuedConnection);
|
||||
}, Qt::QueuedConnection);
|
||||
mainLoop.processEvents();
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
// We should use Qt::CoarseTimer on Windows, to prevent event
|
||||
// dispatcher from sending a posted event.
|
||||
QTimer::singleShot(500, Qt::CoarseTimer, [&mainLoop]() {
|
||||
mainLoop.exit(1);
|
||||
});
|
||||
|
||||
QCOMPARE(mainLoop.exec(), 0);
|
||||
}
|
||||
|
||||
void tst_QEventDispatcher::eventLoopExit()
|
||||
{
|
||||
// This test was inspired by QTBUG-79477. A particular
|
||||
|
|
|
|||
Loading…
Reference in New Issue