@@ -0,0 +1,24 @@ | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
namespace rack { | |||
namespace system { | |||
std::vector<std::string> listEntries(std::string path); | |||
bool isFile(std::string path); | |||
bool isDirectory(std::string path); | |||
void copyFile(std::string srcPath, std::string destPath); | |||
void createDirectory(std::string path); | |||
/** Opens a URL, also happens to work with PDFs and folders. | |||
Shell injection is possible, so make sure the URL is trusted or hard coded. | |||
May block, so open in a new thread. | |||
*/ | |||
void openBrowser(std::string url); | |||
} // namespace system | |||
} // namespace rack |
@@ -17,6 +17,7 @@ | |||
#include "math.hpp" | |||
#include "string.hpp" | |||
#include "logger.hpp" | |||
#include "system.hpp" | |||
namespace rack { | |||
@@ -81,62 +82,5 @@ float randomNormal(); | |||
DEPRECATED inline float randomf() {return randomUniform();} | |||
//////////////////// | |||
// Operating-system specific utilities | |||
// system.cpp | |||
//////////////////// | |||
std::vector<std::string> systemListEntries(std::string path); | |||
bool systemIsFile(std::string path); | |||
bool systemIsDirectory(std::string path); | |||
void systemCopy(std::string srcPath, std::string destPath); | |||
void systemCreateDirectory(std::string path); | |||
/** Opens a URL, also happens to work with PDFs and folders. | |||
Shell injection is possible, so make sure the URL is trusted or hard coded. | |||
May block, so open in a new thread. | |||
*/ | |||
void systemOpenBrowser(std::string url); | |||
//////////////////// | |||
// Debug logger | |||
// logger.cpp | |||
//////////////////// | |||
//////////////////// | |||
// Thread functions | |||
//////////////////// | |||
/** Threads which obtain a VIPLock will cause wait() to block for other less important threads. | |||
This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread. | |||
*/ | |||
struct VIPMutex { | |||
int count = 0; | |||
std::condition_variable cv; | |||
std::mutex countMutex; | |||
/** Blocks until there are no remaining VIPLocks */ | |||
void wait() { | |||
std::unique_lock<std::mutex> lock(countMutex); | |||
while (count > 0) | |||
cv.wait(lock); | |||
} | |||
}; | |||
struct VIPLock { | |||
VIPMutex &m; | |||
VIPLock(VIPMutex &m) : m(m) { | |||
std::unique_lock<std::mutex> lock(m.countMutex); | |||
m.count++; | |||
} | |||
~VIPLock() { | |||
std::unique_lock<std::mutex> lock(m.countMutex); | |||
m.count--; | |||
lock.unlock(); | |||
m.cv.notify_all(); | |||
} | |||
}; | |||
} // namespace rack |
@@ -227,7 +227,7 @@ void ModuleWidget::save(std::string filename) { | |||
void ModuleWidget::loadDialog() { | |||
std::string dir = asset::local("presets"); | |||
systemCreateDirectory(dir); | |||
system::createDirectory(dir); | |||
osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); | |||
char *path = osdialog_file(OSDIALOG_OPEN, dir.c_str(), NULL, filters); | |||
@@ -240,7 +240,7 @@ void ModuleWidget::loadDialog() { | |||
void ModuleWidget::saveDialog() { | |||
std::string dir = asset::local("presets"); | |||
systemCreateDirectory(dir); | |||
system::createDirectory(dir); | |||
osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); | |||
char *path = osdialog_file(OSDIALOG_SAVE, dir.c_str(), "Untitled.vcvm", filters); | |||
@@ -11,7 +11,7 @@ namespace rack { | |||
struct RegisterButton : Button { | |||
void onAction(EventAction &e) override { | |||
std::thread t([&]() { | |||
systemOpenBrowser("https://vcvrack.com/"); | |||
system::openBrowser("https://vcvrack.com/"); | |||
}); | |||
t.detach(); | |||
} | |||
@@ -39,7 +39,7 @@ struct StatusLabel : Label { | |||
struct ManageButton : Button { | |||
void onAction(EventAction &e) override { | |||
std::thread t([&]() { | |||
systemOpenBrowser("https://vcvrack.com/plugins.html"); | |||
system::openBrowser("https://vcvrack.com/plugins.html"); | |||
}); | |||
t.detach(); | |||
} | |||
@@ -45,7 +45,7 @@ void RackScene::step() { | |||
if (!gLatestVersion.empty()) { | |||
std::string versionMessage = string::stringf("Rack %s is available.\n\nYou have Rack %s.\n\nClose Rack and download new version on the website?", gLatestVersion.c_str(), gApplicationVersion.c_str()); | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) { | |||
std::thread t(systemOpenBrowser, "https://vcvrack.com/"); | |||
std::thread t(system::openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
windowClose(); | |||
} | |||
@@ -72,7 +72,7 @@ void RackWidget::loadDialog() { | |||
std::string dir; | |||
if (lastPath.empty()) { | |||
dir = asset::local("patches"); | |||
systemCreateDirectory(dir); | |||
system::createDirectory(dir); | |||
} | |||
else { | |||
dir = string::directory(lastPath); | |||
@@ -101,7 +101,7 @@ void RackWidget::saveAsDialog() { | |||
std::string filename; | |||
if (lastPath.empty()) { | |||
dir = asset::local("patches"); | |||
systemCreateDirectory(dir); | |||
system::createDirectory(dir); | |||
} | |||
else { | |||
dir = string::directory(lastPath); | |||
@@ -92,8 +92,8 @@ void init(bool devMode) { | |||
} | |||
} | |||
systemCreateDirectory(globalDir); | |||
systemCreateDirectory(localDir); | |||
system::createDirectory(globalDir); | |||
system::createDirectory(localDir); | |||
} | |||
@@ -27,6 +27,38 @@ static float sampleRateRequested = sampleRate; | |||
static Module *resetModule = NULL; | |||
static Module *randomizeModule = NULL; | |||
/** Threads which obtain a VIPLock will cause wait() to block for other less important threads. | |||
This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread. | |||
*/ | |||
struct VIPMutex { | |||
int count = 0; | |||
std::condition_variable cv; | |||
std::mutex countMutex; | |||
/** Blocks until there are no remaining VIPLocks */ | |||
void wait() { | |||
std::unique_lock<std::mutex> lock(countMutex); | |||
while (count > 0) | |||
cv.wait(lock); | |||
} | |||
}; | |||
struct VIPLock { | |||
VIPMutex &m; | |||
VIPLock(VIPMutex &m) : m(m) { | |||
std::unique_lock<std::mutex> lock(m.countMutex); | |||
m.count++; | |||
} | |||
~VIPLock() { | |||
std::unique_lock<std::mutex> lock(m.countMutex); | |||
m.count--; | |||
lock.unlock(); | |||
m.cv.notify_all(); | |||
} | |||
}; | |||
static std::mutex mutex; | |||
static std::thread thread; | |||
static VIPMutex vipMutex; | |||
@@ -69,7 +69,7 @@ static bool loadPlugin(std::string path) { | |||
#endif | |||
// Check file existence | |||
if (!systemIsFile(libraryFilename)) { | |||
if (!system::isFile(libraryFilename)) { | |||
warn("Plugin file %s does not exist", libraryFilename.c_str()); | |||
return false; | |||
} | |||
@@ -212,8 +212,8 @@ static bool syncPlugin(std::string slug, json_t *manifestJ, bool dryRun) { | |||
static void loadPlugins(std::string path) { | |||
std::string message; | |||
for (std::string pluginPath : systemListEntries(path)) { | |||
if (!systemIsDirectory(pluginPath)) | |||
for (std::string pluginPath : system::listEntries(path)) { | |||
if (!system::isDirectory(pluginPath)) | |||
continue; | |||
if (!loadPlugin(pluginPath)) { | |||
message += string::stringf("Could not load plugin %s\n", pluginPath.c_str()); | |||
@@ -297,7 +297,7 @@ static int extractZip(const char *filename, const char *path) { | |||
static void extractPackages(std::string path) { | |||
std::string message; | |||
for (std::string packagePath : systemListEntries(path)) { | |||
for (std::string packagePath : system::listEntries(path)) { | |||
if (string::extension(packagePath) != "zip") | |||
continue; | |||
info("Extracting package %s", packagePath.c_str()); | |||
@@ -339,8 +339,8 @@ void pluginInit(bool devMode) { | |||
std::string fundamentalSrc = asset::global("Fundamental.zip"); | |||
std::string fundamentalDest = asset::local("plugins/Fundamental.zip"); | |||
std::string fundamentalDir = asset::local("plugins/Fundamental"); | |||
if (systemIsFile(fundamentalSrc) && !systemIsFile(fundamentalDest) && !systemIsDirectory(fundamentalDir)) { | |||
systemCopy(fundamentalSrc, fundamentalDest); | |||
if (system::isFile(fundamentalSrc) && !system::isFile(fundamentalDest) && !system::isDirectory(fundamentalDir)) { | |||
system::copyFile(fundamentalSrc, fundamentalDest); | |||
} | |||
} | |||
@@ -1,5 +1,3 @@ | |||
#include "util/common.hpp" | |||
#include <dirent.h> | |||
#include <sys/stat.h> | |||
@@ -8,11 +6,15 @@ | |||
#include <shellapi.h> | |||
#endif | |||
#include "system.hpp" | |||
#include "util/common.hpp" | |||
namespace rack { | |||
namespace system { | |||
std::vector<std::string> systemListEntries(std::string path) { | |||
std::vector<std::string> listEntries(std::string path) { | |||
std::vector<std::string> filenames; | |||
DIR *dir = opendir(path.c_str()); | |||
if (dir) { | |||
@@ -28,34 +30,31 @@ std::vector<std::string> systemListEntries(std::string path) { | |||
return filenames; | |||
} | |||
bool systemExists(std::string path) { | |||
struct stat statbuf; | |||
return (stat(path.c_str(), &statbuf) == 0); | |||
} | |||
bool systemIsFile(std::string path) { | |||
bool isFile(std::string path) { | |||
struct stat statbuf; | |||
if (stat(path.c_str(), &statbuf)) | |||
return false; | |||
return S_ISREG(statbuf.st_mode); | |||
} | |||
bool systemIsDirectory(std::string path) { | |||
bool isDirectory(std::string path) { | |||
struct stat statbuf; | |||
if (stat(path.c_str(), &statbuf)) | |||
return false; | |||
return S_ISDIR(statbuf.st_mode); | |||
} | |||
void systemCopy(std::string srcPath, std::string destPath) { | |||
void copyFile(std::string srcPath, std::string destPath) { | |||
// Open files | |||
FILE *source = fopen(srcPath.c_str(), "rb"); | |||
if (!source) return; | |||
if (!source) | |||
return; | |||
defer({ | |||
fclose(source); | |||
}); | |||
FILE *dest = fopen(destPath.c_str(), "wb"); | |||
if (!dest) return; | |||
if (!dest) | |||
return; | |||
defer({ | |||
fclose(dest); | |||
}); | |||
@@ -72,7 +71,7 @@ void systemCopy(std::string srcPath, std::string destPath) { | |||
} | |||
} | |||
void systemCreateDirectory(std::string path) { | |||
void createDirectory(std::string path) { | |||
#if ARCH_WIN | |||
CreateDirectory(path.c_str(), NULL); | |||
#else | |||
@@ -80,14 +79,14 @@ void systemCreateDirectory(std::string path) { | |||
#endif | |||
} | |||
void systemOpenBrowser(std::string url) { | |||
void openBrowser(std::string url) { | |||
#if ARCH_LIN | |||
std::string command = "xdg-open " + url; | |||
(void) system(command.c_str()); | |||
(void) std::system(command.c_str()); | |||
#endif | |||
#if ARCH_MAC | |||
std::string command = "open " + url; | |||
system(command.c_str()); | |||
std::system(command.c_str()); | |||
#endif | |||
#if ARCH_WIN | |||
ShellExecute(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); | |||
@@ -95,4 +94,5 @@ void systemOpenBrowser(std::string url) { | |||
} | |||
} // namespace system | |||
} // namespace rack |