Browse Source

Update DPF

Signed-off-by: falkTX <falktx@falktx.com>
main
falkTX 2 weeks ago
parent
commit
af8fe11b2d
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
44 changed files with 1395 additions and 275 deletions
  1. +5
    -5
      dpf/CMakeLists.txt
  2. +1
    -1
      dpf/Makefile.plugins.mk
  3. +206
    -18
      dpf/cmake/DPF-plugin.cmake
  4. +14
    -3
      dpf/dgl/Application.hpp
  5. +3
    -3
      dpf/dgl/Base.hpp
  6. +5
    -0
      dpf/dgl/Color.hpp
  7. +10
    -1
      dpf/dgl/EventHandlers.hpp
  8. +9
    -0
      dpf/dgl/Makefile
  9. +5
    -0
      dpf/dgl/NanoVG.hpp
  10. +28
    -0
      dpf/dgl/WebView.hpp
  11. +26
    -1
      dpf/dgl/Window.hpp
  12. +54
    -1
      dpf/dgl/src/Application.cpp
  13. +8
    -0
      dpf/dgl/src/Color.cpp
  14. +101
    -1
      dpf/dgl/src/EventHandlers.cpp
  15. +8
    -0
      dpf/dgl/src/NanoVG.cpp
  16. +23
    -0
      dpf/dgl/src/WebViewWin32.cpp
  17. +15
    -1
      dpf/dgl/src/Window.cpp
  18. +92
    -33
      dpf/dgl/src/WindowPrivateData.cpp
  19. +14
    -3
      dpf/dgl/src/WindowPrivateData.hpp
  20. +10
    -5
      dpf/dgl/src/pugl-upstream/src/mac.m
  21. +15
    -4
      dpf/dgl/src/pugl.cpp
  22. +28
    -4
      dpf/distrho/DistrhoDetails.hpp
  23. +22
    -2
      dpf/distrho/DistrhoPluginUtils.hpp
  24. +2
    -1
      dpf/distrho/DistrhoUI.hpp
  25. +2
    -2
      dpf/distrho/DistrhoUIMain.cpp
  26. +1
    -0
      dpf/distrho/DistrhoUI_win32.cpp
  27. +106
    -0
      dpf/distrho/extra/Filesystem.hpp
  28. +18
    -4
      dpf/distrho/extra/String.hpp
  29. +20
    -11
      dpf/distrho/extra/WebViewImpl.cpp
  30. +11
    -2
      dpf/distrho/extra/WebViewImpl.hpp
  31. +25
    -4
      dpf/distrho/extra/WebViewWin32.hpp
  32. +88
    -54
      dpf/distrho/src/DistrhoPluginAU.cpp
  33. +37
    -6
      dpf/distrho/src/DistrhoPluginCLAP.cpp
  34. +3
    -10
      dpf/distrho/src/DistrhoPluginChecks.h
  35. +78
    -65
      dpf/distrho/src/DistrhoPluginInternal.hpp
  36. +3
    -7
      dpf/distrho/src/DistrhoPluginJACK.cpp
  37. +10
    -0
      dpf/distrho/src/DistrhoPluginLV2export.cpp
  38. +6
    -0
      dpf/distrho/src/DistrhoPluginVST3.cpp
  39. +16
    -8
      dpf/distrho/src/DistrhoUIAU.mm
  40. +3
    -7
      dpf/distrho/src/DistrhoUIDSSI.cpp
  41. +7
    -1
      dpf/distrho/src/DistrhoUIPrivateData.hpp
  42. +178
    -6
      dpf/distrho/src/DistrhoUtils.cpp
  43. +2
    -1
      dpf/distrho/src/lv2/lv2_kxstudio_properties.h
  44. +77
    -0
      dpf/utils/install-plugins-symlinks.sh

+ 5
- 5
dpf/CMakeLists.txt View File

@@ -1,10 +1,10 @@
# DISTRHO Plugin Framework (DPF)
# Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
# Copyright (C) 2022-2024 Filipe Coelho <falktx@falktx.com>
# Copyright (C) 2022-2025 Filipe Coelho <falktx@falktx.com>
#
# SPDX-License-Identifier: ISC

cmake_minimum_required(VERSION 3.7)
cmake_minimum_required(VERSION 3.8)

project(DPF)

@@ -34,11 +34,11 @@ if(DPF_LIBRARIES)
if(PKG_CONFIG_FOUND)
pkg_check_modules(CAIRO "cairo")
if(CAIRO_FOUND AND (NOT HAIKU))
dpf__add_dgl_cairo(TRUE, TRUE)
dpf__add_dgl_cairo(TRUE, TRUE, TRUE)
endif()
endif()
dpf__add_dgl_external(TRUE)
dpf__add_dgl_opengl(TRUE, TRUE)
dpf__add_dgl_external(TRUE, TRUE)
dpf__add_dgl_opengl(TRUE, TRUE, TRUE)
endif()

if(DPF_EXAMPLES)


+ 1
- 1
dpf/Makefile.plugins.mk View File

@@ -287,7 +287,7 @@ HAVE_DGL = false
endif
endif

ifeq ($(HAVE_DGL)$(LINUX)$(USE_WEB_VIEW),truetruetrue)
ifeq ($(HAVE_DGL)$(LINUX)$(UI_TYPE),truetruewebview)
DGL_LIB_SHARED = $(shell $(CC) -print-file-name=Scrt1.o)
endif



+ 206
- 18
dpf/cmake/DPF-plugin.cmake View File

@@ -121,23 +121,33 @@ function(dpf_add_plugin NAME)
set(_dgl_library)
if(_dpf_plugin_FILES_UI)
if(_dpf_plugin_UI_TYPE STREQUAL "cairo")
dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-cairo)
elseif(_dpf_plugin_UI_TYPE STREQUAL "external")
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-external)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl")
dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-opengl)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3")
dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-opengl3)
elseif(_dpf_plugin_UI_TYPE STREQUAL "vulkan")
dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-vulkan)
elseif(_dpf_plugin_UI_TYPE STREQUAL "webview")
set(_dpf_plugin_USE_WEB_VIEW TRUE)
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-external)
else()
message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}")
@@ -234,6 +244,112 @@ function(dpf_add_plugin NAME)
endforeach()
endfunction()

# dpf_add_executable(target <args...>)
# ------------------------------------------------------------------------------
#
# Add a simple executable built using the DISTRHO Plugin Framework.
#
# ------------------------------------------------------------------------------
# Arguments:
#
# `UI_TYPE` <type>
# the user interface type, can be one of the following:
# - cairo
# - external
# - opengl (default)
# - opengl3
# - vulkan
# - webview
#
# `NO_SHARED_RESOURCES`
# do not build DPF shared resources (fonts, etc)
#
# `USE_FILE_BROWSER`
# enable file browser dialog APIs
#
# `USE_WEB_VIEW`
# enable web browser view APIs
#
function(dpf_add_executable NAME)
set(options NO_SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW)
set(oneValueArgs UI_TYPE)
cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if("${_dpf_plugin_UI_TYPE}" STREQUAL "")
set(_dpf_plugin_UI_TYPE "opengl")
endif()

set(_dgl_library)
if(_dpf_plugin_UI_TYPE STREQUAL "cairo")
dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-cairo)
elseif(_dpf_plugin_UI_TYPE STREQUAL "external")
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-external)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl")
dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-opengl)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3")
dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-opengl3)
elseif(_dpf_plugin_UI_TYPE STREQUAL "vulkan")
dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>>
$<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-vulkan)
elseif(_dpf_plugin_UI_TYPE STREQUAL "webview")
set(_dpf_plugin_USE_WEB_VIEW TRUE)
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>
$<BOOL:${_dpf_plugin_USE_WEB_VIEW}>)
set(_dgl_library dgl-external)
else()
message(FATAL_ERROR "Unrecognized UI type for executable: ${_dpf_plugin_UI_TYPE}")
endif()

set(_dgl_has_ui OFF)
if(_dgl_library)
set(_dgl_has_ui ON)
endif()

dpf__create_dummy_source_list(_no_srcs)
dpf__add_executable("${NAME}" ${_no_srcs})
target_include_directories("${NAME}" PUBLIC "${DPF_ROOT_DIR}/distrho")

if(_dpf_plugin_USE_FILE_BROWSER)
target_compile_definitions("${NAME}" PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(_dpf_plugin_USE_WEB_VIEW)
target_compile_definitions("${NAME}" PUBLIC "DGL_USE_WEB_VIEW")
endif()

if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
target_link_libraries("${NAME}" PRIVATE "dl")
endif()

if(_dgl_library)
# make sure that all code will see DGL_* definitions
target_link_libraries("${NAME}" PUBLIC
"${_dgl_library}"
"${_dgl_library}-definitions"
dgl-system-libs-definitions
dgl-system-libs)
# extra linkage for linux web view
if(LINUX AND _dpf_plugin_USE_WEB_VIEW)
target_link_libraries("${NAME}" PRIVATE "rt")
endif()
# add the files containing C++17 or Objective-C classes
dpf__add_plugin_specific_ui_sources("${NAME}" "${_dpf_plugin_USE_WEB_VIEW}")
endif()
endfunction()

# ------------------------------------------------------------------------------
# DPF private functions (prefixed with `dpf__`)
# ------------------------------------------------------------------------------
@@ -661,7 +777,7 @@ endfunction()
#
# Add the Cairo variant of DGL, if not already available.
#
function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER)
function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW)
if(TARGET dgl-cairo)
return()
endif()
@@ -710,6 +826,21 @@ function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER)
target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(USE_WEB_VIEW)
target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER")
if(APPLE)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries(dgl-cairo PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
elseif(WIN32)
target_sources(dgl-cairo PRIVATE
"${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp")
set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
endif()
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-cairo PRIVATE dgl-system-libs)

