Skip to content

Commit

Permalink
more linux details
Browse files Browse the repository at this point in the history
Signed-off-by: falkTX <falktx@falktx.com>
  • Loading branch information
falkTX committed Mar 15, 2024
1 parent b0af934 commit 1d873a6
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 59 deletions.
2 changes: 1 addition & 1 deletion src/plugin/DesktopUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class DesktopUI : public UI,
DISTRHO_SAFE_ASSERT_RETURN(port != 0,);

port += kPortNumOffset;
webview = addWebView(getWindow().getNativeWindowHandle(), port);
webview = addWebView(getWindow().getNativeWindowHandle(), getScaleFactor(), port);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/plugin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ DPF_TARGET_DIR = ../../build-plugin
include ../DPF/Makefile.plugins.mk

BUILD_CXX_FLAGS += -DVERSION='"$(shell cat ../../VERSION)"'
# BUILD_CXX_FLAGS += -std=gnu++17

BUILD_CXX_FLAGS += -pthread
LINK_FLAGS += -pthread
Expand All @@ -55,9 +56,9 @@ ifeq ($(LINUX),true)
TARGETS += $(TARGET_DIR)/MOD-Desktop-WebView

$(TARGET_DIR)/MOD-Desktop-WebView: $(BUILD_DIR)/WebViewQt.cpp.o
$(CXX) $^ $(LINK_FLAGS) $(shell $(PKG_CONFIG) --libs Qt5WebEngineWidgets) -o $@
$(CXX) $^ $(LINK_FLAGS) $(shell $(PKG_CONFIG) --libs Qt5WebEngineWidgets x11) -o $@

$(BUILD_DIR)/WebViewQt.cpp.o: BUILD_CXX_FLAGS += -std=gnu++14 $(shell $(PKG_CONFIG) --cflags Qt5WebEngineWidgets)
$(BUILD_DIR)/WebViewQt.cpp.o: BUILD_CXX_FLAGS += -std=gnu++14 $(shell $(PKG_CONFIG) --cflags Qt5WebEngineWidgets webkit2gtk-4.0 x11)

-include $(BUILD_DIR)/WebViewQt.cpp.d

Expand Down
2 changes: 1 addition & 1 deletion src/plugin/WebView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------

void* addWebView(uintptr_t parentWinId, uint port);
void* addWebView(uintptr_t parentWinId, double scaleFactor, uint port);
void destroyWebView(void* webview);
void reloadWebView(void* webview);
void resizeWebView(void* webview, uint offset, uint width, uint height);
Expand Down
2 changes: 1 addition & 1 deletion src/plugin/WebView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

// -----------------------------------------------------------------------------------------------------------

