diff --git a/dgl/Window.hpp b/dgl/Window.hpp index d1344669..b0abee25 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -104,6 +104,43 @@ public: }; #endif // DGL_FILE_BROWSER_DISABLED + /** + Window graphics context as a scoped struct. + This class gives graphics context drawing time to a window's widgets. + Typically used for allowing OpenGL drawing operations during a window + widget constructor. + + Unless you are subclassing the Window or StandaloneWindow classes, you do not need to care. + In such cases you will need to use this struct as a way to get a valid OpenGL context. + For example in a standalone application: + ``` + int main() + { + Application app; + Window win(app); + ScopedPointer widget; + { + const ScopedGraphicsContext sgc(win); + widget = new MyCustomTopLevelWidget(win); + } + app.exec(); + return 0; + } + ``` + + 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. + */ + class ScopedGraphicsContext + { + Window& window; + public: + explicit ScopedGraphicsContext(Window& window); + ~ScopedGraphicsContext(); + DISTRHO_DECLARE_NON_COPYABLE(ScopedGraphicsContext) + DISTRHO_PREVENT_HEAP_ALLOCATION + }; + /** Constructor for a regular, standalone window. */ @@ -362,9 +399,6 @@ public: DISTRHO_DEPRECATED_BY("runAsModal(bool)") inline void exec(bool blockWait = false) { runAsModal(blockWait); } - // TESTING, DO NOT USE - void leaveContext(); - protected: /** A function called when the window is attempted to be closed. @@ -414,6 +448,7 @@ private: struct PrivateData; PrivateData* const pData; friend class Application; + friend class PluginWindow; friend class TopLevelWidget; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index 0d2fa5db..10f77122 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -20,6 +20,20 @@ START_NAMESPACE_DGL +// ----------------------------------------------------------------------- +// ScopedGraphicsContext + +Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win) + : window(win) +{ + puglBackendEnter(window.pData->view); +} + +Window::ScopedGraphicsContext::~ScopedGraphicsContext() +{ + puglBackendLeave(window.pData->view); +} + // ----------------------------------------------------------------------- // Window @@ -265,11 +279,6 @@ void Window::runAsModal(bool blockWait) pData->runAsModal(blockWait); } -void Window::leaveContext() -{ - pData->leaveContext(); -} - void Window::setGeometryConstraints(const uint minimumWidth, const uint minimumHeight, const bool keepAspectRatio, diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index d1ae4f94..71151f1b 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -237,9 +237,6 @@ void Window::PrivateData::initPost() // create view now, as a few methods we allow devs to use require it puglRealize(view); - // FIXME this is bad, the enter/leave should be well scoped. try to find a better place for it.. - puglBackendEnter(view); - if (isEmbed) { appData->oneWindowShown(); @@ -630,14 +627,6 @@ void Window::PrivateData::runAsModal(const bool blockWait) } } -// ----------------------------------------------------------------------- -// TESTING - -void Window::PrivateData::leaveContext() -{ - puglBackendLeave(view); -} - // ----------------------------------------------------------------------- // pugl events diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index 2c48dbc0..2b950fc8 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -161,9 +161,6 @@ struct Window::PrivateData : IdleCallback { void stopModal(); void runAsModal(bool blockWait); - // TESTING - void leaveContext(); - // pugl events void onPuglConfigure(double width, double height); void onPuglExpose(); diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp index 07adfa47..316cc216 100644 --- a/distrho/DistrhoUI.hpp +++ b/distrho/DistrhoUI.hpp @@ -48,6 +48,10 @@ typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget; typedef DGL_NAMESPACE::TopLevelWidget UIWidget; #endif +START_NAMESPACE_DGL +class PluginWindow; +END_NAMESPACE_DGL + START_NAMESPACE_DISTRHO /* ------------------------------------------------------------------------------------------------------------ @@ -311,7 +315,7 @@ protected: private: struct PrivateData; PrivateData* const uiData; - friend class PluginWindow; + friend class DGL_NAMESPACE::PluginWindow; friend class UIExporter; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index 11b0c42f..3052ef4b 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -39,7 +39,7 @@ 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); + pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor); return pData->window.getObject(); } diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp index b8876090..425aaca7 100644 --- a/distrho/src/DistrhoUIPrivateData.hpp +++ b/distrho/src/DistrhoUIPrivateData.hpp @@ -20,8 +20,9 @@ #include "../DistrhoUI.hpp" #include "../../dgl/Application.hpp" -#ifndef DISTRHO_PLUGIN_HAS_EXTERNAL_UI -# include "../../dgl/Window.hpp" +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "../../dgl/src/WindowPrivateData.hpp" +# include "../../dgl/src/pugl.hpp" #endif #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) @@ -35,20 +36,9 @@ # define DISTRHO_UI_USER_RESIZABLE 0 #endif -START_NAMESPACE_DISTRHO - -using DGL_NAMESPACE::Application; -using DGL_NAMESPACE::Window; - // ----------------------------------------------------------------------- -// UI callbacks -typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); -typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); -typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); -typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); -typedef void (*setSizeFunc) (void* ptr, uint width, uint height); -typedef bool (*fileRequestFunc) (void* ptr, const char* key); +START_NAMESPACE_DGL // ----------------------------------------------------------------------- // Plugin Application, will set class name based on plugin details @@ -73,7 +63,136 @@ public: DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) }; -class PluginWindow; +// ----------------------------------------------------------------------- +// 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, + PluginApplication& app, + const uintptr_t parentWindowHandle, + const uint width, + const uint height, + const double scaleFactor) + : Window(app, parentWindowHandle, width, height, scaleFactor, 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, + PluginApplication& app, + const uintptr_t parentWindowHandle, + const uint width, + const uint height, + const double scaleFactor) + : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE), + ui(uiPtr) + { + puglBackendEnter(pData->view); + } + + void leaveContext() + { + puglBackendLeave(pData->view); + } + +protected: + void onFocus(const bool focus, const DGL_NAMESPACE::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); + } + + void onScaleFactorChanged(const double scaleFactor) override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + + ui->uiScaleFactorChanged(scaleFactor); + } + +# ifndef DGL_FILE_BROWSER_DISABLED + void onFileSelected(const char* const filename) override + { + DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); + +# if DISTRHO_PLUGIN_WANT_STATEFILES + if (char* const key = ui->uiData->uiStateFileKeyRequest) + { + ui->uiData->uiStateFileKeyRequest = nullptr; + // notify DSP + ui->setState(key, filename); + // notify UI + ui->stateChanged(key, filename); + std::free(key); + return; + } +# endif + + ui->uiFileBrowserSelected(filename); + } +# endif + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) +}; +#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + +END_NAMESPACE_DGL + +// ----------------------------------------------------------------------- + +START_NAMESPACE_DISTRHO + +using DGL_NAMESPACE::PluginApplication; +using DGL_NAMESPACE::PluginWindow; + +// ----------------------------------------------------------------------- +// UI callbacks + +typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); +typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); +typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); +typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); +typedef void (*setSizeFunc) (void* ptr, uint width, uint height); +typedef bool (*fileRequestFunc) (void* ptr, const char* key); // ----------------------------------------------------------------------- // UI private data @@ -194,100 +313,6 @@ struct UI::PrivateData { 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 DGL_NAMESPACE::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); - } - - void onScaleFactorChanged(const double scaleFactor) override - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - - ui->uiScaleFactorChanged(scaleFactor); - } - -# ifndef DGL_FILE_BROWSER_DISABLED - void onFileSelected(const char* const filename) override - { - DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); - -# if DISTRHO_PLUGIN_WANT_STATEFILES - if (char* const key = ui->uiData->uiStateFileKeyRequest) - { - ui->uiData->uiStateFileKeyRequest = nullptr; - // notify DSP - ui->setState(key, filename); - // notify UI - ui->stateChanged(key, filename); - std::free(key); - return; - } -# endif - - ui->uiFileBrowserSelected(filename); - } -# endif - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) -}; -#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI - // ----------------------------------------------------------------------- // UI private data fileRequestCallback, which requires PluginWindow definitions