@@ -730,7 +861,7 @@ endfunction()
#
# Add the external variant of DGL, if not already available.
#
function(dpf__add_dgl_external USE_FILE_BROWSER)
function(dpf__add_dgl_external USE_FILE_BROWSER USE_WEB_VIEW)
if(TARGET dgl-external)
return()
endif()
@@ -770,6 +901,21 @@ function(dpf__add_dgl_external USE_FILE_BROWSER)
target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(USE_WEB_VIEW)
target_compile_definitions(dgl-external PUBLIC "DGL_USE_WEB_VIEW")
if(APPLE)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries(dgl-external PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
elseif(WIN32)
target_sources(dgl-external PRIVATE
"${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp")
set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
endif()
endif()

dpf__add_dgl_system_libs()
target_compile_definitions(dgl-external PUBLIC "DGL_NO_SHARED_RESOURCES")
target_link_libraries(dgl-external PRIVATE dgl-system-libs)
@@ -786,7 +932,7 @@ endfunction()
#
# Add the OpenGL variant of DGL, if not already available.
#
function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER)
function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW)
if(TARGET dgl-opengl)
return()
endif()
@@ -841,6 +987,21 @@ function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER)
target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(USE_WEB_VIEW)
target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_WEB_VIEW")
if(APPLE)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries(dgl-opengl PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
elseif(WIN32)
target_sources(dgl-opengl PRIVATE
"${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp")
set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
endif()
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-opengl PRIVATE dgl-system-libs)

@@ -856,7 +1017,7 @@ endfunction()
#
# Add the OpenGL3 variant of DGL, if not already available.
#
function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER)
function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW)
if(TARGET dgl-opengl3)
return()
endif()
@@ -911,6 +1072,21 @@ function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER)
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(USE_WEB_VIEW)
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_WEB_VIEW")
if(APPLE)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries(dgl-opengl3 PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
elseif(WIN32)
target_sources(dgl-opengl3 PRIVATE
"${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp")
set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
endif()
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-opengl3 PRIVATE dgl-system-libs)

@@ -926,7 +1102,7 @@ endfunction()
#
# Add the Vulkan variant of DGL, if not already available.
#
function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER)
function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW)
if(TARGET dgl-vulkan)
return()
endif()
@@ -976,6 +1152,21 @@ function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER)
target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(USE_WEB_VIEW)
target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_WEB_VIEW")
if(APPLE)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries(dgl-vulkan PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
elseif(WIN32)
target_sources(dgl-vulkan PRIVATE
"${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp")
set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
endif()
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-vulkan PRIVATE dgl-system-libs)

@@ -1002,13 +1193,10 @@ function(dpf__add_plugin_specific_ui_sources NAME USE_WEB_VIEW)
elseif(WIN32 AND USE_WEB_VIEW)
target_sources("${NAME}" PRIVATE
"${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp")
if (MSVC)
set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp"
PROPERTIES COMPILE_FLAGS /std:c++17)
else()
set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp"
PROPERTIES COMPILE_FLAGS -std=gnu++17)
endif()
set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp"
PROPERTIES
COMPILE_FLAGS
$<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>)
target_link_libraries("${NAME}" PRIVATE "ole32" "uuid")
endif()
endfunction()


+ 14
- 3
dpf/dgl/Application.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
@@ -54,6 +54,12 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on)
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off)
#endif

#ifdef DGL_USE_WEB_VIEW
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_off)
#endif

#ifdef DGL_NO_SHARED_RESOURCES
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on)
#else
@@ -78,11 +84,16 @@ class DISTRHO_API Application
{
public:
/**
Constructor.
Constructor for standalone or plugin application.
*/
// NOTE: the default value is not yet passed, so we catch where we use this
Application(bool isStandalone = true);

/**
Constructor for a standalone application.
This specific constructor is required if using web views in standalone applications.
*/
Application(int argc, char* argv[]);

/**
Destructor.
*/


+ 3
- 3
dpf/dgl/Base.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
@@ -41,8 +41,8 @@
# error typo detected use DGL_USE_FILE_BROWSER instead of DGL_USE_FILEBROWSER
#endif

#ifdef DGL_UI_USE_WEBVIEW
# error typo detected use DGL_UI_USE_WEB_VIEW instead of DGL_UI_USE_WEBVIEW
#ifdef DGL_USE_WEBVIEW
# error typo detected use DGL_USE_WEB_VIEW instead of DGL_USE_WEBVIEW
#endif

#if defined(DGL_FILE_BROWSER_DISABLED)


+ 5
- 0
dpf/dgl/Color.hpp View File

@@ -99,6 +99,11 @@ struct Color {
*/
Color invert() const noexcept;

/**
Create a new color based on this one but in grayscale (using weighted average).
*/
Color asGrayscale() const noexcept;

/**
Create a color specified by hue, saturation and lightness.
Values must in [0..1] range.


+ 10
- 1
dpf/dgl/EventHandlers.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
@@ -63,6 +63,9 @@ public:
bool isCheckable() const noexcept;
void setCheckable(bool checkable) noexcept;

bool isEnabled() const noexcept;
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept;

Point<double> getLastClickPosition() const noexcept;
Point<double> getLastMotionPosition() const noexcept;

@@ -121,6 +124,9 @@ public:
KnobEventHandler& operator=(const KnobEventHandler& other);
virtual ~KnobEventHandler();

bool isEnabled() const noexcept;
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept;

// if setStep(1) has been called before, this returns true
bool isInteger() const noexcept;

@@ -138,6 +144,9 @@ public:
// NOTE: value is assumed to be scaled if using log
void setDefault(float def) noexcept;

float getMinimum() const noexcept;
float getMaximum() const noexcept;

// NOTE: value is assumed to be scaled if using log
void setRange(float min, float max) noexcept;



+ 9
- 0
dpf/dgl/Makefile View File

@@ -54,6 +54,10 @@ OBJS_common = \
$(BUILD_DIR)/dgl/Window.cpp.o \
$(BUILD_DIR)/dgl/WindowPrivateData.cpp.o

ifeq ($(WINDOWS)$(USE_WEB_VIEW),truetrue)
OBJS_common += $(BUILD_DIR)/dgl/WebViewWin32.cpp.o
endif

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

OBJS_cairo = $(OBJS_common) \
@@ -201,6 +205,11 @@ $(BUILD_DIR)/dgl/pugl.mm.o: src/pugl.mm
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -ObjC++ -o $@

$(BUILD_DIR)/dgl/WebViewWin32.cpp.o: src/WebViewWin32.cpp
-@mkdir -p $(BUILD_DIR)/dgl
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@

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

$(BUILD_DIR)/dgl/%.cpp.cairo.o: src/%.cpp


+ 5
- 0
dpf/dgl/NanoVG.hpp View File

@@ -112,6 +112,11 @@ public:
*/
GLuint getTextureHandle() const;

/**
Update the image data in-place.
*/
void update(const uchar* data);

private:
Handle fHandle;
Size<uint> fSize;


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

@@ -0,0 +1,28 @@
/*
* 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

+ 26
- 1
dpf/dgl/Window.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,10 @@
# include "FileBrowserDialog.hpp"
#endif

#ifdef DGL_USE_WEB_VIEW
# include "WebView.hpp"
#endif

#include <vector>

#ifdef DISTRHO_NAMESPACE
@@ -407,6 +411,27 @@ public:
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif

#ifdef DGL_USE_WEB_VIEW
/**
Create a new web view.

The web view will be added on top of this 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 in @p options 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 options: Extra options, optional
*/
bool createWebView(const char* url, const DGL_NAMESPACE::WebViewOptions& options = WebViewOptions());

/**
Evaluate/run JavaScript on the web view.
*/
void evaluateJS(const char* js);
#endif

/**
Request repaint of this window, for the entire area.
*/


+ 54
- 1
dpf/dgl/src/Application.cpp 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
@@ -24,6 +24,11 @@

START_NAMESPACE_DGL

/* define webview start */
#if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW)
int dpf_webview_start(int argc, char* argv[]);
#endif

// --------------------------------------------------------------------------------------------------------------------
// build config sentinels

@@ -42,6 +47,12 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on)
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off)
#endif

#ifdef DGL_USE_WEB_VIEW
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_off)
#endif

#ifdef DGL_NO_SHARED_RESOURCES
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on)
#else
@@ -64,6 +75,11 @@ bool dpf_check_build_status() noexcept
#else
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok &&
#endif
#ifdef DGL_USE_WEB_VIEW
fail_to_link_is_mismatch_dgl_use_web_view_on.ok &&
#else
fail_to_link_is_mismatch_dgl_use_web_view_off.ok &&
#endif
#ifdef DGL_NO_SHARED_RESOURCES
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok &&
#else
@@ -96,6 +112,43 @@ Application::Application(const bool isStandalone)
#else
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true;
#endif
#ifdef DGL_USE_WEB_VIEW
fail_to_link_is_mismatch_dgl_use_web_view_on.ok = true;
#else
fail_to_link_is_mismatch_dgl_use_web_view_off.ok = true;
#endif
#ifdef DGL_NO_SHARED_RESOURCES
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true;
#else
fail_to_link_is_mismatch_dgl_no_shared_resources_off.ok = true;
#endif
DISTRHO_SAFE_ASSERT(dpf_check_build_status());
}

Application::Application(int argc, char* argv[])
: pData(new PrivateData(true))
{
#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));
#endif

// build config sentinels
#ifdef DPF_DEBUG
fail_to_link_is_mismatch_dpf_debug_on.ok = true;
#else
fail_to_link_is_mismatch_dpf_debug_off.ok = true;
#endif
#ifdef DGL_USE_FILE_BROWSER
fail_to_link_is_mismatch_dgl_use_file_browser_on.ok = true;
#else
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true;
#endif
#ifdef DGL_USE_WEB_VIEW
fail_to_link_is_mismatch_dgl_use_web_view_on.ok = true;
#else
fail_to_link_is_mismatch_dgl_use_web_view_off.ok = true;
#endif
#ifdef DGL_NO_SHARED_RESOURCES
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true;
#else


+ 8
- 0
dpf/dgl/src/Color.cpp View File

@@ -172,6 +172,14 @@ Color Color::invert() const noexcept
return color;
}

Color Color::asGrayscale() const noexcept
{
Color color(*this);
// values taken from https://goodcalculators.com/rgb-to-grayscale-conversion-calculator/
color.red = color.green = color.blue = 0.299f * color.red + 0.587f * color.green + 0.114f * color.blue;
return color;
}

