Browse Source

Update DPF, make ProM buildable no matter what

master
falkTX 2 weeks ago
parent
commit
5c201852b6
100 changed files with 7017 additions and 481 deletions
  1. +0
    -9
      Makefile
  2. +15
    -1
      dpf/Makefile.base.mk
  3. +1
    -1
      dpf/dgl/Application.hpp
  4. +4
    -0
      dpf/dgl/Makefile
  5. +10
    -3
      dpf/dgl/OpenGL.hpp
  6. +15
    -12
      dpf/dgl/Window.hpp
  7. +1
    -1
      dpf/dgl/src/Application.cpp
  8. +1
    -0
      dpf/dgl/src/ApplicationPrivateData.cpp
  9. +32
    -3
      dpf/dgl/src/NanoVG.cpp
  10. +30
    -1
      dpf/dgl/src/Window.cpp
  11. +36
    -11
      dpf/dgl/src/WindowPrivateData.cpp
  12. +2
    -2
      dpf/dgl/src/WindowPrivateData.hpp
  13. +3
    -1
      dpf/dgl/src/nanovg/nanovg_gl.h
  14. +4
    -0
      dpf/dgl/src/pugl-upstream/src/mac.m
  15. +10
    -6
      dpf/dgl/src/pugl-upstream/src/x11.c
  16. +51
    -4
      dpf/dgl/src/pugl.cpp
  17. +2
    -2
      dpf/distrho/DistrhoPlugin.hpp
  18. +12
    -12
      dpf/distrho/DistrhoUI.hpp
  19. +433
    -91
      dpf/distrho/extra/ExternalWindow.hpp
  20. +2
    -0
      dpf/distrho/src/DistrhoPluginJACK.cpp
  21. +22
    -26
      dpf/distrho/src/DistrhoPluginVST2.cpp
  22. +31
    -7
      dpf/distrho/src/DistrhoUI.cpp
  23. +13
    -78
      dpf/distrho/src/DistrhoUIInternal.hpp
  24. +122
    -43
      dpf/distrho/src/DistrhoUIPrivateData.hpp
  25. +3
    -3
      dpf/tests/Application.cpp
  26. +1
    -8
      dpf/tests/Makefile
  27. +4
    -1
      dpf/tests/NanoSubWidgets.cpp
  28. +1
    -1
      get-plugins.sh
  29. +4
    -3
      plugins/ProM/DistrhoPluginInfo.h
  30. +9
    -5
      plugins/ProM/DistrhoPluginProM.cpp
  31. +219
    -143
      plugins/ProM/DistrhoUIProM.cpp
  32. +3
    -1
      plugins/ProM/DistrhoUIProM.hpp
  33. +164
    -2
      plugins/ProM/Makefile
  34. +180
    -0
      plugins/ProM/ResizeHandle.hpp
  35. +15
    -0
      plugins/ProM/config.h
  36. +184
    -0
      plugins/ProM/projectM/.appveyor.yml
  37. +40
    -0
      plugins/ProM/projectM/.circleci/config.yml
  38. +66
    -0
      plugins/ProM/projectM/.clang-format
  39. +12
    -0
      plugins/ProM/projectM/.github/FUNDING.yml
  40. +25
    -0
      plugins/ProM/projectM/.github/ISSUE_TEMPLATE/bug_report.md
  41. +20
    -0
      plugins/ProM/projectM/.github/ISSUE_TEMPLATE/feature_request.md
  42. +24
    -0
      plugins/ProM/projectM/.github/workflows/build.cmake
  43. +37
    -0
      plugins/ProM/projectM/.github/workflows/build_cmake.yml
  44. +39
    -0
      plugins/ProM/projectM/.github/workflows/configure.cmake
  45. +47
    -0
      plugins/ProM/projectM/.github/workflows/install_prerequisites.cmake
  46. +21
    -0
      plugins/ProM/projectM/.github/workflows/package.cmake
  47. +60
    -0
      plugins/ProM/projectM/.gitignore
  48. +78
    -0
      plugins/ProM/projectM/.travis.yml
  49. +60
    -0
      plugins/ProM/projectM/AUTHORS.txt
  50. +297
    -0
      plugins/ProM/projectM/BUILDING-cmake.md
  51. +415
    -0
      plugins/ProM/projectM/BUILDING.md
  52. +1
    -0
      plugins/ProM/projectM/CHANGES.md
  53. +271
    -0
      plugins/ProM/projectM/CMakeLists.txt
  54. +285
    -0
      plugins/ProM/projectM/Installer.xcodeproj/project.pbxproj
  55. +67
    -0
      plugins/ProM/projectM/Installer.xcodeproj/xcshareddata/xcschemes/ProjectM Installer.xcscheme
  56. +460
    -0
      plugins/ProM/projectM/LICENSE.txt
  57. +19
    -0
      plugins/ProM/projectM/LLVM_README.md
  58. +54
    -0
      plugins/ProM/projectM/Makefile.am
  59. +152
    -0
      plugins/ProM/projectM/README.md
  60. +9
    -0
      plugins/ProM/projectM/autogen.sh
  61. BIN
      plugins/ProM/projectM/background.png
  62. +26
    -0
      plugins/ProM/projectM/cmake/CheckEnumValueExists.cmake
  63. +47
    -0
      plugins/ProM/projectM/cmake/EnableCFlagsIfSupported.cmake
  64. +20
    -0
      plugins/ProM/projectM/cmake/FindGLM.cmake
  65. +33
    -0
      plugins/ProM/projectM/cmake/FindJACK.cmake
  66. +55
    -0
      plugins/ProM/projectM/cmake/FindLLVM.cmake
  67. +44
    -0
      plugins/ProM/projectM/cmake/FindPulseaudio.cmake
  68. +42
    -0
      plugins/ProM/projectM/cmake/Findlibvisual.cmake
  69. +68
    -0
      plugins/ProM/projectM/cmake/SDL2Target.cmake
  70. +73
    -0
      plugins/ProM/projectM/config.h.cmake.in
  71. +25
    -0
      plugins/ProM/projectM/configure-ndk
  72. +275
    -0
      plugins/ProM/projectM/configure.ac
  73. +103
    -0
      plugins/ProM/projectM/features.cmake
  74. BIN
      plugins/ProM/projectM/fonts/Vera.ttf
  75. BIN
      plugins/ProM/projectM/fonts/VeraMono.ttf
  76. +71
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_absolute_header.m4
  77. +32
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_ac_append_to_file.m4
  78. +32
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_ac_print_to_file.m4
  79. +29
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_am_macro.m4
  80. +28
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_am_macro_static.m4
  81. +50
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_am_trilinos_makefile_export.m4
  82. +53
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_fortify_source.m4
  83. +49
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_recursive_am_macro.m4
  84. +49
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_add_recursive_am_macro_static.m4
  85. +120
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_afs.m4
  86. +55
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_am_jobserver.m4
  87. +44
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_am_macros.m4
  88. +38
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_am_macros_static.m4
  89. +155
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_am_override_var.m4
  90. +67
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_append_compile_flags.m4
  91. +71
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_append_flag.m4
  92. +65
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_append_link_flags.m4
  93. +27
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_append_to_file.m4
  94. +185
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_arg_with_path_style.m4
  95. +57
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_asm_inline.m4
  96. +130
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_at_check_pattern.m4
  97. +63
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_auto_include_headers.m4
  98. +148
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_berkeley_db.m4
  99. +152
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_berkeley_db_cxx.m4
  100. +238
    -0
      plugins/ProM/projectM/m4/autoconf-archive/ax_blas.m4

