iOS: Wrap CFRunLoopSource in C++ class for easier code legibility

Change-Id: If34953b171676f0246c2fb5e60c59f59350863ec
Reviewed-by: Ian Dean <ian@mediator-software.com>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
bb10
Tor Arne Vestbø 2013-06-17 12:57:48 +02:00 committed by The Qt Project
parent 29c1567ee4
commit c0e5f31ad8
2 changed files with 85 additions and 68 deletions

View File

@ -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<QEventDispatcherCoreFoundation *>(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<QEventDispatcherCoreFoundation *>(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<QEventDispatcherCoreFoundation *>(info);
self->m_timerInfoList.activateTimers();
self->maybeStartCFRunLoopTimer();
self->m_blockingTimerRunLoopSource.signal();
// FIXME: And not wake up main run loop?
}
void QEventDispatcherCoreFoundation::maybeStartCFRunLoopTimer()
@ -147,52 +125,43 @@ void QEventDispatcherCoreFoundation::maybeStopCFRunLoopTimer()
m_runLoopTimerRef = 0;
}
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);
m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes);
m_blockingTimerRunLoopSource.addToMode(kCFRunLoopCommonModes);
m_blockingTimerRunLoopSource.addToMode(CFStringRef(UITrackingRunLoopMode));
}
QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation()
{
qDeleteAll(m_timerInfoList);
maybeStopCFRunLoopTimer();
m_cfSocketNotifier.removeSocketNotifiers();
}
void QEventDispatcherCoreFoundation::processPostedEvents()
{
QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
}
QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent)
: QAbstractEventDispatcher(parent)
, m_interrupted(false)
, m_runLoopTimerRef(0)
void QEventDispatcherCoreFoundation::processTimers()
{
m_cfSocketNotifier.setHostEventDispatcher(this);
// 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.
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);
}
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();
m_timerInfoList.activateTimers();
maybeStartCFRunLoopTimer();
}
bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags)
@ -336,7 +305,7 @@ int QEventDispatcherCoreFoundation::remainingTime(int timerId)
void QEventDispatcherCoreFoundation::wakeUp()
{
CFRunLoopSourceSignal(m_postedEventsRunLoopSource);
m_postedEventsRunLoopSource.signal();
CFRunLoopWakeUp(CFRunLoopGetMain());
}

View File

@ -83,6 +83,55 @@
QT_BEGIN_NAMESPACE
class QEventDispatcherCoreFoundation;
template <class T = QEventDispatcherCoreFoundation>
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<RunLoopSource *>(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