Color Color::fromHSL(float hue, float saturation, float lightness, float alpha)
{
float m1, m2;


+ 101
- 1
dpf/dgl/src/EventHandlers.cpp 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
@@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData {
int state;
bool checkable;
bool checked;
bool enabled;
bool enabledInput;

Point<double> lastClickPos;
Point<double> lastMotionPos;
@@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData {
state(kButtonStateDefault),
checkable(false),
checked(false),
enabled(true),
enabledInput(true),
lastClickPos(0, 0),
lastMotionPos(0, 0) {}

bool mouseEvent(const Widget::MouseEvent& ev)
{
if (! enabledInput)
return false;

lastClickPos = ev.pos;

// button was released, handle it now
@@ -98,6 +105,9 @@ struct ButtonEventHandler::PrivateData {

bool motionEvent(const Widget::MotionEvent& ev)
{
if (! enabledInput)
return false;

// keep pressed
if (button != -1)
{
@@ -171,6 +181,27 @@ struct ButtonEventHandler::PrivateData {
}
}

void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept
{
if (appliesToEventInput)
enabledInput = enabled2;

if (enabled == enabled2)
return;

// reset temp vars if disabling
if (! enabled2)
{
button = -1;
state = kButtonStateDefault;
lastClickPos = Point<double>();
lastMotionPos = Point<double>();
}

enabled = enabled2;
widget->repaint();
}

DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
};

@@ -217,6 +248,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept
pData->checkable = checkable;
}

bool ButtonEventHandler::isEnabled() const noexcept
{
return pData->enabled;
}

void ButtonEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept
{
pData->setEnabled(enabled, appliesToEventInput);
}

Point<double> ButtonEventHandler::getLastClickPosition() const noexcept
{
return pData->lastClickPos;
@@ -281,6 +322,8 @@ struct KnobEventHandler::PrivateData {
float value;
float valueDef;
float valueTmp;
bool enabled;
bool enabledInput;
bool usingDefault;
bool usingLog;
Orientation orientation;
@@ -301,6 +344,8 @@ struct KnobEventHandler::PrivateData {
value(0.5f),
valueDef(value),
valueTmp(value),
enabled(true),
enabledInput(true),
usingDefault(false),
usingLog(false),
orientation(Vertical),
@@ -320,6 +365,8 @@ struct KnobEventHandler::PrivateData {
value(other->value),
valueDef(other->valueDef),
valueTmp(value),
enabled(other->enabled),
enabledInput(other->enabledInput),
usingDefault(other->usingDefault),
usingLog(other->usingLog),
orientation(other->orientation),
@@ -338,6 +385,8 @@ struct KnobEventHandler::PrivateData {
value = other->value;
valueDef = other->valueDef;
valueTmp = value;
enabled = other->enabled;
enabledInput = other->enabledInput;
usingDefault = other->usingDefault;
usingLog = other->usingLog;
orientation = other->orientation;
@@ -363,6 +412,9 @@ struct KnobEventHandler::PrivateData {

bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor)
{
if (! enabledInput)
return false;

if (ev.button != 1)
return false;

@@ -416,6 +468,9 @@ struct KnobEventHandler::PrivateData {

bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor)
{
if (! enabledInput)
return false;

if ((state & kKnobStateDragging) == 0x0)
return false;

@@ -501,6 +556,9 @@ struct KnobEventHandler::PrivateData {

bool scrollEvent(const Widget::ScrollEvent& ev)
{
if (! enabledInput)
return false;

if (! widget->contains(ev.pos))
return false;

@@ -541,6 +599,28 @@ struct KnobEventHandler::PrivateData {
return ((usingLog ? invlogscale(value) : value) - minimum) / diff;
}

void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept
{
if (appliesToEventInput)
enabledInput = enabled2;

if (enabled == enabled2)
return;

// reset temp vars if disabling
if (! enabled2)
{
state = kKnobStateDefault;
lastX = 0.0;
lastY = 0.0;
lastClickTime = 0;
valueTmp = value;
}

enabled = enabled2;
widget->repaint();
}

void setRange(const float min, const float max) noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(max > min,);
@@ -598,6 +678,16 @@ KnobEventHandler::~KnobEventHandler()
delete pData;
}

bool KnobEventHandler::isEnabled() const noexcept
{
return pData->enabled;
}

void KnobEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept
{
pData->setEnabled(enabled, appliesToEventInput);
}

bool KnobEventHandler::isInteger() const noexcept
{
return d_isEqual(pData->step, 1.f);
@@ -629,6 +719,16 @@ void KnobEventHandler::setDefault(const float def) noexcept
pData->usingDefault = true;
}

float KnobEventHandler::getMinimum() const noexcept
{
return pData->minimum;
}

float KnobEventHandler::getMaximum() const noexcept
{
return pData->maximum;
}

void KnobEventHandler::setRange(const float min, const float max) noexcept
{
pData->setRange(min, max);


+ 8
- 0
dpf/dgl/src/NanoVG.cpp View File

@@ -279,6 +279,14 @@ GLuint NanoImage::getTextureHandle() const
return nvglImageHandle(fHandle.context, fHandle.imageId);
}

void NanoImage::update(const uchar* const data)
{
DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,);
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,);

nvgUpdateImage(fHandle.context, fHandle.imageId, data);
}

void NanoImage::_updateSize()
{
int w=0, h=0;


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

@@ -0,0 +1,23 @@
/*
* 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"

+ 15
- 1
dpf/dgl/src/Window.cpp 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
@@ -421,6 +421,20 @@ bool Window::openFileBrowser(const FileBrowserOptions& options)
}
#endif

#ifdef DGL_USE_WEB_VIEW
bool Window::createWebView(const char* const url, const DGL_NAMESPACE::WebViewOptions& options)
{
return pData->createWebView(url, options);
}

void Window::evaluateJS(const char* const js)
{
DISTRHO_SAFE_ASSERT_RETURN(pData->webViewHandle != nullptr,);

webViewEvaluateJS(pData->webViewHandle, js);
}
#endif

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


+ 92
- 33
dpf/dgl/src/WindowPrivateData.cpp 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
@@ -40,13 +40,11 @@ START_NAMESPACE_DGL
#endif

#ifdef DGL_DEBUG_EVENTS
# define DGL_DBG(msg) std::fprintf(stderr, "%s", msg);
# define DGL_DBGp(...) std::fprintf(stderr, __VA_ARGS__);
# define DGL_DBGF std::fflush(stderr);
# define DGL_DBG(msg) d_stdout("%s", msg);
# define DGL_DBGp(...) d_stdout(__VA_ARGS__);
#else
# define DGL_DBG(msg)
# define DGL_DBGp(...)
# define DGL_DBGF
#endif

#define DEFAULT_WIDTH 640
@@ -130,6 +128,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
filenameToRenderInto(nullptr),
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
#ifdef DGL_USE_WEB_VIEW
webViewHandle(nullptr),
#endif
modal()
{
@@ -160,6 +161,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c
filenameToRenderInto(nullptr),
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
#ifdef DGL_USE_WEB_VIEW
webViewHandle(nullptr),
#endif
modal(ppData)
{
@@ -192,6 +196,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
filenameToRenderInto(nullptr),
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
#ifdef DGL_USE_WEB_VIEW
webViewHandle(nullptr),
#endif
modal()
{
@@ -227,6 +234,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
filenameToRenderInto(nullptr),
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
#ifdef DGL_USE_WEB_VIEW
webViewHandle(nullptr),
#endif
modal()
{
@@ -247,6 +257,10 @@ Window::PrivateData::~PrivateData()
#ifdef DGL_USE_FILE_BROWSER
if (fileBrowserHandle != nullptr)
fileBrowserClose(fileBrowserHandle);
#endif
#ifdef DGL_USE_WEB_VIEW
if (webViewHandle != nullptr)
webViewDestroy(webViewHandle);
#endif
puglHide(view);
appData->oneWindowClosed();
@@ -394,13 +408,21 @@ void Window::PrivateData::hide()
if (modal.enabled)
stopModal();

#ifdef DGL_USE_FILE_BROWSER
#ifdef DGL_USE_FILE_BROWSER
if (fileBrowserHandle != nullptr)
{
fileBrowserClose(fileBrowserHandle);
fileBrowserHandle = nullptr;
}
#endif
#endif

#ifdef DGL_USE_WEB_VIEW
if (webViewHandle != nullptr)
{
webViewDestroy(webViewHandle);
webViewHandle = nullptr;
}
#endif

puglHide(view);

@@ -443,6 +465,11 @@ void Window::PrivateData::idleCallback()
fileBrowserHandle = nullptr;
}
#endif

#ifdef DGL_USE_WEB_VIEW
if (webViewHandle != nullptr)
webViewIdle(webViewHandle);
#endif
}

// -----------------------------------------------------------------------
@@ -479,7 +506,7 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback)

#ifdef DGL_USE_FILE_BROWSER
// -----------------------------------------------------------------------
// file handling
// file browser dialog

bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)
{
@@ -491,6 +518,8 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)
if (options2.title == nullptr)
options2.title = puglGetViewString(view, PUGL_WINDOW_TITLE);

options2.className = puglGetViewString(view, PUGL_CLASS_NAME);

fileBrowserHandle = fileBrowserCreate(isEmbed,
puglGetNativeView(view),
autoScaling ? autoScaleFactor : scaleFactor,
@@ -500,12 +529,38 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)
}
#endif // DGL_USE_FILE_BROWSER

#ifdef DGL_USE_WEB_VIEW
// -----------------------------------------------------------------------
// file browser dialog

bool Window::PrivateData::createWebView(const char* const url, const DGL_NAMESPACE::WebViewOptions& options)
{
if (webViewHandle != nullptr)
webViewDestroy(webViewHandle);

const PuglRect rect = puglGetFrame(view);
uint initialWidth = static_cast<uint>(rect.width) - options.offset.x;
uint initialHeight = static_cast<uint>(rect.height) - options.offset.y;

webViewOffset = Point<int>(options.offset.x, options.offset.y);

webViewHandle = webViewCreate(url,
puglGetNativeView(view),
initialWidth,
initialHeight,
autoScaling ? autoScaleFactor : scaleFactor,
options);

return webViewHandle != nullptr;
}
#endif // DGL_USE_WEB_VIEW

// -----------------------------------------------------------------------
// modal handling

void Window::PrivateData::startModal()
{
DGL_DBG("Window modal loop starting..."); DGL_DBGF;
DGL_DBG("Window modal loop starting...");
DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show());

// activate modal mode for this window
@@ -527,7 +582,7 @@ void Window::PrivateData::startModal()

void Window::PrivateData::stopModal()
{
DGL_DBG("Window modal loop stopping..."); DGL_DBGF;
DGL_DBG("Window modal loop stopping...");

// deactivate modal mode
modal.enabled = false;
@@ -579,11 +634,11 @@ void Window::PrivateData::runAsModal(const bool blockWait)
// -----------------------------------------------------------------------
// pugl events

void Window::PrivateData::onPuglConfigure(const double width, const double height)
void Window::PrivateData::onPuglConfigure(const uint width, const uint height)
{
DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,);

DGL_DBGp("PUGL: onReshape : %f %f\n", width, height);
DGL_DBGp("PUGL: onReshape : %d %d\n", width, height);

if (autoScaling)
{
@@ -596,8 +651,16 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh
autoScaleFactor = 1.0;
}

const uint uwidth = static_cast<uint>(width / autoScaleFactor + 0.5);
const uint uheight = static_cast<uint>(height / autoScaleFactor + 0.5);
const uint uwidth = d_roundToUnsignedInt(width / autoScaleFactor);
const uint uheight = d_roundToUnsignedInt(height / autoScaleFactor);

#ifdef DGL_USE_WEB_VIEW
if (webViewHandle != nullptr)
webViewResize(webViewHandle,
uwidth - webViewOffset.getX(),
uheight - webViewOffset.getY(),
autoScaling ? autoScaleFactor : scaleFactor);
#endif

self->onReshape(uwidth, uheight);

@@ -860,7 +923,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
{
Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view);
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
if (event->type != PUGL_TIMER) {
if (event->type != PUGL_TIMER && event->type != PUGL_EXPOSE && event->type != PUGL_MOTION) {
printEvent(event, "pugl event: ", true);
}
#endif
@@ -962,7 +1025,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
Widget::KeyboardEvent ev;
ev.mod = event->key.state;
ev.flags = event->key.flags;
ev.time = static_cast<uint>(event->key.time * 1000.0 + 0.5);
ev.time = d_roundToUnsignedInt(event->key.time * 1000.0);
ev.press = event->type == PUGL_KEY_PRESS;
ev.key = event->key.key;
ev.keycode = event->key.keycode;
@@ -985,7 +1048,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
Widget::CharacterInputEvent ev;
ev.mod = event->text.state;
ev.flags = event->text.flags;
ev.time = static_cast<uint>(event->text.time * 1000.0 + 0.5);
ev.time = d_roundToUnsignedInt(event->text.time * 1000.0);
ev.keycode = event->text.keycode;
ev.character = event->text.character;
std::strncpy(ev.string, event->text.string, sizeof(ev.string));
@@ -1008,7 +1071,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
Widget::MouseEvent ev;
ev.mod = event->button.state;
ev.flags = event->button.flags;
ev.time = static_cast<uint>(event->button.time * 1000.0 + 0.5);
ev.time = d_roundToUnsignedInt(event->button.time * 1000.0);
ev.button = event->button.button + 1;
ev.press = event->type == PUGL_BUTTON_PRESS;
if (pData->autoScaling && 0)
@@ -1031,7 +1094,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
Widget::MotionEvent ev;
ev.mod = event->motion.state;
ev.flags = event->motion.flags;
ev.time = static_cast<uint>(event->motion.time * 1000.0 + 0.5);
ev.time = d_roundToUnsignedInt(event->motion.time * 1000.0);
if (pData->autoScaling && 0)
{
const double scaleFactor = pData->autoScaleFactor;
@@ -1052,7 +1115,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
Widget::ScrollEvent ev;
ev.mod = event->scroll.state;
ev.flags = event->scroll.flags;
ev.time = static_cast<uint>(event->scroll.time * 1000.0 + 0.5);
ev.time = d_roundToUnsignedInt(event->scroll.time * 1000.0);
if (pData->autoScaling && 0)
{
const double scaleFactor = pData->autoScaleFactor;
@@ -1119,7 +1182,7 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver
{
#define FFMT "%6.1f"
#define PFMT FFMT " " FFMT
#define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define PRINT(fmt, ...) d_stdout(fmt, __VA_ARGS__), 1

switch (event->type) {
case PUGL_NOTHING:
@@ -1188,25 +1251,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver

if (verbose) {
switch (event->type) {
case PUGL_CREATE:
return fprintf(stderr, "%sCreate\n", prefix);
case PUGL_DESTROY:
return fprintf(stderr, "%sDestroy\n", prefix);
case PUGL_MAP:
return fprintf(stderr, "%sMap\n", prefix);
case PUGL_UNMAP:
return fprintf(stderr, "%sUnmap\n", prefix);
case PUGL_UPDATE:
return 0; // fprintf(stderr, "%sUpdate\n", prefix);
case PUGL_REALIZE:
return PRINT("%sRealize\n", prefix);
case PUGL_UNREALIZE:
return PRINT("%sUnrealize\n", prefix);
case PUGL_CONFIGURE:
return PRINT("%sConfigure " PFMT " " PFMT "\n",
return PRINT("%sConfigure %d %d %d %d\n",
prefix,
event->configure.x,
event->configure.y,
event->configure.width,
event->configure.height);
case PUGL_UPDATE:
return 0; // fprintf(stderr, "%sUpdate\n", prefix);
case PUGL_EXPOSE:
return PRINT("%sExpose " PFMT " " PFMT "\n",
return PRINT("%sExpose %d %d %d %d\n",
prefix,
event->expose.x,
event->expose.y,


+ 14
- 3
dpf/dgl/src/WindowPrivateData.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
@@ -95,6 +95,12 @@ struct Window::PrivateData : IdleCallback {
DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle;
#endif

#ifdef DGL_USE_WEB_VIEW
/** Handle for web view operations. */
DGL_NAMESPACE::WebViewHandle webViewHandle;
DGL_NAMESPACE::Point<int> webViewOffset;
#endif

/** Modal window setup. */
struct Modal {
PrivateData* parent; // parent of this window (so we can become modal)
@@ -169,10 +175,15 @@ struct Window::PrivateData : IdleCallback {
bool removeIdleCallback(IdleCallback* callback);

#ifdef DGL_USE_FILE_BROWSER
// file handling
// file browser dialog
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options);
#endif

#ifdef DGL_USE_WEB_VIEW
// web view
bool createWebView(const char* url, const DGL_NAMESPACE::WebViewOptions& options);
#endif

static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height);

// modal handling
@@ -181,7 +192,7 @@ struct Window::PrivateData : IdleCallback {
void runAsModal(bool blockWait);

// pugl events
void onPuglConfigure(double width, double height);
void onPuglConfigure(uint width, uint height);
void onPuglExpose();
void onPuglClose();
void onPuglFocus(bool focus, CrossingMode mode);


+ 10
- 5
dpf/dgl/src/pugl-upstream/src/mac.m View File

@@ -188,7 +188,7 @@ getCurrentViewStyleFlags(PuglView* const view)
}

static PuglStatus
dispatchCurrentChildViewConfiguration(PuglView* const view)
dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)
{
const NSRect framePt = [view->impl->wrapperView frame];
const NSRect framePx = nsRectFromPoints(view, framePt);
@@ -197,6 +197,11 @@ dispatchCurrentChildViewConfiguration(PuglView* const view)
return PUGL_SUCCESS;
}

if (drawViewResize) {
const NSSize sizePt = [view->impl->drawView convertSizeFromBacking:framePx.size];
[view->impl->drawView setFrameSize:sizePt];
}

const PuglConfigureEvent ev = {
PUGL_CONFIGURE,
0,
@@ -317,7 +322,7 @@ dispatchCurrentChildViewConfiguration(PuglView* const view)
if (puglview->impl->window) {
[puglview->impl->window dispatchCurrentConfiguration];
} else {
dispatchCurrentChildViewConfiguration(puglview);
dispatchCurrentChildViewConfiguration(puglview, true);
}
reshaped = false;
}
@@ -1767,7 +1772,7 @@ puglSetFrame(PuglView* view, const PuglRect frame)

[impl->wrapperView setFrame:framePt];
[impl->drawView setFrame:sizePt];
return dispatchCurrentChildViewConfiguration(view);
return dispatchCurrentChildViewConfiguration(view, false);
}

PuglStatus
@@ -1806,7 +1811,7 @@ puglSetPosition(PuglView* const view, const int x, const int y)
[impl->drawView setFrameOrigin:drawPt.origin];

// Dispatch new configuration
return dispatchCurrentChildViewConfiguration(view);
return dispatchCurrentChildViewConfiguration(view, false);
}

PuglStatus
@@ -1843,7 +1848,7 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
[impl->drawView setFrameSize:drawPt.size];

// Dispatch new configuration
return dispatchCurrentChildViewConfiguration(view);
return dispatchCurrentChildViewConfiguration(view, false);
}

PuglStatus


+ 15
- 4
dpf/dgl/src/pugl.cpp 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
@@ -110,16 +110,26 @@
# endif
#endif

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
# define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
# define FILE_BROWSER_DIALOG_DGL_NAMESPACE
# define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE
# define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
START_NAMESPACE_DGL
# include "../../distrho/extra/FileBrowserDialogImpl.hpp"
END_NAMESPACE_DGL
# include "../../distrho/extra/FileBrowserDialogImpl.cpp"
#endif

#ifdef DGL_USE_WEB_VIEW
# define DGL_WEB_VIEW_HPP_INCLUDED
# define WEB_VIEW_NAMESPACE DGL_NAMESPACE
# define WEB_VIEW_DGL_NAMESPACE
START_NAMESPACE_DGL
# include "../../distrho/extra/WebViewImpl.hpp"
END_NAMESPACE_DGL
# include "../../distrho/extra/WebViewImpl.cpp"
#endif

#if defined(DGL_USING_X11) && defined(DGL_X11_WINDOW_ICON_NAME)
extern const ulong* DGL_X11_WINDOW_ICON_NAME;
#endif
@@ -363,7 +373,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)

#ifdef DGL_USING_X11
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118
if (view->impl->win && !view->parent && !view->transientParent)
// NOTE troublesome if used under KDE
if (view->impl->win && !view->parent && !view->transientParent && std::getenv("KDE_SESSION_VERSION") == nullptr)
{
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0;
}


+ 28
- 4
dpf/distrho/DistrhoDetails.hpp View File

@@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20;

/**
Parameter designation.@n
Allows a parameter to be specially designated for a task, like bypass.
Allows a parameter to be specially designated for a task, like bypass and reset.

Each designation is unique, there must be only one parameter that uses it.@n
The use of designated parameters is completely optional.
@@ -214,13 +214,20 @@ enum ParameterDesignation {
/**
Null or unset designation.
*/
kParameterDesignationNull = 0,
kParameterDesignationNull,

/**
Bypass designation.@n
When on (> 0.5f), it means the plugin must run in a bypassed state.
*/
kParameterDesignationBypass = 1
kParameterDesignationBypass,

/**
Reset designation.@n
When on (> 0.5f), it means the plugin should reset its internal processing state
(like filters, oscillators, envelopes, lfos, etc) and kill all voices.
*/
kParameterDesignationReset,
};

/**
@@ -234,7 +241,12 @@ namespace ParameterDesignationSymbols {
static constexpr const char bypass[] = "dpf_bypass";

/**
Bypass designation symbol, inverted for LV2 so it becomes "enabled".
Reset designation symbol.
*/
static constexpr const char reset[] = "dpf_reset";

/**
LV2 bypass designation symbol, inverted for LV2 so it becomes "enabled".
*/
static constexpr const char bypass_lv2[] = "lv2_enabled";
};
@@ -728,6 +740,18 @@ struct Parameter {
ranges.min = 0.0f;
ranges.max = 1.0f;
break;
case kParameterDesignationReset:
hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger|kParameterIsTrigger;
name = "Reset";
shortName = "Reset";
symbol = ParameterDesignationSymbols::reset;
unit = "";
midiCC = 0;
groupId = kPortGroupNone;
ranges.def = 0.0f;
ranges.min = 0.0f;
ranges.max = 1.0f;
break;
}
}



+ 22
- 2
dpf/distrho/DistrhoPluginUtils.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
@@ -37,9 +37,29 @@ START_NAMESPACE_DISTRHO
*/
const char* getBinaryFilename();

/**
Get an OS-specific directory intended to store persistent configuration data about the plugin.@n
Calling this function will ensure the dictory exists on the filesystem.@n
The returned path already includes DISTRHO_PLUGIN_NAME and final OS separator.
*/
const char* getConfigDir();

/**
Get an OS-specific directory intended to store "documents" for the plugin.@n
Calling this function will ensure the dictory exists on the filesystem.@n
The returned path already includes DISTRHO_PLUGIN_NAME and final OS separator.
*/
const char* getDocumentsDir();

/**
Get the user "home" directory.@n
This function is provided only for convenience, it should not be needed under normal circunstances.
*/
const char* getHomeDir();

/**
Get a string representation of the current plugin format we are building against.@n
This can be "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2" or "VST3".@n
This can be "AudioUnit", "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2" or "VST3" or "CLAP".@n
This string is purely informational and must not be used to tweak plugin behaviour.

@note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT.


+ 2
- 1
dpf/distrho/DistrhoUI.hpp View File

@@ -185,7 +185,8 @@ public:
#if DISTRHO_UI_FILE_BROWSER
/**
Open a file browser dialog with this window as transient parent.@n
A few options can be specified to setup the dialog.
A few options can be specified to setup the dialog.@n
The @a DISTRHO_NAMESPACE::FileBrowserOptions::className variable is automatically set in this call.

If a path is selected, onFileSelected() will be called with the user chosen path.
If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.


+ 2
- 2
dpf/distrho/DistrhoUIMain.cpp 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
@@ -66,7 +66,7 @@
# endif
#endif

#if defined(DPF_USING_LD_LINUX_WEBVIEW) && !DISTRHO_IS_STANDALONE
#if defined(DISTRHO_UI_LINUX_WEBVIEW_START) && !DISTRHO_IS_STANDALONE
int main(int argc, char* argv[])
{
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv);


+ 1
- 0
dpf/distrho/DistrhoUI_win32.cpp View File

@@ -22,6 +22,7 @@

#if DISTRHO_UI_WEB_VIEW
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE
# include "extra/WebView.hpp"
# include "extra/WebViewWin32.hpp"
#endif

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

@@ -0,0 +1,106 @@
/*
* 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

+ 18
- 4
dpf/distrho/extra/String.hpp View File

@@ -22,6 +22,10 @@

#include <algorithm>

#if __cplusplus >= 201703L
# include <string_view>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
@@ -49,10 +53,7 @@ public:
fBufferLen(0),
fBufferAlloc(false)
{
char ch[2];
ch[0] = c;
ch[1] = '\0';

const char ch[2] = { c, '\0' };
_dup(ch);
}

@@ -87,6 +88,19 @@ public:
_dup(strBuf);
}

#if __cplusplus >= 201703L
/*
* std::string_view compatible variant.
*/
explicit String(const std::string_view& strView) noexcept
: fBuffer(_null()),
fBufferLen(0),
fBufferAlloc(false)
{
_dup(strView.data(), strView.size());
}
#endif

/*
* Integer.
*/


+ 20
- 11
dpf/distrho/extra/WebViewImpl.cpp 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
@@ -99,14 +99,14 @@
#define MACRO_NAME(a, b, c) MACRO_NAME2(a, b, c)

#define WEB_VIEW_DELEGATE_CLASS_NAME \
MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE)
MACRO_NAME(WebViewDelegate_, _, WEB_VIEW_NAMESPACE)

@interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate>
@end

@implementation WEB_VIEW_DELEGATE_CLASS_NAME {
@public
DISTRHO_NAMESPACE::WebViewMessageCallback callback;
WEB_VIEW_NAMESPACE::WebViewMessageCallback callback;
void* callbackPtr;
bool loaded;
}
@@ -242,6 +242,11 @@ START_NAMESPACE_DISTRHO

#if WEB_VIEW_USING_X11_IPC

#ifdef WEB_VIEW_DGL_NAMESPACE
using DISTRHO_NAMESPACE::ChildProcess;
using DISTRHO_NAMESPACE::RingBufferControl;
#endif

#ifdef __linux__
typedef int32_t ipc_sem_t;
#else
@@ -773,8 +778,10 @@ void webViewIdle(const WebViewHandle handle)

d_stderr("server ringbuffer data race, abort!");
handle->rbctrl2.flush();
return;
break;
}

std::free(buffer);
#else
// unused
(void)handle;
@@ -941,7 +948,7 @@ struct QSize {
S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \
DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false);

static void web_wake_idle(void* const ptr)
static int web_wake_idle(void* const ptr)
{
WebViewRingBuffer* const shmptr = static_cast<WebViewRingBuffer*>(ptr);

@@ -989,6 +996,7 @@ static void web_wake_idle(void* const ptr)
}

free(buffer);
return 0;
}

