Skip to content

Commit

Permalink
add some mac webui details, cpp->js fully working
Browse files Browse the repository at this point in the history
Signed-off-by: falkTX <falktx@falktx.com>
  • Loading branch information
falkTX committed May 8, 2024
1 parent dd41a63 commit ef613e3
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 26 deletions.
90 changes: 80 additions & 10 deletions distrho/extra/WebViewImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,21 @@
#define WEB_VIEW_DELEGATE_CLASS_NAME \
MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE)

@interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKUIDelegate>
// FIXME
static bool loaded = false;

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

@implementation WEB_VIEW_DELEGATE_CLASS_NAME

- (void)webView:(WKWebView *)webview
didFinishNavigation:(WKNavigation*)navigation
{
d_stdout("page loaded");
loaded = true;
}

- (void)webView:(WKWebView*)webview
runJavaScriptAlertPanelWithMessage:(NSString*)message
initiatedByFrame:(WKFrameInfo*)frame
Expand Down Expand Up @@ -181,6 +191,15 @@
});
}

- (void)userContentController:(WKUserContentController*)userContentController
didReceiveScriptMessage:(WKScriptMessage*)message
{
NSString* const nsstring = static_cast<NSString*>([message body]);
const char* const string = [nsstring UTF8String];

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

@end

#endif // WEB_VIEW_USING_MACOS_WEBKIT
Expand Down Expand Up @@ -349,25 +368,75 @@ WebViewHandle webViewCreate(const uintptr_t windowId,
(initialHeight - options.offset.y));

WKPreferences* const prefs = [[WKPreferences alloc] init];
[prefs setValue:@YES forKey:@"developerExtrasEnabled"];
[prefs setValue:@YES forKey:@"javaScriptCanAccessClipboard"];
[prefs setValue:@YES forKey:@"DOMPasteAllowed"];

// if (debug)
{
[prefs setValue:@YES forKey:@"developerExtrasEnabled"];
// TODO enable_write_console_messages_to_stdout
}

WKWebViewConfiguration* const config = [[WKWebViewConfiguration alloc] init];
config.limitsNavigationsToAppBoundDomains = false;
config.preferences = prefs;

WKWebView* const webview = [[WKWebView alloc] initWithFrame:rect
configuration:config];
[webview setHidden:YES];
[view addSubview:webview];

// TODO webkit_web_view_set_background_color

WEB_VIEW_DELEGATE_CLASS_NAME* const delegate = [[WEB_VIEW_DELEGATE_CLASS_NAME alloc] init];
webview.navigationDelegate = delegate;
webview.UIDelegate = delegate;

const char* const url = "https://mastodon.falktx.com/";
if (WKUserContentController* const controller = [config userContentController])
{
[controller retain];
[controller addScriptMessageHandler:delegate name:@"external"];
}

const char* const url = "file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html";
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 loadRequest:urlreq];
[webview loadFileRequest:urlreq
allowingReadAccessToURL:[NSURL URLWithString:@"file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/"]];

d_stdout("waiting for load");

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

while (! loaded)
{
event = [NSApp
#ifdef __MAC_10_12
nextEventMatchingMask:NSEventMaskAny
#else
nextEventMatchingMask:NSAnyEventMask
#endif
untilDate:date
inMode:NSDefaultRunLoopMode
dequeue:YES];

if (event == nil)
break;

[NSApp sendEvent: event];
}

[pool release];
}

[webview setHidden:NO];

[nsurl release];
Expand Down Expand Up @@ -441,26 +510,26 @@ void webViewDestroy(const WebViewHandle handle)
{
#if WEB_VIEW_USING_CHOC
delete handle->webview;
delete handle;
#elif WEB_VIEW_USING_MACOS_WEBKIT
[handle->webview setHidden:YES];
[handle->webview removeFromSuperview];
[handle->urlreq release];
[handle->delegate release];
delete handle;
#elif WEB_VIEW_USING_X11_IPC
XCloseDisplay(handle->display);
delete handle;
#endif

// maybe unused
(void)handle;
delete handle;
}

