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_
|
#ifndef _WX_OSX_EVTLOOPSRC_H_
|
||||||
#define _WX_OSX_EVTLOOPSRC_H_
|
#define _WX_OSX_EVTLOOPSRC_H_
|
||||||
|
|
||||||
typedef struct __CFFileDescriptor *CFFileDescriptorRef;
|
typedef struct __CFSocket* CFSocketRef;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxCFEventLoopSource: CoreFoundation-based wxEventLoopSource for OS X
|
// wxCFEventLoopSource: CoreFoundation-based wxEventLoopSource for OS X
|
||||||
@@ -20,19 +20,23 @@ typedef struct __CFFileDescriptor *CFFileDescriptorRef;
|
|||||||
class WXDLLIMPEXP_BASE wxCFEventLoopSource : public wxEventLoopSource
|
class WXDLLIMPEXP_BASE wxCFEventLoopSource : public wxEventLoopSource
|
||||||
{
|
{
|
||||||
public:
|
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)
|
wxCFEventLoopSource(wxEventLoopSourceHandler *handler, int flags)
|
||||||
: wxEventLoopSource(handler, flags)
|
: wxEventLoopSource(handler, flags)
|
||||||
{
|
{
|
||||||
m_cffd = NULL;
|
m_cfSocket = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we take ownership of this CFFileDescriptorRef
|
// Finish initialization of the event loop source by providing the
|
||||||
void SetFileDescriptor(CFFileDescriptorRef cffd);
|
// associated socket. This object takes ownership of it and will release it.
|
||||||
|
void InitSourceSocket(CFSocketRef cfSocket);
|
||||||
|
|
||||||
|
// Destructor deletes the associated socket.
|
||||||
virtual ~wxCFEventLoopSource();
|
virtual ~wxCFEventLoopSource();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CFFileDescriptorRef m_cffd;
|
CFSocketRef m_cfSocket;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxCFEventLoopSource);
|
wxDECLARE_NO_COPY_CLASS(wxCFEventLoopSource);
|
||||||
};
|
};
|
||||||
|
@@ -42,23 +42,28 @@
|
|||||||
#include "wx/nonownedwnd.h"
|
#include "wx/nonownedwnd.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFSocket.h>
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// wxCFEventLoopSource and wxCFEventLoop implementation
|
// wxCFEventLoopSource and wxCFEventLoop implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#if wxUSE_EVENTLOOP_SOURCE
|
#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()
|
wxCFEventLoopSource::~wxCFEventLoopSource()
|
||||||
{
|
{
|
||||||
if ( m_cffd )
|
if ( m_cfSocket )
|
||||||
CFRelease(m_cffd);
|
{
|
||||||
|
CFSocketInvalidate(m_cfSocket);
|
||||||
|
CFRelease(m_cfSocket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxUSE_EVENTLOOP_SOURCE
|
#endif // wxUSE_EVENTLOOP_SOURCE
|
||||||
|
@@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <CoreFoundation/CFFileDescriptor.h>
|
|
||||||
#include <CoreFoundation/CFSocket.h>
|
#include <CoreFoundation/CFSocket.h>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -114,34 +113,36 @@ int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
void EnableDescriptorCallBacks(CFFileDescriptorRef cffd, int flags)
|
extern "C"
|
||||||
{
|
|
||||||
if ( flags & wxEVENT_SOURCE_INPUT )
|
|
||||||
CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack);
|
|
||||||
if ( flags & wxEVENT_SOURCE_OUTPUT )
|
|
||||||
CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorWriteCallBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
wx_cffiledescriptor_callback(CFFileDescriptorRef cffd,
|
wx_socket_callback(CFSocketRef WXUNUSED(s),
|
||||||
CFOptionFlags flags,
|
CFSocketCallBackType callbackType,
|
||||||
|
CFDataRef WXUNUSED(address),
|
||||||
|
void const *WXUNUSED(data),
|
||||||
void *ctxData)
|
void *ctxData)
|
||||||
{
|
{
|
||||||
wxLogTrace(wxTRACE_EVT_SOURCE,
|
wxLogTrace(wxTRACE_EVT_SOURCE,
|
||||||
"CFFileDescriptor callback, flags=%d", flags);
|
"CFSocket callback, type=%d", callbackType);
|
||||||
|
|
||||||
wxCFEventLoopSource * const
|
wxCFEventLoopSource * const
|
||||||
source = static_cast<wxCFEventLoopSource *>(ctxData);
|
source = static_cast<wxCFEventLoopSource *>(ctxData);
|
||||||
|
|
||||||
wxEventLoopSourceHandler * const
|
wxEventLoopSourceHandler * const
|
||||||
handler = source->GetHandler();
|
handler = source->GetHandler();
|
||||||
if ( flags & kCFFileDescriptorReadCallBack )
|
|
||||||
handler->OnReadWaiting();
|
|
||||||
if ( flags & kCFFileDescriptorWriteCallBack )
|
|
||||||
handler->OnWriteWaiting();
|
|
||||||
|
|
||||||
// we need to re-enable callbacks to be called again
|
switch ( callbackType )
|
||||||
EnableDescriptorCallBacks(cffd, source->GetFlags());
|
{
|
||||||
|
case kCFSocketReadCallBack:
|
||||||
|
handler->OnReadWaiting();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCFSocketWriteCallBack:
|
||||||
|
handler->OnWriteWaiting();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxFAIL_MSG( "Unexpected callback type." );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@@ -157,31 +158,63 @@ public:
|
|||||||
wxScopedPtr<wxCFEventLoopSource>
|
wxScopedPtr<wxCFEventLoopSource>
|
||||||
source(new wxCFEventLoopSource(handler, flags));
|
source(new wxCFEventLoopSource(handler, flags));
|
||||||
|
|
||||||
CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL };
|
CFSocketContext context = { 0, source.get(), NULL, NULL, NULL };
|
||||||
wxCFRef<CFFileDescriptorRef>
|
|
||||||
cffd(CFFileDescriptorCreate
|
int callbackTypes = 0;
|
||||||
|
if ( flags & wxEVENT_SOURCE_INPUT )
|
||||||
|
callbackTypes |= kCFSocketReadCallBack;
|
||||||
|
if ( flags & wxEVENT_SOURCE_OUTPUT )
|
||||||
|
callbackTypes |= kCFSocketWriteCallBack;
|
||||||
|
|
||||||
|
wxCFRef<CFSocketRef>
|
||||||
|
cfSocket(CFSocketCreateWithNative
|
||||||
(
|
(
|
||||||
kCFAllocatorDefault,
|
kCFAllocatorDefault,
|
||||||
fd,
|
fd,
|
||||||
true, // close on invalidate
|
callbackTypes,
|
||||||
wx_cffiledescriptor_callback,
|
&wx_socket_callback,
|
||||||
&ctx
|
&context
|
||||||
));
|
));
|
||||||
if ( !cffd )
|
|
||||||
|
if ( !cfSocket )
|
||||||
|
{
|
||||||
|
wxLogError(wxS("Failed to create event loop source socket."));
|
||||||
return NULL;
|
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>
|
wxCFRef<CFRunLoopSourceRef>
|
||||||
cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0));
|
runLoopSource(CFSocketCreateRunLoopSource
|
||||||
if ( !cfsrc )
|
(
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
cfSocket,
|
||||||
|
0 // Lowest index means highest priority
|
||||||
|
));
|
||||||
|
if ( !runLoopSource )
|
||||||
|
{
|
||||||
|
wxLogError(wxS("Failed to create low level event loop source."));
|
||||||
|
CFSocketInvalidate(cfSocket);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
CFRunLoopRef cfloop = CFRunLoopGetCurrent();
|
// Save the socket so that we can remove it later if asked to.
|
||||||
CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode);
|
source->InitSourceSocket(cfSocket.release());
|
||||||
|
|
||||||
// Enable the callbacks initially.
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
|
||||||
EnableDescriptorCallBacks(cffd, source->GetFlags());
|
|
||||||
|
|
||||||
source->SetFileDescriptor(cffd.release());
|
|
||||||
|
|
||||||
return source.release();
|
return source.release();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user