+ 0
- 9
Makefile View File

@@ -15,10 +15,6 @@ DESTDIR ?=

# --------------------------------------------------------------

HAVE_PROJM = $(shell pkg-config --exists libprojectM && echo true)

# --------------------------------------------------------------

ifneq ($(CROSS_COMPILING),true)
CAN_GENERATE_TTL = true
else ifneq ($(EXE_WRAPPER),)
@@ -60,10 +56,8 @@ ifeq ($(HAVE_OPENGL),true)
# glBars (needs OpenGL)
$(MAKE) all -C plugins/glBars

ifeq ($(HAVE_PROJM),true)
# ProM (needs OpenGL + ProjectM)
$(MAKE) all -C plugins/ProM
endif # HAVE_PROJM
endif # HAVE_OPENGL

gen: plugins dpf/utils/lv2_ttl_generator
@@ -153,9 +147,6 @@ endif # MACOS
install -m 755 bin/MaPitchshift$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/
ifeq ($(HAVE_OPENGL),true)
install -m 755 bin/glBars$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/
ifeq ($(HAVE_PROJM),true)
install -m 755 bin/ProM$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/
endif # HAVE_PROJM
endif # HAVE_OPENGL

# --------------------------------------------------------------


+ 15
- 1
dpf/Makefile.base.mk View File

@@ -8,6 +8,13 @@ AR ?= ar
CC ?= gcc
CXX ?= g++

# ---------------------------------------------------------------------------------------------------------------------
# Protect against multiple inclusion

ifneq ($(DPF_MAKEFILE_BASE_INCLUDED),true)

DPF_MAKEFILE_BASE_INCLUDED = true

# ---------------------------------------------------------------------------------------------------------------------
# Auto-detect OS if not defined

@@ -227,7 +234,9 @@ endif
# Check for required libraries

HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true)
HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true)

# Vulkan is not supported yet
# HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true)

ifeq ($(MACOS_OR_WINDOWS),true)
HAVE_OPENGL = true
@@ -485,3 +494,8 @@ features:
$(call print_available,HAVE_XRANDR)

# ---------------------------------------------------------------------------------------------------------------------
# Protect against multiple inclusion

endif # DPF_MAKEFILE_BASE_INCLUDED

# ---------------------------------------------------------------------------------------------------------------------

+ 1
- 1
dpf/dgl/Application.hpp View File

@@ -73,7 +73,7 @@ public:
Returning true means there's no event-loop running at the moment (or it's just about to stop).
This function is thread-safe.
*/
bool isQuiting() const noexcept;
bool isQuitting() const noexcept;

/**
Check if the application is standalone, otherwise running as a module or plugin.


+ 4
- 0
dpf/dgl/Makefile View File

@@ -13,6 +13,10 @@ BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-un
BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include
LINK_FLAGS += $(DGL_LIBS)

ifeq ($(USE_OPENGL3),true)
BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3
endif

# TODO fix these after pugl-upstream is done
BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers
ifneq ($(MACOS),true)


+ 10
- 3
dpf/dgl/OpenGL.hpp View File

@@ -67,13 +67,20 @@
// OpenGL includes

#ifdef DISTRHO_OS_MAC
# include <OpenGL/gl.h>
# ifdef DGL_USE_OPENGL3
# include <OpenGL/gl3.h>
# include <OpenGL/gl3ext.h>
# else
# include <OpenGL/gl.h>
# endif
#else
# ifndef DISTRHO_OS_WINDOWS
# define GL_GLEXT_PROTOTYPES
# endif
# include <GL/gl.h>
# include <GL/glext.h>
# ifndef __GLEW_H__
# include <GL/gl.h>
# include <GL/glext.h>
# endif
#endif

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


+ 15
- 12
dpf/dgl/Window.hpp View File

@@ -70,10 +70,6 @@ public:
const char* startDir;
/** File browser dialog window title, uses "FileBrowser" if null */
const char* title;
/** File browser dialog window width */
uint width;
/** File browser dialog window height */
uint height;
// TODO file filter

/**
@@ -98,8 +94,6 @@ public:
FileBrowserOptions()
: startDir(nullptr),
title(nullptr),
width(0),
height(0),
buttons() {}
};
#endif // DGL_FILE_BROWSER_DISABLED
@@ -128,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;
};

/**
@@ -190,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()
*/
@@ -453,6 +447,15 @@ private:
friend class PluginWindow;
friend class TopLevelWidget;

