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.

1052 lines
39KB

  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. @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKUIDelegate>
  74. @end
  75. @implementation WEB_VIEW_DELEGATE_CLASS_NAME
  76. - (void)webView:(WKWebView*)webview
  77. runJavaScriptAlertPanelWithMessage:(NSString*)message
  78. initiatedByFrame:(WKFrameInfo*)frame
  79. completionHandler:(void (^)(void))completionHandler
  80. {
  81. NSAlert* const alert = [[NSAlert alloc] init];
  82. [alert addButtonWithTitle:@"OK"];
  83. [alert setInformativeText:message];
  84. [alert setMessageText:@"Alert"];
  85. dispatch_async(dispatch_get_main_queue(), ^
  86. {
  87. [alert beginSheetModalForWindow:[webview window]
  88. completionHandler:^(NSModalResponse)
  89. {
  90. completionHandler();
  91. [alert release];
  92. }];
  93. });
  94. }
  95. - (void)webView:(WKWebView*)webview
  96. runJavaScriptConfirmPanelWithMessage:(NSString*)message
  97. initiatedByFrame:(WKFrameInfo*)frame
  98. completionHandler:(void (^)(BOOL))completionHandler
  99. {
  100. NSAlert* const alert = [[NSAlert alloc] init];
  101. [alert addButtonWithTitle:@"OK"];
  102. [alert addButtonWithTitle:@"Cancel"];
  103. [alert setInformativeText:message];
  104. [alert setMessageText:@"Confirm"];
  105. dispatch_async(dispatch_get_main_queue(), ^
  106. {
  107. [alert beginSheetModalForWindow:[webview window]
  108. completionHandler:^(NSModalResponse result)
  109. {
  110. completionHandler(result == NSAlertFirstButtonReturn);
  111. [alert release];
  112. }];
  113. });
  114. }
  115. - (void)webView:(WKWebView*)webview
  116. runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
  117. defaultText:(NSString*)defaultText
  118. initiatedByFrame:(WKFrameInfo*)frame
  119. completionHandler:(void (^)(NSString*))completionHandler
  120. {
  121. NSTextField* const input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 30)];
  122. [input setStringValue:defaultText];
  123. NSAlert* const alert = [[NSAlert alloc] init];
  124. [alert setAccessoryView:input];
  125. [alert addButtonWithTitle:@"OK"];
  126. [alert addButtonWithTitle:@"Cancel"];
  127. [alert setInformativeText:prompt];
  128. [alert setMessageText: @"Prompt"];
  129. dispatch_async(dispatch_get_main_queue(), ^
  130. {
  131. [alert beginSheetModalForWindow:[webview window]
  132. completionHandler:^(NSModalResponse result)
  133. {
  134. [input validateEditing];
  135. completionHandler(result == NSAlertFirstButtonReturn ? [input stringValue] : nil);
  136. [alert release];
  137. }];
  138. });
  139. }
  140. - (void)webView:(WKWebView*)webview
  141. runOpenPanelWithParameters:(WKOpenPanelParameters*)params
  142. initiatedByFrame:(WKFrameInfo*)frame
  143. completionHandler:(void (^)(NSArray<NSURL*>*))completionHandler
  144. {
  145. NSOpenPanel* const panel = [[NSOpenPanel alloc] init];
  146. [panel setAllowsMultipleSelection:[params allowsMultipleSelection]];
  147. // [panel setAllowedFileTypes:(NSArray<NSString*>*)[params _allowedFileExtensions]];
  148. [panel setCanChooseDirectories:[params allowsDirectories]];
  149. [panel setCanChooseFiles:![params allowsDirectories]];
  150. dispatch_async(dispatch_get_main_queue(), ^
  151. {
  152. [panel beginSheetModalForWindow:[webview window]
  153. completionHandler:^(NSModalResponse result)
  154. {
  155. completionHandler(result == NSModalResponseOK ? [panel URLs] : nil);
  156. [panel release];
  157. }];
  158. });
  159. }
  160. @end
  161. #endif // WEB_VIEW_USING_MACOS_WEBKIT
  162. // -----------------------------------------------------------------------------------------------------------
  163. #ifdef WEB_VIEW_DGL_NAMESPACE
  164. START_NAMESPACE_DGL
  165. using DISTRHO_NAMESPACE::String;
  166. #else
  167. START_NAMESPACE_DISTRHO
  168. #endif
  169. // -----------------------------------------------------------------------------------------------------------
  170. struct WebViewData {
  171. #if WEB_VIEW_USING_CHOC
  172. choc::ui::WebView* const webview;
  173. #elif WEB_VIEW_USING_MACOS_WEBKIT
  174. NSView* const view;
  175. WKWebView* const webview;
  176. NSURLRequest* const urlreq;
  177. WEB_VIEW_DELEGATE_CLASS_NAME* const delegate;
  178. #elif WEB_VIEW_USING_X11_IPC
  179. ChildProcess p;
  180. ::Display* display;
  181. ::Window childWindow;
  182. ::Window ourWindow;
  183. #endif
  184. };
  185. // -----------------------------------------------------------------------------------------------------------
  186. #if WEB_VIEW_USING_CHOC
  187. static std::optional<choc::ui::WebView::Options::Resource> fetch_resource(const std::string& path)
  188. {
  189. d_stdout("requested path %s", path.c_str());
  190. if (path == "/")
  191. {
  192. const std::string html = R"PREFIX(
  193. <html>
  194. <head>
  195. <style>
  196. html, body { background: black; background-image: url(img.svg); }
  197. </style>
  198. <script>
  199. function parameterChanged(index, value) {
  200. console.log("parameterChanged received", index, value);
  201. }
  202. </script>
  203. </head>
  204. <body>
  205. hello world!
  206. </body>
  207. </html>
  208. )PREFIX";
  209. const std::vector<uint8_t> data(html.begin(), html.end());
  210. return choc::ui::WebView::Options::Resource{ data, "text/html" };
  211. }
  212. if (path == "/img.svg")
  213. {
  214. const std::string html = R"PREFIX(<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  215. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  216. <!-- based on https://github.com/n0jo/rackwindows/blob/master/res/components/rw_knob_large_dark.svg -->
  217. <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;">
  218. <g id="knobLDark">
  219. <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;"/>
  220. </g>
  221. </svg>
  222. )PREFIX";
  223. const std::vector<uint8_t> data(html.begin(), html.end());
  224. return choc::ui::WebView::Options::Resource{ data, "image/svg+xml" };
  225. }
  226. return {};
  227. }
  228. #elif WEB_VIEW_USING_X11_IPC
  229. static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* const ptr)
  230. {
  231. Dl_info info = {};
  232. dladdr(ptr, &info);
  233. if (info.dli_fname[0] == '.')
  234. {
  235. getcwd(filename, PATH_MAX - 1);
  236. std::strncat(filename, info.dli_fname + 1, PATH_MAX - 1);
  237. }
  238. else if (info.dli_fname[0] != '/')
  239. {
  240. getcwd(filename, PATH_MAX - 1);
  241. std::strncat(filename, "/", PATH_MAX - 1);
  242. std::strncat(filename, info.dli_fname, PATH_MAX - 1);
  243. }
  244. else
  245. {
  246. std::strncpy(filename, info.dli_fname, PATH_MAX - 1);
  247. }
  248. }
  249. #endif
  250. // -----------------------------------------------------------------------------------------------------------
  251. WebViewHandle webViewCreate(const uintptr_t windowId,
  252. const uint initialWidth,
  253. const uint initialHeight,
  254. const double scaleFactor,
  255. const WebViewOptions& options)
  256. {
  257. #if WEB_VIEW_USING_CHOC
  258. choc::ui::WebView::Options woptions;
  259. woptions.acceptsFirstMouseClick = true;
  260. woptions.enableDebugMode = true;
  261. woptions.fetchResource = fetch_resource;
  262. std::unique_ptr<choc::ui::WebView> webview = std::make_unique<choc::ui::WebView>(woptions);
  263. DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr);
  264. void* const handle = webview->getViewHandle();
  265. DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
  266. choc::ui::WebView* const www = webview.get();
  267. webview->bind("setParameterValue", [www](const choc::value::ValueView&) -> choc::value::Value {
  268. static int pp = 0;
  269. std::string toeval = "typeof(parameterChanged) === 'function' && parameterChanged(";
  270. toeval += std::to_string(++pp);
  271. toeval += ", 0.1)";
  272. d_stdout("param received | %s", toeval.c_str());
  273. www->evaluateJavascript(toeval);
  274. return {};
  275. });
  276. #ifdef DISTRHO_OS_MAC
  277. NSView* const view = static_cast<NSView*>(handle);
  278. [reinterpret_cast<NSView*>(windowId) addSubview:view];
  279. [view setFrame:NSMakeRect(options.offset.x,
  280. options.offset.y,
  281. DISTRHO_UI_DEFAULT_WIDTH - options.offset.x,
  282. DISTRHO_UI_DEFAULT_HEIGHT - options.offset.y)];
  283. #else
  284. const HWND hwnd = static_cast<HWND>(handle);
  285. LONG_PTR flags = GetWindowLongPtr(hwnd, -16);
  286. flags = (flags & ~WS_POPUP) | WS_CHILD;
  287. SetWindowLongPtr(hwnd, -16, flags);
  288. SetParent(hwnd, reinterpret_cast<HWND>(windowId));
  289. SetWindowPos(hwnd, nullptr,
  290. options.offset.x * scaleFactor,
  291. options.offset.y * scaleFactor,
  292. (initialWidth - options.offset.x) * scaleFactor,
  293. (initialHeight - options.offset.y) * scaleFactor,
  294. SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  295. ShowWindow(hwnd, SW_SHOW);
  296. #endif
  297. return new WebViewData{webview.release()};
  298. #elif WEB_VIEW_USING_MACOS_WEBKIT
  299. NSView* const view = reinterpret_cast<NSView*>(windowId);
  300. const CGRect rect = CGRectMake(options.offset.x,
  301. options.offset.y,
  302. (initialWidth - options.offset.x),
  303. (initialHeight - options.offset.y));
  304. WKPreferences* const prefs = [[WKPreferences alloc] init];
  305. [prefs setValue:@YES forKey:@"developerExtrasEnabled"];
  306. WKWebViewConfiguration* const config = [[WKWebViewConfiguration alloc] init];
  307. config.preferences = prefs;
  308. WKWebView* const webview = [[WKWebView alloc] initWithFrame:rect
  309. configuration:config];
  310. [view addSubview:webview];
  311. WEB_VIEW_DELEGATE_CLASS_NAME* const delegate = [[WEB_VIEW_DELEGATE_CLASS_NAME alloc] init];
  312. webview.UIDelegate = delegate;
  313. const char* const url = "https://mastodon.falktx.com/";
  314. NSString* const nsurl = [[NSString alloc] initWithBytes:url
  315. length:std::strlen(url)
  316. encoding:NSUTF8StringEncoding];
  317. NSURLRequest* const urlreq = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: nsurl]];
  318. [webview loadRequest:urlreq];
  319. [webview setHidden:NO];
  320. [nsurl release];
  321. [config release];
  322. [prefs release];
  323. return new WebViewData{view, webview, urlreq, delegate};
  324. #elif WEB_VIEW_USING_X11_IPC
  325. char ldlinux[PATH_MAX] = {};
  326. getFilenameFromFunctionPtr(ldlinux, dlsym(nullptr, "_rtld_global"));
  327. char filename[PATH_MAX] = {};
  328. getFilenameFromFunctionPtr(filename, reinterpret_cast<const void*>(webViewCreate));
  329. d_stdout("ld-linux is '%s'", ldlinux);
  330. d_stdout("filename is '%s'", filename);
  331. ::Display* const display = XOpenDisplay(nullptr);
  332. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr);
  333. // set up custom child environment
  334. uint envsize = 0;
  335. while (environ[envsize] != nullptr)
  336. ++envsize;
  337. char** const envp = new char*[envsize + 5];
  338. {
  339. uint e = 0;
  340. for (uint i = 0; i < envsize; ++i)
  341. {
  342. if (std::strncmp(environ[i], "LD_PRELOAD=", 11) == 0)
  343. continue;
  344. if (std::strncmp(environ[i], "LD_LIBRARY_PATH=", 16) == 0)
  345. continue;
  346. envp[e++] = strdup(environ[i]);
  347. }
  348. envp[e++] = strdup("LANG=en_US.UTF-8");
  349. envp[e++] = ("DPF_WEB_VIEW_SCALE_FACTOR=" + String(scaleFactor)).getAndReleaseBuffer();
  350. envp[e++] = ("DPF_WEB_VIEW_WIN_ID=" +String(windowId)).getAndReleaseBuffer();
  351. for (uint i = e; i < envsize + 5; ++i)
  352. envp[e++] = nullptr;
  353. }
  354. WebViewData* const handle = new WebViewData();
  355. handle->display = display;
  356. handle->childWindow = 0;
  357. handle->ourWindow = windowId;
  358. const char* const args[] = { ldlinux, filename, "dpf-ld-linux-webview", nullptr };
  359. handle->p.start(args, envp);
  360. for (uint i = 0; envp[i] != nullptr; ++i)
  361. std::free(envp[i]);
  362. delete[] envp;
  363. return handle;
  364. #endif
  365. // maybe unused
  366. (void)windowId;
  367. (void)initialWidth;
  368. (void)initialHeight;
  369. (void)scaleFactor;
  370. (void)options;
  371. return nullptr;
  372. }
  373. void webViewDestroy(const WebViewHandle handle)
  374. {
  375. #if WEB_VIEW_USING_CHOC
  376. delete handle->webview;
  377. delete handle;
  378. #elif WEB_VIEW_USING_MACOS_WEBKIT
  379. [handle->webview setHidden:YES];
  380. [handle->webview removeFromSuperview];
  381. [handle->urlreq release];
  382. [handle->delegate release];
  383. delete handle;
  384. #elif WEB_VIEW_USING_X11_IPC
  385. XCloseDisplay(handle->display);
  386. delete handle;
  387. #endif
  388. // maybe unused
  389. (void)handle;
  390. }
  391. void webViewEvaluateJS(const WebViewHandle handle, const char* const js)
  392. {
  393. #if WEB_VIEW_USING_CHOC
  394. #elif WEB_VIEW_USING_MACOS_WEBKIT
  395. #elif WEB_VIEW_USING_X11_IPC
  396. handle->p.signal(SIGUSR2);
  397. #endif
  398. // maybe unused
  399. (void)handle;
  400. (void)js;
  401. }
  402. void webViewReload(const WebViewHandle handle)
  403. {
  404. #if WEB_VIEW_USING_CHOC
  405. #elif WEB_VIEW_USING_MACOS_WEBKIT
  406. [handle->webview loadRequest:handle->urlreq];
  407. #elif WEB_VIEW_USING_X11_IPC
  408. handle->p.signal(SIGUSR1);
  409. #endif
  410. // maybe unused
  411. (void)handle;
  412. }
  413. void webViewResize(const WebViewHandle handle, const uint width, const uint height, const double scaleFactor)
  414. {
  415. #if WEB_VIEW_USING_CHOC
  416. #ifdef DISTRHO_OS_MAC
  417. NSView* const view = static_cast<NSView*>(handle->webview->getViewHandle());
  418. [view setFrameSize:NSMakeSize(width, height)];
  419. #else
  420. const HWND hwnd = static_cast<HWND>(handle->webview->getViewHandle());
  421. SetWindowPos(hwnd, nullptr, 0, 0,
  422. width * scaleFactor,
  423. height * scaleFactor,
  424. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  425. #endif
  426. #elif WEB_VIEW_USING_MACOS_WEBKIT
  427. [handle->webview setFrameSize:NSMakeSize(width, height)];
  428. #elif WEB_VIEW_USING_X11_IPC
  429. if (handle->childWindow == 0)
  430. {
  431. ::Window rootWindow, parentWindow;
  432. ::Window* childWindows = nullptr;
  433. uint numChildren = 0;
  434. XFlush(handle->display);
  435. XQueryTree(handle->display, handle->ourWindow, &rootWindow, &parentWindow, &childWindows, &numChildren);
  436. if (numChildren == 0 || childWindows == nullptr)
  437. return;
  438. handle->childWindow = childWindows[0];
  439. XFree(childWindows);
  440. }
  441. XResizeWindow(handle->display, handle->childWindow, width, height);
  442. XFlush(handle->display);
  443. #endif
  444. // maybe unused
  445. (void)handle;
  446. (void)width;
  447. (void)height;
  448. (void)scaleFactor;
  449. }
  450. #if WEB_VIEW_USING_X11_IPC
  451. // -----------------------------------------------------------------------------------------------------------
  452. static std::function<void(const char* js)> evaluateFn;
  453. static std::function<void()> reloadFn;
  454. static std::function<void()> terminateFn;
  455. // -----------------------------------------------------------------------------------------------------------
  456. struct GtkContainer;
  457. struct GtkPlug;
  458. struct GtkWidget;
  459. struct GtkWindow;
  460. struct JSCValue;
  461. struct WebKitJavascriptResult;
  462. struct WebKitSettings;
  463. struct WebKitUserContentManager;
  464. struct WebKitWebView;
  465. typedef int gboolean;
  466. #define G_CALLBACK(p) reinterpret_cast<void*>(p)
  467. #define GTK_CONTAINER(p) reinterpret_cast<GtkContainer*>(p)
  468. #define GTK_PLUG(p) reinterpret_cast<GtkPlug*>(p)
  469. #define GTK_WINDOW(p) reinterpret_cast<GtkWindow*>(p)
  470. #define WEBKIT_WEB_VIEW(p) reinterpret_cast<WebKitWebView*>(p)
  471. // struct QApplication;
  472. // struct QUrl;
  473. // struct QWebEngineView;
  474. // struct QWindow;
  475. // -----------------------------------------------------------------------------------------------------------
  476. #define JOIN(A, B) A ## B
  477. #define AUTOSYM(S) \
  478. using JOIN(gtk3_, S) = decltype(&S); \
  479. JOIN(gtk3_, S) S = reinterpret_cast<JOIN(gtk3_, S)>(dlsym(nullptr, #S)); \
  480. DISTRHO_SAFE_ASSERT_RETURN(S != nullptr, false);
  481. #define CSYM(S, NAME) \
  482. S NAME = reinterpret_cast<S>(dlsym(nullptr, #NAME)); \
  483. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  484. #define CPPSYM(S, NAME, SN) \
  485. S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \
  486. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  487. // -----------------------------------------------------------------------------------------------------------
  488. // gtk3 variant
  489. static int gtk_js_cb(WebKitUserContentManager*, WebKitJavascriptResult* const result, void* const arg)
  490. {
  491. void* const lib = static_cast<void*>(arg);
  492. DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, false);
  493. using g_free_t = void (*)(void*);
  494. using jsc_value_to_string_t = char* (*)(JSCValue*);
  495. using webkit_javascript_result_get_js_value_t = JSCValue* (*)(WebKitJavascriptResult*);
  496. CSYM(g_free_t, g_free)
  497. CSYM(jsc_value_to_string_t, jsc_value_to_string)
  498. CSYM(webkit_javascript_result_get_js_value_t, webkit_javascript_result_get_js_value)
  499. JSCValue* const value = webkit_javascript_result_get_js_value(result);
  500. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, false);
  501. char* const string = jsc_value_to_string(value);
  502. DISTRHO_SAFE_ASSERT_RETURN(string != nullptr, false);
  503. d_stdout("js call received with data '%s'", string);
  504. g_free(string);
  505. return 0;
  506. }
  507. static bool gtk3(Display* const display,
  508. const Window winId,
  509. const uint x,
  510. const uint y,
  511. const uint width,
  512. const uint height,
  513. double scaleFactor,
  514. const char* const url)
  515. {
  516. void* lib;
  517. if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  518. (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  519. return false;
  520. using g_signal_connect_data_t = ulong (*)(void*, const char*, void*, void*, void*, int);
  521. using gdk_set_allowed_backends_t = void (*)(const char*);
  522. using gtk_container_add_t = void (*)(GtkContainer*, GtkWidget*);
  523. using gtk_init_check_t = gboolean (*)(int*, char***);
  524. using gtk_main_t = void (*)();
  525. using gtk_main_quit_t = void (*)();
  526. using gtk_plug_get_id_t = Window (*)(GtkPlug*);
  527. using gtk_plug_new_t = GtkWidget* (*)(Window);
  528. using gtk_widget_show_all_t = void (*)(GtkWidget*);
  529. using gtk_window_move_t = void (*)(GtkWindow*, int, int);
  530. using gtk_window_set_default_size_t = void (*)(GtkWindow*, int, int);
  531. using webkit_settings_new_t = WebKitSettings* (*)();
  532. using webkit_settings_set_enable_developer_extras_t = void (*)(WebKitSettings*, gboolean);
  533. using webkit_settings_set_enable_write_console_messages_to_stdout_t = void (*)(WebKitSettings*, gboolean);
  534. using webkit_settings_set_hardware_acceleration_policy_t = void (*)(WebKitSettings*, int);
  535. using webkit_settings_set_javascript_can_access_clipboard_t = void (*)(WebKitSettings*, gboolean);
  536. using webkit_user_content_manager_register_script_message_handler_t = gboolean (*)(WebKitUserContentManager*, const char*);
  537. using webkit_web_view_evaluate_javascript_t = void* (*)(WebKitWebView*, const char*, ssize_t, const char*, const char*, void*, void*, void*);
  538. using webkit_web_view_get_user_content_manager_t = WebKitUserContentManager* (*)(WebKitWebView*);
  539. using webkit_web_view_load_uri_t = void (*)(WebKitWebView*, const char*);
  540. using webkit_web_view_new_with_settings_t = GtkWidget* (*)(WebKitSettings*);
  541. using webkit_web_view_run_javascript_t = void* (*)(WebKitWebView*, const char*, void*, void*, void*);
  542. using webkit_web_view_set_background_color_t = void (*)(WebKitWebView*, const double*);
  543. CSYM(g_signal_connect_data_t, g_signal_connect_data)
  544. CSYM(gdk_set_allowed_backends_t, gdk_set_allowed_backends)
  545. CSYM(gtk_container_add_t, gtk_container_add)
  546. CSYM(gtk_init_check_t, gtk_init_check)
  547. CSYM(gtk_main_t, gtk_main)
  548. CSYM(gtk_main_quit_t, gtk_main_quit)
  549. CSYM(gtk_plug_get_id_t, gtk_plug_get_id)
  550. CSYM(gtk_plug_new_t, gtk_plug_new)
  551. CSYM(gtk_widget_show_all_t, gtk_widget_show_all)
  552. CSYM(gtk_window_move_t, gtk_window_move)
  553. CSYM(gtk_window_set_default_size_t, gtk_window_set_default_size)
  554. CSYM(webkit_settings_new_t, webkit_settings_new)
  555. CSYM(webkit_settings_set_enable_developer_extras_t, webkit_settings_set_enable_developer_extras)
  556. CSYM(webkit_settings_set_enable_write_console_messages_to_stdout_t, webkit_settings_set_enable_write_console_messages_to_stdout)
  557. CSYM(webkit_settings_set_hardware_acceleration_policy_t, webkit_settings_set_hardware_acceleration_policy)
  558. CSYM(webkit_settings_set_javascript_can_access_clipboard_t, webkit_settings_set_javascript_can_access_clipboard)
  559. CSYM(webkit_user_content_manager_register_script_message_handler_t, webkit_user_content_manager_register_script_message_handler)
  560. CSYM(webkit_web_view_get_user_content_manager_t, webkit_web_view_get_user_content_manager)
  561. CSYM(webkit_web_view_load_uri_t, webkit_web_view_load_uri)
  562. CSYM(webkit_web_view_new_with_settings_t, webkit_web_view_new_with_settings)
  563. CSYM(webkit_web_view_set_background_color_t, webkit_web_view_set_background_color)
  564. // special case for legacy API handling
  565. 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"));
  566. 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"));
  567. DISTRHO_SAFE_ASSERT_RETURN(webkit_web_view_evaluate_javascript != nullptr || webkit_web_view_run_javascript != nullptr, false);
  568. const int gdkScale = std::fmod(scaleFactor, 1.0) >= 0.75
  569. ? static_cast<int>(scaleFactor + 0.5)
  570. : static_cast<int>(scaleFactor);
  571. if (gdkScale != 1)
  572. {
  573. char scale[8] = {};
  574. std::snprintf(scale, 7, "%d", gdkScale);
  575. setenv("GDK_SCALE", scale, 1);
  576. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.2);
  577. setenv("GDK_DPI_SCALE", scale, 1);
  578. }
  579. else if (scaleFactor > 1.0)
  580. {
  581. char scale[8] = {};
  582. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.4);
  583. setenv("GDK_DPI_SCALE", scale, 1);
  584. }
  585. scaleFactor /= gdkScale;
  586. gdk_set_allowed_backends("x11");
  587. if (! gtk_init_check (nullptr, nullptr))
  588. return false;
  589. GtkWidget* const window = gtk_plug_new(winId);
  590. DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false);
  591. gtk_window_set_default_size(GTK_WINDOW(window),
  592. (width - x) * scaleFactor,
  593. (height - y) * scaleFactor);
  594. gtk_window_move(GTK_WINDOW(window), x * scaleFactor, y * scaleFactor);
  595. WebKitSettings* const settings = webkit_settings_new();
  596. DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);
  597. webkit_settings_set_javascript_can_access_clipboard(settings, true);
  598. webkit_settings_set_hardware_acceleration_policy(settings, 2 /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */);
  599. // if (debug)
  600. {
  601. webkit_settings_set_enable_developer_extras(settings, true);
  602. webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
  603. }
  604. GtkWidget* const webview = webkit_web_view_new_with_settings(settings);
  605. DISTRHO_SAFE_ASSERT_RETURN(webview != nullptr, false);
  606. const double color[] = {49.0/255, 54.0/255, 59.0/255, 1};
  607. webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(webview), color);
  608. if (WebKitUserContentManager* const manager = webkit_web_view_get_user_content_manager(WEBKIT_WEB_VIEW(webview)))
  609. {
  610. g_signal_connect_data(manager, "script-message-received::external", G_CALLBACK(gtk_js_cb), lib, nullptr, 0);
  611. webkit_user_content_manager_register_script_message_handler(manager, "external");
  612. }
  613. webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url);
  614. gtk_container_add(GTK_CONTAINER(window), webview);
  615. gtk_widget_show_all(window);
  616. Window wid = gtk_plug_get_id(GTK_PLUG(window));
  617. XMapWindow(display, wid);
  618. XFlush(display);
  619. evaluateFn = [=](const char* const js){
  620. if (webkit_web_view_evaluate_javascript != nullptr)
  621. webkit_web_view_evaluate_javascript(WEBKIT_WEB_VIEW(webview), js, -1,
  622. nullptr, nullptr, nullptr, nullptr, nullptr);
  623. else
  624. webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(webview), js, nullptr, nullptr, nullptr);
  625. };
  626. reloadFn = [=](){
  627. webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), url);
  628. };
  629. terminateFn = [=](){
  630. d_stdout("terminateFn");
  631. static bool quit = true;
  632. if (quit)
  633. {
  634. quit = false;
  635. gtk_main_quit();
  636. }
  637. };
  638. gtk_main();
  639. d_stdout("quit");
  640. dlclose(lib);
  641. return true;
  642. }
  643. #if 0
  644. // -----------------------------------------------------------------------------------------------------------
  645. // qt5webengine variant
  646. static bool qt5webengine(const Window winId, const double scaleFactor, const char* const url)
  647. {
  648. void* lib;
  649. if ((lib = dlopen("libQt5WebEngineWidgets.so.5", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  650. (lib = dlopen("libQt5WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  651. return false;
  652. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  653. using QApplication_exec_t = void (*)();
  654. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  655. using QString__init_t = void (*)(void*, const QChar*, ptrdiff_t);
  656. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  657. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  658. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  659. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  660. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  661. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  662. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  663. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  664. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  665. using QWindow_setParent_t = void (*)(QWindow*, void*);
  666. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  667. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  668. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  669. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QChari)
  670. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  671. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  672. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  673. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  674. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  675. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  676. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  677. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  678. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  679. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  680. unsetenv("QT_FONT_DPI");
  681. unsetenv("QT_SCREEN_SCALE_FACTORS");
  682. unsetenv("QT_USE_PHYSICAL_DPI");
  683. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  684. char scale[8] = {};
  685. std::snprintf(scale, 7, "%.2f", scaleFactor);
  686. setenv("QT_SCALE_FACTOR", scale, 1);
  687. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  688. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  689. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  690. static int argc = 0;
  691. static char* argv[] = { nullptr };
  692. uint8_t _app[64]; // sizeof(QApplication) == 16
  693. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  694. QApplication__init(app, argc, argv, 0);
  695. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  696. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  697. {
  698. const size_t url_len = std::strlen(url);
  699. QChar* const url_qchar = new QChar[url_len + 1];
  700. for (size_t i = 0; i < url_len; ++i)
  701. url_qchar[i] = QChar(url[i]);
  702. url_qchar[url_len] = 0;
  703. QString__init(qstrurl, url_qchar, url_len);
  704. }
  705. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  706. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  707. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  708. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  709. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  710. QWebEngineView__init(webview, nullptr);
  711. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  712. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  713. QWebEngineView_winId(webview);
  714. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  715. QWebEngineView_setUrl(webview, *qurl);
  716. QWebEngineView_show(webview);
  717. reloadFn = [=](){
  718. QWebEngineView_setUrl(webview, *qurl);
  719. };
  720. terminateFn = [=](){
  721. // TODO
  722. };
  723. QApplication_exec();
  724. dlclose(lib);
  725. return true;
  726. }
  727. // -----------------------------------------------------------------------------------------------------------
  728. // qt6webengine variant (same as qt5 but `QString__init_t` has different arguments)
  729. static bool qt6webengine(const Window winId, const double scaleFactor, const char* const url)
  730. {
  731. void* lib;
  732. if ((lib = dlopen("libQt6WebEngineWidgets.so.6", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  733. (lib = dlopen("libQt6WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  734. return false;
  735. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  736. using QApplication_exec_t = void (*)();
  737. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  738. using QString__init_t = void (*)(void*, const QChar*, long long);
  739. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  740. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  741. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  742. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  743. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  744. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  745. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  746. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  747. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  748. using QWindow_setParent_t = void (*)(QWindow*, void*);
  749. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  750. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  751. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  752. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QCharx)
  753. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  754. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  755. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  756. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  757. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  758. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  759. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  760. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  761. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  762. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  763. unsetenv("QT_FONT_DPI");
  764. unsetenv("QT_SCREEN_SCALE_FACTORS");
  765. unsetenv("QT_USE_PHYSICAL_DPI");
  766. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  767. char scale[8] = {};
  768. std::snprintf(scale, 7, "%.2f", scaleFactor);
  769. setenv("QT_SCALE_FACTOR", scale, 1);
  770. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  771. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  772. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  773. static int argc = 0;
  774. static char* argv[] = { nullptr };
  775. uint8_t _app[64]; // sizeof(QApplication) == 16
  776. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  777. QApplication__init(app, argc, argv, 0);
  778. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  779. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  780. {
  781. const size_t url_len = std::strlen(url);
  782. QChar* const url_qchar = new QChar[url_len + 1];
  783. for (size_t i = 0; i < url_len; ++i)
  784. url_qchar[i] = QChar(url[i]);
  785. url_qchar[url_len] = 0;
  786. QString__init(qstrurl, url_qchar, url_len);
  787. }
  788. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  789. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  790. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  791. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  792. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  793. QWebEngineView__init(webview, nullptr);
  794. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  795. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  796. QWebEngineView_winId(webview);
  797. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  798. QWebEngineView_setUrl(webview, *qurl);
  799. QWebEngineView_show(webview);
  800. reloadFn = [=](){
  801. QWebEngineView_setUrl(webview, *qurl);
  802. };
  803. terminateFn = [=](){
  804. // TODO
  805. };
  806. QApplication_exec();
  807. dlclose(lib);
  808. return true;
  809. }
  810. #endif
  811. // -----------------------------------------------------------------------------------------------------------
  812. // startup via ld-linux
  813. static void signalHandler(const int sig)
  814. {
  815. switch (sig)
  816. {
  817. case SIGINT:
  818. case SIGTERM:
  819. terminateFn();
  820. break;
  821. case SIGUSR1:
  822. reloadFn();
  823. break;
  824. case SIGUSR2:
  825. evaluateFn("typeof(parameterChanged) === 'function' && parameterChanged(0, 0);");
  826. break;
  827. }
  828. }
  829. int dpf_webview_start(int /* argc */, char** /* argv[] */)
  830. {
  831. uselocale(newlocale(LC_NUMERIC_MASK, "C", nullptr));
  832. const char* const envScaleFactor = std::getenv("DPF_WEB_VIEW_SCALE_FACTOR");
  833. DISTRHO_SAFE_ASSERT_RETURN(envScaleFactor != nullptr, 1);
  834. const char* const envWinId = std::getenv("DPF_WEB_VIEW_WIN_ID");
  835. DISTRHO_SAFE_ASSERT_RETURN(envWinId != nullptr, 1);
  836. const Window winId = std::strtoul(envWinId, nullptr, 10);
  837. DISTRHO_SAFE_ASSERT_RETURN(winId != 0, 1);
  838. const double scaleFactor = std::atof(envScaleFactor);
  839. DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0, 1);
  840. Display* const display = XOpenDisplay(nullptr);
  841. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1);
  842. const char* url = "file:///home/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html";
  843. struct sigaction sig = {};
  844. sig.sa_handler = signalHandler;
  845. sig.sa_flags = SA_RESTART;
  846. sigemptyset(&sig.sa_mask);
  847. sigaction(SIGINT, &sig, nullptr);
  848. sigaction(SIGTERM, &sig, nullptr);
  849. sigaction(SIGUSR1, &sig, nullptr);
  850. sigaction(SIGUSR2, &sig, nullptr);
  851. // qt5webengine(winId, scaleFactor, url) ||
  852. // qt6webengine(winId, scaleFactor, url) ||
  853. gtk3(display, winId, 0, 0, 600, 400, scaleFactor, url);
  854. XCloseDisplay(display);
  855. return 0;
  856. }
  857. // --------------------------------------------------------------------------------------------------------------------
  858. #endif // WEB_VIEW_USING_X11_IPC
  859. #ifdef WEB_VIEW_DGL_NAMESPACE
  860. END_NAMESPACE_DGL
  861. #else
  862. END_NAMESPACE_DISTRHO
  863. #endif
  864. #undef MACRO_NAME
  865. #undef MACRO_NAME2
  866. #undef WEB_VIEW_DISTRHO_NAMESPACE
  867. #undef WEB_VIEW_DGL_NAMESPACE