// -----------------------------------------------------------------------------------------------------------
@@ -1039,7 +1047,9 @@ static bool gtk3(Display* const display,
{
void* lib;
if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr &&
(lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
(lib = dlopen("libwebkit2gtk-4.1.so.0", RTLD_NOW|RTLD_GLOBAL)) == nullptr &&
(lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr &&
(lib = dlopen("libwebkit2gtk-4.1.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr)
{
d_stdout("WebView gtk3 platform not available: %s", dlerror());
return false;
@@ -1135,10 +1145,8 @@ static bool gtk3(Display* const display,
GtkWidget* const window = gtk_plug_new(winId);
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false);

gtk_window_set_default_size(GTK_WINDOW(window),
(width - x) * scaleFactor,
(height - y) * scaleFactor);
gtk_window_move(GTK_WINDOW(window), x * scaleFactor, y * scaleFactor);
gtk_window_set_default_size(GTK_WINDOW(window), width, height);
gtk_window_move(GTK_WINDOW(window), x, y);

WebKitSettings* const settings = webkit_settings_new();
DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false);
@@ -1774,7 +1782,7 @@ static bool qtwebengine(const int qtVersion,
QWebEnginePage_setWebChannel(&page, &channel, 0);

QWebEngineView_move(&webview, QPoint(x, y));
QWebEngineView_resize(&webview, QSize(static_cast<int>(width), static_cast<int>(height)));
QWebEngineView_resize(&webview, QSize(static_cast<int>(width / scaleFactor), static_cast<int>(height / scaleFactor)));
QWebEngineView_winId(&webview);
QWindow_setParent(QWebEngineView_windowHandle(&webview), QWindow_fromWinId(winId));

@@ -2061,3 +2069,4 @@ END_NAMESPACE_DISTRHO

#undef WEB_VIEW_DISTRHO_NAMESPACE
#undef WEB_VIEW_DGL_NAMESPACE
#undef WEB_VIEW_NAMESPACE

+ 11
- 2
dpf/distrho/extra/WebViewImpl.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
@@ -18,7 +18,7 @@
# error bad include
#endif

#if !defined(DGL_UI_USE_WEB_VIEW) && defined(DISTRHO_UI_WEB_VIEW) && DISTRHO_UI_WEB_VIEW == 0
#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

@@ -125,3 +125,12 @@ void webViewReload(WebViewHandle webview);
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); }
};

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

+ 25
- 4
dpf/distrho/extra/WebViewWin32.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
@@ -26,13 +26,26 @@ START_NAMESPACE_DISTRHO

class WebView;

WebView* webview_choc_create(const WebViewOptions& opts);
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

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

@@ -41,9 +54,13 @@ END_NAMESPACE_DISTRHO
# 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 WebViewOptions& opts)
WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts)
{
WebView::Options wopts;
wopts.acceptsFirstMouseClick = true;
@@ -52,7 +69,7 @@ WebView* webview_choc_create(const WebViewOptions& opts)
std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts);
DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr);

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

@@ -94,7 +111,11 @@ 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



+ 88
- 54
dpf/distrho/src/DistrhoPluginAU.cpp 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
@@ -264,7 +264,7 @@ bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs
// --------------------------------------------------------------------------------------------------------------------

struct PropertyListener {
AudioUnitPropertyID prop;
AudioUnitPropertyID prop;
AudioUnitPropertyListenerProc proc;
void* userData;
};
@@ -348,7 +348,8 @@ public:
fUsingRenderListeners(false),
fParameterCount(fPlugin.getParameterCount()),
fLastParameterValues(nullptr),
fBypassParameterIndex(UINT32_MAX)
fBypassParameterIndex(UINT32_MAX),
fResetParameterIndex(UINT32_MAX)
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
, fMidiEventCount(0)
#endif
@@ -365,7 +366,7 @@ public:
, fStateCount(fPlugin.getStateCount())
#endif
{
if (fParameterCount != 0)
if (fParameterCount != 0)
{
fLastParameterValues = new float[fParameterCount];
std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount);
@@ -374,8 +375,17 @@ public:
{
fLastParameterValues[i] = fPlugin.getParameterValue(i);

if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass)
switch (fPlugin.getParameterDesignation(i))
{
case kParameterDesignationNull:
break;
case kParameterDesignationBypass:
fBypassParameterIndex = i;
break;
case kParameterDesignationReset:
fResetParameterIndex = i;
break;
}
}
}

@@ -923,13 +933,13 @@ public:
case kAudioUnitProperty_FastDispatch:
switch (inElement)
{
case kAudioUnitGetParameterSelect:
case kAudioUnitGetParameterSelect:
*static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter;
return noErr;
case kAudioUnitSetParameterSelect:
case kAudioUnitSetParameterSelect:
*static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter;
return noErr;
case kAudioUnitRenderSelect:
case kAudioUnitRenderSelect:
*static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender;
return noErr;
}
@@ -1143,6 +1153,8 @@ public:
const CFStringRef keyRef = CFStringCreateWithCString(nullptr,
fPlugin.getStateKey(i),
kCFStringEncodingASCII);
DISTRHO_SAFE_ASSERT_CONTINUE(keyRef != nullptr);

CFArrayAppendValue(keysRef, keyRef);
CFRelease(keyRef);
}
@@ -1458,7 +1470,7 @@ public:
const float value = bypass ? 1.f : 0.f;
fLastParameterValues[fBypassParameterIndex] = value;
fPlugin.setParameterValue(fBypassParameterIndex, value);
notifyPropertyListeners(inProp, inScope, inElement);
notifyPropertyListeners(inProp, inScope, inElement);
}
}
return noErr;
@@ -1480,12 +1492,12 @@ public:
#if DISTRHO_PLUGIN_WANT_TIMEPOS
{
const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo)));
const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0;
const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0;

