iOS: Fix logic for determining whether to exit the root event loop

Instead of trying to hook into various places where we might be in a
situation where the root event loop should exit, and then enabling the
runloop-observer, we always keep the observer active, and then do the
relevant checks whenever the run-loop exits.

The reason for checking if the event loop is running is that iOS will
enter and exit the root runloop as part of normal operation, eg due to
flicking a scroll view and switching the runloop mode, so we need to
ensure that we're actually supposed to exit the root event loop.

Change-Id: I9b84b47ee45e0c9e2b1d2ebb5a432ea92700b324
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
Tor Arne Vestbø 2013-10-29 15:56:24 +01:00 committed by The Qt Project
parent d2580054f9
commit 769abe8d2f
2 changed files with 8 additions and 32 deletions

View File

@ -54,11 +54,9 @@ public:
explicit QIOSEventDispatcher(QObject *parent = 0);
bool processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE;
void interrupt() Q_DECL_OVERRIDE;
void handleRunLoopExit(CFRunLoopActivity activity);
void checkIfEventLoopShouldExit();
void interruptEventLoopExec();
private:

View File

@ -446,6 +446,8 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
if (!m_processEventCallsAfterExec && (flags & QEventLoop::EventLoopExec)) {
++m_processEventCallsAfterExec;
m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
// We set a new jump point here that we can return to when the event loop
// is asked to exit, so that we can return from QEventLoop::exec().
switch (setjmp(processEventExitJumpPoint)) {
@ -475,44 +477,18 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo
if (m_processEventCallsAfterExec)
--m_processEventCallsAfterExec;
// If we're running with nested event loops and the application is quit,
// then the forwarded interrupt call will happen while our processEvent
// counter is still 2, and we won't detect that we're about to fall down
// to the root iOS run-loop. We do an extra check here to catch that case.
checkIfEventLoopShouldExit();
return processedEvents;
}
void QIOSEventDispatcher::interrupt()
{
QEventDispatcherCoreFoundation::interrupt();
if (!rootLevelRunLoopIntegration())
return;
// If an interrupt happens as part of a non-nested event loop, that is,
// by processing an event or timer in the root iOS run-loop, we'll be
// able to detect it here.
checkIfEventLoopShouldExit();
}
void QIOSEventDispatcher::checkIfEventLoopShouldExit()
{
if (m_processEventCallsAfterExec == 1) {
qEventDispatcherDebug() << "Hit root runloop level, watching for runloop exit";
m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes);
}
}
void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity)
{
Q_UNUSED(activity);
Q_ASSERT(activity == kCFRunLoopExit);
m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
interruptEventLoopExec();
if (m_processEventCallsAfterExec == 1 && !QThreadData::current()->eventLoops.top()->isRunning()) {
qEventDispatcherDebug() << "Root runloop level exited";
interruptEventLoopExec();
}
}
void QIOSEventDispatcher::interruptEventLoopExec()
@ -521,6 +497,8 @@ void QIOSEventDispatcher::interruptEventLoopExec()
--m_processEventCallsAfterExec;
m_runLoopExitObserver.removeFromMode(kCFRunLoopCommonModes);
// We re-set applicationProcessEventsReturnPoint here so that future
// calls to QEventLoop::exec() will end up back here after entering
// processEvents, instead of back in didFinishLaunchingWithOptions.