void* addWebView(const uintptr_t parentWinId, const uint port)
void* addWebView(const uintptr_t parentWinId, double, const uint port)
{
NSView* const view = reinterpret_cast<NSView*>(parentWinId);

Expand Down
248 changes: 203 additions & 45 deletions src/plugin/WebViewQt.cpp
Original file line number Diff line number Diff line change
@@ -1,72 +1,230 @@
// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG
// SPDX-License-Identifier: AGPL-3.0-or-later

#include "DistrhoPluginInfo.h"

#include "../systray/qrc_mod-desktop.hpp"

// TODO split build
#include "../systray/utils.cpp"

#include <QtGui/QWindow>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWebEngineWidgets/QWebEngineView>

// -----------------------------------------------------------------------------------------------------------
#undef signals

int main(int argc, char* argv[])
{
QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#include <gtk/gtkx.h>
#include <webkit2/webkit2.h>

setupControlCloseSignal();
#include <clocale>
#include <cstdio>
#include <dlfcn.h>
#include <new>
#include <X11/Xlib.h>

// TODO set up all branding here
QApplication app(argc, argv);
app.setApplicationName("MOD Desktop");
app.setOrganizationName("MOD Audio");
app.setWindowIcon(QIcon(":/res/mod-logo.svg"));
#include "DistrhoPluginInfo.h"
#include "DistrhoUtils.hpp"

// #include "../systray/qrc_mod-desktop.hpp"
// #include "../systray/utils.cpp"

// -----------------------------------------------------------------------------------------------------------

const bool darkMode = shouldUseDarkMode();
#define JOIN(A, B) A ## B

if (darkMode)
setupDarkModePalette(app);
#define GTK3SYM(S) \
using JOIN(gtk3_, S) = decltype(&S); \
JOIN(gtk3_, S) S = reinterpret_cast<JOIN(gtk3_, S)>(dlsym(nullptr, #S)); \
DISTRHO_SAFE_ASSERT_RETURN(S != nullptr, false);

printf("'%s' '%s'\n", argv[1], argv[2]);
// -----------------------------------------------------------------------------------------------------------
// gtk3 variant

if (argc == 4 && std::strcmp(argv[1], "-xembed") == 0)
static bool gtk3(Display* const display, const Window winId, double scaleFactor, const char* const url)
{
void* const lib = dlopen("libwebkit2gtk-4.0.so.37_____", RTLD_NOW|RTLD_GLOBAL);
DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, false);

GTK3SYM(g_type_check_instance_cast)
GTK3SYM(gdk_set_allowed_backends)
GTK3SYM(gtk_container_add)
GTK3SYM(gtk_container_get_type)
GTK3SYM(gtk_init_check)
GTK3SYM(gtk_main)
GTK3SYM(gtk_plug_get_id)
GTK3SYM(gtk_plug_get_type)
GTK3SYM(gtk_plug_new)
GTK3SYM(gtk_widget_show_all)
GTK3SYM(gtk_window_get_type)
GTK3SYM(gtk_window_move)
GTK3SYM(gtk_window_set_default_size)
GTK3SYM(webkit_settings_new)
GTK3SYM(webkit_settings_set_hardware_acceleration_policy)
GTK3SYM(webkit_settings_set_javascript_can_access_clipboard)
GTK3SYM(webkit_web_view_get_type)
GTK3SYM(webkit_web_view_load_uri)
GTK3SYM(webkit_web_view_new_with_settings)

const int gdkScale = std::fmod(scaleFactor, 1.0) >= 0.75
? static_cast<int>(scaleFactor + 0.5)
: static_cast<int>(scaleFactor);

if (gdkScale != 1)
{
const uintptr_t parentId = std::atoll(argv[2]);
QWindow* const parentWindow = QWindow::fromWinId(parentId);

QWebEngineView webview;
webview.move(0, kVerticalOffset);
webview.setFixedSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset);
webview.winId();
webview.windowHandle()->setParent(parentWindow);
webview.setUrl(QUrl(QString::fromLocal8Bit("http://127.0.0.1:") + QString::fromLocal8Bit(argv[3])));
webview.show();
return app.exec();
char scale[8] = {};
std::snprintf(scale, 7, "%d", gdkScale);
setenv("GDK_SCALE", scale, 1);

std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.2);
setenv("GDK_DPI_SCALE", scale, 1);
}
else
else if (scaleFactor > 1.0)
{
QMainWindow window;
window.setWindowTitle("Web View");
char scale[8] = {};
std::snprintf(scale, 7, "%.2f", (1.0 / scaleFactor) * 1.4);
setenv("GDK_DPI_SCALE", scale, 1);
}

scaleFactor /= gdkScale;

gdk_set_allowed_backends("x11");

if (! gtk_init_check (nullptr, nullptr))
return false;

GtkWidget* const window = gtk_plug_new(winId);
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false);

gtk_window_set_default_size(GTK_WINDOW(window),
DISTRHO_UI_DEFAULT_WIDTH * scaleFactor,
(DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset) * scaleFactor);
gtk_window_move(GTK_WINDOW(window), 0, kVerticalOffset * scaleFactor);

WebKitSettings* const settings = webkit_settings_new();
DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);

webkit_settings_set_javascript_can_access_clipboard(settings, true);
webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);

GtkWidget* const webview = webkit_web_view_new_with_settings(settings);
DISTRHO_SAFE_ASSERT_RETURN(webview != nullptr, false);

webkit_web_view_load_uri (WEBKIT_WEB_VIEW (webview), url);

QWebEngineView webview(&window);
webview.setUrl(QUrl("http://127.0.0.1:18181/"));
gtk_container_add(GTK_CONTAINER(window), webview);

window.setCentralWidget(&webview);
window.resize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset);
gtk_widget_show_all(window);

if (darkMode)
setupDarkModeWindow(window);
Window wid = gtk_plug_get_id(GTK_PLUG(window));
XMapWindow(display, wid);
XFlush(display);

window.show();
return app.exec();
gtk_main();

dlclose(lib);
return true;
}

// -----------------------------------------------------------------------------------------------------------
// qt5webengine variant

// using _QApplication_QApplication = decltype(QApplication::QApplication);

