Files
wxWidgets/src/osx/core/utilsexc_base.cpp

280 lines
8.8 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: mac/corefoundation/utilsexc_base.cpp
// Purpose: wxMacLaunch
// Author: Ryan Norton
// Modified by:
// Created: 2005-06-21
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
// Notes: Source was originally in utilsexc_cf.cpp,1.6 then moved
// 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>
#ifndef __WXOSX_IPHONE__
#include <ApplicationServices/ApplicationServices.h>
#endif
// More WX Includes
#include "wx/filename.h"
#include "wx/osx/core/cfstring.h"
#include "wx/osx/core/private.h"
// Default path style
#define kDefaultPathStyle kCFURLPOSIXPathStyle
extern bool WXDLLEXPORT wxIsDebuggerRunning()
{
// TODO : try to find out ...
return false;
}
#if wxOSX_USE_COCOA_OR_CARBON
// have a fast version for mac code that returns the version as a return value
long UMAGetSystemVersion()
{
static SInt32 sUMASystemVersion = 0 ;
if ( sUMASystemVersion == 0 )
{
verify_noerr(Gestalt(gestaltSystemVersion, &sUMASystemVersion));
}
return sUMASystemVersion ;
}
// our OS version is the same in non GUI and GUI cases
wxOperatingSystemId wxGetOsVersion(int *majorVsn, int *minorVsn)
{
SInt32 theSystem;
Gestalt(gestaltSystemVersion, &theSystem);
if ( majorVsn != NULL )
*majorVsn = (theSystem >> 8);
if ( minorVsn != NULL )
*minorVsn = (theSystem & 0xFF);
return wxOS_MAC_OSX_DARWIN;
}
#include <sys/utsname.h>
wxString wxGetOsDescription()
{
struct utsname name;
uname(&name);
return wxString::Format(_T("Mac OS X (%s %s %s)"),
wxString::FromAscii(name.sysname).c_str(),
wxString::FromAscii(name.release).c_str(),
wxString::FromAscii(name.machine).c_str());
}
#endif // wxOSX_USE_COCOA_OR_CARBON
//===========================================================================
// 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;
for(char** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
{
++cfiCount;
}
// If there is not a single argument then there is no application
// to launch
if(cfiCount == 0)
{
wxLogDebug(wxT("wxMacLaunch No file to launch!"));
return false ;
}
// 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,
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("wxMacLaunch Bad bundle: %s"), path.c_str());
CFRelease(cfurlApp);
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);
if(dwBundleType != 'APPL')
{
wxLogDebug(wxT("wxMacLaunch Not an APPL bundle: %s"), path.c_str());
CFRelease(cfbApp);
CFRelease(cfurlApp);
return false ;
}
// 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)
{
// 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;
launchspec.asyncRefCon = NULL;
// 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 from LSOpenFromURLSpec
if(status != noErr)
{
wxLogDebug(wxT("wxMacLaunch LSOpenFromURLSpec Error: %d"),
(int)status);
return false ;
}
// No error from LSOpenFromURLSpec, so app was launched
return true ;
}