From c0e5f31ad8621127af17ae8cc1660a249391d1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Jun 2013 12:57:48 +0200 Subject: iOS: Wrap CFRunLoopSource in C++ class for easier code legibility Change-Id: If34953b171676f0246c2fb5e60c59f59350863ec Reviewed-by: Ian Dean Reviewed-by: Richard Moe Gustavsen --- .../eventdispatchers/qeventdispatcher_cf.mm | 81 +++++++--------------- .../eventdispatchers/qeventdispatcher_cf_p.h | 56 +++++++++++++-- 2 files changed, 77 insertions(+), 60 deletions(-) (limited to 'src/platformsupport/eventdispatchers') diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm index 55d40937b7..d270dbcfcb 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm @@ -50,17 +50,6 @@ QT_BEGIN_NAMESPACE QT_USE_NAMESPACE -static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2) -{ - return info1 == info2; -} - -void QEventDispatcherCoreFoundation::postedEventsRunLoopCallback(void *info) -{ - QEventDispatcherCoreFoundation *self = static_cast(info); - self->processPostedEvents(); -} - void QEventDispatcherCoreFoundation::nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info) { // The (one and only) CFRunLoopTimer has fired, which means that at least @@ -69,19 +58,8 @@ void QEventDispatcherCoreFoundation::nonBlockingTimerRunLoopCallback(CFRunLoopTi // timers will stop working. The work-around is to forward the callback to a // dedicated CFRunLoopSource that can recurse: QEventDispatcherCoreFoundation *self = static_cast(info); - CFRunLoopSourceSignal(self->m_blockingTimerRunLoopSource); -} - -void QEventDispatcherCoreFoundation::blockingTimerRunLoopCallback(void *info) -{ - // TODO: - // We also need to block this new timer source - // along with the posted event source when calling processEvents() - // "manually" to prevent livelock deep in CFRunLoop. - - QEventDispatcherCoreFoundation *self = static_cast(info); - self->m_timerInfoList.activateTimers(); - self->maybeStartCFRunLoopTimer(); + self->m_blockingTimerRunLoopSource.signal(); + // FIXME: And not wake up main run loop? } void QEventDispatcherCoreFoundation::maybeStartCFRunLoopTimer() @@ -147,54 +125,45 @@ void QEventDispatcherCoreFoundation::maybeStopCFRunLoopTimer() m_runLoopTimerRef = 0; } -void QEventDispatcherCoreFoundation::processPostedEvents() -{ - QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents); -} - QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) : QAbstractEventDispatcher(parent) , m_interrupted(false) + , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents) + , m_blockingTimerRunLoopSource(this, &QEventDispatcherCoreFoundation::processTimers) , m_runLoopTimerRef(0) { m_cfSocketNotifier.setHostEventDispatcher(this); - CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); - CFRunLoopSourceContext context; - bzero(&context, sizeof(CFRunLoopSourceContext)); - context.equal = runLoopSourceEqualCallback; - context.info = this; - - // source used to handle timers: - context.perform = QEventDispatcherCoreFoundation::blockingTimerRunLoopCallback; - 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 = QEventDispatcherCoreFoundation::postedEventsRunLoopCallback; - m_postedEventsRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); - Q_ASSERT(m_postedEventsRunLoopSource); - CFRunLoopAddSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes); + m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes); + + m_blockingTimerRunLoopSource.addToMode(kCFRunLoopCommonModes); + m_blockingTimerRunLoopSource.addToMode(CFStringRef(UITrackingRunLoopMode)); } QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation() { - CFRunLoopRef mainRunLoop = CFRunLoopGetMain(); - CFRunLoopRemoveSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes); - CFRelease(m_postedEventsRunLoopSource); - qDeleteAll(m_timerInfoList); maybeStopCFRunLoopTimer(); - CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes); - CFRunLoopRemoveSource(mainRunLoop, m_blockingTimerRunLoopSource, (CFStringRef) UITrackingRunLoopMode); - CFRelease(m_blockingTimerRunLoopSource); - m_cfSocketNotifier.removeSocketNotifiers(); } +void QEventDispatcherCoreFoundation::processPostedEvents() +{ + QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents); +} + +void QEventDispatcherCoreFoundation::processTimers() +{ + // TODO: + // We also need to block this new timer source + // along with the posted event source when calling processEvents() + // "manually" to prevent livelock deep in CFRunLoop. + + m_timerInfoList.activateTimers(); + maybeStartCFRunLoopTimer(); +} + bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags) { m_interrupted = false; @@ -336,7 +305,7 @@ int QEventDispatcherCoreFoundation::remainingTime(int timerId) void QEventDispatcherCoreFoundation::wakeUp() { - CFRunLoopSourceSignal(m_postedEventsRunLoopSource); + m_postedEventsRunLoopSource.signal(); CFRunLoopWakeUp(CFRunLoopGetMain()); } diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h index 6e5ce658a8..e12098d814 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h @@ -83,6 +83,55 @@ QT_BEGIN_NAMESPACE +class QEventDispatcherCoreFoundation; + +template +class RunLoopSource +{ +public: + typedef void (T::*CallbackFunction) (); + + enum { kHighestPriority = 0 } RunLoopSourcePriority; + + RunLoopSource(T *delegate, CallbackFunction callback) + : m_delegate(delegate), m_callback(callback) + { + CFRunLoopSourceContext context = {}; + context.info = this; + context.perform = RunLoopSource::process; + + m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, kHighestPriority, &context); + Q_ASSERT(m_source); + } + + ~RunLoopSource() + { + CFRunLoopSourceInvalidate(m_source); + CFRelease(m_source); + } + + void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) + { + if (!runLoop) + runLoop = CFRunLoopGetCurrent(); + + CFRunLoopAddSource(runLoop, m_source, mode); + } + + void signal() { CFRunLoopSourceSignal(m_source); } + +private: + static void process(void *info) + { + RunLoopSource *self = static_cast(info); + ((self->m_delegate)->*(self->m_callback))(); + } + + T *m_delegate; + CallbackFunction m_callback; + CFRunLoopSourceRef m_source; +}; + class QEventDispatcherCoreFoundation : public QAbstractEventDispatcher { Q_OBJECT @@ -111,8 +160,8 @@ public: private: bool m_interrupted; - CFRunLoopSourceRef m_postedEventsRunLoopSource; - CFRunLoopSourceRef m_blockingTimerRunLoopSource; + RunLoopSource<> m_postedEventsRunLoopSource; + RunLoopSource<> m_blockingTimerRunLoopSource; QTimerInfoList m_timerInfoList; CFRunLoopTimerRef m_runLoopTimerRef; @@ -120,12 +169,11 @@ private: QCFSocketNotifier m_cfSocketNotifier; void processPostedEvents(); + void processTimers(); void maybeStartCFRunLoopTimer(); void maybeStopCFRunLoopTimer(); - static void postedEventsRunLoopCallback(void *info); static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info); - static void blockingTimerRunLoopCallback(void *info); }; QT_END_NAMESPACE -- cgit v1.2.3