iOS: Only use root level native runloop if at first level of processEvents

We used to support calling QEventLoop::exec() from within a processEvent
recursion and still jump down to the root native runloop, but this does
not work as intended due to how QEventDispatcherCoreFoundation uses
flags in its ProcessEventsState for e.g. deferred wake up or timer
updates. The logic in QEventDispatcherCoreFoundation assumes that
the next recursion to processEvents will be handled by itself, so
that it can interpret the flags in ProcessEventsState. The iOS
event dispatcher subclass, QIOSEventDispatcher, does neither of
these things, and should only be used from a 'clean' state.

Change-Id: I44fa156feecc45772806002465c35bef0797ead2
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com>
This commit is contained in:
Tor Arne Vestbø 2015-03-09 20:37:50 +01:00
parent 4c542ab592
commit dfd6fc7bce
2 changed files with 9 additions and 13 deletions

View File

@ -52,7 +52,7 @@ public:
void interruptEventLoopExec();
private:
uint m_processEventCallsAfterExec;
uint m_processEventLevel;
RunLoopObserver<QIOSEventDispatcher> m_runLoopExitObserver;
};

View File

@ -422,7 +422,7 @@ QT_USE_NAMESPACE
QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
: QEventDispatcherCoreFoundation(parent)
, m_processEventCallsAfterExec(0)
, m_processEventLevel(0)
, m_runLoopExitObserver(this, &QIOSEventDispatcher::handleRunLoopExit, kCFRunLoopExit)
{
}
@ -439,8 +439,8 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
return false;
}
if (!m_processEventCallsAfterExec && (flags & QEventLoop::EventLoopExec)) {
++m_processEventCallsAfterExec;
if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) {
++m_processEventLevel;
m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
@ -465,13 +465,9 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
Q_UNREACHABLE();
}
if (m_processEventCallsAfterExec)
++m_processEventCallsAfterExec;
++m_processEventLevel;
bool processedEvents = QEventDispatcherCoreFoundation::processEvents(flags);
if (m_processEventCallsAfterExec)
--m_processEventCallsAfterExec;
--m_processEventLevel;
return processedEvents;
}
@ -481,7 +477,7 @@ void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
Q_UNUSED(activity);
Q_ASSERT(activity == kCFRunLoopExit);
if (m_processEventCallsAfterExec == 1 && !QThreadData::current()->eventLoops.top()->isRunning()) {
if (m_processEventLevel == 1 && !QThreadData::current()->eventLoops.top()->isRunning()) {
qEventDispatcherDebug() << "Root runloop level exited";
interruptEventLoopExec();
}
@ -489,9 +485,9 @@ void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
void QIOSEventDispatcher::interruptEventLoopExec()
{
Q_ASSERT(m_processEventCallsAfterExec == 1);
Q_ASSERT(m_processEventLevel == 1);
--m_processEventCallsAfterExec;
--m_processEventLevel;
m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);