]> git.saurik.com Git - wxWidgets.git/blob - src/mac/corefoundation/utilsexc_cf.cpp
use wx-style header and commets; fix indentation to be 4 spaces; move Doxygen comment...
[wxWidgets.git] / src / mac / corefoundation / utilsexc_cf.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/corefoundation/utilsexec_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/mac/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 <sys/wait.h>
26
27 #include <CoreFoundation/CFSocket.h>
28
29 /*!
30 Called due to source signal detected by the CFRunLoop.
31 This is nearly identical to the wxGTK equivalent.
32 */
33 extern "C" void WXCF_EndProcessDetector(CFSocketRef s,
34 CFSocketCallBackType WXUNUSED(callbackType),
35 CFDataRef WXUNUSED(address),
36 void const *WXUNUSED(data),
37 void *info)
38 {
39 wxEndProcessData * const proc_data = static_cast<wxEndProcessData*>(info);
40
41 /// This code could reasonably be shared between wxMac/wxCocoa and wxGTK ///
42 // PID is always positive on UNIX but wx uses the sign bit as a flag.
43 int pid = (proc_data->pid > 0) ? proc_data->pid : -proc_data->pid;
44 int status = 0;
45 int rc = waitpid(pid, &status, WNOHANG);
46 if(rc == 0)
47 {
48 // Keep waiting in case we got a spurious notification
49 // NOTE: In my limited testing, this doesn't happen.
50 return;
51 }
52
53 if(rc == -1)
54 { // Error.. really shouldn't happen but try to gracefully handle it
55 wxLogLastError(_T("waitpid"));
56 proc_data->exitcode = -1;
57 }
58 else
59 { // Process ended for some reason
60 wxASSERT_MSG(rc == pid, _T("unexpected waitpid() return value"));
61
62 if(WIFEXITED(status))
63 proc_data->exitcode = WEXITSTATUS(status);
64 else if(WIFSIGNALED(status))
65 // wxGTK doesn't do this but why not?
66 proc_data->exitcode = -WTERMSIG(status);
67 else
68 { // Should NEVER happen according to waitpid docs
69 wxLogError(wxT("waitpid indicates process exited but not due to exiting or signalling"));
70 proc_data->exitcode = -1;
71 }
72 }
73 /// The above code could reasonably be shared between wxMac/wxCocoa and wxGTK ///
74
75 /*
76 Either waitpid failed or the process ended successfully. Either way,
77 we're done. It's not if waitpid is going to magically succeed when
78 we get fired again. CFSocketInvalidate closes the fd for us and also
79 invalidates the run loop source for us which should cause it to
80 release the CFSocket (thus causing it to be deallocated) and remove
81 itself from the runloop which should release it and cause it to also
82 be deallocated. Of course, it's possible the RunLoop hangs onto
83 one or both of them by retaining/releasing them within its stack
84 frame. However, that shouldn't be depended on. Assume that s is
85 deallocated due to the following call.
86 */
87 CFSocketInvalidate(s);
88
89 // Now tell wx that the process has ended.
90 wxHandleProcessTermination(proc_data);
91 }
92
93 /*!
94 Implements the GUI-specific AddProcessCallback() for both wxMac and
95 wxCocoa using the CFSocket/CFRunLoop API which is available to both.
96 Takes advantage of the fact that sockets on UNIX are just regular
97 file descriptors and thus even a non-socket file descriptor can
98 apparently be used with CFSocket so long as you only tell CFSocket
99 to do things with it that would be valid for a non-socket fd.
100 */
101 int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
102 {
103 static int s_last_tag = 0;
104 CFSocketContext context =
105 { 0
106 , static_cast<void*>(proc_data)
107 , NULL
108 , NULL
109 , NULL
110 };
111 CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context);
112 if(cfSocket == NULL)
113 {
114 wxLogError(wxT("Failed to create socket for end process detection"));
115 return 0;
116 }
117 CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0);
118 if(runLoopSource == NULL)
119 {
120 wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection"));
121 // closes the fd.. we can't really stop it, nor do we necessarily want to.
122 CFSocketInvalidate(cfSocket);
123 CFRelease(cfSocket);
124 return 0;
125 }
126 // Now that the run loop source has the socket retained and we no longer
127 // need to refer to it within this method, we can release it.
128 CFRelease(cfSocket);
129
130 CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
131 // Now that the run loop has the source retained we can release it.
132 CFRelease(runLoopSource);
133
134 /*
135 Feed wx some bullshit.. we don't use it since CFSocket helpfully passes
136 itself into our callback and that's enough to be able to
137 CFSocketInvalidate it which is all we need to do to get everything we
138 just created to be deallocated.
139 */
140 return ++s_last_tag;
141 }
142
143 /////////////////////////////////////////////////////////////////////////////
144
145 // NOTE: This doesn't really belong here but this was a handy file to
146 // put it in because it's already compiled for wxCocoa and wxMac GUI lib.
147 #if wxUSE_STDPATHS
148 static wxStandardPathsCF gs_stdPaths;
149 wxStandardPathsBase& wxGUIAppTraits::GetStandardPaths()
150 {
151 return gs_stdPaths;
152 }
153 #endif
154