/** @internal */
explicit Window(Application& app,
uintptr_t parentWindowHandle,
uint width,
uint height,
double scaleFactor,
bool resizable,
bool doPostInit);

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window);
};



+ 1
- 1
dpf/dgl/src/Application.cpp View File

@@ -48,7 +48,7 @@ void Application::quit()
pData->quit();
}

bool Application::isQuiting() const noexcept
bool Application::isQuitting() const noexcept
{
return pData->isQuitting || pData->isQuittingInNextCycle;
}


+ 1
- 0
dpf/dgl/src/ApplicationPrivateData.cpp View File

@@ -151,6 +151,7 @@ void Application::PrivateData::quit()

void Application::PrivateData::setClassName(const char* const name)
{
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);

puglSetClassName(world, name);


+ 32
- 3
dpf/dgl/src/NanoVG.cpp View File

@@ -54,6 +54,15 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
# ifdef DGL_USE_OPENGL3
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
DGL_EXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays)
DGL_EXT(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap)
DGL_EXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex)
DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)
DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
# endif
# undef DGL_EXT
#endif

@@ -61,7 +70,18 @@ DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
// Include NanoVG OpenGL implementation

//#define STB_IMAGE_STATIC
#define NANOVG_GL2_IMPLEMENTATION
#ifdef DGL_USE_OPENGL3
# define NANOVG_GL3_IMPLEMENTATION
#else
# define NANOVG_GL2_IMPLEMENTATION
#endif

#if defined(DISTRHO_OS_MAC) && defined(NANOVG_GL3_IMPLEMENTATION)
# define glBindVertexArray glBindVertexArrayAPPLE
# define glDeleteVertexArrays glDeleteVertexArraysAPPLE
# define glGenVertexArrays glGenVertexArraysAPPLE
#endif

#include "nanovg/nanovg_gl.h"

#if defined(NANOVG_GL2)
@@ -125,6 +145,15 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
# ifdef DGL_USE_OPENGL3
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
DGL_EXT(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays)
DGL_EXT(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap)
DGL_EXT(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex)
DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)
DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
# endif
# undef DGL_EXT
needsInit = false;
# if defined(__GNUC__) && (__GNUC__ >= 9)
@@ -269,12 +298,12 @@ NanoVG::~NanoVG()

void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor)
{
if (fContext == nullptr) return;
DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,);
DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,);
fInFrame = true;

nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor);
if (fContext != nullptr)
nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor);
}

void NanoVG::beginFrame(Widget* const widget)


+ 30
- 1
dpf/dgl/src/Window.cpp View File

@@ -69,6 +69,19 @@ Window::Window(Application& app,
pData->initPost();
}

Window::Window(Application& app,
const uintptr_t parentWindowHandle,
const uint width,
const uint height,
const double scaleFactor,
const bool resizable,
const bool doPostInit)
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable))
{
if (doPostInit)
pData->initPost();
}

Window::~Window()
{
delete pData;
@@ -119,6 +132,8 @@ void Window::setResizable(const bool resizable)

uint Window::getWidth() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

const double width = puglGetFrame(pData->view).width;
DISTRHO_SAFE_ASSERT_RETURN(width >= 0.0, 0);
return static_cast<uint>(width + 0.5);
@@ -126,6 +141,8 @@ uint Window::getWidth() const noexcept

uint Window::getHeight() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

const double height = puglGetFrame(pData->view).height;
DISTRHO_SAFE_ASSERT_RETURN(height >= 0.0, 0);
return static_cast<uint>(height + 0.5);
@@ -133,6 +150,8 @@ uint Window::getHeight() const noexcept

Size<uint> Window::getSize() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>());

const PuglRect rect = puglGetFrame(pData->view);
DISTRHO_SAFE_ASSERT_RETURN(rect.width >= 0.0, Size<uint>());
DISTRHO_SAFE_ASSERT_RETURN(rect.height >= 0.0, Size<uint>());
@@ -201,7 +220,8 @@ const char* Window::getTitle() const noexcept

void Window::setTitle(const char* const title)
{
puglSetWindowTitle(pData->view, title);
if (pData->view != nullptr)
puglSetWindowTitle(pData->view, title);
}

bool Window::isIgnoringKeyRepeat() const noexcept
@@ -264,11 +284,17 @@ bool Window::openFileBrowser(const FileBrowserOptions& options)

void Window::repaint() noexcept
{
if (pData->view == nullptr)
return;

puglPostRedisplay(pData->view);
}

void Window::repaint(const Rectangle<uint>& rect) noexcept
{
if (pData->view == nullptr)
return;

PuglRect prect = {
static_cast<double>(rect.getX()),
static_cast<double>(rect.getY()),
@@ -305,6 +331,9 @@ void Window::setGeometryConstraints(const uint minimumWidth,
pData->autoScaling = automaticallyScale;
pData->keepAspectRatio = keepAspectRatio;

if (pData->view == nullptr)
return;

const double scaleFactor = pData->scaleFactor;

puglSetGeometryConstraints(pData->view,


+ 36
- 11
dpf/dgl/src/WindowPrivateData.cpp View File

@@ -70,7 +70,10 @@ static double getDesktopScaleFactor(const PuglView* const view)
if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
return std::max(1.0, std::atof(scale));

return puglGetDesktopScaleFactor(view);
if (view != nullptr)
return puglGetDesktopScaleFactor(view);

return 1.0;
}

// -----------------------------------------------------------------------
@@ -162,11 +165,11 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
: app(a),
appData(a.pData),
self(s),
view(puglNewView(appData->world)),
view(appData->world != nullptr ? puglNewView(appData->world) : nullptr),
transientParentView(nullptr),
topLevelWidgets(),
isClosed(parentWindowHandle == 0),
isVisible(parentWindowHandle != 0),
isVisible(parentWindowHandle != 0 && view != nullptr),
isEmbed(parentWindowHandle != 0),
scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)),
autoScaling(false),
@@ -187,6 +190,12 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,

Window::PrivateData::~PrivateData()
{
appData->idleCallbacks.remove(this);
appData->windows.remove(self);

if (view == nullptr)
return;

if (isEmbed)
{
#ifdef HAVE_X11
@@ -198,16 +207,12 @@ Window::PrivateData::~PrivateData()
isVisible = false;
}

appData->idleCallbacks.remove(this);
appData->windows.remove(self);

#ifdef DISTRHO_OS_WINDOWS
if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled)
std::free(const_cast<char*>(win32SelectedFile));
#endif

if (view != nullptr)
puglFreeView(view);
puglFreeView(view);
}

