@@ -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 | |||
@@ -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; | |||
@@ -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) | |||
@@ -44,9 +44,9 @@ END_NAMESPACE_DISTRHO | |||
# include "extra/WebViewImpl.cpp" | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
# include <algorithm> | |||
# include <cmath> | |||
#include <algorithm> | |||
#include <cmath> | |||
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 |
@@ -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<NSView*>(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<NSView*>(handle->webview->getViewHandle()); | |||
[view setFrameSize:NSMakeSize(width, height)]; | |||
[view setFrameSize:NSMakeSize(width / scaleFactor, height / scaleFactor)]; | |||
#else | |||
const HWND hwnd = static_cast<HWND>(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) | |||
{ | |||
@@ -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, | |||
@@ -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 | |||
@@ -15,8 +15,8 @@ | |||
*/ | |||
#include "DistrhoDetails.hpp" | |||
#include "DistrhoPluginUtils.hpp" | |||
#include "src/DistrhoPluginChecks.h" | |||
#include "src/DistrhoDefines.h" | |||
#include <cstddef> | |||
@@ -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<double>(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 | |||
@@ -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<v3_plugin_view**>(static_cast<void*>(viewptr)); | |||
@@ -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 |
@@ -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 $@) | |||
# -------------------------------------------------------------- |