]> git.saurik.com Git - wxWidgets.git/blob - src/osx/core/utilsexc_base.cpp
377b2464befe33949d425a92a56f3e2e391bee74
[wxWidgets.git] / src / osx / core / utilsexc_base.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mac/corefoundation/utilsexc_base.cpp
3 // Purpose: wxMacLaunch
4 // Author: Ryan Norton
5 // Modified by:
6 // Created: 2005-06-21
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 // Notes: Source was originally in utilsexc_cf.cpp,1.6 then moved
11 // to totally unrelated hid.cpp,1.8.
12 /////////////////////////////////////////////////////////////////////////////
13
14 //===========================================================================
15 // DECLARATIONS
16 //===========================================================================
17
18 //---------------------------------------------------------------------------
19 // Pre-compiled header stuff
20 //---------------------------------------------------------------------------
21
22 // For compilers that support precompilation, includes "wx.h".
23 #include "wx/wxprec.h"
24
25 // WX includes
26 #ifndef WX_PRECOMP
27 #include "wx/string.h"
28 #include "wx/log.h"
29 #include "wx/intl.h"
30 #include "wx/utils.h"
31 #include "wx/wxcrt.h"
32 #endif // WX_PRECOMP
33
34 // Mac Includes
35 #include <CoreFoundation/CoreFoundation.h>
36 #ifndef __WXOSX_IPHONE__
37 #include <ApplicationServices/ApplicationServices.h>
38 #endif
39
40 // More WX Includes
41 #include "wx/filename.h"
42 #include "wx/mac/corefoundation/cfstring.h"
43
44 // Default path style
45 #define kDefaultPathStyle kCFURLPOSIXPathStyle
46
47 //===========================================================================
48 // IMPLEMENTATION
49 //===========================================================================
50
51 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
52 //
53 // wxMacLaunch
54 //
55 // argv is the command line split up, with the application path first
56 // flags are the flags from wxExecute
57 // process is the process passed from wxExecute for pipe streams etc.
58 // returns -1 on error for wxEXEC_SYNC and 0 on error for wxEXEC_ASYNC
59 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
60 bool wxMacLaunch(char **argv)
61 {
62 // Obtains the number of arguments for determining the size of
63 // the CFArray used to hold them
64 CFIndex cfiCount = 0;
65 for(char** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
66 {
67 ++cfiCount;
68 }
69
70 // If there is not a single argument then there is no application
71 // to launch
72 if(cfiCount == 0)
73 {
74 wxLogDebug(wxT("wxMacLaunch No file to launch!"));
75 return false ;
76 }
77
78 // Path to bundle
79 wxString path = *argv++;
80
81 // Create a CFURL for the application path
82 // Created this way because we are opening a bundle which is a directory
83 CFURLRef cfurlApp =
84 CFURLCreateWithFileSystemPath(
85 kCFAllocatorDefault,
86 wxCFStringRef(path),
87 kDefaultPathStyle,
88 true); //false == not a directory
89
90 // Check for error from the CFURL
91 if(!cfurlApp)
92 {
93 wxLogDebug(wxT("wxMacLaunch Can't open path: %s"), path.c_str());
94 return false ;
95 }
96
97 // Create a CFBundle from the CFURL created earlier
98 CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp);
99
100 // Check to see if CFBundleCreate returned an error,
101 // and if it did this was an invalid bundle or not a bundle
102 // at all (maybe a simple directory etc.)
103 if(!cfbApp)
104 {
105 wxLogDebug(wxT("wxMacLaunch Bad bundle: %s"), path.c_str());
106 CFRelease(cfurlApp);
107 return false ;
108 }
109
110 // Get the bundle type and make sure its an 'APPL' bundle
111 // Otherwise we're dealing with something else here...
112 UInt32 dwBundleType, dwBundleCreator;
113 CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
114 if(dwBundleType != 'APPL')
115 {
116 wxLogDebug(wxT("wxMacLaunch Not an APPL bundle: %s"), path.c_str());
117 CFRelease(cfbApp);
118 CFRelease(cfurlApp);
119 return false ;
120 }
121
122 // Create a CFArray for dealing with the command line
123 // arguments to the bundle
124 CFMutableArrayRef cfaFiles = CFArrayCreateMutable(kCFAllocatorDefault,
125 cfiCount-1, &kCFTypeArrayCallBacks);
126 if(!cfaFiles) //This should never happen
127 {
128 wxLogDebug(wxT("wxMacLaunch Could not create CFMutableArray"));
129 CFRelease(cfbApp);
130 CFRelease(cfurlApp);
131 return false ;
132 }
133
134 // Loop through command line arguments to the bundle,
135 // turn them into CFURLs and then put them in cfaFiles
136 // For use to launch services call
137 for( ; *argv != NULL ; ++argv)
138 {
139 // Check for '<' as this will ring true for
140 // CFURLCreateWithString but is generally not considered
141 // typical on mac but is usually passed here from wxExecute
142 if (wxStrcmp(*argv, wxT("<")) == 0)
143 continue;
144
145
146 CFURLRef cfurlCurrentFile; // CFURL to hold file path
147 wxFileName argfn(*argv); // Filename for path
148
149 if(argfn.DirExists())
150 {
151 // First, try creating as a directory
152 cfurlCurrentFile = CFURLCreateWithFileSystemPath(
153 kCFAllocatorDefault,
154 wxCFStringRef(*argv),
155 kDefaultPathStyle,
156 true); //true == directory
157 }
158 else if(argfn.FileExists())
159 {
160 // And if it isn't a directory try creating it
161 // as a regular file
162 cfurlCurrentFile = CFURLCreateWithFileSystemPath(
163 kCFAllocatorDefault,
164 wxCFStringRef(*argv),
165 kDefaultPathStyle,
166 false); //false == regular file
167 }
168 else
169 {
170 // Argument did not refer to
171 // an entry in the local filesystem,
172 // so try creating it through CFURLCreateWithString
173 cfurlCurrentFile = CFURLCreateWithString(
174 kCFAllocatorDefault,
175 wxCFStringRef(*argv),
176 NULL);
177 }
178
179 // Continue in the loop if the CFURL could not be created
180 if(!cfurlCurrentFile)
181 {
182 wxLogDebug(
183 wxT("wxMacLaunch Could not create CFURL for argument:%s"),
184 *argv);
185 continue;
186 }
187
188 // Add the valid CFURL to the argument array and then
189 // release it as the CFArray adds a ref count to it
190 CFArrayAppendValue(
191 cfaFiles,
192 cfurlCurrentFile
193 );
194 CFRelease(cfurlCurrentFile); // array has retained it
195 }
196
197 // Create a LSLaunchURLSpec for use with LSOpenFromURLSpec
198 // Note that there are several flag options (launchFlags) such
199 // as kLSLaunchDontSwitch etc. and maybe we could be more
200 // picky about the flags we choose
201 LSLaunchURLSpec launchspec;
202 launchspec.appURL = cfurlApp;
203 launchspec.itemURLs = cfaFiles;
204 launchspec.passThruParams = NULL; //AEDesc*
205 launchspec.launchFlags = kLSLaunchDefaults;
206 launchspec.asyncRefCon = NULL;
207
208 // Finally, call LSOpenFromURL spec with our arguments
209 // 2nd parameter is a pointer to a CFURL that gets
210 // the actual path launched by the function
211 OSStatus status = LSOpenFromURLSpec(&launchspec, NULL);
212
213 // Cleanup corefoundation references
214 CFRelease(cfbApp);
215 CFRelease(cfurlApp);
216 CFRelease(cfaFiles);
217
218 // Check for error from LSOpenFromURLSpec
219 if(status != noErr)
220 {
221 wxLogDebug(wxT("wxMacLaunch LSOpenFromURLSpec Error: %d"),
222 (int)status);
223 return false ;
224 }
225
226 // No error from LSOpenFromURLSpec, so app was launched
227 return true ;
228 }
229