]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/corefoundation/utilsexc_base.cpp
corrected GetKeyInfo() (bug 1815516)
[wxWidgets.git] / src / mac / corefoundation / utilsexc_base.cpp
index 855a605c6c8d8c48eb08cf254dfc7dcf32cce785..a82bcb3ceb08128d2543ec4a8f21930b3bc062e2 100644 (file)
 //              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/utils.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"
 
+// 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)
 {
-       const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0);
-       const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID
+    // 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),
+            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;
-            
-            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,
+                                wxMacCFStringHolder(*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,
+                                wxMacCFStringHolder(*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,
+                                wxMacCFStringHolder(*argv),
+                                NULL);
+        }
 
+        // 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.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);
+        wxLogDebug(wxT("wxMacExecute LSOpenFromURLSpec Error: %d"),
+                   (int)status);
         return errorCode ;
     }
-    return successCode; //success
+
+    // No error from LSOpenFromURLSpec, so app was launched
+    return successCode;
 }