| @@ -42,12 +42,12 @@ struct App { | |||
| history::State *history = NULL; | |||
| PatchManager *patch = NULL; | |||
| void init(bool headless); | |||
| void init(); | |||
| ~App(); | |||
| }; | |||
| void appInit(bool headless); | |||
| void appInit(); | |||
| void appDestroy(); | |||
| /** Returns the global App pointer */ | |||
| App *appGet(); | |||
| @@ -18,7 +18,6 @@ struct Scene : widget::OpaqueWidget { | |||
| widget::Widget *moduleBrowser; | |||
| // Version checking | |||
| bool devMode = false; | |||
| bool checkVersion = true; | |||
| bool checkedVersion = false; | |||
| std::string latestVersion; | |||
| @@ -13,7 +13,7 @@ namespace plugin { | |||
| namespace asset { | |||
| void init(bool devMode); | |||
| void init(); | |||
| /** Returns the path of a system resource. Should only read files from this location. */ | |||
| std::string system(std::string filename); | |||
| /** Returns the path of a user resource. Can read and write files to this location. */ | |||
| @@ -27,7 +27,7 @@ enum Level { | |||
| FATAL_LEVEL | |||
| }; | |||
| void init(bool devMode); | |||
| void init(); | |||
| void destroy(); | |||
| /** Do not use this function directly. Use the macros below. | |||
| Thread-safe. | |||
| @@ -9,6 +9,11 @@ namespace rack { | |||
| struct Settings { | |||
| /** Runtime state, not serialized. */ | |||
| bool devMode = false; | |||
| bool headless = false; | |||
| /** Persistent state, serialized to settings.json. */ | |||
| std::string token; | |||
| math::Vec windowSize; | |||
| math::Vec windowPos; | |||
| @@ -31,8 +36,8 @@ struct Settings { | |||
| json_t *toJson(); | |||
| void fromJson(json_t *rootJ); | |||
| void save(std::string filename); | |||
| void load(std::string filename); | |||
| void save(const std::string &path); | |||
| void load(const std::string &path); | |||
| }; | |||
| @@ -5,14 +5,15 @@ | |||
| #include "engine/Engine.hpp" | |||
| #include "app/Scene.hpp" | |||
| #include "history.hpp" | |||
| #include "settings.hpp" | |||
| namespace rack { | |||
| void App::init(bool headless) { | |||
| void App::init() { | |||
| engine = new engine::Engine; | |||
| if (!headless) { | |||
| if (!settings.headless) { | |||
| event = new widget::EventState; | |||
| history = new history::State; | |||
| window = new Window; | |||
| @@ -41,10 +42,10 @@ App::~App() { | |||
| static App *appInstance = NULL; | |||
| void appInit(bool headless) { | |||
| void appInit() { | |||
| assert(!appInstance); | |||
| appInstance = new App; | |||
| appInstance->init(headless); | |||
| appInstance->init(); | |||
| } | |||
| void appDestroy() { | |||
| @@ -47,7 +47,7 @@ void Scene::step() { | |||
| } | |||
| // Request latest version from server | |||
| if (!devMode && checkVersion && !checkedVersion) { | |||
| if (!settings.devMode && checkVersion && !checkedVersion) { | |||
| std::thread t(&Scene::runCheckVersion, this); | |||
| t.detach(); | |||
| checkedVersion = true; | |||
| @@ -1,5 +1,6 @@ | |||
| #include "asset.hpp" | |||
| #include "system.hpp" | |||
| #include "settings.hpp" | |||
| #include "plugin/Plugin.hpp" | |||
| #if defined ARCH_MAC | |||
| @@ -24,10 +25,10 @@ namespace rack { | |||
| namespace asset { | |||
| void init(bool devMode) { | |||
| void init() { | |||
| // Get system dir | |||
| if (systemDir.empty()) { | |||
| if (devMode) { | |||
| if (settings.devMode) { | |||
| systemDir = "."; | |||
| } | |||
| else { | |||
| @@ -57,7 +58,7 @@ void init(bool devMode) { | |||
| // Get user dir | |||
| if (userDir.empty()) { | |||
| if (devMode) { | |||
| if (settings.devMode) { | |||
| userDir = "."; | |||
| } | |||
| else { | |||
| @@ -1,5 +1,6 @@ | |||
| #include "common.hpp" | |||
| #include "asset.hpp" | |||
| #include "settings.hpp" | |||
| #include <chrono> | |||
| #include <mutex> | |||
| @@ -13,9 +14,9 @@ static std::chrono::high_resolution_clock::time_point startTime; | |||
| static std::mutex logMutex; | |||
| void init(bool devMode) { | |||
| void init() { | |||
| startTime = std::chrono::high_resolution_clock::now(); | |||
| if (devMode) { | |||
| if (settings.devMode) { | |||
| outputFile = stderr; | |||
| } | |||
| else { | |||
| @@ -56,8 +56,6 @@ int main(int argc, char *argv[]) { | |||
| (void) instanceMutex; | |||
| #endif | |||
| bool devMode = false; | |||
| bool headless = false; | |||
| std::string patchPath; | |||
| // Parse command line arguments | |||
| @@ -66,10 +64,10 @@ int main(int argc, char *argv[]) { | |||
| while ((c = getopt(argc, argv, "ds:u:")) != -1) { | |||
| switch (c) { | |||
| case 'd': { | |||
| devMode = true; | |||
| settings.devMode = true; | |||
| } break; | |||
| case 'h': { | |||
| headless = true; | |||
| settings.headless = true; | |||
| } break; | |||
| case 's': { | |||
| asset::systemDir = optarg; | |||
| @@ -85,13 +83,13 @@ int main(int argc, char *argv[]) { | |||
| } | |||
| // Initialize environment | |||
| asset::init(devMode); | |||
| logger::init(devMode); | |||
| asset::init(); | |||
| logger::init(); | |||
| // We can now install a signal handler and log the output | |||
| // Mac has its own decent crash handler | |||
| #if 0 | |||
| if (!devMode) { | |||
| if (!settings.devMode) { | |||
| signal(SIGABRT, fatalSignalHandler); | |||
| signal(SIGFPE, fatalSignalHandler); | |||
| signal(SIGILL, fatalSignalHandler); | |||
| @@ -102,7 +100,7 @@ int main(int argc, char *argv[]) { | |||
| // Log environment | |||
| INFO("%s v%s", app::APP_NAME, app::APP_VERSION); | |||
| if (devMode) | |||
| if (settings.devMode) | |||
| INFO("Development mode"); | |||
| INFO("System directory: %s", asset::systemDir.c_str()); | |||
| INFO("User directory: %s", asset::userDir.c_str()); | |||
| @@ -115,7 +113,7 @@ int main(int argc, char *argv[]) { | |||
| keyboard::init(); | |||
| gamepad::init(); | |||
| plugin::init(); | |||
| if (!headless) { | |||
| if (!settings.headless) { | |||
| ui::init(); | |||
| windowInit(); | |||
| } | |||
| @@ -123,22 +121,21 @@ int main(int argc, char *argv[]) { | |||
| // Initialize app | |||
| INFO("Initializing app"); | |||
| settings.load(asset::user("settings.json")); | |||
| appInit(headless); | |||
| appInit(); | |||
| const char *openedFilename = glfwGetOpenedFilename(); | |||
| if (openedFilename) { | |||
| patchPath = openedFilename; | |||
| } | |||
| if (!headless) { | |||
| APP->scene->devMode = devMode; | |||
| if (!settings.headless) { | |||
| APP->patch->init(patchPath); | |||
| } | |||
| INFO("Starting engine"); | |||
| APP->engine->start(); | |||
| if (!headless) { | |||
| if (!settings.headless) { | |||
| INFO("Running window"); | |||
| APP->window->run(); | |||
| INFO("Stopped window"); | |||
| @@ -151,7 +148,7 @@ int main(int argc, char *argv[]) { | |||
| APP->engine->stop(); | |||
| // Destroy app | |||
| if (!headless) { | |||
| if (!settings.headless) { | |||
| APP->patch->save(asset::user("autosave.vcv")); | |||
| } | |||
| INFO("Destroying app"); | |||
| @@ -160,7 +157,7 @@ int main(int argc, char *argv[]) { | |||
| // Destroy environment | |||
| INFO("Destroying environment"); | |||
| if (!headless) { | |||
| if (!settings.headless) { | |||
| windowDestroy(); | |||
| ui::destroy(); | |||
| } | |||
| @@ -356,20 +356,20 @@ void init() { | |||
| plugins.push_back(corePlugin); | |||
| // Get user plugins directory | |||
| std::string userPlugins = asset::user("plugins"); | |||
| mkdir(userPlugins.c_str(), 0755); | |||
| std::string pluginsDir = asset::user("plugins"); | |||
| mkdir(pluginsDir.c_str(), 0755); | |||
| // Copy Fundamental package to plugins directory if folder does not exist | |||
| // Extract packages and load plugins | |||
| extractPackages(pluginsDir); | |||
| loadPlugins(pluginsDir); | |||
| // Copy Fundamental package to plugins directory if Fundamental is not loaded | |||
| std::string fundamentalSrc = asset::system("Fundamental.zip"); | |||
| std::string fundamentalDest = asset::user("plugins/Fundamental.zip"); | |||
| std::string fundamentalDir = asset::user("plugins/Fundamental"); | |||
| if (system::isFile(fundamentalSrc) && !system::isFile(fundamentalDest) && !system::isDirectory(fundamentalDir)) { | |||
| system::copyFile(fundamentalSrc, fundamentalDest); | |||
| if (!settings.devMode && !getPlugin("Fundamental") && system::isFile(fundamentalSrc)) { | |||
| extractZip(fundamentalSrc.c_str(), pluginsDir.c_str()); | |||
| loadPlugin(fundamentalDir); | |||
| } | |||
| // Extract packages and load plugins | |||
| extractPackages(userPlugins); | |||
| loadPlugins(userPlugins); | |||
| } | |||
| void destroy() { | |||
| @@ -172,11 +172,11 @@ void Settings::fromJson(json_t *rootJ) { | |||
| } | |||
| } | |||
| void Settings::save(std::string filename) { | |||
| INFO("Saving settings %s", filename.c_str()); | |||
| void Settings::save(const std::string &path) { | |||
| INFO("Saving settings %s", path.c_str()); | |||
| json_t *rootJ = toJson(); | |||
| if (rootJ) { | |||
| FILE *file = std::fopen(filename.c_str(), "w"); | |||
| FILE *file = std::fopen(path.c_str(), "w"); | |||
| if (!file) | |||
| return; | |||
| @@ -186,9 +186,9 @@ void Settings::save(std::string filename) { | |||
| } | |||
| } | |||
| void Settings::load(std::string filename) { | |||
| INFO("Loading settings %s", filename.c_str()); | |||
| FILE *file = std::fopen(filename.c_str(), "r"); | |||
| void Settings::load(const std::string &path) { | |||
| INFO("Loading settings %s", path.c_str()); | |||
| FILE *file = std::fopen(path.c_str(), "r"); | |||
| if (!file) | |||
| return; | |||