diff --git a/compile.mk b/compile.mk index 929d1cbe..24bd89f6 100644 --- a/compile.mk +++ b/compile.mk @@ -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) diff --git a/ext/osdialog b/ext/osdialog index 952d72f9..c36d25ad 160000 --- a/ext/osdialog +++ b/ext/osdialog @@ -1 +1 @@ -Subproject commit 952d72f925ea5e9086067d47a9d31516878fcaac +Subproject commit c36d25ad244f81cf9f6d27df811cd58f434e7d75 diff --git a/include/app.hpp b/include/app.hpp index 8112e136..64e70c9f 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -314,6 +314,7 @@ struct RackScene : Scene { extern std::string gApplicationName; extern std::string gApplicationVersion; +extern std::string gApiHost; extern RackWidget *gRackWidget; diff --git a/include/util/request.hpp b/include/util/request.hpp index e5d42563..2626cdda 100644 --- a/include/util/request.hpp +++ b/include/util/request.hpp @@ -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) */ diff --git a/src/app.cpp b/src/app.cpp index e626205c..2e827d35 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -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; diff --git a/src/app/RackScene.cpp b/src/app/RackScene.cpp index 533dc60a..5717622a 100644 --- a/src/app/RackScene.cpp +++ b/src/app/RackScene.cpp @@ -1,9 +1,31 @@ #include "app.hpp" #include "gui.hpp" +#include "util/request.hpp" +#include "../ext/osdialog/osdialog.h" +#include 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) { diff --git a/src/plugin.cpp b/src/plugin.cpp index fa88655e..e0fbc180 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include // for MAXPATHLEN @@ -22,9 +21,8 @@ #include #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) { diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index b637a6d4..c275d9d2 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -3,6 +3,7 @@ #include #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); diff --git a/src/widgets/MenuEntry.cpp b/src/widgets/MenuEntry.cpp index f2607b51..6df5fd7b 100644 --- a/src/widgets/MenuEntry.cpp +++ b/src/widgets/MenuEntry.cpp @@ -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; }