#define QT5SYM(S, NAME, SN) \
using SN = decltype(&S); \
SN NAME = reinterpret_cast<SN>(dlsym(nullptr, #SN)); \
DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);

static bool qt5webengine(const Window winId, const double scaleFactor, const char* const url)
{
void* const lib = dlopen("libQt5WebEngineWidgets.so.5", RTLD_NOW|RTLD_GLOBAL);
DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, false);

// qOverload<int, QProcess::ExitStatus>(
// using qt5webengine_qapp = decltype(&QApplication::QApplication);
// qt5webengine_qapp qapp = reinterpret_cast<qt5webengine_qapp>(dlsym(nullptr, "QApplication::QApplication"));
// DISTRHO_SAFE_ASSERT_RETURN(qapp != nullptr, false);

// QT5SYM(QGuiApplication::QGuiApplication, QApplication_QApplication, _ZN15QGuiApplication4execEv)
QT5SYM(QApplication::setAttribute, QApplication_setAttribute, _ZN16QCoreApplication12setAttributeEN2Qt20ApplicationAttributeEb)
QT5SYM(QApplication::exec, QApplication_exec, _ZN15QGuiApplication4execEv)
// QT5SYM(QWebEngineView::move, QWebEngineView_move, _ZN7QWidget4moveERK6QPoint)
// QT5SYM(QWebEngineView::setFixedSize, QWebEngineView_setFixedSize, _ZN7QWidget12setFixedSizeEii)
// QT5SYM(QWebEngineView::winId, QWebEngineView_winId, _ZNK7QWidget5winIdEv)
// QT5SYM(QWebEngineView::windowHandle, QWebEngineView_windowHandle, _ZNK7QWidget12windowHandleEv)
// QT5SYM(QWebEngineView::setUrl, QWebEngineView_setUrl, _ZN14QWebEngineView6setUrlERK4QUrl)
// QT5SYM(QWebEngineView::show, QWebEngineView_show, _ZN7QWidget4showEv)
QT5SYM(QWindow::fromWinId, QWindow_fromWinId, _ZN7QWindow9fromWinIdEy)

unsetenv("QT_FONT_DPI");
unsetenv("QT_SCREEN_SCALE_FACTORS");
unsetenv("QT_USE_PHYSICAL_DPI");
setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0", 1);

char scale[8] = {};
std::snprintf(scale, 7, "%.2f", scaleFactor);
setenv("QT_SCALE_FACTOR", scale, 1);

QApplication_setAttribute(Qt::AA_X11InitThreads, true);
QApplication_setAttribute(Qt::AA_EnableHighDpiScaling, true);
QApplication_setAttribute(Qt::AA_UseHighDpiPixmaps, true);

static int argc = 0;
static char* argv[] = { nullptr };

uint8_t app_data[sizeof(QApplication)];
QApplication* const app = reinterpret_cast<QApplication*>(app_data);
new(app)QApplication(argc, argv);

QWindow* const parentWindow = QWindow_fromWinId(winId);

uint8_t webview_data[sizeof(QWebEngineView)];
QWebEngineView* const webview = reinterpret_cast<QWebEngineView*>(webview_data);
new(webview)QWebEngineView();

webview->move(0, kVerticalOffset);
webview->setFixedSize(DISTRHO_UI_DEFAULT_WIDTH,
DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset);
webview->winId();
webview->windowHandle()->setParent(parentWindow);
webview->setUrl(QUrl(QString::fromLocal8Bit(url)));
webview->show();

QApplication_exec();

webview->~QWebEngineView();
app->~QApplication();

dlclose(lib);
return true;
}

// -----------------------------------------------------------------------------------------------------------

int main(int argc, char* argv[])
{
if (argc != 4)
{
fprintf(stderr, "usage: %s x11-win-id scale-factor port\n", argv[0]);
return 2;
}

uselocale(newlocale(LC_NUMERIC_MASK, "C", nullptr));

const Window winId = std::strtoul(argv[1], nullptr, 10);
DISTRHO_SAFE_ASSERT_RETURN(winId != 0, 1);

const double scaleFactor = std::atof(argv[2]);
DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0, 1);

Display* const display = XOpenDisplay(nullptr);
DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1);

char url[32] = {};
std::snprintf(url, 31, "http://127.0.0.1:%s/", argv[3]);

const bool ok = qt5webengine(winId, scaleFactor, url) ||
gtk3(display, winId, scaleFactor, url);

XCloseDisplay(display);

return ok ? 0 : 1;
}

// -----------------------------------------------------------------------------------------------------------
2 changes: 1 addition & 1 deletion src/plugin/WebViewWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------

void* addWebView(const uintptr_t parentWinId, const uint port)
void* addWebView(const uintptr_t parentWinId, const double scaleFactor, const uint port)
{
return nullptr;
}
Expand Down
9 changes: 5 additions & 4 deletions src/plugin/WebViewX11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct WebViewIPC {

// -----------------------------------------------------------------------------------------------------------

void* addWebView(const uintptr_t parentWinId, const uint port)
void* addWebView(const uintptr_t parentWinId, const double scaleFactor, const uint port)
{
char webviewTool[PATH_MAX] = {};
{
Expand Down Expand Up @@ -62,12 +62,13 @@ void* addWebView(const uintptr_t parentWinId, const uint port)
ipc->childWindow = 0;
ipc->ourWindow = parentWinId;

const String embedIdStr(parentWinId);
const String portStr(port);
const String embedIdStr(parentWinId);
const String scaleFactorStr(scaleFactor);
const char* const args[] = {
webviewTool,
"-platform", "xcb",
"-xembed", embedIdStr.buffer(),
embedIdStr.buffer(),
scaleFactorStr.buffer(),
portStr.buffer(),
nullptr
};
Expand Down
6 changes: 2 additions & 4 deletions src/plugin/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,8 @@ static const wchar_t* getAppDirW()

if (appDir[0] == 0)
{
// SHGetSpecialFolderPathW(nullptr, appDir, CSIDL_PROGRAM_FILES, false);
// std::wcsncat(appDir, L"\\MOD Desktop", MAX_PATH - 1);

std::wcsncat(appDir, L"Z:\\home\\falktx\\Source\\MOD\\mod-desktop\\build", MAX_PATH - 1);
SHGetSpecialFolderPathW(nullptr, appDir, CSIDL_PROGRAM_FILES, false);
std::wcsncat(appDir, L"\\MOD Desktop", MAX_PATH - 1);
}

return appDir;
Expand Down

0 comments on commit 1d873a6

Please sign in to comment.