std::memcpy(&fHostCallbackInfo, inData, usableDataSize);
std::memcpy(&fHostCallbackInfo, inData, usableDataSize);

if (sizeof(HostCallbackInfo) > usableDataSize)
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize);
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize);

if (changed)
notifyPropertyListeners(inProp, inScope, inElement);
@@ -1612,7 +1624,7 @@ public:
AUEventListenerNotify(NULL, NULL, &event);

if (fBypassParameterIndex == inElement)
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
}
return noErr;

@@ -1637,28 +1649,44 @@ public:

case 'DPFs':
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFStringRef), inDataSize, kAudioUnitErr_InvalidPropertyValue);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFDictionaryRef), inDataSize, kAudioUnitErr_InvalidPropertyValue);
#if DISTRHO_PLUGIN_WANT_STATE
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fStateCount, inElement, kAudioUnitErr_InvalidElement);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
{
const CFStringRef valueRef = *static_cast<const CFStringRef*>(inData);
const CFDictionaryRef dictRef = *static_cast<const CFDictionaryRef*>(inData);
DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(dictRef) == CFDictionaryGetTypeID(),
kAudioUnitErr_InvalidPropertyValue);
DISTRHO_SAFE_ASSERT_RETURN(CFDictionaryGetCount(dictRef) == 1, kAudioUnitErr_InvalidPropertyValue);

