Browse Source

Update DPF, remove unused files

Signed-off-by: falkTX <falktx@falktx.com>
main
falkTX 4 months ago
parent
commit
3858414367
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
43 changed files with 72 additions and 18537 deletions
  1. +3
    -1
      Makefile
  2. +15
    -3
      dpf/Makefile.plugins.mk
  3. +0
    -1464
      dpf/cmake/DPF-plugin.cmake
  4. +0
    -28
      dpf/dgl/FileBrowserDialog.hpp
  5. +0
    -71
      dpf/dgl/Layout.hpp
  6. +0
    -1
      dpf/dgl/Makefile
  7. +0
    -103
      dpf/dgl/Vulkan.hpp
  8. +0
    -28
      dpf/dgl/WebView.hpp
  9. +4
    -0
      dpf/dgl/src/Application.cpp
  10. +0
    -201
      dpf/dgl/src/Layout.cpp
  11. +0
    -193
      dpf/dgl/src/Stub.cpp
  12. +0
    -250
      dpf/dgl/src/Vulkan.cpp
  13. +0
    -23
      dpf/dgl/src/WebViewWin32.cpp
  14. +0
    -14
      dpf/dgl/src/pugl-upstream/subprojects/sphinxygen.wrap
  15. +5
    -1
      dpf/distrho/DistrhoUIMain.cpp
  16. +8
    -1
      dpf/distrho/DistrhoUtils.hpp
  17. +0
    -149
      dpf/distrho/extra/Base64.hpp
  18. +0
    -294
      dpf/distrho/extra/ChildProcess.hpp
  19. +0
    -578
      dpf/distrho/extra/ExternalWindow.hpp
  20. +0
    -28
      dpf/distrho/extra/FileBrowserDialog.hpp
  21. +0
    -894
      dpf/distrho/extra/FileBrowserDialogImpl.cpp
  22. +0
    -129
      dpf/distrho/extra/FileBrowserDialogImpl.hpp
  23. +0
    -106
      dpf/distrho/extra/Filesystem.hpp
  24. +0
    -251
      dpf/distrho/extra/Runner.hpp
  25. +0
    -127
      dpf/distrho/extra/Time.hpp
  26. +0
    -28
      dpf/distrho/extra/WebView.hpp
  27. +0
    -2072
      dpf/distrho/extra/WebViewImpl.cpp
  28. +0
    -136
      dpf/distrho/extra/WebViewImpl.hpp
  29. +0
    -122
      dpf/distrho/extra/WebViewWin32.hpp
  30. +0
    -15
      dpf/distrho/extra/choc/LICENSE.md
  31. +0
    -22
      dpf/distrho/extra/choc/README.md
  32. +0
    -2803
      dpf/distrho/extra/choc/choc.patch
  33. +0
    -154
      dpf/distrho/extra/choc/choc_DesktopWindow.h
  34. +0
    -141
      dpf/distrho/extra/choc/choc_DynamicLibrary.h
  35. +0
    -511
      dpf/distrho/extra/choc/choc_MemoryDLL.h
  36. +0
    -67
      dpf/distrho/extra/choc/choc_Platform.h
  37. +0
    -74
      dpf/distrho/extra/choc/choc_StringUtilities.h
  38. +0
    -4769
      dpf/distrho/extra/choc/choc_WebView.h
  39. +0
    -2482
      dpf/distrho/extra/sofd/libsofd.c
  40. +0
    -194
      dpf/distrho/extra/sofd/libsofd.h
  41. +13
    -9
      dpf/distrho/src/DistrhoPluginLV2export.cpp
  42. BIN
      dpf/lac/2014-small-talk.odp
  43. +24
    -0
      get-plugins.sh

+ 3
- 1
Makefile View File

@@ -28,9 +28,11 @@ endif

dgl:
ifeq ($(HAVE_CAIRO_OR_OPENGL),true)
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl
ifeq ($(HAVE_OPENGL),true)
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl opengl
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl opengl3
else
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl cairo
endif
endif



+ 15
- 3
dpf/Makefile.plugins.mk View File

@@ -514,11 +514,21 @@ $(DGL_BUILD_DIR)/libdgl-vulkan.a: $(DGL_POSSIBLE_DEPS)

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

$(BUILD_DIR)/DistrhoPluginMain_%_single_obj.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoPluginMain.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -DDISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT=1 -c -o $@

$(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoPluginMain.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@

$(BUILD_DIR)/DistrhoUIMain_%_single_obj.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUIMain.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -DDISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT=1 -c -o $@

$(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUIMain.cpp ($*)"
@@ -534,10 +544,10 @@ $(BUILD_DIR)/DistrhoUI_win32.cpp.o: $(DPF_PATH)/distrho/DistrhoUI_win32.cpp $(EX
@echo "Compiling DistrhoUI_win32.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@

$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: BUILD_CXX_FLAGS += $(JACK_FLAGS)

$(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: BUILD_CXX_FLAGS += $(JACK_FLAGS)

$(BUILD_DIR)/DistrhoUIMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: BUILD_CXX_FLAGS += $(LIBLO_FLAGS)
@@ -591,7 +601,7 @@ lv2_dsp: $(lv2_dsp)
lv2_sep: $(lv2_dsp) $(lv2_ui)

ifeq ($(HAVE_DGL),true)
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2_single_obj.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2_single_obj.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
else
$(lv2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
endif
@@ -845,6 +855,7 @@ endif
-include $(BUILD_DIR)/DistrhoPluginMain_LADSPA.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_LV2_single_obj.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d
@@ -856,6 +867,7 @@ endif
-include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_LV2_single_obj.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d


+ 0
- 1464
dpf/cmake/DPF-plugin.cmake
File diff suppressed because it is too large
View File


+ 0
- 28
dpf/dgl/FileBrowserDialog.hpp View File

@@ -1,28 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
#define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED

#include "Base.hpp"

START_NAMESPACE_DGL

#include "../distrho/extra/FileBrowserDialogImpl.hpp"

END_NAMESPACE_DGL

#endif // DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED

+ 0
- 71
dpf/dgl/Layout.hpp View File

@@ -1,71 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DGL_LAYOUT_HPP_INCLUDED
#define DGL_LAYOUT_HPP_INCLUDED

#include "Geometry.hpp"

#include <list>

START_NAMESPACE_DGL

class SubWidget;

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

// NOTE: under development, API to be finalized and documented soon

enum SizeHint {
Expanding,
Fixed
};

struct SubWidgetWithSizeHint {
SubWidget* widget;
SizeHint sizeHint;
};

template<bool horizontal>
struct Layout
{
std::list<SubWidgetWithSizeHint> widgets;
uint setAbsolutePos(int x, int y, uint padding);
void setSize(uint size, uint padding);
};

typedef Layout<true> HorizontalLayout;
typedef Layout<false> VerticalLayout;

struct HorizontallyStackedVerticalLayout
{
std::list<VerticalLayout*> items;
Size<uint> adjustSize(uint padding); // TODO
void setAbsolutePos(int x, int y, uint padding);
};

struct VerticallyStackedHorizontalLayout
{
std::list<HorizontalLayout*> items;
Size<uint> adjustSize(uint padding);
void setAbsolutePos(int x, int y, uint padding);
};

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

END_NAMESPACE_DGL

#endif // DGL_LAYOUT_HPP_INCLUDED

+ 0
- 1
dpf/dgl/Makefile View File

@@ -43,7 +43,6 @@ OBJS_common = \
$(BUILD_DIR)/dgl/Geometry.cpp.o \
$(BUILD_DIR)/dgl/ImageBase.cpp.o \
$(BUILD_DIR)/dgl/ImageBaseWidgets.cpp.o \
$(BUILD_DIR)/dgl/Layout.cpp.o \
$(BUILD_DIR)/dgl/Resources.cpp.o \
$(BUILD_DIR)/dgl/SubWidget.cpp.o \
$(BUILD_DIR)/dgl/SubWidgetPrivateData.cpp.o \


+ 0
- 103
dpf/dgl/Vulkan.hpp View File

@@ -1,103 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DGL_VULKAN_HPP_INCLUDED
#define DGL_VULKAN_HPP_INCLUDED

#include "ImageBase.hpp"

#include <vulkan/vulkan_core.h>

START_NAMESPACE_DGL

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

/**
Vulkan Graphics context.
*/
struct VulkanGraphicsContext : GraphicsContext
{
};

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

/**
Vulkan Image class.

TODO ...
*/
class VulkanImage : public ImageBase
{
public:
/**
Constructor for a null Image.
*/
VulkanImage();

/**
Constructor using raw image data.
@note @a rawData must remain valid for the lifetime of this Image.
*/
VulkanImage(const char* rawData, uint width, uint height, ImageFormat format);

/**
Constructor using raw image data.
@note @a rawData must remain valid for the lifetime of this Image.
*/
VulkanImage(const char* rawData, const Size<uint>& size, ImageFormat format);

/**
Constructor using another image data.
*/
VulkanImage(const VulkanImage& image);

/**
Destructor.
*/
~VulkanImage() override;

/**
Load image data from memory.
@note @a rawData must remain valid for the lifetime of this Image.
*/
void loadFromMemory(const char* rawData,
const Size<uint>& size,
ImageFormat format = kImageFormatBGRA) noexcept override;

/**
Draw this image at position @a pos using the graphics context @a context.
*/
void drawAt(const GraphicsContext& context, const Point<int>& pos) override;

/**
TODO document this.
*/
VulkanImage& operator=(const VulkanImage& image) noexcept;

// FIXME this should not be needed
inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA)
{ loadFromMemory(rdata, Size<uint>(w, h), fmt); };
inline void draw(const GraphicsContext& context)
{ drawAt(context, Point<int>(0, 0)); };
inline void drawAt(const GraphicsContext& context, int x, int y)
{ drawAt(context, Point<int>(x, y)); };
};

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

END_NAMESPACE_DGL

#endif

+ 0
- 28
dpf/dgl/WebView.hpp View File

@@ -1,28 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DGL_WEB_VIEW_HPP_INCLUDED
#define DGL_WEB_VIEW_HPP_INCLUDED

#include "Base.hpp"

START_NAMESPACE_DGL

#include "../distrho/extra/WebViewImpl.hpp"

END_NAMESPACE_DGL

#endif // DGL_WEB_VIEW_HPP_INCLUDED

+ 4
- 0
dpf/dgl/src/Application.cpp View File

@@ -131,6 +131,10 @@ Application::Application(int argc, char* argv[])
#if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW)
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
std::exit(dpf_webview_start(argc, argv));
#else
// unused
(void)argc;
(void)argv;
#endif

// build config sentinels


+ 0
- 201
dpf/dgl/src/Layout.cpp View File

@@ -1,201 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "../Layout.hpp"
#include "../SubWidget.hpp"

START_NAMESPACE_DGL

typedef std::list<SubWidgetWithSizeHint>::iterator SubWidgetWithSizeHintIterator;
typedef std::list<HorizontalLayout*>::iterator HorizontalLayoutIterator;
typedef std::list<VerticalLayout*>::iterator VerticalLayoutIterator;

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

template<> // horizontal
uint Layout<true>::setAbsolutePos(int x, const int y, const uint padding)
{
uint maxHeight = 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
maxHeight = std::max(maxHeight, s.widget->getHeight());
s.widget->setAbsolutePos(x, y);
x += static_cast<int>(s.widget->getWidth());
x += static_cast<int>(padding);
}

return maxHeight;
}

template<> // vertical
uint Layout<false>::setAbsolutePos(const int x, int y, const uint padding)
{
uint maxWidth = 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
maxWidth = std::max(maxWidth, s.widget->getWidth());
s.widget->setAbsolutePos(x, y);
y += static_cast<int>(s.widget->getHeight());
y += static_cast<int>(padding);
}

return maxWidth;
}

template<> // horizontal
void Layout<true>::setSize(const uint width, const uint padding)
{
uint maxHeight = 0;
uint nonFixedWidth = width;
uint numDynamiclySizedWidgets = 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
maxHeight = std::max(maxHeight, s.widget->getHeight());

if (s.sizeHint == Fixed)
nonFixedWidth -= s.widget->getWidth();
else
++numDynamiclySizedWidgets;
}

if (const size_t numWidgets = widgets.size())
nonFixedWidth -= padding * static_cast<uint>(numWidgets - 1);

const uint widthPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedWidth / numDynamiclySizedWidgets : 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
if (s.sizeHint != Fixed)
s.widget->setSize(widthPerWidget, maxHeight);
else
s.widget->setHeight(maxHeight);
}
}

template<> // vertical
void Layout<false>::setSize(const uint height, const uint padding)
{
uint biggestWidth = 0;
uint nonFixedHeight = height;
uint numDynamiclySizedWidgets = 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
biggestWidth = std::max(biggestWidth, s.widget->getWidth());

if (s.sizeHint == Fixed)
nonFixedHeight -= s.widget->getHeight();
else
++numDynamiclySizedWidgets;
}

if (const size_t numWidgets = widgets.size())
nonFixedHeight -= padding * static_cast<uint>(numWidgets - 1);

const uint heightPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedHeight / numDynamiclySizedWidgets : 0;

for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it)
{
SubWidgetWithSizeHint& s(*it);
if (s.sizeHint != Fixed)
s.widget->setSize(biggestWidth, heightPerWidget);
else
s.widget->setWidth(biggestWidth);
}
}

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

/* TODO
void HorizontallyStackedVerticalLayout::adjustSize(const uint padding)
{
}
*/

void HorizontallyStackedVerticalLayout::setAbsolutePos(int x, const int y, const uint padding)
{
for (VerticalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
VerticalLayout* l(*it);
x += static_cast<int>(l->setAbsolutePos(x, y, padding));
x += static_cast<int>(padding);
}
}

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

Size<uint> VerticallyStackedHorizontalLayout::adjustSize(const uint padding)
{
uint biggestWidth = 0;
uint totalHeight = 0;

// iterate all widgets to find which one is the biggest (horizontally)
for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
HorizontalLayout* const l(*it);
uint width = 0;
uint height = 0;

for (SubWidgetWithSizeHintIterator it2=l->widgets.begin(), end2=l->widgets.end(); it2 != end2; ++it2)
{
SubWidgetWithSizeHint& s(*it2);

if (width != 0)
width += padding;

width += s.widget->getWidth();
height = std::max(height, s.widget->getHeight());
}

biggestWidth = std::max(biggestWidth, width);

if (totalHeight != 0)
totalHeight += padding;

totalHeight += height;
}