// -----------------------------------------------------------------------
@@ -220,7 +225,7 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo

if (view == nullptr)
{
DGL_DBG("Failed to create Pugl view, everything will fail!\n");
d_stderr2("Failed to create Pugl view, everything will fail!");
return;
}

@@ -234,14 +239,26 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE);
puglSetViewHint(view, PUGL_DEPTH_BITS, 16);
puglSetViewHint(view, PUGL_STENCIL_BITS, 8);
#ifdef DGL_USE_OPENGL3
puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
#endif
// PUGL_SAMPLES ??
puglSetEventFunc(view, puglEventCallback);
}

void Window::PrivateData::initPost()
bool Window::PrivateData::initPost()
{
if (view == nullptr)
return false;

// create view now, as a few methods we allow devs to use require it
puglRealize(view);
if (puglRealize(view) != PUGL_SUCCESS)
{
view = nullptr;
d_stderr2("Failed to realize Pugl view, everything will fail!");
return false;
}

if (isEmbed)
{
@@ -252,6 +269,8 @@ void Window::PrivateData::initPost()
// give context back to transient parent window
if (transientParentView != nullptr)
puglBackendEnter(transientParentView);

return true;
}

// -----------------------------------------------------------------------
@@ -286,6 +305,9 @@ void Window::PrivateData::show()

DGL_DBG("Window show called\n");

if (view == nullptr)
return;

if (isClosed)
{
isClosed = false;
@@ -343,6 +365,9 @@ void Window::PrivateData::hide()

void Window::PrivateData::focus()
{
if (view == nullptr)
return;

if (! isEmbed)
puglRaiseWindow(view);



+ 2
- 2
dpf/dgl/src/WindowPrivateData.hpp View File

@@ -42,7 +42,7 @@ struct Window::PrivateData : IdleCallback {
Window* const self;

/** Pugl view instance. */
PuglView* const view;
PuglView* view;

/** Pugl view instance of the transient parent window. */
PuglView* const transientParentView;
@@ -126,7 +126,7 @@ struct Window::PrivateData : IdleCallback {
/** Helper initialization function called at the end of all this class constructors. */
void initPre(uint width, uint height, bool resizable);
/** Helper initialization function called on the Window constructor after we are done. */
void initPost();
bool initPost();

/** Hide window and notify application of a window close event.
* Does nothing if window is embed (that is, not standalone).


+ 3
- 1
dpf/dgl/src/nanovg/nanovg_gl.h View File

@@ -40,7 +40,9 @@ enum NVGcreateFlags {
#elif defined NANOVG_GL3_IMPLEMENTATION
# define NANOVG_GL3 1
# define NANOVG_GL_IMPLEMENTATION 1
# define NANOVG_GL_USE_UNIFORMBUFFER 1
# ifndef __APPLE__
# define NANOVG_GL_USE_UNIFORMBUFFER 1
# endif
#elif defined NANOVG_GLES2_IMPLEMENTATION
# define NANOVG_GLES2 1
# define NANOVG_GL_IMPLEMENTATION 1


+ 4
- 0
dpf/dgl/src/pugl-upstream/src/mac.m View File

@@ -29,6 +29,10 @@

#include <stdlib.h>

#ifndef __MAC_10_9
typedef NSUInteger NSEventSubtype;
#endif

#ifndef __MAC_10_10
typedef NSUInteger NSEventModifierFlags;
#endif


+ 10
- 6
dpf/dgl/src/pugl-upstream/src/x11.c View File

@@ -366,12 +366,16 @@ puglRealize(PuglView* const view)
}

#ifdef HAVE_XRANDR
// Set refresh rate hint to the real refresh rate
XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent);
short current_rate = XRRConfigCurrentRate(conf);

view->hints[PUGL_REFRESH_RATE] = current_rate;
XRRFreeScreenConfigInfo(conf);
int ignored;
if (XRRQueryExtension(display, &ignored, &ignored))
{
// Set refresh rate hint to the real refresh rate
XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent);
short current_rate = XRRConfigCurrentRate(conf);

view->hints[PUGL_REFRESH_RATE] = current_rate;
XRRFreeScreenConfigInfo(conf);
}
#endif

updateSizeHints(view);


+ 51
- 4
dpf/dgl/src/pugl.cpp View File

@@ -62,6 +62,7 @@
# include <X11/X.h>
# include <X11/Xatom.h>
# include <X11/Xlib.h>
# include <X11/Xresource.h>
# include <X11/Xutil.h>
# include <X11/keysym.h>
# ifdef HAVE_XCURSOR
@@ -112,7 +113,6 @@ START_NAMESPACE_DGL
# endif
# ifndef __MAC_10_9
# define NSModalResponseOK NSOKButton
typedef NSUInteger NSEventSubtype;
# endif
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -207,12 +207,59 @@ double puglGetDesktopScaleFactor(const PuglView* const view)
: [view->impl->wrapperView window])
return [window screen].backingScaleFactor;
return [NSScreen mainScreen].backingScaleFactor;
#else
return 1.0;
#elif defined(DISTRHO_OS_WINDOWS)
if (const HMODULE Shcore = LoadLibraryA("Shcore.dll"))
{
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*);
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*);

const PFN_GetProcessDpiAwareness GetProcessDpiAwareness
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness");
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor");

DWORD dpiAware = 0;
if (GetProcessDpiAwareness && GetScaleFactorForMonitor
&& GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0)
{
const HMONITOR hMon = MonitorFromWindow(view->impl->hwnd, MONITOR_DEFAULTTOPRIMARY);

DWORD scaleFactor = 0;
if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0)
{
FreeLibrary(Shcore);
return static_cast<double>(scaleFactor) / 100.0;
}
}

FreeLibrary(Shcore);
}
#elif defined(HAVE_X11)
XrmInitialize();

if (char* const rms = XResourceManagerString(view->world->impl->display))
{
if (const XrmDatabase sdb = XrmGetStringDatabase(rms))
{
char* type = nullptr;
XrmValue ret;

if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret)
&& ret.addr != nullptr
&& type != nullptr
&& std::strncmp("String", type, 6) == 0)
{
if (const double dpi = std::atof(ret.addr))
return dpi / 96;
}
}
}
#else
// unused
(void)view;
#endif

return 1.0;
}

// --------------------------------------------------------------------------------------------------------------------
@@ -596,7 +643,7 @@ bool sofdFileDialogShow(PuglView* const view,
x_fib_cfg_buttons(2, options.buttons.showPlaces-1);
*/

return (x_fib_show(sofd_display, view->impl->win, 0, 0, scaleFactor) == 0);
return (x_fib_show(sofd_display, view->impl->win, 0, 0, scaleFactor + 0.5) == 0);
}

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


+ 2
- 2
dpf/distrho/DistrhoPlugin.hpp View File

@@ -405,7 +405,7 @@ struct ParameterEnumerationValues {
Array of @ParameterEnumerationValue items.@n
This pointer must be null or have been allocated on the heap with `new ParameterEnumerationValue[count]`.
*/
const ParameterEnumerationValue* values;
ParameterEnumerationValue* values;

/**
Default constructor, for zero enumeration values.
@@ -419,7 +419,7 @@ struct ParameterEnumerationValues {
Constructor using custom values.@n
The pointer to @values must have been allocated on the heap with `new`.
*/
ParameterEnumerationValues(uint32_t c, bool r, const ParameterEnumerationValue* v) noexcept
ParameterEnumerationValues(uint32_t c, bool r, ParameterEnumerationValue* v) noexcept
: count(c),
restrictedMode(r),
values(v) {}


+ 12
- 12
dpf/distrho/DistrhoUI.hpp View File

@@ -250,7 +250,6 @@ protected:
*/
virtual void sampleRateChanged(double newSampleRate);

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/* --------------------------------------------------------------------------------------------------------
* UI Callbacks (optional) */

@@ -262,6 +261,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

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



+ 433
- 91
dpf/distrho/extra/ExternalWindow.hpp View File

@@ -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,164 +33,506 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------
// ExternalWindow class

/**
External Window class.

This is a standalone TopLevelWidget/Window-compatible class, but without any real event handling.
Being compatible with TopLevelWidget/Window, 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".
The uiIdle() function will be called at regular intervals to keep UI running.
There are helper methods in place to launch external tools and keep track of its running state.

External windows can be setup to run in 3 different modes:
* Embed:
Embed into the host UI, even-loop driven by the host.
This is basically working as a regular plugin UI, as you typically expect them to.
The plugin side does not get control over showing, hiding or closing the window (as usual for plugins).
No restrictions on supported plugin format, everything should work.
Requires DISTRHO_PLUGIN_HAS_EMBED_UI to be set to 1.

* Semi-external:
The UI is not embed into the host, but the even-loop is still driven by it.
In this mode the host does not have control over the UI except for showing, hiding and setting transient parent.
It is possible to close the window from the plugin, the host will be notified of such case.
Host regularly calls isQuitting() to check if the UI got closed by the user or plugin side.
This mode is only possible in LV2 plugin formats, using lv2ui:showInterface extension.

* Standalone:
The UI is not embed into the host or uses its event-loop, basically running as standalone.
The host only has control over showing and hiding the window, nothing else.
The UI is still free to close itself at any point.
DPF will keep calling isRunning() to check if it should keep the event-loop running.
Only possible in JACK and DSSI targets, as the UIs are literally standalone applications there.

Please note that for non-embed windows, you cannot show the window yourself.
The plugin window is only allowed to hide or close itself, a "show" action needs to come from the host.

A few callbacks are provided so that implementations do not need to care about checking for state changes.
They are not called on construction, but will be everytime something changes either by the host or the window itself.
*/
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;

public:
/**
Constructor.
*/
explicit ExternalWindow()
: pData() {}

/**
Constructor for DPF internal use.
*/
explicit ExternalWindow(const PrivateData& data)
: pData(data) {}

/**
Destructor.
*/
virtual ~ExternalWindow()
{
terminateAndWaitForProcess();
DISTRHO_SAFE_ASSERT(!pData.visible);
}

/* --------------------------------------------------------------------------------------------------------
* ExternalWindow specific calls - Host side calls that you can reimplement for fine-grained funtionality */

/**
Check if main-loop is running.
This is used under standalone mode to check whether to keep things running.
Returning false from this function will stop the event-loop and close the window.
*/
virtual bool isRunning() const
{
if (ext.inUse)
return ext.isRunning();

return isVisible();
}

/**
Check if we are about to close.
This is used when the event-loop is provided by the host to check if it should close the window.
It is also used in standalone mode right after isRunning() returns false to verify if window needs to be closed.
*/
virtual bool isQuitting() const
{
return ext.inUse ? ext.isQuitting : pData.isQuitting;
}

/**
Get the "native" window handle.
This can be reimplemented in order to pass the native 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`.

@note Only available to override if DISTRHO_PLUGIN_HAS_EMBED_UI is set to 1.
*/
virtual uintptr_t getNativeWindowHandle() const noexcept
{
return 0;
}

/**
Grab the keyboard input focus.
Typically you would setup OS-native methods to bring the window to front and give it focus.
Default implementation does nothing.
*/
virtual void focus() {}

/* --------------------------------------------------------------------------------------------------------
* TopLevelWidget-like calls - Information, can be called by either host or plugin */

#if DISTRHO_PLUGIN_HAS_EMBED_UI
/**
Whether this Window is embed into another (usually not DGL-controlled) Window.
*/
bool isEmbed() const noexcept
{
return pData.parentWindowHandle != 0;
}
#endif

/**
Check if this window is visible.
@see setVisible(bool)
*/
bool isVisible() const noexcept
{
return pData.visible;
}

/**
Whether this Window is running as standalone, that is, without being coupled to a host event-loop.
When in standalone mode, isRunning() is called to check if the event-loop should keep running.
*/
bool isStandalone() const noexcept
{
return pData.isStandalone;
}

/**
Get width of this window.
Only relevant to hosts when the UI is embedded.
*/
uint getWidth() const noexcept
{
return width;
return pData.width;
}

/**
Get height of this window.
Only relevant to hosts when the UI is embedded.
*/
uint getHeight() const noexcept
{
return height;
return pData.height;
}

/**
Get the scale factor requested for this window.
This is purely informational, and up to developers to choose what to do with it.
*/
double getScaleFactor() const noexcept
{
return pData.scaleFactor;
}

/**
Get the title of the window previously set with setTitle().
This is typically displayed in the title bar or in window switchers.
*/
const char* getTitle() const noexcept
{
return title;
return pData.title;
}

uintptr_t getTransientWinId() const noexcept
#if DISTRHO_PLUGIN_HAS_EMBED_UI
/**
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 transientWinId;
return pData.parentWindowHandle;
}
#endif

bool isVisible() const noexcept
/**
Get the transient window that we should attach ourselves to.
TODO what id? also NSView* on macOS, or NSWindow?
*/
uintptr_t getTransientWindowId() const noexcept
{
return visible;
return pData.transientWinId;
}

bool isRunning() noexcept
/* --------------------------------------------------------------------------------------------------------
* TopLevelWidget-like calls - actions called by either host or plugin */

/**
Hide window.
This is the same as calling setVisible(false).
Embed windows should never call this!
@see isVisible(), setVisible(bool)
*/
void hide()
{
if (pid <= 0)
return false;
setVisible(false);
}

const pid_t p = ::waitpid(pid, nullptr, WNOHANG);
/**
Hide the UI and gracefully terminate.
Embed windows should never call this!
*/
virtual void close()
{
pData.isQuitting = true;
hide();

if (p == pid || (p == -1 && errno == ECHILD))
{
printf("NOTICE: Child process exited while idle\n");
pid = 0;
return false;
}
if (ext.inUse)
terminateAndWaitForExternalProcess();
}

/**
Set width of this window.
Can trigger a sizeChanged callback.
Only relevant to hosts when the UI is embedded.
*/
void setWidth(uint width)
{
setSize(width, getHeight());
}

/**
Set height of this window.
Can trigger a sizeChanged callback.
Only relevant to hosts when the UI is embedded.
*/
void setHeight(uint height)
{
setSize(getWidth(), height);
}

/**
Set size of this window using @a width and @a height values.
Can trigger a sizeChanged callback.
Only relevant to hosts when the UI is embedded.
*/
void setSize(uint width, uint height)
{
DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,);

return true;
if (pData.width == width || pData.height == height)
return;

pData.width = width;
pData.height = height;
sizeChanged(width, height);
}

virtual void setSize(uint w, uint h)
/**
Set the title of the window, typically displayed in the title bar or in window switchers.
Can trigger a titleChanged callback.
Only relevant to hosts when the UI is not embedded.
*/
void setTitle(const char* title)
{
width = w;
height = h;
if (pData.title == title)
return;
pData.title = title;
titleChanged(title);
}

virtual void setTitle(const char* const t)
/* --------------------------------------------------------------------------------------------------------
* TopLevelWidget-like calls - actions called by the host */

/**
Show window.
This is the same as calling setVisible(true).
@see isVisible(), setVisible(bool)
*/
void show()
{
title = t;
setVisible(true);
}

virtual void setTransientWinId(const uintptr_t winId)
/**
Set window visible (or not) according to @a visible.
@see isVisible(), hide(), show()
*/
void setVisible(bool visible)
{
transientWinId = winId;
if (pData.visible == visible)
return;
pData.visible = visible;
visibilityChanged(visible);
}

virtual void setVisible(const bool yesNo)
/**
Called by the host to set the transient parent window that we should attach ourselves to.
TODO what id? also NSView* on macOS, or NSWindow?
*/
void setTransientWindowId(uintptr_t winId)
{
visible = yesNo;
if (pData.transientWinId == winId)
return;
pData.transientWinId = winId;
transientParentWindowChanged(winId);
}

protected:
/* --------------------------------------------------------------------------------------------------------
* ExternalWindow special calls for running externals tools */

bool startExternalProcess(const char* args[])
{
terminateAndWaitForProcess();
ext.inUse = true;

pid = vfork();
return ext.start(args);
}

switch (pid)
{
case 0:
execvp(args[0], (char**)args);
_exit(1);
return false;
void terminateAndWaitForExternalProcess()
{
ext.isQuitting = true;
ext.terminateAndWait();
}

case -1:
printf("Could not start external ui\n");
return false;
/* --------------------------------------------------------------------------------------------------------
* ExternalWindow specific callbacks */

default:
return true;
}
/**
A callback for when the window size changes.
@note WIP this might need to get fed back into the host somehow.
*/
virtual void sizeChanged(uint width, uint height)
{
// unused, meant for custom implementations
return; (void)width; (void)height;
}

void terminateAndWaitForProcess()
/**
A callback for when the window title changes.
@note WIP this might need to get fed back into the host somehow.
*/
virtual void titleChanged(const char* title)
{
if (pid <= 0)
return;
// unused, meant for custom implementations
return; (void)title;
}

printf("Waiting for previous process to stop,,,\n");
/**
A callback for when the window visibility changes.
@note WIP this might need to get fed back into the host somehow.
*/
virtual void visibilityChanged(bool visible)
{
// unused, meant for custom implementations
return; (void)visible;
}

/**
A callback for when the transient parent window changes.
*/
virtual void transientParentWindowChanged(uintptr_t winId)
{
// unused, meant for custom implementations
return; (void)winId;
}

private:
friend class PluginWindow;
friend class UI;

struct ExternalProcess {
bool inUse;
bool isQuitting;
mutable pid_t pid;

bool sendTerm = true;
ExternalProcess()
: inUse(false),
isQuitting(false),
pid(0) {}

for (pid_t p;;)
bool isRunning() const noexcept
{
p = ::waitpid(pid, nullptr, WNOHANG);
if (pid <= 0)
return false;

const pid_t p = ::waitpid(pid, nullptr, WNOHANG);

switch (p)
if (p == pid || (p == -1 && errno == ECHILD))
{
d_stdout("NOTICE: Child process exited while idle");
pid = 0;
return false;
}

return true;
}

bool start(const char* args[])
{
terminateAndWait();

pid = vfork();

switch (pid)
{
case 0:
if (sendTerm)
{
sendTerm = false;
::kill(pid, SIGTERM);
}
break;
execvp(args[0], (char**)args);
_exit(1);
return false;

case -1:
if (errno == ECHILD)
{
printf("Done! (no such process)\n");
pid = 0;
return;
}
break;
d_stderr("Could not start external ui");
return false;

default:
if (p == pid)
return true;
}
}

void terminateAndWait()
{
if (pid <= 0)
return;

d_stdout("Waiting for external process to stop,,,");

bool sendTerm = true;

for (pid_t p;;)
{
p = ::waitpid(pid, nullptr, WNOHANG);

switch (p)
{
printf("Done! (clean wait)\n");
pid = 0;
return;
case 0:
if (sendTerm)
{
sendTerm = false;
::kill(pid, SIGTERM);
}
break;

case -1:
if (errno == ECHILD)
{
d_stdout("Done! (no such process)");
pid = 0;
return;
}
break;

default:
if (p == pid)
{
d_stdout("Done! (clean wait)");
pid = 0;
return;
}
break;
}
break;
}

// 5 msec
usleep(5*1000);
// 5 msec
usleep(5*1000);
}
}
}

private:
uint width;
uint height;
String title;
uintptr_t transientWinId;
bool visible;
pid_t pid;

friend class UIExporter;
} ext;

struct PrivateData {
uintptr_t parentWindowHandle;
uintptr_t transientWinId;
uint width;
uint height;
double scaleFactor;
String title;
bool isQuitting;
bool isStandalone;
bool visible;

PrivateData()
: parentWindowHandle(0),
transientWinId(0),
width(1),
height(1),
scaleFactor(1.0),
title(),
isQuitting(false),
isStandalone(false),
visible(false) {}
} pData;

DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow)
};


