Browse Source

Continue web-ui, start hooking plugin functions

Signed-off-by: falkTX <falktx@falktx.com>
web-ui
falkTX 1 year ago
parent
commit
248456fe60
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
9 changed files with 194 additions and 71 deletions
  1. +5
    -0
      dgl/Web.hpp
  2. +11
    -3
      dgl/src/Web.cpp
  3. +7
    -0
      distrho/DistrhoUI.hpp
  4. +25
    -15
      distrho/extra/WebViewImpl.cpp
  5. +16
    -1
      distrho/extra/WebViewImpl.hpp
  6. +109
    -16
      distrho/src/DistrhoUI.cpp
  7. +1
    -2
      examples/WebMeters/ExamplePluginWebMeters.cpp
  8. +1
    -32
      examples/WebMeters/ExampleUIWebMeters.cpp
  9. +19
    -2
      examples/WebMeters/index.html

+ 5
- 0
dgl/Web.hpp View File

@@ -21,6 +21,7 @@

// --------------------------------------------------------------------------------------------------------------------

// TODO private data
START_NAMESPACE_DISTRHO

struct WebViewData;
@@ -53,12 +54,16 @@ public:
void reload();

protected:
virtual void onMessage(char* message);
void onResize(const ResizeEvent& ev) override;

private:
const DISTRHO_NAMESPACE::WebViewHandle webview;
void onDisplay() override {}

// TODO inside private data
static void _on_msg(void*, char*);

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewWidget)
};



+ 11
- 3
dgl/src/Web.cpp View File

@@ -33,10 +33,9 @@ WebViewWidget::WebViewWidget(Window& windowToMapTo)
webview(webViewCreate(windowToMapTo.getNativeWindowHandle(),
windowToMapTo.getWidth(),
windowToMapTo.getHeight(),
windowToMapTo.getScaleFactor()))
windowToMapTo.getScaleFactor(),
WebViewOptions(_on_msg, this)))
{
// FIXME wait till process is here?
d_msleep(200);
}

WebViewWidget::~WebViewWidget()
@@ -57,6 +56,15 @@ void WebViewWidget::reload()
webViewReload(webview);
}

void WebViewWidget::_on_msg(void* const arg, char* const message)
{
static_cast<WebViewWidget*>(arg)->onMessage(message);
}

void WebViewWidget::onMessage(char*)
{
}

void WebViewWidget::onResize(const ResizeEvent& ev)
{
TopLevelWidget::onResize(ev);


+ 7
- 0
distrho/DistrhoUI.hpp View File

@@ -371,6 +371,13 @@ protected:
void onResize(const ResizeEvent& ev) override;
#endif

/* --------------------------------------------------------------------------------------------------------
* WebView message handling, internal */

#if DISTRHO_UI_WEB_VIEW
void onMessage(char* message) override;
#endif

// -------------------------------------------------------------------------------------------------------

private:


+ 25
- 15
distrho/extra/WebViewImpl.cpp View File

@@ -82,13 +82,15 @@
#define WEB_VIEW_DELEGATE_CLASS_NAME \
MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE)

// FIXME
static bool loaded = false;

@interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate>
@end

@implementation WEB_VIEW_DELEGATE_CLASS_NAME
@implementation WEB_VIEW_DELEGATE_CLASS_NAME {
@public
WebViewMessageCallback callback;
void* callbackPtr;
bool loaded;
}

- (void)webView:(WKWebView *)webview
didFinishNavigation:(WKNavigation*)navigation
@@ -195,9 +197,13 @@ static bool loaded = false;
didReceiveScriptMessage:(WKScriptMessage*)message
{
NSString* const nsstring = static_cast<NSString*>([message body]);
const char* const string = [nsstring UTF8String];
char* const string = strdup([nsstring UTF8String]);
d_debug("JS call received '%s' %p", string, callback);

if (callback != nullptr)
callback(callbackPtr, string);

d_stdout("JS call received '%s'", string);
std::free(string);
}