// now make all horizontal lines the same width
for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
HorizontalLayout* const l(*it);
l->setSize(biggestWidth, padding);
}

return Size<uint>(biggestWidth, totalHeight);
}

void VerticallyStackedHorizontalLayout::setAbsolutePos(const int x, int y, const uint padding)
{
for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
HorizontalLayout* l(*it);
y += static_cast<int>(l->setAbsolutePos(x, y, padding));
y += static_cast<int>(padding);
}
}

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

END_NAMESPACE_DGL

+ 0
- 193
dpf/dgl/src/Stub.cpp View File

@@ -1,193 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "Color.hpp"
#include "SubWidgetPrivateData.hpp"
#include "TopLevelWidgetPrivateData.hpp"
#include "WidgetPrivateData.hpp"
#include "WindowPrivateData.hpp"

START_NAMESPACE_DGL

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

static void notImplemented(const char* const name)
{
d_stderr2("stub function not implemented: %s", name);
}

// --------------------------------------------------------------------------------------------------------------------
// Color

void Color::setFor(const GraphicsContext&, bool)
{
notImplemented("Color::setFor");
}

// --------------------------------------------------------------------------------------------------------------------
// Line

template<typename T>
void Line<T>::draw(const GraphicsContext& context, T)
{
notImplemented("Line::draw");
}

template<typename T>
void Line<T>::draw()
{
notImplemented("Line::draw");
}

template class Line<double>;
template class Line<float>;
template class Line<int>;
template class Line<uint>;
template class Line<short>;
template class Line<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Circle

template<typename T>
void Circle<T>::draw(const GraphicsContext&)
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Circle::drawOutline");
}

template<typename T>
void Circle<T>::draw()
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline()
{
notImplemented("Circle::drawOutline");
}

template class Circle<double>;
template class Circle<float>;
template class Circle<int>;
template class Circle<uint>;
template class Circle<short>;
template class Circle<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Triangle

template<typename T>
void Triangle<T>::draw(const GraphicsContext&)
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Triangle::drawOutline");
}

template<typename T>
void Triangle<T>::draw()
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline()
{
notImplemented("Triangle::drawOutline");
}

template class Triangle<double>;
template class Triangle<float>;
template class Triangle<int>;
template class Triangle<uint>;
template class Triangle<short>;
template class Triangle<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Rectangle

template<typename T>
void Rectangle<T>::draw(const GraphicsContext&)
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Rectangle::drawOutline");
}

template<typename T>
void Rectangle<T>::draw()
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline()
{
notImplemented("Rectangle::drawOutline");
}

template class Rectangle<double>;
template class Rectangle<float>;
template class Rectangle<int>;
template class Rectangle<uint>;
template class Rectangle<short>;
template class Rectangle<ushort>;

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

void SubWidget::PrivateData::display(uint, uint, double)
{
}

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

void TopLevelWidget::PrivateData::display()
{
}

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

void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint)
{
notImplemented("Window::PrivateData::renderToPicture");
}

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

const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
GraphicsContext& context((GraphicsContext&)graphicsContext);
return context;
}

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

END_NAMESPACE_DGL

+ 0
- 250
dpf/dgl/src/Vulkan.cpp View File

@@ -1,250 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "../Vulkan.hpp"
#include "../Color.hpp"

#include "SubWidgetPrivateData.hpp"
#include "TopLevelWidgetPrivateData.hpp"
#include "WidgetPrivateData.hpp"
#include "WindowPrivateData.hpp"

START_NAMESPACE_DGL

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

static void notImplemented(const char* const name)
{
d_stderr2("vulkan function not implemented: %s", name);
}

// -----------------------------------------------------------------------
// Color

void Color::setFor(const GraphicsContext&, bool)
{
notImplemented("Color::setFor");
}

// -----------------------------------------------------------------------
// Line

template<typename T>
void Line<T>::draw(const GraphicsContext&, T)
{
notImplemented("Line::draw");
}

template<typename T>
void Line<T>::draw()
{
notImplemented("Line::draw");
}

template class Line<double>;
template class Line<float>;
template class Line<int>;
template class Line<uint>;
template class Line<short>;
template class Line<ushort>;

// -----------------------------------------------------------------------
// Circle

template<typename T>
void Circle<T>::draw(const GraphicsContext&)
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Circle::drawOutline");
}

template<typename T>
void Circle<T>::draw()
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline()
{
notImplemented("Circle::drawOutline");
}

template class Circle<double>;
template class Circle<float>;
template class Circle<int>;
template class Circle<uint>;
template class Circle<short>;
template class Circle<ushort>;

// -----------------------------------------------------------------------
// Triangle

template<typename T>
void Triangle<T>::draw(const GraphicsContext&)
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Triangle::drawOutline");
}

template<typename T>
void Triangle<T>::draw()
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline()
{
notImplemented("Triangle::drawOutline");
}

template class Triangle<double>;
template class Triangle<float>;
template class Triangle<int>;
template class Triangle<uint>;
template class Triangle<short>;
template class Triangle<ushort>;


// -----------------------------------------------------------------------
// Rectangle

template<typename T>
void Rectangle<T>::draw(const GraphicsContext&)
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Rectangle::drawOutline");
}

template<typename T>
void Rectangle<T>::draw()
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline()
{
notImplemented("Rectangle::drawOutline");
}

template class Rectangle<double>;
template class Rectangle<float>;
template class Rectangle<int>;
template class Rectangle<uint>;
template class Rectangle<short>;
template class Rectangle<ushort>;

// -----------------------------------------------------------------------
// VulkanImage

VulkanImage::VulkanImage()
: ImageBase() {}

VulkanImage::VulkanImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt)
: ImageBase(rdata, w, h, fmt) {}

VulkanImage::VulkanImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt)
: ImageBase(rdata, s, fmt) {}

VulkanImage::VulkanImage(const VulkanImage& image)
: ImageBase(image.rawData, image.size, image.format) {}

VulkanImage::~VulkanImage() {}

void VulkanImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
{
ImageBase::loadFromMemory(rdata, s, fmt);
}

void VulkanImage::drawAt(const GraphicsContext&, const Point<int>&)
{
}

VulkanImage& VulkanImage::operator=(const VulkanImage& image) noexcept
{
rawData = image.rawData;
size = image.size;
format = image.format;
return *this;
}

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

void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
{
// TODO

selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
}

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

void TopLevelWidget::PrivateData::display()
{
if (! selfw->pData->visible)
return;

const Size<uint> size(window.getSize());
const uint width = size.getWidth();
const uint height = size.getHeight();

const double autoScaleFactor = window.pData->autoScaleFactor;

// TODO

// main widget drawing
self->onDisplay();

// now draw subwidgets if there are any
selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
}

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

void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint)
{
notImplemented("Window::PrivateData::renderToPicture");
}

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

const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
return (const GraphicsContext&)graphicsContext;
}

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

END_NAMESPACE_DGL

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

+ 0
- 23
dpf/dgl/src/WebViewWin32.cpp View File

@@ -1,23 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

// Include CHOC separately because it requires C++17

#define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION
#define WEB_VIEW_NAMESPACE DGL_NAMESPACE
#define WEB_VIEW_DGL_NAMESPACE
#include "../WebView.hpp"
#include "../../distrho/extra/WebViewWin32.hpp"

+ 0
- 14
dpf/dgl/src/pugl-upstream/subprojects/sphinxygen.wrap View File

@@ -1,14 +0,0 @@
# Copyright 2022 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: 0BSD OR ISC

[wrap-file]
directory = sphinxygen-1.0.0
source_url = https://download.drobilla.net/sphinxygen-1.0.0.tar.gz
source_filename = sphinxygen-1.0.0.tar.gz
source_hash = 96b19e3b37d4886dcf3e89d4ccf0b66c0deb9f2e34ac151a7a6659a421f0282d

# [wrap-git]
# url = https://gitlab.com/drobilla/sphinxygen.git
# push-url = ssh://git@gitlab.com:drobilla/sphinxygen.git
# revision = main
# depth = 1

+ 5
- 1
dpf/distrho/DistrhoUIMain.cpp View File

@@ -23,7 +23,11 @@

#if DISTRHO_PLUGIN_HAS_UI

#if defined(DISTRHO_PLUGIN_TARGET_AU)
#if defined(DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT)
# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# warning Using single/monolithic LV2 target while DISTRHO_PLUGIN_WANT_DIRECT_ACCESS is 0
# endif
#elif defined(DISTRHO_PLUGIN_TARGET_AU)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
# import "src/DistrhoUIAU.mm"
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA)


+ 8
- 1
dpf/distrho/DistrhoUtils.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 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
@@ -23,6 +23,13 @@
# define __STDC_LIMIT_MACROS
#endif

#ifdef __WINE__
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <winsock2.h>
#endif

#include <cstdarg>
#include <cstdio>
#include <cstdlib>


+ 0
- 149
dpf/distrho/extra/Base64.hpp View File

@@ -1,149 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_BASE64_HPP_INCLUDED
#define DISTRHO_BASE64_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#include <vector>

// --------------------------------------------------------------------------------------------------------------------
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html

/*
Copyright (C) 2004-2008 René Nyffenegger

This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.

3. This notice may not be removed or altered from any source distribution.

René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/

// --------------------------------------------------------------------------------------------------------------------
// Helpers

#ifndef DOXYGEN
namespace DistrhoBase64Helpers {

static constexpr const char* const kBase64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

static inline
uint8_t findBase64CharIndex(const char c)
{
static const uint8_t kBase64CharsLen = static_cast<uint8_t>(std::strlen(kBase64Chars));

for (uint8_t i=0; i<kBase64CharsLen; ++i)
{
if (kBase64Chars[i] == c)
return i;
}

d_stderr2("findBase64CharIndex('%c') - failed", c);
return 0;
}

static constexpr inline
bool isBase64Char(const char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/';
}

} // namespace DistrhoBase64Helpers
#endif

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

static inline
std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string)
{
DISTRHO_SAFE_ASSERT_RETURN(base64string != nullptr, std::vector<uint8_t>());

uint i=0, j=0;
uint charArray3[3], charArray4[4];

std::vector<uint8_t> ret;
ret.reserve(std::strlen(base64string)*3/4 + 4);

for (std::size_t l=0, len=std::strlen(base64string); l<len; ++l)
{
const char c = base64string[l];

if (c == '\0' || c == '=')
break;
if (c == ' ' || c == '\n')
continue;

DISTRHO_SAFE_ASSERT_CONTINUE(DistrhoBase64Helpers::isBase64Char(c));

charArray4[i++] = static_cast<uint>(c);

if (i == 4)
{
for (i=0; i<4; ++i)
charArray4[i] = DistrhoBase64Helpers::findBase64CharIndex(static_cast<char>(charArray4[i]));

charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];

for (i=0; i<3; ++i)
ret.push_back(static_cast<uint8_t>(charArray3[i]));

i = 0;
}
}

if (i != 0)
{
for (j=0; j<i && j<4; ++j)
charArray4[j] = DistrhoBase64Helpers::findBase64CharIndex(static_cast<char>(charArray4[j]));

for (j=i; j<4; ++j)
charArray4[j] = 0;

charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4);
charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2);
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3];

for (j=0; i>0 && j<i-1; j++)
ret.push_back(static_cast<uint8_t>(charArray3[j]));
}

return ret;
}

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

#endif // DISTRHO_BASE64_HPP_INCLUDED

+ 0
- 294
dpf/distrho/extra/ChildProcess.hpp View File

@@ -1,294 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#pragma once

#include "Sleep.hpp"
#include "Time.hpp"

#ifdef DISTRHO_OS_WINDOWS
# include <string>
# include <winsock2.h>
# include <windows.h>
#else
# include <cerrno>
# include <ctime>
# include <signal.h>
# include <sys/wait.h>
#endif

START_NAMESPACE_DISTRHO

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

class ChildProcess
{
#ifdef _WIN32
PROCESS_INFORMATION pinfo;
#else
pid_t pid;
#endif

public:
ChildProcess()
#ifdef _WIN32
: pinfo(CPP_AGGREGATE_INIT(PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 })
#else
: pid(-1)
#endif
{
}

~ChildProcess()
{
stop();
}

#ifdef _WIN32
bool start(const char* const args[], const WCHAR* const envp)
#else
bool start(const char* const args[], char* const* const envp = nullptr)
#endif
{
#ifdef _WIN32
std::string cmd;

for (uint i = 0; args[i] != nullptr; ++i)
{
if (i != 0)
cmd += " ";

if (args[i][0] != '"' && std::strchr(args[i], ' ') != nullptr)
{
cmd += "\"";
cmd += args[i];
cmd += "\"";
}
else
{
cmd += args[i];
}
}

wchar_t wcmd[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, cmd.data(), -1, wcmd, PATH_MAX) <= 0)
return false;

STARTUPINFOW si = {};
si.cb = sizeof(si);

d_stdout("will start process with args '%s'", cmd.data());

return CreateProcessW(nullptr, // lpApplicationName
wcmd, // lpCommandLine
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
TRUE, // bInheritHandles
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
const_cast<LPWSTR>(envp), // lpEnvironment
nullptr, // lpCurrentDirectory
&si, // lpStartupInfo
&pinfo) != FALSE;
#else
const pid_t ret = pid = vfork();

switch (ret)
{
// child process
case 0:
if (envp != nullptr)
execve(args[0], const_cast<char* const*>(args), envp);
else
execvp(args[0], const_cast<char* const*>(args));

d_stderr2("exec failed: %d:%s", errno, std::strerror(errno));
_exit(1);
break;

// error
case -1:
d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno));
break;
}

return ret > 0;
#endif
}

void stop(const uint32_t timeoutInMilliseconds = 2000)
{
const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds;
bool sendTerminate = true;

#ifdef _WIN32
if (pinfo.hProcess == INVALID_HANDLE_VALUE)
return;

const PROCESS_INFORMATION opinfo = pinfo;
pinfo = (PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };

for (DWORD exitCode;;)
{
if (GetExitCodeProcess(opinfo.hProcess, &exitCode) == FALSE ||
exitCode != STILL_ACTIVE ||
WaitForSingleObject(opinfo.hProcess, 0) != WAIT_TIMEOUT)
{
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
return;
}

if (sendTerminate)
{
sendTerminate = false;
TerminateProcess(opinfo.hProcess, ERROR_BROKEN_PIPE);
}

if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}
d_stderr("ChildProcess::stop() - timed out");
TerminateProcess(opinfo.hProcess, 9);
d_msleep(5);
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
break;
}
#else
if (pid <= 0)
return;

const pid_t opid = pid;
pid = -1;

for (pid_t ret;;)
{
try {
ret = ::waitpid(opid, nullptr, WNOHANG);
} DISTRHO_SAFE_EXCEPTION_BREAK("waitpid");

switch (ret)
{
case -1:
if (errno == ECHILD)
{
// success, child doesn't exist
return;
}
else
{
d_stderr("ChildProcess::stop() - waitpid failed: %d:%s", errno, std::strerror(errno));
return;
}
break;

case 0:
if (sendTerminate)
{
sendTerminate = false;
kill(opid, SIGTERM);
}
if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}

d_stderr("ChildProcess::stop() - timed out");
kill(opid, SIGKILL);
waitpid(opid, nullptr, WNOHANG);
break;

default:
if (ret == opid)
{
// success
return;
}
else
{
d_stderr("ChildProcess::stop() - got wrong pid %i (requested was %i)", int(ret), int(opid));
return;
}
}

break;
}
#endif
}

bool isRunning()
{
#ifdef _WIN32
if (pinfo.hProcess == INVALID_HANDLE_VALUE)
return false;

DWORD exitCode;
if (GetExitCodeProcess(pinfo.hProcess, &exitCode) == FALSE ||
exitCode != STILL_ACTIVE ||
WaitForSingleObject(pinfo.hProcess, 0) != WAIT_TIMEOUT)
{
const PROCESS_INFORMATION opinfo = pinfo;
pinfo = (PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
return false;
}

return true;
#else
if (pid <= 0)
return false;

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

if (ret == pid || (ret == -1 && errno == ECHILD))
{
pid = 0;
return false;
}

return true;
#endif
}

#ifndef _WIN32
void signal(const int sig)
{
if (pid > 0)
kill(pid, sig);
}
#endif

void terminate()
{
#ifdef _WIN32
if (pinfo.hProcess != INVALID_HANDLE_VALUE)
TerminateProcess(pinfo.hProcess, 15);
#else
if (pid > 0)
kill(pid, SIGTERM);
#endif
}

DISTRHO_DECLARE_NON_COPYABLE(ChildProcess)
};

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

END_NAMESPACE_DISTRHO

+ 0
- 578
dpf/distrho/extra/ExternalWindow.hpp View File

@@ -1,578 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED
#define DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED

#include "String.hpp"

#ifndef DISTRHO_OS_WINDOWS
# include <cerrno>
# include <signal.h>
# include <sys/wait.h>
# include <unistd.h>
#endif

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
{
struct PrivateData;

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

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

/**
Destructor.
*/
virtual ~ExternalWindow()
{
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
{
#ifndef DISTRHO_OS_WINDOWS
if (ext.inUse)
return ext.isRunning();
#endif
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
{
#ifndef DISTRHO_OS_WINDOWS
return ext.inUse ? ext.isQuitting : pData.isQuitting;
#else
return pData.isQuitting;
#endif
}

/**
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 pData.width;
}

/**
Get height of this window.
Only relevant to hosts when the UI is embedded.
*/
uint getHeight() const noexcept
{
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 pData.title;
}

#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 pData.parentWindowHandle;
}
#endif

/**
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 pData.transientWinId;
}

/* --------------------------------------------------------------------------------------------------------
* 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()
{
setVisible(false);
}

/**
Hide the UI and gracefully terminate.
Embed windows should never call this!
*/
virtual void close()
{
pData.isQuitting = true;
hide();
#ifndef DISTRHO_OS_WINDOWS
if (ext.inUse)
terminateAndWaitForExternalProcess();
#endif
}

/**
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_UINT_RETURN(width > 1, width,);
DISTRHO_SAFE_ASSERT_UINT_RETURN(height > 1, height,);

if (pData.width == width && pData.height == height)
return;

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

/**
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)
{
if (pData.title == title)
return;

pData.title = title;
titleChanged(title);
}

/**
Set geometry constraints for the Window when resized by the user.
*/
void setGeometryConstraints(uint minimumWidth, uint minimumHeight, bool keepAspectRatio = false)
{
DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumWidth > 0, minimumWidth,);
DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumHeight > 0, minimumHeight,);