CFStringRef keyRef = nullptr;
CFStringRef valueRef = nullptr;
CFDictionaryGetKeysAndValues(dictRef,
reinterpret_cast<const void**>(&keyRef),
reinterpret_cast<const void**>(&valueRef));
DISTRHO_SAFE_ASSERT_RETURN(keyRef != nullptr && CFGetTypeID(keyRef) == CFStringGetTypeID(),
kAudioUnitErr_InvalidPropertyValue);
DISTRHO_SAFE_ASSERT_RETURN(valueRef != nullptr && CFGetTypeID(valueRef) == CFStringGetTypeID(),
kAudioUnitErr_InvalidPropertyValue);

const CFIndex valueLen = CFStringGetLength(valueRef);
char* const value = static_cast<char*>(std::malloc(valueLen + 1));
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, kAudio_ParamError);
DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8),
const CFIndex keyRefLen = CFStringGetLength(keyRef);
char* key = static_cast<char*>(std::malloc(keyRefLen + 1));
DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(keyRef, key, keyRefLen + 1, kCFStringEncodingASCII),
kAudioUnitErr_InvalidPropertyValue);

const String& key(fPlugin.getStateKey(inElement));
const CFIndex valueRefLen = CFStringGetLength(valueRef);
char* value = static_cast<char*>(std::malloc(valueRefLen + 1));
DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueRefLen + 1, kCFStringEncodingUTF8),
kAudioUnitErr_InvalidPropertyValue);

const String dkey(key);

// save this key as needed
if (fPlugin.wantStateKey(key))
fStateMap[key] = value;
if (fPlugin.wantStateKey(dkey))
fStateMap[dkey] = value;

fPlugin.setState(key, value);
fPlugin.setState(dkey, value);

std::free(key);
std::free(value);
}
return noErr;
@@ -1821,7 +1849,12 @@ public:
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);

if (fPlugin.isActive())
if (fResetParameterIndex != UINT32_MAX)
{
fPlugin.setParameterValue(fResetParameterIndex, 1.f);
fPlugin.setParameterValue(fResetParameterIndex, 0.f);
}
else if (fPlugin.isActive())
{
fPlugin.deactivate();
fPlugin.activate();
@@ -2180,6 +2213,7 @@ private:
const uint32_t fParameterCount;
float* fLastParameterValues;
uint32_t fBypassParameterIndex;
uint32_t fResetParameterIndex;

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
uint32_t fMidiEventCount;
@@ -2220,7 +2254,7 @@ private:
const PropertyListener& pl(*it);

if (pl.prop == prop)
pl.proc(pl.userData, fComponent, prop, scope, elem);
pl.proc(pl.userData, fComponent, prop, scope, elem);
}
}

@@ -2545,12 +2579,12 @@ private:
CFStringRef keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII);
CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8);

if (CFDictionaryRef dictRef = CFDictionaryCreate(nullptr,
reinterpret_cast<const void**>(&keyRef),
reinterpret_cast<const void**>(&valueRef),
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks))
if (const CFDictionaryRef dictRef = CFDictionaryCreate(nullptr,
reinterpret_cast<const void**>(&keyRef),
reinterpret_cast<const void**>(&valueRef),
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks))
{
CFArrayAppendValue(statesRef, dictRef);
CFRelease(dictRef);
@@ -2845,7 +2879,7 @@ private:
// --------------------------------------------------------------------------------------------------------------------

struct AudioComponentPlugInInstance {
AudioComponentPlugInInterface acpi;
AudioComponentPlugInInterface acpi;
PluginAU* plugin;

AudioComponentPlugInInstance() noexcept
@@ -2854,9 +2888,9 @@ struct AudioComponentPlugInInstance {
{
std::memset(&acpi, 0, sizeof(acpi));
acpi.Open = Open;
acpi.Close = Close;
acpi.Lookup = Lookup;
acpi.reserved = nullptr;
acpi.Close = Close;
acpi.Lookup = Lookup;
acpi.reserved = nullptr;
}

~AudioComponentPlugInInstance()
@@ -2864,7 +2898,7 @@ struct AudioComponentPlugInInstance {
delete plugin;
}

static OSStatus Open(void* const self, const AudioUnit component)
static OSStatus Open(void* const self, const AudioUnit component)
{
d_debug("AudioComponentPlugInInstance::Open(%p)", self);

@@ -2872,7 +2906,7 @@ struct AudioComponentPlugInInstance {
return noErr;
}

static OSStatus Close(void* const self)
static OSStatus Close(void* const self)
{
d_debug("AudioComponentPlugInInstance::Close(%p)", self);

@@ -2964,15 +2998,15 @@ struct AudioComponentPlugInInstance {
d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)",
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);

UInt32 dataSize = 0;
Boolean writable = false;
UInt32 dataSize = 0;
Boolean writable = false;
const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable);

if (outDataSize != nullptr)
*outDataSize = dataSize;
if (outDataSize != nullptr)
*outDataSize = dataSize;

if (outWritable != nullptr)
*outWritable = writable;
if (outWritable != nullptr)
*outWritable = writable;

return res;
}
@@ -3016,24 +3050,24 @@ struct AudioComponentPlugInInstance {
if (res != noErr)
return res;

void* outBuffer;
void* outBuffer;
uint8_t* tmpBuffer;
if (inDataSize < outDataSize)
{
tmpBuffer = new uint8_t[outDataSize];
outBuffer = tmpBuffer;
}
{
tmpBuffer = new uint8_t[outDataSize];
outBuffer = tmpBuffer;
}
else
{
tmpBuffer = nullptr;
outBuffer = outData;
}
tmpBuffer = nullptr;
outBuffer = outData;
}

res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer);

if (res != noErr)
if (res != noErr)
{
*ioDataSize = 0;
*ioDataSize = 0;
return res;
}



+ 37
- 6
dpf/distrho/src/DistrhoPluginCLAP.cpp View File

@@ -751,6 +751,7 @@ public:
updateStateValueCallback),
fHost(host),
fOutputEvents(nullptr),
fResetParameterIndex(UINT32_MAX),
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
fUsingCV(false),
#endif
@@ -763,7 +764,19 @@ public:
#endif
fHostExtensions(host)
{
fCachedParameters.setup(fPlugin.getParameterCount());
if (const uint32_t paramCount = fPlugin.getParameterCount())
{
fCachedParameters.setup(paramCount);

for (uint32_t i=0; i<paramCount; ++i)
{
if (fPlugin.getParameterDesignation(i) == kParameterDesignationReset)
{
fResetParameterIndex = i;
break;
}
}
}

#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true);
@@ -823,7 +836,18 @@ public:

void reset()
{
fHost->request_restart(fHost);
if (fResetParameterIndex != UINT32_MAX)
{
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fMidiEventCount = 0;
#endif
fPlugin.setParameterValue(fResetParameterIndex, 1.f);
fPlugin.setParameterValue(fResetParameterIndex, 0.f);
}
else
{
fHost->request_restart(fHost);
}
}

bool process(const clap_process_t* const process)
@@ -1119,14 +1143,19 @@ public:
{
const ParameterRanges& ranges(fPlugin.getParameterRanges(index));

if (fPlugin.getParameterDesignation(index) == kParameterDesignationBypass)
switch (fPlugin.getParameterDesignation(index))
{
case kParameterDesignationBypass:
info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE;
std::strcpy(info->name, "Bypass");
std::strcpy(info->module, "dpf_bypass");
}
else
{
break;
case kParameterDesignationReset:
info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_READONLY;
std::strcpy(info->name, "Reset");
std::strcpy(info->module, "dpf_reset");
break;
default:
const uint32_t hints = fPlugin.getParameterHints(index);
const uint32_t groupId = fPlugin.getParameterGroupId(index);

@@ -1156,6 +1185,7 @@ public:
}

d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn);
break;
}

