@@ -17,6 +17,10 @@ ifeq ($(ARCH), mac) | |||
FLAGS += -DARCH_MAC | |||
CXXFLAGS += -stdlib=libc++ | |||
LDFLAGS += -stdlib=libc++ | |||
MAC_SDK_FLAGS = -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk \ | |||
-mmacosx-version-min=10.7 | |||
FLAGS += $(MAC_SDK_FLAGS) | |||
LDFLAGS += $(MAC_SDK_FLAGS) | |||
endif | |||
ifeq ($(ARCH), win) | |||
@@ -1 +1 @@ | |||
Subproject commit 952d72f925ea5e9086067d47a9d31516878fcaac | |||
Subproject commit c36d25ad244f81cf9f6d27df811cd58f434e7d75 |
@@ -314,6 +314,7 @@ struct RackScene : Scene { | |||
extern std::string gApplicationName; | |||
extern std::string gApplicationVersion; | |||
extern std::string gApiHost; | |||
extern RackWidget *gRackWidget; | |||
@@ -8,10 +8,10 @@ namespace rack { | |||
enum RequestMethod { | |||
GET_METHOD, | |||
POST_METHOD, | |||
PUT_METHOD, | |||
DELETE_METHOD, | |||
METHOD_GET, | |||
METHOD_POST, | |||
METHOD_PUT, | |||
METHOD_DELETE, | |||
}; | |||
/** Requests a JSON API URL over HTTP(S), using the data as the query (GET) or the body (POST, etc) */ | |||
@@ -5,6 +5,7 @@ namespace rack { | |||
std::string gApplicationName = "VCV Rack"; | |||
std::string gApplicationVersion = TOSTRING(VERSION); | |||
std::string gApiHost = "http://api.vcvrack.com"; | |||
RackWidget *gRackWidget = NULL; | |||
@@ -1,9 +1,31 @@ | |||
#include "app.hpp" | |||
#include "gui.hpp" | |||
#include "util/request.hpp" | |||
#include "../ext/osdialog/osdialog.h" | |||
#include <thread> | |||
namespace rack { | |||
static std::string versionMessage = ""; | |||
static void checkVersion() { | |||
json_t *resJ = requestJson(METHOD_GET, gApiHost + "/version", NULL); | |||
if (resJ) { | |||
json_t *versionJ = json_object_get(resJ, "version"); | |||
if (versionJ) { | |||
const char *version = json_string_value(versionJ); | |||
if (version && version != gApplicationVersion) { | |||
versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", version, gApplicationVersion.c_str()); | |||
} | |||
} | |||
json_decref(resJ); | |||
} | |||
} | |||
RackScene::RackScene() { | |||
scrollWidget = new ScrollWidget(); | |||
{ | |||
@@ -16,6 +38,12 @@ RackScene::RackScene() { | |||
toolbar = new Toolbar(); | |||
addChild(toolbar); | |||
scrollWidget->box.pos.y = toolbar->box.size.y; | |||
// Check for new version | |||
if (gApplicationVersion != "dev" || true) { | |||
std::thread versionThread(checkVersion); | |||
versionThread.detach(); | |||
} | |||
} | |||
void RackScene::step() { | |||
@@ -23,6 +51,16 @@ void RackScene::step() { | |||
scrollWidget->box.size = box.size.minus(scrollWidget->box.pos); | |||
Scene::step(); | |||
// Version popup message | |||
if (!versionMessage.empty()) { | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) { | |||
std::thread t(openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
guiClose(); | |||
} | |||
versionMessage = ""; | |||
} | |||
} | |||
void RackScene::draw(NVGcontext *vg) { | |||
@@ -3,7 +3,6 @@ | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <thread> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <sys/param.h> // for MAXPATHLEN | |||
@@ -22,9 +21,8 @@ | |||
#include <dirent.h> | |||
#include "plugin.hpp" | |||
#include "gui.hpp" // for guiClose | |||
#include "app.hpp" | |||
#include "util/request.hpp" | |||
#include "../ext/osdialog/osdialog.h" | |||
namespace rack { | |||
@@ -37,7 +35,6 @@ static float downloadProgress = 0.0; | |||
static std::string downloadName; | |||
static std::string loginStatus; | |||
static std::string apiHost = "http://api.vcvrack.com"; | |||
Plugin::~Plugin() { | |||
@@ -200,37 +197,11 @@ static void refreshPurchase(json_t *pluginJ) { | |||
downloadName = ""; | |||
} | |||
static void checkVersion() { | |||
json_t *resJ = requestJson(GET_METHOD, apiHost + "/version", NULL); | |||
if (resJ) { | |||
json_t *versionJ = json_object_get(resJ, "version"); | |||
if (versionJ) { | |||
const char *version = json_string_value(versionJ); | |||
if (version && version != gApplicationVersion) { | |||
char text[1024]; | |||
snprintf(text, sizeof(text), "Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", version, gApplicationVersion.c_str()); | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, text)) { | |||
std::thread t(openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
guiClose(); | |||
} | |||
} | |||
} | |||
json_decref(resJ); | |||
} | |||
} | |||
//////////////////// | |||
// plugin API | |||
//////////////////// | |||
void pluginInit() { | |||
if (gApplicationVersion != "dev") { | |||
std::thread versionThread(checkVersion); | |||
versionThread.detach(); | |||
} | |||
// Load core | |||
// This function is defined in core.cpp | |||
Plugin *corePlugin = init(); | |||
@@ -261,7 +232,7 @@ void pluginLogIn(std::string email, std::string password) { | |||
json_t *reqJ = json_object(); | |||
json_object_set(reqJ, "email", json_string(email.c_str())); | |||
json_object_set(reqJ, "password", json_string(password.c_str())); | |||
json_t *resJ = requestJson(POST_METHOD, apiHost + "/token", reqJ); | |||
json_t *resJ = requestJson(METHOD_POST, gApiHost + "/token", reqJ); | |||
json_decref(reqJ); | |||
if (resJ) { | |||
@@ -296,7 +267,7 @@ void pluginRefresh() { | |||
json_t *reqJ = json_object(); | |||
json_object_set(reqJ, "token", json_string(gToken.c_str())); | |||
json_t *resJ = requestJson(GET_METHOD, apiHost + "/purchases", reqJ); | |||
json_t *resJ = requestJson(METHOD_GET, gApiHost + "/purchases", reqJ); | |||
json_decref(reqJ); | |||
if (resJ) { | |||
@@ -3,6 +3,7 @@ | |||
#include <GL/glew.h> | |||
#include "../ext/nanovg/src/nanovg_gl.h" | |||
#include "../ext/nanovg/src/nanovg_gl_utils.h" | |||
#include "../ext/osdialog/osdialog.h" | |||
namespace rack { | |||
@@ -39,6 +40,7 @@ void FramebufferWidget::step() { | |||
if (dirty) { | |||
internal->box.pos = padding.neg(); | |||
internal->box.size = box.size.plus(padding.mult(2)); | |||
internal->box.size = Vec(ceilf(internal->box.size.x), ceilf(internal->box.size.y)); | |||
Vec fbSize = internal->box.size.mult(gPixelRatio * oversample); | |||
// assert(fbSize.isFinite()); | |||
// Reject zero area size | |||
@@ -48,6 +50,14 @@ void FramebufferWidget::step() { | |||
// Delete old one first to free up GPU memory | |||
internal->setFramebuffer(NULL); | |||
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
if (!fb) { | |||
char buf[1024]; | |||
snprintf(buf, sizeof(buf), "%f %f, %f %f; %f %f; %p\n", internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, fbSize.x, fbSize.y, fb); | |||
if (!osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK_CANCEL, buf)) | |||
exit(0); | |||
} | |||
if (!fb) | |||
return; | |||
internal->setFramebuffer(fb); | |||
@@ -5,7 +5,8 @@ namespace rack { | |||
float MenuEntry::computeMinWidth(NVGcontext *vg) { | |||
return bndLabelWidth(vg, -1, text.c_str()); | |||
// Add 10 more pixels because Retina measurements are sometimes too small | |||
return bndLabelWidth(vg, -1, text.c_str()) + 10.0; | |||
} | |||