pData.minWidth = minimumWidth;
pData.minHeight = minimumHeight;
pData.keepAspectRatio = keepAspectRatio;
}

/* --------------------------------------------------------------------------------------------------------
* TopLevelWidget-like calls - actions called by the host */

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

/**
Set window visible (or not) according to @a visible.
@see isVisible(), hide(), show()
*/
void setVisible(bool visible)
{
if (pData.visible == visible)
return;

pData.visible = visible;
visibilityChanged(visible);
}

/**
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)
{
if (pData.transientWinId == winId)
return;

pData.transientWinId = winId;
transientParentWindowChanged(winId);
}

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

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

return ext.start(args);
#else
(void)args;
return false; // TODO
#endif
}

void terminateAndWaitForExternalProcess()
{
#ifndef DISTRHO_OS_WINDOWS
ext.isQuitting = true;
ext.terminateAndWait();
#else
// TODO
#endif
}

/* --------------------------------------------------------------------------------------------------------
* ExternalWindow specific callbacks */

/**
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
}

/**
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 */)
{
// unused, meant for custom implementations
}

/**
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
}

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

private:
friend class PluginWindow;
friend class UI;

#ifndef DISTRHO_OS_WINDOWS
struct ExternalProcess {
bool inUse;
bool isQuitting;
mutable pid_t pid;

ExternalProcess()
: inUse(false),
isQuitting(false),
pid(0) {}

bool isRunning() const noexcept
{
if (pid <= 0)
return false;

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

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:
execvp(args[0], (char**)args);
_exit(1);
return false;

case -1:
d_stderr("Could not start external ui");
return false;

default:
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)
{
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;
}

// 5 msec
usleep(5*1000);
}
}
} ext;
#endif

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

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

DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow)
};

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_EXTERNAL_WINDOW_HPP_INCLUDED

+ 0
- 28
dpf/distrho/extra/FileBrowserDialog.hpp View File

@@ -1,28 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED
#define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

START_NAMESPACE_DISTRHO

#include "FileBrowserDialogImpl.hpp"

END_NAMESPACE_DISTRHO

#endif // DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED

+ 0
- 894
dpf/distrho/extra/FileBrowserDialogImpl.cpp View File

@@ -1,894 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED)
# error bad include
#endif
#if !defined(FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE) && !defined(FILE_BROWSER_DIALOG_DGL_NAMESPACE)
# error bad usage
#endif

#include "ScopedPointer.hpp"
#include "String.hpp"

#ifdef DISTRHO_OS_MAC
# import <Cocoa/Cocoa.h>
#endif

#ifdef DISTRHO_OS_WASM
# include <emscripten/emscripten.h>
# include <sys/stat.h>
#endif

#ifdef DISTRHO_OS_WINDOWS
# include <direct.h>
# include <process.h>
# include <winsock2.h>
# include <windows.h>
# include <commdlg.h>
# include <vector>
#else
# include <unistd.h>
#endif

#ifdef HAVE_DBUS
# include <dbus/dbus.h>
#endif

#ifdef HAVE_X11
# define DBLCLKTME 400
# include "sofd/libsofd.h"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-qual"
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wfloat-conversion"
# pragma GCC diagnostic ignored "-Wshadow"
# pragma GCC diagnostic ignored "-Wsign-conversion"
# pragma GCC diagnostic ignored "-Wstrict-overflow"
# endif
# include "sofd/libsofd.c"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic pop
# endif
# undef HAVE_MNTENT
# undef MAX
# undef MIN
#endif

#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE
START_NAMESPACE_DGL
using DISTRHO_NAMESPACE::ScopedPointer;
using DISTRHO_NAMESPACE::String;
#else
START_NAMESPACE_DISTRHO
#endif

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

// static pointer used for signal null/none action taken
static const char* const kSelectedFileCancelled = "__dpf_cancelled__";

#ifdef HAVE_DBUS
static constexpr bool isHexChar(const char c) noexcept
{
return c >= '0' && c <= 'f' && (c <= '9' || (c >= 'A' && c <= 'F') || c >= 'a');
}

static constexpr int toHexChar(const char c) noexcept
{
return c >= '0' && c <= '9' ? c - '0' : (c >= 'A' && c <= 'F' ? c - 'A' : c - 'a') + 10;
}
#endif

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

#ifdef DISTRHO_OS_WASM
# define DISTRHO_WASM_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION
# define DISTRHO_WASM_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_WASM_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION)
# define DISTRHO_WASM_NAMESPACE_HELPER(NS) #NS
# define DISTRHO_WASM_NAMESPACE(NS) DISTRHO_WASM_NAMESPACE_HELPER(NS)
# define fileBrowserSetPathNamespaced DISTRHO_WASM_NAMESPACE_MACRO(FILE_BROWSER_DIALOG_NAMESPACE, fileBrowserSetPath)
# define fileBrowserSetPathFuncName DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE) "_fileBrowserSetPath"

// FIXME use world class name as prefix
static bool openWebBrowserFileDialog(const char* const funcname, void* const handle)
{
const char* const nameprefix = DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE);

return EM_ASM_INT({
var canvasFileObjName = UTF8ToString($0) + "_file_open";
var canvasFileOpenElem = document.getElementById(canvasFileObjName);

var jsfuncname = UTF8ToString($1);
var jsfunc = Module.cwrap(jsfuncname, 'null', ['number', 'string']);

if (canvasFileOpenElem) {
document.body.removeChild(canvasFileOpenElem);
}

canvasFileOpenElem = document.createElement('input');
canvasFileOpenElem.type = 'file';
canvasFileOpenElem.id = canvasFileObjName;
canvasFileOpenElem.style.display = 'none';
document.body.appendChild(canvasFileOpenElem);

canvasFileOpenElem.onchange = function(e) {
if (!canvasFileOpenElem.files) {
jsfunc($2, "");
return;
}

// store uploaded files inside a specific dir
try {
Module.FS.mkdir('/userfiles');
} catch (e) {}

var file = canvasFileOpenElem.files[0];
var filename = '/userfiles/' + file.name;
var reader = new FileReader();

reader.onloadend = function(e) {
var content = new Uint8Array(reader.result);
Module.FS.writeFile(filename, content);
jsfunc($2, filename);
};

reader.readAsArrayBuffer(file);
};

canvasFileOpenElem.click();
return 1;
}, nameprefix, funcname, handle) != 0;
}

static bool downloadWebBrowserFile(const char* const filename)
{
const char* const nameprefix = DISTRHO_WASM_NAMESPACE(FILE_BROWSER_DIALOG_NAMESPACE);

return EM_ASM_INT({
var canvasFileObjName = UTF8ToString($0) + "_file_save";
var jsfilename = UTF8ToString($1);

var canvasFileSaveElem = document.getElementById(canvasFileObjName);
if (canvasFileSaveElem) {
// only 1 file save allowed at once
console.warn("One file save operation already in progress, refusing to open another");
return 0;
}

canvasFileSaveElem = document.createElement('a');
canvasFileSaveElem.download = jsfilename;
canvasFileSaveElem.id = canvasFileObjName;
canvasFileSaveElem.style.display = 'none';
document.body.appendChild(canvasFileSaveElem);

var content = Module.FS.readFile('/userfiles/' + jsfilename);
canvasFileSaveElem.href = URL.createObjectURL(new Blob([content]));
canvasFileSaveElem.click();

setTimeout(function() {
URL.revokeObjectURL(canvasFileSaveElem.href);
document.body.removeChild(canvasFileSaveElem);
}, 2000);
return 1;
}, nameprefix, filename) != 0;
}
#endif

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

struct FileBrowserData {
const char* selectedFile;

#ifdef DISTRHO_OS_MAC
NSSavePanel* nsBasePanel;
NSOpenPanel* nsOpenPanel;
#endif
#ifdef HAVE_DBUS
DBusConnection* dbuscon;
#endif
#ifdef HAVE_X11
Display* x11display;
#endif

#ifdef DISTRHO_OS_WASM
char* defaultName;
bool saving;
#endif

#ifdef DISTRHO_OS_WINDOWS
OPENFILENAMEW ofn;
volatile bool threadCancelled;
uintptr_t threadHandle;
std::vector<WCHAR> fileNameW;
std::vector<WCHAR> startDirW;
std::vector<WCHAR> titleW;
const bool saving;
bool isEmbed;

FileBrowserData(const bool save)
: selectedFile(nullptr),
threadCancelled(false),
threadHandle(0),
fileNameW(32768),
saving(save),
isEmbed(false)
{
std::memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = fileNameW.data();
ofn.nMaxFile = (DWORD)fileNameW.size();
}

~FileBrowserData()
{
if (cancelAndStop())
free();
}

void setupAndStart(const bool embed,
const char* const startDir,
const char* const windowTitle,
const uintptr_t winId,
const FileBrowserOptions options)
{
isEmbed = embed;

ofn.hwndOwner = (HWND)winId;

ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
ofn.Flags |= OFN_FORCESHOWHIDDEN;

ofn.FlagsEx = 0x0;
if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible)
ofn.FlagsEx |= OFN_EX_NOPLACESBAR;

startDirW.resize(std::strlen(startDir) + 1);
if (MultiByteToWideChar(CP_UTF8, 0, startDir, -1, startDirW.data(), static_cast<int>(startDirW.size())))
ofn.lpstrInitialDir = startDirW.data();

titleW.resize(std::strlen(windowTitle) + 1);
if (MultiByteToWideChar(CP_UTF8, 0, windowTitle, -1, titleW.data(), static_cast<int>(titleW.size())))
ofn.lpstrTitle = titleW.data();

uint threadId;
threadCancelled = false;
threadHandle = _beginthreadex(nullptr, 0, _run, this, 0, &threadId);
}

bool cancelAndStop()
{
threadCancelled = true;

if (threadHandle == 0)
return true;

// if previous dialog running, carefully close its window
const HWND owner = isEmbed ? GetParent(ofn.hwndOwner) : ofn.hwndOwner;

if (owner != nullptr && owner != INVALID_HANDLE_VALUE)
{
const HWND window = GetWindow(owner, GW_HWNDFIRST);

if (window != nullptr && window != INVALID_HANDLE_VALUE)
{
SendMessage(window, WM_SYSCOMMAND, SC_CLOSE, 0);
SendMessage(window, WM_CLOSE, 0, 0);
WaitForSingleObject((HANDLE)threadHandle, 5000);
}
}

if (threadHandle == 0)
return true;

// not good if thread still running, but let's close the handle anyway
CloseHandle((HANDLE)threadHandle);
threadHandle = 0;
return false;
}

void run()
{
const char* nextFile = nullptr;

if (saving ? GetSaveFileNameW(&ofn) : GetOpenFileNameW(&ofn))
{
if (threadCancelled)
{
threadHandle = 0;
return;
}

// back to UTF-8
std::vector<char> fileNameA(4 * 32768);
if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1,
fileNameA.data(), (int)fileNameA.size(),
nullptr, nullptr))
{
nextFile = strdup(fileNameA.data());
}
}

if (threadCancelled)
{
threadHandle = 0;
return;
}

if (nextFile == nullptr)
nextFile = kSelectedFileCancelled;

selectedFile = nextFile;
threadHandle = 0;
}

static unsigned __stdcall _run(void* const arg)
{
// CoInitializeEx(nullptr, COINIT_MULTITHREADED);
static_cast<FileBrowserData*>(arg)->run();
// CoUninitialize();
_endthreadex(0);
return 0;
}
#else // DISTRHO_OS_WINDOWS
FileBrowserData(const bool save)
: selectedFile(nullptr)
#ifdef DISTRHO_OS_MAC
, nsBasePanel(nullptr)
, nsOpenPanel(nullptr)
#endif
#ifdef HAVE_DBUS
, dbuscon(nullptr)
#endif
#ifdef HAVE_X11
, x11display(nullptr)
#endif
{
#ifdef DISTRHO_OS_MAC
if (save)
{
nsOpenPanel = nullptr;
nsBasePanel = [[NSSavePanel savePanel]retain];
}
else
{
nsOpenPanel = [[NSOpenPanel openPanel]retain];
nsBasePanel = nsOpenPanel;
}
#endif
#ifdef DISTRHO_OS_WASM
defaultName = nullptr;
saving = save;
#endif
#ifdef HAVE_DBUS
if ((dbuscon = dbus_bus_get(DBUS_BUS_SESSION, nullptr)) != nullptr)
dbus_connection_set_exit_on_disconnect(dbuscon, false);
#endif
#ifdef HAVE_X11
x11display = XOpenDisplay(nullptr);
#endif

// maybe unused
return; (void)save;
}

~FileBrowserData()
{
#ifdef DISTRHO_OS_MAC
[nsBasePanel release];
#endif
#ifdef DISTRHO_OS_WASM
std::free(defaultName);
#endif
#ifdef HAVE_DBUS
if (dbuscon != nullptr)
dbus_connection_unref(dbuscon);
#endif
#ifdef HAVE_X11
if (x11display != nullptr)
XCloseDisplay(x11display);
#endif

free();
}
#endif

void free()
{
if (selectedFile == nullptr)
return;

if (selectedFile == kSelectedFileCancelled || std::strcmp(selectedFile, kSelectedFileCancelled) == 0)
{
selectedFile = nullptr;
return;
}

std::free(const_cast<char*>(selectedFile));
selectedFile = nullptr;
}

DISTRHO_DECLARE_NON_COPYABLE(FileBrowserData)
};

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

#ifdef DISTRHO_OS_WASM
extern "C" {
EMSCRIPTEN_KEEPALIVE
void fileBrowserSetPathNamespaced(FileBrowserHandle handle, const char* filename)
{
handle->free();

if (filename != nullptr && filename[0] != '\0')
handle->selectedFile = strdup(filename);
else
handle->selectedFile = kSelectedFileCancelled;
}
}
#endif

FileBrowserHandle fileBrowserCreate(const bool isEmbed,
const uintptr_t windowId,
const double scaleFactor,
const FileBrowserOptions& options)
{
String startDir(options.startDir);

if (startDir.isEmpty())
{
#ifdef DISTRHO_OS_WINDOWS
if (char* const cwd = _getcwd(nullptr, 0))
#else
if (char* const cwd = getcwd(nullptr, 0))
#endif
{
startDir = cwd;
std::free(cwd);
}
}

DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), nullptr);

if (! startDir.endsWith(DISTRHO_OS_SEP))
startDir += DISTRHO_OS_SEP_STR;

String windowTitle(options.title);

if (windowTitle.isEmpty())
windowTitle = "FileBrowser";

ScopedPointer<FileBrowserData> handle(new FileBrowserData(options.saving));

#ifdef DISTRHO_OS_MAC
# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
// unsupported
d_stderr2("fileBrowserCreate is unsupported on macos < 10.8");
return nullptr;
# else
NSSavePanel* const nsBasePanel = handle->nsBasePanel;
DISTRHO_SAFE_ASSERT_RETURN(nsBasePanel != nullptr, nullptr);

if (! options.saving)
{
NSOpenPanel* const nsOpenPanel = handle->nsOpenPanel;
DISTRHO_SAFE_ASSERT_RETURN(nsOpenPanel != nullptr, nullptr);

[nsOpenPanel setAllowsMultipleSelection:NO];
[nsOpenPanel setCanChooseDirectories:NO];
[nsOpenPanel setCanChooseFiles:YES];
}

NSString* const startDirString = [[NSString alloc]
initWithBytes:startDir
length:strlen(startDir)
encoding:NSUTF8StringEncoding];
[nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:startDirString]];

// TODO file filter using allowedContentTypes: [UTType]

if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked)
[nsBasePanel setAllowsOtherFileTypes:YES];
if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
[nsBasePanel setShowsHiddenFiles:YES];

NSString* const titleString = [[NSString alloc]
initWithBytes:windowTitle
length:strlen(windowTitle)
encoding:NSUTF8StringEncoding];
[nsBasePanel setTitle:titleString];

FileBrowserData* const handleptr = handle.get();

dispatch_async(dispatch_get_main_queue(), ^
{
[nsBasePanel beginSheetModalForWindow:[(NSView*)windowId window]
completionHandler:^(NSModalResponse result)
{
if (result == NSModalResponseOK && [[nsBasePanel URL] isFileURL])
{
NSString* const path = [[nsBasePanel URL] path];
handleptr->selectedFile = strdup([path UTF8String]);
}
else
{
handleptr->selectedFile = kSelectedFileCancelled;
}
}];
});

[startDirString release];
[titleString release];
# endif
#endif

#ifdef DISTRHO_OS_WASM
if (options.saving)
{
const size_t len = options.defaultName != nullptr ? strlen(options.defaultName) : 0;
DISTRHO_SAFE_ASSERT_RETURN(len != 0, nullptr);

// store uploaded files inside a specific dir
mkdir("/userfiles", 0777);

char* const filename = static_cast<char*>(malloc(len + 12));
std::strncpy(filename, "/userfiles/", 12);
std::memcpy(filename + 11, options.defaultName, len + 1);

handle->defaultName = strdup(options.defaultName);
handle->selectedFile = filename;
return handle.release();
}

const char* const funcname = fileBrowserSetPathFuncName;
if (openWebBrowserFileDialog(funcname, handle.get()))
return handle.release();

return nullptr;
#endif

#ifdef DISTRHO_OS_WINDOWS
handle->setupAndStart(isEmbed, startDir, windowTitle, windowId, options);
#endif

#ifdef HAVE_DBUS
// optional, can be null
DBusConnection* const dbuscon = handle->dbuscon;

// https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser
if (dbuscon != nullptr)
{
// if this is the first time we are calling into DBus, check if things are working
static bool checkAvailable = !dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr);

if (checkAvailable)
{
checkAvailable = false;

if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.FileChooser",
"version"))
{
if (DBusMessage* const reply = dbus_connection_send_with_reply_and_block(dbuscon, msg, 250, nullptr))
dbus_message_unref(reply);

dbus_message_unref(msg);
}
}

// Any subsquent calls should have this DBus service active
if (dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr))
{
if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.FileChooser",
options.saving ? "SaveFile" : "OpenFile"))
{
#ifdef HAVE_X11
char windowIdStr[32];
memset(windowIdStr, 0, sizeof(windowIdStr));
snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId);
const char* windowIdStrPtr = windowIdStr;
#endif

dbus_message_append_args(msg,
#ifdef HAVE_X11
DBUS_TYPE_STRING, &windowIdStrPtr,
#endif
DBUS_TYPE_STRING, &windowTitle,
DBUS_TYPE_INVALID);

DBusMessageIter iter, array;
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);

{
DBusMessageIter dict, variant, variantArray;
const char* const current_folder_key = "current_folder";
const char* const current_folder_val = startDir.buffer();

dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &current_folder_key);
dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant);
dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray);
dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE,
&current_folder_val,
static_cast<int>(startDir.length() + 1));
dbus_message_iter_close_container(&variant, &variantArray);
dbus_message_iter_close_container(&dict, &variant);
dbus_message_iter_close_container(&array, &dict);
}

dbus_message_iter_close_container(&iter, &array);

dbus_connection_send(dbuscon, msg, nullptr);

dbus_message_unref(msg);
return handle.release();
}
}
}
#endif

#ifdef HAVE_X11
Display* const x11display = handle->x11display;
DISTRHO_SAFE_ASSERT_RETURN(x11display != nullptr, nullptr);

// unsupported at the moment
if (options.saving)
return nullptr;

DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, nullptr);
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, windowTitle) == 0, nullptr);

const int button1 = options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked ? 1
: options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
const int button2 = options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked ? 1
: options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
const int button3 = options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked ? 1
: options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;

x_fib_cfg_buttons(1, button1);
x_fib_cfg_buttons(2, button2);
x_fib_cfg_buttons(3, button3);

if (x_fib_show(x11display, windowId, 0, 0, scaleFactor + 0.5) != 0)
return nullptr;
#endif

return handle.release();

// might be unused
(void)isEmbed;
(void)windowId;
(void)scaleFactor;
}

// --------------------------------------------------------------------------------------------------------------------
// returns true if dialog was closed (with or without a file selection)

bool fileBrowserIdle(const FileBrowserHandle handle)
{
#ifdef HAVE_DBUS
if (DBusConnection* dbuscon = handle->dbuscon)
{
while (dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_DATA_REMAINS) {}
dbus_connection_read_write_dispatch(dbuscon, 0);

if (DBusMessage* const msg = dbus_connection_pop_message(dbuscon))
{
const char* const interface = dbus_message_get_interface(msg);
const char* const member = dbus_message_get_member(msg);

if (interface != nullptr && std::strcmp(interface, "org.freedesktop.portal.Request") == 0
&& member != nullptr && std::strcmp(member, "Response") == 0)
{
do {
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);

// starts with uint32 for return/exit code
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32);

uint32_t ret = 1;
dbus_message_iter_get_basic(&iter, &ret);

if (ret != 0)
break;

// next must be array
dbus_message_iter_next(&iter);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);

// open dict array
DBusMessageIter dictArray;
dbus_message_iter_recurse(&iter, &dictArray);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);

// open containing dict
DBusMessageIter dict;
dbus_message_iter_recurse(&dictArray, &dict);

// look for dict with string "uris"
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);

const char* key = nullptr;
dbus_message_iter_get_basic(&dict, &key);
DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);

// keep going until we find it
while (std::strcmp(key, "uris") != 0)
{
key = nullptr;
dbus_message_iter_next(&dictArray);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);

dbus_message_iter_recurse(&dictArray, &dict);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);

dbus_message_iter_get_basic(&dict, &key);
DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);
}

if (key == nullptr)
break;

// then comes variant
dbus_message_iter_next(&dict);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_VARIANT);

DBusMessageIter variant;
dbus_message_iter_recurse(&dict, &variant);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY);

// open variant array (variant type is string)
DBusMessageIter variantArray;
dbus_message_iter_recurse(&variant, &variantArray);
DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variantArray) == DBUS_TYPE_STRING);

const char* value = nullptr;
dbus_message_iter_get_basic(&variantArray, &value);

// and finally we have our dear value, just make sure it is local
DISTRHO_SAFE_ASSERT_BREAK(value != nullptr);

if (const char* const localvalue = std::strstr(value, "file:///"))
{
if (char* const decodedvalue = strdup(localvalue + 7))
{
for (char* s = decodedvalue; (s = std::strchr(s, '%')) != nullptr; ++s)
{
if (! isHexChar(s[1]) || ! isHexChar(s[2]))
continue;

const int decodedNum = toHexChar(s[1]) * 0x10 + toHexChar(s[2]);

char replacementChar;
switch (decodedNum)
{
case 0x20: replacementChar = ' '; break;
case 0x22: replacementChar = '\"'; break;
case 0x23: replacementChar = '#'; break;
case 0x25: replacementChar = '%'; break;
case 0x3c: replacementChar = '<'; break;
case 0x3e: replacementChar = '>'; break;
case 0x5b: replacementChar = '['; break;
case 0x5c: replacementChar = '\\'; break;
case 0x5d: replacementChar = ']'; break;
case 0x5e: replacementChar = '^'; break;
case 0x60: replacementChar = '`'; break;
case 0x7b: replacementChar = '{'; break;
case 0x7c: replacementChar = '|'; break;
case 0x7d: replacementChar = '}'; break;
case 0x7e: replacementChar = '~'; break;
default: continue;
}

s[0] = replacementChar;
std::memmove(s + 1, s + 3, std::strlen(s) - 2);
}

handle->selectedFile = decodedvalue;
}
}

} while(false);

if (handle->selectedFile == nullptr)
handle->selectedFile = kSelectedFileCancelled;
}

dbus_message_unref(msg);
}
}
#endif

#ifdef HAVE_X11
Display* const x11display = handle->x11display;

if (x11display == nullptr)
return false;

XEvent event;
while (XPending(x11display) > 0)
{
XNextEvent(x11display, &event);

if (x_fib_handle_events(x11display, &event) == 0)
continue;

if (x_fib_status() > 0)
handle->selectedFile = x_fib_filename();
else
handle->selectedFile = kSelectedFileCancelled;

x_fib_close(x11display);
XCloseDisplay(x11display);
handle->x11display = nullptr;
break;
}
#endif

return handle->selectedFile != nullptr;
}

// --------------------------------------------------------------------------------------------------------------------
// close sofd file dialog

void fileBrowserClose(const FileBrowserHandle handle)
{
#ifdef DISTRHO_OS_WASM
if (handle->saving && fileBrowserGetPath(handle) != nullptr)
downloadWebBrowserFile(handle->defaultName);
#endif

#ifdef HAVE_X11
if (Display* const x11display = handle->x11display)
x_fib_close(x11display);
#endif

delete handle;
}

// --------------------------------------------------------------------------------------------------------------------
// get path chosen via sofd file dialog

const char* fileBrowserGetPath(const FileBrowserHandle handle)
{
if (const char* const selectedFile = handle->selectedFile)
if (selectedFile != kSelectedFileCancelled && std::strcmp(selectedFile, kSelectedFileCancelled) != 0)
return selectedFile;

return nullptr;
}

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

#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE
END_NAMESPACE_DGL
#else
END_NAMESPACE_DISTRHO
#endif

#undef FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE
#undef FILE_BROWSER_DIALOG_DGL_NAMESPACE
#undef FILE_BROWSER_DIALOG_NAMESPACE

#undef fileBrowserSetPathNamespaced
#undef fileBrowserSetPathFuncName

+ 0
- 129
dpf/distrho/extra/FileBrowserDialogImpl.hpp View File

@@ -1,129 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED)
# error bad include
#endif

#if !defined(DGL_USE_FILE_BROWSER) && defined(DISTRHO_UI_FILE_BROWSER) && DISTRHO_UI_FILE_BROWSER == 0
# error To use File Browser in DPF plugins please set DISTRHO_UI_FILE_BROWSER to 1
#endif

// --------------------------------------------------------------------------------------------------------------------
// File Browser Dialog stuff

struct FileBrowserData;
typedef FileBrowserData* FileBrowserHandle;

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

/**
File browser options, for customizing the file browser dialog.@n
By default the file browser dialog will be work as "open file" in the current working directory.
*/
struct FileBrowserOptions {
/** Whether we are saving, opening files otherwise (default) */
bool saving;

/** Default filename when saving, required in some platforms (basename without path separators) */
const char* defaultName;

/** Start directory, uses current working directory if null */
const char* startDir;

/** File browser dialog window title, uses "FileBrowser" if null */
const char* title;

/** Class name of the matching Application instance that controls this dialog */
const char* className;

// TODO file filter

/**
File browser button state.
This allows to customize the behaviour of the file browse dialog buttons.
Note these are merely hints, not all systems support them.
*/
enum ButtonState {
kButtonInvisible,
kButtonVisibleUnchecked,
kButtonVisibleChecked,
};

/**
File browser buttons.
*/
struct Buttons {
/** Whether to list all files vs only those with matching file extension */
ButtonState listAllFiles;
/** Whether to show hidden files */
ButtonState showHidden;
/** Whether to show list of places (bookmarks) */
ButtonState showPlaces;

/** Constructor for default values */
Buttons()
: listAllFiles(kButtonVisibleChecked),
showHidden(kButtonVisibleUnchecked),
showPlaces(kButtonVisibleChecked) {}
} buttons;

/** Constructor for default values */
FileBrowserOptions()
: saving(false),
defaultName(nullptr),
startDir(nullptr),
title(nullptr),
className(nullptr),
buttons() {}
};

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