@end
@@ -216,6 +222,7 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------------------------------------------

struct WebViewData {
const WebViewMessageCallback callback;
#if WEB_VIEW_USING_CHOC
choc::ui::WebView* const webview;
#elif WEB_VIEW_USING_MACOS_WEBKIT
@@ -358,7 +365,7 @@ WebViewHandle webViewCreate(const uintptr_t windowId,
ShowWindow(hwnd, SW_SHOW);
#endif

return new WebViewData{webview.release()};
return new WebViewData{options.callback, webview.release()};
#elif WEB_VIEW_USING_MACOS_WEBKIT
NSView* const view = reinterpret_cast<NSView*>(windowId);

@@ -389,6 +396,10 @@ WebViewHandle webViewCreate(const uintptr_t windowId,
// TODO webkit_web_view_set_background_color

WEB_VIEW_DELEGATE_CLASS_NAME* const delegate = [[WEB_VIEW_DELEGATE_CLASS_NAME alloc] init];
delegate->callback = options.callback;
delegate->callbackPtr = options.callbackPtr;
delegate->loaded = false;

webview.navigationDelegate = delegate;
webview.UIDelegate = delegate;

@@ -410,13 +421,13 @@ WebViewHandle webViewCreate(const uintptr_t windowId,

d_stdout("waiting for load");

if (! loaded)
if (! delegate->loaded)
{
NSAutoreleasePool* const pool = [[NSAutoreleasePool alloc] init];
NSDate* const date = [NSDate distantPast];
NSDate* const date = [NSDate distantFuture];
NSEvent* event;

while (! loaded)
while (! delegate->loaded)
{
event = [NSApp
#ifdef __MAC_10_12
@@ -437,13 +448,15 @@ WebViewHandle webViewCreate(const uintptr_t windowId,
[pool release];
}

d_stdout("waiting done");

[webview setHidden:NO];

[nsurl release];
[config release];
[prefs release];

return new WebViewData{view, webview, urlreq, delegate};
return new WebViewData{options.callback, view, webview, urlreq, delegate};
#elif WEB_VIEW_USING_X11_IPC
char ldlinux[PATH_MAX] = {};
getFilenameFromFunctionPtr(ldlinux, dlsym(nullptr, "_rtld_global"));
@@ -482,10 +495,7 @@ WebViewHandle webViewCreate(const uintptr_t windowId,
envp[e++] = nullptr;
}

WebViewData* const handle = new WebViewData();
handle->display = display;
handle->childWindow = 0;
handle->ourWindow = windowId;
WebViewData* const handle = new WebViewData{options.callback, {}, display, 0, windowId};

const char* const args[] = { ldlinux, filename, "dpf-ld-linux-webview", nullptr };
handle->p.start(args, envp);


+ 16
- 1
distrho/extra/WebViewImpl.hpp View File

@@ -23,6 +23,7 @@

struct WebViewData;
typedef WebViewData* WebViewHandle;
typedef void (*WebViewMessageCallback)(void* arg, char* msg);

// --------------------------------------------------------------------------------------------------------------------

@@ -44,9 +45,23 @@ struct WebViewOptions {
PositionOffset() : x(0), y(0) {}
} offset;

/**
Message callback triggered from JavaScript code inside the WebView.
*/
WebViewMessageCallback callback;
void* callbackPtr;

/** Constructor for default values */
WebViewOptions()
: offset() {}
: offset(),
callback(nullptr),
callbackPtr(nullptr) {}

/** Constructor providing a callback */
WebViewOptions(const WebViewMessageCallback cb, void* const ptr)
: offset(),
callback(cb),
callbackPtr(ptr) {}
};

// --------------------------------------------------------------------------------------------------------------------


+ 109
- 16
distrho/src/DistrhoUI.cpp View File

@@ -264,6 +264,18 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA
// unused
(void)automaticallyScaleAndSetAsMinimumSize;
#endif

#if DISTRHO_UI_WEB_VIEW
evaluateJS("\
function editParameter(index, started){ window.webkit.messageHandlers.external.postMessage('editparam ' + index + ' ' + (started ? 1 : 0)) }\
function setParameterValue(index, value){ window.webkit.messageHandlers.external.postMessage('setparam ' + index + ' ' + value) }\
");
#if DISTRHO_PLUGIN_WANT_STATE
evaluateJS("\
function setState(key, value){ window.webkit.messageHandlers.external.postMessage('setstate ' + key + ' ' + value) }\
");
#endif
#endif
}

UI::~UI()
@@ -381,37 +393,57 @@ uintptr_t UI::getNextWindowId() noexcept

void UI::parameterChanged(const uint32_t index, const float value)
{
#if DISTRHO_UI_WEB_VIEW
evaluateJS("typeof(parameterChanged) === 'function' && parameterChanged(0, 0);");
#else
#if DISTRHO_UI_WEB_VIEW
char msg[128];
{
const ScopedSafeLocale ssl;
std::snprintf(msg, sizeof(msg) - 1,
"typeof(parameterChanged) === 'function' && parameterChanged(%u,%f)", index, value);
}
evaluateJS(msg);
#else
// unused
(void)index;
(void)value;
#endif
#endif
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void UI::programLoaded(const uint32_t index)
{
#if DISTRHO_UI_WEB_VIEW
evaluateJS("typeof(programLoaded) === 'function' && programLoaded(0);");
#else
#if DISTRHO_UI_WEB_VIEW
char msg[128];
std::snprintf(msg, sizeof(msg) - 1,
"typeof(programLoaded) === 'function' && programLoaded(%u)", index);
evaluateJS(msg);
#else
// unused
(void)index;
#endif
#endif
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
void UI::stateChanged(const char* const key, const char* const value)
{
#if DISTRHO_UI_WEB_VIEW
evaluateJS("typeof(stateChanged) === 'function' && stateChanged('', '');");
#else
#if DISTRHO_UI_WEB_VIEW
const size_t keylen = std::strlen(key);
const size_t valuelen = std::strlen(value);
const size_t msglen = keylen + valuelen + 60;
if (char* const msg = static_cast<char*>(std::malloc(msglen)))
{
// TODO escape \\'
std::snprintf(msg, sizeof(msglen) - 1,
"typeof(stateChanged) === 'function' && stateChanged('%s','%s')", key, value);
msg[msglen - 1] = '\0';
evaluateJS(msg);
std::free(msg);
}
#else
// unused
(void)key;
(void)value;
#endif
#endif
}
#endif

@@ -420,12 +452,18 @@ void UI::stateChanged(const char* const key, const char* const value)

void UI::sampleRateChanged(const double sampleRate)
{
#if DISTRHO_UI_WEB_VIEW
evaluateJS("typeof(sampleRateChanged) === 'function' && sampleRateChanged(0);");
#else
#if DISTRHO_UI_WEB_VIEW
char msg[128];
{
const ScopedSafeLocale ssl;
std::snprintf(msg, sizeof(msg) - 1,
"typeof(sampleRateChanged) === 'function' && sampleRateChanged(%f)", sampleRate);
}
evaluateJS(msg);
#else
// unused
(void)sampleRate;
#endif
#endif
}

/* ------------------------------------------------------------------------------------------------------------
@@ -515,4 +553,59 @@ void UI::requestSizeChange(const uint width, const uint height)

// -----------------------------------------------------------------------------------------------------------

#if DISTRHO_UI_WEB_VIEW
void UI::onMessage(char* const message)
{
if (std::strncmp(message, "setparam ", 9) == 0)
{
char* const strindex = message + 9;
char* const sep = std::strchr(strindex, ' ');
DISTRHO_SAFE_ASSERT_RETURN(sep != nullptr,);
*sep = 0;
char* const strvalue = sep + 1;

const uint32_t index = std::atoi(strindex);
float value;
{
const ScopedSafeLocale ssl;
value = std::atof(strvalue);
}
setParameterValue(index, value);
return;
}

if (std::strncmp(message, "editparam ", 10) == 0)
{
char* const strindex = message + 10;
char* const sep = std::strchr(strindex, ' ');
DISTRHO_SAFE_ASSERT_RETURN(sep != nullptr,);
*sep = 0;
char* const strstarted = sep + 1;

const uint32_t index = std::atoi(strindex);
const bool started = std::atoi(strstarted) != 0;
editParameter(index, started);
return;
}

#if DISTRHO_PLUGIN_WANT_STATE
if (std::strncmp(message, "setstate ", 9) == 0)
{
char* const key = message + 9;
char* const sep = std::strchr(key, ' ');
DISTRHO_SAFE_ASSERT_RETURN(sep != nullptr,);
*sep = 0;
char* const value = sep + 1;

setState(key, value);
return;
}
#endif

d_stderr("UI received unknown message %s", message);
}
#endif

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

+ 1
- 2
examples/WebMeters/ExamplePluginWebMeters.cpp View File

@@ -237,8 +237,7 @@ protected:
{
fOutLeft = tmpLeft;
fOutRight = tmpRight;
// TODO
// fNeedsReset = false;
fNeedsReset = false;
}
else
{


+ 1
- 32
examples/WebMeters/ExampleUIWebMeters.cpp View File

@@ -24,41 +24,10 @@ class ExampleUIMeters : public UI
{
public:
ExampleUIMeters()
: UI(600, 400, true)
: UI(100, 500, true)
{
}

protected:
/* --------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks */

/**
A parameter has changed on the plugin side.
This is called by the host to inform the UI about parameter changes.
*/
void parameterChanged(uint32_t index, float value) override
{
// d_stdout("param changed %u %f", index, value);
char msg[512];
{
const ScopedSafeLocale ssl;
std::snprintf(msg, sizeof(msg) - 1,
"typeof(parameterChanged) === 'function' && parameterChanged(%u, %f)", index, value);
}
evaluateJS(msg);
}

/**
A state has changed on the plugin side.
This is called by the host to inform the UI about state changes.
*/
void stateChanged(const char*, const char*) override
{
// nothing here
}

// -------------------------------------------------------------------------------------------------------

private:
/**
Set our UI class as non-copyable and add a leak detector just in case.


+ 19
- 2
examples/WebMeters/index.html View File

@@ -14,6 +14,20 @@

setTimeout(function() {
document.getElementById('user-agent').textContent = window.navigator.userAgent;
document.getElementById('left-meter').onclick = function() {
console.log("left meter clicked");
fColorValue = fColorValue == 1 ? 0 : 1;
updateColor(fColorValue, true);
setParameterValue(0, fColorValue);
repaint();
}
document.getElementById('right-meter').onclick = function() {
console.log("right meter clicked");
fColorValue = fColorValue == 1 ? 0 : 1;
updateColor(fColorValue, true);
setParameterValue(0, fColorValue);
repaint();
}
}, 1)

function repaint() {
@@ -21,9 +35,12 @@
const rmeter = document.getElementById('right-meter-x');
lmeter.setAttribute('style', 'background:' + fColor + ';top:' + (100 * (1.0 - fOutLeft)) + '%;height:' + (100 * fOutLeft) + '%');
rmeter.setAttribute('style', 'background:' + fColor + ';top:' + (100 * (1.0 - fOutRight)) + '%;height:' + (100 * fOutRight) + '%');
setTimeout(function() {
setState('reset', '');
}, 1)
}
function updateColor(color) {
if (fColorValue === color)
function updateColor(color, forced) {
if (fColorValue === color && !forced)
return;

fColorValue = color;


Loading…
Cancel
Save