@@ -1,6 +1,6 @@ | |||
RACK_DIR ?= . | |||
# VERSION := 1.dev.$(shell git rev-parse --short HEAD) | |||
VERSION := 1.1.0 | |||
VERSION := 1.dev.$(shell git rev-parse --short HEAD) | |||
# VERSION := 1.1.0 | |||
FLAGS += -DVERSION=$(VERSION) | |||
FLAGS += -Iinclude -Idep/include | |||
@@ -12,15 +12,17 @@ namespace rack { | |||
namespace app { | |||
extern std::string APP_NAME; | |||
extern std::string APP_VERSION; | |||
extern std::string APP_VERSION_UPDATE; | |||
extern std::string API_URL; | |||
extern std::string API_VERSION; | |||
extern std::string ABI_VERSION; | |||
extern const std::string APP_NAME; | |||
extern const std::string APP_VERSION; | |||
extern const std::string APP_ARCH; | |||
static const float SVG_DPI = 75.0; | |||
static const float MM_PER_IN = 25.4; | |||
extern const std::string ABI_VERSION; | |||
extern const std::string API_URL; | |||
extern const std::string API_VERSION; | |||
static const float SVG_DPI = 75.f; | |||
static const float MM_PER_IN = 25.4f; | |||
/** Converts inch measurements to pixels */ | |||
@@ -50,8 +52,5 @@ static const math::Vec RACK_OFFSET = RACK_GRID_SIZE.mult(math::Vec(2000, 100)); | |||
static const math::Vec BUS_BOARD_GRID_SIZE = math::Vec(RACK_GRID_WIDTH * 20, RACK_GRID_HEIGHT); | |||
void init(); | |||
} // namespace app | |||
} // namespace rack |
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include <common.hpp> | |||
namespace rack { | |||
/** Automatically updates the application. | |||
*/ | |||
namespace updater { | |||
extern std::string version; | |||
extern std::string changelogUrl; | |||
extern float progress; | |||
void init(); | |||
bool isUpdateAvailable(); | |||
/** Updates Rack automatically or opens the browser to the URL. | |||
Blocking. Call on a detached thread. | |||
*/ | |||
void update(); | |||
} // namespace updater | |||
} // namespace rack |
@@ -15,6 +15,7 @@ | |||
#include <system.hpp> | |||
#include <plugin.hpp> | |||
#include <patch.hpp> | |||
#include <updater.hpp> | |||
#include <osdialog.h> | |||
#include <thread> | |||
@@ -61,6 +62,16 @@ struct UrlItem : ui::MenuItem { | |||
} | |||
}; | |||
struct FolderItem : ui::MenuItem { | |||
std::string path; | |||
void onAction(const event::Action &e) override { | |||
std::thread t([=] { | |||
system::openFolder(path); | |||
}); | |||
t.detach(); | |||
} | |||
}; | |||
//////////////////// | |||
// File | |||
//////////////////// | |||
@@ -701,15 +712,35 @@ struct LibraryButton : MenuButton { | |||
// Help | |||
//////////////////// | |||
struct UserFolderItem : ui::MenuItem { | |||
struct UpdateItem : ui::MenuItem { | |||
ui::Menu *createChildMenu() override { | |||
ui::Menu *menu = new ui::Menu; | |||
UrlItem *changelogUrl = new UrlItem; | |||
changelogUrl->text = "Changelog"; | |||
changelogUrl->url = updater::changelogUrl; | |||
menu->addChild(changelogUrl); | |||
return menu; | |||
} | |||
void step() override { | |||
if (updater::progress > 0) { | |||
rightText = string::f("%.0f%%", updater::progress * 100.f); | |||
} | |||
MenuItem::step(); | |||
} | |||
void onAction(const event::Action &e) override { | |||
std::thread t([] { | |||
system::openFolder(asset::user("")); | |||
std::thread t([=] { | |||
updater::update(); | |||
}); | |||
t.detach(); | |||
e.consume(NULL); | |||
} | |||
}; | |||
struct HelpButton : MenuButton { | |||
NotificationIcon *notification; | |||
@@ -723,11 +754,10 @@ struct HelpButton : MenuButton { | |||
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | |||
menu->box.size.x = box.size.x; | |||
if (hasUpdate()) { | |||
UrlItem *updateItem = new UrlItem; | |||
if (updater::isUpdateAvailable()) { | |||
UpdateItem *updateItem = new UpdateItem; | |||
updateItem->text = "Update " + APP_NAME; | |||
updateItem->rightText = APP_VERSION + " → " + APP_VERSION_UPDATE; | |||
updateItem->url = "https://vcvrack.com/"; | |||
updateItem->rightText = APP_VERSION + " → " + updater::version; | |||
menu->addChild(updateItem); | |||
} | |||
@@ -742,20 +772,17 @@ struct HelpButton : MenuButton { | |||
websiteItem->url = "https://vcvrack.com/"; | |||
menu->addChild(websiteItem); | |||
UserFolderItem *folderItem = new UserFolderItem; | |||
FolderItem *folderItem = new FolderItem; | |||
folderItem->text = "Open user folder"; | |||
folderItem->path = asset::user(""); | |||
menu->addChild(folderItem); | |||
} | |||
void step() override { | |||
notification->box.pos = math::Vec(0, 0); | |||
notification->visible = hasUpdate(); | |||
notification->visible = updater::isUpdateAvailable(); | |||
MenuButton::step(); | |||
} | |||
bool hasUpdate() { | |||
return !APP_VERSION_UPDATE.empty() && APP_VERSION_UPDATE != APP_VERSION; | |||
} | |||
}; | |||
//////////////////// | |||
@@ -1,45 +1,24 @@ | |||
#include <app/common.hpp> | |||
#include <settings.hpp> | |||
#include <network.hpp> | |||
#include <thread> | |||
namespace rack { | |||
namespace app { | |||
std::string APP_NAME = "VCV Rack"; | |||
std::string APP_VERSION = TOSTRING(VERSION); | |||
std::string APP_VERSION_UPDATE; | |||
std::string API_URL = "https://api.vcvrack.com"; | |||
std::string API_VERSION = "1"; | |||
std::string ABI_VERSION = "1"; | |||
static void checkVersion() { | |||
std::string versionUrl = app::API_URL + "/version"; | |||
json_t *versionResJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); | |||
if (!versionResJ) { | |||
WARN("Request for version failed"); | |||
return; | |||
} | |||
DEFER({ | |||
json_decref(versionResJ); | |||
}); | |||
json_t *versionJ = json_object_get(versionResJ, "version"); | |||
if (versionJ) | |||
APP_VERSION_UPDATE = json_string_value(versionJ); | |||
} | |||
void init() { | |||
if (!settings::devMode) { | |||
std::thread t([] { | |||
checkVersion(); | |||
}); | |||
t.detach(); | |||
} | |||
} | |||
const std::string APP_NAME = "VCV Rack"; | |||
const std::string APP_VERSION = TOSTRING(VERSION); | |||
#if defined ARCH_WIN | |||
const std::string APP_ARCH = "win"; | |||
#elif ARCH_MAC | |||
const std::string APP_ARCH = "mac"; | |||
#elif defined ARCH_LIN | |||
const std::string APP_ARCH = "lin"; | |||
#endif | |||
const std::string ABI_VERSION = "1"; | |||
const std::string API_URL = "https://api.vcvrack.com"; | |||
const std::string API_VERSION = "1"; | |||
} // namespace app | |||
@@ -16,6 +16,7 @@ | |||
#include <ui.hpp> | |||
#include <system.hpp> | |||
#include <string.hpp> | |||
#include <updater.hpp> | |||
#include <osdialog.h> | |||
#include <thread> | |||
@@ -150,7 +151,7 @@ int main(int argc, char *argv[]) { | |||
keyboard::init(); | |||
gamepad::init(); | |||
plugin::init(); | |||
app::init(); | |||
updater::init(); | |||
if (!settings::headless) { | |||
ui::init(); | |||
windowInit(); | |||
@@ -476,21 +476,13 @@ void syncUpdate(Update *update) { | |||
isSyncingUpdate = false; | |||
}); | |||
#if defined ARCH_WIN | |||
std::string arch = "win"; | |||
#elif ARCH_MAC | |||
std::string arch = "mac"; | |||
#elif defined ARCH_LIN | |||
std::string arch = "lin"; | |||
#endif | |||
std::string downloadUrl = app::API_URL + "/download"; | |||
downloadUrl += "?token=" + network::encodeUrl(settings::token); | |||
downloadUrl += "&slug=" + network::encodeUrl(update->pluginSlug); | |||
downloadUrl += "&version=" + network::encodeUrl(update->version); | |||
downloadUrl += "&arch=" + network::encodeUrl(arch); | |||
downloadUrl += "&arch=" + network::encodeUrl(app::APP_ARCH); | |||
INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), arch.c_str()); | |||
INFO("Downloading plugin %s %s %s", update->pluginSlug.c_str(), update->version.c_str(), app::APP_ARCH.c_str()); | |||
// Download zip | |||
std::string pluginDest = asset::pluginsPath + "/" + update->pluginSlug + ".zip"; | |||
@@ -0,0 +1,83 @@ | |||
#include <updater.hpp> | |||
#include <settings.hpp> | |||
#include <app/common.hpp> | |||
#include <network.hpp> | |||
#include <system.hpp> | |||
#include <app.hpp> | |||
#include <window.hpp> | |||
#include <thread> | |||
namespace rack { | |||
namespace updater { | |||
std::string version; | |||
std::string changelogUrl; | |||
float progress = 0.f; | |||
static std::string downloadUrl; | |||
static void checkVersion() { | |||
std::string versionUrl = app::API_URL + "/version"; | |||
json_t *resJ = network::requestJson(network::METHOD_GET, versionUrl, NULL); | |||
if (!resJ) { | |||
WARN("Request for version failed"); | |||
return; | |||
} | |||
DEFER({ | |||
json_decref(resJ); | |||
}); | |||
json_t *versionJ = json_object_get(resJ, "version"); | |||
if (versionJ) | |||
version = json_string_value(versionJ); | |||
json_t *changelogUrlJ = json_object_get(resJ, "changelogUrl"); | |||
if (changelogUrlJ) | |||
changelogUrl = json_string_value(changelogUrlJ); | |||
json_t *downloadUrlsJ = json_object_get(resJ, "downloadUrls"); | |||
if (downloadUrlsJ) { | |||
json_t *downloadUrlJ = json_object_get(downloadUrlsJ, app::APP_ARCH.c_str()); | |||
if (downloadUrlJ) | |||
downloadUrl = json_string_value(downloadUrlJ); | |||
} | |||
} | |||
void init() { | |||
if (!settings::devMode) { | |||
std::thread t([] { | |||
checkVersion(); | |||
}); | |||
t.detach(); | |||
} | |||
} | |||
void update() { | |||
if (downloadUrl == "") | |||
return; | |||
#if defined ARCH_WIN | |||
// Download and launch the installer on Windows | |||
std::string path = asset::user("Rack-setup.exe"); | |||
network::requestDownload(downloadUrl, path, &progress); | |||
system::runProcessDetached(path); | |||
#else | |||
// Open the browser on Mac and Linux. The user will know what to do. | |||
system::openBrowser(downloadUrl); | |||
#endif | |||
APP->window->close(); | |||
} | |||
bool isUpdateAvailable() { | |||
return (version != "") && (version != app::APP_VERSION); | |||
} | |||
} // namespace updater | |||
} // namespace rack |