1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/core/utilsexc_cf.cpp
3 // Purpose: Execution-related utilities for Darwin
4 // Author: David Elliott, Ryan Norton (wxMacExecute)
5 // Modified by: Stefan Csomor (added necessary wxT for unicode builds)
8 // Copyright: (c) David Elliott, Ryan Norton
9 // Licence: wxWindows licence
10 // Notes: This code comes from src/osx/carbon/utilsexc.cpp,1.11
11 /////////////////////////////////////////////////////////////////////////////
13 #include "wx/wxprec.h"
17 #endif //ndef WX_PRECOMP
18 #include "wx/unix/execute.h"
19 #include "wx/stdpaths.h"
21 #include "wx/apptrait.h"
22 #include "wx/thread.h"
23 #include "wx/process.h"
25 #include "wx/evtloop.h"
26 #include "wx/evtloopsrc.h"
27 #include "wx/private/eventloopsourcesmanager.h"
31 #include <CoreFoundation/CFSocket.h>
34 Called due to source signal detected by the CFRunLoop.
35 This is nearly identical to the wxGTK equivalent.
37 extern "C" void WXCF_EndProcessDetector(CFSocketRef s
,
38 CFSocketCallBackType
WXUNUSED(callbackType
),
39 CFDataRef
WXUNUSED(address
),
40 void const *WXUNUSED(data
),
44 Either our pipe was closed or the process ended successfully. Either way,
45 we're done. It's not if waitpid is going to magically succeed when
46 we get fired again. CFSocketInvalidate closes the fd for us and also
47 invalidates the run loop source for us which should cause it to
48 release the CFSocket (thus causing it to be deallocated) and remove
49 itself from the runloop which should release it and cause it to also
50 be deallocated. Of course, it's possible the RunLoop hangs onto
51 one or both of them by retaining/releasing them within its stack
52 frame. However, that shouldn't be depended on. Assume that s is
53 deallocated due to the following call.
55 CFSocketInvalidate(s
);
57 // Now tell wx that the process has ended.
58 wxHandleProcessTermination(static_cast<wxEndProcessData
*>(info
));
62 Implements the GUI-specific AddProcessCallback() for both wxMac and
63 wxCocoa using the CFSocket/CFRunLoop API which is available to both.
64 Takes advantage of the fact that sockets on UNIX are just regular
65 file descriptors and thus even a non-socket file descriptor can
66 apparently be used with CFSocket so long as you only tell CFSocket
67 to do things with it that would be valid for a non-socket fd.
69 int wxGUIAppTraits::AddProcessCallback(wxEndProcessData
*proc_data
, int fd
)
71 static int s_last_tag
= 0;
72 CFSocketContext context
=
74 , static_cast<void*>(proc_data
)
79 CFSocketRef cfSocket
= CFSocketCreateWithNative(kCFAllocatorDefault
,fd
,kCFSocketReadCallBack
,&WXCF_EndProcessDetector
,&context
);
82 wxLogError(wxT("Failed to create socket for end process detection"));
85 CFRunLoopSourceRef runLoopSource
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, cfSocket
, /*highest priority:*/0);
86 if(runLoopSource
== NULL
)
88 wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection"));
89 // closes the fd.. we can't really stop it, nor do we necessarily want to.
90 CFSocketInvalidate(cfSocket
);
94 // Now that the run loop source has the socket retained and we no longer
95 // need to refer to it within this method, we can release it.
98 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource
, kCFRunLoopCommonModes
);
99 // Now that the run loop has the source retained we can release it.
100 CFRelease(runLoopSource
);
103 Feed wx some bullshit.. we don't use it since CFSocket helpfully passes
104 itself into our callback and that's enough to be able to
105 CFSocketInvalidate it which is all we need to do to get everything we
106 just created to be deallocated.
111 #if wxUSE_EVENTLOOP_SOURCE
118 wx_socket_callback(CFSocketRef
WXUNUSED(s
),
119 CFSocketCallBackType callbackType
,
120 CFDataRef
WXUNUSED(address
),
121 void const *WXUNUSED(data
),
124 wxLogTrace(wxTRACE_EVT_SOURCE
,
125 "CFSocket callback, type=%d", callbackType
);
127 wxCFEventLoopSource
* const
128 source
= static_cast<wxCFEventLoopSource
*>(ctxData
);
130 wxEventLoopSourceHandler
* const
131 handler
= source
->GetHandler();
133 switch ( callbackType
)
135 case kCFSocketReadCallBack
:
136 handler
->OnReadWaiting();
139 case kCFSocketWriteCallBack
:
140 handler
->OnWriteWaiting();
144 wxFAIL_MSG( "Unexpected callback type." );
148 } // anonymous namespace
150 class wxCFEventLoopSourcesManager
: public wxEventLoopSourcesManagerBase
154 AddSourceForFD(int fd
, wxEventLoopSourceHandler
*handler
, int flags
)
156 wxCHECK_MSG( fd
!= -1, NULL
, "can't monitor invalid fd" );
158 wxScopedPtr
<wxCFEventLoopSource
>
159 source(new wxCFEventLoopSource(handler
, flags
));
161 CFSocketContext context
= { 0, source
.get(), NULL
, NULL
, NULL
};
163 int callbackTypes
= 0;
164 if ( flags
& wxEVENT_SOURCE_INPUT
)
165 callbackTypes
|= kCFSocketReadCallBack
;
166 if ( flags
& wxEVENT_SOURCE_OUTPUT
)
167 callbackTypes
|= kCFSocketWriteCallBack
;
170 cfSocket(CFSocketCreateWithNative
181 wxLogError(wxS("Failed to create event loop source socket."));
185 // Adjust the socket options to suit our needs:
186 CFOptionFlags sockopt
= CFSocketGetSocketFlags(cfSocket
);
188 // First, by default, write callback is not called repeatedly when data
189 // can be written to the socket but we need this behaviour so request
191 if ( flags
& wxEVENT_SOURCE_OUTPUT
)
192 sockopt
|= kCFSocketAutomaticallyReenableWriteCallBack
;
194 // Second, we use the socket to monitor the FD but it doesn't own it,
195 // so prevent the FD from being closed when the socket is invalidated.
196 sockopt
&= ~kCFSocketCloseOnInvalidate
;
198 CFSocketSetSocketFlags(cfSocket
, sockopt
);
200 wxCFRef
<CFRunLoopSourceRef
>
201 runLoopSource(CFSocketCreateRunLoopSource
205 0 // Lowest index means highest priority
207 if ( !runLoopSource
)
209 wxLogError(wxS("Failed to create low level event loop source."));
210 CFSocketInvalidate(cfSocket
);
214 // Save the socket so that we can remove it later if asked to.
215 source
->InitSourceSocket(cfSocket
.release());
217 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource
, kCFRunLoopCommonModes
);
219 return source
.release();
223 wxEventLoopSourcesManagerBase
* wxGUIAppTraits::GetEventLoopSourcesManager()
225 static wxCFEventLoopSourcesManager s_eventLoopSourcesManager
;
227 return &s_eventLoopSourcesManager
;
230 #endif // wxUSE_EVENTLOOP_SOURCE
232 /////////////////////////////////////////////////////////////////////////////
234 // NOTE: This doesn't really belong here but this was a handy file to
235 // put it in because it's already compiled for wxCocoa and wxMac GUI lib.
237 static wxStandardPathsCF gs_stdPaths
;
238 wxStandardPaths
& wxGUIAppTraits::GetStandardPaths()
246 // we need to implement this method in a file of the core library as it should
247 // only be used for the GUI applications but we can't use socket stuff from it
248 // directly as this would create unwanted dependencies of core on net library
250 // so we have this global pointer which is set from sockosx.cpp when it is
251 // linked in and we simply return it from here
252 extern WXDLLIMPEXP_BASE wxSocketManager
*wxOSXSocketManagerCF
;
253 wxSocketManager
*wxGUIAppTraits::GetSocketManager()
255 return wxOSXSocketManagerCF
? wxOSXSocketManagerCF
256 : wxGUIAppTraitsBase::GetSocketManager();
259 #endif // wxUSE_SOCKETS