/**
Create a new file browser dialog.

@p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows)
@p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*)
@p scaleFactor: Scale factor to use (only used on X11)
@p options: Extra options, optional
By default the file browser dialog will work as "open file" in the current working directory.
*/
FileBrowserHandle fileBrowserCreate(bool isEmbed,
uintptr_t windowId,
double scaleFactor,
const FileBrowserOptions& options = FileBrowserOptions());

/**
Idle the file browser dialog handle.@n
Returns true if dialog was closed (with or without a file selection),
in which case this idle function must not be called anymore for this handle.
You can then call fileBrowserGetPath to know the selected file (or null if cancelled).
*/
bool fileBrowserIdle(FileBrowserHandle handle);

/**
Close and free the file browser dialog, handle must not be used afterwards.
*/
void fileBrowserClose(FileBrowserHandle handle);

/**
Get the path chosen by the user or null.@n
Should only be called after fileBrowserIdle returns true.
*/
const char* fileBrowserGetPath(FileBrowserHandle handle);

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

+ 0
- 106
dpf/distrho/extra/Filesystem.hpp View File

@@ -1,106 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED
#define DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED

#include "String.hpp"

#include <cstdio>

#ifdef DISTRHO_OS_WINDOWS
# include <stringapiset.h>
#endif

