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.

586 lines
21KB

  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_WEBVIEW_HPP_INCLUDED) && !defined(DGL_WEBVIEW_HPP_INCLUDED)
  17. # error bad include
  18. #endif
  19. #if !defined(WEBVIEW_DISTRHO_NAMESPACE) && !defined(WEBVIEW_DGL_NAMESPACE)
  20. # error bad usage
  21. #endif
  22. // #define QT_NO_VERSION_TAGGING
  23. // #include <QtCore/QChar>
  24. // #include <QtCore/QPoint>
  25. // #include <QtCore/QSize>
  26. // #undef signals
  27. #include "ChildProcess.hpp"
  28. #include "String.hpp"
  29. #include <clocale>
  30. #include <cstdio>
  31. #include <dlfcn.h>
  32. #include <functional>
  33. #include <linux/limits.h>
  34. #include <X11/Xlib.h>
  35. #ifdef WEBVIEW_DGL_NAMESPACE
  36. START_NAMESPACE_DGL
  37. using DISTRHO_NAMESPACE::String;
  38. #else
  39. START_NAMESPACE_DISTRHO
  40. #endif
  41. // -----------------------------------------------------------------------------------------------------------
  42. struct WebViewData {
  43. ChildProcess p;
  44. ::Display* display;
  45. ::Window childWindow;
  46. ::Window ourWindow;
  47. };
  48. // -----------------------------------------------------------------------------------------------------------
  49. static void getFilenameFromFunctionPtr(char filename[PATH_MAX], const void* const ptr)
  50. {
  51. Dl_info info = {};
  52. dladdr(ptr, &info);
  53. if (info.dli_fname[0] == '.')
  54. {
  55. getcwd(filename, PATH_MAX - 1);
  56. std::strncat(filename, info.dli_fname + 1, PATH_MAX - 1);
  57. }
  58. else if (info.dli_fname[0] != '/')
  59. {
  60. getcwd(filename, PATH_MAX - 1);
  61. std::strncat(filename, "/", PATH_MAX - 1);
  62. std::strncat(filename, info.dli_fname, PATH_MAX - 1);
  63. }
  64. else
  65. {
  66. std::strncpy(filename, info.dli_fname, PATH_MAX - 1);
  67. }
  68. }
  69. WebViewHandle addWebView(const uintptr_t parentWindowId,
  70. const int x,
  71. const int y,
  72. const uint width,
  73. const uint height,
  74. const double scaleFactor)
  75. {
  76. char ldlinux[PATH_MAX] = {};
  77. getFilenameFromFunctionPtr(ldlinux, dlsym(nullptr, "_rtld_global"));
  78. char filename[PATH_MAX] = {};
  79. getFilenameFromFunctionPtr(filename, reinterpret_cast<const void*>(addWebView));
  80. d_stdout("ld-linux is '%s'", ldlinux);
  81. d_stdout("filename is '%s'", filename);
  82. ::Display* const display = XOpenDisplay(nullptr);
  83. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr);
  84. // set up custom child environment
  85. uint envsize = 0;
  86. while (environ[envsize] != nullptr)
  87. ++envsize;
  88. char** const envp = new char*[envsize + 5];
  89. {
  90. uint e = 0;
  91. for (uint i = 0; i < envsize; ++i)
  92. {
  93. if (std::strncmp(environ[i], "LD_PRELOAD=", 11) == 0)
  94. continue;
  95. if (std::strncmp(environ[i], "LD_LIBRARY_PATH=", 16) == 0)
  96. continue;
  97. envp[e++] = strdup(environ[i]);
  98. }
  99. envp[e++] = strdup("LANG=en_US.UTF-8");
  100. envp[e++] = ("DPF_WEBVIEW_SCALE_FACTOR=" + String(scaleFactor)).getAndReleaseBuffer();
  101. envp[e++] = ("DPF_WEBVIEW_WIN_ID=" +String(parentWindowId)).getAndReleaseBuffer();
  102. for (uint i = e; i < envsize + 5; ++i)
  103. envp[e++] = nullptr;
  104. }
  105. WebViewData* const handle = new WebViewData();
  106. handle->display = display;
  107. handle->childWindow = 0;
  108. handle->ourWindow = parentWindowId;
  109. const char* const args[] = { ldlinux, filename, "dpf-ld-linux-webview", nullptr };
  110. handle->p.start(args, envp);
  111. for (uint i = 0; envp[i] != nullptr; ++i)
  112. std::free(envp[i]);
  113. delete[] envp;
  114. return handle;
  115. }
  116. void destroyWebView(const WebViewHandle handle)
  117. {
  118. XCloseDisplay(handle->display);
  119. delete handle;
  120. }
  121. void reloadWebView(const WebViewHandle handle, uint)
  122. {
  123. handle->p.signal(SIGUSR1);
  124. }
  125. void resizeWebView(const WebViewHandle handle, int x, int y, uint width, uint height)
  126. {
  127. if (handle->childWindow == 0)
  128. {
  129. ::Window rootWindow, parentWindow;
  130. ::Window* childWindows = nullptr;
  131. uint numChildren = 0;
  132. XFlush(handle->display);
  133. XQueryTree(handle->display, handle->ourWindow, &rootWindow, &parentWindow, &childWindows, &numChildren);
  134. if (numChildren == 0 || childWindows == nullptr)
  135. return;
  136. handle->childWindow = childWindows[0];
  137. XFree(childWindows);
  138. }
  139. XMoveResizeWindow(handle->display, handle->childWindow, x, y, width, height);
  140. XFlush(handle->display);
  141. }
  142. // -----------------------------------------------------------------------------------------------------------
  143. static std::function<void()> reloadFn;
  144. // -----------------------------------------------------------------------------------------------------------
  145. struct GtkContainer;
  146. struct GtkPlug;
  147. struct GtkWidget;
  148. struct GtkWindow;
  149. struct WebKitSettings;
  150. struct WebKitWebView;
  151. #define GTK_CONTAINER(p) reinterpret_cast<GtkContainer*>(p)
  152. #define GTK_PLUG(p) reinterpret_cast<GtkPlug*>(p)
  153. #define GTK_WINDOW(p) reinterpret_cast<GtkWindow*>(p)
  154. #define WEBKIT_WEB_VIEW(p) reinterpret_cast<WebKitWebView*>(p)
  155. // struct QApplication;
  156. // struct QUrl;
  157. // struct QWebEngineView;
  158. // struct QWindow;
  159. // -----------------------------------------------------------------------------------------------------------
  160. #define JOIN(A, B) A ## B
  161. #define AUTOSYM(S) \
  162. using JOIN(gtk3_, S) = decltype(&S); \
  163. JOIN(gtk3_, S) S = reinterpret_cast<JOIN(gtk3_, S)>(dlsym(nullptr, #S)); \
  164. DISTRHO_SAFE_ASSERT_RETURN(S != nullptr, false);
  165. #define CSYM(S, NAME) \
  166. S NAME = reinterpret_cast<S>(dlsym(nullptr, #NAME)); \
  167. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  168. #define CPPSYM(S, NAME, SN) \
  169. S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \
  170. DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);
  171. // -----------------------------------------------------------------------------------------------------------
  172. // gtk3 variant
  173. static bool gtk3(Display* const display,
  174. const Window winId,
  175. const uint x,
  176. const uint y,
  177. const uint width,
  178. const uint height,
  179. double scaleFactor,
  180. const char* const url)
  181. {
  182. void* lib;
  183. if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  184. (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  185. return false;
  186. using gdk_set_allowed_backends_t = void (*)(const char*);
  187. using gtk_container_add_t = void (*)(GtkContainer*, GtkWidget*);
  188. using gtk_init_check_t = bool (*)(int*, char***);
  189. using gtk_main_t = void (*)();
  190. using gtk_plug_get_id_t = Window (*)(GtkPlug*);
  191. using gtk_plug_new_t = GtkWidget* (*)(Window);
  192. using gtk_widget_show_all_t = void (*)(GtkWidget*);
  193. using gtk_window_move_t = void (*)(GtkWindow*, int, int);
  194. using gtk_window_set_default_size_t = void (*)(GtkWindow*, int, int);
  195. using webkit_settings_new_t = WebKitSettings* (*)();
  196. using webkit_settings_set_hardware_acceleration_policy_t = void (*)(WebKitSettings*, int);
  197. using webkit_settings_set_javascript_can_access_clipboard_t = void (*)(WebKitSettings*, bool);
  198. using webkit_web_view_load_uri_t = void (*)(WebKitWebView*, const char*);
  199. using webkit_web_view_new_with_settings_t = GtkWidget* (*)(WebKitSettings*);
  200. CSYM(gdk_set_allowed_backends_t, gdk_set_allowed_backends)
  201. CSYM(gtk_container_add_t, gtk_container_add)
  202. CSYM(gtk_init_check_t, gtk_init_check)
  203. CSYM(gtk_main_t, gtk_main)
  204. CSYM(gtk_plug_get_id_t, gtk_plug_get_id)
  205. CSYM(gtk_plug_new_t, gtk_plug_new)
  206. CSYM(gtk_widget_show_all_t, gtk_widget_show_all)
  207. CSYM(gtk_window_move_t, gtk_window_move)
  208. CSYM(gtk_window_set_default_size_t, gtk_window_set_default_size)
  209. CSYM(webkit_settings_new_t, webkit_settings_new)
  210. CSYM(webkit_settings_set_hardware_acceleration_policy_t, webkit_settings_set_hardware_acceleration_policy)
  211. CSYM(webkit_settings_set_javascript_can_access_clipboard_t, webkit_settings_set_javascript_can_access_clipboard)
  212. CSYM(webkit_web_view_load_uri_t, webkit_web_view_load_uri)
  213. CSYM(webkit_web_view_new_with_settings_t, webkit_web_view_new_with_settings)
  214. const int gdkScale = std::fmod(scaleFactor, 1.0) >= 0.75
  215. ? static_cast<int>(scaleFactor + 0.5)
  216. : static_cast<int>(scaleFactor);
  217. if (gdkScale != 1)
  218. {
  219. char scale[8] = {};
  220. std::snprintf(scale, 7, "%d", gdkScale);
  221. setenv("GDK_SCALE", scale, 1);
  222. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.2);
  223. setenv("GDK_DPI_SCALE", scale, 1);
  224. }
  225. else if (scaleFactor > 1.0)
  226. {
  227. char scale[8] = {};
  228. std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.4);
  229. setenv("GDK_DPI_SCALE", scale, 1);
  230. }
  231. scaleFactor /= gdkScale;
  232. gdk_set_allowed_backends("x11");
  233. if (! gtk_init_check (nullptr, nullptr))
  234. return false;
  235. GtkWidget* const window = gtk_plug_new(winId);
  236. DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false);
  237. gtk_window_set_default_size(GTK_WINDOW(window),
  238. (width - x) * scaleFactor,
  239. (height - y) * scaleFactor);
  240. gtk_window_move(GTK_WINDOW(window), x * scaleFactor, y * scaleFactor);
  241. WebKitSettings* const settings = webkit_settings_new();
  242. DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);
  243. webkit_settings_set_javascript_can_access_clipboard(settings, true);
  244. webkit_settings_set_hardware_acceleration_policy(settings, 2 /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */);
  245. GtkWidget* const webview = webkit_web_view_new_with_settings(settings);
  246. DISTRHO_SAFE_ASSERT_RETURN(webview != nullptr, false);
  247. webkit_web_view_load_uri(WEBKIT_WEB_VIEW (webview), url);
  248. gtk_container_add(GTK_CONTAINER(window), webview);
  249. gtk_widget_show_all(window);
  250. Window wid = gtk_plug_get_id(GTK_PLUG(window));
  251. XMapWindow(display, wid);
  252. XFlush(display);
  253. reloadFn = [=](){
  254. webkit_web_view_load_uri(WEBKIT_WEB_VIEW (webview), url);
  255. };
  256. gtk_main();
  257. dlclose(lib);
  258. return true;
  259. }
  260. #if 0
  261. // -----------------------------------------------------------------------------------------------------------
  262. // qt5webengine variant
  263. static bool qt5webengine(const Window winId, const double scaleFactor, const char* const url)
  264. {
  265. void* lib;
  266. if ((lib = dlopen("libQt5WebEngineWidgets.so.5", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  267. (lib = dlopen("libQt5WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  268. return false;
  269. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  270. using QApplication_exec_t = void (*)();
  271. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  272. using QString__init_t = void (*)(void*, const QChar*, ptrdiff_t);
  273. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  274. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  275. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  276. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  277. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  278. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  279. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  280. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  281. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  282. using QWindow_setParent_t = void (*)(QWindow*, void*);
  283. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  284. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  285. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  286. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QChari)
  287. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  288. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  289. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  290. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  291. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  292. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  293. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  294. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  295. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  296. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  297. unsetenv("QT_FONT_DPI");
  298. unsetenv("QT_SCREEN_SCALE_FACTORS");
  299. unsetenv("QT_USE_PHYSICAL_DPI");
  300. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  301. char scale[8] = {};
  302. std::snprintf(scale, 7, "%.2f", scaleFactor);
  303. setenv("QT_SCALE_FACTOR", scale, 1);
  304. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  305. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  306. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  307. static int argc = 0;
  308. static char* argv[] = { nullptr };
  309. uint8_t _app[64]; // sizeof(QApplication) == 16
  310. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  311. QApplication__init(app, argc, argv, 0);
  312. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  313. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  314. {
  315. const size_t url_len = std::strlen(url);
  316. QChar* const url_qchar = new QChar[url_len + 1];
  317. for (size_t i = 0; i < url_len; ++i)
  318. url_qchar[i] = QChar(url[i]);
  319. url_qchar[url_len] = 0;
  320. QString__init(qstrurl, url_qchar, url_len);
  321. }
  322. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  323. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  324. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  325. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  326. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  327. QWebEngineView__init(webview, nullptr);
  328. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  329. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  330. QWebEngineView_winId(webview);
  331. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  332. QWebEngineView_setUrl(webview, *qurl);
  333. QWebEngineView_show(webview);
  334. reloadFn = [=](){
  335. QWebEngineView_setUrl(webview, *qurl);
  336. };
  337. QApplication_exec();
  338. dlclose(lib);
  339. return true;
  340. }
  341. // -----------------------------------------------------------------------------------------------------------
  342. // qt6webengine variant (same as qt5 but `QString__init_t` has different arguments)
  343. static bool qt6webengine(const Window winId, const double scaleFactor, const char* const url)
  344. {
  345. void* lib;
  346. if ((lib = dlopen("libQt6WebEngineWidgets.so.6", RTLD_NOW|RTLD_GLOBAL)) == nullptr ||
  347. (lib = dlopen("libQt6WebEngineWidgets.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
  348. return false;
  349. using QApplication__init_t = void (*)(QApplication*, int&, char**, int);
  350. using QApplication_exec_t = void (*)();
  351. using QApplication_setAttribute_t = void (*)(Qt::ApplicationAttribute, bool);
  352. using QString__init_t = void (*)(void*, const QChar*, long long);
  353. using QUrl__init_t = void (*)(void*, const QString&, int /* QUrl::ParsingMode */);
  354. using QWebEngineView__init_t = void (*)(QWebEngineView*, void*);
  355. using QWebEngineView_move_t = void (*)(QWebEngineView*, const QPoint&);
  356. using QWebEngineView_resize_t = void (*)(QWebEngineView*, const QSize&);
  357. using QWebEngineView_setUrl_t = void (*)(QWebEngineView*, const QUrl&);
  358. using QWebEngineView_show_t = void (*)(QWebEngineView*);
  359. using QWebEngineView_winId_t = ulonglong (*)(QWebEngineView*);
  360. using QWebEngineView_windowHandle_t = QWindow* (*)(QWebEngineView*);
  361. using QWindow_fromWinId_t = QWindow* (*)(ulonglong);
  362. using QWindow_setParent_t = void (*)(QWindow*, void*);
  363. CPPSYM(QApplication__init_t, QApplication__init, _ZN12QApplicationC1ERiPPci)
  364. CPPSYM(QApplication_exec_t, QApplication_exec, _ZN15QGuiApplication4execEv)
  365. CPPSYM(QApplication_setAttribute_t, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
  366. CPPSYM(QString__init_t, QString__init, _ZN7QStringC2EPK5QCharx)
  367. CPPSYM(QUrl__init_t, QUrl__init, _ZN4QUrlC1ERK7QStringNS_11ParsingModeE)
  368. CPPSYM(QWebEngineView__init_t, QWebEngineView__init, _ZN14QWebEngineViewC1EP7QWidget)
  369. CPPSYM(QWebEngineView_move_t, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
  370. CPPSYM(QWebEngineView_resize_t, QWebEngineView_resize, _ZN7QWidget6resizeERK5QSize)
  371. CPPSYM(QWebEngineView_setUrl_t, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
  372. CPPSYM(QWebEngineView_show_t, QWebEngineView_show, _ZN7QWidget4showEv)
  373. CPPSYM(QWebEngineView_winId_t, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
  374. CPPSYM(QWebEngineView_windowHandle_t, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
  375. CPPSYM(QWindow_fromWinId_t, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)
  376. CPPSYM(QWindow_setParent_t, QWindow_setParent, _ZN7QWindow9setParentEPS_)
  377. unsetenv("QT_FONT_DPI");
  378. unsetenv("QT_SCREEN_SCALE_FACTORS");
  379. unsetenv("QT_USE_PHYSICAL_DPI");
  380. setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);
  381. char scale[8] = {};
  382. std::snprintf(scale, 7, "%.2f", scaleFactor);
  383. setenv("QT_SCALE_FACTOR", scale, 1);
  384. QApplication_setAttribute(Qt::AA_X11InitThreads, true);
  385. QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
  386. QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);
  387. static int argc = 0;
  388. static char* argv[] = { nullptr };
  389. uint8_t _app[64]; // sizeof(QApplication) == 16
  390. QApplication* const app = reinterpret_cast<QApplication*>(_app);
  391. QApplication__init(app, argc, argv, 0);
  392. uint8_t _qstrurl[32]; // sizeof(QString) == 8
  393. QString* const qstrurl(reinterpret_cast<QString*>(_qstrurl));
  394. {
  395. const size_t url_len = std::strlen(url);
  396. QChar* const url_qchar = new QChar[url_len + 1];
  397. for (size_t i = 0; i < url_len; ++i)
  398. url_qchar[i] = QChar(url[i]);
  399. url_qchar[url_len] = 0;
  400. QString__init(qstrurl, url_qchar, url_len);
  401. }
  402. uint8_t _qurl[32]; // sizeof(QUrl) == 8
  403. QUrl* const qurl(reinterpret_cast<QUrl*>(_qurl));
  404. QUrl__init(qurl, *qstrurl, 1 /* QUrl::StrictMode */);
  405. uint8_t _webview[128]; // sizeof(QWebEngineView) == 56
  406. QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(_webview);
  407. QWebEngineView__init(webview, nullptr);
  408. QWebEngineView_move(webview, QPoint(0, kVerticalOffset));
  409. QWebEngineView_resize(webview, QSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset));
  410. QWebEngineView_winId(webview);
  411. QWindow_setParent(QWebEngineView_windowHandle(webview), QWindow_fromWinId(winId));
  412. QWebEngineView_setUrl(webview, *qurl);
  413. QWebEngineView_show(webview);
  414. reloadFn = [=](){
  415. QWebEngineView_setUrl(webview, *qurl);
  416. };
  417. QApplication_exec();
  418. dlclose(lib);
  419. return true;
  420. }
  421. #endif
  422. // -----------------------------------------------------------------------------------------------------------
  423. // startup via ld-linux
  424. static void signalHandler(const int sig)
  425. {
  426. DISTRHO_SAFE_ASSERT_RETURN(sig == SIGUSR1,);
  427. reloadFn();
  428. }
  429. int dpf_webview_start(int /* argc */, char** /* argv[] */)
  430. {
  431. uselocale(newlocale(LC_NUMERIC_MASK, "C", nullptr));
  432. const char* const envScaleFactor = std::getenv("DPF_WEBVIEW_SCALE_FACTOR");
  433. DISTRHO_SAFE_ASSERT_RETURN(envScaleFactor != nullptr, 1);
  434. const char* const envWinId = std::getenv("DPF_WEBVIEW_WIN_ID");
  435. DISTRHO_SAFE_ASSERT_RETURN(envWinId != nullptr, 1);
  436. const Window winId = std::strtoul(envWinId, nullptr, 10);
  437. DISTRHO_SAFE_ASSERT_RETURN(winId != 0, 1);
  438. const double scaleFactor = std::atof(envScaleFactor);
  439. DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0, 1);
  440. Display* const display = XOpenDisplay(nullptr);
  441. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1);
  442. // const char* url = "file:///home/falktx/";
  443. const char* url = "https://mastodon.falktx.com/";
  444. struct sigaction sig = {};
  445. sig.sa_handler = signalHandler;
  446. sig.sa_flags = SA_RESTART;
  447. sigemptyset(&sig.sa_mask);
  448. sigaction(SIGUSR1, &sig, nullptr);
  449. // qt5webengine(winId, scaleFactor, url) ||
  450. // qt6webengine(winId, scaleFactor, url) ||
  451. gtk3(display, winId, 0, 0, 600, 400, scaleFactor, url);
  452. XCloseDisplay(display);
  453. return 0;
  454. }
  455. // --------------------------------------------------------------------------------------------------------------------
  456. #ifdef WEBVIEW_DGL_NAMESPACE
  457. END_NAMESPACE_DGL
  458. #else
  459. END_NAMESPACE_DISTRHO
  460. #endif
  461. #undef WEBVIEW_DISTRHO_NAMESPACE
  462. #undef WEBVIEW_DGL_NAMESPACE
  463. #undef WEBVIEW_NAMESPACE
  464. #undef fileBrowserSetPathNamespaced
  465. #undef fileBrowserSetPathFuncName