DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 054f35db47a783108e61088a628427dd6e213f9f
parent 52d5af44d6ec0e292d66f08d90ad53192efa537c
Author: falkTX <falktx@falktx.com>
Date:   Sun, 22 Aug 2021 19:23:04 +0100

Start rework of ExternalWindow, add stubs to make it build, WIP

Diffstat:
Mdgl/Window.hpp | 12++++++------
Mdistrho/DistrhoUI.hpp | 24++++++++++++------------
Mdistrho/extra/ExternalWindow.hpp | 267++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mdistrho/src/DistrhoUI.cpp | 30++++++++++++++++++++++++------
Mdistrho/src/DistrhoUIInternal.hpp | 86++++++++++---------------------------------------------------------------------
Mdistrho/src/DistrhoUIPrivateData.hpp | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
6 files changed, 388 insertions(+), 166 deletions(-)

diff --git a/dgl/Window.hpp b/dgl/Window.hpp @@ -122,17 +122,17 @@ public: ``` This struct is necessary because we cannot automatically make the window leave the OpenGL context in custom code. - We must always cleanly enter and leave the OpenGL context. - In order to avoid messing up the global host context, this class is used around widget creation. + And we must always cleanly enter and leave the OpenGL context. + So in order to avoid messing up the global host context, this class is used around widget creation. */ - class ScopedGraphicsContext + struct ScopedGraphicsContext { - Window& window; - public: explicit ScopedGraphicsContext(Window& window); ~ScopedGraphicsContext(); DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext) DISTRHO_PREVENT_HEAP_ALLOCATION + private: + Window& window; }; /** @@ -184,7 +184,7 @@ public: bool isVisible() const noexcept; /** - Set windows visible (or not) according to @a visible. + Set window visible (or not) according to @a visible. Only valid for standalones, embed windows are always visible. @see isVisible(), hide(), show() */ diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp @@ -250,7 +250,6 @@ protected: */ virtual void sampleRateChanged(double newSampleRate); -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /* -------------------------------------------------------------------------------------------------------- * UI Callbacks (optional) */ @@ -263,6 +262,16 @@ protected: virtual void uiIdle() {} /** + Window scale factor function, called when the scale factor changes. + This function is for plugin UIs to be able to override Window::onScaleFactorChanged(double). + + The default implementation does nothing. + WARNING function needs a proper name + */ + virtual void uiScaleFactorChanged(double scaleFactor); + +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + /** Windows focus function, called when the window gains or loses the keyboard focus. This function is for plugin UIs to be able to override Window::onFocus(bool, CrossingMode). @@ -275,22 +284,13 @@ protected: This function is for plugin UIs to be able to override Window::onReshape(uint, uint). The plugin UI size will be set right after this function. - The default implementation sets up drawing context where necessary. + The default implementation sets up the drawing context where necessary. You should almost never need to override this function. The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code. */ virtual void uiReshape(uint width, uint height); - /** - Window scale factor function, called when the scale factor changes. - This function is for plugin UIs to be able to override Window::onScaleFactorChanged(double). - - The default implementation does nothing. - WARNING function needs a proper name - */ - virtual void uiScaleFactorChanged(double scaleFactor); - # ifndef DGL_FILE_BROWSER_DISABLED /** Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser(). @@ -313,7 +313,7 @@ protected: @see Widget::onResize(const ResizeEvent&) */ void onResize(const ResizeEvent& ev) override; -#endif +#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI // ------------------------------------------------------------------------------------------------------- diff --git a/distrho/extra/ExternalWindow.hpp b/distrho/extra/ExternalWindow.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> + * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -33,45 +33,247 @@ START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- // ExternalWindow class +/** + External Window class. + + This is a standalone TopLevelWidget-compatible class, but without any real event handling. + Being compatible with TopLevelWidget, it allows to be used as DPF UI target. + + It can be used to embed non-DPF things or to run a tool in a new process as the "UI". + */ class ExternalWindow { -public: - ExternalWindow(const uint w = 1, const uint h = 1, const char* const t = "") - : width(w), - height(h), - title(t), - transientWinId(0), - visible(false), - pid(0) {} + struct PrivateData { + uintptr_t parentWindowHandle; + uintptr_t transientWinId; + uint width; + uint height; + double scaleFactor; + String title; + bool visible; + pid_t pid; + + PrivateData() + : parentWindowHandle(0), + transientWinId(0), + width(1), + height(1), + scaleFactor(1.0), + title(), + visible(false), + pid(0) {} + } pData; +public: + /** + Constructor. + */ + explicit ExternalWindow() + : pData() {} + + /** + Constructor. + */ + explicit ExternalWindow(const PrivateData& data) + : pData(data) {} + + /** + Destructor. + */ virtual ~ExternalWindow() { + /* terminateAndWaitForProcess(); + */ } + /* -------------------------------------------------------------------------------------------------------- + * ExternalWindow specific calls */ + + virtual bool isRunning() const + { + return false; + } + + virtual void setTransientWindowId(uintptr_t winId) + { + if (pData.transientWinId == winId) + return; + pData.transientWinId = winId; + } + +#if DISTRHO_PLUGIN_HAS_EMBED_UI + /** + Get the "native" window handle. + This can be reimplemented in order to pass the child window to hosts that can use such informaton. + + Returned value type depends on the platform: + - HaikuOS: This is a pointer to a `BView`. + - MacOS: This is a pointer to an `NSView*`. + - Windows: This is a `HWND`. + - Everything else: This is an [X11] `Window`. + */ + virtual uintptr_t getNativeWindowHandle() const noexcept + { + return 0; + } + + /** + Get the "native" window handle that this window should embed itself into. + Returned value type depends on the platform: + - HaikuOS: This is a pointer to a `BView`. + - MacOS: This is a pointer to an `NSView*`. + - Windows: This is a `HWND`. + - Everything else: This is an [X11] `Window`. + */ + uintptr_t getParentWindowHandle() const noexcept + { + return pData.parentWindowHandle; + } +#endif + + /* -------------------------------------------------------------------------------------------------------- + * TopLevelWidget-like calls */ + + /** + Check if this window is visible. + @see setVisible(bool) + */ + bool isVisible() const noexcept + { + return pData.visible; + } + + /** + Set window visible (or not) according to @a visible. + @see isVisible(), hide(), show() + */ + virtual void setVisible(bool visible) + { + if (pData.visible == visible) + return; + pData.visible = visible; + } + + /** + Show window. + This is the same as calling setVisible(true). + @see isVisible(), setVisible(bool) + */ + void show() + { + setVisible(true); + } + + /** + Hide window. + This is the same as calling setVisible(false). + @see isVisible(), setVisible(bool) + */ + void hide() + { + setVisible(false); + } + + /** + Get width. + */ uint getWidth() const noexcept { - return width; + return pData.width; } + /** + Get height. + */ uint getHeight() const noexcept { - return height; + return pData.height; } + /** + Set width. + */ + void setWidth(uint width) + { + setSize(width, getHeight()); + } + + /** + Set height. + */ + void setHeight(uint height) + { + setSize(getWidth(), height); + } + + /** + Set size using @a width and @a height values. + */ + virtual void setSize(uint width, uint height) + { + DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,); + + if (pData.width == width || pData.height == height) + return; + + pData.width = width; + pData.height = height; + onResize(width, height); + } + + /** + Get the title of the window previously set with setTitle(). + */ const char* getTitle() const noexcept { - return title; + return pData.title; } - uintptr_t getTransientWinId() const noexcept + /** + Set the title of the window, typically displayed in the title bar or in window switchers. + */ + virtual void setTitle(const char* title) { - return transientWinId; + if (pData.title == title) + return; + pData.title = title; } - bool isVisible() const noexcept + /** + Get the scale factor requested for this window. + This is purely informational, and up to developers to choose what to do with it. + + If you do not want to deal with this yourself, + consider using setGeometryConstraints() where you can specify to automatically scale the window contents. + @see setGeometryConstraints + */ + double getScaleFactor() const noexcept + { + return pData.scaleFactor; + } + + /** + Grab the keyboard input focus. + */ + virtual void focus() {} + +protected: + /** + A function called when the window is resized. + */ + virtual void onResize(uint width, uint height) { - return visible; + // unused, meant for custom implementations + return; + (void)width; + (void)height; + } + + /* + uintptr_t getTransientWinId() const noexcept + { + return transientWinId; } bool isRunning() noexcept @@ -91,28 +293,10 @@ public: return true; } - virtual void setSize(uint w, uint h) - { - width = w; - height = h; - } - - virtual void setTitle(const char* const t) - { - title = t; - } - - virtual void setTransientWinId(const uintptr_t winId) - { - transientWinId = winId; - } - - virtual void setVisible(const bool yesNo) - { - visible = yesNo; - } + */ protected: + /* bool startExternalProcess(const char* args[]) { terminateAndWaitForProcess(); @@ -181,16 +365,11 @@ protected: usleep(5*1000); } } + */ private: - uint width; - uint height; - String title; - uintptr_t transientWinId; - bool visible; - pid_t pid; - - friend class UIExporter; + friend class PluginWindow; + friend class UI; DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow) }; diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp @@ -36,11 +36,26 @@ const char* g_nextBundlePath = nullptr; UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr; -PluginWindow& UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint height) +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +ExternalWindow::PrivateData +#else +PluginWindow& +#endif +UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint height) { UI::PrivateData* const pData = s_nextPrivateData; pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor); +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + ExternalWindow::PrivateData ewData; + ewData.parentWindowHandle = pData->winId; + ewData.width = width; + ewData.height = height; + ewData.scaleFactor = pData->scaleFactor; + ewData.title = DISTRHO_PLUGIN_NAME; + return ewData; +#else return pData->window.getObject(); +#endif } /* ------------------------------------------------------------------------------------------------------------ @@ -58,6 +73,9 @@ UI::UI(const uint width, const uint height, const bool automaticallyScale) if (automaticallyScale) setGeometryConstraints(width, height, true, true); } +#else + // unused + return; (void)automaticallyScale; #endif } @@ -162,10 +180,14 @@ void UI::sampleRateChanged(double) { } -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /* ------------------------------------------------------------------------------------------------------------ * UI Callbacks (optional) */ +void UI::uiScaleFactorChanged(double) +{ +} + +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI void UI::uiFocus(bool, DGL_NAMESPACE::CrossingMode) { } @@ -176,10 +198,6 @@ void UI::uiReshape(uint, uint) pData->fallbackOnResize(); } -void UI::uiScaleFactorChanged(double) -{ -} - # ifndef DGL_FILE_BROWSER_DISABLED void UI::uiFileBrowserSelected(const char*) { diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp @@ -19,10 +19,6 @@ #include "DistrhoUIPrivateData.hpp" -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -# include "../extra/Sleep.hpp" -#endif - START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- @@ -70,10 +66,8 @@ public: uiData->bgColor = bgColor; uiData->fgColor = fgColor; -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI uiData->scaleFactor = scaleFactor; uiData->winId = winId; -#endif uiData->callbacksPtr = callbacksPtr; uiData->editParamCallbackFunc = editParamCall; @@ -197,40 +191,7 @@ public: // ------------------------------------------------------------------- -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - void exec(DGL_NAMESPACE::IdleCallback* const cb) - { - DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->setVisible(true); - cb->idleCallback(); - - while (ui->isRunning()) - { - d_msleep(10); - cb->idleCallback(); - } - } - - bool idle() - { - return true; - } - - void focus() - { - } - - void quit() - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->setVisible(false); - ui->terminateAndWaitForProcess(); - } -#else -# if DISTRHO_UI_IS_STANDALONE +#if DISTRHO_UI_IS_STANDALONE void exec(DGL_NAMESPACE::IdleCallback* const cb) { DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); @@ -246,7 +207,7 @@ public: ui->uiIdle(); } -# else +#else bool plugin_idle() { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); @@ -255,7 +216,7 @@ public: ui->uiIdle(); return ! uiData->app.isQuiting(); } -# endif +#endif void focus() { @@ -269,50 +230,22 @@ public: if (uiData->app.isStandalone()) uiData->app.quit(); } -#endif // ------------------------------------------------------------------- -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - void setWindowTitle(const char* const uiTitle) - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->setTitle(uiTitle); - } - - void setWindowSize(const uint width, const uint height) - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->setSize(width, height); - } - - void setWindowTransientWinId(const uintptr_t winId) - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->setTransientWinId(winId); - } - - bool setWindowVisible(const bool yesNo) - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); - - ui->setVisible(yesNo); - - return ui->isRunning(); - } -#else void setWindowTitle(const char* const uiTitle) { uiData->window->setTitle(uiTitle); } - void setWindowTransientWinId(const uintptr_t /*winId*/) + void setWindowTransientWinId(const uintptr_t winId) { -#if 0 /* TODO */ +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + ui->setTransientWindowId(winId); +#elif 0 /* TODO */ glWindow.setTransientWinId(winId); +#else + (void)winId; #endif } @@ -323,6 +256,7 @@ public: return ! uiData->app.isQuiting(); } +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods) { // TODO also trigger Character input event diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp @@ -18,9 +18,11 @@ #define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED #include "../DistrhoUI.hpp" -#include "../../dgl/Application.hpp" -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "../extra/Sleep.hpp" +#else +# include "../../dgl/Application.hpp" # include "../../dgl/src/WindowPrivateData.hpp" # include "../../dgl/src/pugl.hpp" #endif @@ -31,18 +33,71 @@ # define DISTRHO_UI_IS_STANDALONE 0 #endif -#if defined(DISTRHO_PLUGIN_TARGET_VST2) +#if defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_VST3) # undef DISTRHO_UI_USER_RESIZABLE # define DISTRHO_UI_USER_RESIZABLE 0 #endif // ----------------------------------------------------------------------- +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +START_NAMESPACE_DISTRHO +#else START_NAMESPACE_DGL +#endif // ----------------------------------------------------------------------- // Plugin Application, will set class name based on plugin details +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +struct PluginApplication +{ + IdleCallback* idleCallback; + UI* ui; + + explicit PluginApplication() + : idleCallback(nullptr), + ui(nullptr) {} + + void addIdleCallback(IdleCallback* const cb) + { + idleCallback = cb; + } + + bool isQuiting() const noexcept + { + // TODO + return false; + } + + bool isStandalone() const noexcept + { + return DISTRHO_UI_IS_STANDALONE; + } + + void exec() + { + // TODO + while (ui->isRunning()) + { + d_msleep(10); + idleCallback->idleCallback(); + } + } + + void idle() + { + // TODO + } + + void quit() + { + // TODO + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) +}; +#else class PluginApplication : public Application { public: @@ -62,29 +117,32 @@ public: DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) }; +#endif // ----------------------------------------------------------------------- // Plugin Window, will pass some Window events to UI #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -// TODO external ui stuff class PluginWindow { - DISTRHO_NAMESPACE::UI* const ui; + UI* const ui; public: - explicit PluginWindow(DISTRHO_NAMESPACE::UI* const uiPtr, + explicit PluginWindow(UI* const uiPtr, PluginApplication& app, const uintptr_t parentWindowHandle, - const uint width, - const uint height, + uint, uint, // width and height const double scaleFactor) - : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE), - ui(uiPtr) {} + : ui(uiPtr) + { + app.ui = ui; + ui->pData.parentWindowHandle = parentWindowHandle; + ui->pData.scaleFactor = scaleFactor; + } uint getWidth() const noexcept { - return ui->getWidth(); + return ui->pData.width; } uint getHeight() const noexcept @@ -92,6 +150,11 @@ public: return ui->getHeight(); } + double getScaleFactor() const noexcept + { + return ui->getScaleFactor(); + } + bool isVisible() const noexcept { return ui->isRunning(); @@ -99,12 +162,36 @@ public: uintptr_t getNativeWindowHandle() const noexcept { - return 0; + return ui->getNativeWindowHandle(); + } + + void close() + { + } + + void focus() + { + ui->focus(); + } + + void show() + { + ui->show(); + } + + void setTitle(const char* const title) + { + ui->setTitle(title); + } + + void setVisible(const bool visible) + { + ui->setVisible(visible); } DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) }; -#else +#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI class PluginWindow : public Window { DISTRHO_NAMESPACE::UI* const ui; @@ -155,16 +242,22 @@ protected: DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) }; -#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +END_NAMESPACE_DISTRHO +#else END_NAMESPACE_DGL +#endif // ----------------------------------------------------------------------- START_NAMESPACE_DISTRHO +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI using DGL_NAMESPACE::PluginApplication; using DGL_NAMESPACE::PluginWindow; +#endif // ----------------------------------------------------------------------- // UI callbacks @@ -192,12 +285,10 @@ struct UI::PrivateData { // UI uint bgColor; uint fgColor; -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI double scaleFactor; uintptr_t winId; -# ifndef DGL_FILE_BROWSER_DISABLED +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) char* uiStateFileKeyRequest; -# endif #endif // Callbacks @@ -211,20 +302,16 @@ struct UI::PrivateData { PrivateData() noexcept : app(), -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI window(nullptr), -#endif sampleRate(0), parameterOffset(0), dspPtr(nullptr), bgColor(0), fgColor(0xffffffff), -#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI scaleFactor(1.0), winId(0), -# ifndef DGL_FILE_BROWSER_DISABLED +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) uiStateFileKeyRequest(nullptr), -# endif #endif callbacksPtr(nullptr), editParamCallbackFunc(nullptr), @@ -292,7 +379,11 @@ struct UI::PrivateData { bool fileRequestCallback(const char* const key); static UI::PrivateData* s_nextPrivateData; +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height); +#else static PluginWindow& createNextWindow(UI* ui, uint width, uint height); +#endif }; // -----------------------------------------------------------------------