@@ -1,10 +1,10 @@ | |||||
# DISTRHO Plugin Framework (DPF) | # DISTRHO Plugin Framework (DPF) | ||||
# Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | # 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 | # SPDX-License-Identifier: ISC | ||||
cmake_minimum_required(VERSION 3.7) | |||||
cmake_minimum_required(VERSION 3.8) | |||||
project(DPF) | project(DPF) | ||||
@@ -34,11 +34,11 @@ if(DPF_LIBRARIES) | |||||
if(PKG_CONFIG_FOUND) | if(PKG_CONFIG_FOUND) | ||||
pkg_check_modules(CAIRO "cairo") | pkg_check_modules(CAIRO "cairo") | ||||
if(CAIRO_FOUND AND (NOT HAIKU)) | if(CAIRO_FOUND AND (NOT HAIKU)) | ||||
dpf__add_dgl_cairo(TRUE, TRUE) | |||||
dpf__add_dgl_cairo(TRUE, TRUE, TRUE) | |||||
endif() | endif() | ||||
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() | endif() | ||||
if(DPF_EXAMPLES) | if(DPF_EXAMPLES) | ||||
@@ -287,7 +287,7 @@ HAVE_DGL = false | |||||
endif | endif | ||||
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) | DGL_LIB_SHARED = $(shell $(CC) -print-file-name=Scrt1.o) | ||||
endif | endif | ||||
@@ -121,23 +121,33 @@ function(dpf_add_plugin NAME) | |||||
set(_dgl_library) | set(_dgl_library) | ||||
if(_dpf_plugin_FILES_UI) | if(_dpf_plugin_FILES_UI) | ||||
if(_dpf_plugin_UI_TYPE STREQUAL "cairo") | 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) | set(_dgl_library dgl-cairo) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "external") | 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) | set(_dgl_library dgl-external) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl") | 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) | set(_dgl_library dgl-opengl) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3") | 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) | set(_dgl_library dgl-opengl3) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "vulkan") | 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) | set(_dgl_library dgl-vulkan) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "webview") | elseif(_dpf_plugin_UI_TYPE STREQUAL "webview") | ||||
set(_dpf_plugin_USE_WEB_VIEW TRUE) | 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) | set(_dgl_library dgl-external) | ||||
else() | else() | ||||
message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}") | message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}") | ||||
@@ -234,6 +244,112 @@ function(dpf_add_plugin NAME) | |||||
endforeach() | endforeach() | ||||
endfunction() | 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__`) | # DPF private functions (prefixed with `dpf__`) | ||||
# ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||
@@ -661,7 +777,7 @@ endfunction() | |||||
# | # | ||||
# Add the Cairo variant of DGL, if not already available. | # 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) | if(TARGET dgl-cairo) | ||||
return() | return() | ||||
endif() | 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") | target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER") | ||||
endif() | 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() | dpf__add_dgl_system_libs() | ||||
target_link_libraries(dgl-cairo PRIVATE 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. | # 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) | if(TARGET dgl-external) | ||||
return() | return() | ||||
endif() | endif() | ||||
@@ -770,6 +901,21 @@ function(dpf__add_dgl_external USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER") | target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER") | ||||
endif() | 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() | dpf__add_dgl_system_libs() | ||||
target_compile_definitions(dgl-external PUBLIC "DGL_NO_SHARED_RESOURCES") | target_compile_definitions(dgl-external PUBLIC "DGL_NO_SHARED_RESOURCES") | ||||
target_link_libraries(dgl-external PRIVATE dgl-system-libs) | target_link_libraries(dgl-external PRIVATE dgl-system-libs) | ||||
@@ -786,7 +932,7 @@ endfunction() | |||||
# | # | ||||
# Add the OpenGL variant of DGL, if not already available. | # 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) | if(TARGET dgl-opengl) | ||||
return() | return() | ||||
endif() | 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") | target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_FILE_BROWSER") | ||||
endif() | 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() | dpf__add_dgl_system_libs() | ||||
target_link_libraries(dgl-opengl PRIVATE 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. | # 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) | if(TARGET dgl-opengl3) | ||||
return() | return() | ||||
endif() | 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") | target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_FILE_BROWSER") | ||||
endif() | 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() | dpf__add_dgl_system_libs() | ||||
target_link_libraries(dgl-opengl3 PRIVATE 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. | # 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) | if(TARGET dgl-vulkan) | ||||
return() | return() | ||||
endif() | 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") | target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_FILE_BROWSER") | ||||
endif() | 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() | dpf__add_dgl_system_libs() | ||||
target_link_libraries(dgl-vulkan PRIVATE 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) | elseif(WIN32 AND USE_WEB_VIEW) | ||||
target_sources("${NAME}" PRIVATE | target_sources("${NAME}" PRIVATE | ||||
"${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp") | "${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") | target_link_libraries("${NAME}" PRIVATE "ole32" "uuid") | ||||
endif() | endif() | ||||
endfunction() | endfunction() | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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) | BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | ||||
#endif | #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 | #ifdef DGL_NO_SHARED_RESOURCES | ||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | ||||
#else | #else | ||||
@@ -78,11 +84,16 @@ class DISTRHO_API Application | |||||
{ | { | ||||
public: | 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); | 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. | Destructor. | ||||
*/ | */ | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 | # error typo detected use DGL_USE_FILE_BROWSER instead of DGL_USE_FILEBROWSER | ||||
#endif | #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 | #endif | ||||
#if defined(DGL_FILE_BROWSER_DISABLED) | #if defined(DGL_FILE_BROWSER_DISABLED) | ||||
@@ -99,6 +99,11 @@ struct Color { | |||||
*/ | */ | ||||
Color invert() const noexcept; | 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. | Create a color specified by hue, saturation and lightness. | ||||
Values must in [0..1] range. | Values must in [0..1] range. | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -63,6 +63,9 @@ public: | |||||
bool isCheckable() const noexcept; | bool isCheckable() const noexcept; | ||||
void setCheckable(bool checkable) 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> getLastClickPosition() const noexcept; | ||||
Point<double> getLastMotionPosition() const noexcept; | Point<double> getLastMotionPosition() const noexcept; | ||||
@@ -121,6 +124,9 @@ public: | |||||
KnobEventHandler& operator=(const KnobEventHandler& other); | KnobEventHandler& operator=(const KnobEventHandler& other); | ||||
virtual ~KnobEventHandler(); | virtual ~KnobEventHandler(); | ||||
bool isEnabled() const noexcept; | |||||
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; | |||||
// if setStep(1) has been called before, this returns true | // if setStep(1) has been called before, this returns true | ||||
bool isInteger() const noexcept; | bool isInteger() const noexcept; | ||||
@@ -138,6 +144,9 @@ public: | |||||
// NOTE: value is assumed to be scaled if using log | // NOTE: value is assumed to be scaled if using log | ||||
void setDefault(float def) noexcept; | void setDefault(float def) noexcept; | ||||
float getMinimum() const noexcept; | |||||
float getMaximum() const noexcept; | |||||
// NOTE: value is assumed to be scaled if using log | // NOTE: value is assumed to be scaled if using log | ||||
void setRange(float min, float max) noexcept; | void setRange(float min, float max) noexcept; | ||||
@@ -54,6 +54,10 @@ OBJS_common = \ | |||||
$(BUILD_DIR)/dgl/Window.cpp.o \ | $(BUILD_DIR)/dgl/Window.cpp.o \ | ||||
$(BUILD_DIR)/dgl/WindowPrivateData.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) \ | OBJS_cairo = $(OBJS_common) \ | ||||
@@ -201,6 +205,11 @@ $(BUILD_DIR)/dgl/pugl.mm.o: src/pugl.mm | |||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -ObjC++ -o $@ | $(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 | $(BUILD_DIR)/dgl/%.cpp.cairo.o: src/%.cpp | ||||
@@ -112,6 +112,11 @@ public: | |||||
*/ | */ | ||||
GLuint getTextureHandle() const; | GLuint getTextureHandle() const; | ||||
/** | |||||
Update the image data in-place. | |||||
*/ | |||||
void update(const uchar* data); | |||||
private: | private: | ||||
Handle fHandle; | Handle fHandle; | ||||
Size<uint> fSize; | Size<uint> fSize; | ||||
@@ -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 |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -23,6 +23,10 @@ | |||||
# include "FileBrowserDialog.hpp" | # include "FileBrowserDialog.hpp" | ||||
#endif | #endif | ||||
#ifdef DGL_USE_WEB_VIEW | |||||
# include "WebView.hpp" | |||||
#endif | |||||
#include <vector> | #include <vector> | ||||
#ifdef DISTRHO_NAMESPACE | #ifdef DISTRHO_NAMESPACE | ||||
@@ -407,6 +411,27 @@ public: | |||||
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | ||||
#endif | #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. | Request repaint of this window, for the entire area. | ||||
*/ | */ | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -24,6 +24,11 @@ | |||||
START_NAMESPACE_DGL | 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 | // 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) | BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | ||||
#endif | #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 | #ifdef DGL_NO_SHARED_RESOURCES | ||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | ||||
#else | #else | ||||
@@ -64,6 +75,11 @@ bool dpf_check_build_status() noexcept | |||||
#else | #else | ||||
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok && | fail_to_link_is_mismatch_dgl_use_file_browser_off.ok && | ||||
#endif | #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 | #ifdef DGL_NO_SHARED_RESOURCES | ||||
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok && | fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok && | ||||
#else | #else | ||||
@@ -96,6 +112,43 @@ Application::Application(const bool isStandalone) | |||||
#else | #else | ||||
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true; | fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true; | ||||
#endif | #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 | #ifdef DGL_NO_SHARED_RESOURCES | ||||
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true; | fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true; | ||||
#else | #else | ||||
@@ -172,6 +172,14 @@ Color Color::invert() const noexcept | |||||
return color; | 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) | Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) | ||||
{ | { | ||||
float m1, m2; | float m1, m2; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData { | |||||
int state; | int state; | ||||
bool checkable; | bool checkable; | ||||
bool checked; | bool checked; | ||||
bool enabled; | |||||
bool enabledInput; | |||||
Point<double> lastClickPos; | Point<double> lastClickPos; | ||||
Point<double> lastMotionPos; | Point<double> lastMotionPos; | ||||
@@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData { | |||||
state(kButtonStateDefault), | state(kButtonStateDefault), | ||||
checkable(false), | checkable(false), | ||||
checked(false), | checked(false), | ||||
enabled(true), | |||||
enabledInput(true), | |||||
lastClickPos(0, 0), | lastClickPos(0, 0), | ||||
lastMotionPos(0, 0) {} | lastMotionPos(0, 0) {} | ||||
bool mouseEvent(const Widget::MouseEvent& ev) | bool mouseEvent(const Widget::MouseEvent& ev) | ||||
{ | { | ||||
if (! enabledInput) | |||||
return false; | |||||
lastClickPos = ev.pos; | lastClickPos = ev.pos; | ||||
// button was released, handle it now | // button was released, handle it now | ||||
@@ -98,6 +105,9 @@ struct ButtonEventHandler::PrivateData { | |||||
bool motionEvent(const Widget::MotionEvent& ev) | bool motionEvent(const Widget::MotionEvent& ev) | ||||
{ | { | ||||
if (! enabledInput) | |||||
return false; | |||||
// keep pressed | // keep pressed | ||||
if (button != -1) | 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) | DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | ||||
}; | }; | ||||
@@ -217,6 +248,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept | |||||
pData->checkable = checkable; | 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 | Point<double> ButtonEventHandler::getLastClickPosition() const noexcept | ||||
{ | { | ||||
return pData->lastClickPos; | return pData->lastClickPos; | ||||
@@ -281,6 +322,8 @@ struct KnobEventHandler::PrivateData { | |||||
float value; | float value; | ||||
float valueDef; | float valueDef; | ||||
float valueTmp; | float valueTmp; | ||||
bool enabled; | |||||
bool enabledInput; | |||||
bool usingDefault; | bool usingDefault; | ||||
bool usingLog; | bool usingLog; | ||||
Orientation orientation; | Orientation orientation; | ||||
@@ -301,6 +344,8 @@ struct KnobEventHandler::PrivateData { | |||||
value(0.5f), | value(0.5f), | ||||
valueDef(value), | valueDef(value), | ||||
valueTmp(value), | valueTmp(value), | ||||
enabled(true), | |||||
enabledInput(true), | |||||
usingDefault(false), | usingDefault(false), | ||||
usingLog(false), | usingLog(false), | ||||
orientation(Vertical), | orientation(Vertical), | ||||
@@ -320,6 +365,8 @@ struct KnobEventHandler::PrivateData { | |||||
value(other->value), | value(other->value), | ||||
valueDef(other->valueDef), | valueDef(other->valueDef), | ||||
valueTmp(value), | valueTmp(value), | ||||
enabled(other->enabled), | |||||
enabledInput(other->enabledInput), | |||||
usingDefault(other->usingDefault), | usingDefault(other->usingDefault), | ||||
usingLog(other->usingLog), | usingLog(other->usingLog), | ||||
orientation(other->orientation), | orientation(other->orientation), | ||||
@@ -338,6 +385,8 @@ struct KnobEventHandler::PrivateData { | |||||
value = other->value; | value = other->value; | ||||
valueDef = other->valueDef; | valueDef = other->valueDef; | ||||
valueTmp = value; | valueTmp = value; | ||||
enabled = other->enabled; | |||||
enabledInput = other->enabledInput; | |||||
usingDefault = other->usingDefault; | usingDefault = other->usingDefault; | ||||
usingLog = other->usingLog; | usingLog = other->usingLog; | ||||
orientation = other->orientation; | orientation = other->orientation; | ||||
@@ -363,6 +412,9 @@ struct KnobEventHandler::PrivateData { | |||||
bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) | bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) | ||||
{ | { | ||||
if (! enabledInput) | |||||
return false; | |||||
if (ev.button != 1) | if (ev.button != 1) | ||||
return false; | return false; | ||||
@@ -416,6 +468,9 @@ struct KnobEventHandler::PrivateData { | |||||
bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) | bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) | ||||
{ | { | ||||
if (! enabledInput) | |||||
return false; | |||||
if ((state & kKnobStateDragging) == 0x0) | if ((state & kKnobStateDragging) == 0x0) | ||||
return false; | return false; | ||||
@@ -501,6 +556,9 @@ struct KnobEventHandler::PrivateData { | |||||
bool scrollEvent(const Widget::ScrollEvent& ev) | bool scrollEvent(const Widget::ScrollEvent& ev) | ||||
{ | { | ||||
if (! enabledInput) | |||||
return false; | |||||
if (! widget->contains(ev.pos)) | if (! widget->contains(ev.pos)) | ||||
return false; | return false; | ||||
@@ -541,6 +599,28 @@ struct KnobEventHandler::PrivateData { | |||||
return ((usingLog ? invlogscale(value) : value) - minimum) / diff; | 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 | void setRange(const float min, const float max) noexcept | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(max > min,); | DISTRHO_SAFE_ASSERT_RETURN(max > min,); | ||||
@@ -598,6 +678,16 @@ KnobEventHandler::~KnobEventHandler() | |||||
delete pData; | 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 | bool KnobEventHandler::isInteger() const noexcept | ||||
{ | { | ||||
return d_isEqual(pData->step, 1.f); | return d_isEqual(pData->step, 1.f); | ||||
@@ -629,6 +719,16 @@ void KnobEventHandler::setDefault(const float def) noexcept | |||||
pData->usingDefault = true; | 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 | void KnobEventHandler::setRange(const float min, const float max) noexcept | ||||
{ | { | ||||
pData->setRange(min, max); | pData->setRange(min, max); | ||||
@@ -279,6 +279,14 @@ GLuint NanoImage::getTextureHandle() const | |||||
return nvglImageHandle(fHandle.context, fHandle.imageId); | 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() | void NanoImage::_updateSize() | ||||
{ | { | ||||
int w=0, h=0; | int w=0, h=0; | ||||
@@ -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" |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 | #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 | void Window::repaint() noexcept | ||||
{ | { | ||||
if (pData->view == nullptr) | if (pData->view == nullptr) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -40,13 +40,11 @@ START_NAMESPACE_DGL | |||||
#endif | #endif | ||||
#ifdef DGL_DEBUG_EVENTS | #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 | #else | ||||
# define DGL_DBG(msg) | # define DGL_DBG(msg) | ||||
# define DGL_DBGp(...) | # define DGL_DBGp(...) | ||||
# define DGL_DBGF | |||||
#endif | #endif | ||||
#define DEFAULT_WIDTH 640 | #define DEFAULT_WIDTH 640 | ||||
@@ -130,6 +128,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
webViewHandle(nullptr), | |||||
#endif | #endif | ||||
modal() | modal() | ||||
{ | { | ||||
@@ -160,6 +161,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
webViewHandle(nullptr), | |||||
#endif | #endif | ||||
modal(ppData) | modal(ppData) | ||||
{ | { | ||||
@@ -192,6 +196,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
webViewHandle(nullptr), | |||||
#endif | #endif | ||||
modal() | modal() | ||||
{ | { | ||||
@@ -227,6 +234,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
webViewHandle(nullptr), | |||||
#endif | #endif | ||||
modal() | modal() | ||||
{ | { | ||||
@@ -247,6 +257,10 @@ Window::PrivateData::~PrivateData() | |||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
if (fileBrowserHandle != nullptr) | if (fileBrowserHandle != nullptr) | ||||
fileBrowserClose(fileBrowserHandle); | fileBrowserClose(fileBrowserHandle); | ||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
if (webViewHandle != nullptr) | |||||
webViewDestroy(webViewHandle); | |||||
#endif | #endif | ||||
puglHide(view); | puglHide(view); | ||||
appData->oneWindowClosed(); | appData->oneWindowClosed(); | ||||
@@ -394,13 +408,21 @@ void Window::PrivateData::hide() | |||||
if (modal.enabled) | if (modal.enabled) | ||||
stopModal(); | stopModal(); | ||||
#ifdef DGL_USE_FILE_BROWSER | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
if (fileBrowserHandle != nullptr) | if (fileBrowserHandle != nullptr) | ||||
{ | { | ||||
fileBrowserClose(fileBrowserHandle); | fileBrowserClose(fileBrowserHandle); | ||||
fileBrowserHandle = nullptr; | fileBrowserHandle = nullptr; | ||||
} | } | ||||
#endif | |||||
#endif | |||||
#ifdef DGL_USE_WEB_VIEW | |||||
if (webViewHandle != nullptr) | |||||
{ | |||||
webViewDestroy(webViewHandle); | |||||
webViewHandle = nullptr; | |||||
} | |||||
#endif | |||||
puglHide(view); | puglHide(view); | ||||
@@ -443,6 +465,11 @@ void Window::PrivateData::idleCallback() | |||||
fileBrowserHandle = nullptr; | fileBrowserHandle = nullptr; | ||||
} | } | ||||
#endif | #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 | #ifdef DGL_USE_FILE_BROWSER | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// file handling | |||||
// file browser dialog | |||||
bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | ||||
{ | { | ||||
@@ -491,6 +518,8 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||||
if (options2.title == nullptr) | if (options2.title == nullptr) | ||||
options2.title = puglGetViewString(view, PUGL_WINDOW_TITLE); | options2.title = puglGetViewString(view, PUGL_WINDOW_TITLE); | ||||
options2.className = puglGetViewString(view, PUGL_CLASS_NAME); | |||||
fileBrowserHandle = fileBrowserCreate(isEmbed, | fileBrowserHandle = fileBrowserCreate(isEmbed, | ||||
puglGetNativeView(view), | puglGetNativeView(view), | ||||
autoScaling ? autoScaleFactor : scaleFactor, | autoScaling ? autoScaleFactor : scaleFactor, | ||||
@@ -500,12 +529,38 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||||
} | } | ||||
#endif // DGL_USE_FILE_BROWSER | #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 | // modal handling | ||||
void Window::PrivateData::startModal() | 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()); | DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show()); | ||||
// activate modal mode for this window | // activate modal mode for this window | ||||
@@ -527,7 +582,7 @@ void Window::PrivateData::startModal() | |||||
void Window::PrivateData::stopModal() | void Window::PrivateData::stopModal() | ||||
{ | { | ||||
DGL_DBG("Window modal loop stopping..."); DGL_DBGF; | |||||
DGL_DBG("Window modal loop stopping..."); | |||||
// deactivate modal mode | // deactivate modal mode | ||||
modal.enabled = false; | modal.enabled = false; | ||||
@@ -579,11 +634,11 @@ void Window::PrivateData::runAsModal(const bool blockWait) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// pugl events | // 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,); | 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) | if (autoScaling) | ||||
{ | { | ||||
@@ -596,8 +651,16 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh | |||||
autoScaleFactor = 1.0; | 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); | 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); | Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); | ||||
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | #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); | printEvent(event, "pugl event: ", true); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -962,7 +1025,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
Widget::KeyboardEvent ev; | Widget::KeyboardEvent ev; | ||||
ev.mod = event->key.state; | ev.mod = event->key.state; | ||||
ev.flags = event->key.flags; | 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.press = event->type == PUGL_KEY_PRESS; | ||||
ev.key = event->key.key; | ev.key = event->key.key; | ||||
ev.keycode = event->key.keycode; | ev.keycode = event->key.keycode; | ||||
@@ -985,7 +1048,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
Widget::CharacterInputEvent ev; | Widget::CharacterInputEvent ev; | ||||
ev.mod = event->text.state; | ev.mod = event->text.state; | ||||
ev.flags = event->text.flags; | 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.keycode = event->text.keycode; | ||||
ev.character = event->text.character; | ev.character = event->text.character; | ||||
std::strncpy(ev.string, event->text.string, sizeof(ev.string)); | 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; | Widget::MouseEvent ev; | ||||
ev.mod = event->button.state; | ev.mod = event->button.state; | ||||
ev.flags = event->button.flags; | 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.button = event->button.button + 1; | ||||
ev.press = event->type == PUGL_BUTTON_PRESS; | ev.press = event->type == PUGL_BUTTON_PRESS; | ||||
if (pData->autoScaling && 0) | if (pData->autoScaling && 0) | ||||
@@ -1031,7 +1094,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
Widget::MotionEvent ev; | Widget::MotionEvent ev; | ||||
ev.mod = event->motion.state; | ev.mod = event->motion.state; | ||||
ev.flags = event->motion.flags; | 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) | if (pData->autoScaling && 0) | ||||
{ | { | ||||
const double scaleFactor = pData->autoScaleFactor; | const double scaleFactor = pData->autoScaleFactor; | ||||
@@ -1052,7 +1115,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
Widget::ScrollEvent ev; | Widget::ScrollEvent ev; | ||||
ev.mod = event->scroll.state; | ev.mod = event->scroll.state; | ||||
ev.flags = event->scroll.flags; | 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) | if (pData->autoScaling && 0) | ||||
{ | { | ||||
const double scaleFactor = pData->autoScaleFactor; | 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 FFMT "%6.1f" | ||||
#define PFMT FFMT " " FFMT | #define PFMT FFMT " " FFMT | ||||
#define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) | |||||
#define PRINT(fmt, ...) d_stdout(fmt, __VA_ARGS__), 1 | |||||
switch (event->type) { | switch (event->type) { | ||||
case PUGL_NOTHING: | case PUGL_NOTHING: | ||||
@@ -1188,25 +1251,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver | |||||
if (verbose) { | if (verbose) { | ||||
switch (event->type) { | 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: | case PUGL_CONFIGURE: | ||||
return PRINT("%sConfigure " PFMT " " PFMT "\n", | |||||
return PRINT("%sConfigure %d %d %d %d\n", | |||||
prefix, | prefix, | ||||
event->configure.x, | event->configure.x, | ||||
event->configure.y, | event->configure.y, | ||||
event->configure.width, | event->configure.width, | ||||
event->configure.height); | event->configure.height); | ||||
case PUGL_UPDATE: | |||||
return 0; // fprintf(stderr, "%sUpdate\n", prefix); | |||||
case PUGL_EXPOSE: | case PUGL_EXPOSE: | ||||
return PRINT("%sExpose " PFMT " " PFMT "\n", | |||||
return PRINT("%sExpose %d %d %d %d\n", | |||||
prefix, | prefix, | ||||
event->expose.x, | event->expose.x, | ||||
event->expose.y, | event->expose.y, | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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; | DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle; | ||||
#endif | #endif | ||||
#ifdef DGL_USE_WEB_VIEW | |||||
/** Handle for web view operations. */ | |||||
DGL_NAMESPACE::WebViewHandle webViewHandle; | |||||
DGL_NAMESPACE::Point<int> webViewOffset; | |||||
#endif | |||||
/** Modal window setup. */ | /** Modal window setup. */ | ||||
struct Modal { | struct Modal { | ||||
PrivateData* parent; // parent of this window (so we can become modal) | PrivateData* parent; // parent of this window (so we can become modal) | ||||
@@ -169,10 +175,15 @@ struct Window::PrivateData : IdleCallback { | |||||
bool removeIdleCallback(IdleCallback* callback); | bool removeIdleCallback(IdleCallback* callback); | ||||
#ifdef DGL_USE_FILE_BROWSER | #ifdef DGL_USE_FILE_BROWSER | ||||
// file handling | |||||
// file browser dialog | |||||
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); | bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); | ||||
#endif | #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); | static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | ||||
// modal handling | // modal handling | ||||
@@ -181,7 +192,7 @@ struct Window::PrivateData : IdleCallback { | |||||
void runAsModal(bool blockWait); | void runAsModal(bool blockWait); | ||||
// pugl events | // pugl events | ||||
void onPuglConfigure(double width, double height); | |||||
void onPuglConfigure(uint width, uint height); | |||||
void onPuglExpose(); | void onPuglExpose(); | ||||
void onPuglClose(); | void onPuglClose(); | ||||
void onPuglFocus(bool focus, CrossingMode mode); | void onPuglFocus(bool focus, CrossingMode mode); | ||||
@@ -188,7 +188,7 @@ getCurrentViewStyleFlags(PuglView* const view) | |||||
} | } | ||||
static PuglStatus | static PuglStatus | ||||
dispatchCurrentChildViewConfiguration(PuglView* const view) | |||||
dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize) | |||||
{ | { | ||||
const NSRect framePt = [view->impl->wrapperView frame]; | const NSRect framePt = [view->impl->wrapperView frame]; | ||||
const NSRect framePx = nsRectFromPoints(view, framePt); | const NSRect framePx = nsRectFromPoints(view, framePt); | ||||
@@ -197,6 +197,11 @@ dispatchCurrentChildViewConfiguration(PuglView* const view) | |||||
return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
} | } | ||||
if (drawViewResize) { | |||||
const NSSize sizePt = [view->impl->drawView convertSizeFromBacking:framePx.size]; | |||||
[view->impl->drawView setFrameSize:sizePt]; | |||||
} | |||||
const PuglConfigureEvent ev = { | const PuglConfigureEvent ev = { | ||||
PUGL_CONFIGURE, | PUGL_CONFIGURE, | ||||
0, | 0, | ||||
@@ -317,7 +322,7 @@ dispatchCurrentChildViewConfiguration(PuglView* const view) | |||||
if (puglview->impl->window) { | if (puglview->impl->window) { | ||||
[puglview->impl->window dispatchCurrentConfiguration]; | [puglview->impl->window dispatchCurrentConfiguration]; | ||||
} else { | } else { | ||||
dispatchCurrentChildViewConfiguration(puglview); | |||||
dispatchCurrentChildViewConfiguration(puglview, true); | |||||
} | } | ||||
reshaped = false; | reshaped = false; | ||||
} | } | ||||
@@ -1767,7 +1772,7 @@ puglSetFrame(PuglView* view, const PuglRect frame) | |||||
[impl->wrapperView setFrame:framePt]; | [impl->wrapperView setFrame:framePt]; | ||||
[impl->drawView setFrame:sizePt]; | [impl->drawView setFrame:sizePt]; | ||||
return dispatchCurrentChildViewConfiguration(view); | |||||
return dispatchCurrentChildViewConfiguration(view, false); | |||||
} | } | ||||
PuglStatus | PuglStatus | ||||
@@ -1806,7 +1811,7 @@ puglSetPosition(PuglView* const view, const int x, const int y) | |||||
[impl->drawView setFrameOrigin:drawPt.origin]; | [impl->drawView setFrameOrigin:drawPt.origin]; | ||||
// Dispatch new configuration | // Dispatch new configuration | ||||
return dispatchCurrentChildViewConfiguration(view); | |||||
return dispatchCurrentChildViewConfiguration(view, false); | |||||
} | } | ||||
PuglStatus | PuglStatus | ||||
@@ -1843,7 +1848,7 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height) | |||||
[impl->drawView setFrameSize:drawPt.size]; | [impl->drawView setFrameSize:drawPt.size]; | ||||
// Dispatch new configuration | // Dispatch new configuration | ||||
return dispatchCurrentChildViewConfiguration(view); | |||||
return dispatchCurrentChildViewConfiguration(view, false); | |||||
} | } | ||||
PuglStatus | PuglStatus | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -110,16 +110,26 @@ | |||||
# endif | # endif | ||||
#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_DGL_NAMESPACE | ||||
# define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE | # define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE | ||||
# define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
# include "../../distrho/extra/FileBrowserDialogImpl.hpp" | # include "../../distrho/extra/FileBrowserDialogImpl.hpp" | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
# include "../../distrho/extra/FileBrowserDialogImpl.cpp" | # include "../../distrho/extra/FileBrowserDialogImpl.cpp" | ||||
#endif | #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) | #if defined(DGL_USING_X11) && defined(DGL_X11_WINDOW_ICON_NAME) | ||||
extern const ulong* DGL_X11_WINDOW_ICON_NAME; | extern const ulong* DGL_X11_WINDOW_ICON_NAME; | ||||
#endif | #endif | ||||
@@ -363,7 +373,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) | |||||
#ifdef DGL_USING_X11 | #ifdef DGL_USING_X11 | ||||
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118 | // 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; | view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0; | ||||
} | } | ||||
@@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20; | |||||
/** | /** | ||||
Parameter designation.@n | 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 | Each designation is unique, there must be only one parameter that uses it.@n | ||||
The use of designated parameters is completely optional. | The use of designated parameters is completely optional. | ||||
@@ -214,13 +214,20 @@ enum ParameterDesignation { | |||||
/** | /** | ||||
Null or unset designation. | Null or unset designation. | ||||
*/ | */ | ||||
kParameterDesignationNull = 0, | |||||
kParameterDesignationNull, | |||||
/** | /** | ||||
Bypass designation.@n | Bypass designation.@n | ||||
When on (> 0.5f), it means the plugin must run in a bypassed state. | 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"; | 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"; | static constexpr const char bypass_lv2[] = "lv2_enabled"; | ||||
}; | }; | ||||
@@ -728,6 +740,18 @@ struct Parameter { | |||||
ranges.min = 0.0f; | ranges.min = 0.0f; | ||||
ranges.max = 1.0f; | ranges.max = 1.0f; | ||||
break; | 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; | |||||
} | } | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -37,9 +37,29 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
const char* getBinaryFilename(); | 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 | 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. | This string is purely informational and must not be used to tweak plugin behaviour. | ||||
@note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT. | @note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT. | ||||
@@ -185,7 +185,8 @@ public: | |||||
#if DISTRHO_UI_FILE_BROWSER | #if DISTRHO_UI_FILE_BROWSER | ||||
/** | /** | ||||
Open a file browser dialog with this window as transient parent.@n | 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 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. | If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename. | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -66,7 +66,7 @@ | |||||
# endif | # endif | ||||
#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[]) | int main(int argc, char* argv[]) | ||||
{ | { | ||||
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | ||||
@@ -22,6 +22,7 @@ | |||||
#if DISTRHO_UI_WEB_VIEW | #if DISTRHO_UI_WEB_VIEW | ||||
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | # define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | ||||
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE | |||||
# include "extra/WebView.hpp" | # include "extra/WebView.hpp" | ||||
# include "extra/WebViewWin32.hpp" | # include "extra/WebViewWin32.hpp" | ||||
#endif | #endif |
@@ -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 |
@@ -22,6 +22,10 @@ | |||||
#include <algorithm> | #include <algorithm> | ||||
#if __cplusplus >= 201703L | |||||
# include <string_view> | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -49,10 +53,7 @@ public: | |||||
fBufferLen(0), | fBufferLen(0), | ||||
fBufferAlloc(false) | fBufferAlloc(false) | ||||
{ | { | ||||
char ch[2]; | |||||
ch[0] = c; | |||||
ch[1] = '\0'; | |||||
const char ch[2] = { c, '\0' }; | |||||
_dup(ch); | _dup(ch); | ||||
} | } | ||||
@@ -87,6 +88,19 @@ public: | |||||
_dup(strBuf); | _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. | * Integer. | ||||
*/ | */ | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 MACRO_NAME(a, b, c) MACRO_NAME2(a, b, c) | ||||
#define WEB_VIEW_DELEGATE_CLASS_NAME \ | #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> | @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate> | ||||
@end | @end | ||||
@implementation WEB_VIEW_DELEGATE_CLASS_NAME { | @implementation WEB_VIEW_DELEGATE_CLASS_NAME { | ||||
@public | @public | ||||
DISTRHO_NAMESPACE::WebViewMessageCallback callback; | |||||
WEB_VIEW_NAMESPACE::WebViewMessageCallback callback; | |||||
void* callbackPtr; | void* callbackPtr; | ||||
bool loaded; | bool loaded; | ||||
} | } | ||||
@@ -242,6 +242,11 @@ START_NAMESPACE_DISTRHO | |||||
#if WEB_VIEW_USING_X11_IPC | #if WEB_VIEW_USING_X11_IPC | ||||
#ifdef WEB_VIEW_DGL_NAMESPACE | |||||
using DISTRHO_NAMESPACE::ChildProcess; | |||||
using DISTRHO_NAMESPACE::RingBufferControl; | |||||
#endif | |||||
#ifdef __linux__ | #ifdef __linux__ | ||||
typedef int32_t ipc_sem_t; | typedef int32_t ipc_sem_t; | ||||
#else | #else | ||||
@@ -773,8 +778,10 @@ void webViewIdle(const WebViewHandle handle) | |||||
d_stderr("server ringbuffer data race, abort!"); | d_stderr("server ringbuffer data race, abort!"); | ||||
handle->rbctrl2.flush(); | handle->rbctrl2.flush(); | ||||
return; | |||||
break; | |||||
} | } | ||||
std::free(buffer); | |||||
#else | #else | ||||
// unused | // unused | ||||
(void)handle; | (void)handle; | ||||
@@ -941,7 +948,7 @@ struct QSize { | |||||
S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \ | S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \ | ||||
DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false); | 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); | WebViewRingBuffer* const shmptr = static_cast<WebViewRingBuffer*>(ptr); | ||||
@@ -989,6 +996,7 @@ static void web_wake_idle(void* const ptr) | |||||
} | } | ||||
free(buffer); | free(buffer); | ||||
return 0; | |||||
} | } | ||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -1039,7 +1047,9 @@ static bool gtk3(Display* const display, | |||||
{ | { | ||||
void* lib; | void* lib; | ||||
if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | 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()); | d_stdout("WebView gtk3 platform not available: %s", dlerror()); | ||||
return false; | return false; | ||||
@@ -1135,10 +1145,8 @@ static bool gtk3(Display* const display, | |||||
GtkWidget* const window = gtk_plug_new(winId); | GtkWidget* const window = gtk_plug_new(winId); | ||||
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false); | 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(); | WebKitSettings* const settings = webkit_settings_new(); | ||||
DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false); | ||||
@@ -1774,7 +1782,7 @@ static bool qtwebengine(const int qtVersion, | |||||
QWebEnginePage_setWebChannel(&page, &channel, 0); | QWebEnginePage_setWebChannel(&page, &channel, 0); | ||||
QWebEngineView_move(&webview, QPoint(x, y)); | 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); | QWebEngineView_winId(&webview); | ||||
QWindow_setParent(QWebEngineView_windowHandle(&webview), QWindow_fromWinId(winId)); | QWindow_setParent(QWebEngineView_windowHandle(&webview), QWindow_fromWinId(winId)); | ||||
@@ -2061,3 +2069,4 @@ END_NAMESPACE_DISTRHO | |||||
#undef WEB_VIEW_DISTRHO_NAMESPACE | #undef WEB_VIEW_DISTRHO_NAMESPACE | ||||
#undef WEB_VIEW_DGL_NAMESPACE | #undef WEB_VIEW_DGL_NAMESPACE | ||||
#undef WEB_VIEW_NAMESPACE |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,7 +18,7 @@ | |||||
# error bad include | # error bad include | ||||
#endif | #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 | # error To use WebViews in DPF plugins please set DISTRHO_UI_WEB_VIEW to 1 | ||||
#endif | #endif | ||||
@@ -125,3 +125,12 @@ void webViewReload(WebViewHandle webview); | |||||
void webViewResize(WebViewHandle webview, uint width, uint height, double scaleFactor); | 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); } | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -26,13 +26,26 @@ START_NAMESPACE_DISTRHO | |||||
class WebView; | 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_destroy(WebView*); | ||||
void* webview_choc_handle(WebView*); | void* webview_choc_handle(WebView*); | ||||
void webview_choc_eval(WebView*, const char* js); | void webview_choc_eval(WebView*, const char* js); | ||||
void webview_choc_navigate(WebView*, const char* url); | void webview_choc_navigate(WebView*, const char* url); | ||||
#ifdef WEB_VIEW_DGL_NAMESPACE | |||||
END_NAMESPACE_DGL | |||||
#else | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -41,9 +54,13 @@ END_NAMESPACE_DISTRHO | |||||
# define WC_ERR_INVALID_CHARS 0 | # define WC_ERR_INVALID_CHARS 0 | ||||
# include "choc/choc_WebView.h" | # include "choc/choc_WebView.h" | ||||
#ifdef WEB_VIEW_DGL_NAMESPACE | |||||
START_NAMESPACE_DGL | |||||
#else | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
#endif | |||||
WebView* webview_choc_create(const WebViewOptions& opts) | |||||
WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts) | |||||
{ | { | ||||
WebView::Options wopts; | WebView::Options wopts; | ||||
wopts.acceptsFirstMouseClick = true; | wopts.acceptsFirstMouseClick = true; | ||||
@@ -52,7 +69,7 @@ WebView* webview_choc_create(const WebViewOptions& opts) | |||||
std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts); | std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts); | ||||
DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr); | 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);}"); | 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); | webview->navigate(url); | ||||
} | } | ||||
#ifdef WEB_VIEW_DGL_NAMESPACE | |||||
END_NAMESPACE_DGL | |||||
#else | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
#endif | |||||
#endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | #endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 { | struct PropertyListener { | ||||
AudioUnitPropertyID prop; | |||||
AudioUnitPropertyID prop; | |||||
AudioUnitPropertyListenerProc proc; | AudioUnitPropertyListenerProc proc; | ||||
void* userData; | void* userData; | ||||
}; | }; | ||||
@@ -348,7 +348,8 @@ public: | |||||
fUsingRenderListeners(false), | fUsingRenderListeners(false), | ||||
fParameterCount(fPlugin.getParameterCount()), | fParameterCount(fPlugin.getParameterCount()), | ||||
fLastParameterValues(nullptr), | fLastParameterValues(nullptr), | ||||
fBypassParameterIndex(UINT32_MAX) | |||||
fBypassParameterIndex(UINT32_MAX), | |||||
fResetParameterIndex(UINT32_MAX) | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
, fMidiEventCount(0) | , fMidiEventCount(0) | ||||
#endif | #endif | ||||
@@ -365,7 +366,7 @@ public: | |||||
, fStateCount(fPlugin.getStateCount()) | , fStateCount(fPlugin.getStateCount()) | ||||
#endif | #endif | ||||
{ | { | ||||
if (fParameterCount != 0) | |||||
if (fParameterCount != 0) | |||||
{ | { | ||||
fLastParameterValues = new float[fParameterCount]; | fLastParameterValues = new float[fParameterCount]; | ||||
std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); | std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); | ||||
@@ -374,8 +375,17 @@ public: | |||||
{ | { | ||||
fLastParameterValues[i] = fPlugin.getParameterValue(i); | fLastParameterValues[i] = fPlugin.getParameterValue(i); | ||||
if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | |||||
switch (fPlugin.getParameterDesignation(i)) | |||||
{ | |||||
case kParameterDesignationNull: | |||||
break; | |||||
case kParameterDesignationBypass: | |||||
fBypassParameterIndex = i; | fBypassParameterIndex = i; | ||||
break; | |||||
case kParameterDesignationReset: | |||||
fResetParameterIndex = i; | |||||
break; | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -923,13 +933,13 @@ public: | |||||
case kAudioUnitProperty_FastDispatch: | case kAudioUnitProperty_FastDispatch: | ||||
switch (inElement) | switch (inElement) | ||||
{ | { | ||||
case kAudioUnitGetParameterSelect: | |||||
case kAudioUnitGetParameterSelect: | |||||
*static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter; | *static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter; | ||||
return noErr; | return noErr; | ||||
case kAudioUnitSetParameterSelect: | |||||
case kAudioUnitSetParameterSelect: | |||||
*static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter; | *static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter; | ||||
return noErr; | return noErr; | ||||
case kAudioUnitRenderSelect: | |||||
case kAudioUnitRenderSelect: | |||||
*static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender; | *static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender; | ||||
return noErr; | return noErr; | ||||
} | } | ||||
@@ -1143,6 +1153,8 @@ public: | |||||
const CFStringRef keyRef = CFStringCreateWithCString(nullptr, | const CFStringRef keyRef = CFStringCreateWithCString(nullptr, | ||||
fPlugin.getStateKey(i), | fPlugin.getStateKey(i), | ||||
kCFStringEncodingASCII); | kCFStringEncodingASCII); | ||||
DISTRHO_SAFE_ASSERT_CONTINUE(keyRef != nullptr); | |||||
CFArrayAppendValue(keysRef, keyRef); | CFArrayAppendValue(keysRef, keyRef); | ||||
CFRelease(keyRef); | CFRelease(keyRef); | ||||
} | } | ||||
@@ -1458,7 +1470,7 @@ public: | |||||
const float value = bypass ? 1.f : 0.f; | const float value = bypass ? 1.f : 0.f; | ||||
fLastParameterValues[fBypassParameterIndex] = value; | fLastParameterValues[fBypassParameterIndex] = value; | ||||
fPlugin.setParameterValue(fBypassParameterIndex, value); | fPlugin.setParameterValue(fBypassParameterIndex, value); | ||||
notifyPropertyListeners(inProp, inScope, inElement); | |||||
notifyPropertyListeners(inProp, inScope, inElement); | |||||
} | } | ||||
} | } | ||||
return noErr; | return noErr; | ||||
@@ -1480,12 +1492,12 @@ public: | |||||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
{ | { | ||||
const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo))); | 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) | if (sizeof(HostCallbackInfo) > usableDataSize) | ||||
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||||
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||||
if (changed) | if (changed) | ||||
notifyPropertyListeners(inProp, inScope, inElement); | notifyPropertyListeners(inProp, inScope, inElement); | ||||
@@ -1612,7 +1624,7 @@ public: | |||||
AUEventListenerNotify(NULL, NULL, &event); | AUEventListenerNotify(NULL, NULL, &event); | ||||
if (fBypassParameterIndex == inElement) | if (fBypassParameterIndex == inElement) | ||||
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||||
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||||
} | } | ||||
return noErr; | return noErr; | ||||
@@ -1637,28 +1649,44 @@ public: | |||||
case 'DPFs': | case 'DPFs': | ||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | 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 | #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(), | DISTRHO_SAFE_ASSERT_RETURN(valueRef != nullptr && CFGetTypeID(valueRef) == CFStringGetTypeID(), | ||||
kAudioUnitErr_InvalidPropertyValue); | 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); | 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 | // 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); | std::free(value); | ||||
} | } | ||||
return noErr; | 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(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope); | ||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement); | 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.deactivate(); | ||||
fPlugin.activate(); | fPlugin.activate(); | ||||
@@ -2180,6 +2213,7 @@ private: | |||||
const uint32_t fParameterCount; | const uint32_t fParameterCount; | ||||
float* fLastParameterValues; | float* fLastParameterValues; | ||||
uint32_t fBypassParameterIndex; | uint32_t fBypassParameterIndex; | ||||
uint32_t fResetParameterIndex; | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
uint32_t fMidiEventCount; | uint32_t fMidiEventCount; | ||||
@@ -2220,7 +2254,7 @@ private: | |||||
const PropertyListener& pl(*it); | const PropertyListener& pl(*it); | ||||
if (pl.prop == prop) | 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 keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII); | ||||
CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8); | 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); | CFArrayAppendValue(statesRef, dictRef); | ||||
CFRelease(dictRef); | CFRelease(dictRef); | ||||
@@ -2845,7 +2879,7 @@ private: | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
struct AudioComponentPlugInInstance { | struct AudioComponentPlugInInstance { | ||||
AudioComponentPlugInInterface acpi; | |||||
AudioComponentPlugInInterface acpi; | |||||
PluginAU* plugin; | PluginAU* plugin; | ||||
AudioComponentPlugInInstance() noexcept | AudioComponentPlugInInstance() noexcept | ||||
@@ -2854,9 +2888,9 @@ struct AudioComponentPlugInInstance { | |||||
{ | { | ||||
std::memset(&acpi, 0, sizeof(acpi)); | std::memset(&acpi, 0, sizeof(acpi)); | ||||
acpi.Open = Open; | acpi.Open = Open; | ||||
acpi.Close = Close; | |||||
acpi.Lookup = Lookup; | |||||
acpi.reserved = nullptr; | |||||
acpi.Close = Close; | |||||
acpi.Lookup = Lookup; | |||||
acpi.reserved = nullptr; | |||||
} | } | ||||
~AudioComponentPlugInInstance() | ~AudioComponentPlugInInstance() | ||||
@@ -2864,7 +2898,7 @@ struct AudioComponentPlugInInstance { | |||||
delete plugin; | 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); | d_debug("AudioComponentPlugInInstance::Open(%p)", self); | ||||
@@ -2872,7 +2906,7 @@ struct AudioComponentPlugInInstance { | |||||
return noErr; | return noErr; | ||||
} | } | ||||
static OSStatus Close(void* const self) | |||||
static OSStatus Close(void* const self) | |||||
{ | { | ||||
d_debug("AudioComponentPlugInInstance::Close(%p)", self); | d_debug("AudioComponentPlugInInstance::Close(%p)", self); | ||||
@@ -2964,15 +2998,15 @@ struct AudioComponentPlugInInstance { | |||||
d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", | d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", | ||||
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | 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); | 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; | return res; | ||||
} | } | ||||
@@ -3016,24 +3050,24 @@ struct AudioComponentPlugInInstance { | |||||
if (res != noErr) | if (res != noErr) | ||||
return res; | return res; | ||||
void* outBuffer; | |||||
void* outBuffer; | |||||
uint8_t* tmpBuffer; | uint8_t* tmpBuffer; | ||||
if (inDataSize < outDataSize) | if (inDataSize < outDataSize) | ||||
{ | |||||
tmpBuffer = new uint8_t[outDataSize]; | |||||
outBuffer = tmpBuffer; | |||||
} | |||||
{ | |||||
tmpBuffer = new uint8_t[outDataSize]; | |||||
outBuffer = tmpBuffer; | |||||
} | |||||
else | else | ||||
{ | { | ||||
tmpBuffer = nullptr; | |||||
outBuffer = outData; | |||||
} | |||||
tmpBuffer = nullptr; | |||||
outBuffer = outData; | |||||
} | |||||
res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); | res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); | ||||
if (res != noErr) | |||||
if (res != noErr) | |||||
{ | { | ||||
*ioDataSize = 0; | |||||
*ioDataSize = 0; | |||||
return res; | return res; | ||||
} | } | ||||
@@ -751,6 +751,7 @@ public: | |||||
updateStateValueCallback), | updateStateValueCallback), | ||||
fHost(host), | fHost(host), | ||||
fOutputEvents(nullptr), | fOutputEvents(nullptr), | ||||
fResetParameterIndex(UINT32_MAX), | |||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | ||||
fUsingCV(false), | fUsingCV(false), | ||||
#endif | #endif | ||||
@@ -763,7 +764,19 @@ public: | |||||
#endif | #endif | ||||
fHostExtensions(host) | 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 | #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); | fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); | ||||
@@ -823,7 +836,18 @@ public: | |||||
void reset() | 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) | bool process(const clap_process_t* const process) | ||||
@@ -1119,14 +1143,19 @@ public: | |||||
{ | { | ||||
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | 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; | info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE; | ||||
std::strcpy(info->name, "Bypass"); | std::strcpy(info->name, "Bypass"); | ||||
std::strcpy(info->module, "dpf_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 hints = fPlugin.getParameterHints(index); | ||||
const uint32_t groupId = fPlugin.getParameterGroupId(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); | d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn); | ||||
break; | |||||
} | } | ||||
info->id = index; | info->id = index; | ||||
@@ -1791,6 +1821,7 @@ private: | |||||
const clap_host_t* const fHost; | const clap_host_t* const fHost; | ||||
const clap_output_events_t* fOutputEvents; | const clap_output_events_t* fOutputEvents; | ||||
uint32_t fResetParameterIndex; | |||||
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 | #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | ||||
const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; | const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; | ||||
#endif | #endif | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 | # error DISTRHO_UI_IS_STANDALONE must not be defined | ||||
#endif | #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 | #endif | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -338,6 +338,64 @@ public: | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != 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__) | #if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__) | ||||
/* Run-time testing build. | /* Run-time testing build. | ||||
* Verify that virtual functions are overriden if parameters, programs or states are in use. | * 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 DISTRHO_PLUGIN_WANT_STATE | ||||
if (fData->stateCount != 0) | 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 | # endif | ||||
@@ -412,64 +483,6 @@ public: | |||||
# endif | # endif | ||||
#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->callbacksPtr = callbacksPtr; | ||||
fData->writeMidiCallbackFunc = writeMidiCall; | fData->writeMidiCallbackFunc = writeMidiCall; | ||||
fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall; | fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU Lesser General Public | * 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; | static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; | ||||
#endif | #endif | ||||
#ifdef DPF_USING_LD_LINUX_WEBVIEW | |||||
int dpf_webview_start(int argc, char* argv[]); | |||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
static volatile bool gCloseSignalReceived = false; | static volatile bool gCloseSignalReceived = false; | ||||
@@ -1003,9 +999,9 @@ int main(int argc, char* argv[]) | |||||
} | } | ||||
#endif | #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) | 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 | #endif | ||||
if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | ||||
@@ -758,6 +758,16 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; | pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; | ||||
pluginString += " lv2:designation lv2:enabled ;\n"; | pluginString += " lv2:designation lv2:enabled ;\n"; | ||||
break; | 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; | |||||
} | } | ||||
} | } | ||||
@@ -1747,6 +1747,12 @@ public: | |||||
case kParameterDesignationBypass: | case kParameterDesignationBypass: | ||||
flags |= V3_PARAM_IS_BYPASS; | flags |= V3_PARAM_IS_BYPASS; | ||||
break; | 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) | if (hints & kParameterIsOutput) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -125,6 +125,7 @@ public: | |||||
CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | ||||
// setup property listeners | |||||
AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); | AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); | ||||
AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this); | AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this); | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
@@ -322,15 +323,22 @@ private: | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
void setState(const char* const key, const char* const value) | 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) | static void setStateCallback(void* const ptr, const char* const key, const char* const value) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * 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 | // unsupported in DSSI | ||||
static constexpr const fileRequestFunc fileRequestCallback = nullptr; | 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 | 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) | 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 | #endif | ||||
// dummy test mode | // dummy test mode | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -61,6 +61,12 @@ | |||||
START_NAMESPACE_DISTRHO | 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 | // Plugin Application, will set class name based on plugin details | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * 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 | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -23,13 +23,19 @@ | |||||
#include "../DistrhoStandaloneUtils.hpp" | #include "../DistrhoStandaloneUtils.hpp" | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
# include <direct.h> | |||||
# include <shlobj.h> | |||||
# include <windows.h> | # include <windows.h> | ||||
#else | #else | ||||
# ifndef STATIC_BUILD | # ifndef STATIC_BUILD | ||||
# include <dlfcn.h> | # include <dlfcn.h> | ||||
# endif | # endif | ||||
# include <fcntl.h> | |||||
# include <limits.h> | # include <limits.h> | ||||
# include <pwd.h> | |||||
# include <stdlib.h> | # include <stdlib.h> | ||||
# include <sys/stat.h> | |||||
# include <unistd.h> | |||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
@@ -76,6 +82,177 @@ const char* getBinaryFilename() | |||||
return filename; | 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 | const char* getPluginFormatName() noexcept | ||||
{ | { | ||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) | #if defined(DISTRHO_PLUGIN_TARGET_AU) | ||||
@@ -166,11 +343,6 @@ bool requestBufferSizeChange(uint) { return false; } | |||||
bool requestMIDI() { return false; } | bool requestMIDI() { return false; } | ||||
#endif | #endif | ||||
/* define webview start */ | |||||
#ifdef DPF_USING_LD_LINUX_WEBVIEW | |||||
int dpf_webview_start(int argc, char* argv[]); | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
LV2 KXStudio Properties Extension | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" | ||||
#define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" | #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__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" | ||||
#define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | ||||
@@ -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 |