info->id = index;
@@ -1791,6 +1821,7 @@ private:
const clap_host_t* const fHost;
const clap_output_events_t* fOutputEvents;

uint32_t fResetParameterIndex;
#if DISTRHO_PLUGIN_NUM_INPUTS != 0
const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS];
#endif


+ 3
- 10
dpf/distrho/src/DistrhoPluginChecks.h 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
@@ -286,15 +286,8 @@ static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)) == 5, "The macro DISTR
# error DISTRHO_UI_IS_STANDALONE must not be defined
#endif

#ifdef DPF_USING_LD_LINUX_WEBVIEW
# error DPF_USING_LD_LINUX_WEBVIEW must not be defined
#endif

// --------------------------------------------------------------------------------------------------------------------
// Set DPF_USING_LD_LINUX_WEBVIEW for internal use

#if DISTRHO_UI_WEB_VIEW && defined(DISTRHO_OS_LINUX)
# define DPF_USING_LD_LINUX_WEBVIEW
#ifdef DISTRHO_UI_LINUX_WEBVIEW_START
# error DISTRHO_UI_LINUX_WEBVIEW_START must not be defined
#endif

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


+ 78
- 65
dpf/distrho/src/DistrhoPluginInternal.hpp View File

@@ -338,6 +338,64 @@ public:
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
{
uint32_t j=0;
# if DISTRHO_PLUGIN_NUM_INPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
# endif
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
# endif
}
#endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0

for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
fPlugin->initParameter(i, fData->parameters[i]);

{
std::set<uint32_t> portGroupIndices;

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
portGroupIndices.insert(fData->audioPorts[i].groupId);
#endif
for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
portGroupIndices.insert(fData->parameters[i].groupId);

portGroupIndices.erase(kPortGroupNone);

if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size()))
{
fData->portGroups = new PortGroupWithId[portGroupSize];
fData->portGroupCount = portGroupSize;

uint32_t index = 0;
for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index)
{
PortGroupWithId& portGroup(fData->portGroups[index]);
portGroup.groupId = *it;

if (portGroup.groupId < portGroupSize)
fPlugin->initPortGroup(portGroup.groupId, portGroup);
else
fillInPredefinedPortGroupData(portGroup.groupId, portGroup);
}
}
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
for (uint32_t i=0; i < fData->programCount; ++i)
fPlugin->initProgramName(i, fData->programNames[i]);
#endif

#if DISTRHO_PLUGIN_WANT_STATE
for (uint32_t i=0; i < fData->stateCount; ++i)
fPlugin->initState(i, fData->states[i]);
#endif

#if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__)
/* Run-time testing build.
* Verify that virtual functions are overriden if parameters, programs or states are in use.
@@ -380,17 +438,30 @@ public:
# if DISTRHO_PLUGIN_WANT_STATE
if (fData->stateCount != 0)
{
if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) ==
(void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))
bool hasNonUiState = false;
for (uint32_t i=0; i < fData->stateCount; ++i)
{
d_stderr2("DPF warning: Plugins with state must implement `initState`");
abort();
if ((fData->states[i].hints & kStateIsOnlyForUI) == 0)
{
hasNonUiState = true;
break;
}
}

if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
if (hasNonUiState)
{
d_stderr2("DPF warning: Plugins with state must implement `setState`");
abort();
if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) ==
(void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))
{
d_stderr2("DPF warning: Plugins with state must implement `initState`");
abort();
}

if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
{
d_stderr2("DPF warning: Plugins with state must implement `setState`");
abort();
}
}
}
# endif
@@ -412,64 +483,6 @@ public:
# endif
#endif

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
{
uint32_t j=0;
# if DISTRHO_PLUGIN_NUM_INPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j)
fPlugin->initAudioPort(true, i, fData->audioPorts[j]);
# endif
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j)
fPlugin->initAudioPort(false, i, fData->audioPorts[j]);
# endif
}
#endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0

for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
fPlugin->initParameter(i, fData->parameters[i]);

{
std::set<uint32_t> portGroupIndices;

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
portGroupIndices.insert(fData->audioPorts[i].groupId);
#endif
for (uint32_t i=0, count=fData->parameterCount; i < count; ++i)
portGroupIndices.insert(fData->parameters[i].groupId);

portGroupIndices.erase(kPortGroupNone);

if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size()))
{
fData->portGroups = new PortGroupWithId[portGroupSize];
fData->portGroupCount = portGroupSize;

uint32_t index = 0;
for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index)
{
PortGroupWithId& portGroup(fData->portGroups[index]);
portGroup.groupId = *it;

if (portGroup.groupId < portGroupSize)
fPlugin->initPortGroup(portGroup.groupId, portGroup);
else
fillInPredefinedPortGroupData(portGroup.groupId, portGroup);
}
}
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
for (uint32_t i=0, count=fData->programCount; i < count; ++i)
fPlugin->initProgramName(i, fData->programNames[i]);
#endif

#if DISTRHO_PLUGIN_WANT_STATE
for (uint32_t i=0, count=fData->stateCount; i < count; ++i)
fPlugin->initState(i, fData->states[i]);
#endif

fData->callbacksPtr = callbacksPtr;
fData->writeMidiCallbackFunc = writeMidiCall;
fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall;


+ 3
- 7
dpf/distrho/src/DistrhoPluginJACK.cpp 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>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -88,10 +88,6 @@ static const writeMidiFunc writeMidiCallback = nullptr;
static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
#endif

#ifdef DPF_USING_LD_LINUX_WEBVIEW
int dpf_webview_start(int argc, char* argv[]);
#endif

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

static volatile bool gCloseSignalReceived = false;
@@ -1003,9 +999,9 @@ int main(int argc, char* argv[])
}
#endif

#ifdef DPF_USING_LD_LINUX_WEBVIEW
#if defined(DISTRHO_UI_LINUX_WEBVIEW_START)
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
return dpf_webview_start(argc, argv);
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv);
#endif

if (argc == 2 && std::strcmp(argv[1], "selftest") == 0)


+ 10
- 0
dpf/distrho/src/DistrhoPluginLV2export.cpp View File

@@ -758,6 +758,16 @@ void lv2_generate_ttl(const char* const basename)
pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n";
pluginString += " lv2:designation lv2:enabled ;\n";
break;
case kParameterDesignationReset:
designated = true;
pluginString += " lv2:name \"Reset\" ;\n";
pluginString += " lv2:symbol \"" + String(ParameterDesignationSymbols::reset) + "\" ;\n";
pluginString += " lv2:default 0 ;\n";
pluginString += " lv2:minimum 0 ;\n";
pluginString += " lv2:maximum 1 ;\n";
pluginString += " lv2:portProperty lv2:toggled , lv2:integer , <" LV2_PORT_PROPS__trigger "> ;\n";
pluginString += " lv2:designation <" LV2_KXSTUDIO_PROPERTIES__Reset "> ;\n";
break;
}
}



+ 6
- 0
dpf/distrho/src/DistrhoPluginVST3.cpp View File

@@ -1747,6 +1747,12 @@ public:
case kParameterDesignationBypass:
flags |= V3_PARAM_IS_BYPASS;
break;
case kParameterDesignationReset:
info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN;
info->step_count = 1;
strncpy_utf16(info->title, "Reset", 128);
strncpy_utf16(info->short_title, "Reset", 128);
return V3_OK;
}

if (hints & kParameterIsOutput)


+ 16
- 8
dpf/distrho/src/DistrhoUIAU.mm 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
@@ -125,6 +125,7 @@ public:

CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes);

// setup property listeners
AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this);
AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this);
#if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -322,15 +323,22 @@ private:
#if DISTRHO_PLUGIN_WANT_STATE
void setState(const char* const key, const char* const value)
{
const std::vector<String>::iterator it = std::find(fStateKeys.begin(), fStateKeys.end(), key);
DISTRHO_SAFE_ASSERT_RETURN(it != fStateKeys.end(),);

if (const CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8))
CFStringRef keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII);
CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8);

if (const CFDictionaryRef dictRef = CFDictionaryCreate(nullptr,
reinterpret_cast<const void**>(&keyRef),
reinterpret_cast<const void**>(&valueRef),
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks))
{
const uint32_t index = it - fStateKeys.begin();
AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, index, &valueRef, sizeof(CFStringRef));
CFRelease(valueRef);
AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, 0, &dictRef, sizeof(dictRef));
CFRelease(dictRef);
}

CFRelease(keyRef);
CFRelease(valueRef);
}

static void setStateCallback(void* const ptr, const char* const key, const char* const value)


+ 3
- 7
dpf/distrho/src/DistrhoUIDSSI.cpp 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
@@ -38,10 +38,6 @@ static constexpr const setSizeFunc setSizeCallback = nullptr;
// unsupported in DSSI
static constexpr const fileRequestFunc fileRequestCallback = nullptr;

#ifdef DPF_USING_LD_LINUX_WEBVIEW
int dpf_webview_start(int argc, char* argv[]);
#endif

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


@@ -391,9 +387,9 @@ int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO

#ifdef DPF_USING_LD_LINUX_WEBVIEW
#if defined(DISTRHO_UI_LINUX_WEBVIEW_START)
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
return dpf_webview_start(argc - 1, argv + 1);
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv);
#endif

// dummy test mode


+ 7
- 1
dpf/distrho/src/DistrhoUIPrivateData.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
@@ -61,6 +61,12 @@

START_NAMESPACE_DISTRHO

/* define webview start */
#if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && DISTRHO_UI_WEB_VIEW
# define DISTRHO_UI_LINUX_WEBVIEW_START
int dpf_webview_start(int argc, char* argv[]);
#endif

