X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/71e9885be0a84f3c544b992aeb3a842f821035b5..9e2e5d0759966cdcdb7dd1ffcae65e359e447e89:/src/osx/core/utilsexc_cf.cpp diff --git a/src/osx/core/utilsexc_cf.cpp b/src/osx/core/utilsexc_cf.cpp index 221bbb322d..2a8c436223 100644 --- a/src/osx/core/utilsexc_cf.cpp +++ b/src/osx/core/utilsexc_cf.cpp @@ -4,8 +4,8 @@ // Author: David Elliott, Ryan Norton (wxMacExecute) // Modified by: Stefan Csomor (added necessary wxT for unicode builds) // Created: 2004-11-04 -// RCS-ID: $Id$ // Copyright: (c) David Elliott, Ryan Norton +// (c) 2013 Rob Bresalier // Licence: wxWindows licence // Notes: This code comes from src/osx/carbon/utilsexc.cpp,1.11 ///////////////////////////////////////////////////////////////////////////// @@ -15,7 +15,6 @@ #include "wx/log.h" #include "wx/utils.h" #endif //ndef WX_PRECOMP -#include "wx/unix/execute.h" #include "wx/stdpaths.h" #include "wx/app.h" #include "wx/apptrait.h" @@ -28,120 +27,43 @@ #include -#include #include -/*! - Called due to source signal detected by the CFRunLoop. - This is nearly identical to the wxGTK equivalent. - */ -extern "C" void WXCF_EndProcessDetector(CFSocketRef s, - CFSocketCallBackType WXUNUSED(callbackType), - CFDataRef WXUNUSED(address), - void const *WXUNUSED(data), - void *info) -{ - /* - Either our pipe was closed or the process ended successfully. Either way, - we're done. It's not if waitpid is going to magically succeed when - we get fired again. CFSocketInvalidate closes the fd for us and also - invalidates the run loop source for us which should cause it to - release the CFSocket (thus causing it to be deallocated) and remove - itself from the runloop which should release it and cause it to also - be deallocated. Of course, it's possible the RunLoop hangs onto - one or both of them by retaining/releasing them within its stack - frame. However, that shouldn't be depended on. Assume that s is - deallocated due to the following call. - */ - CFSocketInvalidate(s); - - // Now tell wx that the process has ended. - wxHandleProcessTermination(static_cast(info)); -} - -/*! - Implements the GUI-specific AddProcessCallback() for both wxMac and - wxCocoa using the CFSocket/CFRunLoop API which is available to both. - Takes advantage of the fact that sockets on UNIX are just regular - file descriptors and thus even a non-socket file descriptor can - apparently be used with CFSocket so long as you only tell CFSocket - to do things with it that would be valid for a non-socket fd. - */ -int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd) -{ - static int s_last_tag = 0; - CFSocketContext context = - { 0 - , static_cast(proc_data) - , NULL - , NULL - , NULL - }; - CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context); - if(cfSocket == NULL) - { - wxLogError(wxT("Failed to create socket for end process detection")); - return 0; - } - CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0); - if(runLoopSource == NULL) - { - wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection")); - // closes the fd.. we can't really stop it, nor do we necessarily want to. - CFSocketInvalidate(cfSocket); - CFRelease(cfSocket); - return 0; - } - // Now that the run loop source has the socket retained and we no longer - // need to refer to it within this method, we can release it. - CFRelease(cfSocket); - - CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); - // Now that the run loop has the source retained we can release it. - CFRelease(runLoopSource); - - /* - Feed wx some bullshit.. we don't use it since CFSocket helpfully passes - itself into our callback and that's enough to be able to - CFSocketInvalidate it which is all we need to do to get everything we - just created to be deallocated. - */ - return ++s_last_tag; -} - #if wxUSE_EVENTLOOP_SOURCE 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", static_cast(callbackType)); wxCFEventLoopSource * const source = static_cast(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 +79,63 @@ public: wxScopedPtr source(new wxCFEventLoopSource(handler, flags)); - CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL }; - wxCFRef - 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 + 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 - 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); - - // Enable the callbacks initially. - EnableDescriptorCallBacks(cffd, source->GetFlags()); + // Save the socket so that we can remove it later if asked to. + source->InitSourceSocket(cfSocket.release()); - source->SetFileDescriptor(cffd.release()); + CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); return source.release(); } @@ -201,9 +155,19 @@ wxEventLoopSourcesManagerBase* wxGUIAppTraits::GetEventLoopSourcesManager() // NOTE: This doesn't really belong here but this was a handy file to // put it in because it's already compiled for wxCocoa and wxMac GUI lib. #if wxUSE_STDPATHS -static wxStandardPathsCF gs_stdPaths; wxStandardPaths& wxGUIAppTraits::GetStandardPaths() { + // Derive a class just to be able to create it: wxStandardPaths ctor is + // protected to prevent its misuse, but it also means we can't create an + // object of this class directly. + class wxStandardPathsDefault : public wxStandardPathsCF + { + public: + wxStandardPathsDefault() { } + }; + + static wxStandardPathsDefault gs_stdPaths; + return gs_stdPaths; } #endif