+ wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" );
+
+ wxScopedPtr<wxCFEventLoopSource>
+ source(new wxCFEventLoopSource(handler, flags));
+
+ CFSocketContext context = { 0, source.get(), NULL, NULL, NULL };
+
+ int callbackTypes = 0;
+ if ( flags & wxEVENT_SOURCE_INPUT )
+ callbackTypes |= kCFSocketReadCallBack;
+ if ( flags & wxEVENT_SOURCE_OUTPUT )
+ callbackTypes |= kCFSocketWriteCallBack;
+
+ wxCFRef<CFSocketRef>
+ cfSocket(CFSocketCreateWithNative
+ (
+ kCFAllocatorDefault,
+ fd,
+ callbackTypes,
+ &wx_socket_callback,
+ &context
+ ));
+
+ if ( !cfSocket )
+ {
+ wxLogError(wxS("Failed to create event loop source socket."));
+ return NULL;
+ }
+
+ // Adjust the socket options to suit our needs:
+ CFOptionFlags sockopt = CFSocketGetSocketFlags(cfSocket);
+
+ // First, by default, write callback is not called repeatedly when data
+ // can be written to the socket but we need this behaviour so request
+ // it explicitly.
+ if ( flags & wxEVENT_SOURCE_OUTPUT )
+ sockopt |= kCFSocketAutomaticallyReenableWriteCallBack;
+
+ // Second, we use the socket to monitor the FD but it doesn't own it,
+ // so prevent the FD from being closed when the socket is invalidated.
+ sockopt &= ~kCFSocketCloseOnInvalidate;
+
+ CFSocketSetSocketFlags(cfSocket, sockopt);
+
+ wxCFRef<CFRunLoopSourceRef>
+ runLoopSource(CFSocketCreateRunLoopSource
+ (
+ kCFAllocatorDefault,
+ cfSocket,
+ 0 // Lowest index means highest priority
+ ));
+ if ( !runLoopSource )
+ {
+ wxLogError(wxS("Failed to create low level event loop source."));
+ CFSocketInvalidate(cfSocket);
+ return NULL;
+ }
+
+ // Save the socket so that we can remove it later if asked to.
+ source->InitSourceSocket(cfSocket.release());
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
+
+ return source.release();