5#include <QtCore/qcoreapplication.h>
6#include <QtCore/qsocketnotifier.h>
7#include <QtCore/qthread.h>
12
13
15 const void *data,
void *info)
18 QCFSocketNotifier *cfSocketNotifier =
static_cast<QCFSocketNotifier *>(info);
19 int nativeSocket = CFSocketGetNative(s);
20 MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket);
21 QEvent notifierEvent(QEvent::SockAct);
28 if (callbackType == kCFSocketConnectCallBack) {
31 if (socketInfo->readNotifier)
32 QCoreApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent);
33 if (socketInfo->writeNotifier)
34 QCoreApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent);
36 }
else if (callbackType == kCFSocketReadCallBack) {
37 if (socketInfo->readNotifier && socketInfo->readEnabled) {
38 socketInfo->readEnabled =
false;
39 QCoreApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent);
41 }
else if (callbackType == kCFSocketWriteCallBack) {
42 if (socketInfo->writeNotifier && socketInfo->writeEnabled) {
43 socketInfo->writeEnabled =
false;
44 QCoreApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent);
48 if (cfSocketNotifier->maybeCancelWaitForMoreEvents)
49 cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher);
53
54
57 CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
61 CFRunLoopAddSource(CFRunLoopGetCurrent(), loopSource, kCFRunLoopCommonModes);
66
67
71 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloop, kCFRunLoopCommonModes);
72 CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
73 CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
76QCFSocketNotifier::QCFSocketNotifier()
78 , maybeCancelWaitForMoreEvents(0)
79 , enableNotifiersObserver(0)
84QCFSocketNotifier::~QCFSocketNotifier()
89void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher)
91 eventDispatcher = hostEventDispacher;
94void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack)
96 maybeCancelWaitForMoreEvents = callBack;
99void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier)
102 int nativeSocket = notifier->socket();
103 int type = notifier->type();
105 if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
106 qWarning(
"QSocketNotifier: Internal error");
108 }
else if (notifier->thread() != eventDispatcher->thread()
109 || eventDispatcher->thread() != QThread::currentThread()) {
110 qWarning(
"QSocketNotifier: socket notifiers cannot be enabled from another thread");
115 if (type == QSocketNotifier::Exception) {
116 qWarning(
"QSocketNotifier::Exception is not supported on iOS");
121 MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
123 socketInfo =
new MacSocketInfo();
127 const int callbackTypes = kCFSocketConnectCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack;
128 CFSocketContext context = {0,
this, 0, 0, 0};
129 socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
130 if (CFSocketIsValid(socketInfo->socket) ==
false) {
131 qWarning(
"QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
135 CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
137 flags &= ~kCFSocketCloseOnInvalidate;
139 flags &= ~(kCFSocketAutomaticallyReenableWriteCallBack | kCFSocketAutomaticallyReenableReadCallBack);
140 CFSocketSetSocketFlags(socketInfo->socket, flags);
142 macSockets.insert(nativeSocket, socketInfo);
145 if (type == QSocketNotifier::Read) {
146 Q_ASSERT(socketInfo->readNotifier == 0);
147 socketInfo->readNotifier = notifier;
148 socketInfo->readEnabled =
false;
149 }
else if (type == QSocketNotifier::Write) {
150 Q_ASSERT(socketInfo->writeNotifier == 0);
151 socketInfo->writeNotifier = notifier;
152 socketInfo->writeEnabled =
false;
155 if (!enableNotifiersObserver) {
158 CFRunLoopObserverContext context = {};
160 enableNotifiersObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeSources,
161 true, 0, enableSocketNotifiers, &context);
162 Q_ASSERT(enableNotifiersObserver);
163 CFRunLoopAddObserver(CFRunLoopGetCurrent(), enableNotifiersObserver, kCFRunLoopCommonModes);
167void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier)
170 int nativeSocket = notifier->socket();
171 int type = notifier->type();
173 if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
174 qWarning(
"QSocketNotifier: Internal error");
176 }
else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) {
177 qWarning(
"QSocketNotifier: socket notifiers cannot be disabled from another thread");
182 if (type == QSocketNotifier::Exception) {
183 qWarning(
"QSocketNotifier::Exception is not supported on iOS");
186 MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
188 qWarning(
"QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
193 if (type == QSocketNotifier::Read) {
194 Q_ASSERT(notifier == socketInfo->readNotifier);
195 socketInfo->readNotifier = 0;
196 socketInfo->readEnabled =
false;
197 CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
198 }
else if (type == QSocketNotifier::Write) {
199 Q_ASSERT(notifier == socketInfo->writeNotifier);
200 socketInfo->writeNotifier = 0;
201 socketInfo->writeEnabled =
false;
202 CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
206 if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
207 unregisterSocketInfo(socketInfo);
209 macSockets.remove(nativeSocket);
213void QCFSocketNotifier::removeSocketNotifiers()
216 for (MacSocketInfo *socketInfo : std::as_const(macSockets)) {
217 unregisterSocketInfo(socketInfo);
223 destroyRunLoopObserver();
226void QCFSocketNotifier::destroyRunLoopObserver()
228 if (!enableNotifiersObserver)
231 CFRunLoopObserverInvalidate(enableNotifiersObserver);
232 CFRelease(enableNotifiersObserver);
233 enableNotifiersObserver = 0;
236void QCFSocketNotifier::unregisterSocketInfo(MacSocketInfo *socketInfo)
238 if (socketInfo->runloop) {
239 if (CFSocketIsValid(socketInfo->socket))
240 qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
241 CFRunLoopSourceInvalidate(socketInfo->runloop);
242 CFRelease(socketInfo->runloop);
244 CFSocketInvalidate(socketInfo->socket);
245 CFRelease(socketInfo->socket);
248void QCFSocketNotifier::enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoopActivity activity,
void *info)
253 const QCFSocketNotifier *that =
static_cast<QCFSocketNotifier *>(info);
255 for (MacSocketInfo *socketInfo : that->macSockets) {
256 if (!CFSocketIsValid(socketInfo->socket))
259 if (!socketInfo->runloop) {
261 if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
262 qWarning(
"QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
263 CFSocketInvalidate(socketInfo->socket);
273 socketInfo->readEnabled = (socketInfo->readNotifier !=
nullptr);
274 if (!socketInfo->readEnabled)
275 CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
276 socketInfo->writeEnabled = (socketInfo->writeNotifier !=
nullptr);
277 if (!socketInfo->writeEnabled)
278 CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
282 if (socketInfo->readNotifier && !socketInfo->readEnabled) {
283 socketInfo->readEnabled =
true;
284 CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
286 if (socketInfo->writeNotifier && !socketInfo->writeEnabled) {
287 socketInfo->writeEnabled =
true;
288 CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
QT_BEGIN_NAMESPACE void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, const void *data, void *info)