From 7db33dd7ad69260bf3ee0a36278285448442daa5 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Fri, 18 Nov 2005 18:40:34 +0000 Subject: [PATCH] patch 1265473 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@36197 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/mac/carbon/mimetmac.cpp | 3 +- src/mac/corefoundation/utilsexc_base.cpp | 185 ++++++++++++++++++----- 2 files changed, 148 insertions(+), 40 deletions(-) diff --git a/src/mac/carbon/mimetmac.cpp b/src/mac/carbon/mimetmac.cpp index cc471b746b..634c70065c 100644 --- a/src/mac/carbon/mimetmac.cpp +++ b/src/mac/carbon/mimetmac.cpp @@ -418,8 +418,9 @@ wxString wxFileTypeImpl::GetCommand(const wxString& verb) const CFRelease(cfurlAppPath); //PHEW! Success! + //Since a filename might have spaces in it, so surround it with quotes if(cfsUnixPath) - return wxMacCFStringHolder(cfsUnixPath).AsString(wxLocale::GetSystemEncoding()); + return wxString(wxT("'")) + wxMacCFStringHolder(cfsUnixPath).AsString(wxLocale::GetSystemEncoding()) + wxString(wxT("'")); } else { diff --git a/src/mac/corefoundation/utilsexc_base.cpp b/src/mac/corefoundation/utilsexc_base.cpp index 855a605c6c..db2c9f38a4 100644 --- a/src/mac/corefoundation/utilsexc_base.cpp +++ b/src/mac/corefoundation/utilsexc_base.cpp @@ -11,8 +11,18 @@ // 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" @@ -20,113 +30,210 @@ #include "wx/utils.h" #endif // WX_PRECOMP - +// Mac Includes #include #include -#include "wx/uri.h" +// More WX Includes +#include "wx/filename.h" #include "wx/mac/corefoundation/cfstring.h" +// Default path style +#ifdef __WXMAC_OSX__ +#define kDefaultPathStyle kCFURLPOSIXPathStyle +#else +#define kDefaultPathStyle kCFURLHFSPathStyle +#endif + +//=========================================================================== +// IMPLEMENTATION +//=========================================================================== + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxMacExecute +// +// 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 +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ long wxMacExecute(wxChar **argv, int flags, wxProcess *process) { + // Semi-macros used for return value of wxMacExecute const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0); const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID + // 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) { ++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 ; } - 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); + wxMacCFStringHolder(path, + wxLocale::GetSystemEncoding()), + kDefaultPathStyle, + true); //false == not a directory + // Check for error from the CFURL + if(!cfurlApp) + { + wxLogDebug(wxT("wxMacExecute Can't open path: %s"), path.c_str()); + return errorCode ; + } + + // 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("wxMacExecute Bad bundle: %s"), path.c_str()); CFRelease(cfurlApp); return errorCode ; } - + // 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("wxMacExecute Not an APPL bundle: %s"), path.c_str()); + CFRelease(cfbApp); CFRelease(cfurlApp); return errorCode ; } - // - // 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("wxMacExecute Could not create CFMutableArray")); + CFRelease(cfbApp); + CFRelease(cfurlApp); + return errorCode ; + } + + // 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; + // 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; - if(wxURI(*argv).IsReference()) - sCurrentFile = wxString(wxT("file://")) + *argv; - else - sCurrentFile = *argv; + + CFURLRef cfurlCurrentFile; // CFURL to hold file path + wxFileName argfn(*argv); // Filename for path - CFURLRef cfurlCurrentFile = CFURLCreateWithString( + if(argfn.DirExists()) + { + // First, try creating as a directory + cfurlCurrentFile = CFURLCreateWithFileSystemPath( + kCFAllocatorDefault, + wxMacCFStringHolder(*argv, + wxLocale::GetSystemEncoding()), + 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, + wxMacCFStringHolder(*argv, + wxLocale::GetSystemEncoding()), + 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, - wxMacCFStringHolder(sCurrentFile, wxLocale::GetSystemEncoding()), + wxMacCFStringHolder(*argv, wxLocale::GetSystemEncoding()), NULL); - wxASSERT(cfurlCurrentFile); + } + + // Continue in the loop if the CFURL could not be created + if(!cfurlCurrentFile) + { + wxLogDebug( + wxT("wxMacExecute 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.launchFlags = kLSLaunchDefaults; launchspec.asyncRefCon = NULL; - OSStatus status = LSOpenFromURLSpec(&launchspec, - NULL); //2nd is CFURLRef* really launched + // 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 + // 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); + wxLogDebug(wxT("wxMacExecute LSOpenFromURLSpec Error: %d"), + (int)status); return errorCode ; } - return successCode; //success + + // No error from LSOpenFromURLSpec, so app was launched + return successCode; } -- 2.45.2