diff options
author | Ian Dean <ian@mediator-software.com> | 2013-04-18 11:36:34 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-06-13 12:41:05 +0200 |
commit | 71b8f12aaa7b6195b27bdb8633191415d744322a (patch) | |
tree | b22d95ba4b5d0ca286633bcd02887548526c57d1 /src/platformsupport/eventdispatchers | |
parent | c172ae81c93ed8de8e8c080b849a6c7ba66a71d2 (diff) |
Correct implementation of nested runloop to match UIApplicationMain()
The previous implementation of the nested runloop was derived from the
Mac Cocoa implementation(?), and did not correctly deal with UI
animations and other UIKit functions which are run in a different mode
to the default mode. This version corrects that (in most cases) and
switches the implementation to use CoreFoundation instead of NextStep
APIs.
Change-Id: I45802d22044465749a1e5b6207d745268f6ae8a1
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
Diffstat (limited to 'src/platformsupport/eventdispatchers')
-rw-r--r-- | src/platformsupport/eventdispatchers/qioseventdispatcher.mm | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/src/platformsupport/eventdispatchers/qioseventdispatcher.mm b/src/platformsupport/eventdispatchers/qioseventdispatcher.mm index f8f8cc15ad..ab3036143d 100644 --- a/src/platformsupport/eventdispatchers/qioseventdispatcher.mm +++ b/src/platformsupport/eventdispatchers/qioseventdispatcher.mm @@ -117,7 +117,9 @@ void QIOSEventDispatcher::maybeStartCFRunLoopTimer() m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info); Q_ASSERT(m_runLoopTimerRef != 0); - CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes); + CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); + CFRunLoopAddTimer(mainRunLoop, m_runLoopTimerRef, kCFRunLoopCommonModes); + CFRunLoopAddTimer(mainRunLoop, m_runLoopTimerRef, (CFStringRef) UITrackingRunLoopMode); } else { struct timespec tv; // Calculate when the next timer should fire: @@ -167,6 +169,7 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent) m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); Q_ASSERT(m_blockingTimerRunLoopSource); CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, (CFStringRef) UITrackingRunLoopMode); // source used to handle posted events: context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback; @@ -183,7 +186,9 @@ QIOSEventDispatcher::~QIOSEventDispatcher() qDeleteAll(m_timerInfoList); maybeStopCFRunLoopTimer(); - CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + + CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, (CFStringRef) UITrackingRunLoopMode); CFRelease(m_blockingTimerRunLoopSource); m_cfSocketNotifier.removeSocketNotifiers(); @@ -198,14 +203,42 @@ bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec); bool useExecMode = execFlagSet && !excludeUserEvents; + CFTimeInterval distantFuture = CFTimeInterval(3600. * 24. * 365. * 10.); + SInt32 result; + if (useExecMode) { - NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; - while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted); + while (!m_interrupted) { + // Run a single pass on the runloop to unblock it + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + + // Run the default runloop until interrupted (by Qt or UIKit) + if (result != kCFRunLoopRunFinished) + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, distantFuture, false); + + // App has quit or Qt has interrupted? + if (result == kCFRunLoopRunFinished || m_interrupted) + break; + + // Runloop was interrupted by UIKit? + if (result == kCFRunLoopRunStopped && !m_interrupted) { + // Run runloop in UI tracking mode + if (CFRunLoopRunInMode((CFStringRef) UITrackingRunLoopMode, + distantFuture, false) == kCFRunLoopRunFinished) + break; + } + } eventsProcessed = true; } else { if (!(flags & QEventLoop::WaitForMoreEvents)) wakeUp(); - eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + + // Run runloop in default mode + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, distantFuture, true); + if (result != kCFRunLoopRunFinished) { + // Run runloop in UI tracking mode + CFRunLoopRunInMode((CFStringRef) UITrackingRunLoopMode, distantFuture, false); + } + eventsProcessed = (result == kCFRunLoopRunHandledSource); } return eventsProcessed; } @@ -308,8 +341,9 @@ void QIOSEventDispatcher::wakeUp() void QIOSEventDispatcher::interrupt() { - wakeUp(); + // Stop the runloop, which will cause processEvents() to exit m_interrupted = true; + CFRunLoopStop(CFRunLoopGetMain()); } void QIOSEventDispatcher::flush() |