+ 2
- 0
dpf/distrho/src/DistrhoPluginJACK.cpp View File

@@ -206,6 +206,8 @@ public:

jackbridge_activate(fClient);

std::fflush(stdout);

#if DISTRHO_PLUGIN_HAS_UI
if (const char* const name = jackbridge_get_client_name(fClient))
fUI.setWindowTitle(name);


+ 22
- 26
dpf/distrho/src/DistrhoPluginVST2.cpp View File

@@ -22,7 +22,7 @@
# define DISTRHO_PLUGIN_HAS_UI 0
#endif

#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL)
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# undef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif
@@ -189,8 +189,7 @@ public:
nullptr, // TODO file request
nullptr,
plugin->getInstancePointer(),
scaleFactor),
fHasScaleFactor(d_isNotZero(scaleFactor))
scaleFactor)
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
, fKeyboardModifiers(0)
# endif
@@ -400,13 +399,11 @@ protected:

void setSize(uint width, uint height)
{
// figure out scale factor ourselves if the host doesn't support it
if (! fHasScaleFactor)
{
const double scaleFactor = fUI.getScaleFactor();
width /= scaleFactor;
height /= scaleFactor;
}
# ifdef DISTRHO_OS_MAC
const double scaleFactor = fUI.getScaleFactor();
width /= scaleFactor;
height /= scaleFactor;
# endif
hostCallback(audioMasterSizeWindow, width, height);
}

