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)
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 /////////////////////////////////////////////////////////////////////////////
13 #include "wx/wxprec.h"
17 #endif //ndef WX_PRECOMP
18 #include "wx/unix/execute.h"
19 #include "wx/stdpaths.h"
20 #include "wx/apptrait.h"
23 #include <CoreFoundation/CoreFoundation.h>
24 #include <ApplicationServices/ApplicationServices.h>
26 #include "wx/mac/private.h"
27 #include "LaunchServices.h"
31 #include "wx/mac/corefoundation/cfstring.h"
33 long wxMacExecute(wxChar
**argv
,
39 for(wxChar
** argvcopy
= argv
; *argvcopy
!= NULL
; ++argvcopy
)
44 if(cfiCount
== 0) //no file to launch?
46 wxLogDebug(wxT("wxMacExecute No file to launch!"));
50 CFURLRef cfurlApp
= CFURLCreateWithString(
52 wxMacCFStringHolder(*argv
++, wxLocale::GetSystemEncoding()),
56 CFBundleRef cfbApp
= CFBundleCreate(kCFAllocatorDefault
, cfurlApp
);
59 wxLogDebug(wxT("wxMacExecute Bad bundle"));
65 UInt32 dwBundleType
, dwBundleCreator
;
66 CFBundleGetPackageInfo(cfbApp
, &dwBundleType
, &dwBundleCreator
);
68 //Only call wxMacExecute for .app bundles - others could be actual unix programs
69 if(dwBundleType
!= 'APPL')
76 // We have a good bundle - so let's launch it!
79 CFMutableArrayRef cfaFiles
= CFArrayCreateMutable(kCFAllocatorDefault
, cfiCount
- 1, NULL
);
85 for( ; *argv
!= NULL
; ++argv
)
88 wxString sCurrentFile
;
90 if(wxURI(*argv
).IsReference())
91 sCurrentFile
= wxString(wxT("file://")) + *argv
;
95 CFURLRef cfurlCurrentFile
= CFURLCreateWithString(
97 wxMacCFStringHolder(sCurrentFile
, wxLocale::GetSystemEncoding()),
99 wxASSERT(cfurlCurrentFile
);
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
;
115 OSStatus status
= LSOpenFromURLSpec(&launchspec
,
116 NULL
); //2nd is CFURLRef* really launched
125 wxLogDebug(wxString::Format(wxT("wxMacExecute ERROR: %d")), (int)status
);
132 #include <CoreFoundation/CFMachPort.h>
133 #include <sys/wait.h>
135 #include <mach/mach.h>
138 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port
, void *data
)
140 wxEndProcessData
*proc_data
= (wxEndProcessData
*)data
;
141 wxLogDebug(wxT("Process ended"));
143 int rc
= waitpid(abs(proc_data
->pid
), &status
, WNOHANG
);
146 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
149 if((rc
!= -1) && WIFEXITED(status
))
150 proc_data
->exitcode
= WEXITSTATUS(status
);
152 proc_data
->exitcode
= -1;
153 wxHandleProcessTermination(proc_data
);
156 int wxAddProcessCallbackForPid(wxEndProcessData
*proc_data
, int pid
)
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
)
166 wxLogDebug(wxT("No mach_task_self()"));
169 wxLogDebug(wxT("pid=%d"),pid
);
170 kernResult
= task_for_pid(taskOfOurProcess
,pid
, &machPortForProcess
);
171 if(kernResult
!= KERN_SUCCESS
)
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
);
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
)
194 wxLogDebug(wxT("No CFMachPortForProcess"));
195 mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
200 kernResult
= mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
201 if(kernResult
!=KERN_SUCCESS
)
203 wxLogDebug(wxT("Couldn't deallocate mach port"));
207 CFMachPortSetInvalidationCallBack(CFMachPortForProcess
, &wxMAC_MachPortEndProcessDetect
);
208 CFRunLoopSourceRef runloopsource
;
209 runloopsource
= CFMachPortCreateRunLoopSource(NULL
,CFMachPortForProcess
, (CFIndex
)0);
212 wxLogDebug(wxT("Couldn't create runloopsource"));
216 CFRelease(CFMachPortForProcess
);
218 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource
,kCFRunLoopDefaultMode
);
219 CFRelease(runloopsource
);
220 wxLogDebug(wxT("Successfully added notification to the runloop"));
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()