|
- #include <arch.hpp>
-
- #if defined ARCH_MAC
- #include <CoreFoundation/CoreFoundation.h>
- #include <CoreServices/CoreServices.h>
- #include <pwd.h>
- #endif
-
- #if defined ARCH_WIN
- #include <Windows.h>
- #include <Shlobj.h>
- #include <Shlwapi.h>
- #endif
-
- #if defined ARCH_LIN
- #include <unistd.h>
- #include <sys/types.h>
- #include <pwd.h>
- #endif
-
- #include <asset.hpp>
- #include <system.hpp>
- #include <settings.hpp>
- #include <string.hpp>
- #include <plugin/Plugin.hpp>
- #include <engine/Module.hpp>
- #include <app/common.hpp>
- #include <osdialog.h>
-
-
- namespace rack {
- namespace asset {
-
-
- #if defined ARCH_MAC
- std::string getApplicationSupportDir();
- #endif
-
-
- static void initSystemDir() {
- if (!systemDir.empty())
- return;
-
- if (settings::devMode) {
- systemDir = system::getWorkingDirectory();
- return;
- }
-
- // Environment variable overrides
- const char* envSystem = getenv("RACK_SYSTEM_DIR");
- if (envSystem) {
- systemDir = envSystem;
- return;
- }
-
- #if defined ARCH_MAC
- CFBundleRef bundle = CFBundleGetMainBundle();
- assert(bundle);
-
- // Check if we're running as a command-line program or an app bundle.
- CFURLRef bundleUrl = CFBundleCopyBundleURL(bundle);
- // Thanks Ken Thomases! https://stackoverflow.com/a/58369256/272642
- CFStringRef uti;
- if (CFURLCopyResourcePropertyForKey(bundleUrl, kCFURLTypeIdentifierKey, &uti, NULL) && uti && UTTypeConformsTo(uti, kUTTypeApplicationBundle)) {
- char bundleBuf[PATH_MAX];
- Boolean success = CFURLGetFileSystemRepresentation(bundleUrl, TRUE, (UInt8*) bundleBuf, sizeof(bundleBuf));
- assert(success);
- bundlePath = bundleBuf;
- }
-
- CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(bundle);
- char resourcesBuf[PATH_MAX];
- Boolean success = CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8*) resourcesBuf, sizeof(resourcesBuf));
- assert(success);
- CFRelease(resourcesUrl);
- systemDir = resourcesBuf;
- #endif
- #if defined ARCH_WIN
- // Get path to executable
- wchar_t moduleBufW[MAX_PATH] = L"";
- DWORD length = GetModuleFileNameW(NULL, moduleBufW, LENGTHOF(moduleBufW));
- assert(length > 0);
- // Get directory of executable
- PathRemoveFileSpecW(moduleBufW);
- systemDir = string::UTF16toUTF8(moduleBufW);
- #endif
- #if defined ARCH_LIN
- // Use the current working directory as the default path on Linux.
- systemDir = system::getWorkingDirectory();
- #endif
- }
-
-
- static void initUserDir() {
- if (!userDir.empty())
- return;
-
- if (settings::devMode) {
- userDir = systemDir;
- return;
- }
-
- // Environment variable overrides
- const char* envUser = getenv("RACK_USER_DIR");
- if (envUser) {
- userDir = envUser;
- return;
- }
-
- #if defined ARCH_WIN
- // Get AppData/Local path
- WCHAR localBufW[MAX_PATH] = {};
- HRESULT localH = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, localBufW);
- assert(SUCCEEDED(localH));
- std::string localDir = string::UTF16toUTF8(localBufW);
-
- // Usually C:/Users/<username>/AppData/Local/Rack2
- userDir = system::join(localDir, "Rack" + APP_VERSION_MAJOR);
-
- // Get Documents path
- WCHAR documentsBufW[MAX_PATH] = {};
- HRESULT documentsH = SHGetFolderPathW(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, documentsBufW);
- assert(SUCCEEDED(documentsH));
- std::string documentsDir = string::UTF16toUTF8(documentsBufW);
-
- // Rack <2.5.0 used "My Documents/Rack2"
- oldUserDir = system::join(documentsDir, "Rack" + APP_VERSION_MAJOR);
- #endif
-
- #if defined ARCH_MAC
- // Usually ~/Library/Application Support/Rack2
- userDir = system::join(getApplicationSupportDir(), "Rack" + APP_VERSION_MAJOR);
-
- // Get home directory
- struct passwd* pw = getpwuid(getuid());
- assert(pw);
- std::string homeDir = pw->pw_dir;
-
- // Rack <2.5.0 used ~/Documents/Rack2
- oldUserDir = system::join(homeDir, "Documents", "Rack" + APP_VERSION_MAJOR);
- #endif
-
- #if defined ARCH_LIN
- // Get home path
- const char* homeBuf = getenv("HOME");
- if (!homeBuf) {
- struct passwd* pw = getpwuid(getuid());
- assert(pw);
- homeBuf = pw->pw_dir;
- }
- std::string homeDir = homeBuf;
-
- // Get XDG data path
- const char* envData = getenv("XDG_DATA_HOME");
- if (envData) {
- userDir = envData;
- }
- else {
- userDir = system::join(homeDir, ".local", "share");
- }
- // Usually ~/.local/share/Rack2
- userDir = system::join(userDir, "Rack" + APP_VERSION_MAJOR);
-
- // Rack <2.5.0 used ~/.Rack2
- oldUserDir = system::join(homeDir, ".Rack" + APP_VERSION_MAJOR);
- #endif
-
- // If userDir doesn't exist but oldUserDir does, attempt to move it and inform user.
- if (oldUserDir != "" && !system::isDirectory(userDir) && system::isDirectory(oldUserDir)) {
- if (system::rename(oldUserDir, userDir)) {
- std::string msg = APP_NAME + "'s user folder has been moved from";
- msg += "\n" + oldUserDir;
- msg += "\nto";
- msg += "\n" + userDir;
- osdialog_message(OSDIALOG_INFO, OSDIALOG_OK, msg.c_str());
- }
- else {
- std::string msg = "Failed to move " + APP_NAME + "'s user folder from";
- msg += "\n" + oldUserDir;
- msg += "\nto";
- msg += "\n" + userDir;
- msg += "\nConsider moving this folder manually to ensure compatibility with future versions.";
- osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, msg.c_str());
- // Move failed, just use the old dir instead
- userDir = oldUserDir;
- oldUserDir = "";
- }
- }
- else {
- oldUserDir = "";
- }
-
- // Create user dir if it doesn't exist
- system::createDirectory(userDir);
- }
-
-
- void init() {
- initSystemDir();
- initUserDir();
- }
-
-
- std::string system(std::string filename) {
- return system::join(systemDir, filename);
- }
-
-
- std::string user(std::string filename) {
- return system::join(userDir, filename);
- }
-
-
- std::string plugin(plugin::Plugin* plugin, std::string filename) {
- assert(plugin);
- return system::join(plugin->path, filename);
- }
-
-
- std::string systemDir;
- std::string userDir;
- std::string oldUserDir;
-
- std::string bundlePath;
-
-
- } // namespace asset
- } // namespace rack
|