START_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------
// filesystem related calls

/*
* Wrapper around `fopen` call, needed on Windows because its C standard functions use ASCII instead of UTF-8.
*/
static inline
FILE* d_fopen(const char* const pathname, const char* const mode)
{
#ifdef DISTRHO_OS_WINDOWS
WCHAR lpathname[MAX_PATH];
WCHAR lmode[4];
if (MultiByteToWideChar(CP_UTF8, 0, pathname, -1, lpathname, ARRAY_SIZE(lpathname)) != 0 &&
MultiByteToWideChar(CP_UTF8, 0, mode, -1, lmode, ARRAY_SIZE(lmode)) != 0)
return _wfopen(lpathname, lmode);
#endif

return fopen(pathname, mode);
}

// --------------------------------------------------------------------------------------------------------------------
// filesystem related classes

/**
Handy class to help write files in a safe way, which does:
- open pathname + ".tmp" instead of opening a file directly (so partial writes are safe)
- on close, flush data to disk and rename file to remove ".tmp"

To use it, create a local variable (on the stack) and call ok() or manually check @a fd variable.
@code
if (const SafeFileWriter file("/path/to/file.txt"); file.ok())
file.write("Success!");
@endcode
*/
struct SafeFileWriter
{
String filename;
FILE* const fd;

/**
Constructor, opening @a pathname + ".tmp" for writing.
*/
SafeFileWriter(const char* const pathname, const char* const mode = "w")
: filename(pathname),
fd(d_fopen(filename + ".tmp", mode)) {}

/**
Destructor, will flush file data contents, close and rename file.
*/
~SafeFileWriter()
{
if (fd == nullptr)
return;

std::fflush(fd);
std::fclose(fd);
std::rename(filename + ".tmp", filename);
}

/** Check if the file was opened successfully. */
inline bool ok() const noexcept
{
return fd != nullptr;
}

/** Wrapper around `fwrite`, purely for convenience. */
inline size_t write(const void* const ptr, const size_t size, const size_t nmemb = 1) const
{
return std::fwrite(ptr, size, nmemb, fd);
}
};

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED

+ 0
- 251
dpf/distrho/extra/Runner.hpp View File

@@ -1,251 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_RUNNER_HPP_INCLUDED
#define DISTRHO_RUNNER_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#ifndef DISTRHO_OS_WASM
# include "Thread.hpp"
#else
# include "String.hpp"
# include <emscripten/html5.h>
#endif

START_NAMESPACE_DISTRHO

#ifdef DISTRHO_RUNNER_INDIRECT_WASM_CALLS
long d_emscripten_set_interval(void (*)(void*), double, void*);
void d_emscripten_clear_interval(long);
#else
# define d_emscripten_set_interval emscripten_set_interval
# define d_emscripten_clear_interval emscripten_clear_interval
#endif

// -------------------------------------------------------------------------------------------------------------------
// Runner class

/**
Runner class for DPF.

This is a handy class that handles "idle" time in either background or main thread,
whichever is more suitable to the target platform.
Typically background threads on desktop platforms, main thread on web.

A single function is expected to be implemented by subclasses,
which directly allows it to stop the runner by returning false.

You can use it for quick operations that do not need to be handled in the main thread if possible.
The target is to spread out execution over many runs, instead of spending a lot of time on a single task.
*/
class Runner
{
protected:
/*
* Constructor.
*/
Runner(const char* const runnerName = nullptr) noexcept
#ifndef DISTRHO_OS_WASM
: fRunnerThread(this, runnerName),
fTimeInterval(0)
#else
: fRunnerName(runnerName),
fIntervalId(0)
#endif
{
}

/*
* Destructor.
*/
virtual ~Runner() /*noexcept*/
{
DISTRHO_SAFE_ASSERT(! isRunnerActive());

stopRunner();
}

/*
* Virtual function to be implemented by the subclass.
* Return true to keep running, false to stop execution.
*/
virtual bool run() = 0;

/*
* Check if the runner should stop.
* To be called from inside the runner to know if a stop request has been made.
*/
bool shouldRunnerStop() const noexcept
{
#ifndef DISTRHO_OS_WASM
return fRunnerThread.shouldThreadExit();
#else
return fIntervalId == 0;
#endif
}

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

public:
/*
* Check if the runner is active.
*/
bool isRunnerActive() noexcept
{
#ifndef DISTRHO_OS_WASM
return fRunnerThread.isThreadRunning();
#else
return fIntervalId != 0;
#endif
}

/*
* Start the runner.
*/
bool startRunner(const uint timeIntervalMilliseconds = 0) noexcept
{
#ifndef DISTRHO_OS_WASM
DISTRHO_SAFE_ASSERT_RETURN(!fRunnerThread.isThreadRunning(), false);
fTimeInterval = timeIntervalMilliseconds;
return fRunnerThread.startThread();
#else
DISTRHO_SAFE_ASSERT_RETURN(fIntervalId == 0, false);
fIntervalId = d_emscripten_set_interval(_entryPoint, timeIntervalMilliseconds, this);
return true;
#endif
}

/*
* Stop the runner.
* This will signal the runner to stop if active, and wait until it finishes.
*/
bool stopRunner() noexcept
{
#ifndef DISTRHO_OS_WASM
return fRunnerThread.stopThread(-1);
#else
signalRunnerShouldStop();
return true;
#endif
}

/*
* Tell the runner to stop as soon as possible.
*/
void signalRunnerShouldStop() noexcept
{
#ifndef DISTRHO_OS_WASM
fRunnerThread.signalThreadShouldExit();
#else
if (fIntervalId != 0)
{
d_emscripten_clear_interval(fIntervalId);
fIntervalId = 0;
}
#endif
}

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

/*
* Returns the name of the runner.
* This is the name that gets set in the constructor.
*/
const String& getRunnerName() const noexcept
{
#ifndef DISTRHO_OS_WASM
return fRunnerThread.getThreadName();
#else
return fRunnerName;
#endif
}

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

private:
#ifndef DISTRHO_OS_WASM
class RunnerThread : public Thread
{
Runner* const runner;

public:
RunnerThread(Runner* const r, const char* const rn)
: Thread(rn),
runner(r) {}

protected:
void run() override
{
const uint timeInterval = runner->fTimeInterval;

while (!shouldThreadExit())
{
bool stillRunning = false;

try {
stillRunning = runner->run();
} catch(...) {}

if (stillRunning && !shouldThreadExit())
{
if (timeInterval != 0)
d_msleep(timeInterval);

// FIXME
// pthread_yield();
continue;
}

break;
}
}
} fRunnerThread;

uint fTimeInterval;
#else
const String fRunnerName;
long fIntervalId;

void _runEntryPoint() noexcept
{
bool stillRunning = false;

try {
stillRunning = run();
} catch(...) {}

if (fIntervalId != 0 && !stillRunning)
{
d_emscripten_clear_interval(fIntervalId);
fIntervalId = 0;
}
}

static void _entryPoint(void* const userData) noexcept
{
static_cast<Runner*>(userData)->_runEntryPoint();
}
#endif

DISTRHO_DECLARE_NON_COPYABLE(Runner)
};

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_RUNNER_HPP_INCLUDED

+ 0
- 127
dpf/distrho/extra/Time.hpp View File

@@ -1,127 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_TIME_HPP_INCLUDED
#define DISTRHO_TIME_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#ifdef DISTRHO_OS_WINDOWS
# include <winsock2.h>
# include <windows.h>
# include <mmsystem.h>
#else
# include <ctime>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------
// d_gettime_*

/*
* Get a monotonically-increasing time in milliseconds.
*/
static inline
uint32_t d_gettime_ms() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const time_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000;
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000) - s;
#elif defined(DISTRHO_OS_WINDOWS)
return static_cast<uint32_t>(timeGetTime());
#else
static struct {
timespec ts;
int r;
uint32_t ms;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint32_t>(s.ts.tv_sec * 1000 +
s.ts.tv_nsec / 1000000) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) - s.ms;
#endif
}

/*
* Get a monotonically-increasing time in microseconds.
*/
static inline
uint64_t d_gettime_us() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000;
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000) - s;
#elif defined(DISTRHO_OS_WINDOWS)
static struct {
LARGE_INTEGER freq;
LARGE_INTEGER counter;
BOOL r1, r2;
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) };

LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (counter.QuadPart - s.counter.QuadPart) * 1000000 / s.freq.QuadPart;
#else
static struct {
timespec ts;
int r;
uint64_t us;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000 +
s.ts.tv_nsec / 1000) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) - s.us;
#endif
}

/*
* Get a monotonically-increasing time in nanoseconds.
*/
static inline
uint64_t d_gettime_ns() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) - s;
#elif defined(DISTRHO_OS_WINDOWS)
static struct {
LARGE_INTEGER freq;
LARGE_INTEGER counter;
BOOL r1, r2;
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) };

LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (counter.QuadPart - s.counter.QuadPart) * 1000000000ULL / s.freq.QuadPart;
#else
static struct {
timespec ts;
int r;
uint64_t ns;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000000ULL +
s.ts.tv_nsec) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000000000ULL + ts.tv_nsec) - s.ns;
#endif
}

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

