Rewrite the OS X bundle utils in Obj-C++ and return std::strings rather than malloced char *

Originally committed to SVN as r6896.
This commit is contained in:
Thomas Goyne 2012-06-12 03:13:49 +00:00
parent 4b78e05695
commit 0f071d978a
7 changed files with 119 additions and 213 deletions

View file

@ -46,8 +46,8 @@ SRC += \
unix/path.cpp
ifeq (yes, $(BUILD_DARWIN))
SRC += \
osx/util.cpp
SRC += osx/util.mm
osx/util.o: OBJCXXFLAGS += -fobjc-arc
endif
HEADER += \
@ -57,8 +57,7 @@ HEADER += \
include/libaegisub/charsets.def \
include/libaegisub/cajun/*.h
EXTRA_DIST += osx/util.cpp
EXTRA_DIST += osx/util.mm
include ../Makefile.target
-include */*.d

View file

@ -16,8 +16,8 @@
/// @file util_osx.h
/// @brief OSX Utilities
/// @ingroup libaegisub osx
/// @brief OSX Utilities
/// @ingroup libaegisub osx
///
/// Utility functions for running regular *NIX libraries inside application
/// bundles on Apple Macintosh OS X.
@ -29,44 +29,38 @@
///
/// When linking with this library, be sure to add '-framework CoreFoundation'
/// to the GCC commandline.
///
/// @note All strings returned by these functions are allocated by strdup(), it is
/// the responsibility of the caller to free() them.
/// All of the functions may return NULL on error.
#ifndef LAGI_PRE
#include <string>
#endif
namespace agi {
namespace util {
/// @brief Get the full name of bundle.
/// @return Full name of bundle.
/// Get the full name of the bundle itself.
///
/// @warning May return NULL if the current executable is not inside a bundle.
char * OSX_GetBundlePath();
/// @warning May return "" if the current executable is not inside a bundle.
std::string OSX_GetBundlePath();
/// @brief Get the esources directory.
/// @return Resources directory.
///
/// Mainly for user interface elements such as graphics and strings
char * OSX_GetBundleResourcesDirectory();
std::string OSX_GetBundleResourcesDirectory();
/// @brief Get the built-in plugins directory.
/// @return Built-in plugins directory.
///
/// This is generaly only used by native Carbon and Cocoa applications. It is
/// not for general shared libraries.
char * OSX_GetBundleBuiltInPlugInsDirectory();
std::string OSX_GetBundleBuiltInPlugInsDirectory();
/// @brief Get the private Frameworks directory.
/// @return Private Framework directory.
///
/// These are suitable locations for shared libraries.
char * OSX_GetBundlePrivateFrameworksDirectory();
std::string OSX_GetBundlePrivateFrameworksDirectory();
/// @brief Get the shared Frameworks directory.
/// @return Shared Framework directory.
@ -74,44 +68,30 @@ char * OSX_GetBundlePrivateFrameworksDirectory();
/// @see OSX_GetBundlePrivateFrameworksDirectory()
/// @note Does anyone know the difference between private and shared frameworks
/// inside a bundle?
char * OSX_GetBundleSharedFrameworksDirectory();
std::string OSX_GetBundleSharedFrameworksDirectory();
/// @brief Get the shared support directory
/// @return Shared support directory
///
/// This is a suitable location for static configuration files. (Remember,
/// bundle is considered read-only.)
char * OSX_GetBundleSharedSupportDirectory();
/// @brief Get the support directory
/// @return Support directory
/// @see OSX_GetBundleSharedSupportDirectory()
/// @note Again, what is the difference between Support and SharedSupport?
char * OSX_GetBundleSupportFilesDirectory();
std::string OSX_GetBundleSharedSupportDirectory();
/// @brief Get the main executable path.
/// @return Main executable path.
///
/// The binary run when the user launches the bundle from Finder.
char * OSX_GetBundleExecutablePath();
std::string OSX_GetBundleExecutablePath();
/// @brief Get the auxillary executable path.
/// @return Auxillary executable path.
///
/// Pass the basename of the executable to get the path.
char * OSX_GetBundleAuxillaryExecutablePath(const char *executableName);
std::string OSX_GetBundleAuxillaryExecutablePath(std::string const& executableName);
/// @brief Open a URI using the Launcher.
/// @param location URI of file
/// @note If this is a FILE or DIRECTORY the path must be ABSOLUTE no 'file://'
/// @return Error code.
void OSX_OpenLocation(const char *location);
void OSX_OpenLocation(std::string const& location);
} // namespace io
} // namespace agi