@@ -438,7 +435,6 @@ private:

// Plugin UI
UIExporter fUI;
const bool fHasScaleFactor;
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uint16_t fKeyboardModifiers;
# endif
@@ -688,13 +684,11 @@ public:
{
fVstRect.right = fVstUI->getWidth();
fVstRect.bottom = fVstUI->getHeight();
// figure out scale factor ourselves if the host doesn't support it
if (fLastScaleFactor == 0.0f)
{
const double scaleFactor = fVstUI->getScaleFactor();
fVstRect.right /= scaleFactor;
fVstRect.bottom /= scaleFactor;
}
# ifdef DISTRHO_OS_MAC
const double scaleFactor = fVstUI->getScaleFactor();
fVstRect.right /= scaleFactor;
fVstRect.bottom /= scaleFactor;
# endif
}
else
{
@@ -703,13 +697,11 @@ public:
fPlugin.getInstancePointer(), fLastScaleFactor);
fVstRect.right = tmpUI.getWidth();
fVstRect.bottom = tmpUI.getHeight();
// figure out scale factor ourselves if the host doesn't support it
if (fLastScaleFactor == 0.0f)
{
const double scaleFactor = tmpUI.getScaleFactor();
fVstRect.right /= scaleFactor;
fVstRect.bottom /= scaleFactor;
}
# ifdef DISTRHO_OS_MAC
const double scaleFactor = tmpUI.getScaleFactor();
fVstRect.right /= scaleFactor;
fVstRect.bottom /= scaleFactor;
# endif
tmpUI.quit();
}
*(ERect**)ptr = &fVstRect;
@@ -1003,6 +995,10 @@ public:
fUsingNsView = true;
return 0xbeef0000;
}
#endif
#ifndef DISTRHO_OS_MAC
if (std::strcmp(canDo, "supportsViewDpiScaling") == 0)
return 1;
#endif
if (std::strcmp(canDo, "receiveVstEvents") == 0 ||
std::strcmp(canDo, "receiveVstMidiEvent") == 0)
@@ -1028,7 +1024,7 @@ public:
break;