// -----------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details



+ 178
- 6
dpf/distrho/src/DistrhoUtils.cpp 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,13 +23,19 @@
#include "../DistrhoStandaloneUtils.hpp"

#ifdef DISTRHO_OS_WINDOWS
# include <direct.h>
# include <shlobj.h>
# include <windows.h>
#else
# ifndef STATIC_BUILD
# include <dlfcn.h>
# endif
# include <fcntl.h>
# include <limits.h>
# include <pwd.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <unistd.h>
#endif

#ifdef DISTRHO_OS_WINDOWS
@@ -76,6 +82,177 @@ const char* getBinaryFilename()
return filename;
}

const char* getConfigDir()
{
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS)
return getDocumentsDir();
#else
static String dir;

if (dir.isEmpty())
{
if (const char* const xdgEnv = getenv("XDG_CONFIG_HOME"))
dir = xdgEnv;

if (dir.isEmpty())
{
dir = getHomeDir();
dir += "/.config";
}

// ensure main config dir exists
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);

// and also our custom subdir
dir += "/" DISTRHO_PLUGIN_NAME "/";
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);
}

return dir;
#endif
}

const char* getDocumentsDir()
{
static String dir;

if (dir.isEmpty())
{
#if defined(DISTRHO_OS_MAC)
dir = getHomeDir();
dir += "/Documents/" DISTRHO_PLUGIN_NAME "/";
#elif defined(DISTRHO_OS_WASM)
dir = getHomeDir();
dir += "/";
#elif defined(DISTRHO_OS_WINDOWS)
WCHAR wpath[MAX_PATH];
if (SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, wpath) == S_OK)
{
CHAR apath[MAX_PATH];
if (WideCharToMultiByte(CP_UTF8, 0, wpath, -1, apath, MAX_PATH, nullptr, nullptr) != 0)
{
dir = apath;
dir += "\\" DISTRHO_PLUGIN_NAME "\\";
wcscat(wpath, L"\\" DISTRHO_PLUGIN_NAME "\\");
}
}
#else
String xdgDirsConfigPath(getConfigDir());
xdgDirsConfigPath += "/user-dirs.dirs";

if (FILE* const f = std::fopen(xdgDirsConfigPath, "r"))
{
std::fseek(f, 0, SEEK_END);
const long size = std::ftell(f);
std::fseek(f, 0, SEEK_SET);

// something is wrong if config dirs file is longer than 1MiB!
if (size > 0 && size < 1024 * 1024)
{
if (char* filedata = static_cast<char*>(std::malloc(size)))
{
for (long r = 0, total = 0; total < size;)
{
r = std::fread(filedata + total, 1, size - total, f);

if (r == 0)
{
std::free(filedata);
filedata = nullptr;
break;
}

total += r;
}

if (filedata != nullptr)
{
if (char* const xdgDocsDir = std::strstr(filedata, "XDG_DOCUMENTS_DIR=\""))
{
if (char* const xdgDocsDirNL = std::strstr(xdgDocsDir, "\"\n"))
{
*xdgDocsDirNL = '\0';
String sdir(xdgDocsDir + 19);

if (sdir.startsWith("$HOME"))
{
dir = getHomeDir();
dir += sdir.buffer() + 5;
}
else
{
dir = sdir;
}

// ensure main config dir exists
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);
}
}

std::free(filedata);
}
}
}

std::fclose(f);
}

// ${XDG_CONFIG_HOME}/user-dirs.dirs does not exist or has bad data
if (dir.isEmpty())
{
dir = getDocumentsDir();
dir += DISTRHO_PLUGIN_NAME "/";
}
#endif

// ensure our custom subdir exists
if (dir.isNotEmpty())
{
#ifdef DISTRHO_OS_WINDOWS
_wmkdir(wpath);
#else
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);
#endif
}
}

return dir;
}

const char* getHomeDir()
{
static String dir;

if (dir.isEmpty())
{
#ifdef DISTRHO_OS_WINDOWS
WCHAR wpath[MAX_PATH];
if (SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, SHGFP_TYPE_CURRENT, wpath) == S_OK)
{
CHAR apath[MAX_PATH];
if (WideCharToMultiByte(CP_UTF8, 0, wpath, -1, apath, MAX_PATH, nullptr, nullptr) != 0)
dir = apath;
}
#else
if (const char* const homeEnv = getenv("HOME"))
dir = homeEnv;

if (dir.isEmpty())
if (struct passwd* const pwd = getpwuid(getuid()))
dir = pwd->pw_dir;

if (dir.isNotEmpty() && ! dir.endsWith('/'))
dir += "/";
#endif
}

return dir;
}

const char* getPluginFormatName() noexcept
{
#if defined(DISTRHO_PLUGIN_TARGET_AU)
@@ -166,11 +343,6 @@ bool requestBufferSizeChange(uint) { return false; }
bool requestMIDI() { return false; }
#endif

/* define webview start */
#ifdef DPF_USING_LD_LINUX_WEBVIEW
int dpf_webview_start(int argc, char* argv[]);
#endif

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

END_NAMESPACE_DISTRHO

+ 2
- 1
dpf/distrho/src/lv2/lv2_kxstudio_properties.h View File

@@ -1,6 +1,6 @@
/*
LV2 KXStudio Properties Extension
Copyright 2014-2021 Filipe Coelho <falktx@falktx.com>
Copyright 2014-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
@@ -27,6 +27,7 @@
#define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#"

#define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable"
#define LV2_KXSTUDIO_PROPERTIES__Reset LV2_KXSTUDIO_PROPERTIES_PREFIX "Reset"
#define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat"
#define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId"



+ 77
- 0
dpf/utils/install-plugins-symlinks.sh View File

@@ -0,0 +1,77 @@
#!/bin/bash

# the realpath function is not available on some systems
if ! which realpath &>/dev/null; then
function realpath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
fi

set -e

DPF_UTILS_DIR="$(dirname $(realpath ${0}))"

if [ -d bin ]; then
cd bin
elif [ -d build/bin ]; then
cd build/bin
else
echo "Please run this script from the root folder"
exit
fi

if [ "$(uname -s)" = "Darwin" ]; then
CLAP_PATH=~/Library/Audio/Plug-Ins/CLAP
LV2_PATH=~/Library/Audio/Plug-Ins/LV2
VST2_PATH=~/Library/Audio/Plug-Ins/VST
VST3_PATH=~/Library/Audio/Plug-Ins/VST3
else
CLAP_PATH=~/.clap
LV2_PATH=~/.lv2
VST2_PATH=~/.vst
VST3_PATH=~/.vst3
fi

export IFS=$'\n'

# NOTE macOS ignores AU plugins installed in ~/Library/Audio/Plug-Ins/Components/
# we **MUST** install AU plugins system-wide, so we need sudo/root here
# they cannot be symlinks either, so we do a full copy
for p in $(find . -maxdepth 1 -name '*.component' -print | grep '.component'); do
basename=$(basename ${p})
if [ ! -L /Library/Audio/Plug-Ins/Components/"${basename}" ]; then
sudo cp -r $(pwd)/"${basename}" /Library/Audio/Plug-Ins/Components/
fi
done

for p in $(find . -maxdepth 1 -name '*.clap' -print); do
basename=$(basename ${p})
mkdir -p ${CLAP_PATH}
if [ ! -L ${CLAP_PATH}/"${basename}" ]; then
ln -s $(pwd)/"${basename}" ${CLAP_PATH}/"${basename}"
fi
done

for p in $(find . -maxdepth 1 -name '*.lv2' -print); do
basename=$(basename ${p})
mkdir -p ${LV2_PATH}
if [ ! -L ${LV2_PATH}/"${basename}" ]; then
ln -s $(pwd)/"${basename}" ${LV2_PATH}/"${basename}"
fi
done

for p in $(find . -maxdepth 1 -name '*.vst' -print); do
basename=$(basename ${p})
mkdir -p ${VST2_PATH}
if [ ! -L ${VST2_PATH}/"${basename}" ]; then
ln -s $(pwd)/"${basename}" ${VST2_PATH}/"${basename}"
fi
done

for p in $(find . -maxdepth 1 -name '*.vst3' -print); do
basename=$(basename ${p})
mkdir -p ${VST3_PATH}
if [ ! -L ${VST3_PATH}/"${basename}" ]; then
ln -s $(pwd)/"${basename}" ${VST3_PATH}/"${basename}"
fi
done

Loading…
Cancel
Save