Signed-off-by: falkTX <falktx@falktx.com>pull/281/head
| @@ -367,6 +367,10 @@ protected: | |||
| A function called when the window is attempted to be closed. | |||
| Returning true closes the window, which is the default behaviour. | |||
| Override this method and return false to prevent the window from being closed by the user. | |||
| This method is not used for embed windows, and not even made available in DISTRHO_NAMESPACE::UI. | |||
| For embed windows, closing is handled by the host/parent process and we have no control over it. | |||
| As such, a close action on embed windows will always succeed and cannot be cancelled. | |||
| */ | |||
| virtual bool onClose(); | |||
| @@ -237,26 +237,46 @@ protected: | |||
| * UI Callbacks (optional) */ | |||
| /** | |||
| uiIdle. | |||
| @TODO Document this. | |||
| UI idle function, called to give idle time to the plugin UI directly from the host. | |||
| This is called right after OS event handling and Window idle events (within the same cycle). | |||
| There are no guarantees in terms of timing. | |||
| @see addIdleCallback(IdleCallback*, uint). | |||
| */ | |||
| virtual void uiIdle() {} | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| File browser selected function. | |||
| @see Window::onFileSelected(const char*) | |||
| 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). | |||
| The default implementation does nothing. | |||
| */ | |||
| virtual void uiFileBrowserSelected(const char* filename); | |||
| # endif | |||
| virtual void uiFocus(bool focus, CrossingMode mode); | |||
| /** | |||
| OpenGL window reshape function, called when parent window is resized. | |||
| You can reimplement this function for a custom OpenGL state. | |||
| @see Window::onReshape(uint,uint) | |||
| Window reshape function, called when the window is resized. | |||
| 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. | |||
| 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); | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser(). | |||
| This function is for plugin UIs to be able to override Window::onFileSelected(const char*). | |||
| This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | |||
| The default implementation does nothing. | |||
| If you need to use files as plugin state, please setup and use DISTRHO_PLUGIN_WANT_STATEFILES instead. | |||
| */ | |||
| virtual void uiFileBrowserSelected(const char* filename); | |||
| # endif | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * UI Resize Handling, internal */ | |||
| @@ -265,7 +285,7 @@ protected: | |||
| This is overriden here so the host knows when the UI is resized by you. | |||
| @see Widget::onResize(const ResizeEvent&) | |||
| */ | |||
| void onResize(const ResizeEvent& ev) override; | |||
| // void onResize(const ResizeEvent& ev) override; | |||
| #endif | |||
| // ------------------------------------------------------------------------------------------------------- | |||
| @@ -273,8 +293,8 @@ protected: | |||
| private: | |||
| struct PrivateData; | |||
| PrivateData* const uiData; | |||
| friend class PluginWindow; | |||
| friend class UIExporter; | |||
| friend class UIExporterWindow; | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | |||
| }; | |||
| @@ -145,6 +145,9 @@ public: | |||
| /** Returns the object that this ScopedPointer refers to. */ | |||
| ObjectType* get() const noexcept { return object; } | |||
| /** Returns the object that this ScopedPointer refers to. */ | |||
| ObjectType& getObject() const noexcept { return *object; } | |||
| /** Returns the object that this ScopedPointer refers to. */ | |||
| ObjectType& operator*() const noexcept { return *object; } | |||
| @@ -17,7 +17,6 @@ | |||
| #include "DistrhoPluginInternal.hpp" | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| # define DISTRHO_UI_IS_STANDALONE true | |||
| # include "DistrhoUIInternal.hpp" | |||
| # include "../extra/RingBuffer.hpp" | |||
| #else | |||
| @@ -110,7 +109,9 @@ public: | |||
| PluginJack(jack_client_t* const client) | |||
| : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| fUI(this, 0, | |||
| fUI(this, | |||
| 0, // winId | |||
| d_lastSampleRate, | |||
| nullptr, // edit param | |||
| setParameterValueCallback, | |||
| setStateCallback, | |||
| @@ -301,7 +302,7 @@ protected: | |||
| } | |||
| } | |||
| fUI.exec_idle(); | |||
| fUI.idle(); | |||
| } | |||
| #endif | |||
| @@ -797,9 +798,6 @@ int main() | |||
| d_lastBufferSize = jack_get_buffer_size(client); | |||
| d_lastSampleRate = jack_get_sample_rate(client); | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| d_lastUiSampleRate = d_lastSampleRate; | |||
| #endif | |||
| const PluginJack p(client); | |||
| @@ -25,7 +25,6 @@ | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| # undef DISTRHO_UI_USER_RESIZABLE | |||
| # define DISTRHO_UI_USER_RESIZABLE 0 | |||
| # define DISTRHO_UI_IS_STANDALONE false | |||
| # include "DistrhoUIInternal.hpp" | |||
| # include "../extra/RingBuffer.hpp" | |||
| #endif | |||
| @@ -178,7 +177,7 @@ public: | |||
| fEffect(effect), | |||
| fUiHelper(uiHelper), | |||
| fPlugin(plugin), | |||
| fUI(this, winId, | |||
| fUI(this, winId, plugin->getSampleRate(), | |||
| editParameterCallback, | |||
| setParameterCallback, | |||
| setStateCallback, | |||
| @@ -671,9 +670,7 @@ public: | |||
| } | |||
| else | |||
| { | |||
| d_lastUiSampleRate = fPlugin.getSampleRate(); | |||
| UIExporter tmpUI(nullptr, 0, | |||
| UIExporter tmpUI(nullptr, 0,fPlugin.getSampleRate(), | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | |||
| fPlugin.getInstancePointer(), fLastScaleFactor); | |||
| fVstRect.right = tmpUI.getWidth(); | |||
| @@ -694,8 +691,6 @@ public: | |||
| return 0; | |||
| } | |||
| # endif | |||
| d_lastUiSampleRate = fPlugin.getSampleRate(); | |||
| fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr, fLastScaleFactor); | |||
| # if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
| @@ -20,71 +20,38 @@ | |||
| # include "src/TopLevelWidgetPrivateData.hpp" | |||
| #endif | |||
| #include "NanoVG.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Static data, see DistrhoUIInternal.hpp and DistrhoUIPrivateData.hpp */ | |||
| * Static data, see DistrhoUIInternal.hpp */ | |||
| double d_lastUiSampleRate = 0.0; | |||
| void* d_lastUiDspPtr = nullptr; | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| const char* g_nextBundlePath = nullptr; | |||
| double g_nextScaleFactor = 1.0; | |||
| uintptr_t g_nextWindowId = 0; | |||
| #else | |||
| Window* d_lastUiWindow = nullptr; | |||
| uintptr_t g_nextWindowId = 0; | |||
| double g_nextScaleFactor = 1.0; | |||
| const char* g_nextBundlePath = nullptr; | |||
| #endif | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * UI::PrivateData special handling */ | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath) | |||
| { | |||
| d_lastUiDspPtr = dspPtr; | |||
| g_nextWindowId = winId; | |||
| g_nextScaleFactor = scaleFactor; | |||
| g_nextBundlePath = bundlePath; | |||
| UI* const ret = createUI(); | |||
| d_lastUiDspPtr = nullptr; | |||
| g_nextWindowId = 0; | |||
| g_nextScaleFactor = 1.0; | |||
| g_nextBundlePath = nullptr; | |||
| return ret; | |||
| } | |||
| #else | |||
| UI* createUiWrapper(void* const dspPtr, Window* const window) | |||
| { | |||
| d_lastUiDspPtr = dspPtr; | |||
| d_lastUiWindow = window; | |||
| UI* const ret = createUI(); | |||
| d_lastUiDspPtr = nullptr; | |||
| d_lastUiWindow = nullptr; | |||
| return ret; | |||
| } | |||
| #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr; | |||
| PluginWindow& UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint height) | |||
| { | |||
| UI::PrivateData* const pData = s_nextPrivateData; | |||
| pData->window = new PluginWindow(ui, pData, width, height); | |||
| return pData->window.getObject(); | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * UI */ | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| UI::UI(uint width, uint height) | |||
| : UIWidget(width, height), | |||
| uiData(new PrivateData()) {} | |||
| #else | |||
| UI::UI(uint width, uint height) | |||
| : UIWidget(*d_lastUiWindow), | |||
| uiData(new PrivateData()) | |||
| { | |||
| if (width > 0 && height > 0) | |||
| setSize(width, height); | |||
| } | |||
| #endif | |||
| UI::UI(const uint width, const uint height) | |||
| : UIWidget(UI::PrivateData::createNextWindow(this, width, height)), | |||
| uiData(UI::PrivateData::s_nextPrivateData) {} | |||
| UI::~UI() | |||
| { | |||
| delete uiData; | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -166,22 +133,22 @@ uintptr_t UI::getNextWindowId() noexcept | |||
| return g_nextWindowId; | |||
| } | |||
| # endif | |||
| #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| #endif | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * DSP/Plugin Callbacks (optional) */ | |||
| void UI::sampleRateChanged(double) {} | |||
| void UI::sampleRateChanged(double) | |||
| { | |||
| } | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * UI Callbacks (optional) */ | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| void UI::uiFileBrowserSelected(const char*) | |||
| void UI::uiFocus(bool, CrossingMode) | |||
| { | |||
| } | |||
| # endif | |||
| void UI::uiReshape(uint, uint) | |||
| { | |||
| @@ -189,33 +156,32 @@ void UI::uiReshape(uint, uint) | |||
| pData->fallbackOnResize(); | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * UI Resize Handling, internal */ | |||
| void UI::onResize(const ResizeEvent& ev) | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| void UI::uiFileBrowserSelected(const char*) | |||
| { | |||
| if (uiData->resizeInProgress) | |||
| return; | |||
| UIWidget::onResize(ev); | |||
| } | |||
| # endif | |||
| const uint width = ev.size.getWidth(); | |||
| const uint height = ev.size.getHeight(); | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * UI Resize Handling, internal */ | |||
| /* | |||
| pData->window.setSize(width, height); | |||
| */ | |||
| uiData->setSizeCallback(width, height); | |||
| } | |||
| // void UI::onResize(const ResizeEvent& ev) | |||
| // { | |||
| // if (uiData->resizeInProgress) | |||
| // return; | |||
| // | |||
| // UIWidget::onResize(ev); | |||
| // | |||
| // const uint width = ev.size.getWidth(); | |||
| // const uint height = ev.size.getHeight(); | |||
| // | |||
| // /* | |||
| // pData->window.setSize(width, height); | |||
| // */ | |||
| // uiData->setSizeCallback(width, height); | |||
| // } | |||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| // Possible template data types | |||
| // template class NanoBaseWidget<SubWidget>; | |||
| // template class NanoBaseWidget<TopLevelWidget>; | |||
| // template class NanoBaseWidget<StandaloneWindow>; | |||
| @@ -14,7 +14,6 @@ | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #define DISTRHO_UI_IS_STANDALONE true | |||
| #include "DistrhoUIInternal.hpp" | |||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| @@ -97,8 +96,9 @@ struct OscData { | |||
| class UIDssi | |||
| { | |||
| public: | |||
| UIDssi(const OscData& oscData, const char* const uiTitle) | |||
| : fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, nullptr), | |||
| UIDssi(const OscData& oscData, const char* const uiTitle, const double sampleRate) | |||
| : fUI(this, 0, sampleRate, nullptr, | |||
| setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, nullptr), | |||
| fHostClosed(false), | |||
| fOscData(oscData) | |||
| { | |||
| @@ -252,16 +252,17 @@ private: | |||
| static OscData gOscData; | |||
| static const char* gUiTitle = nullptr; | |||
| static UIDssi* globalUI = nullptr; | |||
| static double sampleRate = 0.0; | |||
| static void initUiIfNeeded() | |||
| { | |||
| if (globalUI != nullptr) | |||
| return; | |||
| if (d_lastUiSampleRate == 0.0) | |||
| d_lastUiSampleRate = 44100.0; | |||
| if (sampleRate == 0.0) | |||
| sampleRate = 44100.0; | |||
| globalUI = new UIDssi(gOscData, gUiTitle); | |||
| globalUI = new UIDssi(gOscData, gUiTitle, sampleRate); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -337,10 +338,8 @@ int osc_program_handler(const char*, const char*, lo_arg** argv, int, lo_message | |||
| int osc_sample_rate_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*) | |||
| { | |||
| const int32_t sampleRate = argv[0]->i; | |||
| d_debug("osc_sample_rate_handler(%i)", sampleRate); | |||
| d_lastUiSampleRate = sampleRate; | |||
| sampleRate = argv[0]->i; | |||
| d_debug("osc_sample_rate_handler(%f)", sampleRate); | |||
| if (globalUI != nullptr) | |||
| globalUI->dssiui_samplerate(sampleRate); | |||
| @@ -481,7 +480,7 @@ int main(int argc, char* argv[]) | |||
| { | |||
| lo_server_recv(oscServer); | |||
| if (d_lastUiSampleRate != 0.0 || globalUI != nullptr) | |||
| if (sampleRate != 0.0 || globalUI != nullptr) | |||
| break; | |||
| d_msleep(50); | |||
| @@ -489,7 +488,7 @@ int main(int argc, char* argv[]) | |||
| int ret = 1; | |||
| if (d_lastUiSampleRate != 0.0 || globalUI != nullptr) | |||
| if (sampleRate != 0.0 || globalUI != nullptr) | |||
| { | |||
| initUiIfNeeded(); | |||
| @@ -21,13 +21,6 @@ | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| # include "../extra/Sleep.hpp" | |||
| using DGL_NAMESPACE::IdleCallback; | |||
| #else | |||
| # include "../../dgl/Application.hpp" | |||
| # include "../../dgl/Window.hpp" | |||
| using DGL_NAMESPACE::Application; | |||
| using DGL_NAMESPACE::IdleCallback; | |||
| using DGL_NAMESPACE::Window; | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| @@ -35,121 +28,32 @@ START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| // Static data, see DistrhoUI.cpp | |||
| extern double d_lastUiSampleRate; | |||
| extern void* d_lastUiDspPtr; | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| extern const char* g_nextBundlePath; | |||
| extern double g_nextScaleFactor; | |||
| extern uintptr_t g_nextWindowId; | |||
| #else | |||
| extern Window* d_lastUiWindow; | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath); | |||
| #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| UI* createUiWrapper(void* const dspPtr, Window* const window); | |||
| #endif | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // ----------------------------------------------------------------------- | |||
| // Plugin Application, will set class name based on plugin details | |||
| class PluginApplication : public Application | |||
| { | |||
| public: | |||
| PluginApplication() | |||
| : Application(DISTRHO_UI_IS_STANDALONE) | |||
| { | |||
| const char* const className = ( | |||
| #ifdef DISTRHO_PLUGIN_BRAND | |||
| DISTRHO_PLUGIN_BRAND | |||
| #else | |||
| DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) | |||
| extern double g_nextScaleFactor; | |||
| extern const char* g_nextBundlePath; | |||
| #endif | |||
| "-" DISTRHO_PLUGIN_NAME | |||
| ); | |||
| setClassName(className); | |||
| } | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // Plugin Window, needed to take care of resize properly | |||
| // UI exporter class | |||
| class UIExporterWindow : public Window | |||
| class UIExporter | |||
| { | |||
| public: | |||
| UIExporterWindow(PluginApplication& app, const intptr_t winId, const double scaleFactor, void* const dspPtr) | |||
| : Window(app, winId, scaleFactor, DISTRHO_UI_USER_RESIZABLE), | |||
| fUI(createUiWrapper(dspPtr, this)), | |||
| fIsReady(false) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI->uiData != nullptr,); | |||
| setSize(fUI->getWidth(), fUI->getHeight()); | |||
| } | |||
| ~UIExporterWindow() | |||
| { | |||
| delete fUI; | |||
| } | |||
| UI* getUI() const noexcept | |||
| { | |||
| return fUI; | |||
| } | |||
| bool isReady() const noexcept | |||
| { | |||
| return fIsReady; | |||
| } | |||
| protected: | |||
| // custom window reshape | |||
| void onReshape(uint width, uint height) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| UI::PrivateData* const uiData = fUI->uiData; | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | |||
| /* | |||
| uiData->resizeInProgress = true; | |||
| fUI->setSize(width, height); | |||
| uiData->resizeInProgress = false; | |||
| */ | |||
| fUI->uiReshape(width, height); | |||
| fIsReady = true; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // UI Widget and its private data | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| // custom file-browser selected | |||
| void onFileSelected(const char* const filename) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| UI* ui; | |||
| UI::PrivateData* uiData; | |||
| fUI->uiFileBrowserSelected(filename); | |||
| } | |||
| # endif | |||
| // prevent resize recursion | |||
| bool changingSizeRecursionCheck; | |||
| private: | |||
| UI* const fUI; | |||
| bool fIsReady; | |||
| }; | |||
| #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // ----------------------------------------------------------------------- | |||
| // UI exporter class | |||
| // ------------------------------------------------------------------- | |||
| class UIExporter | |||
| { | |||
| public: | |||
| UIExporter(void* const callbacksPtr, | |||
| const intptr_t winId, | |||
| const uintptr_t winId, | |||
| const double sampleRate, | |||
| const editParamFunc editParamCall, | |||
| const setParamFunc setParamCall, | |||
| const setStateFunc setStateCall, | |||
| @@ -161,139 +65,130 @@ public: | |||
| const double scaleFactor = 1.0, | |||
| const uint32_t bgColor = 0, | |||
| const uint32_t fgColor = 0xffffffff) | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| : fUI(createUiWrapper(dspPtr, winId, scaleFactor, bundlePath)), | |||
| #else | |||
| : glApp(), | |||
| glWindow(glApp, winId, scaleFactor, dspPtr), | |||
| fChangingSize(false), | |||
| fUI(glWindow.getUI()), | |||
| #endif | |||
| fData((fUI != nullptr) ? fUI->uiData : nullptr) | |||
| : ui(nullptr), | |||
| uiData(new UI::PrivateData()), | |||
| changingSizeRecursionCheck(false) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
| fData->bgColor = bgColor; | |||
| fData->fgColor = fgColor; | |||
| fData->callbacksPtr = callbacksPtr; | |||
| fData->editParamCallbackFunc = editParamCall; | |||
| fData->setParamCallbackFunc = setParamCall; | |||
| fData->setStateCallbackFunc = setStateCall; | |||
| fData->sendNoteCallbackFunc = sendNoteCall; | |||
| fData->setSizeCallbackFunc = setSizeCall; | |||
| fData->fileRequestCallbackFunc = fileRequestCall; | |||
| uiData->sampleRate = sampleRate; | |||
| uiData->dspPtr = dspPtr; | |||
| uiData->bgColor = bgColor; | |||
| uiData->fgColor = fgColor; | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // unused | |||
| return; (void)bundlePath; | |||
| uiData->scaleFactor = scaleFactor; | |||
| uiData->winId = winId; | |||
| #endif | |||
| } | |||
| uiData->callbacksPtr = callbacksPtr; | |||
| uiData->editParamCallbackFunc = editParamCall; | |||
| uiData->setParamCallbackFunc = setParamCall; | |||
| uiData->setStateCallbackFunc = setStateCall; | |||
| uiData->sendNoteCallbackFunc = sendNoteCall; | |||
| uiData->setSizeCallbackFunc = setSizeCall; | |||
| uiData->fileRequestCallbackFunc = fileRequestCall; | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| ~UIExporter() | |||
| { | |||
| delete fUI; | |||
| } | |||
| g_nextWindowId = winId; | |||
| g_nextScaleFactor = scaleFactor; | |||
| g_nextBundlePath = bundlePath; | |||
| #endif | |||
| UI::PrivateData::s_nextPrivateData = uiData; | |||
| // ------------------------------------------------------------------- | |||
| UI* const uiPtr = createUI(); | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| uint getWidth() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | |||
| return fUI->getWidth(); | |||
| } | |||
| g_nextWindowId = 0; | |||
| g_nextScaleFactor = 0.0; | |||
| g_nextBundlePath = nullptr; | |||
| #endif | |||
| UI::PrivateData::s_nextPrivateData = nullptr; | |||
| uint getHeight() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | |||
| return fUI->getHeight(); | |||
| } | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,); | |||
| ui = uiPtr; | |||
| bool isVisible() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||
| return fUI->isRunning(); | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // unused | |||
| (void)bundlePath; | |||
| #endif | |||
| } | |||
| uintptr_t getNativeWindowHandle() const noexcept | |||
| ~UIExporter() | |||
| { | |||
| return 0; | |||
| delete ui; | |||
| delete uiData; | |||
| } | |||
| #else | |||
| // ------------------------------------------------------------------- | |||
| uint getWidth() const noexcept | |||
| { | |||
| return glWindow.getWidth(); | |||
| return uiData->window->getWidth(); | |||
| } | |||
| uint getHeight() const noexcept | |||
| { | |||
| return glWindow.getHeight(); | |||
| return uiData->window->getHeight(); | |||
| } | |||
| bool isVisible() const noexcept | |||
| { | |||
| return glWindow.isVisible(); | |||
| return uiData->window->isVisible(); | |||
| } | |||
| uintptr_t getNativeWindowHandle() const noexcept | |||
| { | |||
| return glWindow.getNativeWindowHandle(); | |||
| return uiData->window->getNativeWindowHandle(); | |||
| } | |||
| #endif | |||
| uint getBackgroundColor() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0); | |||
| return fData->bgColor; | |||
| return uiData->bgColor; | |||
| } | |||
| uint getForegroundColor() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0xffffffff); | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff); | |||
| return fData->fgColor; | |||
| return uiData->fgColor; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| uint32_t getParameterOffset() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0); | |||
| return fData->parameterOffset; | |||
| return uiData->parameterOffset; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void parameterChanged(const uint32_t index, const float value) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->parameterChanged(index, value); | |||
| ui->parameterChanged(index, value); | |||
| } | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| void programLoaded(const uint32_t index) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->programLoaded(index); | |||
| ui->programLoaded(index); | |||
| } | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| void stateChanged(const char* const key, const char* const value) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | |||
| DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); | |||
| fUI->stateChanged(key, value); | |||
| ui->stateChanged(key, value); | |||
| } | |||
| #endif | |||
| @@ -303,12 +198,12 @@ public: | |||
| void exec(IdleCallback* const cb) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->setVisible(true); | |||
| ui->setVisible(true); | |||
| cb->idleCallback(); | |||
| while (fUI->isRunning()) | |||
| while (ui->isRunning()) | |||
| { | |||
| d_msleep(10); | |||
| cb->idleCallback(); | |||
| @@ -330,49 +225,38 @@ public: | |||
| void quit() | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->setVisible(false); | |||
| fUI->terminateAndWaitForProcess(); | |||
| ui->setVisible(false); | |||
| ui->terminateAndWaitForProcess(); | |||
| } | |||
| #else | |||
| void exec(IdleCallback* const cb) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| glWindow.setVisible(true); | |||
| glApp.addIdleCallback(cb); | |||
| glApp.exec(); | |||
| } | |||
| void exec_idle() | |||
| { | |||
| if (glWindow.isReady()) | |||
| fUI->uiIdle(); | |||
| uiData->window->show(); | |||
| uiData->app.addIdleCallback(cb); | |||
| uiData->app.exec(); | |||
| } | |||
| void focus() | |||
| { | |||
| glWindow.focus(); | |||
| uiData->window->focus(); | |||
| } | |||
| bool idle() | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | |||
| glApp.idle(); | |||
| if (glWindow.isReady()) | |||
| fUI->uiIdle(); | |||
| return ! glApp.isQuiting(); | |||
| ui->uiIdle(); | |||
| return ! uiData->app.isQuiting(); | |||
| } | |||
| void quit() | |||
| { | |||
| glWindow.close(); | |||
| glApp.quit(); | |||
| uiData->window->close(); | |||
| uiData->app.quit(); | |||
| } | |||
| #endif | |||
| @@ -381,52 +265,46 @@ public: | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| void setWindowTitle(const char* const uiTitle) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->setTitle(uiTitle); | |||
| ui->setTitle(uiTitle); | |||
| } | |||
| void setWindowSize(const uint width, const uint height, const bool = false) | |||
| void setWindowSize(const uint width, const uint height) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->setSize(width, height); | |||
| ui->setSize(width, height); | |||
| } | |||
| void setWindowTransientWinId(const uintptr_t winId) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| fUI->setTransientWinId(winId); | |||
| ui->setTransientWinId(winId); | |||
| } | |||
| bool setWindowVisible(const bool yesNo) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | |||
| fUI->setVisible(yesNo); | |||
| ui->setVisible(yesNo); | |||
| return fUI->isRunning(); | |||
| return ui->isRunning(); | |||
| } | |||
| #else | |||
| void setWindowTitle(const char* const uiTitle) | |||
| { | |||
| glWindow.setTitle(uiTitle); | |||
| // glWindow.setTitle(uiTitle); | |||
| } | |||
| void setWindowSize(const uint width, const uint height, const bool updateUI = false) | |||
| void setWindowSize(const uint width, const uint height) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(! fChangingSize,); | |||
| fChangingSize = true; | |||
| DISTRHO_SAFE_ASSERT_RETURN(! changingSizeRecursionCheck,); | |||
| if (updateUI) | |||
| fUI->setSize(width, height); | |||
| glWindow.setSize(width, height); | |||
| fChangingSize = false; | |||
| changingSizeRecursionCheck = true; | |||
| // glWindow.setSize(width, height); | |||
| changingSizeRecursionCheck = false; | |||
| } | |||
| void setWindowTransientWinId(const uintptr_t /*winId*/) | |||
| @@ -438,9 +316,10 @@ public: | |||
| bool setWindowVisible(const bool yesNo) | |||
| { | |||
| glWindow.setVisible(yesNo); | |||
| // glWindow.setVisible(yesNo); | |||
| return ! glApp.isQuiting(); | |||
| // return ! glApp.isQuiting(); | |||
| return true; | |||
| } | |||
| bool handlePluginKeyboard(const bool /*press*/, const uint /*key*/, const uint16_t /*mods*/) | |||
| @@ -464,37 +343,19 @@ public: | |||
| void setSampleRate(const double sampleRate, const bool doCallback = false) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | |||
| DISTRHO_SAFE_ASSERT(sampleRate > 0.0); | |||
| if (d_isEqual(fData->sampleRate, sampleRate)) | |||
| if (d_isEqual(uiData->sampleRate, sampleRate)) | |||
| return; | |||
| fData->sampleRate = sampleRate; | |||
| uiData->sampleRate = sampleRate; | |||
| if (doCallback) | |||
| fUI->sampleRateChanged(sampleRate); | |||
| ui->sampleRateChanged(sampleRate); | |||
| } | |||
| private: | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // ------------------------------------------------------------------- | |||
| // DGL Application and Window for this widget | |||
| PluginApplication glApp; | |||
| UIExporterWindow glWindow; | |||
| // prevent recursion | |||
| bool fChangingSize; | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| // Widget and DistrhoUI data | |||
| UI* const fUI; | |||
| UI::PrivateData* const fData; | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter) | |||
| }; | |||
| @@ -14,7 +14,6 @@ | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #define DISTRHO_UI_IS_STANDALONE false | |||
| #include "DistrhoUIInternal.hpp" | |||
| #include "../extra/String.hpp" | |||
| @@ -73,10 +72,11 @@ public: | |||
| const LV2UI_Write_Function writeFunc, | |||
| LV2UI_Widget* const widget, | |||
| void* const dspPtr, | |||
| const float sampleRate, | |||
| const float scaleFactor, | |||
| const uint32_t bgColor, | |||
| const uint32_t fgColor) | |||
| : fUI(this, winId, | |||
| : fUI(this, winId, sampleRate, | |||
| editParameterCallback, | |||
| setParameterCallback, | |||
| setStateCallback, | |||
| @@ -208,7 +208,8 @@ public: | |||
| int lv2ui_resize(uint width, uint height) | |||
| { | |||
| fUI.setWindowSize(width, height, true); | |||
| // FIXME | |||
| // fUI.setWindowSize(width, height, true); | |||
| return 0; | |||
| } | |||
| @@ -526,6 +527,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| #endif | |||
| const intptr_t winId = (intptr_t)parentId; | |||
| float sampleRate = 0.0f; | |||
| float scaleFactor = 1.0f; | |||
| uint32_t bgColor = 0; | |||
| uint32_t fgColor = 0xffffffff; | |||
| @@ -544,7 +546,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| /**/ if (options[i].key == uridSampleRate) | |||
| { | |||
| if (options[i].type == uridAtomFloat) | |||
| d_lastUiSampleRate = *(const float*)options[i].value; | |||
| sampleRate = *(const float*)options[i].value; | |||
| else | |||
| d_stderr("Host provides UI sample-rate but has wrong value type"); | |||
| } | |||
| @@ -572,15 +574,15 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| } | |||
| } | |||
| if (d_lastUiSampleRate < 1.0) | |||
| if (sampleRate < 1.0) | |||
| { | |||
| d_stdout("WARNING: this host does not send sample-rate information for LV2 UIs, using 44100 as fallback (this could be wrong)"); | |||
| d_lastUiSampleRate = 44100.0; | |||
| sampleRate = 44100.0; | |||
| } | |||
| return new UiLv2(bundlePath, winId, options, uridMap, features, | |||
| controller, writeFunction, widget, instance, | |||
| scaleFactor, bgColor, fgColor); | |||
| sampleRate, scaleFactor, bgColor, fgColor); | |||
| } | |||
| #define uiPtr ((UiLv2*)ui) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2020 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 | |||
| @@ -18,14 +18,22 @@ | |||
| #define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED | |||
| #include "../DistrhoUI.hpp" | |||
| #include "../../dgl/Application.hpp" | |||
| START_NAMESPACE_DISTRHO | |||
| #ifndef DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| # include "../../dgl/Window.hpp" | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Static data, see DistrhoUI.cpp | |||
| #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) | |||
| # define DISTRHO_UI_IS_STANDALONE true | |||
| #else | |||
| # define DISTRHO_UI_IS_STANDALONE false | |||
| #endif | |||
| extern double d_lastUiSampleRate; | |||
| extern void* d_lastUiDspPtr; | |||
| START_NAMESPACE_DISTRHO | |||
| using DGL_NAMESPACE::Application; | |||
| using DGL_NAMESPACE::Window; | |||
| // ----------------------------------------------------------------------- | |||
| // UI callbacks | |||
| @@ -37,24 +45,51 @@ typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8 | |||
| typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |||
| typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |||
| // ----------------------------------------------------------------------- | |||
| // Plugin Application, will set class name based on plugin details | |||
| class PluginApplication : public Application | |||
| { | |||
| public: | |||
| explicit PluginApplication() | |||
| : Application(DISTRHO_UI_IS_STANDALONE) | |||
| { | |||
| const char* const className = ( | |||
| #ifdef DISTRHO_PLUGIN_BRAND | |||
| DISTRHO_PLUGIN_BRAND | |||
| #else | |||
| DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) | |||
| #endif | |||
| "-" DISTRHO_PLUGIN_NAME | |||
| ); | |||
| setClassName(className); | |||
| } | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
| }; | |||
| class PluginWindow; | |||
| // ----------------------------------------------------------------------- | |||
| // UI private data | |||
| struct UI::PrivateData { | |||
| // DGL | |||
| PluginApplication app; | |||
| ScopedPointer<PluginWindow> window; | |||
| // DSP | |||
| double sampleRate; | |||
| uint32_t parameterOffset; | |||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| void* dspPtr; | |||
| #endif | |||
| // UI | |||
| bool automaticallyScale; | |||
| bool resizeInProgress; | |||
| uint minWidth; | |||
| uint minHeight; | |||
| uint bgColor; | |||
| uint fgColor; | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| double scaleFactor; | |||
| uintptr_t winId; | |||
| #endif | |||
| // Callbacks | |||
| void* callbacksPtr; | |||
| @@ -66,17 +101,19 @@ struct UI::PrivateData { | |||
| fileRequestFunc fileRequestCallbackFunc; | |||
| PrivateData() noexcept | |||
| : sampleRate(d_lastUiSampleRate), | |||
| parameterOffset(0), | |||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| dspPtr(d_lastUiDspPtr), | |||
| : app(), | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| window(nullptr), | |||
| #endif | |||
| automaticallyScale(false), | |||
| resizeInProgress(false), | |||
| minWidth(0), | |||
| minHeight(0), | |||
| sampleRate(0), | |||
| parameterOffset(0), | |||
| dspPtr(nullptr), | |||
| bgColor(0), | |||
| fgColor(0), | |||
| fgColor(0xffffffff), | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| scaleFactor(1.0), | |||
| winId(0), | |||
| #endif | |||
| callbacksPtr(nullptr), | |||
| editParamCallbackFunc(nullptr), | |||
| setParamCallbackFunc(nullptr), | |||
| @@ -85,8 +122,6 @@ struct UI::PrivateData { | |||
| setSizeCallbackFunc(nullptr), | |||
| fileRequestCallbackFunc(nullptr) | |||
| { | |||
| DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | |||
| #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) | |||
| parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; | |||
| # if DISTRHO_PLUGIN_WANT_LATENCY | |||
| @@ -143,7 +178,84 @@ struct UI::PrivateData { | |||
| return false; | |||
| } | |||
| static UI::PrivateData* s_nextPrivateData; | |||
| static PluginWindow& createNextWindow(UI* ui, uint width, uint height); | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // Plugin Window, will pass some Window events to UI | |||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // TODO external ui stuff | |||
| class PluginWindow | |||
| { | |||
| UI* const ui; | |||
| public: | |||
| explicit PluginWindow(UI* const uiPtr, UI::PrivateData* const pData, const uint width, const uint height) | |||
| : Window(pData->app, pData->winId, pData->scaleFactor, width, height, DISTRHO_UI_USER_RESIZABLE), | |||
| ui(uiPtr) {} | |||
| uint getWidth() const noexcept | |||
| { | |||
| return ui->getWidth(); | |||
| } | |||
| uint getHeight() const noexcept | |||
| { | |||
| return ui->getHeight(); | |||
| } | |||
| bool isVisible() const noexcept | |||
| { | |||
| return ui->isRunning(); | |||
| } | |||
| uintptr_t getNativeWindowHandle() const noexcept | |||
| { | |||
| return 0; | |||
| } | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
| }; | |||
| #else | |||
| class PluginWindow : public Window | |||
| { | |||
| UI* const ui; | |||
| public: | |||
| explicit PluginWindow(UI* const uiPtr, UI::PrivateData* const pData, const uint width, const uint height) | |||
| : Window(pData->app, pData->winId, width, height, pData->scaleFactor, DISTRHO_UI_USER_RESIZABLE), | |||
| ui(uiPtr) {} | |||
| protected: | |||
| void onFocus(const bool focus, const CrossingMode mode) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| ui->uiFocus(focus, mode); | |||
| } | |||
| void onReshape(const uint width, const uint height) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| ui->uiReshape(width, height); | |||
| } | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| void onFileSelected(const char* const filename) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
| ui->uiFileBrowserSelected(filename); | |||
| } | |||
| # endif | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
| }; | |||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| // ----------------------------------------------------------------------- | |||