END_NAMESPACE_DISTRHO

#endif // DISTRHO_TIME_HPP_INCLUDED

+ 0
- 28
dpf/distrho/extra/WebView.hpp View File

@@ -1,28 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_WEB_VIEW_HPP_INCLUDED
#define DISTRHO_WEB_VIEW_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

START_NAMESPACE_DISTRHO

#include "WebViewImpl.hpp"

END_NAMESPACE_DISTRHO

#endif // DISTRHO_WEB_VIEW_HPP_INCLUDED

+ 0
- 2072
dpf/distrho/extra/WebViewImpl.cpp
File diff suppressed because it is too large
View File


+ 0
- 136
dpf/distrho/extra/WebViewImpl.hpp View File

@@ -1,136 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED)
# error bad include
#endif

#if !defined(DGL_USE_WEB_VIEW) && defined(DISTRHO_UI_WEB_VIEW) && DISTRHO_UI_WEB_VIEW == 0
# error To use WebViews in DPF plugins please set DISTRHO_UI_WEB_VIEW to 1
#endif

// --------------------------------------------------------------------------------------------------------------------
// Web View stuff

struct WebViewData;
typedef WebViewData* WebViewHandle;
typedef void (*WebViewMessageCallback)(void* arg, char* msg);

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

/**
Web view options, for customizing web view details.
*/
struct WebViewOptions {
/**
Position offset, for cases of mixing regular widgets with web views.
*/
struct PositionOffset {
/** Horizontal offset, with scale factor pre-applied */
int x;

/** Vertical offset, with scale factor pre-applied */
int y;

/** Constructor for default values */
PositionOffset() : x(0), y(0) {}
} offset;

/**
Set some JavaScript to evalute on every new page load.
*/
const char* initialJS;

/**
Message callback triggered from JavaScript code inside the WebView.
*/
WebViewMessageCallback callback;
void* callbackPtr;

/** Constructor for default values */
WebViewOptions()
: offset(),
initialJS(nullptr),
callback(nullptr),
callbackPtr(nullptr) {}

/** Constructor providing a callback */
WebViewOptions(const WebViewMessageCallback cb, void* const ptr)
: offset(),
initialJS(nullptr),
callback(cb),
callbackPtr(ptr) {}
};

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

/**
Create a new web view.

The web view will be added on top of an existing platform-specific view/window.
This means it will draw on top of whatever is below it,
something to take into consideration if mixing regular widgets with web views.

Provided metrics must have scale factor pre-applied.

@p url: The URL to open, assumed to be in encoded form (e.g spaces converted to %20)
@p windowId: The native window id to attach this view to (X11 Window, HWND or NSView*)
@p scaleFactor: Scale factor in use
@p options: Extra options, optional
*/
WebViewHandle webViewCreate(const char* url,
uintptr_t windowId,
uint initialWidth,
uint initialHeight,
double scaleFactor,
const WebViewOptions& options = WebViewOptions());

/**
Destroy the web view, handle must not be used afterwards.
*/
void webViewDestroy(WebViewHandle webview);

/**
Idle the web view, to be called on regular intervals.
Can cause callbacks to trigger.
*/
void webViewIdle(WebViewHandle webview);

/**
Evaluate/run JavaScript on the web view.
*/
void webViewEvaluateJS(WebViewHandle webview, const char* js);

/**
Reload the web view current page.
*/
void webViewReload(WebViewHandle webview);

/**
Resize the web view.
*/
void webViewResize(WebViewHandle webview, uint width, uint height, double scaleFactor);

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

/**
Helper class for usage in std::shared_ptr and std::unique_ptr.
*/
struct WebViewDestroy {
void operator()(WebViewHandle handle) { webViewDestroy(handle); }
};

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

+ 0
- 122
dpf/distrho/extra/WebViewWin32.hpp View File

@@ -1,122 +0,0 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 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
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED)
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION
# include "WebView.hpp"
#endif

// --------------------------------------------------------------------------------------------------------------------
// Web View stuff

START_NAMESPACE_DISTRHO

class WebView;

END_NAMESPACE_DISTRHO

#ifdef WEB_VIEW_DGL_NAMESPACE
START_NAMESPACE_DGL
using DISTRHO_NAMESPACE::WebView;
#else
START_NAMESPACE_DISTRHO
#endif

WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts);
void webview_choc_destroy(WebView*);
void* webview_choc_handle(WebView*);
void webview_choc_eval(WebView*, const char* js);
void webview_choc_navigate(WebView*, const char* url);

#ifdef WEB_VIEW_DGL_NAMESPACE
END_NAMESPACE_DGL
#else
END_NAMESPACE_DISTRHO
#endif

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

#ifdef DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION

# define WC_ERR_INVALID_CHARS 0
# include "choc/choc_WebView.h"

#ifdef WEB_VIEW_DGL_NAMESPACE
START_NAMESPACE_DGL
#else
START_NAMESPACE_DISTRHO
#endif

WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts)
{
WebView::Options wopts;
wopts.acceptsFirstMouseClick = true;
wopts.enableDebugMode = true;

std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts);
DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr);

if (const WEB_VIEW_NAMESPACE::WebViewMessageCallback callback = opts.callback)
{
webview->addInitScript("function postMessage(m){window.chrome.webview.postMessage(m);}");

void* const callbackPtr = opts.callbackPtr;
webview->bind([callback, callbackPtr](const std::string& value) {
char* const data = strdup(value.data());
callback(callbackPtr, data);
std::free(data);
});
}
else
{
webview->addInitScript("function postMessage(m){}");
}

if (opts.initialJS != nullptr)
webview->addInitScript(opts.initialJS);

return webview.release();
}

void webview_choc_destroy(WebView* const webview)
{
delete webview;
}

void* webview_choc_handle(WebView* const webview)
{
return webview->getViewHandle();
}

void webview_choc_eval(WebView* const webview, const char* const js)
{
webview->evaluateJavascript(js);
}

void webview_choc_navigate(WebView* const webview, const char* const url)
{
webview->navigate(url);
}

#ifdef WEB_VIEW_DGL_NAMESPACE
END_NAMESPACE_DGL
#else
END_NAMESPACE_DISTRHO
#endif

#endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION

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

+ 0
- 15
dpf/distrho/extra/choc/LICENSE.md View File

@@ -1,15 +0,0 @@
## CHOC: licensing

I'd like anyone to feel able to use this library code without worrying about the legal implications, so it's released under the permissive ISC license:

----

**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 permission notice appear in all copies.**

**THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.**

https://en.wikipedia.org/wiki/ISC_license

----

Note that if you use the `choc::ui::WebView` class on Windows, it embeds some Microsoft redistributable code which has its own (permissive) license that you should be aware of. See inside the file `choc_WebView.h` for more details.

+ 0
- 22
dpf/distrho/extra/choc/README.md View File

@@ -1,22 +0,0 @@
Taken from https://github.com/Tracktion/choc

```
commit 2512542b2d65f3e92df7f2f1f7eeb712fa41a0de (HEAD -> main, origin/main, origin/HEAD)
Author: Cesare Ferrari <cesare.ferrari@gmail.com>
Date: Sun Apr 28 12:53:17 2024 +0100

Disable additional gcc warnin
```

With the big [choc.patch](./choc.patch) patch applied to top for:

- remove everything not related to windows
- remove everything unused by DPF
- convert webview JS callbacks to pass raw strings instead of json
- remove even more stuff (json no longer needed)
- convert choc asserts into distrho ones
- put everything inside distrho namespace

And then backported:

- https://github.com/Tracktion/choc/commit/792e4bd9bedf38b9a28f12be0535c90649d5616b

+ 0
- 2803
dpf/distrho/extra/choc/choc.patch
File diff suppressed because it is too large
View File


+ 0
- 154
dpf/distrho/extra/choc/choc_DesktopWindow.h View File

@@ -1,154 +0,0 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef CHOC_DESKTOPWINDOW_HEADER_INCLUDED
#define CHOC_DESKTOPWINDOW_HEADER_INCLUDED

#include "choc_Platform.h"

//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#define NOMINMAX
#define Rectangle Rectangle_renamed_to_avoid_name_collisions
#include <windows.h>
#undef Rectangle

START_NAMESPACE_DISTRHO

struct HWNDHolder
{
HWNDHolder() = default;
HWNDHolder (HWND h) : hwnd (h) {}
HWNDHolder (const HWNDHolder&) = delete;
HWNDHolder& operator= (const HWNDHolder&) = delete;
HWNDHolder (HWNDHolder&& other) : hwnd (other.hwnd) { other.hwnd = {}; }
HWNDHolder& operator= (HWNDHolder&& other) { reset(); hwnd = other.hwnd; other.hwnd = {}; return *this; }
~HWNDHolder() { reset(); }

operator HWND() const { return hwnd; }
operator void*() const { return (void*) hwnd; }

void reset() { if (IsWindow (hwnd)) DestroyWindow (hwnd); hwnd = {}; }

HWND hwnd = {};
};

struct WindowClass
{
WindowClass (std::wstring name, WNDPROC wndProc)
{
name += std::to_wstring (static_cast<uint32_t> (GetTickCount()));

moduleHandle = GetModuleHandle (nullptr);
auto icon = (HICON) LoadImage (moduleHandle, IDI_APPLICATION, IMAGE_ICON,
GetSystemMetrics (SM_CXSMICON),
GetSystemMetrics (SM_CYSMICON),
LR_DEFAULTCOLOR);

WNDCLASSEXW wc;
ZeroMemory (&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC;
wc.hInstance = moduleHandle;
wc.lpszClassName = name.c_str();
wc.hIcon = icon;
wc.hIconSm = icon;
wc.lpfnWndProc = wndProc;

classAtom = (LPCWSTR) (uintptr_t) RegisterClassExW (&wc);
DISTRHO_SAFE_ASSERT (classAtom != 0);
}

~WindowClass()
{
UnregisterClassW (classAtom, moduleHandle);
}

HWNDHolder createWindow (DWORD style, int w, int h, void* userData)
{
if (auto hwnd = CreateWindowW (classAtom, L"", style, CW_USEDEFAULT, CW_USEDEFAULT,
w, h, nullptr, nullptr, moduleHandle, nullptr))
{
SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) userData);
return hwnd;
}

return {};
}

auto getClassName() const { return classAtom; }

HINSTANCE moduleHandle = {};
LPCWSTR classAtom = {};
};

static std::string createUTF8FromUTF16 (const std::wstring& utf16)
{
if (! utf16.empty())
{
auto numWideChars = static_cast<int> (utf16.size());
auto resultSize = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, nullptr, 0, nullptr, nullptr);

if (resultSize > 0)
{
std::string result;
result.resize (static_cast<size_t> (resultSize));

if (WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, result.data(), resultSize, nullptr, nullptr) > 0)
return result;
}
}

return {};
}

static std::wstring createUTF16StringFromUTF8 (std::string_view utf8)
{
if (! utf8.empty())
{
auto numUTF8Bytes = static_cast<int> (utf8.size());
auto resultSize = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, nullptr, 0);

if (resultSize > 0)
{
std::wstring result;
result.resize (static_cast<size_t> (resultSize));

if (MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, result.data(), resultSize) > 0)
return result;
}
}

return {};
}

END_NAMESPACE_DISTRHO

#endif // CHOC_DESKTOPWINDOW_HEADER_INCLUDED

+ 0
- 141
dpf/distrho/extra/choc/choc_DynamicLibrary.h View File

@@ -1,141 +0,0 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED
#define CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED

#include <string>

START_NAMESPACE_DISTRHO

//==============================================================================
/**
A minimal cross-platform loader for .dll/.so files.
*/
struct DynamicLibrary
{
DynamicLibrary() = default;

/// Attempts to load a library with the given name or path.
DynamicLibrary (std::string_view library);

DynamicLibrary (const DynamicLibrary&) = delete;
DynamicLibrary& operator= (const DynamicLibrary&) = delete;
DynamicLibrary (DynamicLibrary&&);
DynamicLibrary& operator= (DynamicLibrary&&);

/// On destruction, this object releases the library that was loaded
~DynamicLibrary();

/// Returns a pointer to the function with this name, or nullptr if not found.
void* findFunction (std::string_view functionName);

/// Returns true if the library was successfully loaded
operator bool() const noexcept { return handle != nullptr; }

/// Releases any handle that this object is holding
void close();

/// platform-specific handle. Will be nullptr if not loaded
void* handle = nullptr;
};



//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

inline DynamicLibrary::~DynamicLibrary()
{
close();
}

inline DynamicLibrary::DynamicLibrary (DynamicLibrary&& other) : handle (other.handle)
{
other.handle = nullptr;
}

inline DynamicLibrary& DynamicLibrary::operator= (DynamicLibrary&& other)
{
close();
handle = other.handle;
other.handle = nullptr;
return *this;
}

//==============================================================================
namespace win32_defs
{
#if ! (defined (_WINDOWS_) || defined (_APISETLIBLOADER_)) // only use these local definitions if windows.h isn't already included
using CHOC_HMODULE = void*;
#ifdef _MSC_VER
extern "C" CHOC_HMODULE __stdcall choc_LoadLibraryA (const char*);
extern "C" int __stdcall choc_FreeLibrary (CHOC_HMODULE);
extern "C" void* __stdcall choc_GetProcAddress (CHOC_HMODULE, const char*);
#pragma comment(linker,"/alternatename:choc_LoadLibraryA=LoadLibraryA")
#pragma comment(linker,"/alternatename:choc_FreeLibrary=FreeLibrary")
#pragma comment(linker,"/alternatename:choc_GetProcAddress=GetProcAddress")
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return choc_LoadLibraryA (l); }
static inline int FreeLibrary (CHOC_HMODULE m) { return choc_FreeLibrary (m); }
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return choc_GetProcAddress (m, f); }
#else
extern "C" __declspec(dllimport) CHOC_HMODULE __stdcall LoadLibraryA (const char*);
extern "C" __declspec(dllimport) int __stdcall FreeLibrary (CHOC_HMODULE);
extern "C" __declspec(dllimport) void* __stdcall GetProcAddress (CHOC_HMODULE, const char*);
#endif
#else
using CHOC_HMODULE = HMODULE;
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return ::LoadLibraryA (l); }
static inline int FreeLibrary (CHOC_HMODULE m) { return ::FreeLibrary (m); }
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return (void*) ::GetProcAddress (m, f); }
#endif
}

