DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1122 lines
41KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED)
  17. # error bad include
  18. #endif
  19. #if !defined(WEB_VIEW_DISTRHO_NAMESPACE) && !defined(WEB_VIEW_DGL_NAMESPACE)
  20. # error bad usage
  21. #endif
  22. // #include <gtk/gtk.h>
  23. // #include <gtk/gtkx.h>
  24. // #include <webkit2/webkit2.h>
  25. #define WEB_VIEW_USING_CHOC 0
  26. #ifndef WEB_VIEW_USING_CHOC
  27. # define WEB_VIEW_USING_CHOC 0
  28. #elif WEB_VIEW_USING_CHOC && !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS))
  29. # undef WEB_VIEW_USING_CHOC
  30. # define WEB_VIEW_USING_CHOC 0
  31. #endif
  32. #if defined(DISTRHO_OS_MAC) && !WEB_VIEW_USING_CHOC
  33. # undef WEB_VIEW_USING_MACOS_WEBKIT
  34. # define WEB_VIEW_USING_MACOS_WEBKIT 1
  35. #else
  36. # undef WEB_VIEW_USING_MACOS_WEBKIT
  37. # define WEB_VIEW_USING_MACOS_WEBKIT 0
  38. #endif
  39. #if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX)
  40. # undef WEB_VIEW_USING_X11_IPC
  41. # define WEB_VIEW_USING_X11_IPC 1
  42. #else
  43. # undef WEB_VIEW_USING_X11_IPC
  44. # define WEB_VIEW_USING_X11_IPC 0
  45. #endif
  46. #if WEB_VIEW_USING_CHOC
  47. # define WC_ERR_INVALID_CHARS 0
  48. # include "../CHOC/gui/choc_WebView.h"
  49. #elif WEB_VIEW_USING_MACOS_WEBKIT
  50. # include <Cocoa/Cocoa.h>
  51. # include <WebKit/WebKit.h>
  52. #elif WEB_VIEW_USING_X11_IPC
  53. // #define QT_NO_VERSION_TAGGING
  54. // #include <QtCore/QChar>
  55. // #include <QtCore/QPoint>
  56. // #include <QtCore/QSize>
  57. // #undef signals
  58. # include "ChildProcess.hpp"
  59. # include "String.hpp"
  60. # include <clocale>
  61. # include <cstdio>
  62. # include <dlfcn.h>
  63. # include <functional>
  64. # include <linux/limits.h>
  65. # include <X11/Xlib.h>
  66. #endif
  67. // -----------------------------------------------------------------------------------------------------------
  68. #if WEB_VIEW_USING_MACOS_WEBKIT
  69. #define MACRO_NAME2(a, b, c) a ## b ## c
  70. #define MACRO_NAME(a, b, c) MACRO_NAME2(a, b, c)
  71. #define WEB_VIEW_DELEGATE_CLASS_NAME \
  72. MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE)
  73. // FIXME
  74. static bool loaded = false;
  75. @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate>
  76. @end
  77. @implementation WEB_VIEW_DELEGATE_CLASS_NAME
  78. - (void)webView:(WKWebView *)webview
  79. didFinishNavigation:(WKNavigation*)navigation
  80. {
  81. d_stdout("page loaded");
  82. loaded = true;
  83. }
  84. - (void)webView:(WKWebView*)webview
  85. runJavaScriptAlertPanelWithMessage:(NSString*)message
  86. initiatedByFrame:(WKFrameInfo*)frame
  87. completionHandler:(void (^)(void))completionHandler
  88. {
  89. NSAlert* const alert = [[NSAlert alloc] init];
  90. [alert addButtonWithTitle:@"OK"];
  91. [alert setInformativeText:message];
  92. [alert setMessageText:@"Alert"];
  93. dispatch_async(dispatch_get_main_queue(), ^
  94. {
  95. [alert beginSheetModalForWindow:[webview window]
  96. completionHandler:^(NSModalResponse)
  97. {
  98. completionHandler();
  99. [alert release];
  100. }];
  101. });
  102. }
  103. - (void)webView:(WKWebView*)webview
  104. runJavaScriptConfirmPanelWithMessage:(NSString*)message
  105. initiatedByFrame:(WKFrameInfo*)frame
  106. completionHandler:(void (^)(BOOL))completionHandler
  107. {
  108. NSAlert* const alert = [[NSAlert alloc] init];
  109. [alert addButtonWithTitle:@"OK"];
  110. [alert addButtonWithTitle:@"Cancel"];
  111. [alert setInformativeText:message];
  112. [alert setMessageText:@"Confirm"];
  113. dispatch_async(dispatch_get_main_queue(), ^
  114. {
  115. [alert beginSheetModalForWindow:[webview window]
  116. completionHandler:^(NSModalResponse result)
  117. {
  118. completionHandler(result == NSAlertFirstButtonReturn);
  119. [alert release];
  120. }];
  121. });
  122. }
  123. - (void)webView:(WKWebView*)webview
  124. runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
  125. defaultText:(NSString*)defaultText
  126. initiatedByFrame:(WKFrameInfo*)frame
  127. completionHandler:(void (^)(NSString*))completionHandler
  128. {
  129. NSTextField* const input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 30)];
  130. [input setStringValue:defaultText];
  131. NSAlert* const alert = [[NSAlert alloc] init];
  132. [alert setAccessoryView:input];
  133. [alert addButtonWithTitle:@"OK"];
  134. [alert addButtonWithTitle:@"Cancel"];
  135. [alert setInformativeText:prompt];
  136. [alert setMessageText: @"Prompt"];
  137. dispatch_async(dispatch_get_main_queue(), ^
  138. {
  139. [alert beginSheetModalForWindow:[webview window]
  140. completionHandler:^(NSModalResponse result)
  141. {
  142. [input validateEditing];
  143. completionHandler(result == NSAlertFirstButtonReturn ? [input stringValue] : nil);
  144. [alert release];
  145. }];
  146. });
  147. }
  148. - (void)webView:(WKWebView*)webview
  149. runOpenPanelWithParameters:(WKOpenPanelParameters*)params
  150. initiatedByFrame:(WKFrameInfo*)frame
  151. completionHandler:(void (^)(NSArray<NSURL*>*))completionHandler
  152. {
  153. NSOpenPanel* const panel = [[NSOpenPanel alloc] init];
  154. [panel setAllowsMultipleSelection:[params allowsMultipleSelection]];
  155. // [panel setAllowedFileTypes:(NSArray<NSString*>*)[params _allowedFileExtensions]];
  156. [panel setCanChooseDirectories:[params allowsDirectories]];
  157. [panel setCanChooseFiles:![params allowsDirectories]];
  158. dispatch_async(dispatch_get_main_queue(), ^
  159. {
  160. [panel beginSheetModalForWindow:[webview window]
  161. completionHandler:^(NSModalResponse result)
  162. {
  163. completionHandler(result == NSModalResponseOK ? [panel URLs] : nil);
  164. [panel release];
  165. }];
  166. });
  167. }
  168. - (void)userContentController:(WKUserContentController*)userContentController
  169. didReceiveScriptMessage:(WKScriptMessage*)message
  170. {
  171. NSString* const nsstring = static_cast<NSString*>([message body]);
  172. const char* const string = [nsstring UTF8String];
  173. d_stdout("JS call received '%s'", string);
  174. }
  175. @end
  176. #endif // WEB_VIEW_USING_MACOS_WEBKIT
  177. // -----------------------------------------------------------------------------------------------------------
  178. #ifdef WEB_VIEW_DGL_NAMESPACE
  179. START_NAMESPACE_DGL
  180. using DISTRHO_NAMESPACE::String;
  181. #else
  182. START_NAMESPACE_DISTRHO
  183. #endif
  184. // -----------------------------------------------------------------------------------------------------------
  185. struct WebViewData {
  186. #if WEB_VIEW_USING_CHOC
  187. choc::ui::WebView* const webview;
  188. #elif WEB_VIEW_USING_MACOS_WEBKIT
  189. NSView* const view;
  190. WKWebView* const webview;
  191. NSURLRequest* const urlreq;
  192. WEB_VIEW_DELEGATE_CLASS_NAME* const delegate;
  193. #elif WEB_VIEW_USING_X11_IPC
  194. ChildProcess p;
  195. ::Display* display;
  196. ::Window childWindow;
  197. ::Window ourWindow;
  198. #endif
  199. };
  200. // -----------------------------------------------------------------------------------------------------------
  201. #if WEB_VIEW_USING_CHOC
  202. static std::optional<choc::ui::WebView::Options::Resource> fetch_resource(const std::string& path)
  203. {
  204. d_stdout("requested path %s", path.c_str());
  205. if (path == "/")
  206. {
  207. const std::string html = R"PREFIX(
  208. <html>
  209. <head>
  210. <style>
  211. html, body { background: black; background-image: url(img.svg); }
  212. </style>
  213. <script>
  214. function parameterChanged(index, value) {
  215. console.log("parameterChanged received", index, value);
  216. }
  217. </script>
  218. </head>
  219. <body>
  220. hello world!
  221. </body>
  222. </html>
  223. )PREFIX";
  224. const std::vector<uint8_t> data(html.begin(), html.end());
  225. return choc::ui::WebView::Options::Resource{ data, "text/html" };
  226. }
  227. if (path == "/img.svg")
  228. {
  229. const std::string html = R"PREFIX(<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  230. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  231. <!-- based on https://github.com/n0jo/rackwindows/blob/master/res/components/rw_knob_large_dark.svg -->
  232. <svg width="47px" height="47px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;">
  233. <g id="knobLDark">
  234. <path id="path3832" d="M23.521,45.109c-7.674,0 -3.302,3.9 -10.224,0.498c-6.922,-3.403 -1.202,-2.341 -5.997,-8.501c-4.795,-6.159 -5.059,-0.201 -6.763,-7.827c-1.704,-7.625 1.043,-2.42 2.76,-10.046c1.718,-7.626 -2.998,-4.102 1.797,-10.221c4.795,-6.12 2.51,-0.673 9.432,-4.035c6.921,-3.363 1.321,-4.977 8.995,-4.977c7.675,0 2.087,1.574 8.996,4.977c6.909,3.402 4.636,-2.045 9.432,4.035c4.795,6.078 0.079,2.689 1.796,10.26c1.717,7.572 4.465,2.422 2.761,10.048c-1.704,7.625 -1.982,1.708 -6.763,7.827c-4.782,6.119 0.924,5.057 -5.998,8.46c-6.921,3.402 -2.549,-0.498 -10.224,-0.498Z" style="fill:#ccc;fill-rule:nonzero;"/>
  235. </g>
  236. </svg>
  237. )PREFIX";
  238. const std::vector<uint8_t> data(html.begin(), html.end());
  239. return choc::ui::WebView::Options::Resource{ data, "image/svg+xml" };
  240. }
  241. return {};
  242. }
  243. #elif WEB_VIEW_USING_X11_IPC
  244. static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* const ptr)
  245. {
  246. Dl_info info = {};
  247. dladdr(ptr, &info);
  248. if (info.dli_fname[0] == '.')
  249. {
  250. getcwd(filename, PATH_MAX - 1);
  251. std::strncat(filename, info.dli_fname + 1, PATH_MAX - 1);
  252. }
  253. else if (info.dli_fname[0] != '/')
  254. {
  255. getcwd(filename, PATH_MAX - 1);
  256. std::strncat(filename, "/", PATH_MAX - 1);
  257. std::strncat(filename, info.dli_fname, PATH_MAX - 1);
  258. }
  259. else
  260. {
  261. std::strncpy(filename, info.dli_fname, PATH_MAX - 1);
  262. }
  263. }
  264. #endif
  265. // -----------------------------------------------------------------------------------------------------------
  266. WebViewHandle webViewCreate(const uintptr_t windowId,
  267. const uint initialWidth,
  268. const uint initialHeight,
  269. const double scaleFactor,
  270. const WebViewOptions& options)
  271. {
  272. #if WEB_VIEW_USING_CHOC
  273. choc::ui::WebView::Options woptions;
  274. woptions.acceptsFirstMouseClick = true;
  275. woptions.enableDebugMode = true;
  276. woptions.fetchResource = fetch_resource;
  277. std::unique_ptr<choc::ui::WebView> webview = std::make_unique<choc::ui::WebView>(woptions);
  278. DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr);
  279. void* const handle = webview->getViewHandle();
  280. DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  281. choc::ui::WebView* const www = webview.get();
  282. webview->bind("setParameterValue", [www](const choc::value::ValueView&) -> choc::value::Value {
  283. static int pp = 0;
  284. std::string toeval = "typeof(parameterChanged) === 'function' && parameterChanged(";
  285. toeval += std::to_string(++pp);
  286. toeval += ", 0.1)";
  287. d_stdout("param received | %s", toeval.c_str());
  288. www->evaluateJavascript(toeval);
  289. return {};
  290. });
  291. #ifdef DISTRHO_OS_MAC
  292. NSView* const view = static_cast<NSView*>(handle);
  293. [reinterpret_cast<NSView*>(windowId) addSubview:view];
  294. [view setFrame:NSMakeRect(options.offset.x,
  295. options.offset.y,
  296. DISTRHO_UI_DEFAULT_WIDTH - options.offset.x,
  297. DISTRHO_UI_DEFAULT_HEIGHT - options.offset.y)];
  298. #else
  299. const HWND hwnd = static_cast<HWND>(handle);
  300. LONG_PTR flags = GetWindowLongPtr(hwnd, -16);
  301. flags = (flags & ~WS_POPUP) | WS_CHILD;
  302. SetWindowLongPtr(hwnd, -16, flags);
  303. SetParent(hwnd, reinterpret_cast<HWND>(windowId));
  304. SetWindowPos(hwnd, nullptr,
  305. options.offset.x * scaleFactor,
  306. options.offset.y * scaleFactor,
  307. (initialWidth - options.offset.x) * scaleFactor,
  308. (initialHeight - options.offset.y) * scaleFactor,
  309. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  310. ShowWindow(hwnd, SW_SHOW);
  311. #endif
  312. return new WebViewData{webview.release()};
  313. #elif WEB_VIEW_USING_MACOS_WEBKIT
  314. NSView* const view = reinterpret_cast<NSView*>(windowId);
  315. const CGRect rect = CGRectMake(options.offset.x,
  316. options.offset.y,
  317. (initialWidth - options.offset.x),
  318. (initialHeight - options.offset.y));
  319. WKPreferences* const prefs = [[WKPreferences alloc] init];
  320. [prefs setValue:@YES forKey:@"javaScriptCanAccessClipboard"];
  321. [prefs setValue:@YES forKey:@"DOMPasteAllowed"];
  322. // if (debug)
  323. {
  324. [prefs setValue:@YES forKey:@"developerExtrasEnabled"];
  325. // TODO enable_write_console_messages_to_stdout
  326. }
  327. WKWebViewConfiguration* const config = [[WKWebViewConfiguration alloc] init];
  328. config.limitsNavigationsToAppBoundDomains = false;
  329. config.preferences = prefs;
  330. WKWebView* const webview = [[WKWebView alloc] initWithFrame:rect
  331. configuration:config];
  332. [webview setHidden:YES];
  333. [view addSubview:webview];
  334. // TODO webkit_web_view_set_background_color
  335. WEB_VIEW_DELEGATE_CLASS_NAME* const delegate = [[WEB_VIEW_DELEGATE_CLASS_NAME alloc] init];
  336. webview.navigationDelegate = delegate;
  337. webview.UIDelegate = delegate;
  338. if (WKUserContentController* const controller = [config userContentController])
  339. {
  340. [controller retain];
  341. [controller addScriptMessageHandler:delegate name:@"external"];
  342. }
  343. const char* const url = "file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html";
  344. NSString* const nsurl = [[NSString alloc] initWithBytes:url
  345. length:std::strlen(url)
  346. encoding:NSUTF8StringEncoding];
  347. NSURLRequest* const urlreq = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: nsurl]];
  348. // [webview loadRequest:urlreq];
  349. [webview loadFileRequest:urlreq
  350. allowingReadAccessToURL:[NSURL URLWithString:@"file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/"]];
  351. d_stdout("waiting for load");
  352. if (! loaded)
  353. {
  354. NSAutoreleasePool* const pool = [[NSAutoreleasePool alloc] init];
  355. NSDate* const date = [NSDate distantPast];
  356. NSEvent* event;
  357. while (! loaded)
  358. {
  359. event = [NSApp
  360. #ifdef __MAC_10_12
  361. nextEventMatchingMask:NSEventMaskAny
  362. #else
  363. nextEventMatchingMask:NSAnyEventMask
  364. #endif
  365. untilDate:date
  366. inMode:NSDefaultRunLoopMode
  367. dequeue:YES];
  368. if (event == nil)
  369. break;
  370. [NSApp sendEvent: event];
  371. }
  372. [pool release];
  373. }
  374. [webview setHidden:NO];
  375. [nsurl release];
  376. [config release];
  377. [prefs release];
  378. return new WebViewData{view, webview, urlreq, delegate};
  379. #elif WEB_VIEW_USING_X11_IPC
  380. char ldlinux[PATH_MAX] = {};
  381. getFilenameFromFunctionPtr(ldlinux, dlsym(nullptr, "_rtld_global"));
  382. char filename[PATH_MAX] = {};
  383. getFilenameFromFunctionPtr(filename, reinterpret_cast<const void*>(webViewCreate));
  384. d_stdout("ld-linux is '%s'", ldlinux);
  385. d_stdout("filename is '%s'", filename);
  386. ::Display* const display = XOpenDisplay(nullptr);
  387. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr);
  388. // set up custom child environment
  389. uint envsize = 0;
  390. while (environ[envsize] != nullptr)
  391. ++envsize;
  392. char** const envp = new char*[envsize + 5];
  393. {
  394. uint e = 0;
  395. for (uint i = 0; i < envsize; ++i)
  396. {
  397. if (std::strncmp(environ[i], "LD_PRELOAD=", 11) == 0)
  398. continue;
  399. if (std::strncmp(environ[i], "LD_LIBRARY_PATH=", 16) == 0)
  400. continue;
  401. envp[e++] = strdup(environ[i]);
  402. }
  403. envp[e++] = strdup("LANG=en_US.UTF-8");
  404. envp[e++] = ("DPF_WEB_VIEW_SCALE_FACTOR=" + String(scaleFactor)).getAndReleaseBuffer();
  405. envp[e++] = ("DPF_WEB_VIEW_WIN_ID=" +String(windowId)).getAndReleaseBuffer();
  406. for (uint i = e; i < envsize + 5; ++i)
  407. envp[e++] = nullptr;
  408. }
  409. WebViewData* const handle = new WebViewData();
  410. handle->display = display;
  411. handle->childWindow = 0;
  412. handle->ourWindow = windowId;
  413. const char* const args[] = { ldlinux, filename, "dpf-ld-linux-webview", nullptr };
  414. handle->p.start(args, envp);
  415. for (uint i = 0; envp[i] != nullptr; ++i)
  416. std::free(envp[i]);
  417. delete[] envp;
  418. return handle;
  419. #endif
  420. // maybe unused
  421. (void)windowId;
  422. (void)initialWidth;
  423. (void)initialHeight;
  424. (void)scaleFactor;
  425. (void)options;
  426. return nullptr;
  427. }
  428. void webViewDestroy(const WebViewHandle handle)
  429. {
  430. #if WEB_VIEW_USING_CHOC
  431. delete handle->webview;
  432. #elif WEB_VIEW_USING_MACOS_WEBKIT
  433. [handle->webview setHidden:YES];
  434. [handle->webview removeFromSuperview];
  435. [handle->urlreq release];
  436. [handle->delegate release];
  437. #elif WEB_VIEW_USING_X11_IPC
  438. XCloseDisplay(handle->display);
  439. #endif
  440. delete handle;
  441. }
  442. void webViewEvaluateJS(const WebViewHandle handle, const char* const js)
  443. {
  444. #if WEB_VIEW_USING_CHOC
  445. #elif WEB_VIEW_USING_MACOS_WEBKIT
  446. NSString* const nsjs = [[NSString alloc] initWithBytes:js
  447. length:std::strlen(js)
  448. encoding:NSUTF8StringEncoding];
  449. [handle->webview evaluateJavaScript:nsjs completionHandler:nullptr];
  450. [nsjs release];
  451. #elif WEB_VIEW_USING_X11_IPC
  452. handle->p.signal(SIGUSR2);
  453. #endif
  454. // maybe unused
  455. (void)handle;
  456. (void)js;
  457. }
  458. void webViewReload(const WebViewHandle handle)
  459. {
  460. #if WEB_VIEW_USING_CHOC
  461. #elif WEB_VIEW_USING_MACOS_WEBKIT
  462. [handle->webview loadRequest:handle->urlreq];
  463. #elif WEB_VIEW_USING_X11_IPC
  464. handle->p.signal(SIGUSR1);
  465. #endif
  466. // maybe unused
  467. (void)handle;
  468. }
  469. void webViewResize(const WebViewHandle handle, const uint width, const uint height, const double scaleFactor)
  470. {
  471. #if WEB_VIEW_USING_CHOC
  472. #ifdef DISTRHO_OS_MAC
  473. NSView* const view = static_cast<NSView*>(handle->webview->getViewHandle());
  474. [view setFrameSize:NSMakeSize(width, height)];
  475. #else
  476. const HWND hwnd = static_cast<HWND>(handle->webview->getViewHandle());
  477. SetWindowPos(hwnd, nullptr, 0, 0,
  478. width * scaleFactor,
  479. height * scaleFactor,
  480. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  481. #endif
  482. #elif WEB_VIEW_USING_MACOS_WEBKIT
  483. [handle->webview setFrameSize:NSMakeSize(width, height)];
  484. #elif WEB_VIEW_USING_X11_IPC
  485. if (handle->childWindow == 0)
  486. {
  487. ::Window rootWindow, parentWindow;
  488. ::Window* childWindows = nullptr;
  489. uint numChildren = 0;
  490. XFlush(handle->display);
  491. XQueryTree(handle->display, handle->ourWindow, &rootWindow, &parentWindow, &childWindows, &numChildren);
  492. if (numChildren == 0 || childWindows == nullptr)
  493. return;
  494. handle->childWindow = childWindows[0];
  495. XFree(childWindows);
  496. }
  497. XResizeWindow(handle->display, handle->childWindow, width, height);
  498. XFlush(handle->display);
  499. #endif
  500. // maybe unused
  501. (void)handle;
  502. (void)width;
  503. (void)height;
  504. (void)scaleFactor;
  505. }
  506. #if WEB_VIEW_USING_X11_IPC
  507. // -----------------------------------------------------------------------------------------------------------
  508. static std::function<void(const char* js)> evaluateFn;
  509. static std::function<void()> reloadFn;
  510. static std::function<void()> terminateFn;
  511. // -----------------------------------------------------------------------------------------------------------
  512. struct GtkContainer;
  513. struct GtkPlug;
  514. struct GtkWidget;
  515. struct GtkWindow;
  516. struct JSCValue;
  517. struct WebKitJavascriptResult;
  518. struct WebKitSettings;
  519. struct WebKitUserContentManager;
  520. struct WebKitWebView;
  521. typedef int gboolean;
  522. #define G_CALLBACK(p) reinterpret_cast<void*>(p)
  523. #define GTK_CONTAINER(p) reinterpret_cast<GtkContainer*>(p)
  524. #define GTK_PLUG(p) reinterpret_cast<GtkPlug*>(p)
  525. #define GTK_WINDOW(p) reinterpret_cast<GtkWindow*>(p)
  526. #define WEBKIT_WEB_VIEW(p) reinterpret_cast<WebKitWebView*>(p)
  527. // struct QApplication;
  528. // struct QUrl;
  529. // struct QWebEngineView;
  530. // struct QWindow;
  531. // -----------------------------------------------------------------------------------------------------------
  532. #define JOIN(A, B) A ## B
  533. #define AUTOSYM(S) \
  534. using JOIN(gtk3_, S) = decltype(&S); \
  535. JOIN(gtk3_, S) S = reinterpret_cast<JOIN(gtk3_, S)>(dlsym(nullptr, #S)); \
  536. DISTRHO_SAFE_ASSERT_RETURN(S != nullptr, false);
  537. #define CSYM(S, NAME) \
  538. S NAME = reinterpret_cast<S>(dlsym(nullptr, #NAME)); \
  539. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  540. #define CPPSYM(S, NAME, SN) \
  541. S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \
  542. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  543. // -----------------------------------------------------------------------------------------------------------
  544. // gtk3 variant
  545. static int gtk_js_cb(WebKitUserContentManager*, WebKitJavascriptResult* const result, void* const arg)
  546. {
  547. void* const lib = static_cast<void*>(arg);
  548. DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, false);
  549. using g_free_t = void (*)(void*);
  550. using jsc_value_to_string_t = char* (*)(JSCValue*);
  551. using webkit_javascript_result_get_js_value_t = JSCValue* (*)(WebKitJavascriptResult*);
  552. CSYM(g_free_t, g_free)
  553. CSYM(jsc_value_to_string_t, jsc_value_to_string)
  554. CSYM(webkit_javascript_result_get_js_value_t, webkit_javascript_result_get_js_value)
  555. JSCValue* const value = webkit_javascript_result_get_js_value(result);
  556. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, false);
  557. char* const string = jsc_value_to_string(value);
  558. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr, false);
  559. d_stdout("js call received with data '%s'", string);
  560. g_free(string);
  561. return 0;
  562. }
  563. static bool gtk3(Display* const display,
  564. const Window winId,
  565. const uint x,
  566. const uint y,
  567. const uint width,
  568. const uint height,
  569. double scaleFactor,
  570. const char* const url)
  571. {
  572. void* lib;
  573. if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  574. (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  575. return false;
  576. using g_signal_connect_data_t = ulong (*)(void*, const char*, void*, void*, void*, int);
  577. using gdk_set_allowed_backends_t = void (*)(const char*);
  578. using gtk_container_add_t = void (*)(GtkContainer*, GtkWidget*);
  579. using gtk_init_check_t = gboolean (*)(int*, char***);
  580. using gtk_main_t = void (*)();
  581. using gtk_main_quit_t = void (*)();
  582. using gtk_plug_get_id_t = Window (*)(GtkPlug*);
  583. using gtk_plug_new_t = GtkWidget* (*)(Window);
  584. using gtk_widget_show_all_t = void (*)(GtkWidget*);
  585. using gtk_window_move_t = void (*)(GtkWindow*, int, int);
  586. using gtk_window_set_default_size_t = void (*)(GtkWindow*, int, int);
  587. using webkit_settings_new_t = WebKitSettings* (*)();
  588. using webkit_settings_set_enable_developer_extras_t = void (*)(WebKitSettings*, gboolean);
  589. using webkit_settings_set_enable_write_console_messages_to_stdout_t = void (*)(WebKitSettings*, gboolean);
  590. using webkit_settings_set_hardware_acceleration_policy_t = void (*)(WebKitSettings*, int);
  591. using webkit_settings_set_javascript_can_access_clipboard_t = void (*)(WebKitSettings*, gboolean);
  592. using webkit_user_content_manager_register_script_message_handler_t = gboolean (*)(WebKitUserContentManager*, const char*);
  593. using webkit_web_view_evaluate_javascript_t = void* (*)(WebKitWebView*, const char*, ssize_t, const char*, const char*, void*, void*, void*);
  594. using webkit_web_view_get_user_content_manager_t = WebKitUserContentManager* (*)(WebKitWebView*);
  595. using webkit_web_view_load_uri_t = void (*)(WebKitWebView*, const char*);
  596. using webkit_web_view_new_with_settings_t = GtkWidget* (*)(WebKitSettings*);
  597. using webkit_web_view_run_javascript_t = void* (*)(WebKitWebView*, const char*, void*, void*, void*);
  598. using webkit_web_view_set_background_color_t = void (*)(WebKitWebView*, const double*);
  599. CSYM(g_signal_connect_data_t, g_signal_connect_data)
  600. CSYM(gdk_set_allowed_backends_t, gdk_set_allowed_backends)
  601. CSYM(gtk_container_add_t, gtk_container_add)
  602. CSYM(gtk_init_check_t, gtk_init_check)
  603. CSYM(gtk_main_t, gtk_main)
  604. CSYM(gtk_main_quit_t, gtk_main_quit)
  605. CSYM(gtk_plug_get_id_t, gtk_plug_get_id)
  606. CSYM(gtk_plug_new_t, gtk_plug_new)
  607. CSYM(gtk_widget_show_all_t, gtk_widget_show_all)
  608. CSYM(gtk_window_move_t, gtk_window_move)
  609. CSYM(gtk_window_set_default_size_t, gtk_window_set_default_size)
  610. CSYM(webkit_settings_new_t, webkit_settings_new)
  611. CSYM(webkit_settings_set_enable_developer_extras_t, webkit_settings_set_enable_developer_extras)
  612. CSYM(webkit_settings_set_enable_write_console_messages_to_stdout_t, webkit_settings_set_enable_write_console_messages_to_stdout)
  613. CSYM(webkit_settings_set_hardware_acceleration_policy_t, webkit_settings_set_hardware_acceleration_policy)
  614. CSYM(webkit_settings_set_javascript_can_access_clipboard_t, webkit_settings_set_javascript_can_access_clipboard)
  615. CSYM(webkit_user_content_manager_register_script_message_handler_t, webkit_user_content_manager_register_script_message_handler)
  616. CSYM(webkit_web_view_get_user_content_manager_t, webkit_web_view_get_user_content_manager)
  617. CSYM(webkit_web_view_load_uri_t, webkit_web_view_load_uri)
  618. CSYM(webkit_web_view_new_with_settings_t, webkit_web_view_new_with_settings)
  619. CSYM(webkit_web_view_set_background_color_t, webkit_web_view_set_background_color)
  620. // special case for legacy API handling
  621. webkit_web_view_evaluate_javascript_t webkit_web_view_evaluate_javascript = reinterpret_cast<webkit_web_view_evaluate_javascript_t>(dlsym(nullptr, "webkit_web_view_evaluate_javascript"));
  622. webkit_web_view_run_javascript_t webkit_web_view_run_javascript = reinterpret_cast<webkit_web_view_run_javascript_t>(dlsym(nullptr, "webkit_web_view_run_javascript"));
  623. DISTRHO_SAFE_ASSERT_RETURN(webkit_web_view_evaluate_javascript != nullptr || webkit_web_view_run_javascript != nullptr, false);
  624. const int gdkScale = std::fmod(scaleFactor, 1.0) >= 0.75
  625. ? static_cast<int>(scaleFactor + 0.5)
  626. : static_cast<int>(scaleFactor);
  627. if (gdkScale != 1)
  628. {
  629. char scale[8] = {};
  630. std::snprintf(scale, 7, "%d", gdkScale);
  631. setenv("GDK_SCALE", scale, 1);
  632. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.2);
  633. setenv("GDK_DPI_SCALE", scale, 1);
  634. }
  635. else if (scaleFactor > 1.0)
  636. {
  637. char scale[8] = {};
  638. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.4);
  639. setenv("GDK_DPI_SCALE", scale, 1);
  640. }
  641. scaleFactor /= gdkScale;
  642. gdk_set_allowed_backends("x11");
  643. if (! gtk_init_check (nullptr, nullptr))
  644. return false;
  645. GtkWidget* const window = gtk_plug_new(winId);
  646. DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false);
  647. gtk_window_set_default_size(GTK_WINDOW(window),
  648. (width - x) * scaleFactor,
  649. (height - y) * scaleFactor);
  650. gtk_window_move(GTK_WINDOW(window), x * scaleFactor, y * scaleFactor);
  651. WebKitSettings* const settings = webkit_settings_new();
  652. DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);
  653. // TODO DOMPasteAllowed
  654. webkit_settings_set_javascript_can_access_clipboard(settings, true);
  655. webkit_settings_set_hardware_acceleration_policy(settings, 2 /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */);
  656. // if (debug)
  657. {
  658. webkit_settings_set_enable_developer_extras(settings, true);
  659. webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
  660. }
  661. GtkWidget* const webview = webkit_web_view_new_with_settings(settings);
  662. DISTRHO_SAFE_ASSERT_RETURN(webview != nullptr, false);
  663. const double color[] = {49.0/255, 54.0/255, 59.0/255, 1};
  664. webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(webview), color);
  665. if (WebKitUserContentManager* const manager = webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview)))
  666. {
  667. g_signal_connect_data(manager, "script-message-received::external", G_CALLBACK(gtk_js_cb), lib, nullptr, 0);
  668. webkit_user_content_manager_register_script_message_handler(manager, "external");
  669. }
  670. webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url);
  671. gtk_container_add(GTK_CONTAINER(window), webview);
  672. gtk_widget_show_all(window);
  673. Window wid = gtk_plug_get_id(GTK_PLUG(window));
  674. XMapWindow(display, wid);
  675. XFlush(display);
  676. evaluateFn = [=](const char* const js){
  677. if (webkit_web_view_evaluate_javascript != nullptr)
  678. webkit_web_view_evaluate_javascript(WEBKIT_WEB_VIEW(webview), js, -1,
  679. nullptr, nullptr, nullptr, nullptr, nullptr);
  680. else
  681. webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(webview), js, nullptr, nullptr, nullptr);
  682. };
  683. reloadFn = [=](){
  684. webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url);
  685. };
  686. terminateFn = [=](){
  687. d_stdout("terminateFn");
  688. static bool quit = true;
  689. if (quit)
  690. {
  691. quit = false;
  692. gtk_main_quit();
  693. }
  694. };
  695. gtk_main();
  696. d_stdout("quit");
  697. dlclose(lib);
  698. return true;
  699. }
  700. #if 0
  701. // -----------------------------------------------------------------------------------------------------------
  702. // qt5webengine variant
  703. static bool qt5webengine(const Window winId, const double scaleFactor, const char* const url)
  704. {
  705. void* lib;
  706. if ((lib = dlopen("libQt5WebEngineWidgets.so.5", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  707. (lib = dlopen("libQt5WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  708. return false;
  709. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  710. using QApplication_exec_t = void (*)();
  711. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  712. using QString__init_t = void (*)(void*, const QChar*, ptrdiff_t);
  713. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  714. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  715. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  716. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  717. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  718. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  719. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  720. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  721. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  722. using QWindow_setParent_t = void (*)(QWindow*, void*);
  723. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  724. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  725. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  726. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QChari)
  727. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  728. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  729. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  730. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  731. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  732. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  733. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  734. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  735. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  736. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  737. unsetenv("QT_FONT_DPI");
  738. unsetenv("QT_SCREEN_SCALE_FACTORS");
  739. unsetenv("QT_USE_PHYSICAL_DPI");
  740. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  741. char scale[8] = {};
  742. std::snprintf(scale, 7, "%.2f", scaleFactor);
  743. setenv("QT_SCALE_FACTOR", scale, 1);
  744. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  745. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  746. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  747. static int argc = 0;
  748. static char* argv[] = { nullptr };
  749. uint8_t _app[64]; // sizeof(QApplication) == 16
  750. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  751. QApplication__init(app, argc, argv, 0);
  752. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  753. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  754. {
  755. const size_t url_len = std::strlen(url);
  756. QChar* const url_qchar = new QChar[url_len + 1];
  757. for (size_t i = 0; i < url_len; ++i)
  758. url_qchar[i] = QChar(url[i]);
  759. url_qchar[url_len] = 0;
  760. QString__init(qstrurl, url_qchar, url_len);
  761. }
  762. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  763. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  764. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  765. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  766. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  767. QWebEngineView__init(webview, nullptr);
  768. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  769. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  770. QWebEngineView_winId(webview);
  771. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  772. QWebEngineView_setUrl(webview, *qurl);
  773. QWebEngineView_show(webview);
  774. reloadFn = [=](){
  775. QWebEngineView_setUrl(webview, *qurl);
  776. };
  777. terminateFn = [=](){
  778. // TODO
  779. };
  780. QApplication_exec();
  781. dlclose(lib);
  782. return true;
  783. }
  784. // -----------------------------------------------------------------------------------------------------------
  785. // qt6webengine variant (same as qt5 but `QString__init_t` has different arguments)
  786. static bool qt6webengine(const Window winId, const double scaleFactor, const char* const url)
  787. {
  788. void* lib;
  789. if ((lib = dlopen("libQt6WebEngineWidgets.so.6", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  790. (lib = dlopen("libQt6WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  791. return false;
  792. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  793. using QApplication_exec_t = void (*)();
  794. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  795. using QString__init_t = void (*)(void*, const QChar*, long long);
  796. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  797. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  798. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  799. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  800. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  801. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  802. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  803. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  804. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  805. using QWindow_setParent_t = void (*)(QWindow*, void*);
  806. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  807. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  808. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  809. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QCharx)
  810. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  811. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  812. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  813. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  814. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  815. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  816. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  817. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  818. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  819. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  820. unsetenv("QT_FONT_DPI");
  821. unsetenv("QT_SCREEN_SCALE_FACTORS");
  822. unsetenv("QT_USE_PHYSICAL_DPI");
  823. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  824. char scale[8] = {};
  825. std::snprintf(scale, 7, "%.2f", scaleFactor);
  826. setenv("QT_SCALE_FACTOR", scale, 1);
  827. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  828. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  829. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  830. static int argc = 0;
  831. static char* argv[] = { nullptr };
  832. uint8_t _app[64]; // sizeof(QApplication) == 16
  833. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  834. QApplication__init(app, argc, argv, 0);
  835. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  836. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  837. {
  838. const size_t url_len = std::strlen(url);
  839. QChar* const url_qchar = new QChar[url_len + 1];
  840. for (size_t i = 0; i < url_len; ++i)
  841. url_qchar[i] = QChar(url[i]);
  842. url_qchar[url_len] = 0;
  843. QString__init(qstrurl, url_qchar, url_len);
  844. }
  845. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  846. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  847. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  848. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  849. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  850. QWebEngineView__init(webview, nullptr);
  851. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  852. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  853. QWebEngineView_winId(webview);
  854. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  855. QWebEngineView_setUrl(webview, *qurl);
  856. QWebEngineView_show(webview);
  857. reloadFn = [=](){
  858. QWebEngineView_setUrl(webview, *qurl);
  859. };
  860. terminateFn = [=](){
  861. // TODO
  862. };
  863. QApplication_exec();
  864. dlclose(lib);
  865. return true;
  866. }
  867. #endif
  868. // -----------------------------------------------------------------------------------------------------------
  869. // startup via ld-linux
  870. static void signalHandler(const int sig)
  871. {
  872. switch (sig)
  873. {
  874. case SIGINT:
  875. case SIGTERM:
  876. terminateFn();
  877. break;
  878. case SIGUSR1:
  879. reloadFn();
  880. break;
  881. case SIGUSR2:
  882. evaluateFn("typeof(parameterChanged) === 'function' && parameterChanged(0, 0);");
  883. break;
  884. }
  885. }
  886. int dpf_webview_start(int /* argc */, char** /* argv[] */)
  887. {
  888. uselocale(newlocale(LC_NUMERIC_MASK, "C", nullptr));
  889. const char* const envScaleFactor = std::getenv("DPF_WEB_VIEW_SCALE_FACTOR");
  890. DISTRHO_SAFE_ASSERT_RETURN(envScaleFactor != nullptr, 1);
  891. const char* const envWinId = std::getenv("DPF_WEB_VIEW_WIN_ID");
  892. DISTRHO_SAFE_ASSERT_RETURN(envWinId != nullptr, 1);
  893. const Window winId = std::strtoul(envWinId, nullptr, 10);
  894. DISTRHO_SAFE_ASSERT_RETURN(winId != 0, 1);
  895. const double scaleFactor = std::atof(envScaleFactor);
  896. DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0, 1);
  897. Display* const display = XOpenDisplay(nullptr);
  898. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1);
  899. const char* url = "file:///home/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html";
  900. struct sigaction sig = {};
  901. sig.sa_handler = signalHandler;
  902. sig.sa_flags = SA_RESTART;
  903. sigemptyset(&sig.sa_mask);
  904. sigaction(SIGINT, &sig, nullptr);
  905. sigaction(SIGTERM, &sig, nullptr);
  906. sigaction(SIGUSR1, &sig, nullptr);
  907. sigaction(SIGUSR2, &sig, nullptr);
  908. // qt5webengine(winId, scaleFactor, url) ||
  909. // qt6webengine(winId, scaleFactor, url) ||
  910. gtk3(display, winId, 0, 0, 600, 400, scaleFactor, url);
  911. XCloseDisplay(display);
  912. return 0;
  913. }
  914. // --------------------------------------------------------------------------------------------------------------------
  915. #endif // WEB_VIEW_USING_X11_IPC
  916. #ifdef WEB_VIEW_DGL_NAMESPACE
  917. END_NAMESPACE_DGL
  918. #else
  919. END_NAMESPACE_DISTRHO
  920. #endif
  921. #undef MACRO_NAME
  922. #undef MACRO_NAME2
  923. #undef WEB_VIEW_DISTRHO_NAMESPACE
  924. #undef WEB_VIEW_DGL_NAMESPACE