summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@digia.com>2013-02-15 11:25:39 +0100
committerTor Arne Vestbø <tor.arne.vestbo@digia.com>2013-02-27 23:56:10 +0100
commitaa5528b050472d1d1097e2665fb346232cbfa7e5 (patch)
treee7c0b081141a808465b60077165adb2e60cd7bed /src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
parent0c1ae5f8660941fed55c468487635c9a74846f7a (diff)
iOS: Implement socket notifiers.
Create the QCFSocketNotifier class in platform support which contains shared socket notifier support for the Cocoa and iOS plugins. Remove the old code from the Cocoa plugin. The Cocoa code had one QCocoaEventDispatcher-specific call: maybeCancelWaitForMoreEvents. Create a forwarding function that is passed to QCFSocketNotifier. Change-Id: Ibf9bd4745ba4f577a55f13d0cc00f5ae04447405 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm193
1 files changed, 12 insertions, 181 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 987600c6b4..ed4f8cd1fb 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -270,58 +270,6 @@ QCocoaEventDispatcher::registeredTimers(QObject *object) const
return d->timerInfoList.registeredTimers(object);
}
-/**************************************************************************
- Socket Notifiers
- *************************************************************************/
-void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
- const void *, void *info) {
- QCocoaEventDispatcherPrivate *const eventDispatcher
- = static_cast<QCocoaEventDispatcherPrivate *>(info);
- int nativeSocket = CFSocketGetNative(s);
- MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket);
- QEvent notifierEvent(QEvent::SockAct);
-
- // There is a race condition that happen where we disable the notifier and
- // the kernel still has a notification to pass on. We then get this
- // notification after we've successfully disabled the CFSocket, but our Qt
- // notifier is now gone. The upshot is we have to check the notifier
- // everytime.
- if (callbackType == kCFSocketReadCallBack) {
- if (socketInfo->readNotifier)
- QGuiApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
- } else if (callbackType == kCFSocketWriteCallBack) {
- if (socketInfo->writeNotifier)
- QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
- }
-
- eventDispatcher->maybeCancelWaitForMoreEvents();
-}
-
-/*
- Adds a loop source for the given socket to the current run loop.
-*/
-CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
-{
- CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
- if (!loopSource)
- return 0;
-
- CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes);
- return loopSource;
-}
-
-/*
- Removes the loop source for the given socket from the current run loop.
-*/
-void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
-{
- Q_ASSERT(runloop);
- CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes);
- CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
- CFRunLoopSourceInvalidate(runloop);
-}
-
/*
Register a QSocketNotifier with the mac event system by creating a CFSocket with
with a read/write callback.
@@ -331,130 +279,14 @@ void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSource
*/
void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread()
- || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
-
- // Check if we have a CFSocket for the native socket, create one if not.
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- socketInfo = new MacSocketInfo();
-
- // Create CFSocket, specify that we want both read and write callbacks (the callbacks
- // are enabled/disabled later on).
- const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
- CFSocketContext context = {0, d, 0, 0, 0};
- socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
- if (CFSocketIsValid(socketInfo->socket) == false) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
- return;
- }
-
- CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
- flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write
- flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation
- CFSocketSetSocketFlags(socketInfo->socket, flags);
-
- // Add CFSocket to runloop.
- if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- return;
- }
-
- // Disable both callback types by default. This must be done after
- // we add the CFSocket to the runloop, or else these calls will have
- // no effect.
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
-
- d->macSockets.insert(nativeSocket, socketInfo);
- }
-
- // Increment read/write counters and select enable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(socketInfo->readNotifier == 0);
- socketInfo->readNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(socketInfo->writeNotifier == 0);
- socketInfo->writeNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
+ d->cfSocketNotifier.registerSocketNotifier(notifier);
}
-/*
- Unregister QSocketNotifer. The CFSocket correspoding to this notifier is
- removed from the runloop of this is the last notifier that users
- that CFSocket.
-*/
void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
- return;
- }
-
- // Decrement read/write counters and disable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(notifier == socketInfo->readNotifier);
- socketInfo->readNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(notifier == socketInfo->writeNotifier);
- socketInfo->writeNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
-
- // Remove CFSocket from runloop if this was the last QSocketNotifier.
- if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
- if (CFSocketIsValid(socketInfo->socket))
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- delete socketInfo;
- d->macSockets.remove(nativeSocket);
- }
+ d->cfSocketNotifier.unregisterSocketNotifier(notifier);
}
bool QCocoaEventDispatcher::hasPendingEvents()
@@ -940,11 +772,19 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
{
}
+void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
+{
+ static_cast<QCocoaEventDispatcher *>(eventDispatcher)->d_func()->maybeCancelWaitForMoreEvents();
+}
+
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
: QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
+ d->cfSocketNotifier.setHostEventDispatcher(this);
+ d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder);
+
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
@@ -1127,17 +967,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
[nsevent release];
}
- // Remove CFSockets from the runloop.
- for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) {
- MacSocketInfo *socketInfo = (*it);
- if (CFSocketIsValid(socketInfo->socket)) {
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- }
- }
+ d->cfSocketNotifier.removeSocketNotifiers();
+
CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
CFRelease(d->postedEventsSource);