]> git.saurik.com Git - wxWidgets.git/blob - src/mac/corefoundation/utilsexc_cf.cpp
Fixes to allow compilation with no wchar_t (djgpp probably has a real wchar_t
[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/apptrait.h"
21
22 #ifdef __WXCOCOA__
23 #include <CoreFoundation/CoreFoundation.h>
24 #include <ApplicationServices/ApplicationServices.h>
25 #else
26 #include "wx/mac/private.h"
27 #include "LaunchServices.h"
28 #endif
29
30 #include "wx/uri.h"
31 #include "wx/mac/corefoundation/cfstring.h"
32
33 long wxMacExecute(wxChar **argv,
34 int flags,
35 wxProcess *process)
36 {
37 CFIndex cfiCount = 0;
38 //get count
39 for(wxChar** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
40 {
41 ++cfiCount;
42 }
43
44 if(cfiCount == 0) //no file to launch?
45 {
46 wxLogDebug(wxT("wxMacExecute No file to launch!"));
47 return -1;
48 }
49
50 CFURLRef cfurlApp = CFURLCreateWithString(
51 kCFAllocatorDefault,
52 wxMacCFStringHolder(*argv++, wxLocale::GetSystemEncoding()),
53 NULL);
54 wxASSERT(cfurlApp);
55
56 CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp);
57 if(!cfbApp)
58 {
59 wxLogDebug(wxT("wxMacExecute Bad bundle"));
60 CFRelease(cfurlApp);
61 return -1;
62 }
63
64
65 UInt32 dwBundleType, dwBundleCreator;
66 CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
67
68 //Only call wxMacExecute for .app bundles - others could be actual unix programs
69 if(dwBundleType != 'APPL')
70 {
71 CFRelease(cfurlApp);
72 return -1;
73 }
74
75 //
76 // We have a good bundle - so let's launch it!
77 //
78
79 CFMutableArrayRef cfaFiles = CFArrayCreateMutable(kCFAllocatorDefault, cfiCount - 1, NULL);
80
81 wxASSERT(cfaFiles);
82
83 if(--cfiCount)
84 {
85 for( ; *argv != NULL ; ++argv)
86 {
87 // wxLogDebug(*argv);
88 wxString sCurrentFile;
89
90 if(wxURI(*argv).IsReference())
91 sCurrentFile = wxString(wxT("file://")) + *argv;
92 else
93 sCurrentFile = *argv;
94
95 CFURLRef cfurlCurrentFile = CFURLCreateWithString(
96 kCFAllocatorDefault,
97 wxMacCFStringHolder(sCurrentFile, wxLocale::GetSystemEncoding()),
98 NULL);
99 wxASSERT(cfurlCurrentFile);
100
101 CFArrayAppendValue(
102 cfaFiles,
103 cfurlCurrentFile
104 );
105 }
106 }
107
108 LSLaunchURLSpec launchspec;
109 launchspec.appURL = cfurlApp;
110 launchspec.itemURLs = cfaFiles;
111 launchspec.passThruParams = NULL; //AEDesc*
112 launchspec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch; //TODO: Possibly be smarter with flags
113 launchspec.asyncRefCon = NULL;
114
115 OSStatus status = LSOpenFromURLSpec(&launchspec,
116 NULL); //2nd is CFURLRef* really launched
117
118 //cleanup
119 CFRelease(cfurlApp);
120 CFRelease(cfaFiles);
121
122 //check for error
123 if(status != noErr)
124 {
125 wxLogDebug(wxString::Format(wxT("wxMacExecute ERROR: %d")), (int)status);
126 return -1;
127 }
128 return 0; //success
129 }
130
131
132 #include <CoreFoundation/CFMachPort.h>
133 #include <sys/wait.h>
134 extern "C" {
135 #include <mach/mach.h>
136 }
137
138 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
139 {
140 wxEndProcessData *proc_data = (wxEndProcessData*)data;
141 wxLogDebug(wxT("Process ended"));
142 int status = 0;
143 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
144 if(!rc)
145 {
146 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
147 return;
148 }
149 if((rc != -1) && WIFEXITED(status))
150 proc_data->exitcode = WEXITSTATUS(status);
151 else
152 proc_data->exitcode = -1;
153 wxHandleProcessTermination(proc_data);
154 }
155
156 int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
157 {
158 if(pid < 1)
159 return -1;
160 kern_return_t kernResult;
161 mach_port_t taskOfOurProcess;
162 mach_port_t machPortForProcess;
163 taskOfOurProcess = mach_task_self();
164 if(taskOfOurProcess == MACH_PORT_NULL)
165 {
166 wxLogDebug(wxT("No mach_task_self()"));
167 return -1;
168 }
169 wxLogDebug(wxT("pid=%d"),pid);
170 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
171 if(kernResult != KERN_SUCCESS)
172 {
173 wxLogDebug(wxT("no task_for_pid()"));
174 // try seeing if it is already dead or something
175 // FIXME: a better method would be to call the callback function
176 // from idle time until the process terminates. Of course, how
177 // likely is it that it will take more than 0.1 seconds for the
178 // mach terminate event to make its way to the BSD subsystem?
179 usleep(100); // sleep for 0.1 seconds
180 wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data);
181 return -1;
182 }
183 CFMachPortContext termcb_contextinfo;
184 termcb_contextinfo.version = 0;
185 termcb_contextinfo.info = (void*)proc_data;
186 termcb_contextinfo.retain = NULL;
187 termcb_contextinfo.release = NULL;
188 termcb_contextinfo.copyDescription = NULL;
189 CFMachPortRef CFMachPortForProcess;
190 Boolean ShouldFreePort;
191 CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort);
192 if(!CFMachPortForProcess)
193 {
194 wxLogDebug(wxT("No CFMachPortForProcess"));
195 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
196 return -1;
197 }
198 if(ShouldFreePort)
199 {
200 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
201 if(kernResult!=KERN_SUCCESS)
202 {
203 wxLogDebug(wxT("Couldn't deallocate mach port"));
204 return -1;
205 }
206 }
207 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
208 CFRunLoopSourceRef runloopsource;
209 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
210 if(!runloopsource)
211 {
212 wxLogDebug(wxT("Couldn't create runloopsource"));
213 return -1;
214 }
215
216 CFRelease(CFMachPortForProcess);
217
218 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
219 CFRelease(runloopsource);
220 wxLogDebug(wxT("Successfully added notification to the runloop"));
221 return 0;
222 }
223
224 // NOTE: This doens't really belong here but this was a handy file to
225 // put it in because it's already compiled for wxCocoa and wxMac GUI lib.
226 static wxStandardPathsCF gs_stdPaths;
227 wxStandardPathsBase& wxGUIAppTraits::GetStandardPaths()
228 {
229 return gs_stdPaths;
230 }
231