summaryrefslogtreecommitdiffstats
path: root/src/platformsupport
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@digia.com>2013-06-17 15:50:08 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-23 11:28:48 +0200
commit56083adbeabf3c7e96c39d884c7260ad75fcd1de (patch)
tree14863bf87a001cfbf46297175424800394517b9a /src/platformsupport
parent321cc1f27712100933da6a087e1846633b8b0051 (diff)
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 <ian@mediator-software.com> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Diffstat (limited to 'src/platformsupport')
-rw-r--r--src/platformsupport/eventdispatchers/qeventdispatcher_cf.mm25
-rw-r--r--src/platformsupport/eventdispatchers/qeventdispatcher_cf_p.h47
2 files changed, 72 insertions, 0 deletions
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 T = QEventDispatcherCoreFoundation>
+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<RunLoopObserver *>(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);
};