/////////////////////////////////////////////////////////////////////////////
// Name: mac/corefoundation/utilsexc_base.cpp
-// Purpose: wxMacExecute
+// Purpose: wxMacLaunch
// Author: Ryan Norton
// Modified by:
// Created: 2005-06-21
// to totally unrelated hid.cpp,1.8.
/////////////////////////////////////////////////////////////////////////////
+//===========================================================================
+// DECLARATIONS
+//===========================================================================
+
+//---------------------------------------------------------------------------
+// Pre-compiled header stuff
+//---------------------------------------------------------------------------
+
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
+
+// WX includes
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/utils.h"
+ #include "wx/wxcrt.h"
#endif // WX_PRECOMP
-
+// Mac Includes
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
-#include "wx/uri.h"
+// More WX Includes
+#include "wx/filename.h"
#include "wx/mac/corefoundation/cfstring.h"
-long wxMacExecute(wxChar **argv,
- int flags,
- wxProcess *process)
-{
- const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0);
- const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID
+// Default path style
+#define kDefaultPathStyle kCFURLPOSIXPathStyle
+//===========================================================================
+// IMPLEMENTATION
+//===========================================================================
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxMacLaunch
+//
+// argv is the command line split up, with the application path first
+// flags are the flags from wxExecute
+// process is the process passed from wxExecute for pipe streams etc.
+// returns -1 on error for wxEXEC_SYNC and 0 on error for wxEXEC_ASYNC
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+bool wxMacLaunch(char **argv)
+{
+ // Obtains the number of arguments for determining the size of
+ // the CFArray used to hold them
CFIndex cfiCount = 0;
- //get count
- for(wxChar** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
+ for(char** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
{
++cfiCount;
}
- if(cfiCount == 0) //no file to launch?
+ // If there is not a single argument then there is no application
+ // to launch
+ if(cfiCount == 0)
{
- wxLogDebug(wxT("wxMacExecute No file to launch!"));
- return errorCode ;
+ wxLogDebug(wxT("wxMacLaunch No file to launch!"));
+ return false ;
}
-
- CFURLRef cfurlApp = CFURLCreateWithString(
+
+ // Path to bundle
+ wxString path = *argv++;
+
+ // Create a CFURL for the application path
+ // Created this way because we are opening a bundle which is a directory
+ CFURLRef cfurlApp =
+ CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
- wxMacCFStringHolder(*argv++, wxLocale::GetSystemEncoding()),
- NULL);
- wxASSERT(cfurlApp);
+ wxCFStringRef(path),
+ kDefaultPathStyle,
+ true); //false == not a directory
+ // Check for error from the CFURL
+ if(!cfurlApp)
+ {
+ wxLogDebug(wxT("wxMacLaunch Can't open path: %s"), path.c_str());
+ return false ;
+ }
+
+ // Create a CFBundle from the CFURL created earlier
CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp);
+
+ // Check to see if CFBundleCreate returned an error,
+ // and if it did this was an invalid bundle or not a bundle
+ // at all (maybe a simple directory etc.)
if(!cfbApp)
{
- wxLogDebug(wxT("wxMacExecute Bad bundle"));
+ wxLogDebug(wxT("wxMacLaunch Bad bundle: %s"), path.c_str());
CFRelease(cfurlApp);
- return errorCode ;
+ return false ;
}
-
-
+
+ // Get the bundle type and make sure its an 'APPL' bundle
+ // Otherwise we're dealing with something else here...
UInt32 dwBundleType, dwBundleCreator;
CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
-
- //Only call wxMacExecute for .app bundles - others could be actual unix programs
if(dwBundleType != 'APPL')
{
+ wxLogDebug(wxT("wxMacLaunch Not an APPL bundle: %s"), path.c_str());
+ CFRelease(cfbApp);
CFRelease(cfurlApp);
- return errorCode ;
+ return false ;
}
-
- //
- // We have a good bundle - so let's launch it!
- //
-
- CFMutableArrayRef cfaFiles =
- CFArrayCreateMutable(kCFAllocatorDefault, cfiCount - 1, &kCFTypeArrayCallBacks);
-
- wxASSERT(cfaFiles);
-
- if(--cfiCount)
+
+ // Create a CFArray for dealing with the command line
+ // arguments to the bundle
+ CFMutableArrayRef cfaFiles = CFArrayCreateMutable(kCFAllocatorDefault,
+ cfiCount-1, &kCFTypeArrayCallBacks);
+ if(!cfaFiles) //This should never happen
{
+ wxLogDebug(wxT("wxMacLaunch Could not create CFMutableArray"));
+ CFRelease(cfbApp);
+ CFRelease(cfurlApp);
+ return false ;
+ }
+
+ // Loop through command line arguments to the bundle,
+ // turn them into CFURLs and then put them in cfaFiles
+ // For use to launch services call
for( ; *argv != NULL ; ++argv)
{
-// wxLogDebug(*argv);
- wxString sCurrentFile;
-
- if(wxURI(*argv).IsReference())
- sCurrentFile = wxString(wxT("file://")) + *argv;
- else
- sCurrentFile = *argv;
-
- CFURLRef cfurlCurrentFile = CFURLCreateWithString(
- kCFAllocatorDefault,
- wxMacCFStringHolder(sCurrentFile, wxLocale::GetSystemEncoding()),
- NULL);
- wxASSERT(cfurlCurrentFile);
+ // Check for '<' as this will ring true for
+ // CFURLCreateWithString but is generally not considered
+ // typical on mac but is usually passed here from wxExecute
+ if (wxStrcmp(*argv, wxT("<")) == 0)
+ continue;
+
+
+ CFURLRef cfurlCurrentFile; // CFURL to hold file path
+ wxFileName argfn(*argv); // Filename for path
+
+ if(argfn.DirExists())
+ {
+ // First, try creating as a directory
+ cfurlCurrentFile = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault,
+ wxCFStringRef(*argv),
+ kDefaultPathStyle,
+ true); //true == directory
+ }
+ else if(argfn.FileExists())
+ {
+ // And if it isn't a directory try creating it
+ // as a regular file
+ cfurlCurrentFile = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault,
+ wxCFStringRef(*argv),
+ kDefaultPathStyle,
+ false); //false == regular file
+ }
+ else
+ {
+ // Argument did not refer to
+ // an entry in the local filesystem,
+ // so try creating it through CFURLCreateWithString
+ cfurlCurrentFile = CFURLCreateWithString(
+ kCFAllocatorDefault,
+ wxCFStringRef(*argv),
+ NULL);
+ }
+ // Continue in the loop if the CFURL could not be created
+ if(!cfurlCurrentFile)
+ {
+ wxLogDebug(
+ wxT("wxMacLaunch Could not create CFURL for argument:%s"),
+ *argv);
+ continue;
+ }
+
+ // Add the valid CFURL to the argument array and then
+ // release it as the CFArray adds a ref count to it
CFArrayAppendValue(
cfaFiles,
cfurlCurrentFile
);
CFRelease(cfurlCurrentFile); // array has retained it
}
- }
-
+
+ // Create a LSLaunchURLSpec for use with LSOpenFromURLSpec
+ // Note that there are several flag options (launchFlags) such
+ // as kLSLaunchDontSwitch etc. and maybe we could be more
+ // picky about the flags we choose
LSLaunchURLSpec launchspec;
launchspec.appURL = cfurlApp;
launchspec.itemURLs = cfaFiles;
- launchspec.passThruParams = NULL; //AEDesc*
- launchspec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch; //TODO: Possibly be smarter with flags
+ launchspec.passThruParams = NULL; //AEDesc*
+ launchspec.launchFlags = kLSLaunchDefaults;
launchspec.asyncRefCon = NULL;
-
- OSStatus status = LSOpenFromURLSpec(&launchspec,
- NULL); //2nd is CFURLRef* really launched
- //cleanup
+ // Finally, call LSOpenFromURL spec with our arguments
+ // 2nd parameter is a pointer to a CFURL that gets
+ // the actual path launched by the function
+ OSStatus status = LSOpenFromURLSpec(&launchspec, NULL);
+
+ // Cleanup corefoundation references
+ CFRelease(cfbApp);
CFRelease(cfurlApp);
CFRelease(cfaFiles);
-
- //check for error
+
+ // Check for error from LSOpenFromURLSpec
if(status != noErr)
{
- wxLogDebug(wxT("wxMacExecute ERROR: %d"), (int)status);
- return errorCode ;
+ wxLogDebug(wxT("wxMacLaunch LSOpenFromURLSpec Error: %d"),
+ (int)status);
+ return false ;
}
- return successCode; //success
+
+ // No error from LSOpenFromURLSpec, so app was launched
+ return true ;
}