]> git.saurik.com Git - wxWidgets.git/blob - src/osx/core/utilsexc_cf.cpp
221bbb322d5f399f3ac29b5df7a19157362728b6
[wxWidgets.git] / src / osx / core / utilsexc_cf.cpp
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)
6 // Created: 2004-11-04
7 // RCS-ID: $Id$
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 /////////////////////////////////////////////////////////////////////////////
12
13 #include "wx/wxprec.h"
14 #ifndef WX_PRECOMP
15 #include "wx/log.h"
16 #include "wx/utils.h"
17 #endif //ndef WX_PRECOMP
18 #include "wx/unix/execute.h"
19 #include "wx/stdpaths.h"
20 #include "wx/app.h"
21 #include "wx/apptrait.h"
22 #include "wx/thread.h"
23 #include "wx/process.h"
24
25 #include "wx/evtloop.h"
26 #include "wx/evtloopsrc.h"
27 #include "wx/private/eventloopsourcesmanager.h"
28
29 #include <sys/wait.h>
30
31 #include <CoreFoundation/CFFileDescriptor.h>
32 #include <CoreFoundation/CFSocket.h>
33
34 /*!
35 Called due to source signal detected by the CFRunLoop.
36 This is nearly identical to the wxGTK equivalent.
37 */
38 extern "C" void WXCF_EndProcessDetector(CFSocketRef s,
39 CFSocketCallBackType WXUNUSED(callbackType),
40 CFDataRef WXUNUSED(address),
41 void const *WXUNUSED(data),
42 void *info)
43 {
44 /*
45 Either our pipe was closed or the process ended successfully. Either way,
46 we're done. It's not if waitpid is going to magically succeed when
47 we get fired again. CFSocketInvalidate closes the fd for us and also
48 invalidates the run loop source for us which should cause it to
49 release the CFSocket (thus causing it to be deallocated) and remove
50 itself from the runloop which should release it and cause it to also
51 be deallocated. Of course, it's possible the RunLoop hangs onto
52 one or both of them by retaining/releasing them within its stack
53 frame. However, that shouldn't be depended on. Assume that s is
54 deallocated due to the following call.
55 */
56 CFSocketInvalidate(s);
57
58 // Now tell wx that the process has ended.
59 wxHandleProcessTermination(static_cast<wxEndProcessData *>(info));
60 }
61
62 /*!
63 Implements the GUI-specific AddProcessCallback() for both wxMac and
64 wxCocoa using the CFSocket/CFRunLoop API which is available to both.
65 Takes advantage of the fact that sockets on UNIX are just regular
66 file descriptors and thus even a non-socket file descriptor can
67 apparently be used with CFSocket so long as you only tell CFSocket
68 to do things with it that would be valid for a non-socket fd.
69 */
70 int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
71 {
72 static int s_last_tag = 0;
73 CFSocketContext context =
74 { 0
75 , static_cast<void*>(proc_data)
76 , NULL
77 , NULL
78 , NULL
79 };
80 CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context);
81 if(cfSocket == NULL)
82 {
83 wxLogError(wxT("Failed to create socket for end process detection"));
84 return 0;
85 }
86 CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0);
87 if(runLoopSource == NULL)
88 {
89 wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection"));
90 // closes the fd.. we can't really stop it, nor do we necessarily want to.
91 CFSocketInvalidate(cfSocket);
92 CFRelease(cfSocket);
93 return 0;
94 }
95 // Now that the run loop source has the socket retained and we no longer
96 // need to refer to it within this method, we can release it.
97 CFRelease(cfSocket);
98
99 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
100 // Now that the run loop has the source retained we can release it.
101 CFRelease(runLoopSource);
102
103 /*
104 Feed wx some bullshit.. we don't use it since CFSocket helpfully passes
105 itself into our callback and that's enough to be able to
106 CFSocketInvalidate it which is all we need to do to get everything we
107 just created to be deallocated.
108 */
109 return ++s_last_tag;
110 }
111
112 #if wxUSE_EVENTLOOP_SOURCE
113
114 namespace
115 {
116
117 void EnableDescriptorCallBacks(CFFileDescriptorRef cffd, int flags)
118 {
119 if ( flags & wxEVENT_SOURCE_INPUT )
120 CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack);
121 if ( flags & wxEVENT_SOURCE_OUTPUT )
122 CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorWriteCallBack);
123 }
124
125 void
126 wx_cffiledescriptor_callback(CFFileDescriptorRef cffd,
127 CFOptionFlags flags,
128 void *ctxData)
129 {
130 wxLogTrace(wxTRACE_EVT_SOURCE,
131 "CFFileDescriptor callback, flags=%d", flags);
132
133 wxCFEventLoopSource * const
134 source = static_cast<wxCFEventLoopSource *>(ctxData);
135
136 wxEventLoopSourceHandler * const
137 handler = source->GetHandler();
138 if ( flags & kCFFileDescriptorReadCallBack )
139 handler->OnReadWaiting();
140 if ( flags & kCFFileDescriptorWriteCallBack )
141 handler->OnWriteWaiting();
142
143 // we need to re-enable callbacks to be called again
144 EnableDescriptorCallBacks(cffd, source->GetFlags());
145 }
146
147 } // anonymous namespace
148
149 class wxCFEventLoopSourcesManager : public wxEventLoopSourcesManagerBase
150 {
151 public:
152 wxEventLoopSource *
153 AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags)
154 {
155 wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" );
156
157 wxScopedPtr<wxCFEventLoopSource>
158 source(new wxCFEventLoopSource(handler, flags));
159
160 CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL };
161 wxCFRef<CFFileDescriptorRef>
162 cffd(CFFileDescriptorCreate
163 (
164 kCFAllocatorDefault,
165 fd,
166 true, // close on invalidate
167 wx_cffiledescriptor_callback,
168 &ctx
169 ));
170 if ( !cffd )
171 return NULL;
172
173 wxCFRef<CFRunLoopSourceRef>
174 cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0));
175 if ( !cfsrc )
176 return NULL;
177
178 CFRunLoopRef cfloop = CFRunLoopGetCurrent();
179 CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode);
180
181 // Enable the callbacks initially.
182 EnableDescriptorCallBacks(cffd, source->GetFlags());
183
184 source->SetFileDescriptor(cffd.release());
185
186 return source.release();
187 }
188 };
189
190 wxEventLoopSourcesManagerBase* wxGUIAppTraits::GetEventLoopSourcesManager()
191 {
192 static wxCFEventLoopSourcesManager s_eventLoopSourcesManager;
193
194 return &s_eventLoopSourcesManager;
195 }
196
197 #endif // wxUSE_EVENTLOOP_SOURCE
198
199 /////////////////////////////////////////////////////////////////////////////
200
201 // NOTE: This doesn't really belong here but this was a handy file to
202 // put it in because it's already compiled for wxCocoa and wxMac GUI lib.
203 #if wxUSE_STDPATHS
204 static wxStandardPathsCF gs_stdPaths;
205 wxStandardPaths& wxGUIAppTraits::GetStandardPaths()
206 {
207 return gs_stdPaths;
208 }
209 #endif
210
211 #if wxUSE_SOCKETS
212
213 // we need to implement this method in a file of the core library as it should
214 // only be used for the GUI applications but we can't use socket stuff from it
215 // directly as this would create unwanted dependencies of core on net library
216 //
217 // so we have this global pointer which is set from sockosx.cpp when it is
218 // linked in and we simply return it from here
219 extern WXDLLIMPEXP_BASE wxSocketManager *wxOSXSocketManagerCF;
220 wxSocketManager *wxGUIAppTraits::GetSocketManager()
221 {
222 return wxOSXSocketManagerCF ? wxOSXSocketManagerCF
223 : wxGUIAppTraitsBase::GetSocketManager();
224 }
225
226 #endif // wxUSE_SOCKETS