inline DynamicLibrary::DynamicLibrary (std::string_view library)
{
handle = (void*) win32_defs::LoadLibraryA (std::string (library).c_str());
}

inline void DynamicLibrary::close()
{
if (handle != nullptr)
{
win32_defs::FreeLibrary ((win32_defs::CHOC_HMODULE) handle);
handle = nullptr;
}
}

inline void* DynamicLibrary::findFunction (std::string_view name)
{
if (handle != nullptr)
return (void*) win32_defs::GetProcAddress ((win32_defs::CHOC_HMODULE) handle, std::string (name).c_str());

return {};
}

END_NAMESPACE_DISTRHO

#endif // CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED

+ 0
- 511
dpf/distrho/extra/choc/choc_MemoryDLL.h View File

@@ -1,511 +0,0 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef CHOC_MEMORYDLL_HEADER_INCLUDED
#define CHOC_MEMORYDLL_HEADER_INCLUDED

#include <stddef.h>
#include <memory>
#include <string>

START_NAMESPACE_DISTRHO

/**
MemoryDLL is an egregious hack that allows you to load DLL files from a chunk
of memory in the same way you might load them from a file on disk.

This opens up the ability to do horrible things such as embedding a random DLL
in a chunk of C++ code, so that it gets baked directly into your executable..
That means that if your app requires a 3rd-party DLL but you don't want the hassle
of having to install the DLL file in the right place on your users' machines, you
could use this trick to embed it invisibly inside your executable...

Currently this is only implemented for Windows DLLs, but a linux/OSX loader for
.dylibs is also totally feasible if anyone fancies having a go :)

@see DynamicLibrary
*/
struct MemoryDLL
{
MemoryDLL() = default;
MemoryDLL (MemoryDLL&&) = default;
MemoryDLL& operator= (MemoryDLL&&) = default;
~MemoryDLL();

/// Attempts to load a chunk of memory that contains a DLL file image.
MemoryDLL (const void* data, size_t size);

/// Returns a pointer to the function with this name, or nullptr if not found.
void* findFunction (std::string_view functionName);

/// Returns true if the library was successfully loaded
operator bool() const { return pimpl != nullptr; }

private:
struct Pimpl;
std::unique_ptr<Pimpl> pimpl;
};

END_NAMESPACE_DISTRHO



//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

#include <vector>
#include <unordered_map>
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#define NOMINMAX
#define Rectangle Rectangle_renamed_to_avoid_name_collisions
#include <windows.h>
#undef Rectangle

START_NAMESPACE_DISTRHO

struct MemoryDLL::Pimpl
{
Pimpl() = default;

~Pimpl()
{
if (entryFunction != nullptr)
(*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_DETACH, nullptr);

for (auto& m : loadedModules)
FreeLibrary (m);

if (imageData != nullptr)
VirtualFree (imageData, 0, MEM_RELEASE);

for (auto m : virtualBlocks)
VirtualFree (m, 0, MEM_RELEASE);
}

bool initialise (const void* data, size_t size)
{
if (size < sizeof (IMAGE_DOS_HEADER))
return false;

auto dosHeader = static_cast<const IMAGE_DOS_HEADER*> (data);

if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE
|| size < static_cast<size_t> (dosHeader->e_lfanew) + sizeof (IMAGE_NT_HEADERS))
return false;

const auto& headers = *getOffsetAs<IMAGE_NT_HEADERS> (data, dosHeader->e_lfanew);

if (headers.Signature != IMAGE_NT_SIGNATURE
|| (headers.OptionalHeader.SectionAlignment & 1) != 0)
return false;

#ifdef _M_ARM64
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_ARM64) return false;
#elif defined (_WIN64)
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) return false;
#else
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_I386) return false;
#endif

SYSTEM_INFO systemInfo;
GetNativeSystemInfo (std::addressof (systemInfo));

auto alignedImageSize = roundUp (headers.OptionalHeader.SizeOfImage, systemInfo.dwPageSize);

if (alignedImageSize != roundUp (getLastSectionEnd (headers), systemInfo.dwPageSize))
return false;

imageData = VirtualAlloc (reinterpret_cast<void*> (headers.OptionalHeader.ImageBase),
alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
{
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
return false;
}

while ((((uint64_t) imageData) >> 32) < (((uint64_t) imageData + alignedImageSize) >> 32))
{
virtualBlocks.push_back (imageData);
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
return false;
}

isDLL = (headers.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0;
pageSize = systemInfo.dwPageSize;

if (size < headers.OptionalHeader.SizeOfHeaders)
return false;

auto newHeaders = VirtualAlloc (imageData, headers.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
memcpy (newHeaders, dosHeader, headers.OptionalHeader.SizeOfHeaders);
imageHeaders = getOffsetAs<IMAGE_NT_HEADERS> (newHeaders, dosHeader->e_lfanew);
imageHeaders->OptionalHeader.ImageBase = reinterpret_cast<uintptr_t> (imageData);

if (copySections (data, size, headers.OptionalHeader.SectionAlignment))
{
if (auto locationDelta = (ptrdiff_t) (imageHeaders->OptionalHeader.ImageBase - headers.OptionalHeader.ImageBase))
performRelocation (locationDelta);

if (loadImports() && prepareSections())
{
executeTLS();
loadNameTable();

if (imageHeaders->OptionalHeader.AddressOfEntryPoint != 0)
{
entryFunction = getOffsetAs<char> (imageData, imageHeaders->OptionalHeader.AddressOfEntryPoint);

if (isDLL)
return (*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_ATTACH, nullptr);

return true;
}
}
}

return false;
}

void* findFunction (std::string_view name)
{
if (auto found = exportedFunctionOffsets.find (std::string (name)); found != exportedFunctionOffsets.end())
return getOffsetAs<char> (imageData, found->second);

return {};
}

private:
PIMAGE_NT_HEADERS imageHeaders = {};
void* imageData = nullptr;
std::vector<HMODULE> loadedModules;
uint32_t pageSize = 0;
bool isDLL = false;
std::vector<void*> virtualBlocks;
std::unordered_map<std::string, size_t> exportedFunctionOffsets;
using DLLEntryFn = BOOL(WINAPI*)(HINSTANCE, DWORD, void*);
void* entryFunction = {};

template <typename Type, typename Diff>
static const Type* getOffsetAs (const void* address, Diff offset)
{
return reinterpret_cast<const Type*> (static_cast<const char*> (address) + offset);
}

template <typename Type, typename Diff>
static Type* getOffsetAs (void* address, Diff offset)
{
return reinterpret_cast<Type*> (static_cast<char*> (address) + offset);
}

template <typename Type>
Type* getDataDirectoryAddress (int type) const
{
auto& dd = imageHeaders->OptionalHeader.DataDirectory[type];

if (dd.Size > 0)
return getOffsetAs<Type> (imageData, dd.VirtualAddress);

return {};
}

static size_t getLastSectionEnd (const IMAGE_NT_HEADERS& headers)
{
auto section = IMAGE_FIRST_SECTION (&headers);
auto optionalSectionSize = headers.OptionalHeader.SectionAlignment;
size_t lastSectionEnd = 0;

for (uint32_t i = 0; i < headers.FileHeader.NumberOfSections; ++i, ++section)
{
auto end = section->VirtualAddress + (section->SizeOfRawData == 0 ? optionalSectionSize
: section->SizeOfRawData);
if (end > lastSectionEnd)
lastSectionEnd = end;
}

return lastSectionEnd;
}

void loadNameTable()
{
if (auto exports = getDataDirectoryAddress<IMAGE_EXPORT_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_EXPORT))
{
if (exports->NumberOfNames > 0 && exports->NumberOfFunctions > 0)
{
auto name = getOffsetAs<const DWORD> (imageData, exports->AddressOfNames);
auto ordinal = getOffsetAs<const WORD> (imageData, exports->AddressOfNameOrdinals);

exportedFunctionOffsets.reserve (exports->NumberOfNames);

for (size_t i = 0; i < exports->NumberOfNames; ++i, ++name, ++ordinal)
if (*ordinal <= exports->NumberOfFunctions)
exportedFunctionOffsets[std::string (getOffsetAs<const char> (imageData, *name))]
= getOffsetAs<DWORD> (imageData, exports->AddressOfFunctions)[*ordinal];
}
}
}

void executeTLS()
{
if (auto tls = getDataDirectoryAddress<IMAGE_TLS_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_TLS))
if (auto callback = reinterpret_cast<PIMAGE_TLS_CALLBACK*> (tls->AddressOfCallBacks))
while (*callback != nullptr)
(*callback++) ((void*) imageData, DLL_PROCESS_ATTACH, nullptr);
}

bool prepareSections()
{
auto section = IMAGE_FIRST_SECTION (imageHeaders);
auto size = getSectionSize (*section);
auto address = getSectionAddress (*section);
auto addressPage = getPageBase (address);
auto characteristics = section->Characteristics;

for (WORD i = 1; i < imageHeaders->FileHeader.NumberOfSections; ++i)
{
++section;
auto nextSize = getSectionSize (*section);
auto nextAddress = getSectionAddress (*section);
auto nextAddressPage = getPageBase (nextAddress);

if (addressPage == nextAddressPage || address + size > nextAddressPage)
{
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
characteristics = (characteristics | section->Characteristics) & ~static_cast<DWORD> (IMAGE_SCN_MEM_DISCARDABLE);
else
characteristics |= section->Characteristics;

size = static_cast<size_t> ((nextAddress + nextSize) - address);
continue;
}

if (! setProtectionFlags (size, characteristics, address, addressPage, false))
return false;

size = nextSize;
address = nextAddress;
addressPage = nextAddressPage;
characteristics = section->Characteristics;
}

return setProtectionFlags (size, characteristics, address, addressPage, true);
}

bool setProtectionFlags (size_t sectionSize, DWORD sectionCharacteristics, void* sectionAddress, void* addressPage, bool isLast)
{
if (sectionSize == 0)
return true;

if ((sectionCharacteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
{
if (sectionAddress == addressPage
&& (isLast || imageHeaders->OptionalHeader.SectionAlignment == pageSize || (sectionSize % pageSize) == 0))
VirtualFree (sectionAddress, sectionSize, MEM_DECOMMIT);

return true;
}

auto getProtectionFlags = [] (DWORD type)
{
return ((type & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0)
| ((type & IMAGE_SCN_MEM_EXECUTE)
? ((type & IMAGE_SCN_MEM_READ)
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ)
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_WRITECOPY : PAGE_EXECUTE))
: ((type & IMAGE_SCN_MEM_READ)
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_READWRITE : PAGE_READONLY)
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_WRITECOPY : PAGE_NOACCESS)));
};

DWORD oldProtectValue;
return VirtualProtect (sectionAddress, sectionSize,
static_cast<DWORD> (getProtectionFlags (sectionCharacteristics)),
std::addressof (oldProtectValue)) != 0;
}

bool loadImports()
{
auto imp = getDataDirectoryAddress<IMAGE_IMPORT_DESCRIPTOR> (IMAGE_DIRECTORY_ENTRY_IMPORT);

if (imp == nullptr)
return false;

while (! IsBadReadPtr (imp, sizeof (IMAGE_IMPORT_DESCRIPTOR)) && imp->Name != 0)
{
auto handle = LoadLibraryA (getOffsetAs<const char> (imageData, imp->Name));

if (handle == nullptr)
return false;

loadedModules.push_back (handle);
auto thunkRef = getOffsetAs<uintptr_t> (imageData, imp->OriginalFirstThunk ? imp->OriginalFirstThunk
: imp->FirstThunk);
auto funcRef = getOffsetAs<FARPROC> (imageData, imp->FirstThunk);

for (; *thunkRef != 0; ++thunkRef, ++funcRef)
{
auto name = IMAGE_SNAP_BY_ORDINAL(*thunkRef)
? (LPCSTR) IMAGE_ORDINAL(*thunkRef)
: (LPCSTR) std::addressof (getOffsetAs<IMAGE_IMPORT_BY_NAME> (imageData, *thunkRef)->Name);

*funcRef = GetProcAddress (handle, name);

if (*funcRef == 0)
return false;
}

++imp;
}

return true;
}

size_t getSectionSize (const IMAGE_SECTION_HEADER& section) const
{
if (auto size = section.SizeOfRawData)
return size;

if (section.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
return imageHeaders->OptionalHeader.SizeOfInitializedData;

if (section.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
return imageHeaders->OptionalHeader.SizeOfUninitializedData;

return 0;
}

static size_t roundUp (size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); }
char* getPageBase (void* address) const { return (char*) (reinterpret_cast<uintptr_t> (address) & ~static_cast<uintptr_t> (pageSize - 1)); }

char* getSectionAddress (const IMAGE_SECTION_HEADER& section) const
{
#ifdef _WIN64
return reinterpret_cast<char*> (static_cast<uintptr_t> (section.Misc.PhysicalAddress)
| (static_cast<uintptr_t> (imageHeaders->OptionalHeader.ImageBase & 0xffffffff00000000)));
#else
return reinterpret_cast<char*> (section.Misc.PhysicalAddress);
#endif
}

bool copySections (const void* data, size_t size, size_t sectionAlignment) const
{
auto section = IMAGE_FIRST_SECTION (imageHeaders);

for (int i = 0; i < imageHeaders->FileHeader.NumberOfSections; ++i, ++section)
{
if (section->SizeOfRawData == 0)
{
if (sectionAlignment == 0)
continue;

if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress),
sectionAlignment, MEM_COMMIT, PAGE_READWRITE))
{
dest = getOffsetAs<char> (imageData, section->VirtualAddress);
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest));
memset (dest, 0, sectionAlignment);
continue;
}

return false;
}

if (size < section->PointerToRawData + section->SizeOfRawData)
return false;

if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress),
section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE))
{
dest = getOffsetAs<char> (imageData, section->VirtualAddress);
memcpy (dest, static_cast<const char*> (data) + section->PointerToRawData, section->SizeOfRawData);
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest));
continue;
}

return false;
}