case effVendorSpecific:
#if DISTRHO_PLUGIN_HAS_UI
#if DISTRHO_PLUGIN_HAS_UI && !defined(DISTRHO_OS_MAC)
if (index == CCONST('P', 'r', 'e', 'S') && value == CCONST('A', 'e', 'C', 's'))
{
if (d_isEqual(fLastScaleFactor, opt))


+ 31
- 7
dpf/distrho/src/DistrhoUI.cpp View File

@@ -36,11 +36,28 @@ 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;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
pData->window = new PluginWindow(ui, pData->app);
ExternalWindow::PrivateData ewData;
ewData.parentWindowHandle = pData->winId;
ewData.width = width;
ewData.height = height;
ewData.scaleFactor = pData->scaleFactor;
ewData.title = DISTRHO_PLUGIN_NAME;
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE;
return ewData;
#else
pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor);
return pData->window.getObject();
#endif
}

/* ------------------------------------------------------------------------------------------------------------
@@ -58,6 +75,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
}

@@ -71,7 +91,11 @@ UI::~UI()
bool UI::isResizable() const noexcept
{
#if DISTRHO_UI_USER_RESIZABLE
# if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
return true;
# else
return uiData->window->isResizable();
# endif
#else
return false;
#endif
@@ -153,7 +177,7 @@ uintptr_t UI::getNextWindowId() noexcept
return g_nextWindowId;
}
# endif
#endif
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI

/* ------------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks (optional) */
@@ -162,10 +186,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 +204,6 @@ void UI::uiReshape(uint, uint)
pData->fallbackOnResize();
}

