diff --git a/distrho/extra/WebViewImpl.cpp b/distrho/extra/WebViewImpl.cpp index aae84a00..1e8b4536 100644 --- a/distrho/extra/WebViewImpl.cpp +++ b/distrho/extra/WebViewImpl.cpp @@ -307,11 +307,35 @@ static bool webview_timedwait(ipc_sem_t* const sem) #endif } +static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* const ptr) +{ + Dl_info info = {}; + dladdr(ptr, &info); + + if (info.dli_fname[0] == '.') + { + getcwd(filename, PATH_MAX - 1); + std::strncat(filename, info.dli_fname + 1, PATH_MAX - 1); + } + else if (info.dli_fname[0] != '/') + { + getcwd(filename, PATH_MAX - 1); + std::strncat(filename, "/", PATH_MAX - 1); + std::strncat(filename, info.dli_fname, PATH_MAX - 1); + } + else + { + std::strncpy(filename, info.dli_fname, PATH_MAX - 1); + } +} #endif struct WebViewData { #if WEB_VIEW_USING_CHOC - choc::ui::WebView* const webview; + choc::ui::WebView* webview; + WebViewMessageCallback callback; + void* callbackPtr; + std::string url; #elif WEB_VIEW_USING_MACOS_WEBKIT NSView* view; WKWebView* webview; @@ -335,77 +359,6 @@ struct WebViewData { // ----------------------------------------------------------------------------------------------------------- -#if WEB_VIEW_USING_CHOC -static std::optional fetch_resource(const std::string& path) -{ - d_stdout("requested path %s", path.c_str()); - - if (path == "/") - { - const std::string html = R"PREFIX( - - - - - - -hello world! - - -)PREFIX"; - const std::vector data(html.begin(), html.end()); - return choc::ui::WebView::Options::Resource{ data, "text/html" }; - } - if (path == "/img.svg") - { - const std::string html = R"PREFIX( - - - - - - - - -)PREFIX"; - const std::vector data(html.begin(), html.end()); - return choc::ui::WebView::Options::Resource{ data, "image/svg+xml" }; - } - - return {}; -} -#elif WEB_VIEW_USING_X11_IPC -static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* const ptr) -{ - Dl_info info = {}; - dladdr(ptr, &info); - - if (info.dli_fname[0] == '.') - { - getcwd(filename, PATH_MAX - 1); - std::strncat(filename, info.dli_fname + 1, PATH_MAX - 1); - } - else if (info.dli_fname[0] != '/') - { - getcwd(filename, PATH_MAX - 1); - std::strncat(filename, "/", PATH_MAX - 1); - std::strncat(filename, info.dli_fname, PATH_MAX - 1); - } - else - { - std::strncpy(filename, info.dli_fname, PATH_MAX - 1); - } -} -#endif - -// ----------------------------------------------------------------------------------------------------------- - WebViewHandle webViewCreate(const char* const url, const uintptr_t windowId, const uint initialWidth, @@ -417,7 +370,6 @@ WebViewHandle webViewCreate(const char* const url, choc::ui::WebView::Options woptions; woptions.acceptsFirstMouseClick = true; woptions.enableDebugMode = true; - woptions.fetchResource = fetch_resource; std::unique_ptr webview = std::make_unique(woptions); DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr); @@ -425,16 +377,25 @@ WebViewHandle webViewCreate(const char* const url, void* const handle = webview->getViewHandle(); DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); - choc::ui::WebView* const www = webview.get(); - webview->bind("setParameterValue", [www](const choc::value::ValueView&) -> choc::value::Value { - static int pp = 0; - std::string toeval = "typeof(parameterChanged) === 'function' && parameterChanged("; - toeval += std::to_string(++pp); - toeval += ", 0.1)"; - d_stdout("param received | %s", toeval.c_str()); - www->evaluateJavascript(toeval); - return {}; - }); + if (const WebViewMessageCallback callback = options.callback) + { + webview->addInitScript("function postMessage(m) { js2cpp(m); }"); + + void* const callbackPtr = options.callbackPtr; + webview->bind("js2cpp", [callback, callbackPtr](const choc::value::ValueView& args) -> choc::value::Value { + callback(callbackPtr, args[0].toString().data()); + return {}; + }); + } + else + { + webview->addInitScript("function postMessage(m) {}"); + } + + if (options.initialJS != nullptr) + webview->addInitScript(options.initialJS); + + webview->navigate(url); #ifdef DISTRHO_OS_MAC NSView* const view = static_cast(handle); @@ -461,7 +422,12 @@ WebViewHandle webViewCreate(const char* const url, ShowWindow(hwnd, SW_SHOW); #endif - return new WebViewData{options.callback, webview.release()}; + WebViewData* const whandle = new WebViewData; + whandle->webview = webview.release(); + whandle->callback = options.callback; + whandle->callbackPtr = options.callbackPtr; + whandle->url = url; + return whandle; #elif WEB_VIEW_USING_MACOS_WEBKIT NSView* const view = reinterpret_cast(windowId); @@ -498,9 +464,18 @@ WebViewHandle webViewCreate(const char* const url, if (WKUserContentController* const controller = [config userContentController]) { - [controller retain]; [controller addScriptMessageHandler:delegate name:@"external"]; - + + WKUserScript* const mscript = [[WKUserScript alloc] + initWithSource:(options.callback != nullptr + ? @"function postMessage(m){window.webkit.messageHandlers.external.postMessage(m)}" + : @"function postMessage(m){}}") + injectionTime:WKUserScriptInjectionTimeAtDocumentStart + forMainFrameOnly:true + ]; + [controller addUserScript:mscript]; + [mscript release]; + if (options.initialJS != nullptr) { NSString* const nsInitialJS = [[NSString alloc] initWithBytes:options.initialJS @@ -742,6 +717,10 @@ void webViewDestroy(const WebViewHandle handle) [handle->urlreq release]; // [handle->delegate release]; #elif WEB_VIEW_USING_X11_IPC + #ifndef __linux__ + sem_destroy(&handle->shmptr->client.sem); + sem_destroy(&handle->shmptr->server.sem); + #endif munmap(handle->shmptr, sizeof(WebViewRingBuffer)); close(handle->shmfd); shm_unlink(handle->shmname); @@ -800,6 +779,7 @@ void webViewIdle(const WebViewHandle handle) void webViewEvaluateJS(const WebViewHandle handle, const char* const js) { #if WEB_VIEW_USING_CHOC + handle->webview->evaluateJavascript(js); #elif WEB_VIEW_USING_MACOS_WEBKIT NSString* const nsjs = [[NSString alloc] initWithBytes:js length:std::strlen(js) @@ -824,6 +804,7 @@ void webViewEvaluateJS(const WebViewHandle handle, const char* const js) void webViewReload(const WebViewHandle handle) { #if WEB_VIEW_USING_CHOC + handle->webview->navigate(handle->url); #elif WEB_VIEW_USING_MACOS_WEBKIT [handle->webview loadRequest:handle->urlreq]; #elif WEB_VIEW_USING_X11_IPC @@ -1144,14 +1125,18 @@ static bool gtk3(Display* const display, if (WebKitUserContentManager* const manager = webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview))) { + g_signal_connect_data(manager, "script-message-received::external", G_CALLBACK(gtk3_js_cb), shmptr, nullptr, 0); + webkit_user_content_manager_register_script_message_handler(manager, "external"); + + WebKitUserScript* const mscript = webkit_user_script_new( + "function postMessage(m){window.webkit.messageHandlers.external.postMessage(m)}", 0, 0, nullptr, nullptr); + webkit_user_content_manager_add_script(manager, mscript); + if (initialJS != nullptr) { WebKitUserScript* const script = webkit_user_script_new(initialJS, 0, 0, nullptr, nullptr); webkit_user_content_manager_add_script(manager, script); } - - g_signal_connect_data(manager, "script-message-received::external", G_CALLBACK(gtk3_js_cb), shmptr, nullptr, 0); - webkit_user_content_manager_register_script_message_handler(manager, "external"); } webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url); diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index d20a481e..86c09fd6 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -290,14 +290,14 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA } 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)};" +"editParameter = function(index, started){ postMessage('editparam '+index+' '+(started ? 1 : 0)) };" +"setParameterValue = function(index, value){ postMessage('setparam '+index+' '+value) };" #if DISTRHO_PLUGIN_WANT_STATE -"setState=function(key,value){window.webkit.messageHandlers.external.postMessage('setstate '+key+' '+value)};" -"requestStateFile=function(key){window.webkit.messageHandlers.external.postMessage('reqstatefile '+key)};" +"setState = function(key, value){ postMessage('setstate '+key+' '+value) };" +"requestStateFile = function(key){ postMessage('reqstatefile '+key) };" #endif #if DISTRHO_PLUGIN_WANT_MIDI_INPUT -"sendNote=function(channel,note,velocity){window.webkit.messageHandlers.external.postMessage('sendnote '+channel+' '+note+' '+velocity)};" +"sendNote = function(channel, note, velocity){ postMessage('sendnote '+channel+' '+note+' '+velocity) };" #endif ); #endif @@ -652,7 +652,7 @@ void UI::onMessage(char* const message) } #endif - d_stderr("UI received unknown message %s", message); + d_stderr("UI received unknown message '%s'", message); } #endif