Use CFSocket instead of CFFileDescriptor in wxCFEventLoopSource.
Use OS X socket APIs for monitoring file descriptors. They are more flexible than CFFileDescriptor functions and can be used with any descriptors, not necessarily the socket ones. See #10258. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74342 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		@@ -11,7 +11,7 @@
 | 
			
		||||
#ifndef _WX_OSX_EVTLOOPSRC_H_
 | 
			
		||||
#define _WX_OSX_EVTLOOPSRC_H_
 | 
			
		||||
 | 
			
		||||
typedef struct __CFFileDescriptor *CFFileDescriptorRef;
 | 
			
		||||
typedef struct __CFSocket* CFSocketRef;
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// wxCFEventLoopSource: CoreFoundation-based wxEventLoopSource for OS X
 | 
			
		||||
@@ -20,19 +20,23 @@ typedef struct __CFFileDescriptor *CFFileDescriptorRef;
 | 
			
		||||
class WXDLLIMPEXP_BASE wxCFEventLoopSource : public wxEventLoopSource
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    // Create a new source in uninitialized state, call InitSocketRef() later
 | 
			
		||||
    // to associate it with the socket it is going to use.
 | 
			
		||||
    wxCFEventLoopSource(wxEventLoopSourceHandler *handler, int flags)
 | 
			
		||||
        : wxEventLoopSource(handler, flags)
 | 
			
		||||
    {
 | 
			
		||||
        m_cffd = NULL;
 | 
			
		||||
        m_cfSocket = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // we take ownership of this CFFileDescriptorRef
 | 
			
		||||
    void SetFileDescriptor(CFFileDescriptorRef cffd);
 | 
			
		||||
    // Finish initialization of the event loop source by providing the
 | 
			
		||||
    // associated socket. This object takes ownership of it and will release it.
 | 
			
		||||
    void InitSourceSocket(CFSocketRef cfSocket);
 | 
			
		||||
 | 
			
		||||
    // Destructor deletes the associated socket.
 | 
			
		||||
    virtual ~wxCFEventLoopSource();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    CFFileDescriptorRef m_cffd;
 | 
			
		||||
    CFSocketRef m_cfSocket;
 | 
			
		||||
 | 
			
		||||
    wxDECLARE_NO_COPY_CLASS(wxCFEventLoopSource);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -42,23 +42,28 @@
 | 
			
		||||
    #include "wx/nonownedwnd.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <CoreFoundation/CFSocket.h>
 | 
			
		||||
 | 
			
		||||
// ============================================================================
 | 
			
		||||
// wxCFEventLoopSource and wxCFEventLoop implementation
 | 
			
		||||
// ============================================================================
 | 
			
		||||
 | 
			
		||||
#if wxUSE_EVENTLOOP_SOURCE
 | 
			
		||||
 | 
			
		||||
void wxCFEventLoopSource::SetFileDescriptor(CFFileDescriptorRef cffd)
 | 
			
		||||
void wxCFEventLoopSource::InitSourceSocket(CFSocketRef cfSocket)
 | 
			
		||||
{
 | 
			
		||||
    wxASSERT_MSG( !m_cffd, "shouldn't be called more than once" );
 | 
			
		||||
    wxASSERT_MSG( !m_cfSocket, "shouldn't be called more than once" );
 | 
			
		||||
 | 
			
		||||
    m_cffd = cffd;
 | 
			
		||||
    m_cfSocket = cfSocket;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
wxCFEventLoopSource::~wxCFEventLoopSource()
 | 
			
		||||
{
 | 
			
		||||
    if ( m_cffd )
 | 
			
		||||
        CFRelease(m_cffd);
 | 
			
		||||
    if ( m_cfSocket )
 | 
			
		||||
    {
 | 
			
		||||
        CFSocketInvalidate(m_cfSocket);
 | 
			
		||||
        CFRelease(m_cfSocket);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // wxUSE_EVENTLOOP_SOURCE
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@
 | 
			
		||||
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
 | 
			
		||||
#include <CoreFoundation/CFFileDescriptor.h>
 | 
			
		||||
#include <CoreFoundation/CFSocket.h>
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
@@ -114,34 +113,36 @@ int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
void EnableDescriptorCallBacks(CFFileDescriptorRef cffd, int flags)
 | 
			
		||||
{
 | 
			
		||||
    if ( flags & wxEVENT_SOURCE_INPUT )
 | 
			
		||||
        CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack);
 | 
			
		||||
    if ( flags & wxEVENT_SOURCE_OUTPUT )
 | 
			
		||||
        CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorWriteCallBack);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C"
 | 
			
		||||
void
 | 
			
		||||
wx_cffiledescriptor_callback(CFFileDescriptorRef cffd,
 | 
			
		||||
                             CFOptionFlags flags,
 | 
			
		||||
                             void *ctxData)
 | 
			
		||||
wx_socket_callback(CFSocketRef WXUNUSED(s),
 | 
			
		||||
                   CFSocketCallBackType callbackType,
 | 
			
		||||
                   CFDataRef WXUNUSED(address),
 | 
			
		||||
                   void const *WXUNUSED(data),
 | 
			
		||||
                   void *ctxData)
 | 
			
		||||
{
 | 
			
		||||
    wxLogTrace(wxTRACE_EVT_SOURCE,
 | 
			
		||||
               "CFFileDescriptor callback, flags=%d", flags);
 | 
			
		||||
               "CFSocket callback, type=%d", callbackType);
 | 
			
		||||
 | 
			
		||||
    wxCFEventLoopSource * const
 | 
			
		||||
        source = static_cast<wxCFEventLoopSource *>(ctxData);
 | 
			
		||||
 | 
			
		||||
    wxEventLoopSourceHandler * const
 | 
			
		||||
        handler = source->GetHandler();
 | 
			
		||||
    if ( flags & kCFFileDescriptorReadCallBack )
 | 
			
		||||
        handler->OnReadWaiting();
 | 
			
		||||
    if ( flags & kCFFileDescriptorWriteCallBack )
 | 
			
		||||
        handler->OnWriteWaiting();
 | 
			
		||||
 | 
			
		||||
    // we need to re-enable callbacks to be called again
 | 
			
		||||
    EnableDescriptorCallBacks(cffd, source->GetFlags());
 | 
			
		||||
    switch ( callbackType )
 | 
			
		||||
    {
 | 
			
		||||
        case kCFSocketReadCallBack:
 | 
			
		||||
            handler->OnReadWaiting();
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case kCFSocketWriteCallBack:
 | 
			
		||||
            handler->OnWriteWaiting();
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            wxFAIL_MSG( "Unexpected callback type." );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // anonymous namespace
 | 
			
		||||
@@ -157,31 +158,63 @@ public:
 | 
			
		||||
        wxScopedPtr<wxCFEventLoopSource>
 | 
			
		||||
            source(new wxCFEventLoopSource(handler, flags));
 | 
			
		||||
 | 
			
		||||
        CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL };
 | 
			
		||||
        wxCFRef<CFFileDescriptorRef>
 | 
			
		||||
            cffd(CFFileDescriptorCreate
 | 
			
		||||
                 (
 | 
			
		||||
                      kCFAllocatorDefault,
 | 
			
		||||
                      fd,
 | 
			
		||||
                      true,   // close on invalidate
 | 
			
		||||
                      wx_cffiledescriptor_callback,
 | 
			
		||||
                      &ctx
 | 
			
		||||
                 ));
 | 
			
		||||
        if ( !cffd )
 | 
			
		||||
        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>
 | 
			
		||||
            cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0));
 | 
			
		||||
        if ( !cfsrc )
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CFRunLoopRef cfloop = CFRunLoopGetCurrent();
 | 
			
		||||
        CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode);
 | 
			
		||||
        // Save the socket so that we can remove it later if asked to.
 | 
			
		||||
        source->InitSourceSocket(cfSocket.release());
 | 
			
		||||
 | 
			
		||||
        // Enable the callbacks initially.
 | 
			
		||||
        EnableDescriptorCallBacks(cffd, source->GetFlags());
 | 
			
		||||
 | 
			
		||||
        source->SetFileDescriptor(cffd.release());
 | 
			
		||||
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
 | 
			
		||||
 | 
			
		||||
        return source.release();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user