return true;
}

void performRelocation (ptrdiff_t delta)
{
auto directory = imageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

if (directory.Size != 0)
{
auto relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (imageData, directory.VirtualAddress);

while (relocation->VirtualAddress > 0)
{
auto dest = getOffsetAs<char> (imageData, relocation->VirtualAddress);
auto offset = getOffsetAs<uint16_t> (relocation, sizeof (IMAGE_BASE_RELOCATION));

for (uint32_t i = 0; i < (relocation->SizeOfBlock - sizeof (IMAGE_BASE_RELOCATION)) / 2; ++i, ++offset)
{
switch (*offset >> 12)
{
case IMAGE_REL_BASED_HIGHLOW: addDelta<uint32_t> (dest + (*offset & 0xfff), delta); break;
case IMAGE_REL_BASED_DIR64: addDelta<uint64_t> (dest + (*offset & 0xfff), delta); break;
case IMAGE_REL_BASED_ABSOLUTE:
default: break;
}
}

relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (relocation, relocation->SizeOfBlock);
}
}
}

template <typename Type>
static void addDelta (char* addr, ptrdiff_t delta)
{
*reinterpret_cast<Type*> (addr) = static_cast<Type> (static_cast<ptrdiff_t> (*reinterpret_cast<Type*> (addr)) + delta);
}
};

inline MemoryDLL::~MemoryDLL() = default;

inline MemoryDLL::MemoryDLL (const void* data, size_t size) : pimpl (std::make_unique<Pimpl>())
{
if (! pimpl->initialise (data, size))
pimpl.reset();
}

inline void* MemoryDLL::findFunction (std::string_view name)
{
return pimpl != nullptr ? pimpl->findFunction (name) : nullptr;
}

END_NAMESPACE_DISTRHO

#endif // CHOC_MEMORYDLL_HEADER_INCLUDED

+ 0
- 67
dpf/distrho/extra/choc/choc_Platform.h View File

@@ -1,67 +0,0 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef CHOC_PLATFORM_DETECT_HEADER_INCLUDED
#define CHOC_PLATFORM_DETECT_HEADER_INCLUDED

/*
These conditionals declare the macros
- CHOC_WINDOWS
- CHOC_ANDROID
- CHOC_LINUX
- CHOC_OSX
- CHOC_IOS
...based on the current operating system.

It also declares a string literal macro CHOC_OPERATING_SYSTEM_NAME
which can be used if you need a text description of the OS.
*/
#if defined (_WIN32) || defined (_WIN64)
#define CHOC_WINDOWS 1
#define CHOC_OPERATING_SYSTEM_NAME "Windows"
#elif __ANDROID__
#define CHOC_ANDROID 1
#define CHOC_OPERATING_SYSTEM_NAME "Android"
#elif defined (LINUX) || defined (__linux__)
#define CHOC_LINUX 1
#define CHOC_OPERATING_SYSTEM_NAME "Linux"
#elif __APPLE__
#define CHOC_APPLE 1
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define CHOC_IOS 1
#define CHOC_OPERATING_SYSTEM_NAME "iOS"
#else
#define CHOC_OSX 1
#define CHOC_OPERATING_SYSTEM_NAME "OSX"
#endif
#elif defined (__FreeBSD__) || (__OpenBSD__)
#define CHOC_BSD 1
#define CHOC_OPERATING_SYSTEM_NAME "BSD"
#elif defined (_POSIX_VERSION)
#define CHOC_POSIX 1
#define CHOC_OPERATING_SYSTEM_NAME "Posix"
#elif defined (__EMSCRIPTEN__)
#define CHOC_EMSCRIPTEN 1
#define CHOC_OPERATING_SYSTEM_NAME "Emscripten"
#else
#error "Unknown platform!"
#endif


#endif // CHOC_PLATFORM_DETECT_HEADER_INCLUDED

+ 0
- 74
dpf/distrho/extra/choc/choc_StringUtilities.h View File

@@ -1,74 +0,0 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#ifndef CHOC_STRING_UTILS_HEADER_INCLUDED
#define CHOC_STRING_UTILS_HEADER_INCLUDED

#include <cctype>
#include <string>
#include <vector>
#include <cmath>
#include <chrono>
#include <memory>
#include <algorithm>
#include <cwctype>

START_NAMESPACE_DISTRHO

//==============================================================================
/// Returns a hex string for the given value.
/// If the minimum number of digits is non-zero, it will be zero-padded to fill this length;
template <typename IntegerType>
std::string createHexString (IntegerType value);


//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

template <typename IntegerType>
std::string createHexString (IntegerType v)
{
static_assert (std::is_integral<IntegerType>::value, "Need to pass integers into this method");
auto value = static_cast<typename std::make_unsigned<IntegerType>::type> (v);

char hex[40];
const auto end = hex + sizeof (hex) - 1;
auto d = end;
*d = 0;

for (;;)
{
*--d = "0123456789abcdef"[static_cast<uint32_t> (value) & 15u];
value = static_cast<decltype (value)> (value >> 4);

if (value == 0)
return std::string (d, end);
}
}

END_NAMESPACE_DISTRHO

#endif

+ 0
- 4769
dpf/distrho/extra/choc/choc_WebView.h
File diff suppressed because it is too large
View File


+ 0
- 2482
dpf/distrho/extra/sofd/libsofd.c
File diff suppressed because it is too large
View File


+ 0
- 194
dpf/distrho/extra/sofd/libsofd.h View File

@@ -1,194 +0,0 @@
/* libSOFD - Simple Open File Dialog [for X11 without toolkit]
*
* Copyright (C) 2014 Robin Gareus <robin@gareus.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef LIBSOFD_H
#define LIBSOFD_H 1

#ifdef HAVE_X11
#include <X11/Xlib.h>

#ifdef __cplusplus
extern "C" {
#endif

///////////////////////////////////////////////////////////////////////////////
/* public API */

/** open a file select dialog
* @param dpy X Display connection
* @param parent (optional) if not NULL, become transient for given window
* @param x if >0 set explict initial width of the window
* @param y if >0 set explict initial height of the window
* @return 0 on success
*/
int x_fib_show (Display *dpy, Window parent, int x, int y, double scalefactor);

/** force close the dialog.
* This is normally not needed, the dialog closes itself
* when a file is selected or the user cancels selection.
* @param dpy X Display connection
*/
void x_fib_close (Display *dpy);

/** non-blocking X11 event handler.
* It is safe to run this function even if the dialog is
* closed or was not initialized.
*
* @param dpy X Display connection
* @param event the XEvent to process
* @return status
* 0: the event was not for this window, or file-dialog still
* active, or the dialog window is not displayed.
* >0: file was selected, dialog closed
* <0: file selection was cancelled.
*/
int x_fib_handle_events (Display *dpy, XEvent *event);

/** last status of the dialog
* @return >0: file was selected, <0: canceled or inactive. 0: active
*/
int x_fib_status ();

/** query the selected filename
* @return NULL if none set, or allocated string to be free()ed by the called
*/
char *x_fib_filename ();

/** customize/configure the dialog before calling \ref x_fib_show
* changes only have any effect if the dialog is not visible.
* @param k key to change
* 0: set current dir to display (must end with slash)
* 1: set title of dialog window
* 2: specify a custom X11 font to use
* 3: specify a custom 'places' file to include
* (following gtk-bookmark convention)
* @param v value
* @return 0 on success.
*/
int x_fib_configure (int k, const char *v);

/** customize/configure the dialog before calling \ref x_fib_show
* changes only have any effect if the dialog is not visible.
*
* @param k button to change:
* 1: show hidden files
* 2: show places
* 3: show filter/list all (automatically hidden if there is no
* filter function)
* @param v <0 to hide the button >=0 show button,
* 0: set button-state to not-checked
* 1: set button-state to checked
* >1: retain current state
* @return 0 on success.
*/
int x_fib_cfg_buttons (int k, int v);

/** set custom callback to filter file-names.
* NULL will disable the filter and hide the 'show all' button.
* changes only have any effect if the dialog is not visible.
*
* @param cb callback function to check file
* the callback function is called with the file name (basename only)
* and is expected to return 1 if the file passes the filter
* and 0 if the file should not be listed by default.
* @return 0 on success.
*/
int x_fib_cfg_filter_callback (int (*cb)(const char*));

#ifdef __cplusplus
}
#endif

#endif /* END X11 specific functions */

#ifdef __cplusplus
extern "C" {
#endif

/* 'recently used' API. x-platform
* NOTE: all functions use a static cache and are not reentrant.
* It is expected that none of these functions are called in
* parallel from different threads.
*/

/** release static resources of 'recently used files'
*/
void x_fib_free_recent ();

/** add an entry to the recently used list
*
* The dialog does not add files automatically on open,
* if the application succeeds to open a selected file,
* this function should be called.
*
* @param path complete path to file
* @param atime time of last use, 0: NOW
* @return -1 on error, number of current entries otherwise
*/
int x_fib_add_recent (const char *path, time_t atime);

/** get a platform specific path to a good location for
* saving the recently used file list.
* (follows XDG_DATA_HOME on Unix, and CSIDL_LOCAL_APPDATA spec)
*
* @param application-name to use to include in file
* @return pointer to static path or NULL
*/
const char *x_fib_recent_file(const char *appname);

/** save the current list of recently used files to the given filename
* (the format is one file per line, filename URL encoded and space separated
* with last-used timestamp)
*
* This function tries to creates the containing directory if it does
* not exist.
*
* @param fn file to save the list to
* @return 0: on success
*/
int x_fib_save_recent (const char *fn);

/** load a recently used file list.
*
* @param fn file to load the list from
* @return 0: on success
*/
int x_fib_load_recent (const char *fn);

/** get number of entries in the current list
* @return number of entries in the recently used list
*/
unsigned int x_fib_recent_count ();

/** get recently used entry at given position
*
* @param i entry to query
* @return pointer to static string
*/
const char *x_fib_recent_at (unsigned int i);

#ifdef __cplusplus
}
#endif

#endif // header guard

+ 13
- 9
dpf/distrho/src/DistrhoPluginLV2export.cpp View File

@@ -66,6 +66,10 @@
# define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048
#endif

#ifndef DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
#endif

#ifndef DISTRHO_PLUGIN_USES_MODGUI
# define DISTRHO_PLUGIN_USES_MODGUI 0
#endif
@@ -260,14 +264,14 @@ void lv2_generate_ttl(const char* const basename)
const String pluginDLL(basename);
const String pluginTTL(pluginDLL + ".ttl");

#if DISTRHO_PLUGIN_HAS_UI
#if DISTRHO_PLUGIN_HAS_UI
String pluginUI(pluginDLL);
# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
#if ! DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
pluginUI.truncate(pluginDLL.rfind("_dsp"));
pluginUI += "_ui";
const String uiTTL(pluginUI + ".ttl");
# endif
#endif
#endif
#endif

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

@@ -278,7 +282,7 @@ void lv2_generate_ttl(const char* const basename)
String manifestString;
manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
manifestString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n";
#endif
#if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -304,14 +308,14 @@ void lv2_generate_ttl(const char* const basename)
manifestString += "<" DISTRHO_UI_URI ">\n";
manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n";
manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n";
# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# if DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
addAttribute(manifestString, "lv2:extensionData", lv2ManifestUiExtensionData, 4);
addAttribute(manifestString, "lv2:optionalFeature", lv2ManifestUiOptionalFeatures, 4);
addAttribute(manifestString, "lv2:requiredFeature", lv2ManifestUiRequiredFeatures, 4);
addAttribute(manifestString, "opts:supportedOption", lv2ManifestUiSupportedOptions, 4, true);
# else // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# else // DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n";
# endif // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# endif // DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
manifestString += "\n";
#endif

@@ -1564,7 +1568,7 @@ void lv2_generate_ttl(const char* const basename)

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

#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT
{
std::cout << "Writing " << uiTTL << "..."; std::cout.flush();
std::fstream uiFile(uiTTL, std::ios::out);


BIN
dpf/lac/2014-small-talk.odp View File


+ 24
- 0
get-plugins.sh View File

@@ -35,16 +35,40 @@ mkdir plugins
mv repos/DPF dpf
rm -rf dpf/.git*
rm -rf dpf/.travis*
rm -rf dpf/distrho/extra/choc
rm -rf dpf/distrho/extra/sofd
rm -rf dpf/dgl/pugl-extra
rm -rf dpf/dgl/src/pugl-upstream/bindings
rm -rf dpf/dgl/src/pugl-upstream/doc
rm -rf dpf/dgl/src/pugl-upstream/examples
rm -rf dpf/dgl/src/pugl-upstream/meson*
rm -rf dpf/dgl/src/pugl-upstream/resources
rm -rf dpf/dgl/src/pugl-upstream/scripts
rm -rf dpf/dgl/src/pugl-upstream/subprojects
rm -rf dpf/dgl/src/pugl-upstream/test
rm -rf dpf/cmake
rm -rf dpf/examples
rm -rf dpf/lac
rm -rf dpf/tests
rm -f dpf/Makefile
rm -f dpf/dgl/FileBrowserDialog.hpp
rm -f dpf/dgl/Layout.hpp
rm -f dpf/dgl/Vulkan.hpp
rm -f dpf/dgl/WebView.hpp
rm -f dpf/dgl/src/Layout.cpp
rm -f dpf/dgl/src/Stub.cpp
rm -f dpf/dgl/src/Vulkan.cpp
rm -f dpf/dgl/src/WebViewWin32.cpp
rm -f dpf/distrho/extra/Base64.hpp
rm -f dpf/distrho/extra/ChildProcess.hpp
rm -f dpf/distrho/extra/ExternalWindow.hpp
rm -f dpf/distrho/extra/FileBrowserDialog*
rm -f dpf/distrho/extra/Filesystem.hpp
rm -f dpf/distrho/extra/Runner.hpp
rm -f dpf/distrho/extra/Time.hpp
rm -f dpf/distrho/extra/WebView*

sed -i '/ $(BUILD_DIR)\/dgl\/Layout.cpp.o \\/d' dpf/dgl/Makefile

for PLUGIN in ${PLUGINS[@]}; do
for f in $(ls repos/${PLUGIN}/plugins/); do


Loading…
Cancel
Save