diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp index 2b5723d827708758001903832c5fe15e36f104a5..91f7aeb7d03cfc9f50c9dffeb7b99435cf25410e 100644 --- a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp +++ b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp @@ -55,11 +55,15 @@ void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CF // notifier is now gone. The upshot is we have to check the notifier // every time. if (callbackType == kCFSocketReadCallBack) { - if (socketInfo->readNotifier) + if (socketInfo->readNotifier && socketInfo->readEnabled) { + socketInfo->readEnabled = false; QGuiApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); + } } else if (callbackType == kCFSocketWriteCallBack) { - if (socketInfo->writeNotifier) + if (socketInfo->writeNotifier && socketInfo->writeEnabled) { + socketInfo->writeEnabled = false; QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); + } } if (cfSocketNotifier->maybeCancelWaitForMoreEvents) @@ -150,8 +154,8 @@ void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier) } CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); - flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write - flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation + // QSocketNotifier doesn't close the socket upon destruction/invalidation + flags &= ~(kCFSocketCloseOnInvalidate | kCFSocketAutomaticallyReenableReadCallBack); CFSocketSetSocketFlags(socketInfo->socket, flags); // Add CFSocket to runloop. @@ -171,15 +175,14 @@ void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier) 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); + socketInfo->readEnabled = false; } else if (type == QSocketNotifier::Write) { Q_ASSERT(socketInfo->writeNotifier == 0); socketInfo->writeNotifier = notifier; - CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + socketInfo->writeEnabled = false; } } @@ -212,10 +215,12 @@ void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) if (type == QSocketNotifier::Read) { Q_ASSERT(notifier == socketInfo->readNotifier); socketInfo->readNotifier = 0; + socketInfo->readEnabled = false; CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); } else if (type == QSocketNotifier::Write) { Q_ASSERT(notifier == socketInfo->writeNotifier); socketInfo->writeNotifier = 0; + socketInfo->writeEnabled = false; CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); } @@ -232,6 +237,24 @@ void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) } } +void QCFSocketNotifier::enableSocketNotifiers() +{ + // Enable CFSockets in runloop. + for (MacSocketHash::ConstIterator it = macSockets.constBegin(); it != macSockets.constEnd(); ++it) { + MacSocketInfo *socketInfo = (*it); + if (CFSocketIsValid(socketInfo->socket)) { + if (socketInfo->readNotifier && !socketInfo->readEnabled) { + socketInfo->readEnabled = true; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } + if (socketInfo->writeNotifier && !socketInfo->writeEnabled) { + socketInfo->writeEnabled = true; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + } + } +} + void QCFSocketNotifier::removeSocketNotifiers() { // Remove CFSockets from the runloop. diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h index af8122f753af0dc65744508373483d62c08e3a0d..1d6dcf288507905a32a5f88f963534cc98802bf9 100644 --- a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h +++ b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h @@ -53,11 +53,14 @@ QT_BEGIN_NAMESPACE struct MacSocketInfo { - MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {} + MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0), + readEnabled(false), writeEnabled(false) {} CFSocketRef socket; CFRunLoopSourceRef runloop; QObject *readNotifier; QObject *writeNotifier; + bool readEnabled; + bool writeEnabled; }; typedef QHash<int, MacSocketInfo *> MacSocketHash; @@ -81,6 +84,7 @@ public: void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack); void registerSocketNotifier(QSocketNotifier *notifier); void unregisterSocketNotifier(QSocketNotifier *notifier); + void enableSocketNotifiers(); void removeSocketNotifiers(); MacSocketHash macSockets; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 52b2e23345aa55c10d0e865bda42811970c1f8e3..b443233d1540a0ab428f87c18c2d7e71efa2c2b7 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -845,10 +845,13 @@ QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent) void QCocoaEventDispatcherPrivate::waitingObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info) { - if (activity == kCFRunLoopBeforeWaiting) - emit static_cast<QCocoaEventDispatcher*>(info)->aboutToBlock(); - else - emit static_cast<QCocoaEventDispatcher*>(info)->awake(); + QCocoaEventDispatcher *dispatcher = static_cast<QCocoaEventDispatcher *>(info); + if (activity == kCFRunLoopBeforeWaiting) { + dispatcher->d_func()->cfSocketNotifier.enableSocketNotifiers(); + emit dispatcher->aboutToBlock(); + } else { + emit dispatcher->awake(); + } } void QCocoaEventDispatcherPrivate::processPostedEvents()