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:
parent
71e9885be0
commit
a25b76f5f9
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user