void UI::uiScaleFactorChanged(double)
{
}

# ifndef DGL_FILE_BROWSER_DISABLED
void UI::uiFileBrowserSelected(const char*)
{


+ 13
- 78
dpf/distrho/src/DistrhoUIInternal.hpp View File

@@ -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,45 +191,13 @@ 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,);

uiData->window->show();
uiData->window->focus();
uiData->app.addIdleCallback(cb);
uiData->app.exec();
}
@@ -246,16 +208,16 @@ public:

ui->uiIdle();
}
# else
#else
bool plugin_idle()
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);

uiData->app.idle();
ui->uiIdle();
return ! uiData->app.isQuiting();
return ! uiData->app.isQuitting();
}
# endif
#endif

void focus()
{
@@ -269,50 +231,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
}

@@ -320,9 +254,10 @@ public:
{
uiData->window->setVisible(yesNo);

return ! uiData->app.isQuiting();
return ! uiData->app.isQuitting();
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods)
{
// TODO also trigger Character input event


+ 122
- 43
dpf/distrho/src/DistrhoUIPrivateData.hpp View File

@@ -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,69 @@
# 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)
{
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,);

idleCallback = cb;
}

bool isQuitting() const noexcept
{
return ui->isQuitting();
}

bool isStandalone() const noexcept
{
return DISTRHO_UI_IS_STANDALONE;
}

void exec()
{
while (ui->isRunning())
{
d_msleep(30);
idleCallback->idleCallback();
}

if (! ui->isQuitting())
ui->close();
}

// these are not needed
void idle() {}
void quit() {}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};
#else
class PluginApplication : public Application
{
public:
@@ -62,52 +115,46 @@ 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,
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
explicit PluginWindow(UI* const uiPtr, PluginApplication& app)
: ui(uiPtr)
{
return ui->isRunning();
app.ui = ui;
}

uintptr_t getNativeWindowHandle() const noexcept
{
return 0;
}
// fetch cached data
uint getWidth() const noexcept { return ui->pData.width; }
uint getHeight() const noexcept { return ui->pData.height; }
double getScaleFactor() const noexcept { return ui->pData.scaleFactor; }

// direct mappings
void close() { ui->close(); }
void focus() { ui->focus(); }
void show() { ui->show(); }
bool isResizable() const noexcept { return ui->isResizable(); }
bool isVisible() const noexcept { return ui->isVisible(); }
void setTitle(const char* const title) { ui->setTitle(title); }
void setVisible(const bool visible) { ui->setVisible(visible); }
uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); }

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
class PluginWindow : public Window
{
DISTRHO_NAMESPACE::UI* const ui;
bool initializing;
bool receivedReshapeDuringInit;

public:
explicit PluginWindow(DISTRHO_NAMESPACE::UI* const uiPtr,
@@ -116,14 +163,27 @@ public:
const uint width,
const uint height,
const double scaleFactor)
: Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE),
ui(uiPtr)
: Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE, false),
ui(uiPtr),
initializing(true),
receivedReshapeDuringInit(false)
{
puglBackendEnter(pData->view);
if (pData->view == nullptr)
return;

if (pData->initPost())
puglBackendEnter(pData->view);
}

void leaveContext()
{
if (pData->view == nullptr)
return;

if (receivedReshapeDuringInit)
ui->uiReshape(getWidth(), getHeight());

initializing = false;
puglBackendLeave(pData->view);
}

@@ -132,6 +192,9 @@ protected:
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

if (initializing)
return;

ui->uiFocus(focus, mode);
}