diff --git a/src/plugin/ChildProcess.hpp b/src/plugin/ChildProcess.hpp index ca99278..4ef01b4 100644 --- a/src/plugin/ChildProcess.hpp +++ b/src/plugin/ChildProcess.hpp @@ -134,6 +134,29 @@ class ChildProcess #endif } + bool start2(const char* const args[]) + { + const pid_t ret = pid = vfork(); + + switch (ret) + { + // child process + case 0: + execvp(args[0], const_cast(args)); + + d_stderr2("exec failed: %d:%s", errno, std::strerror(errno)); + _exit(1); + break; + + // error + case -1: + d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno)); + break; + } + + return ret > 0; + } + void stop(const uint32_t timeoutInMilliseconds = 2000) { const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds; @@ -237,7 +260,7 @@ class ChildProcess #endif } - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChildProcess) + DISTRHO_DECLARE_NON_COPYABLE(ChildProcess) }; // ----------------------------------------------------------------------------------------------------------- diff --git a/src/plugin/DesktopAudioDriver.cpp b/src/plugin/DesktopAudioDriver.cpp index 67d9a2a..2b3b6d8 100644 --- a/src/plugin/DesktopAudioDriver.cpp +++ b/src/plugin/DesktopAudioDriver.cpp @@ -164,7 +164,7 @@ class DesktopAudioDriver : public JackAudioDriver printf("%03d:%s\n", __LINE__, __FUNCTION__); } - int Open(jack_nframes_t buffer_size, + int Open(jack_nframes_t buffersize, jack_nframes_t samplerate, bool capturing, bool playing, @@ -177,7 +177,7 @@ class DesktopAudioDriver : public JackAudioDriver jack_nframes_t playback_latency) override { printf("%03d:%s\n", __LINE__, __FUNCTION__); - if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, chan_in, chan_out, monitor, + if (JackAudioDriver::Open(buffersize, samplerate, capturing, playing, chan_in, chan_out, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) { return -1; } diff --git a/src/plugin/DesktopUI.cpp b/src/plugin/DesktopUI.cpp index 67da055..2323f56 100644 --- a/src/plugin/DesktopUI.cpp +++ b/src/plugin/DesktopUI.cpp @@ -2,17 +2,12 @@ // SPDX-License-Identifier: AGPL-3.0-or-later #include "DistrhoUI.hpp" +#include "WebView.hpp" START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- -void* addWebView(void* view); -void reloadWebView(void* webview); -void resizeWebView(void* webview, uint offset, uint width, uint height); - -// ----------------------------------------------------------------------------------------------------------- - class DesktopUI : public UI { void* webview = nullptr; @@ -21,7 +16,7 @@ class DesktopUI : public UI DesktopUI() : UI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT) { - webview = addWebView(reinterpret_cast(getWindow().getNativeWindowHandle())); + webview = addWebView(getWindow().getNativeWindowHandle()); const double scaleFactor = getScaleFactor(); @@ -39,6 +34,7 @@ class DesktopUI : public UI ~DesktopUI() override { + destroyWebView(webview); } protected: @@ -85,7 +81,7 @@ class DesktopUI : public UI { UI::onResize(ev); - uint offset = 20; + uint offset = kVerticalOffset; uint width = ev.size.getWidth(); uint height = ev.size.getHeight() - offset; diff --git a/src/plugin/DistrhoPluginInfo.h b/src/plugin/DistrhoPluginInfo.h index ed5535e..2350a0e 100644 --- a/src/plugin/DistrhoPluginInfo.h +++ b/src/plugin/DistrhoPluginInfo.h @@ -22,3 +22,5 @@ #define DISTRHO_UI_DEFAULT_WIDTH 1170 #define DISTRHO_UI_DEFAULT_HEIGHT 600 #define DISTRHO_UI_USER_RESIZABLE 1 + +static const constexpr unsigned int kVerticalOffset = 25; diff --git a/src/plugin/Makefile b/src/plugin/Makefile index ac0b63b..7d6f2e0 100644 --- a/src/plugin/Makefile +++ b/src/plugin/Makefile @@ -15,6 +15,8 @@ FILES_UI = DesktopUI.cpp ifeq ($(MACOS),true) FILES_UI += WebView.mm +else ifeq ($(LINUX),true) +FILES_UI += WebViewX11.cpp endif # --------------------------------------------------------------------------------------------------------------------- @@ -29,8 +31,27 @@ ifeq ($(MACOS),true) LINK_FLAGS += -framework WebKit else ifeq ($(WINDOWS),true) LINK_FLAGS += -lwinmm +else ifeq ($(LINUX),true) +LINK_FLAGS += -ldl endif -all: jack vst2 +TARGETS = jack vst2 # --------------------------------------------------------------------------------------------------------------------- + +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 $@ + +$(BUILD_DIR)/WebViewQt.cpp.o: BUILD_CXX_FLAGS += -std=gnu++14 $(shell $(PKG_CONFIG) --cflags Qt5WebEngineWidgets) + +include $(BUILD_DIR)/WebViewQt.cpp.d + +endif + +# --------------------------------------------------------------------------------------------------------------------- + +all: $(TARGETS) diff --git a/src/plugin/WebView.hpp b/src/plugin/WebView.hpp new file mode 100644 index 0000000..db4e735 --- /dev/null +++ b/src/plugin/WebView.hpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include "DistrhoUtils.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +void* addWebView(uintptr_t viewptr); +void destroyWebView(void* webview); +void reloadWebView(void* webview); +void resizeWebView(void* webview, uint offset, uint width, uint height); + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/src/plugin/WebView.mm b/src/plugin/WebView.mm index be96324..8e82e1e 100644 --- a/src/plugin/WebView.mm +++ b/src/plugin/WebView.mm @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2023-2024 MOD Audio UG // SPDX-License-Identifier: AGPL-3.0-or-later -#include "DistrhoUtils.hpp" +#include "WebView.hpp" #import #import @@ -10,14 +10,16 @@ // ----------------------------------------------------------------------------------------------------------- -void* addWebView(void* view); -void reloadWebView(void* webview); -void resizeWebView(void* webview, uint offset, uint width, uint height); - -void* addWebView(void* const viewptr) +void* addWebView(const uintptr_t viewptr) { - NSView* const view = static_cast(viewptr); - WKWebView* const webview = [[WKWebView alloc] initWithFrame: CGRectMake(0, 25, 225, 300)]; + NSView* const view = reinterpret_cast(viewptr); + + cosnt CGRect rect = CGRectMake(0, + kVerticalOffset, + DISTRHO_UI_DEFAULT_WIDTH, + DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset); + + WKWebView* const webview = [[WKWebView alloc] initWithFrame: rect]; [[[webview configuration] preferences] setValue: @(true) forKey: @"developerExtrasEnabled"]; diff --git a/src/plugin/WebViewQt.cpp b/src/plugin/WebViewQt.cpp new file mode 100644 index 0000000..7630cfe --- /dev/null +++ b/src/plugin/WebViewQt.cpp @@ -0,0 +1,72 @@ +// 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 +#include +#include +#include + +// ----------------------------------------------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + QApplication::setAttribute(Qt::AA_X11InitThreads); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + setupControlCloseSignal(); + + // 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")); + + const bool darkMode = shouldUseDarkMode(); + + if (darkMode) + setupDarkModePalette(app); + + printf("'%s' '%s'\n", argv[1], argv[2]); + + if (argc == 3 && std::strcmp(argv[1], "-xembed") == 0) + { + 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("http://127.0.0.1:18181/")); + webview.show(); + return app.exec(); + } + else + { + QMainWindow window; + window.setWindowTitle("Web View"); + + QWebEngineView webview(&window); + webview.setUrl(QUrl("http://127.0.0.1:18181/")); + + window.setCentralWidget(&webview); + window.resize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset); + + if (darkMode) + setupDarkModeWindow(window); + + window.show(); + return app.exec(); + } +} + +// ----------------------------------------------------------------------------------------------------------- diff --git a/src/plugin/WebViewX11.cpp b/src/plugin/WebViewX11.cpp new file mode 100644 index 0000000..c05fa49 --- /dev/null +++ b/src/plugin/WebViewX11.cpp @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include "WebView.hpp" + +#include "ChildProcess.hpp" +#include "extra/String.hpp" + +#include +#include +#include +// #include + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +struct WebViewIPC { + ChildProcess p; + ::Display* display; + ::Window childWindow; + ::Window ourWindow; +}; + +// ----------------------------------------------------------------------------------------------------------- + +void* addWebView(uintptr_t viewptr) +{ + ::Display* const display = XOpenDisplay(nullptr); + DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr); + + WebViewIPC* const ipc = new WebViewIPC(); + ipc->display = display; + ipc->childWindow = 0; + ipc->ourWindow = viewptr; + + char webviewTool[PATH_MAX] = {}; + + { + Dl_info info = {}; + dladdr((void*)addWebView, &info); + + if (info.dli_fname[0] == '.') + { + getcwd(webviewTool, PATH_MAX - 1); + std::strncat(webviewTool, info.dli_fname + 1, PATH_MAX - 1); + } + else if (info.dli_fname[0] != '/') + { + getcwd(webviewTool, PATH_MAX - 1); + std::strncat(webviewTool, "/", PATH_MAX - 1); + std::strncat(webviewTool, info.dli_fname, PATH_MAX - 1); + } + else + { + std::strncpy(webviewTool, info.dli_fname, PATH_MAX - 1); + } + } + + if (char* const c = std::strrchr(webviewTool, '/')) + *c = 0; + + std::strncat(webviewTool, "/MOD-Desktop-WebView", PATH_MAX - 1); + + const String viewStr(viewptr); + const char* const args[] = { webviewTool, "-platform", "xcb", "-xembed", viewStr.buffer(), nullptr }; + ipc->p.start2(args); + + return ipc; +} + +void destroyWebView(void* const webviewptr) +{ + WebViewIPC* const ipc = static_cast(webviewptr); + + XCloseDisplay(ipc->display); + delete ipc; +} + +void reloadWebView(void* const webviewptr) +{ +} + +void resizeWebView(void* const webviewptr, const uint offset, const uint width, const uint height) +{ + WebViewIPC* const ipc = static_cast(webviewptr); + + if (ipc->childWindow == 0) + { + ::Window rootWindow, parentWindow; + ::Window* childWindows = nullptr; + uint numChildren = 0; + + XFlush(ipc->display); + XQueryTree(ipc->display, ipc->ourWindow, &rootWindow, &parentWindow, &childWindows, &numChildren); + + if (numChildren == 0 || childWindows == nullptr) + return; + + ipc->childWindow = childWindows[0]; + XFree(childWindows); + } + + XMoveResizeWindow(ipc->display, ipc->childWindow, 0, offset, width, height); + XFlush(ipc->display); +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/src/systray/main.cpp b/src/systray/main.cpp index 80b1a62..2ff61ba 100644 --- a/src/systray/main.cpp +++ b/src/systray/main.cpp @@ -9,6 +9,10 @@ int main(int argc, char* argv[]) { + QApplication::setAttribute(Qt::AA_X11InitThreads); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + initEvironment(); setupControlCloseSignal(); diff --git a/src/systray/mod-desktop.hpp b/src/systray/mod-desktop.hpp index 3f02f38..efe1c43 100644 --- a/src/systray/mod-desktop.hpp +++ b/src/systray/mod-desktop.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/src/systray/utils.cpp b/src/systray/utils.cpp index 9aa0957..5c008fd 100644 --- a/src/systray/utils.cpp +++ b/src/systray/utils.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,7 @@ void initEvironment() } } - if (char* const c = strrchr(appDir, '/')) + if (char* const c = std::strrchr(appDir, '/')) *c = 0; #endif diff --git a/src/systray/utils.hpp b/src/systray/utils.hpp index 15f6f97..da34700 100644 --- a/src/systray/utils.hpp +++ b/src/systray/utils.hpp @@ -5,6 +5,8 @@ #include +class QMainWindow; + static inline QWidget* getLastParentOrSelf(QWidget* const w) noexcept {