From 56083adbeabf3c7e96c39d884c7260ad75fcd1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Jun 2013 15:50:08 +0200 Subject: iOS: Make the event dispatcher properly emit aboutToBlock() and awake() This approach follows the same one used by the Cocoa event dispatcher. Change-Id: I2813b09beae07d90477c9ca506924058ace13f34 Reviewed-by: Ian Dean Reviewed-by: Richard Moe Gustavsen --- .../eventdispatchers/qeventdispatcher_cf.mm | 25 ++++++++++++ .../eventdispatchers/qeventdispatcher_cf_p.h | 47 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'src/platformsupport') diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm index d128d2936d..78f97d5556 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm @@ -134,6 +134,8 @@ QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) , m_interrupted(false) , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents) , m_blockingTimerRunLoopSource(this, &QEventDispatcherCoreFoundation::processTimers) + , m_awakeAndBlockObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, + kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting) , m_runLoopTimerRef(0) { m_cfSocketNotifier.setHostEventDispatcher(this); @@ -142,6 +144,8 @@ QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) m_blockingTimerRunLoopSource.addToMode(kCFRunLoopCommonModes); m_blockingTimerRunLoopSource.addToMode(CFStringRef(UITrackingRunLoopMode)); + + m_awakeAndBlockObserver.addToMode(kCFRunLoopCommonModes); } QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation() @@ -168,11 +172,32 @@ void QEventDispatcherCoreFoundation::processTimers() maybeStartCFRunLoopTimer(); } +void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity) +{ + switch (activity) { + case kCFRunLoopBeforeWaiting: + emit aboutToBlock(); + break; + case kCFRunLoopAfterWaiting: + emit awake(); + break; + default: + Q_UNREACHABLE(); + } +} + bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags) { m_interrupted = false; bool eventsProcessed = false; + // The documentation states that this signal is emitted after the event + // loop returns from a function that could block, which is not the case + // here, but all the other event dispatchers emit awake at the start of + // processEvents, and the QEventLoop auto-test has an explicit check for + // this behavior, so we assume it's for a good reason and do it as well. + emit awake(); + bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents; bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec); bool useExecMode = execFlagSet && !excludeUserEvents; diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h index e12098d814..e23b8f0ece 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h @@ -132,6 +132,48 @@ private: CFRunLoopSourceRef m_source; }; +template +class RunLoopObserver +{ +public: + typedef void (T::*CallbackFunction) (CFRunLoopActivity activity); + + RunLoopObserver(T *delegate, CallbackFunction callback, CFOptionFlags activities) + : m_delegate(delegate), m_callback(callback) + { + CFRunLoopObserverContext context = {}; + context.info = this; + + m_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, activities, true, 0, process, &context); + Q_ASSERT(m_observer); + } + + ~RunLoopObserver() + { + CFRunLoopObserverInvalidate(m_observer); + CFRelease(m_observer); + } + + void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) + { + if (!runLoop) + runLoop = CFRunLoopGetCurrent(); + + CFRunLoopAddObserver(runLoop, m_observer, mode); + } + +private: + static void process(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info) + { + RunLoopObserver *self = static_cast(info); + ((self->m_delegate)->*(self->m_callback))(activity); + } + + T *m_delegate; + CallbackFunction m_callback; + CFRunLoopObserverRef m_observer; +}; + class QEventDispatcherCoreFoundation : public QAbstractEventDispatcher { Q_OBJECT @@ -163,6 +205,8 @@ private: RunLoopSource<> m_postedEventsRunLoopSource; RunLoopSource<> m_blockingTimerRunLoopSource; + RunLoopObserver<> m_awakeAndBlockObserver; + QTimerInfoList m_timerInfoList; CFRunLoopTimerRef m_runLoopTimerRef; @@ -170,9 +214,12 @@ private: void processPostedEvents(); void processTimers(); + void maybeStartCFRunLoopTimer(); void maybeStopCFRunLoopTimer(); + void handleRunLoopActivity(CFRunLoopActivity activity); + static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info); }; -- cgit v1.2.3