View file

@ -1,156 +0,0 @@
// Copyright (c) 2008-2009 Niels Martin Hansen
// Copyright (c) 2010 Amar Takhar
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file util.cpp
/// @brief OSX Utilities
/// @ingroup libosxutil osx
#include <string.h>
#include <sys/param.h>
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFURL.h>
#include <CoreFoundation/CFString.h>
#include <ApplicationServices/ApplicationServices.h>
#include "libaegisub/util_osx.h"
namespace agi {
namespace util {
/// @brief Type of functions that return a URL from a bundle.
/// @internal
typedef CFURLRef (*GetURLFunc)(CFBundleRef);
/// @brief Generic implementation to retrieve pathnames inside a bundle.
///
/// @internal Provide a generic implementation for most of the logic
/// in path-retrieval, since what differs for the various functions is
/// only the call used to retrieve the actual path inside the bundle.
static char * GetDir(GetURLFunc GetURL)
{
CFBundleRef bundle;
CFURLRef res_dir_url;
char res_dir_str[MAXPATHLEN];
Boolean res;
bundle = CFBundleGetMainBundle();
if (!bundle) return NULL;
res_dir_url = (*GetURL)(bundle);
/* we do not own 'bundle' so don't release it */
if (!res_dir_url) return NULL;
res = CFURLGetFileSystemRepresentation(res_dir_url, true, (UInt8*)res_dir_str, MAXPATHLEN);
CFRelease(res_dir_url);
if (res == false)
return NULL;
else
return strdup(res_dir_str);
}
char * OSX_GetBundlePath()
{
return GetDir(CFBundleCopyBundleURL);
}
char * OSX_GetBundleResourcesDirectory()
{
return GetDir(CFBundleCopyResourcesDirectoryURL);
}
char * OSX_GetBundleExecutablePath()
{
return GetDir(CFBundleCopyExecutableURL);
}
char * OSX_GetBundleBuiltInPlugInsDirectory()
{
return GetDir(CFBundleCopyBuiltInPlugInsURL);
}
char * OSX_GetBundlePrivateFrameworksDirectory()
{
return GetDir(CFBundleCopyPrivateFrameworksURL);
}
char * OSX_GetBundleSharedFrameworksDirectory()
{
return GetDir(CFBundleCopySharedFrameworksURL);
}
char * OSX_GetBundleSharedSupportDirectory()
{
return GetDir(CFBundleCopySharedSupportURL);
}
char * OSX_GetBundleSupportFilesDirectory()
{
return GetDir(CFBundleCopySupportFilesDirectoryURL);
}
char * OSX_GetBundleAuxillaryExecutablePath(const char *executableName)
{
CFStringRef exename_str;
CFBundleRef bundle;
CFURLRef res_dir_url;
char res_dir_str[MAXPATHLEN];
Boolean res;
exename_str = CFStringCreateWithCString(NULL, executableName, kCFStringEncodingUTF8);
if (!exename_str) return NULL;
bundle = CFBundleGetMainBundle();
if (!bundle) return NULL;
res_dir_url = CFBundleCopyAuxiliaryExecutableURL(bundle, exename_str);
CFRelease(exename_str);
if (!res_dir_url) return NULL;
res = CFURLGetFileSystemRepresentation(res_dir_url, true, (UInt8*)res_dir_str, MAXPATHLEN);
CFRelease(res_dir_url);
if (res == false)
return NULL;
else
return strdup(res_dir_str);
}
void OSX_OpenLocation (const char *location) {
CFStringRef CFSlocation = CFStringCreateWithCString(NULL, location, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSlocation , kCFURLPOSIXPathStyle, false);
OSStatus stat = LSOpenCFURLRef(url, NULL);
printf("libosxutil::OSX_OpenLocation: %s\n", GetMacOSStatusCommentString(stat));
}
} // namespace io
} // namespace agi

View file