void webViewEvaluateJS(const WebViewHandle handle, const char* const js)
{
#if WEB_VIEW_USING_CHOC
#elif WEB_VIEW_USING_MACOS_WEBKIT
NSString* const nsjs = [[NSString alloc] initWithBytes:js
length:std::strlen(js)
encoding:NSUTF8StringEncoding];
[handle->webview evaluateJavaScript:nsjs completionHandler:nullptr];
[nsjs release];
#elif WEB_VIEW_USING_X11_IPC
handle->p.signal(SIGUSR2);
#endif
Expand Down Expand Up @@ -705,6 +774,7 @@ static bool gtk3(Display* const display,
WebKitSettings* const settings = webkit_settings_new();
DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);

// TODO DOMPasteAllowed
webkit_settings_set_javascript_can_access_clipboard(settings, true);
webkit_settings_set_hardware_acceleration_policy(settings, 2 /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */);

Expand Down
4 changes: 3 additions & 1 deletion distrho/extra/WebViewImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ struct WebViewOptions {
This means it will draw on top of whatever is below it,
something to take into consideration if mixing regular widgets with web views.
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 (only used on X11)
@p scaleFactor: Scale factor to use (ignored on macOS)
@p options: Extra options, optional
*/
WebViewHandle webViewCreate(uintptr_t windowId,
Expand Down
4 changes: 2 additions & 2 deletions examples/Meters/ExampleUIMeters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ class ExampleUIMeters : public UI
static const Color kColorYellow(255, 255, 0);

// get meter values
const float outLeft(fOutLeft);
const float outRight(fOutRight);
const float outLeft = fOutLeft;
const float outRight = fOutRight;

// tell DSP side to reset meter values
setState("reset", "");
Expand Down
3 changes: 2 additions & 1 deletion examples/WebMeters/ExamplePluginWebMeters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ class ExamplePluginMeters : public Plugin
{
fOutLeft = tmpLeft;
fOutRight = tmpRight;
fNeedsReset = false;
// TODO
// fNeedsReset = false;
}
else
{
Expand Down
15 changes: 10 additions & 5 deletions examples/WebMeters/ExampleUIWebMeters.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
Expand All @@ -24,9 +24,8 @@ class ExampleUIMeters : public UI
{
public:
ExampleUIMeters()
: UI(600, 400)
: UI(600, 400, true)
{
setGeometryConstraints(600, 400, false);
}

protected:
Expand All @@ -39,8 +38,14 @@ class ExampleUIMeters : public UI
*/
void parameterChanged(uint32_t index, float value) override
{
d_stdout("param changed %u %f", index, value);
evaluateJS("if (typeof(parameterChanged) === 'function') { parameterChanged(0, 0); }");
// 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);
}

/**
Expand Down
121 changes: 114 additions & 7 deletions examples/WebMeters/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,129 @@
<meta charset="utf-8">
<title></title>
<script>
const METER_COLOR_GREEN = 0;
const METER_COLOR_BLUE = 1;
const kSmoothMultiplier = 3.0;
let fColorValue = null;
let fColor = 'rgb(93, 231, 61)';
let fOutLeft = 0.0;
let fOutRight = 0.0;

setTimeout(function() {
document.getElementById('user-agent').textContent = window.navigator.userAgent;
}, 1)

function repaint() {
const lmeter = document.getElementById('left-meter-x');
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) + '%');
}
function updateColor(color) {
if (fColorValue === color)
return;

fColorValue = color;

switch (color) {
case METER_COLOR_GREEN:
fColor = "rgb(93, 231, 61)";
break;
case METER_COLOR_BLUE:
fColor = "rgb(82, 238, 248)";
break;
}

repaint();
}
function parameterChanged(index, value) {
console.log("parameterChanged", index, value);
switch (index) {
case 0: // color
updateColor(parseInt(Math.round(value)));
break;
case 1: // out-left
value = (fOutLeft * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0);

/**/ if (value < 0.001) value = 0.0;
else if (value > 0.999) value = 1.0;

if (fOutLeft != value)
{
fOutLeft = value;
repaint();
}
break;
case 2: // out-right
value = (fOutRight * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0);

/**/ if (value < 0.001) value = 0.0;
else if (value > 0.999) value = 1.0;

if (fOutRight != value)
{
fOutRight = value;
repaint();
}
break;
}
}
</script>
<style>
html, body {
background: transparent;
background: grey;
color: white;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
}
p {
margin: 6px;
font-size: 15px;
overflow: hidden;
text-overflow: ellipsis;
width: calc(100% - 12px);
height: 15px;
white-space: nowrap;
}
#meters {
display: flex;
flex-direction: row;
}
.meter {
background: black;
margin: 6px;
margin-top: 0px;
width: calc(50vw - 9px);
height: calc(100vh - 12px - 6px - 15px);
}
.meter:first-child {
margin-right: 3px;
}
.meter:last-child {
margin-left: 3px;
}
.meter-x {
background: rgb(93, 231, 61);
position: relative;
top: 0%;
left: 0;
width: 100%;
height: 0%;
}
</style>
</head>
<body>
<header>Hello World!</header>
<main>
<p>This is my text, nice neato.</p>
</main>
<footer></footer>
<p id="user-agent">&nbsp;</p>
<div id="meters">
<div class="meter" id="left-meter">
<div class="meter-x" id="left-meter-x"></div>
</div>
<div class="meter" id="right-meter">
<div class="meter-x" id="right-meter-x"></div>
</div>
</div>
</body>
</html>

0 comments on commit ef613e3

Please sign in to comment.