diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk index 5f9dfd2c..fad70d01 100644 --- a/Makefile.plugins.mk +++ b/Makefile.plugins.mk @@ -238,16 +238,6 @@ endif ifeq ($(UI_TYPE),web) DGL_FLAGS += -DDGL_WEB -DHAVE_DGL -ifeq ($(MACOS),true) -# BUILD_CXX_FLAGS += -std=gnu++17 -DGL_LIBS += -framework WebKit -else ifeq ($(WINDOWS),true) -# DGL_FLAGS += -std=gnu++17 -DGL_LIBS += -lole32 -luuid -else -DGL_FLAGS += -pthread -DGL_LIBS += -pthread -lrt -endif DGL_LIB = $(DGL_BUILD_DIR)/libdgl-web.a HAVE_DGL = true USE_WEBVIEW = true @@ -271,6 +261,19 @@ ifeq ($(HAVE_DGL)$(LINUX)$(USE_WEBVIEW),truetruetrue) DGL_LIB_SHARED = $(shell $(CC) -print-file-name=Scrt1.o) endif +ifeq ($(USE_WEBVIEW),true) +ifeq ($(MACOS),true) +# BUILD_CXX_FLAGS += -std=gnu++17 +DGL_LIBS += -framework WebKit +else ifeq ($(WINDOWS),true) +# DGL_FLAGS += -std=gnu++17 +DGL_LIBS += -lole32 -luuid +else +DGL_FLAGS += -pthread +DGL_LIBS += -pthread -lrt +endif +endif + DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm # TODO split dsp and ui object build flags diff --git a/dgl/Web.hpp b/dgl/Web.hpp index 2a4db1ee..8c2d84b1 100644 --- a/dgl/Web.hpp +++ b/dgl/Web.hpp @@ -43,20 +43,20 @@ public: /** Constructor for a WebViewWidget. */ - explicit WebViewWidget(Window& windowToMapTo, bool initLater = false); + explicit WebViewWidget(Window& windowToMapTo); /** Destructor. */ ~WebViewWidget() override; + void init(const char* url, const char* initialJS); + // webview methods void evaluateJS(const char* js); void reload(); protected: - void init(const char* initialJS); - virtual void onMessage(char* message); void onResize(const ResizeEvent& ev) override; diff --git a/dgl/src/Web.cpp b/dgl/src/Web.cpp index 822990fa..1a04c684 100644 --- a/dgl/src/Web.cpp +++ b/dgl/src/Web.cpp @@ -28,18 +28,10 @@ START_NAMESPACE_DGL // -------------------------------------------------------------------------------------------------------------------- -WebViewWidget::WebViewWidget(Window& windowToMapTo, bool initLater) +WebViewWidget::WebViewWidget(Window& windowToMapTo) : TopLevelWidget(windowToMapTo), - webview(initLater ? nullptr : webViewCreate(windowToMapTo.getNativeWindowHandle(), - windowToMapTo.getWidth(), - windowToMapTo.getHeight(), - windowToMapTo.getScaleFactor(), - WebViewOptions(_on_msg, this))) + webview(nullptr) { - #if !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) - if (webview != nullptr) - addIdleCallback(this, 1000 / 60); - #endif } WebViewWidget::~WebViewWidget() @@ -53,13 +45,13 @@ WebViewWidget::~WebViewWidget() } } -void WebViewWidget::init(const char* const initialJS) +void WebViewWidget::init(const char* const url, const char* const initialJS) { DISTRHO_SAFE_ASSERT_RETURN(webview == nullptr,); WebViewOptions options(_on_msg, this); options.initialJS = initialJS; - webview = webViewCreate(getWindow().getNativeWindowHandle(), getWidth(), getHeight(), getScaleFactor(), options); + webview = webViewCreate(url, getWindow().getNativeWindowHandle(), getWidth(), getHeight(), getScaleFactor(), options); // FIXME implement initialJS if (webview != nullptr) diff --git a/distrho/DistrhoUI_macOS.mm b/distrho/DistrhoUI_macOS.mm index 17bda5f4..18eda348 100644 --- a/distrho/DistrhoUI_macOS.mm +++ b/distrho/DistrhoUI_macOS.mm @@ -44,9 +44,9 @@ END_NAMESPACE_DISTRHO # include "extra/WebViewImpl.cpp" #endif -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -# include -# include +#include +#include + START_NAMESPACE_DISTRHO double getDesktopScaleFactor(const uintptr_t parentWindowHandle) { @@ -61,4 +61,3 @@ double getDesktopScaleFactor(const uintptr_t parentWindowHandle) return [NSScreen mainScreen].backingScaleFactor; } END_NAMESPACE_DISTRHO -#endif diff --git a/distrho/extra/WebViewImpl.cpp b/distrho/extra/WebViewImpl.cpp index c43c7c8e..556fa278 100644 --- a/distrho/extra/WebViewImpl.cpp +++ b/distrho/extra/WebViewImpl.cpp @@ -406,7 +406,8 @@ static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* cons // ----------------------------------------------------------------------------------------------------------- -WebViewHandle webViewCreate(const uintptr_t windowId, +WebViewHandle webViewCreate(const char* const url, + const uintptr_t windowId, const uint initialWidth, const uint initialHeight, const double scaleFactor, @@ -464,11 +465,6 @@ WebViewHandle webViewCreate(const uintptr_t windowId, #elif WEB_VIEW_USING_MACOS_WEBKIT NSView* const view = reinterpret_cast(windowId); - const CGRect rect = CGRectMake(options.offset.x, - options.offset.y, - (initialWidth - options.offset.x), - (initialHeight - options.offset.y)); - WKPreferences* const prefs = [[WKPreferences alloc] init]; [prefs setValue:@YES forKey:@"javaScriptCanAccessClipboard"]; [prefs setValue:@YES forKey:@"DOMPasteAllowed"]; @@ -483,6 +479,11 @@ WebViewHandle webViewCreate(const uintptr_t windowId, config.limitsNavigationsToAppBoundDomains = false; config.preferences = prefs; + const CGRect rect = CGRectMake(options.offset.x / scaleFactor, + options.offset.y / scaleFactor, + initialWidth, + initialHeight); + WKWebView* const webview = [[WKWebView alloc] initWithFrame:rect configuration:config]; [webview setHidden:YES]; @@ -495,31 +496,61 @@ WebViewHandle webViewCreate(const uintptr_t windowId, delegate->callbackPtr = options.callbackPtr; delegate->loaded = false; - webview.navigationDelegate = delegate; - webview.UIDelegate = delegate; - if (WKUserContentController* const controller = [config userContentController]) { [controller retain]; [controller addScriptMessageHandler:delegate name:@"external"]; + + if (options.initialJS != nullptr) + { + NSString* const nsInitialJS = [[NSString alloc] initWithBytes:options.initialJS + length:std::strlen(options.initialJS) + encoding:NSUTF8StringEncoding]; + + WKUserScript* const script = [[WKUserScript alloc] initWithSource:nsInitialJS + injectionTime:WKUserScriptInjectionTimeAtDocumentStart + forMainFrameOnly:true]; + + [controller addUserScript:script]; + + [script release]; + [nsInitialJS release]; + } } - const char* const url = "file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html"; + [webview setNavigationDelegate:delegate]; + [webview setUIDelegate:delegate]; + NSString* const nsurl = [[NSString alloc] initWithBytes:url length:std::strlen(url) encoding:NSUTF8StringEncoding]; NSURLRequest* const urlreq = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: nsurl]]; - // [webview loadRequest:urlreq]; - [webview loadFileRequest:urlreq - allowingReadAccessToURL:[NSURL URLWithString:@"file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/"]]; + d_stdout("url is '%s'", url); + if (std::strncmp(url, "file://", 7) == 0) + { + const char* const lastsep = std::strrchr(url + 7, '/'); + + NSString* const urlpath = [[NSString alloc] initWithBytes:url + length:(lastsep - url) + encoding:NSUTF8StringEncoding]; + + [webview loadFileRequest:urlreq + allowingReadAccessToURL:[NSURL URLWithString:urlpath]]; + + [urlpath release]; + } + else + { + [webview loadRequest:urlreq]; + } d_stdout("waiting for load"); if (! delegate->loaded) { NSAutoreleasePool* const pool = [[NSAutoreleasePool alloc] init]; - NSDate* const date = [NSDate distantFuture]; + NSDate* const date = [NSDate dateWithTimeIntervalSinceNow:0.05]; NSEvent* event; while (! delegate->loaded) @@ -702,7 +733,7 @@ void webViewDestroy(const WebViewHandle handle) [handle->webview setHidden:YES]; [handle->webview removeFromSuperview]; [handle->urlreq release]; - [handle->delegate release]; + // [handle->delegate release]; #elif WEB_VIEW_USING_X11_IPC munmap(handle->shmptr, sizeof(WebViewRingBuffer)); close(handle->shmfd); @@ -804,16 +835,15 @@ void webViewResize(const WebViewHandle handle, const uint width, const uint heig #if WEB_VIEW_USING_CHOC #ifdef DISTRHO_OS_MAC NSView* const view = static_cast(handle->webview->getViewHandle()); - [view setFrameSize:NSMakeSize(width, height)]; + [view setFrameSize:NSMakeSize(width / scaleFactor, height / scaleFactor)]; #else const HWND hwnd = static_cast(handle->webview->getViewHandle()); SetWindowPos(hwnd, nullptr, 0, 0, - width * scaleFactor, - height * scaleFactor, + width, height, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); #endif #elif WEB_VIEW_USING_MACOS_WEBKIT - [handle->webview setFrameSize:NSMakeSize(width, height)]; + [handle->webview setFrameSize:NSMakeSize(width / scaleFactor, height / scaleFactor)]; #elif WEB_VIEW_USING_X11_IPC if (handle->childWindow == 0) { diff --git a/distrho/extra/WebViewImpl.hpp b/distrho/extra/WebViewImpl.hpp index 142c6a8f..c1f25f59 100644 --- a/distrho/extra/WebViewImpl.hpp +++ b/distrho/extra/WebViewImpl.hpp @@ -35,10 +35,10 @@ struct WebViewOptions { Position offset, for cases of mixing regular widgets with web views. */ struct PositionOffset { - /** Horizontal offset */ + /** Horizontal offset, with scale factor pre-applied */ int x; - /** Vertical offset */ + /** Vertical offset, with scale factor pre-applied */ int y; /** Constructor for default values */ @@ -83,10 +83,11 @@ struct WebViewOptions { Provided metrics must not have scale factor pre-applied. @p windowId: The native window id to attach this view to (X11 Window, HWND or NSView*) - @p scaleFactor: Scale factor to use (ignored on macOS) + @p scaleFactor: Scale factor in use @p options: Extra options, optional */ -WebViewHandle webViewCreate(uintptr_t windowId, +WebViewHandle webViewCreate(const char* url, + uintptr_t windowId, uint initialWidth, uint initialHeight, double scaleFactor, diff --git a/distrho/src/DistrhoPluginJACK.cpp b/distrho/src/DistrhoPluginJACK.cpp index 6fda2a62..a50700a2 100644 --- a/distrho/src/DistrhoPluginJACK.cpp +++ b/distrho/src/DistrhoPluginJACK.cpp @@ -980,15 +980,11 @@ int main(int argc, char* argv[]) String tmpPath(getBinaryFilename()); tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); #if defined(DISTRHO_OS_MAC) - if (tmpPath.endsWith("/MacOS")) + if (tmpPath.endsWith("/Contents/MacOS")) { - tmpPath.truncate(tmpPath.rfind('/')); - if (tmpPath.endsWith("/Contents")) - { - tmpPath.truncate(tmpPath.rfind('/')); - bundlePath = tmpPath; - d_nextBundlePath = bundlePath.buffer(); - } + tmpPath.truncate(tmpPath.length() - 15); + bundlePath = tmpPath; + d_nextBundlePath = bundlePath.buffer(); } #else #ifdef DISTRHO_OS_WINDOWS diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index 9edddc40..6b4e4909 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -15,8 +15,8 @@ */ #include "DistrhoDetails.hpp" +#include "DistrhoPluginUtils.hpp" #include "src/DistrhoPluginChecks.h" -#include "src/DistrhoDefines.h" #include @@ -88,7 +88,6 @@ uintptr_t g_nextWindowId = 0; double g_nextScaleFactor = 1.0; #endif -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI /* ------------------------------------------------------------------------------------------------------------ * get global scale factor */ @@ -101,23 +100,23 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) if (const char* const scale = getenv("DPF_SCALE_FACTOR")) return std::max(1.0, std::atof(scale)); -#if defined(DISTRHO_OS_WINDOWS) + #if defined(DISTRHO_OS_WINDOWS) if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) { typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); -# if defined(__GNUC__) && (__GNUC__ >= 9) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-function-type" -# endif + #if defined(__GNUC__) && (__GNUC__ >= 9) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-function-type" + #endif const PFN_GetProcessDpiAwareness GetProcessDpiAwareness = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); -# if defined(__GNUC__) && (__GNUC__ >= 9) -# pragma GCC diagnostic pop -# endif + #if defined(__GNUC__) && (__GNUC__ >= 9) + #pragma GCC diagnostic pop + #endif DWORD dpiAware = 0; DWORD scaleFactor = 100; @@ -133,7 +132,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) FreeLibrary(Shcore); return static_cast(scaleFactor) / 100.0; } -#elif defined(HAVE_X11) + #elif defined(HAVE_X11) ::Display* const display = XOpenDisplay(nullptr); DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0); @@ -164,7 +163,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) XCloseDisplay(display); return dpi / 96; -#endif + #endif return 1.0; @@ -173,8 +172,6 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) } #endif // !DISTRHO_OS_MAC -#endif - /* ------------------------------------------------------------------------------------------------------------ * UI::PrivateData special handling */ @@ -188,7 +185,6 @@ PluginWindow& UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const bool adjustForScaleFactor) { UI::PrivateData* const pData = s_nextPrivateData; - #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI const double scaleFactor = d_isNotZero(pData->scaleFactor) ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) @@ -197,6 +193,7 @@ UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const b height *= scaleFactor; } + #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI pData->window = new PluginWindow(ui, pData->app); ExternalWindow::PrivateData ewData; ewData.parentWindowHandle = pData->winId; @@ -207,14 +204,7 @@ UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const b ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; return ewData; #else - const double scaleFactor = pData->scaleFactor; - - if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) - { - width *= scaleFactor; - height *= scaleFactor; - } - + d_stdout("createNextWindow %u %u %f %d", width, height, scaleFactor, adjustForScaleFactor); pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, scaleFactor); // If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks @@ -246,11 +236,7 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA #else false #endif - ) - #if DISTRHO_UI_WEB_VIEW - , true - #endif - ), + )), uiData(UI::PrivateData::s_nextPrivateData) { #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI @@ -273,7 +259,37 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA #endif #if DISTRHO_UI_WEB_VIEW - init( + String path(uiData->bundlePath); + + if (path.isNotEmpty()) + { + // FIXME get resource path + #ifdef DISTRHO_OS_MAC + path += "/Contents/Resources"; + #endif + } + else + { + path = getBinaryFilename(); + path.truncate(path.rfind(DISTRHO_OS_SEP)); + #ifdef DISTRHO_OS_WINDOWS + // TODO make valid URL + #endif + #ifdef DISTRHO_OS_MAC + if (path.endsWith("/Contents/MacOS")) + { + path.truncate(path.length() - 5); + path += "Resources"; + } + else + #endif + { + path += "/resources"; + } + // TODO encode for HTML URL + } + + init("file://" + path + "/index.html", "editParameter=function(index,started){window.webkit.messageHandlers.external.postMessage('editparam '+index+' '+(started ? 1 : 0))};" "setParameterValue=function(index,value){window.webkit.messageHandlers.external.postMessage('setparam '+index+' '+value)};" #if DISTRHO_PLUGIN_WANT_STATE diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp index cb194b28..f3bc02d0 100644 --- a/distrho/src/DistrhoUIVST3.cpp +++ b/distrho/src/DistrhoUIVST3.cpp @@ -1636,6 +1636,7 @@ v3_plugin_view** dpf_plugin_view_create(v3_host_application** const host, void* const instancePointer, const double sampleRate) { + g_nextBundlePath = d_nextBundlePath; dpf_plugin_view** const viewptr = new dpf_plugin_view*; *viewptr = new dpf_plugin_view(host, instancePointer, sampleRate); return static_cast(static_cast(viewptr)); diff --git a/examples/WebMeters/DistrhoPluginInfo.h b/examples/WebMeters/DistrhoPluginInfo.h index cd6d395e..2c6fe5e2 100644 --- a/examples/WebMeters/DistrhoPluginInfo.h +++ b/examples/WebMeters/DistrhoPluginInfo.h @@ -39,6 +39,5 @@ #define DISTRHO_UI_DEFAULT_WIDTH 100 #define DISTRHO_UI_DEFAULT_HEIGHT 500 -#define kVerticalOffset 0 #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/examples/WebMeters/Makefile b/examples/WebMeters/Makefile index 269476e1..0a93d479 100644 --- a/examples/WebMeters/Makefile +++ b/examples/WebMeters/Makefile @@ -51,6 +51,18 @@ TARGETS += au endif # HAVE_OPENGL -all: $(TARGETS) +ifeq ($(MACOS_APP_BUNDLE),true) +jackfiles += $(TARGET_DIR)/$(NAME).app/Contents/Resources/index.html +else +jackfiles += $(TARGET_DIR)/resources/index.html +endif + +vst3files += $(TARGET_DIR)/$(NAME).vst3/Contents/Resources/index.html + +all: $(TARGETS) $(jackfiles) $(vst3files) + +%/index.html: index.html + -$(SILENT)$(shell mkdir -p "$(shell dirname $(abspath $@))") + install -m 644 $< $(abspath $@) # --------------------------------------------------------------