From 769abe8d2f34fdd5c67f82cd104187c4ca377f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 29 Oct 2013 15:56:24 +0100 Subject: [PATCH] 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 --- .../platforms/ios/qioseventdispatcher.h | 2 - .../platforms/ios/qioseventdispatcher.mm | 38 ++++--------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h index f2272ecd68..5caa7f5d2d 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.h +++ b/src/plugins/platforms/ios/qioseventdispatcher.h @@ -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: diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 3dd9c7ad9f..51eb10d385 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -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.