@ -0,0 +1,92 @@
// Copyright (c) 2012 Thomas Goyne, <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// $Id$
/// @file util.mm
/// @brief OSX Utilities
/// @ingroup libosxutil osx
#include "config.h"
#include "libaegisub/util_osx.h"
#import <ApplicationServices/ApplicationServices.h>
#import <Foundation/Foundation.h>
static std::string EmptyIfNil(NSString *string) {
return string ? [string UTF8String] : "";
}
namespace agi {
namespace util {
std::string OSX_GetBundlePath() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] bundlePath]);
}
}
std::string OSX_GetBundleResourcesDirectory() {
@autoreleasepool {
return EmptyIfNil([[[NSBundle mainBundle] resourceURL] path]);
}
}
std::string OSX_GetBundleExecutablePath() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] executablePath]);
}
}
std::string OSX_GetBundleBuiltInPlugInsDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] builtInPlugInsPath]);
}
}
std::string OSX_GetBundlePrivateFrameworksDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] privateFrameworksPath]);
}
}
std::string OSX_GetBundleSharedFrameworksDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] sharedFrameworksPath]);
}
}
std::string OSX_GetBundleSharedSupportDirectory() {
@autoreleasepool {
return EmptyIfNil([[NSBundle mainBundle] sharedSupportPath]);
}
}
std::string OSX_GetBundleAuxillaryExecutablePath(std::string const& executableName) {
@autoreleasepool {
NSString *name = [NSString stringWithUTF8String:executableName.c_str()];
return EmptyIfNil([[NSBundle mainBundle]pathForAuxiliaryExecutable:name]);
}
}
void OSX_OpenLocation(std::string const& location) {
@autoreleasepool {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:location.c_str()]];
LSOpenCFURLRef((__bridge CFURLRef)url, NULL);
}
}
}
}

View file

@ -98,10 +98,7 @@ struct help_files : public Command {
STR_HELP("Resource files")
void operator()(agi::Context *) {
char *shared_path = agi::util::OSX_GetBundleSharedSupportDirectory();
wxString help_path = wxString::Format("%s/doc", wxString(shared_path, wxConvUTF8));
agi::util::OSX_OpenLocation(help_path.c_str());
free(shared_path);
agi::util::OSX_OpenLocation((agi::util::OSX_GetBundleSharedSupportDirectory() + "/doc").c_str());
}
};
#endif

View file

@ -83,15 +83,10 @@ class FontConfigCacheThread : public wxThread {
ASS_Renderer *ass_renderer;
FontConfigCacheThread** thisPtr;
ExitCode Entry() {
#ifdef __APPLE__
char config_path[MAXPATHLEN];
char *config_dir;
config_dir = agi::util::OSX_GetBundleResourcesDirectory();
snprintf(config_path, MAXPATHLEN, "%s/etc/fonts/fonts.conf", config_dir);
free(config_dir);
#else
const char *config_path = NULL;
#ifdef __APPLE__
std::string conf_path = agi::util::OSX_GetBundleResourcesDirectory() + "/etc/fonts/fonts.conf";
config_path = conf_path.c_str();
#endif
if (ass_library) ass_renderer = ass_renderer_init(ass_library);

View file

@ -282,14 +282,13 @@ void RestartAegisub() {
wxStandardPaths stand;
wxExecute("\"" + stand.GetExecutablePath() + "\"");
#elif defined(__WXMAC__)
char *bundle_path = agi::util::OSX_GetBundlePath();
char *support_path = agi::util::OSX_GetBundleSupportFilesDirectory();
if (!bundle_path || !support_path) return; // oops
wxString exec = wxString::Format("\"%s/MacOS/restart-helper\" /usr/bin/open -n \"%s\"'", wxString(support_path, wxConvUTF8), wxString(bundle_path, wxConvUTF8));
std::string bundle_path = agi::util::OSX_GetBundlePath();
std::string helper_path = agi::util::OSX_GetBundleAuxillaryExecutablePath("restart-helper");
if (bundle_path.empty() || helper_path.empty()) return;
wxString exec = wxString::Format("\"%s\" /usr/bin/open -n \"%s\"'", lagi_wxString(helper_path), lagi_wxString(bundle_path));
LOG_I("util/restart/exec") << exec;
wxExecute(exec);
free(bundle_path);
free(support_path);
#else
wxStandardPaths stand;
wxExecute(stand.GetExecutablePath());