@@ -28,9 +28,9 @@ endif | |||||
dgl: | dgl: | ||||
ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ifeq ($(HAVE_CAIRO_OR_OPENGL),true) | ||||
$(MAKE) FILE_BROWSER_DISABLED=true -C dpf/dgl | |||||
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl | |||||
ifeq ($(HAVE_OPENGL),true) | ifeq ($(HAVE_OPENGL),true) | ||||
$(MAKE) FILE_BROWSER_DISABLED=true -C dpf/dgl opengl3 | |||||
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl opengl3 | |||||
endif | endif | ||||
endif | endif | ||||
@@ -1,5 +1,6 @@ | |||||
# 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> | |||||
# | # | ||||
# SPDX-License-Identifier: ISC | # SPDX-License-Identifier: ISC | ||||
@@ -33,10 +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(FALSE) | |||||
dpf__add_dgl_cairo(TRUE, TRUE) | |||||
endif() | endif() | ||||
endif() | endif() | ||||
dpf__add_dgl_opengl(FALSE) | |||||
dpf__add_dgl_external(TRUE) | |||||
dpf__add_dgl_opengl(TRUE, TRUE) | |||||
endif() | endif() | ||||
if(DPF_EXAMPLES) | if(DPF_EXAMPLES) | ||||
@@ -47,9 +49,6 @@ if(DPF_EXAMPLES) | |||||
add_subdirectory("examples/CairoUI") | add_subdirectory("examples/CairoUI") | ||||
endif() | endif() | ||||
endif() | endif() | ||||
if((NOT WIN32) AND (NOT APPLE)) | |||||
add_subdirectory("examples/ExternalUI") | |||||
endif() | |||||
add_subdirectory("examples/EmbedExternalUI") | add_subdirectory("examples/EmbedExternalUI") | ||||
add_subdirectory("examples/FileHandling") | add_subdirectory("examples/FileHandling") | ||||
add_subdirectory("examples/Info") | add_subdirectory("examples/Info") | ||||
@@ -58,4 +57,5 @@ if(DPF_EXAMPLES) | |||||
add_subdirectory("examples/MidiThrough") | add_subdirectory("examples/MidiThrough") | ||||
add_subdirectory("examples/Parameters") | add_subdirectory("examples/Parameters") | ||||
add_subdirectory("examples/States") | add_subdirectory("examples/States") | ||||
add_subdirectory("examples/WebMeters") | |||||
endif() | endif() |
@@ -4,29 +4,29 @@ This file describes the available features for each plugin format. | |||||
The limitations could be due to the plugin format itself or within DPF. | The limitations could be due to the plugin format itself or within DPF. | ||||
If the limitation is within DPF, a link is provided to a description below on the reason for it. | If the limitation is within DPF, a link is provided to a description below on the reason for it. | ||||
| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | CLAP | Feature | | |||||
|---------------------|---------------------------------------|--------------------|---------------------|-------------------------------|----------------------------|----------------------------|-------------------------------|---------------------| | |||||
| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | Yes | Yes | Audio port groups | | |||||
| Audio port as CV | Yes | No | No | Yes | No | [Yes*](#vst3-cv) | [No*](#work-in-progress) | Audio port as CV | | |||||
| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Audio sidechan | | |||||
| Bypass control | No | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Bypass control | | |||||
| MIDI input | Yes | No | Yes | Yes | Yes | Yes | Yes | MIDI input | | |||||
| MIDI output | Yes | No | No | Yes | Yes | Yes | Yes | MIDI output | | |||||
| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Yes | Parameter changes | | |||||
| Parameter groups | No | No | No | Yes | Yes | [No*](#work-in-progress) | Yes | Parameter groups | | |||||
| Parameter outputs | No | No | No | Yes | No | Yes | Yes | Parameter outputs | | |||||
| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers | | |||||
| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-rdf) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | No | Programs | | |||||
| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | Yes | States | | |||||
| Full/internal state | Yes | No | No | Yes | Yes | Yes | Yes | Full/internal state | | |||||
| Time position | Yes | No | No | Yes | Yes | Yes | Yes | Time position | | |||||
| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | Yes | UI | | |||||
| UI bg/fg colors | No | No | No | Yes | No | No? | No | UI bg/fg colors | | |||||
| UI direct access | Yes | No | No | Yes | Yes | Yes | Yes | UI direct access | | |||||
| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-deprecated) | [No*](#work-in-progress) | [No*](#work-in-progress) | UI host-filebrowser | | |||||
| UI host-resize | Yes | No | Yes | Yes | No | Yes | Yes | UI host-resize | | |||||
| UI remote control | No | No | Yes | Yes | No | Yes | No | UI remote control | | |||||
| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | Yes | UI send midi note | | |||||
| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | CLAP | AU | Feature | | |||||
|---------------------|---------------------------------------|--------------------|---------------------|-------------------------------|----------------------------|----------------------------|----------------------------|----------------------------|---------------------| | |||||
| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | Yes | Yes | [No*](#work-in-progress) | Audio port groups | | |||||
| Audio port as CV | Yes | No | No | Yes | No | [Yes*](#vst3-cv) | [No*](#work-in-progress) | No | Audio port as CV | | |||||
| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | [No*](#work-in-progress) | Audio sidechan | | |||||
| Bypass control | No | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Yes | Bypass control | | |||||
| MIDI input | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes | MIDI input | | |||||
| MIDI output | Yes | No | No | Yes | Yes | Yes | Yes | Yes | MIDI output | | |||||
| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Yes | Yes | Parameter changes | | |||||
| Parameter groups | No | No | No | Yes | Yes | [No*](#work-in-progress) | Yes | [No*](#work-in-progress) | Parameter groups | | |||||
| Parameter outputs | No | No | No | Yes | No | Yes | Yes | Yes | Parameter outputs | | |||||
| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers | | |||||
| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-rdf) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | No | Yes | Programs | | |||||
| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | Yes | Yes | States | | |||||
| Full/internal state | Yes | No | No | Yes | Yes | Yes | Yes | Yes | Full/internal state | | |||||
| Time position | Yes | No | No | Yes | Yes | Yes | Yes | Yes | Time position | | |||||
| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | Yes | Embed only | UI | | |||||
| UI bg/fg colors | No | No | No | Yes | No | No? | No | No | UI bg/fg colors | | |||||
| UI direct access | Yes | No | No | Yes | Yes | Yes | Yes | Yes | UI direct access | | |||||
| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-deprecated) | [No*](#work-in-progress) | [No*](#work-in-progress) | No | UI host-filebrowser | | |||||
| UI host-resize | Yes | No | Yes | Yes | No | Yes | Yes | No | UI host-resize | | |||||
| UI remote control | No | No | Yes | Yes | No | Yes | No | Yes | UI remote control | | |||||
| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes | UI send midi note | | |||||
For things that could be unclear: | For things that could be unclear: | ||||
@@ -1,12 +1,13 @@ | |||||
Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
or without fee is hereby granted, provided that the above copyright notice and this | |||||
permission notice appear in all copies. | |||||
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. | |||||
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. |
@@ -7,15 +7,16 @@ This file describes the licensing that applies to each individual plugin format | |||||
Regardless of target format, DPF itself needs to be mentioned in attribution. | Regardless of target format, DPF itself needs to be mentioned in attribution. | ||||
See the [LICENSE](LICENSE) file for copyright details. | See the [LICENSE](LICENSE) file for copyright details. | ||||
| Target | License(s) | License restrictions | Additional attribution | | |||||
|-----------------|----------------------|-----------------------|------------------------| | |||||
| JACK/Standalone | MIT (RtAudio) | Copyright attribution | **RtAudio**: 2001-2019 Gary P. Scavone | | |||||
| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||||
| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;<br/> **ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai | | |||||
| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;<br/> 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||||
| VST2 | BSD-3 | Copyright attribution | 2020-2022 Michael Fabian 'Xaymar' Dirks | | |||||
| VST3 | ISC | Copyright attribution | (none, only DPF files used) | | |||||
| CLAP | MIT | Copyright attribution | 2014-2022 Alexandre Bique | | |||||
| Target | License(s) | License restrictions | Additional attribution | | |||||
|-----------------|-----------------------|-----------------------|-----------------------------------------| | |||||
| JACK/Standalone | MIT (RtAudio, RtMidi) | Copyright attribution | **RtAudio**: 2001-2021 Gary P. Scavone | | |||||
| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||||
| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;<br/> **ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai | | |||||
| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;<br/> 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||||
| VST2 | BSD-3 | Copyright attribution | 2020-2022 Michael Fabian 'Xaymar' Dirks | | |||||
| VST3 | ISC | Copyright attribution | (none, only DPF files used) | | |||||
| CLAP | MIT | Copyright attribution | 2014-2022 Alexandre Bique | | |||||
| AU | ISC | Copyright attribution | (none, only DPF files used) | | |||||
### LADSPA and DSSI special note | ### LADSPA and DSSI special note | ||||
@@ -4,15 +4,22 @@ | |||||
# Created by falkTX | # Created by falkTX | ||||
# | # | ||||
AR ?= ar | |||||
CC ?= gcc | |||||
CXX ?= g++ | |||||
# Before including this file, a few variables can be set in order to tweak build behaviour: | # Before including this file, a few variables can be set in order to tweak build behaviour: | ||||
# DEBUG=true | # DEBUG=true | ||||
# Building in debug mode | |||||
# Implies SKIP_STRIPPING=true as well | |||||
# NOOPT=true | # NOOPT=true | ||||
# Do not automatically set optimization flags | |||||
# SKIP_STRIPPING=true | # SKIP_STRIPPING=true | ||||
# Do not strip output binaries | |||||
# NVG_DISABLE_SKIPPING_WHITESPACE=true | # NVG_DISABLE_SKIPPING_WHITESPACE=true | ||||
# Tweak `nvgTextBreakLines` to allow space characters | |||||
# FIXME proper details | |||||
# NVG_FONT_TEXTURE_FLAGS=0 | # NVG_FONT_TEXTURE_FLAGS=0 | ||||
# FILE_BROWSER_DISABLED=true | # FILE_BROWSER_DISABLED=true | ||||
# WINDOWS_ICON_ID=0 | # WINDOWS_ICON_ID=0 | ||||
@@ -21,9 +28,25 @@ CXX ?= g++ | |||||
# USE_OPENGL3=true | # USE_OPENGL3=true | ||||
# USE_NANOVG_FBO=true | # USE_NANOVG_FBO=true | ||||
# USE_NANOVG_FREETYPE=true | # USE_NANOVG_FREETYPE=true | ||||
# USE_FILE_BROWSER=true | |||||
# USE_WEB_VIEW=true | |||||
# STATIC_BUILD=true | # STATIC_BUILD=true | ||||
# Tweak build to be able to generate fully static builds (e.g. skip use of libdl) | |||||
# Experimental, use only if you know what you are doing | |||||
# FORCE_NATIVE_AUDIO_FALLBACK=true | # FORCE_NATIVE_AUDIO_FALLBACK=true | ||||
# Do not use JACK for the standalone, only native audio | |||||
# SKIP_NATIVE_AUDIO_FALLBACK=true | # SKIP_NATIVE_AUDIO_FALLBACK=true | ||||
# Do not use native audio for the standalone, only use JACK | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Read target compiler from environment | |||||
AR ?= ar | |||||
CC ?= gcc | |||||
CXX ?= g++ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Protect against multiple inclusion | # Protect against multiple inclusion | ||||
@@ -212,6 +235,27 @@ ifeq ($(MACOS),true) | |||||
UNIX = true | UNIX = true | ||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Compatibility checks | |||||
ifeq ($(FILE_BROWSER_DISABLED),true) | |||||
$(error FILE_BROWSER_DISABLED has been replaced by USE_FILE_BROWSER (opt-in vs opt-out)) | |||||
endif | |||||
ifeq ($(USE_FILEBROWSER),true) | |||||
$(error typo detected use USE_FILE_BROWSER instead of USE_FILEBROWSER) | |||||
endif | |||||
ifeq ($(USE_WEBVIEW),true) | |||||
$(error typo detected use USE_WEB_VIEW instead of USE_WEBVIEW) | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Set optional flags | |||||
USE_FILE_BROWSER ?= true | |||||
USE_WEB_VIEW ?= false | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Set build and link flags | # Set build and link flags | ||||
@@ -250,7 +294,9 @@ BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse | |||||
endif | endif | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
ifneq ($(MACOS_NO_DEAD_STRIP),true) | |||||
LINK_OPTS += -Wl,-dead_strip,-dead_strip_dylibs | LINK_OPTS += -Wl,-dead_strip,-dead_strip_dylibs | ||||
endif | |||||
else ifeq ($(WASM),true) | else ifeq ($(WASM),true) | ||||
LINK_OPTS += -O3 | LINK_OPTS += -O3 | ||||
LINK_OPTS += -Wl,--gc-sections | LINK_OPTS += -Wl,--gc-sections | ||||
@@ -416,6 +462,9 @@ else ifeq ($(MACOS),true) | |||||
DGL_SYSTEM_LIBS += -framework Cocoa | DGL_SYSTEM_LIBS += -framework Cocoa | ||||
DGL_SYSTEM_LIBS += -framework CoreVideo | DGL_SYSTEM_LIBS += -framework CoreVideo | ||||
ifeq ($(USE_WEB_VIEW),true) | |||||
DGL_SYSTEM_LIBS += -framework WebKit | |||||
endif | |||||
else ifeq ($(WASM),true) | else ifeq ($(WASM),true) | ||||
@@ -430,13 +479,19 @@ DGL_SYSTEM_LIBS += -lcomdlg32 | |||||
DGL_SYSTEM_LIBS += -ldwmapi | DGL_SYSTEM_LIBS += -ldwmapi | ||||
DGL_SYSTEM_LIBS += -lgdi32 | DGL_SYSTEM_LIBS += -lgdi32 | ||||
# DGL_SYSTEM_LIBS += -lole32 | # DGL_SYSTEM_LIBS += -lole32 | ||||
ifeq ($(USE_WEB_VIEW),true) | |||||
DGL_SYSTEM_LIBS += -lole32 | |||||
DGL_SYSTEM_LIBS += -luuid | |||||
endif | |||||
else | else | ||||
ifneq ($(FILE_BROWSER_DISABLED),true) | |||||
ifeq ($(HAVE_DBUS),true) | ifeq ($(HAVE_DBUS),true) | ||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS | DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS | ||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) | ||||
endif | endif | ||||
endif | |||||
ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | ||||
@@ -453,6 +508,10 @@ ifeq ($(HAVE_XRANDR),true) | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xrandr) -DHAVE_XRANDR | DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xrandr) -DHAVE_XRANDR | ||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xrandr) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xrandr) | ||||
endif | endif | ||||
ifeq ($(USE_WEB_VIEW),true) | |||||
DGL_FLAGS += -pthread | |||||
DGL_SYSTEM_LIBS += -pthread -lrt | |||||
endif | |||||
endif # HAVE_X11 | endif # HAVE_X11 | ||||
endif | endif | ||||
@@ -563,11 +622,11 @@ SHARED_MEMORY_LIBS = -lrt | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Backwards-compatible HAVE_DGL | |||||
# Generic HAVE_DGL | |||||
ifeq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) | ifeq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) | ||||
HAVE_DGL = true | HAVE_DGL = true | ||||
else ifeq ($(HAVE_OPENGL),true) | |||||
else | |||||
HAVE_DGL = $(HAVE_X11) | HAVE_DGL = $(HAVE_X11) | ||||
endif | endif | ||||
@@ -593,10 +652,6 @@ ifneq ($(NVG_FONT_TEXTURE_FLAGS),) | |||||
BUILD_CXX_FLAGS += -DNVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS) | BUILD_CXX_FLAGS += -DNVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS) | ||||
endif | endif | ||||
ifeq ($(FILE_BROWSER_DISABLED),true) | |||||
BUILD_CXX_FLAGS += -DDGL_FILE_BROWSER_DISABLED | |||||
endif | |||||
ifneq ($(WINDOWS_ICON_ID),) | ifneq ($(WINDOWS_ICON_ID),) | ||||
BUILD_CXX_FLAGS += -DDGL_WINDOWS_ICON_ID=$(WINDOWS_ICON_ID) | BUILD_CXX_FLAGS += -DDGL_WINDOWS_ICON_ID=$(WINDOWS_ICON_ID) | ||||
endif | endif | ||||
@@ -633,6 +688,14 @@ ifeq ($(USE_RGBA),true) | |||||
BUILD_CXX_FLAGS += -DDGL_USE_RGBA | BUILD_CXX_FLAGS += -DDGL_USE_RGBA | ||||
endif | endif | ||||
ifeq ($(USE_FILE_BROWSER),true) | |||||
BUILD_CXX_FLAGS += -DDGL_USE_FILE_BROWSER | |||||
endif | |||||
ifeq ($(USE_WEB_VIEW),true) | |||||
BUILD_CXX_FLAGS += -DDGL_USE_WEB_VIEW | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Set app extension | # Set app extension | ||||
@@ -688,7 +751,9 @@ endif | |||||
# Set VST3 binary directory, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html | # Set VST3 binary directory, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html | ||||
ifeq ($(LINUX),true) | ifeq ($(LINUX),true) | ||||
VST3_BINARY_DIR = Contents/$(TARGET_PROCESSOR)-linux | |||||
# This must match `uname -m`, which differs from `gcc -dumpmachine` on PowerPC. | |||||
VST3_ARCHITECTURE := $(patsubst powerpc%,ppc%,$(TARGET_PROCESSOR)) | |||||
VST3_BINARY_DIR = Contents/$(VST3_ARCHITECTURE)-linux | |||||
else ifeq ($(MACOS),true) | else ifeq ($(MACOS),true) | ||||
VST3_BINARY_DIR = Contents/MacOS | VST3_BINARY_DIR = Contents/MacOS | ||||
else ifeq ($(WASM),true) | else ifeq ($(WASM),true) | ||||
@@ -796,30 +861,99 @@ MOD_ENVIRONMENT = \ | |||||
modduo: | modduo: | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) | ||||
modduo-new: | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) | |||||
modduox: | modduox: | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) | ||||
modduox-new: | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) | |||||
moddwarf: | moddwarf: | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) | ||||
moddwarf-new: | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) | |||||
modpush: | modpush: | ||||
tar -C bin -cz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo | |||||
tar -C bin -chz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo | |||||
ifneq (,$(findstring modduo-,$(MAKECMDGOALS))) | |||||
ifneq (,$(findstring modduo-new-,$(MAKECMDGOALS))) | |||||
$(MAKECMDGOALS): | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) $(subst modduo-new-,,$(MAKECMDGOALS)) | |||||
else ifneq (,$(findstring modduo-,$(filter-out modduo-new,$(MAKECMDGOALS)))) | |||||
$(MAKECMDGOALS): | $(MAKECMDGOALS): | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) $(subst modduo-,,$(MAKECMDGOALS)) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) $(subst modduo-,,$(MAKECMDGOALS)) | ||||
endif | endif | ||||
ifneq (,$(findstring modduox-,$(MAKECMDGOALS))) | |||||
ifneq (,$(findstring modduox-new-,$(MAKECMDGOALS))) | |||||
$(MAKECMDGOALS): | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) $(subst modduox-new-,,$(MAKECMDGOALS)) | |||||
else ifneq (,$(findstring modduox-,$(filter-out modduox-new,$(MAKECMDGOALS)))) | |||||
$(MAKECMDGOALS): | $(MAKECMDGOALS): | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) | ||||
endif | endif | ||||
ifneq (,$(findstring moddwarf-,$(MAKECMDGOALS))) | |||||
ifneq (,$(findstring moddwarf-new-,$(MAKECMDGOALS))) | |||||
$(MAKECMDGOALS): | |||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) $(subst moddwarf-new-,,$(MAKECMDGOALS)) | |||||
else ifneq (,$(findstring moddwarf-,$(filter-out moddwarf-new,$(MAKECMDGOALS)))) | |||||
$(MAKECMDGOALS): | $(MAKECMDGOALS): | ||||
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) | $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) | ||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Convenience rules for common builds | |||||
macos-intel-10.8: | |||||
$(MAKE) \ | |||||
CFLAGS="$(CFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.8" \ | |||||
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.8 -stdlib=libc++" \ | |||||
LDFLAGS="$(LDFLAGS) -stdlib=libc++" \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
macos-universal-10.8: | |||||
$(MAKE) \ | |||||
CFLAGS="$(CFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.15" \ | |||||
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.15 -stdlib=libc++" \ | |||||
LDFLAGS="$(LDFLAGS) -stdlib=libc++" \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
macos-intel-10.15: | |||||
$(MAKE) \ | |||||
CFLAGS="$(CFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \ | |||||
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
macos-universal-10.15: | |||||
$(MAKE) \ | |||||
CFLAGS="$(CFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \ | |||||
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
mingw32: | |||||
$(MAKE) \ | |||||
AR=i686-w64-mingw32-ar \ | |||||
CC=i686-w64-mingw32-gcc \ | |||||
CXX=i686-w64-mingw32-g++ \ | |||||
EXE_WRAPPER=wine \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
mingw64: | |||||
$(MAKE) \ | |||||
AR=x86_64-w64-mingw32-ar \ | |||||
CC=x86_64-w64-mingw32-gcc \ | |||||
CXX=x86_64-w64-mingw32-g++ \ | |||||
EXE_WRAPPER=wine \ | |||||
PKG_CONFIG=/usr/bin/false \ | |||||
PKG_CONFIG_PATH=/NOT | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Protect against multiple inclusion | # Protect against multiple inclusion | ||||
@@ -1,27 +1,75 @@ | |||||
#!/usr/bin/make -f | #!/usr/bin/make -f | ||||
# Makefile for DPF Example Plugins # | |||||
# -------------------------------- # | |||||
# Makefile for DPF # | |||||
# ---------------- # | |||||
# Created by falkTX | # Created by falkTX | ||||
# | # | ||||
# NOTE: NAME, FILES_DSP and FILES_UI must have been defined before including this file! | # NOTE: NAME, FILES_DSP and FILES_UI must have been defined before including this file! | ||||
# extra useful variables to define before including this file: | |||||
# - DPF_BUILD_DIR: where to place temporary build files | |||||
# - DPF_TARGET_DIR: where to place final binary files | |||||
# - UI_TYPE: one of cairo, opengl, opengl3 or external, with opengl being default | |||||
# ("generic" is also allowed if only using image widgets) | |||||
# override the "all" target after including this file to define which plugin formats to build, like so: | |||||
# all: au clap jack lv2_sep vst2 vst3 | |||||
# NOTE the "lv2" target refers to a monolithic build (dsp and ui combined), | |||||
# while "lv2_sep" target has dsp and ui in separate binaries. | |||||
# use of this target must match the definition of `DISTRHO_PLUGIN_WANT_DIRECT_ACCESS` | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Try to figure out where DPF is located | |||||
ifeq ($(DPF_PATH),) | ifeq ($(DPF_PATH),) | ||||
ifneq (,$(wildcard dpf/Makefile.base.mk)) | |||||
BASE_PATH=. | |||||
DPF_PATH=dpf | |||||
else ifneq (,$(wildcard ../dpf/Makefile.base.mk)) | |||||
BASE_PATH=.. | |||||
DPF_PATH=../dpf | |||||
else ifneq (,$(wildcard ../../dpf/Makefile.base.mk)) | |||||
BASE_PATH=../.. | |||||
DPF_PATH=../../dpf | |||||
# find path to this makefile | |||||
DPF_PLUGINS_MAKEFILE = $(lastword $(filter %Makefile.plugins.mk,$(MAKEFILE_LIST))) | |||||
# error out if wrongly named or referencing it without any path | |||||
ifeq (,$(findstring /Makefile.plugins.mk,$(DPF_PLUGINS_MAKEFILE))) | |||||
$(error wrong inclusion of Makefile.plugins.mk, must be either absolute or relative path) | |||||
endif | |||||
# find path to DPF | |||||
DPF_PATH = $(patsubst %/Makefile.plugins.mk,%,$(DPF_PLUGINS_MAKEFILE)) | |||||
# best guess for where to place binary files | |||||
ifeq ($(DPF_PATH),..) | |||||
BASE_PATH = $(DPF_PATH) | |||||
else ifeq ($(DPF_PATH),../..) | |||||
BASE_PATH = $(DPF_PATH) | |||||
else ifeq ($(DPF_PATH),../../..) | |||||
BASE_PATH = $(DPF_PATH) | |||||
else | else | ||||
BASE_PATH=../.. | |||||
DPF_PATH=../.. | |||||
BASE_PATH = $(patsubst %/,%,$(dir $(DPF_PATH))) | |||||
endif | endif | ||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Check for proper UI_TYPE parameter | |||||
ifeq ($(UI_TYPE),) | |||||
else ifeq ($(UI_TYPE),cairo) | |||||
else ifeq ($(UI_TYPE),external) | |||||
else ifeq ($(UI_TYPE),generic) | |||||
else ifeq ($(UI_TYPE),opengl) | |||||
else ifeq ($(UI_TYPE),opengl3) | |||||
USE_OPENGL3 = true | |||||
else ifeq ($(UI_TYPE),vulkan) | |||||
else ifeq ($(UI_TYPE),webview) | |||||
USE_CLAP_BUNDLE = true | |||||
USE_VST2_BUNDLE = true | |||||
USE_WEB_VIEW = true | |||||
else | |||||
$(error unknown UI_TYPE $(UI_TYPE)) | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Include DPF base setup | |||||
include $(DPF_PATH)/Makefile.base.mk | include $(DPF_PATH)/Makefile.base.mk | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -140,6 +188,8 @@ OBJS_UI = $(FILES_UI:%=$(BUILD_DIR)/%.o) | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | ||||
else ifeq ($(WINDOWS)$(USE_WEB_VIEW),truetrue) | |||||
OBJS_UI += $(BUILD_DIR)/DistrhoUI_win32.cpp.o | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -159,6 +209,9 @@ ifeq ($(HAVE_OPENGL),true) | |||||
UI_TYPE = opengl | UI_TYPE = opengl | ||||
else ifeq ($(HAVE_CAIRO),true) | else ifeq ($(HAVE_CAIRO),true) | ||||
UI_TYPE = cairo | UI_TYPE = cairo | ||||
else | |||||
HAVE_DGL = false | |||||
UI_TYPE = none | |||||
endif | endif | ||||
endif | endif | ||||
@@ -211,12 +264,22 @@ endif | |||||
endif | endif | ||||
ifeq ($(UI_TYPE),external) | ifeq ($(UI_TYPE),external) | ||||
DGL_FLAGS += -DDGL_EXTERNAL | |||||
DGL_FLAGS += -DDGL_EXTERNAL -DHAVE_DGL | |||||
ifeq ($(HAVE_STUB),true) | |||||
DGL_FLAGS += $(STUB_FLAGS) | |||||
DGL_LIBS += $(STUB_LIBS) | |||||
DGL_LIB = $(DGL_BUILD_DIR)/libdgl-stub.a | |||||
HAVE_DGL = true | HAVE_DGL = true | ||||
else | |||||
HAVE_DGL = false | |||||
endif | |||||
endif | endif | ||||
ifeq ($(UI_TYPE),stub) | |||||
ifeq ($(UI_TYPE),webview) | |||||
DGL_FLAGS += -DDGL_EXTERNAL -DHAVE_DGL | |||||
ifeq ($(HAVE_STUB),true) | ifeq ($(HAVE_STUB),true) | ||||
DGL_FLAGS += $(STUB_FLAGS) | |||||
DGL_LIBS += $(STUB_LIBS) | |||||
DGL_LIB = $(DGL_BUILD_DIR)/libdgl-stub.a | DGL_LIB = $(DGL_BUILD_DIR)/libdgl-stub.a | ||||
HAVE_DGL = true | HAVE_DGL = true | ||||
else | else | ||||
@@ -224,6 +287,10 @@ HAVE_DGL = false | |||||
endif | endif | ||||
endif | endif | ||||
ifeq ($(HAVE_DGL)$(LINUX)$(USE_WEB_VIEW),truetruetrue) | |||||
DGL_LIB_SHARED = $(shell $(CC) -print-file-name=Scrt1.o) | |||||
endif | |||||
DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm | DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm | ||||
# TODO split dsp and ui object build flags | # TODO split dsp and ui object build flags | ||||
@@ -296,6 +363,8 @@ static = $(TARGET_DIR)/$(NAME).a | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
BUNDLE_RESOURCES = Info.plist PkgInfo Resources/empty.lproj | BUNDLE_RESOURCES = Info.plist PkgInfo Resources/empty.lproj | ||||
au = $(TARGET_DIR)/$(NAME).component/Contents/MacOS/$(NAME) | |||||
aufiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).component/Contents/%) | |||||
vst2files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/%) | vst2files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/%) | ||||
vst3files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/%) | vst3files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/%) | ||||
clapfiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/%) | clapfiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/%) | ||||
@@ -316,6 +385,7 @@ endif | |||||
# Set plugin symbols to export | # Set plugin symbols to export | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
SYMBOLS_AU = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/au.exp | |||||
SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | ||||
SYMBOLS_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp | SYMBOLS_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp | ||||
SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp | SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp | ||||
@@ -410,10 +480,11 @@ ifeq ($(DPF_BUILD_DIR),) | |||||
endif | endif | ||||
rm -rf $(TARGET_DIR)/$(NAME) | rm -rf $(TARGET_DIR)/$(NAME) | ||||
rm -rf $(TARGET_DIR)/$(NAME)-* | rm -rf $(TARGET_DIR)/$(NAME)-* | ||||
rm -rf $(TARGET_DIR)/$(NAME).clap | |||||
rm -rf $(TARGET_DIR)/$(NAME).component | |||||
rm -rf $(TARGET_DIR)/$(NAME).lv2 | rm -rf $(TARGET_DIR)/$(NAME).lv2 | ||||
rm -rf $(TARGET_DIR)/$(NAME).vst | rm -rf $(TARGET_DIR)/$(NAME).vst | ||||
rm -rf $(TARGET_DIR)/$(NAME).vst3 | rm -rf $(TARGET_DIR)/$(NAME).vst3 | ||||
rm -rf $(TARGET_DIR)/$(NAME).clap | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# DGL | # DGL | ||||
@@ -458,15 +529,18 @@ $(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm $(EX | |||||
@echo "Compiling DistrhoUI_macOS.mm ($*)" | @echo "Compiling DistrhoUI_macOS.mm ($*)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | ||||
$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES) | |||||
$(BUILD_DIR)/DistrhoUI_win32.cpp.o: $(DPF_PATH)/distrho/DistrhoUI_win32.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) | |||||
-@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
@echo "Compiling DistrhoPluginMain.cpp (JACK)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@ | |||||
@echo "Compiling DistrhoUI_win32.cpp ($*)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@ | |||||
$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) | |||||
-@mkdir -p $(BUILD_DIR) | |||||
@echo "Compiling DistrhoUIMain.cpp (DSSI)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI $(LIBLO_FLAGS) -c -o $@ | |||||
$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: BUILD_CXX_FLAGS += $(JACK_FLAGS) | |||||
$(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||||
$(BUILD_DIR)/DistrhoUIMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||||
$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: BUILD_CXX_FLAGS += $(LIBLO_FLAGS) | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# JACK | # JACK | ||||
@@ -517,9 +591,9 @@ lv2_dsp: $(lv2_dsp) | |||||
lv2_sep: $(lv2_dsp) $(lv2_ui) | lv2_sep: $(lv2_dsp) $(lv2_ui) | ||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
else | else | ||||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||||
$(lv2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||||
endif | endif | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LV2 plugin for $(NAME)" | @echo "Creating LV2 plugin for $(NAME)" | ||||
@@ -530,7 +604,7 @@ $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||||
@echo "Creating LV2 plugin library for $(NAME)" | @echo "Creating LV2 plugin library for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ | $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ | ||||
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||||
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LV2 plugin UI for $(NAME)" | @echo "Creating LV2 plugin UI for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@ | $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@ | ||||
@@ -635,7 +709,7 @@ modgui: | |||||
vst2 vst: $(vst2) $(vst2files) | vst2 vst: $(vst2) $(vst2files) | ||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) | |||||
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
else | else | ||||
$(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | $(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | ||||
endif | endif | ||||
@@ -649,7 +723,7 @@ endif | |||||
vst3: $(vst3) $(vst3files) | vst3: $(vst3) $(vst3files) | ||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) | |||||
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
else | else | ||||
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | ||||
endif | endif | ||||
@@ -671,7 +745,7 @@ endif | |||||
clap: $(clap) $(clapfiles) | clap: $(clap) $(clapfiles) | ||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
$(clap): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.o $(DGL_LIB) | |||||
$(clap): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
else | else | ||||
$(clap): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o | $(clap): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o | ||||
endif | endif | ||||
@@ -679,13 +753,39 @@ endif | |||||
@echo "Creating CLAP plugin for $(NAME)" | @echo "Creating CLAP plugin for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(CLAP_LIBS) $(SHARED) $(SYMBOLS_CLAP) -o $@ | $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(CLAP_LIBS) $(SHARED) $(SYMBOLS_CLAP) -o $@ | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# AU | |||||
au: $(au) $(aufiles) | |||||
ifeq ($(HAVE_DGL),true) | |||||
$(au): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o $(BUILD_DIR)/DistrhoUIMain_AU.cpp.o $(DGL_LIB) | |||||
else | |||||
$(au): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o | |||||
endif | |||||
-@mkdir -p $(shell dirname $@) | |||||
@echo "Creating AU component for $(NAME)" | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) -framework AudioToolbox -framework AudioUnit -framework CoreFoundation $(SHARED) $(SYMBOLS_AU) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Export | |||||
ifeq ($(HAVE_DGL),true) | |||||
$(BUILD_DIR)/export$(APP_EXT): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_EXPORT.cpp.o $(BUILD_DIR)/DistrhoUIMain_EXPORT.cpp.o $(DGL_LIB) | |||||
else | |||||
$(BUILD_DIR)/export$(APP_EXT): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_EXPORT.cpp.o | |||||
endif | |||||
-@mkdir -p $(shell dirname $@) | |||||
@echo "Creating export tool for $(NAME)" | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Shared | # Shared | ||||
shared: $(shared) | shared: $(shared) | ||||
ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
$(shared): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.o $(DGL_LIB) | |||||
$(shared): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||||
else | else | ||||
$(shared): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o | $(shared): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o | ||||
endif | endif | ||||
@@ -727,6 +827,13 @@ $(TARGET_DIR)/%/Resources/empty.lproj: $(DPF_PATH)/utils/plugin.bundle/Contents/ | |||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
$(SILENT)cp $< $@ | $(SILENT)cp $< $@ | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# format-specific files | |||||
$(TARGET_DIR)/$(NAME).component/Contents/Info.plist: $(BUILD_DIR)/export$(APP_EXT) | |||||
-@mkdir -p $(shell dirname $@) | |||||
cd $(TARGET_DIR)/$(NAME).component/Contents && $(abspath $<) "$(NAME)" | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
-include $(OBJS_DSP:%.o=%.d) | -include $(OBJS_DSP:%.o=%.d) | ||||
@@ -741,6 +848,8 @@ endif | |||||
-include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.d | |||||
-include $(BUILD_DIR)/DistrhoPluginMain_Export.cpp.d | |||||
-include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d | ||||
@@ -750,6 +859,7 @@ endif | |||||
-include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoUIMain_AU.cpp.d | |||||
-include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d | ||||
-include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d | ||||
@@ -1,6 +1,6 @@ | |||||
# 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 Filipe Coelho <falktx@falktx.com> | |||||
# Copyright (C) 2022-2024 Filipe Coelho <falktx@falktx.com> | |||||
# | # | ||||
# SPDX-License-Identifier: ISC | # SPDX-License-Identifier: ISC | ||||
@@ -75,7 +75,13 @@ include(CMakeParseArguments) | |||||
# `jack`, `ladspa`, `dssi`, `lv2`, `vst2`, `vst3`, `clap` | # `jack`, `ladspa`, `dssi`, `lv2`, `vst2`, `vst3`, `clap` | ||||
# | # | ||||
# `UI_TYPE` <type> | # `UI_TYPE` <type> | ||||
# the user interface type: `opengl` (default), `cairo`, `external` | |||||
# the user interface type, can be one of the following: | |||||
# - cairo | |||||
# - external | |||||
# - opengl (default) | |||||
# - opengl3 | |||||
# - vulkan | |||||
# - webview | |||||
# | # | ||||
# `FILES_COMMON` <file1>...<fileN> | # `FILES_COMMON` <file1>...<fileN> | ||||
# list of sources which are part of both DSP and UI | # list of sources which are part of both DSP and UI | ||||
@@ -96,8 +102,14 @@ include(CMakeParseArguments) | |||||
# `NO_SHARED_RESOURCES` | # `NO_SHARED_RESOURCES` | ||||
# do not build DPF shared resources (fonts, etc) | # 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_plugin NAME) | function(dpf_add_plugin NAME) | ||||
set(options MONOLITHIC NO_SHARED_RESOURCES) | |||||
set(options MONOLITHIC NO_SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||||
set(oneValueArgs MODGUI_CLASS_NAME UI_TYPE) | set(oneValueArgs MODGUI_CLASS_NAME UI_TYPE) | ||||
set(multiValueArgs FILES_COMMON FILES_DSP FILES_UI TARGETS) | set(multiValueArgs FILES_COMMON FILES_DSP FILES_UI TARGETS) | ||||
cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
@@ -107,23 +119,35 @@ function(dpf_add_plugin NAME) | |||||
endif() | endif() | ||||
set(_dgl_library) | set(_dgl_library) | ||||
set(_dgl_external OFF) | |||||
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("${_dpf_plugin_NO_SHARED_RESOURCES}") | |||||
dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||||
set(_dgl_library dgl-cairo) | set(_dgl_library dgl-cairo) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "external") | |||||
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||||
set(_dgl_library dgl-external) | |||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl") | elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl") | ||||
dpf__add_dgl_opengl("${_dpf_plugin_NO_SHARED_RESOURCES}") | |||||
dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||||
set(_dgl_library dgl-opengl) | set(_dgl_library dgl-opengl) | ||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "external") | |||||
set(_dgl_external ON) | |||||
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3") | |||||
dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||||
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}>) | |||||
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}>) | |||||
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}") | ||||
endif() | endif() | ||||
else() | |||||
set(_dpf_plugin_UI_TYPE "") | |||||
endif() | endif() | ||||
set(_dgl_has_ui OFF) | set(_dgl_has_ui OFF) | ||||
if(_dgl_library OR _dgl_external) | |||||
if(_dgl_library) | |||||
set(_dgl_has_ui ON) | set(_dgl_has_ui ON) | ||||
endif() | endif() | ||||
@@ -137,6 +161,14 @@ function(dpf_add_plugin NAME) | |||||
target_include_directories("${NAME}" PUBLIC | target_include_directories("${NAME}" PUBLIC | ||||
"${DPF_ROOT_DIR}/distrho") | "${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(_dpf_plugin_MODGUI_CLASS_NAME) | if(_dpf_plugin_MODGUI_CLASS_NAME) | ||||
target_compile_definitions("${NAME}" PUBLIC "DISTRHO_PLUGIN_MODGUI_CLASS_NAME=\"${_dpf_plugin_MODGUI_CLASS_NAME}\"") | target_compile_definitions("${NAME}" PUBLIC "DISTRHO_PLUGIN_MODGUI_CLASS_NAME=\"${_dpf_plugin_MODGUI_CLASS_NAME}\"") | ||||
endif() | endif() | ||||
@@ -145,7 +177,7 @@ function(dpf_add_plugin NAME) | |||||
target_link_libraries("${NAME}" PRIVATE "dl") | target_link_libraries("${NAME}" PRIVATE "dl") | ||||
endif() | endif() | ||||
if(_dgl_library AND NOT _dgl_external) | |||||
if(_dgl_library) | |||||
# make sure that all code will see DGL_* definitions | # make sure that all code will see DGL_* definitions | ||||
target_link_libraries("${NAME}" PUBLIC | target_link_libraries("${NAME}" PUBLIC | ||||
"${_dgl_library}-definitions" | "${_dgl_library}-definitions" | ||||
@@ -156,22 +188,20 @@ function(dpf_add_plugin NAME) | |||||
dpf__add_static_library("${NAME}-dsp" ${_dpf_plugin_FILES_DSP}) | dpf__add_static_library("${NAME}-dsp" ${_dpf_plugin_FILES_DSP}) | ||||
target_link_libraries("${NAME}-dsp" PUBLIC "${NAME}") | target_link_libraries("${NAME}-dsp" PUBLIC "${NAME}") | ||||
if(_dgl_library AND NOT _dgl_external) | |||||
if(_dgl_library) | |||||
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI}) | dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI}) | ||||
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library}) | target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library}) | ||||
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | ||||
target_link_libraries("${NAME}-ui" PRIVATE "dl") | target_link_libraries("${NAME}-ui" PRIVATE "dl") | ||||
if(LINUX AND _dpf_plugin_USE_WEB_VIEW) | |||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=Scrt1.o | |||||
OUTPUT_STRIP_TRAILING_WHITESPACE | |||||
OUTPUT_VARIABLE _dpf_plugin_shared_crt) | |||||
target_link_libraries("${NAME}-ui" PRIVATE "rt") | |||||
endif() | |||||
endif() | endif() | ||||
# add the files containing Objective-C classes | |||||
dpf__add_plugin_specific_ui_sources("${NAME}-ui") | |||||
elseif(_dgl_external) | |||||
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI}) | |||||
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}") | |||||
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||||
target_link_libraries("${NAME}-ui" PRIVATE "dl") | |||||
endif() | |||||
# add the files containing Objective-C classes | |||||
dpf__add_plugin_specific_ui_sources("${NAME}-ui") | |||||
# add the files containing C++17 or Objective-C classes | |||||
dpf__add_plugin_specific_ui_sources("${NAME}-ui" "${_dpf_plugin_USE_WEB_VIEW}") | |||||
else() | else() | ||||
add_library("${NAME}-ui" INTERFACE) | add_library("${NAME}-ui" INTERFACE) | ||||
endif() | endif() | ||||
@@ -185,13 +215,17 @@ function(dpf_add_plugin NAME) | |||||
elseif(_target STREQUAL "dssi") | elseif(_target STREQUAL "dssi") | ||||
dpf__build_dssi("${NAME}" "${_dgl_has_ui}") | dpf__build_dssi("${NAME}" "${_dgl_has_ui}") | ||||
elseif(_target STREQUAL "lv2") | elseif(_target STREQUAL "lv2") | ||||
dpf__build_lv2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_MONOLITHIC}") | |||||
dpf__build_lv2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_MONOLITHIC}" "${_dpf_plugin_shared_crt}") | |||||
elseif(_target STREQUAL "vst2") | elseif(_target STREQUAL "vst2") | ||||
dpf__build_vst2("${NAME}" "${_dgl_has_ui}") | |||||
dpf__build_vst2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}") | |||||
elseif(_target STREQUAL "vst3") | elseif(_target STREQUAL "vst3") | ||||
dpf__build_vst3("${NAME}" "${_dgl_has_ui}") | |||||
dpf__build_vst3("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}") | |||||
elseif(_target STREQUAL "clap") | elseif(_target STREQUAL "clap") | ||||
dpf__build_clap("${NAME}" "${_dgl_has_ui}") | |||||
dpf__build_clap("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}") | |||||
elseif(_target STREQUAL "au") | |||||
if (APPLE) | |||||
dpf__build_au("${NAME}" "${_dgl_has_ui}") | |||||
endif() | |||||
elseif(_target STREQUAL "static") | elseif(_target STREQUAL "static") | ||||
dpf__build_static("${NAME}" "${_dgl_has_ui}") | dpf__build_static("${NAME}" "${_dgl_has_ui}") | ||||
else() | else() | ||||
@@ -341,7 +375,7 @@ endfunction() | |||||
# | # | ||||
# Add build rules for an LV2 plugin. | # Add build rules for an LV2 plugin. | ||||
# | # | ||||
function(dpf__build_lv2 NAME HAS_UI MONOLITHIC) | |||||
function(dpf__build_lv2 NAME HAS_UI MONOLITHIC EXTRA_UI_LINK_OPTS) | |||||
dpf__create_dummy_source_list(_no_srcs) | dpf__create_dummy_source_list(_no_srcs) | ||||
dpf__add_module("${NAME}-lv2" ${_no_srcs}) | dpf__add_module("${NAME}-lv2" ${_no_srcs}) | ||||
@@ -362,12 +396,14 @@ function(dpf__build_lv2 NAME HAS_UI MONOLITHIC) | |||||
if(MONOLITHIC) | if(MONOLITHIC) | ||||
dpf__add_ui_main("${NAME}-lv2" "lv2" "${HAS_UI}") | dpf__add_ui_main("${NAME}-lv2" "lv2" "${HAS_UI}") | ||||
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-ui") | target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-ui") | ||||
target_link_options("${NAME}-lv2" PRIVATE "${EXTRA_UI_LINK_OPTS}") | |||||
set_target_properties("${NAME}-lv2" PROPERTIES | set_target_properties("${NAME}-lv2" PROPERTIES | ||||
OUTPUT_NAME "${NAME}") | OUTPUT_NAME "${NAME}") | ||||
else() | else() | ||||
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs}) | dpf__add_module("${NAME}-lv2-ui" ${_no_srcs}) | ||||
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${HAS_UI}") | dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${HAS_UI}") | ||||
dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui") | dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui") | ||||
target_link_options("${NAME}-lv2-ui" PRIVATE "${EXTRA_UI_LINK_OPTS}") | |||||
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui") | target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui") | ||||
set_target_properties("${NAME}-lv2-ui" PROPERTIES | set_target_properties("${NAME}-lv2-ui" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | ||||
@@ -396,7 +432,7 @@ endfunction() | |||||
# | # | ||||
# Add build rules for a VST2 plugin. | # Add build rules for a VST2 plugin. | ||||
# | # | ||||
function(dpf__build_vst2 NAME HAS_UI) | |||||
function(dpf__build_vst2 NAME HAS_UI EXTRA_UI_LINK_OPTS) | |||||
dpf__create_dummy_source_list(_no_srcs) | dpf__create_dummy_source_list(_no_srcs) | ||||
dpf__add_module("${NAME}-vst2" ${_no_srcs}) | dpf__add_module("${NAME}-vst2" ${_no_srcs}) | ||||
@@ -404,6 +440,7 @@ function(dpf__build_vst2 NAME HAS_UI) | |||||
dpf__add_ui_main("${NAME}-vst2" "vst2" "${HAS_UI}") | dpf__add_ui_main("${NAME}-vst2" "vst2" "${HAS_UI}") | ||||
dpf__set_module_export_list("${NAME}-vst2" "vst2") | dpf__set_module_export_list("${NAME}-vst2" "vst2") | ||||
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui") | target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui") | ||||
target_link_options("${NAME}-vst2" PRIVATE "${EXTRA_UI_LINK_OPTS}") | |||||
set_target_properties("${NAME}-vst2" PROPERTIES | set_target_properties("${NAME}-vst2" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst2/$<0:>" | ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst2/$<0:>" | ||||
@@ -456,7 +493,7 @@ function(dpf__determine_vst3_package_architecture OUTPUT_VARIABLE) | |||||
else() | else() | ||||
set(vst3_package_arch "i386") | set(vst3_package_arch "i386") | ||||
endif() | endif() | ||||
elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*)$") | |||||
elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*|ppc(64)?(le)?)$") | |||||
set(vst3_package_arch "${vst3_system_arch}") | set(vst3_package_arch "${vst3_system_arch}") | ||||
elseif(vst3_system_arch MATCHES "^(aarch64)$") | elseif(vst3_system_arch MATCHES "^(aarch64)$") | ||||
set(vst3_package_arch "aarch64") | set(vst3_package_arch "aarch64") | ||||
@@ -474,7 +511,7 @@ endfunction() | |||||
# | # | ||||
# Add build rules for a VST3 plugin. | # Add build rules for a VST3 plugin. | ||||
# | # | ||||
function(dpf__build_vst3 NAME HAS_UI) | |||||
function(dpf__build_vst3 NAME HAS_UI EXTRA_UI_LINK_OPTS) | |||||
dpf__determine_vst3_package_architecture(vst3_arch) | dpf__determine_vst3_package_architecture(vst3_arch) | ||||
dpf__create_dummy_source_list(_no_srcs) | dpf__create_dummy_source_list(_no_srcs) | ||||
@@ -484,6 +521,7 @@ function(dpf__build_vst3 NAME HAS_UI) | |||||
dpf__add_ui_main("${NAME}-vst3" "vst3" "${HAS_UI}") | dpf__add_ui_main("${NAME}-vst3" "vst3" "${HAS_UI}") | ||||
dpf__set_module_export_list("${NAME}-vst3" "vst3") | dpf__set_module_export_list("${NAME}-vst3" "vst3") | ||||
target_link_libraries("${NAME}-vst3" PRIVATE "${NAME}-dsp" "${NAME}-ui") | target_link_libraries("${NAME}-vst3" PRIVATE "${NAME}-dsp" "${NAME}-ui") | ||||
target_link_options("${NAME}-vst3" PRIVATE "${EXTRA_UI_LINK_OPTS}") | |||||
set_target_properties("${NAME}-vst3" PROPERTIES | set_target_properties("${NAME}-vst3" PROPERTIES | ||||
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst3/$<0:>" | ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst3/$<0:>" | ||||
OUTPUT_NAME "${NAME}" | OUTPUT_NAME "${NAME}" | ||||
@@ -516,7 +554,7 @@ endfunction() | |||||
# | # | ||||
# Add build rules for a CLAP plugin. | # Add build rules for a CLAP plugin. | ||||
# | # | ||||
function(dpf__build_clap NAME HAS_UI) | |||||
function(dpf__build_clap NAME HAS_UI EXTRA_UI_LINK_OPTS) | |||||
dpf__create_dummy_source_list(_no_srcs) | dpf__create_dummy_source_list(_no_srcs) | ||||
dpf__add_module("${NAME}-clap" ${_no_srcs}) | dpf__add_module("${NAME}-clap" ${_no_srcs}) | ||||
@@ -524,6 +562,7 @@ function(dpf__build_clap NAME HAS_UI) | |||||
dpf__add_ui_main("${NAME}-clap" "clap" "${HAS_UI}") | dpf__add_ui_main("${NAME}-clap" "clap" "${HAS_UI}") | ||||
dpf__set_module_export_list("${NAME}-clap" "clap") | dpf__set_module_export_list("${NAME}-clap" "clap") | ||||
target_link_libraries("${NAME}-clap" PRIVATE "${NAME}-dsp" "${NAME}-ui") | target_link_libraries("${NAME}-clap" PRIVATE "${NAME}-dsp" "${NAME}-ui") | ||||
target_link_options("${NAME}-clap" PRIVATE "${EXTRA_UI_LINK_OPTS}") | |||||
set_target_properties("${NAME}-clap" PROPERTIES | set_target_properties("${NAME}-clap" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/clap/$<0:>" | ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/clap/$<0:>" | ||||
@@ -544,6 +583,53 @@ function(dpf__build_clap NAME HAS_UI) | |||||
endif() | endif() | ||||
endfunction() | endfunction() | ||||
# dpf__build_au | |||||
# ------------------------------------------------------------------------------ | |||||
# | |||||
# Add build rules for an AUv2 plugin. | |||||
# | |||||
function(dpf__build_au NAME HAS_UI) | |||||
dpf__create_dummy_source_list(_no_srcs) | |||||
dpf__add_module("${NAME}-au" ${_no_srcs}) | |||||
dpf__add_plugin_main("${NAME}-au" "au") | |||||
dpf__add_ui_main("${NAME}-au" "au" "${HAS_UI}") | |||||
dpf__set_module_export_list("${NAME}-au" "au") | |||||
find_library(APPLE_AUDIOTOOLBOX_FRAMEWORK "AudioToolbox") | |||||
find_library(APPLE_AUDIOUNIT_FRAMEWORK "AudioUnit") | |||||
find_library(APPLE_COREFOUNDATION_FRAMEWORK "CoreFoundation") | |||||
target_compile_options("${NAME}-au" PRIVATE "-ObjC++") | |||||
target_link_libraries("${NAME}-au" PRIVATE | |||||
"${NAME}-dsp" | |||||
"${NAME}-ui" | |||||
"${APPLE_AUDIOTOOLBOX_FRAMEWORK}" | |||||
"${APPLE_AUDIOUNIT_FRAMEWORK}" | |||||
"${APPLE_COREFOUNDATION_FRAMEWORK}") | |||||
set_target_properties("${NAME}-au" PROPERTIES | |||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents/MacOS/$<0:>" | |||||
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/au/$<0:>" | |||||
OUTPUT_NAME "${NAME}" | |||||
PREFIX "" | |||||
SUFFIX "") | |||||
dpf__add_executable("${NAME}-export" ${_no_srcs}) | |||||
dpf__add_plugin_main("${NAME}-export" "export") | |||||
dpf__add_ui_main("${NAME}-export" "export" "${HAS_UI}") | |||||
target_link_libraries("${NAME}-export" PRIVATE "${NAME}-dsp" "${NAME}-ui") | |||||
separate_arguments(CMAKE_CROSSCOMPILING_EMULATOR) | |||||
add_custom_command(TARGET "${NAME}-au" POST_BUILD | |||||
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} "$<TARGET_FILE:${NAME}-export>" "${NAME}" | |||||
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents" | |||||
DEPENDS "${NAME}-export") | |||||
add_dependencies("${NAME}-au" "${NAME}-export") | |||||
file(COPY "${DPF_ROOT_DIR}/utils/plugin.bundle/Contents/PkgInfo" | |||||
DESTINATION "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents") | |||||
endfunction() | |||||
# dpf__build_static | # dpf__build_static | ||||
# ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||
# | # | ||||
@@ -577,7 +663,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 NO_SHARED_RESOURCES) | |||||
function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER) | |||||
if(TARGET dgl-cairo) | if(TARGET dgl-cairo) | ||||
return() | return() | ||||
endif() | endif() | ||||
@@ -605,23 +691,27 @@ function(dpf__add_dgl_cairo NO_SHARED_RESOURCES) | |||||
"${DPF_ROOT_DIR}/dgl/src/Window.cpp" | "${DPF_ROOT_DIR}/dgl/src/Window.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/Cairo.cpp") | "${DPF_ROOT_DIR}/dgl/src/Cairo.cpp") | ||||
if(NO_SHARED_RESOURCES) | |||||
target_compile_definitions(dgl-cairo PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
else() | |||||
if(SHARED_RESOURCES) | |||||
target_sources(dgl-cairo PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | target_sources(dgl-cairo PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | ||||
else() | |||||
target_compile_definitions(dgl-cairo PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
endif() | endif() | ||||
if(NOT APPLE) | |||||
if(APPLE) | |||||
target_sources(dgl-cairo PRIVATE | target_sources(dgl-cairo PRIVATE | ||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
else() | else() | ||||
target_sources(dgl-cairo PRIVATE | target_sources(dgl-cairo PRIVATE | ||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
endif() | endif() | ||||
target_include_directories(dgl-cairo PUBLIC | target_include_directories(dgl-cairo PUBLIC | ||||
"${DPF_ROOT_DIR}/dgl") | "${DPF_ROOT_DIR}/dgl") | ||||
target_include_directories(dgl-cairo PUBLIC | target_include_directories(dgl-cairo PUBLIC | ||||
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | "${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | ||||
if(USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER") | |||||
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) | ||||
@@ -637,12 +727,68 @@ function(dpf__add_dgl_cairo NO_SHARED_RESOURCES) | |||||
target_link_libraries(dgl-cairo PRIVATE dgl-cairo-definitions) | target_link_libraries(dgl-cairo PRIVATE dgl-cairo-definitions) | ||||
endfunction() | endfunction() | ||||
# dpf__add_dgl_external | |||||
# ------------------------------------------------------------------------------ | |||||
# | |||||
# Add the external variant of DGL, if not already available. | |||||
# | |||||
function(dpf__add_dgl_external USE_FILE_BROWSER) | |||||
if(TARGET dgl-external) | |||||
return() | |||||
endif() | |||||
dpf__add_static_library(dgl-external STATIC | |||||
"${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Layout.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Widget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Stub.cpp") | |||||
if(APPLE) | |||||
target_sources(dgl-external PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
else() | |||||
target_sources(dgl-external PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
endif() | |||||
target_include_directories(dgl-external PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl") | |||||
target_include_directories(dgl-external PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | |||||
if(USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER") | |||||
endif() | |||||
dpf__add_dgl_system_libs() | |||||
target_compile_definitions(dgl-external PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
target_link_libraries(dgl-external PRIVATE dgl-system-libs) | |||||
add_library(dgl-external-definitions INTERFACE) | |||||
target_compile_definitions(dgl-external-definitions INTERFACE "DGL_EXTERNAL" "HAVE_DGL") | |||||
target_include_directories(dgl-external PUBLIC "${OPENGL_INCLUDE_DIR}") | |||||
target_link_libraries(dgl-external PRIVATE dgl-external-definitions "${OPENGL_gl_LIBRARY}") | |||||
endfunction() | |||||
# dpf__add_dgl_opengl | # dpf__add_dgl_opengl | ||||
# ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||
# | # | ||||
# 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 NO_SHARED_RESOURCES) | |||||
function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER) | |||||
if(TARGET dgl-opengl) | if(TARGET dgl-opengl) | ||||
return() | return() | ||||
endif() | endif() | ||||
@@ -672,17 +818,17 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES) | |||||
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | "${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | ||||
"${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | "${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | ||||
if(NO_SHARED_RESOURCES) | |||||
target_compile_definitions(dgl-opengl PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
else() | |||||
if(SHARED_RESOURCES) | |||||
target_sources(dgl-opengl PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | target_sources(dgl-opengl PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | ||||
else() | |||||
target_compile_definitions(dgl-opengl PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
endif() | endif() | ||||
if(NOT APPLE) | |||||
if(APPLE) | |||||
target_sources(dgl-opengl PRIVATE | target_sources(dgl-opengl PRIVATE | ||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
else() | else() | ||||
target_sources(dgl-opengl PRIVATE | target_sources(dgl-opengl PRIVATE | ||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
endif() | endif() | ||||
target_include_directories(dgl-opengl PUBLIC | target_include_directories(dgl-opengl PUBLIC | ||||
"${DPF_ROOT_DIR}/dgl") | "${DPF_ROOT_DIR}/dgl") | ||||
@@ -693,6 +839,10 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES) | |||||
target_compile_definitions(dgl-opengl PUBLIC "GL_SILENCE_DEPRECATION") | target_compile_definitions(dgl-opengl PUBLIC "GL_SILENCE_DEPRECATION") | ||||
endif() | endif() | ||||
if(USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_FILE_BROWSER") | |||||
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) | ||||
@@ -703,15 +853,165 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES) | |||||
target_link_libraries(dgl-opengl PRIVATE dgl-opengl-definitions "${OPENGL_gl_LIBRARY}") | target_link_libraries(dgl-opengl PRIVATE dgl-opengl-definitions "${OPENGL_gl_LIBRARY}") | ||||
endfunction() | endfunction() | ||||
# dpf__add_dgl_opengl3 | |||||
# ------------------------------------------------------------------------------ | |||||
# | |||||
# Add the OpenGL3 variant of DGL, if not already available. | |||||
# | |||||
function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER) | |||||
if(TARGET dgl-opengl3) | |||||
return() | |||||
endif() | |||||
if(NOT OpenGL_GL_PREFERENCE) | |||||
set(OpenGL_GL_PREFERENCE "LEGACY") | |||||
endif() | |||||
find_package(OpenGL REQUIRED) | |||||
dpf__add_static_library(dgl-opengl3 STATIC | |||||
"${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Layout.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Widget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | |||||
if(SHARED_RESOURCES) | |||||
target_sources(dgl-opengl3 PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||||
else() | |||||
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
endif() | |||||
if(APPLE) | |||||
target_sources(dgl-opengl3 PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
else() | |||||
target_sources(dgl-opengl3 PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
endif() | |||||
target_include_directories(dgl-opengl3 PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl") | |||||
target_include_directories(dgl-opengl3 PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | |||||
if(APPLE) | |||||
target_compile_definitions(dgl-opengl3 PUBLIC "GL_SILENCE_DEPRECATION") | |||||
endif() | |||||
if(USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_FILE_BROWSER") | |||||
endif() | |||||
dpf__add_dgl_system_libs() | |||||
target_link_libraries(dgl-opengl3 PRIVATE dgl-system-libs) | |||||
add_library(dgl-opengl3-definitions INTERFACE) | |||||
target_compile_definitions(dgl-opengl3-definitions INTERFACE "DGL_USE_OPENGL3" "DGL_OPENGL" "HAVE_OPENGL" "HAVE_DGL") | |||||
target_include_directories(dgl-opengl3 PUBLIC "${OPENGL_INCLUDE_DIR}") | |||||
target_link_libraries(dgl-opengl3 PRIVATE dgl-opengl3-definitions "${OPENGL_gl_LIBRARY}") | |||||
endfunction() | |||||
# dpf__add_dgl_vulkan | |||||
# ------------------------------------------------------------------------------ | |||||
# | |||||
# Add the Vulkan variant of DGL, if not already available. | |||||
# | |||||
function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER) | |||||
if(TARGET dgl-vulkan) | |||||
return() | |||||
endif() | |||||
find_package(Vulkan REQUIRED) | |||||
dpf__add_static_library(dgl-vulkan STATIC | |||||
"${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Layout.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/TopLevelWidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Widget.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WidgetPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||||
"${DPF_ROOT_DIR}/dgl/src/Vulkan.cpp") | |||||
if(NO_SHARED_RESOURCES) | |||||
target_sources(dgl-vulkan PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||||
else() | |||||
target_compile_definitions(dgl-vulkan PUBLIC "DGL_NO_SHARED_RESOURCES") | |||||
endif() | |||||
if(APPLE) | |||||
target_sources(dgl-vulkan PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||||
else() | |||||
target_sources(dgl-vulkan PRIVATE | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||||
endif() | |||||
target_include_directories(dgl-vulkan PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl") | |||||
target_include_directories(dgl-vulkan PUBLIC | |||||
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | |||||
if(APPLE) | |||||
target_compile_definitions(dgl-vulkan PUBLIC "GL_SILENCE_DEPRECATION") | |||||
endif() | |||||
if(USE_FILE_BROWSER) | |||||
target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_FILE_BROWSER") | |||||
endif() | |||||
dpf__add_dgl_system_libs() | |||||
target_link_libraries(dgl-vulkan PRIVATE dgl-system-libs) | |||||
add_library(dgl-vulkan-definitions INTERFACE) | |||||
target_compile_definitions(dgl-vulkan-definitions INTERFACE "DGL_VULKAN" "HAVE_VULKAN" "HAVE_DGL") | |||||
target_include_directories(dgl-vulkan PUBLIC "${OPENGL_INCLUDE_DIR}") | |||||
target_link_libraries(dgl-vulkan PRIVATE dgl-vulkan-definitions "${OPENGL_gl_LIBRARY}") | |||||
endfunction() | |||||
# dpf__add_plugin_specific_ui_sources | # dpf__add_plugin_specific_ui_sources | ||||
# ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||
# | # | ||||
# Compile system specific files, for now it is just Objective-C code | |||||
# Compile system specific files | |||||
# | # | ||||
function(dpf__add_plugin_specific_ui_sources NAME) | |||||
function(dpf__add_plugin_specific_ui_sources NAME USE_WEB_VIEW) | |||||
if(APPLE) | if(APPLE) | ||||
target_sources("${NAME}" PRIVATE | target_sources("${NAME}" PRIVATE | ||||
"${DPF_ROOT_DIR}/distrho/DistrhoUI_macOS.mm") | "${DPF_ROOT_DIR}/distrho/DistrhoUI_macOS.mm") | ||||
if(USE_WEB_VIEW) | |||||
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||||
target_link_libraries("${NAME}" PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||||
endif() | |||||
elseif(WIN32 AND USE_WEB_VIEW) | |||||
target_sources("${NAME}" PRIVATE | |||||
"${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp") | |||||
if (MSVC) | |||||
set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp" | |||||
PROPERTIES COMPILE_FLAGS /std:c++17) | |||||
else() | |||||
set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp" | |||||
PROPERTIES COMPILE_FLAGS -std=gnu++17) | |||||
endif() | |||||
target_link_libraries("${NAME}" PRIVATE "ole32" "uuid") | |||||
endif() | endif() | ||||
endfunction() | endfunction() | ||||
@@ -804,7 +1104,9 @@ endfunction() | |||||
function(dpf__add_module NAME) | function(dpf__add_module NAME) | ||||
add_library("${NAME}" MODULE ${ARGN}) | add_library("${NAME}" MODULE ${ARGN}) | ||||
dpf__set_target_defaults("${NAME}") | dpf__set_target_defaults("${NAME}") | ||||
if(MINGW) | |||||
if(APPLE) | |||||
set_target_properties("${NAME}" PROPERTIES SUFFIX ".dylib") | |||||
elseif(MINGW) | |||||
target_link_libraries("${NAME}" PRIVATE "-static") | target_link_libraries("${NAME}" PRIVATE "-static") | ||||
endif() | endif() | ||||
endfunction() | endfunction() | ||||
@@ -861,6 +1163,9 @@ function(dpf__set_target_defaults NAME) | |||||
if (CMAKE_COMPILER_IS_GNUCXX) | if (CMAKE_COMPILER_IS_GNUCXX) | ||||
target_compile_options("${NAME}" PUBLIC "-fno-gnu-unique") | target_compile_options("${NAME}" PUBLIC "-fno-gnu-unique") | ||||
endif() | endif() | ||||
if ((NOT APPLE) AND (NOT MSVC)) | |||||
target_link_options("${NAME}" PUBLIC "-Wl,--no-undefined") | |||||
endif() | |||||
endfunction() | endfunction() | ||||
# dpf__add_plugin_main | # dpf__add_plugin_main | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -27,6 +27,41 @@ END_NAMESPACE_DISTRHO | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// build config sentinels | |||||
/** | |||||
This set of static variables act as a build sentinel that detects a configuration error. | |||||
Usually this means the way DGL was built and how it is being used and linked into your program is different, | |||||
we want to avoid such combinations as memory layout would then also be different | |||||
leading to all sort of subtle but very nasty memory corruption issues. | |||||
Make sure the flags used to build DGL match the ones used by your program and the link errors should go away. | |||||
*/ | |||||
#define BUILD_CONFIG_SENTINEL(NAME) \ | |||||
static struct DISTRHO_JOIN_MACRO(_, NAME) { bool ok; DISTRHO_JOIN_MACRO(_, NAME)() noexcept; } NAME; | |||||
#ifdef DPF_DEBUG | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_off) | |||||
#endif | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | |||||
#endif | |||||
#ifdef DGL_NO_SHARED_RESOURCES | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off) | |||||
#endif | |||||
#undef BUILD_CONFIG_SENTINEL | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
/** | /** | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -20,6 +20,35 @@ | |||||
#include "../distrho/extra/LeakDetector.hpp" | #include "../distrho/extra/LeakDetector.hpp" | ||||
#include "../distrho/extra/ScopedPointer.hpp" | #include "../distrho/extra/ScopedPointer.hpp" | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Compatibility checks | |||||
#if defined(DGL_CAIRO) && defined(DGL_EXTERNAL) | |||||
# error invalid build config: trying to build for both cairo and external at the same time | |||||
#elif defined(DGL_CAIRO) && defined(DGL_OPENGL) | |||||
# error invalid build config: trying to build for both cairo and opengl at the same time | |||||
#elif defined(DGL_CAIRO) && defined(DGL_VULKAN) | |||||
# error invalid build config: trying to build for both cairo and vulkan at the same time | |||||
#elif defined(DGL_EXTERNAL) && defined(DGL_OPENGL) | |||||
# error invalid build config: trying to build for both external and opengl at the same time | |||||
#elif defined(DGL_EXTERNAL) && defined(DGL_VULKAN) | |||||
# error invalid build config: trying to build for both external and vulkan at the same time | |||||
#elif defined(DGL_OPENGL) && defined(DGL_VULKAN) | |||||
# error invalid build config: trying to build for both opengl and vulkan at the same time | |||||
#endif | |||||
#ifdef DGL_USE_FILEBROWSER | |||||
# error typo detected use DGL_USE_FILE_BROWSER instead of DGL_USE_FILEBROWSER | |||||
#endif | |||||
#ifdef DGL_UI_USE_WEBVIEW | |||||
# error typo detected use DGL_UI_USE_WEB_VIEW instead of DGL_UI_USE_WEBVIEW | |||||
#endif | |||||
#if defined(DGL_FILE_BROWSER_DISABLED) | |||||
# error DGL_FILE_BROWSER_DISABLED has been replaced by DGL_USE_FILE_BROWSER (opt-in vs opt-out) | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// Define namespace | // Define namespace | ||||
@@ -40,10 +69,13 @@ START_NAMESPACE_DGL | |||||
Keyboard modifier flags. | Keyboard modifier flags. | ||||
*/ | */ | ||||
enum Modifier { | enum Modifier { | ||||
kModifierShift = 1u << 0u, ///< Shift key | |||||
kModifierControl = 1u << 1u, ///< Control key | |||||
kModifierAlt = 1u << 2u, ///< Alt/Option key | |||||
kModifierSuper = 1u << 3u ///< Mod4/Command/Windows key | |||||
kModifierShift = 1U << 0U, ///< Shift key | |||||
kModifierControl = 1U << 1U, ///< Control key | |||||
kModifierAlt = 1U << 2U, ///< Alt/Option key | |||||
kModifierSuper = 1U << 3U, ///< Mod4/Command/Windows key | |||||
kModifierNumLock = 1U << 4U, ///< Num lock enabled | |||||
kModifierScrollLock = 1U << 5U, ///< Scroll lock enabled | |||||
kModifierCapsLock = 1U << 6U, ///< Caps lock enabled | |||||
}; | }; | ||||
/** | /** | ||||
@@ -63,13 +95,14 @@ enum Modifier { | |||||
enum Key { | enum Key { | ||||
// Convenience symbols for ASCII control characters | // Convenience symbols for ASCII control characters | ||||
kKeyBackspace = 0x00000008U, ///< Backspace | kKeyBackspace = 0x00000008U, ///< Backspace | ||||
kKeyTab = 0x00000009U, ///< Tab | |||||
kKeyEnter = 0x0000000DU, ///< Enter | kKeyEnter = 0x0000000DU, ///< Enter | ||||
kKeyEscape = 0x0000001BU, ///< Escape | kKeyEscape = 0x0000001BU, ///< Escape | ||||
kKeyDelete = 0x0000007FU, ///< Delete | kKeyDelete = 0x0000007FU, ///< Delete | ||||
kKeySpace = 0x00000020U, ///< Space | kKeySpace = 0x00000020U, ///< Space | ||||
// Unicode Private Use Area | // Unicode Private Use Area | ||||
kKeyF1 = 0x0000E000U, ///< F1 | |||||
kKeyF1 = 0xE000U, ///< F1 | |||||
kKeyF2, ///< F2 | kKeyF2, ///< F2 | ||||
kKeyF3, ///< F3 | kKeyF3, ///< F3 | ||||
kKeyF4, ///< F4 | kKeyF4, ///< F4 | ||||
@@ -81,7 +114,7 @@ enum Key { | |||||
kKeyF10, ///< F10 | kKeyF10, ///< F10 | ||||
kKeyF11, ///< F11 | kKeyF11, ///< F11 | ||||
kKeyF12, ///< F12 | kKeyF12, ///< F12 | ||||
kKeyPageUp = 0xE031, ///< Page Up | |||||
kKeyPageUp = 0xE031U, ///< Page Up | |||||
kKeyPageDown, ///< Page Down | kKeyPageDown, ///< Page Down | ||||
kKeyEnd, ///< End | kKeyEnd, ///< End | ||||
kKeyHome, ///< Home | kKeyHome, ///< Home | ||||
@@ -96,7 +129,7 @@ enum Key { | |||||
kKeyNumLock, ///< Num Lock | kKeyNumLock, ///< Num Lock | ||||
kKeyScrollLock, ///< Scroll Lock | kKeyScrollLock, ///< Scroll Lock | ||||
kKeyCapsLock, ///< Caps Lock | kKeyCapsLock, ///< Caps Lock | ||||
kKeyShiftL = 0xE051U, ///< Left Shift, | |||||
kKeyShiftL = 0xE051U, ///< Left Shift | |||||
kKeyShiftR, ///< Right Shift | kKeyShiftR, ///< Right Shift | ||||
kKeyControlL, ///< Left Control | kKeyControlL, ///< Left Control | ||||
kKeyControlR, ///< Right Control | kKeyControlR, ///< Right Control | ||||
@@ -150,7 +183,7 @@ enum Key { | |||||
*/ | */ | ||||
enum EventFlag { | enum EventFlag { | ||||
kFlagSendEvent = 1, ///< Event is synthetic | kFlagSendEvent = 1, ///< Event is synthetic | ||||
kFlagIsHint = 2 ///< Event is a hint (not direct user input) | |||||
kFlagIsHint = 2, ///< Event is a hint (not direct user input) | |||||
}; | }; | ||||
/** | /** | ||||
@@ -159,7 +192,7 @@ enum EventFlag { | |||||
enum CrossingMode { | enum CrossingMode { | ||||
kCrossingNormal, ///< Crossing due to pointer motion | kCrossingNormal, ///< Crossing due to pointer motion | ||||
kCrossingGrab, ///< Crossing due to a grab | kCrossingGrab, ///< Crossing due to a grab | ||||
kCrossingUngrab ///< Crossing due to a grab release | |||||
kCrossingUngrab, ///< Crossing due to a grab release | |||||
}; | }; | ||||
/** | /** | ||||
@@ -204,7 +237,7 @@ enum MouseCursor { | |||||
// Backwards compatibility with old DPF | // Backwards compatibility with old DPF | ||||
kMouseCursorDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpLeftDownRight") = kMouseCursorUpLeftDownRight, | kMouseCursorDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpLeftDownRight") = kMouseCursorUpLeftDownRight, | ||||
kMouseCursorAntiDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpRightDownLeft") = kMouseCursorUpRightDownLeft | |||||
kMouseCursorAntiDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpRightDownLeft") = kMouseCursorUpRightDownLeft, | |||||
}; | }; | ||||
/** | /** | ||||
@@ -215,11 +248,11 @@ enum MouseCursor { | |||||
while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads. | while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads. | ||||
*/ | */ | ||||
enum ScrollDirection { | enum ScrollDirection { | ||||
kScrollUp, ///< Scroll up | |||||
kScrollDown, ///< Scroll down | |||||
kScrollLeft, ///< Scroll left | |||||
kScrollRight, ///< Scroll right | |||||
kScrollSmooth ///< Smooth scroll in any direction | |||||
kScrollUp, ///< Scroll up | |||||
kScrollDown, ///< Scroll down | |||||
kScrollLeft, ///< Scroll left | |||||
kScrollRight, ///< Scroll right | |||||
kScrollSmooth, ///< Smooth scroll in any direction | |||||
}; | }; | ||||
/** | /** | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -133,6 +133,8 @@ public: | |||||
// returns 0-1 ranged value, already with log scale as needed | // returns 0-1 ranged value, already with log scale as needed | ||||
float getNormalizedValue() const noexcept; | float getNormalizedValue() const noexcept; | ||||
float getDefault() const noexcept; | |||||
// 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; | ||||
@@ -186,7 +188,7 @@ private: | |||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
DISTRHO_LEAK_DETECTOR(SliderEventHandler) | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SliderEventHandler) | |||||
}; | }; | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -138,6 +138,7 @@ public: | |||||
virtual void imageKnobDragStarted(ImageBaseKnob* imageKnob) = 0; | virtual void imageKnobDragStarted(ImageBaseKnob* imageKnob) = 0; | ||||
virtual void imageKnobDragFinished(ImageBaseKnob* imageKnob) = 0; | virtual void imageKnobDragFinished(ImageBaseKnob* imageKnob) = 0; | ||||
virtual void imageKnobValueChanged(ImageBaseKnob* imageKnob, float value) = 0; | virtual void imageKnobValueChanged(ImageBaseKnob* imageKnob, float value) = 0; | ||||
virtual void imageKnobDoubleClicked(ImageBaseKnob*) {}; | |||||
}; | }; | ||||
explicit ImageBaseKnob(Widget* parentWidget, const ImageType& image, Orientation orientation = Vertical) noexcept; | explicit ImageBaseKnob(Widget* parentWidget, const ImageType& image, Orientation orientation = Vertical) noexcept; | ||||
@@ -14,6 +14,7 @@ BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include | |||||
LINK_FLAGS += $(DGL_LIBS) | LINK_FLAGS += $(DGL_LIBS) | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
BUILD_CXX_FLAGS += -DDISTRHO_MACOS_NAMESPACE_TIME=$(shell date +%s) | |||||
BUILD_CXX_FLAGS += -Wno-deprecated-declarations | BUILD_CXX_FLAGS += -Wno-deprecated-declarations | ||||
else | else | ||||
PUGL_EXTRA_FLAGS = -Wno-extra -Wmissing-field-initializers | PUGL_EXTRA_FLAGS = -Wno-extra -Wmissing-field-initializers | ||||
@@ -90,7 +91,8 @@ endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
OBJS_stub = $(OBJS_common) | |||||
OBJS_stub = $(OBJS_common) \ | |||||
$(BUILD_DIR)/dgl/Stub.cpp.o | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
OBJS_stub += $(BUILD_DIR)/dgl/pugl.mm.o | OBJS_stub += $(BUILD_DIR)/dgl/pugl.mm.o | ||||
@@ -117,8 +119,6 @@ endif | |||||
ifeq ($(HAVE_OPENGL),true) | ifeq ($(HAVE_OPENGL),true) | ||||
TARGETS += $(BUILD_DIR)/libdgl-opengl.a | TARGETS += $(BUILD_DIR)/libdgl-opengl.a | ||||
# Compat name, to be removed soon | |||||
TARGETS += $(BUILD_DIR)/libdgl.a | |||||
endif | endif | ||||
ifeq ($(HAVE_STUB),true) | ifeq ($(HAVE_STUB),true) | ||||
@@ -138,6 +138,7 @@ opengl: $(BUILD_DIR)/libdgl-opengl.a | |||||
opengl3: $(BUILD_DIR)/libdgl-opengl3.a | opengl3: $(BUILD_DIR)/libdgl-opengl3.a | ||||
stub: $(BUILD_DIR)/libdgl-stub.a | stub: $(BUILD_DIR)/libdgl-stub.a | ||||
vulkan: $(BUILD_DIR)/libdgl-vulkan.a | vulkan: $(BUILD_DIR)/libdgl-vulkan.a | ||||
web: $(BUILD_DIR)/libdgl-web.a | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -171,11 +172,6 @@ $(BUILD_DIR)/libdgl-vulkan.a: $(OBJS_vulkan) | |||||
$(SILENT)rm -f $@ | $(SILENT)rm -f $@ | ||||
$(SILENT)$(AR) crs $@ $^ | $(SILENT)$(AR) crs $@ $^ | ||||
# Compat name, to be removed soon | |||||
$(BUILD_DIR)/libdgl.a: $(BUILD_DIR)/libdgl-opengl.a | |||||
@echo "Symlinking libdgl.a" | |||||
$(SILENT)ln -sf $< $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
$(BUILD_DIR)/dgl/%.c.o: src/%.c | $(BUILD_DIR)/dgl/%.c.o: src/%.c | ||||
@@ -73,6 +73,7 @@ public: | |||||
uint getHeight() const noexcept { return Window::getHeight(); } | uint getHeight() const noexcept { return Window::getHeight(); } | ||||
const Size<uint> getSize() const noexcept { return Window::getSize(); } | const Size<uint> getSize() const noexcept { return Window::getSize(); } | ||||
void repaint() noexcept { Window::repaint(); } | void repaint() noexcept { Window::repaint(); } | ||||
void repaint(const Rectangle<uint>& rect) noexcept { Window::repaint(rect); } | |||||
void setWidth(uint width) { Window::setWidth(width); } | void setWidth(uint width) { Window::setWidth(width); } | ||||
void setHeight(uint height) { Window::setHeight(height); } | void setHeight(uint height) { Window::setHeight(height); } | ||||
void setSize(uint width, uint height) { Window::setSize(width, height); } | void setSize(uint width, uint height) { Window::setSize(width, height); } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -407,7 +407,7 @@ protected: | |||||
/** | /** | ||||
A function called to draw the widget contents. | A function called to draw the widget contents. | ||||
*/ | */ | ||||
virtual void onDisplay() = 0; | |||||
virtual void onDisplay() {}; | |||||
/** | /** | ||||
A function called when a key is pressed or released. | A function called when a key is pressed or released. | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -19,7 +19,7 @@ | |||||
#include "Geometry.hpp" | #include "Geometry.hpp" | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
# include "FileBrowserDialog.hpp" | # include "FileBrowserDialog.hpp" | ||||
#endif | #endif | ||||
@@ -394,7 +394,7 @@ public: | |||||
*/ | */ | ||||
void focus(); | void focus(); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
/** | /** | ||||
Open a file browser dialog with this window as transient parent. | Open a file browser dialog with this window as transient parent. | ||||
A few options can be specified to setup the dialog. | A few options can be specified to setup the dialog. | ||||
@@ -405,7 +405,7 @@ public: | |||||
This function does not block the event loop. | This function does not block the event loop. | ||||
*/ | */ | ||||
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | ||||
#endif | |||||
#endif | |||||
/** | /** | ||||
Request repaint of this window, for the entire area. | Request repaint of this window, for the entire area. | ||||
@@ -517,7 +517,7 @@ protected: | |||||
*/ | */ | ||||
virtual void onScaleFactorChanged(double scaleFactor); | virtual void onScaleFactorChanged(double scaleFactor); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
/** | /** | ||||
A function called when a path is selected by the user, as triggered by openFileBrowser(). | A function called when a path is selected by the user, as triggered by openFileBrowser(). | ||||
This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | ||||
@@ -528,7 +528,7 @@ protected: | |||||
/** DEPRECATED Use onFileSelected(). */ | /** DEPRECATED Use onFileSelected(). */ | ||||
DISTRHO_DEPRECATED_BY("onFileSelected(const char*)") | DISTRHO_DEPRECATED_BY("onFileSelected(const char*)") | ||||
inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); } | inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); } | ||||
#endif | |||||
#endif | |||||
private: | private: | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
@@ -545,6 +545,7 @@ private: | |||||
uint height, | uint height, | ||||
double scaleFactor, | double scaleFactor, | ||||
bool resizable, | bool resizable, | ||||
bool usesScheduledRepaints, | |||||
bool usesSizeRequest, | bool usesSizeRequest, | ||||
bool doPostInit); | bool doPostInit); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,55 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// build config sentinels | |||||
#define BUILD_CONFIG_SENTINEL(NAME) \ | |||||
DISTRHO_JOIN_MACRO(_, NAME)::DISTRHO_JOIN_MACRO(_, NAME)() noexcept : ok(false) {} | |||||
#ifdef DPF_DEBUG | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_off) | |||||
#endif | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | |||||
#endif | |||||
#ifdef DGL_NO_SHARED_RESOURCES | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | |||||
#else | |||||
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off) | |||||
#endif | |||||
#undef BUILD_CONFIG_SENTINEL | |||||
static inline | |||||
bool dpf_check_build_status() noexcept | |||||
{ | |||||
return ( | |||||
#ifdef DPF_DEBUG | |||||
fail_to_link_is_mismatch_dpf_debug_on.ok && | |||||
#else | |||||
fail_to_link_is_mismatch_dpf_debug_off.ok && | |||||
#endif | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
fail_to_link_is_mismatch_dgl_use_file_browser_on.ok && | |||||
#else | |||||
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok && | |||||
#endif | |||||
#ifdef DGL_NO_SHARED_RESOURCES | |||||
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok && | |||||
#else | |||||
fail_to_link_is_mismatch_dgl_no_shared_resources_off.ok && | |||||
#endif | |||||
true | |||||
); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
#ifdef __EMSCRIPTEN__ | #ifdef __EMSCRIPTEN__ | ||||
@@ -34,7 +83,26 @@ static void app_idle(void* const app) | |||||
#endif | #endif | ||||
Application::Application(const bool isStandalone) | Application::Application(const bool isStandalone) | ||||
: pData(new PrivateData(isStandalone)) {} | |||||
: pData(new PrivateData(isStandalone)) | |||||
{ | |||||
// 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_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() | Application::~Application() | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,24 +23,25 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
typedef std::list<DGL_NAMESPACE::Window*>::iterator WindowListIterator; | |||||
typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator; | typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator; | ||||
static d_ThreadHandle getCurrentThreadHandle() noexcept | static d_ThreadHandle getCurrentThreadHandle() noexcept | ||||
{ | { | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
return GetCurrentThread(); | return GetCurrentThread(); | ||||
#else | |||||
#else | |||||
return pthread_self(); | return pthread_self(); | ||||
#endif | |||||
#endif | |||||
} | } | ||||
static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept | static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept | ||||
{ | { | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
return GetCurrentThread() == mainThreadHandle; // IsGUIThread ? | return GetCurrentThread() == mainThreadHandle; // IsGUIThread ? | ||||
#else | |||||
#else | |||||
return pthread_equal(getCurrentThreadHandle(), mainThreadHandle) != 0; | return pthread_equal(getCurrentThreadHandle(), mainThreadHandle) != 0; | ||||
#endif | |||||
#endif | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -59,6 +60,7 @@ Application::PrivateData::PrivateData(const bool standalone) | |||||
isQuitting(false), | isQuitting(false), | ||||
isQuittingInNextCycle(false), | isQuittingInNextCycle(false), | ||||
isStarting(true), | isStarting(true), | ||||
needsRepaint(false), | |||||
visibleWindows(0), | visibleWindows(0), | ||||
mainThreadHandle(getCurrentThreadHandle()), | mainThreadHandle(getCurrentThreadHandle()), | ||||
windows(), | windows(), | ||||
@@ -66,12 +68,16 @@ Application::PrivateData::PrivateData(const bool standalone) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | ||||
#ifdef DGL_USING_SDL | |||||
SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO); | |||||
#else | |||||
puglSetWorldHandle(world, this); | puglSetWorldHandle(world, this); | ||||
#ifdef __EMSCRIPTEN__ | #ifdef __EMSCRIPTEN__ | ||||
puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); | puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); | ||||
#else | #else | ||||
puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); | puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); | ||||
#endif | #endif | ||||
#endif | |||||
} | } | ||||
Application::PrivateData::~PrivateData() | Application::PrivateData::~PrivateData() | ||||
@@ -82,8 +88,12 @@ Application::PrivateData::~PrivateData() | |||||
windows.clear(); | windows.clear(); | ||||
idleCallbacks.clear(); | idleCallbacks.clear(); | ||||
#ifdef DGL_USING_SDL | |||||
SDL_Quit(); | |||||
#else | |||||
if (world != nullptr) | if (world != nullptr) | ||||
puglFreeWorld(world); | puglFreeWorld(world); | ||||
#endif | |||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -136,6 +146,20 @@ void Application::PrivateData::triggerIdleCallbacks() | |||||
} | } | ||||
} | } | ||||
void Application::PrivateData::repaintIfNeeeded() | |||||
{ | |||||
if (needsRepaint) | |||||
{ | |||||
needsRepaint = false; | |||||
for (WindowListIterator it = windows.begin(), ite = windows.end(); it != ite; ++it) | |||||
{ | |||||
DGL_NAMESPACE::Window* const window(*it); | |||||
window->repaint(); | |||||
} | |||||
} | |||||
} | |||||
void Application::PrivateData::quit() | void Application::PrivateData::quit() | ||||
{ | { | ||||
if (! isThisTheMainThread(mainThreadHandle)) | if (! isThisTheMainThread(mainThreadHandle)) | ||||
@@ -149,13 +173,13 @@ void Application::PrivateData::quit() | |||||
isQuitting = true; | isQuitting = true; | ||||
#ifndef DPF_TEST_APPLICATION_CPP | |||||
#ifndef DPF_TEST_APPLICATION_CPP | |||||
for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit) | for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit) | ||||
{ | { | ||||
DGL_NAMESPACE::Window* const window(*rit); | DGL_NAMESPACE::Window* const window(*rit); | ||||
window->close(); | window->close(); | ||||
} | } | ||||
#endif | |||||
#endif | |||||
} | } | ||||
double Application::PrivateData::getTime() const | double Application::PrivateData::getTime() const | ||||
@@ -63,6 +63,9 @@ struct Application::PrivateData { | |||||
/** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | ||||
bool isStarting; | bool isStarting; | ||||
/** When true force all windows to be repainted on next idle. */ | |||||
bool needsRepaint; | |||||
/** Counter of visible windows, only used in standalone mode. | /** Counter of visible windows, only used in standalone mode. | ||||
If 0->1, application is starting. If 1->0, application is quitting/stopping. */ | If 0->1, application is starting. If 1->0, application is quitting/stopping. */ | ||||
uint visibleWindows; | uint visibleWindows; | ||||
@@ -96,6 +99,9 @@ struct Application::PrivateData { | |||||
/** Run each idle callback without updating pugl world. */ | /** Run each idle callback without updating pugl world. */ | ||||
void triggerIdleCallbacks(); | void triggerIdleCallbacks(); | ||||
/** Trigger a repaint of all windows if @a needsRepaint is true. */ | |||||
void repaintIfNeeeded(); | |||||
/** Set flag indicating application is quitting, and close all windows in reverse order of registration. | /** Set flag indicating application is quitting, and close all windows in reverse order of registration. | ||||
For standalone mode only. */ | For standalone mode only. */ | ||||
void quit(); | void quit(); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | * Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | ||||
* | * | ||||
* 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 | ||||
@@ -438,9 +438,9 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, co | |||||
for (int w = 0; w < width; ++w) | for (int w = 0; w < width; ++w) | ||||
{ | { | ||||
const uchar a = urdata[h*width*4+w*4+3]; | const uchar a = urdata[h*width*4+w*4+3]; | ||||
newdata[h*width*4+w*4+0] = (urdata[h*width*4+w*4+0] * a) >> 8; | |||||
newdata[h*width*4+w*4+1] = (urdata[h*width*4+w*4+1] * a) >> 8; | |||||
newdata[h*width*4+w*4+2] = (urdata[h*width*4+w*4+2] * a) >> 8; | |||||
newdata[h*width*4+w*4+0] = static_cast<uchar>((urdata[h*width*4+w*4+0] * a) >> 8); | |||||
newdata[h*width*4+w*4+1] = static_cast<uchar>((urdata[h*width*4+w*4+1] * a) >> 8); | |||||
newdata[h*width*4+w*4+2] = static_cast<uchar>((urdata[h*width*4+w*4+2] * a) >> 8); | |||||
newdata[h*width*4+w*4+3] = a; | newdata[h*width*4+w*4+3] = a; | ||||
} | } | ||||
} | } | ||||
@@ -465,9 +465,9 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, co | |||||
for (int w = 0; w < width; ++w) | for (int w = 0; w < width; ++w) | ||||
{ | { | ||||
const uchar a = urdata[h*width*4+w*4+3]; | const uchar a = urdata[h*width*4+w*4+3]; | ||||
newdata[h*width*4+w*4+0] = (urdata[h*width*4+w*4+2] * a) >> 8; | |||||
newdata[h*width*4+w*4+1] = (urdata[h*width*4+w*4+1] * a) >> 8; | |||||
newdata[h*width*4+w*4+2] = (urdata[h*width*4+w*4+0] * a) >> 8; | |||||
newdata[h*width*4+w*4+0] = static_cast<uchar>((urdata[h*width*4+w*4+2] * a) >> 8); | |||||
newdata[h*width*4+w*4+1] = static_cast<uchar>((urdata[h*width*4+w*4+1] * a) >> 8); | |||||
newdata[h*width*4+w*4+2] = static_cast<uchar>((urdata[h*width*4+w*4+0] * a) >> 8); | |||||
newdata[h*width*4+w*4+3] = a; | newdata[h*width*4+w*4+3] = a; | ||||
} | } | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -419,7 +419,7 @@ struct KnobEventHandler::PrivateData { | |||||
if ((state & kKnobStateDragging) == 0x0) | if ((state & kKnobStateDragging) == 0x0) | ||||
return false; | return false; | ||||
float movDiff; | |||||
double movDiff; | |||||
switch (orientation) | switch (orientation) | ||||
{ | { | ||||
@@ -431,8 +431,8 @@ struct KnobEventHandler::PrivateData { | |||||
break; | break; | ||||
case Both: | case Both: | ||||
{ | { | ||||
const float movDiffX = ev.pos.getX() / scaleFactor - lastX; | |||||
const float movDiffY = lastY - ev.pos.getY() / scaleFactor; | |||||
const double movDiffX = ev.pos.getX() / scaleFactor - lastX; | |||||
const double movDiffY = lastY - ev.pos.getY() / scaleFactor; | |||||
movDiff = std::abs(movDiffX) > std::abs(movDiffY) ? movDiffX : movDiffY; | movDiff = std::abs(movDiffX) > std::abs(movDiffY) ? movDiffX : movDiffY; | ||||
} | } | ||||
break; | break; | ||||
@@ -444,7 +444,7 @@ struct KnobEventHandler::PrivateData { | |||||
return true; | return true; | ||||
const float divisor = (ev.mod & kModifierControl) ? accel * 10.f : accel; | const float divisor = (ev.mod & kModifierControl) ? accel * 10.f : accel; | ||||
valueTmp += (maximum - minimum) / divisor * movDiff; | |||||
valueTmp += (maximum - minimum) / divisor * static_cast<float>(movDiff); | |||||
if (usingLog) | if (usingLog) | ||||
valueTmp = logscale(valueTmp); | valueTmp = logscale(valueTmp); | ||||
@@ -618,6 +618,11 @@ float KnobEventHandler::getNormalizedValue() const noexcept | |||||
return pData->getNormalizedValue(); | return pData->getNormalizedValue(); | ||||
} | } | ||||
float KnobEventHandler::getDefault() const noexcept | |||||
{ | |||||
return pData->valueDef; | |||||
} | |||||
void KnobEventHandler::setDefault(const float def) noexcept | void KnobEventHandler::setDefault(const float def) noexcept | ||||
{ | { | ||||
pData->valueDef = def; | pData->valueDef = def; | ||||
@@ -316,6 +316,13 @@ struct ImageBaseKnob<ImageType>::PrivateData : public KnobEventHandler::Callback | |||||
callback->imageKnobValueChanged(imageKnob, value); | callback->imageKnobValueChanged(imageKnob, value); | ||||
} | } | ||||
void knobDoubleClicked(SubWidget* const widget) override | |||||
{ | |||||
if (callback != nullptr) | |||||
if (ImageBaseKnob* const imageKnob = dynamic_cast<ImageBaseKnob*>(widget)) | |||||
callback->imageKnobDoubleClicked(imageKnob); | |||||
} | |||||
// implemented independently per graphics backend | // implemented independently per graphics backend | ||||
void init(); | void init(); | ||||
void cleanup(); | void cleanup(); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -35,8 +35,8 @@ uint Layout<true>::setAbsolutePos(int x, const int y, const uint padding) | |||||
SubWidgetWithSizeHint& s(*it); | SubWidgetWithSizeHint& s(*it); | ||||
maxHeight = std::max(maxHeight, s.widget->getHeight()); | maxHeight = std::max(maxHeight, s.widget->getHeight()); | ||||
s.widget->setAbsolutePos(x, y); | s.widget->setAbsolutePos(x, y); | ||||
x += s.widget->getWidth(); | |||||
x += padding; | |||||
x += static_cast<int>(s.widget->getWidth()); | |||||
x += static_cast<int>(padding); | |||||
} | } | ||||
return maxHeight; | return maxHeight; | ||||
@@ -52,8 +52,8 @@ uint Layout<false>::setAbsolutePos(const int x, int y, const uint padding) | |||||
SubWidgetWithSizeHint& s(*it); | SubWidgetWithSizeHint& s(*it); | ||||
maxWidth = std::max(maxWidth, s.widget->getWidth()); | maxWidth = std::max(maxWidth, s.widget->getWidth()); | ||||
s.widget->setAbsolutePos(x, y); | s.widget->setAbsolutePos(x, y); | ||||
y += s.widget->getHeight(); | |||||
y += padding; | |||||
y += static_cast<int>(s.widget->getHeight()); | |||||
y += static_cast<int>(padding); | |||||
} | } | ||||
return maxWidth; | return maxWidth; | ||||
@@ -78,7 +78,7 @@ void Layout<true>::setSize(const uint width, const uint padding) | |||||
} | } | ||||
if (const size_t numWidgets = widgets.size()) | if (const size_t numWidgets = widgets.size()) | ||||
nonFixedWidth -= padding * (numWidgets - 1); | |||||
nonFixedWidth -= padding * static_cast<uint>(numWidgets - 1); | |||||
const uint widthPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedWidth / numDynamiclySizedWidgets : 0; | const uint widthPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedWidth / numDynamiclySizedWidgets : 0; | ||||
@@ -111,7 +111,7 @@ void Layout<false>::setSize(const uint height, const uint padding) | |||||
} | } | ||||
if (const size_t numWidgets = widgets.size()) | if (const size_t numWidgets = widgets.size()) | ||||
nonFixedHeight -= padding * (numWidgets - 1); | |||||
nonFixedHeight -= padding * static_cast<uint>(numWidgets - 1); | |||||
const uint heightPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedHeight / numDynamiclySizedWidgets : 0; | const uint heightPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedHeight / numDynamiclySizedWidgets : 0; | ||||
@@ -138,8 +138,8 @@ void HorizontallyStackedVerticalLayout::setAbsolutePos(int x, const int y, const | |||||
for (VerticalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it) | for (VerticalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it) | ||||
{ | { | ||||
VerticalLayout* l(*it); | VerticalLayout* l(*it); | ||||
x += l->setAbsolutePos(x, y, padding); | |||||
x += padding; | |||||
x += static_cast<int>(l->setAbsolutePos(x, y, padding)); | |||||
x += static_cast<int>(padding); | |||||
} | } | ||||
} | } | ||||
@@ -157,9 +157,9 @@ Size<uint> VerticallyStackedHorizontalLayout::adjustSize(const uint padding) | |||||
uint width = 0; | uint width = 0; | ||||
uint height = 0; | uint height = 0; | ||||
for (SubWidgetWithSizeHintIterator it=l->widgets.begin(), end=l->widgets.end(); it != end; ++it) | |||||
for (SubWidgetWithSizeHintIterator it2=l->widgets.begin(), end2=l->widgets.end(); it2 != end2; ++it2) | |||||
{ | { | ||||
SubWidgetWithSizeHint& s(*it); | |||||
SubWidgetWithSizeHint& s(*it2); | |||||
if (width != 0) | if (width != 0) | ||||
width += padding; | width += padding; | ||||
@@ -191,8 +191,8 @@ void VerticallyStackedHorizontalLayout::setAbsolutePos(const int x, int y, const | |||||
for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it) | for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it) | ||||
{ | { | ||||
HorizontalLayout* l(*it); | HorizontalLayout* l(*it); | ||||
y += l->setAbsolutePos(x, y, padding); | |||||
y += padding; | |||||
y += static_cast<int>(l->setAbsolutePos(x, y, padding)); | |||||
y += static_cast<int>(padding); | |||||
} | } | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -691,12 +691,12 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
const int w = static_cast<int>(self->getWidth()); | const int w = static_cast<int>(self->getWidth()); | ||||
const int h = static_cast<int>(self->getHeight()); | const int h = static_cast<int>(self->getHeight()); | ||||
if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0) | |||||
if (d_isNotZero(viewportScaleFactor) && d_isNotEqual(viewportScaleFactor, 1.0)) | |||||
{ | { | ||||
glViewport(x, | glViewport(x, | ||||
-static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5), | |||||
static_cast<int>(width * viewportScaleFactor + 0.5), | |||||
static_cast<int>(height * viewportScaleFactor + 0.5)); | |||||
-d_roundToIntPositive(height * viewportScaleFactor - height + absolutePos.getY()), | |||||
d_roundToIntPositive(width * viewportScaleFactor), | |||||
d_roundToIntPositive(height * viewportScaleFactor)); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -712,16 +712,16 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||||
else | else | ||||
{ | { | ||||
// set viewport pos | // set viewport pos | ||||
glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5), | |||||
-static_cast<int>(absolutePos.getY() * autoScaleFactor + 0.5), | |||||
glViewport(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor), | |||||
-d_roundToIntPositive(absolutePos.getY() * autoScaleFactor), | |||||
static_cast<int>(width), | static_cast<int>(width), | ||||
static_cast<int>(height)); | static_cast<int>(height)); | ||||
// then cut the outer bounds | // then cut the outer bounds | ||||
glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5), | |||||
static_cast<int>(height - (self->getHeight() + absolutePos.getY()) * autoScaleFactor + 0.5), | |||||
static_cast<int>(self->getWidth() * autoScaleFactor + 0.5), | |||||
static_cast<int>(self->getHeight() * autoScaleFactor + 0.5)); | |||||
glScissor(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor), | |||||
d_roundToIntPositive(height - (static_cast<int>(self->getHeight()) + absolutePos.getY()) * autoScaleFactor), | |||||
d_roundToIntPositive(self->getWidth() * autoScaleFactor), | |||||
d_roundToIntPositive(self->getHeight() * autoScaleFactor)); | |||||
glEnable(GL_SCISSOR_TEST); | glEnable(GL_SCISSOR_TEST); | ||||
needsDisableScissor = true; | needsDisableScissor = true; | ||||
@@ -0,0 +1,193 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "Color.hpp" | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "WindowPrivateData.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
static void notImplemented(const char* const name) | |||||
{ | |||||
d_stderr2("stub function not implemented: %s", name); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Color | |||||
void Color::setFor(const GraphicsContext&, bool) | |||||
{ | |||||
notImplemented("Color::setFor"); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Line | |||||
template<typename T> | |||||
void Line<T>::draw(const GraphicsContext& context, T) | |||||
{ | |||||
notImplemented("Line::draw"); | |||||
} | |||||
template<typename T> | |||||
void Line<T>::draw() | |||||
{ | |||||
notImplemented("Line::draw"); | |||||
} | |||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Circle | |||||
template<typename T> | |||||
void Circle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Circle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Circle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::draw() | |||||
{ | |||||
notImplemented("Circle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Circle::drawOutline"); | |||||
} | |||||
template class Circle<double>; | |||||
template class Circle<float>; | |||||
template class Circle<int>; | |||||
template class Circle<uint>; | |||||
template class Circle<short>; | |||||
template class Circle<ushort>; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Triangle | |||||
template<typename T> | |||||
void Triangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Triangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Triangle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::draw() | |||||
{ | |||||
notImplemented("Triangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Triangle::drawOutline"); | |||||
} | |||||
template class Triangle<double>; | |||||
template class Triangle<float>; | |||||
template class Triangle<int>; | |||||
template class Triangle<uint>; | |||||
template class Triangle<short>; | |||||
template class Triangle<ushort>; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Rectangle | |||||
template<typename T> | |||||
void Rectangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Rectangle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::draw() | |||||
{ | |||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Rectangle::drawOutline"); | |||||
} | |||||
template class Rectangle<double>; | |||||
template class Rectangle<float>; | |||||
template class Rectangle<int>; | |||||
template class Rectangle<uint>; | |||||
template class Rectangle<short>; | |||||
template class Rectangle<ushort>; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void SubWidget::PrivateData::display(uint, uint, double) | |||||
{ | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void TopLevelWidget::PrivateData::display() | |||||
{ | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||||
{ | |||||
notImplemented("Window::PrivateData::renderToPicture"); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||||
{ | |||||
GraphicsContext& context((GraphicsContext&)graphicsContext); | |||||
return context; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -71,7 +71,7 @@ Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept | |||||
const int y = getAbsoluteY(); | const int y = getAbsoluteY(); | ||||
if (x >= 0 && y >= 0) | if (x >= 0 && y >= 0) | ||||
return Rectangle<uint>(x, y, getSize()); | |||||
return Rectangle<uint>(static_cast<uint>(x), static_cast<uint>(y), getSize()); | |||||
const int xOffset = std::min(0, x); | const int xOffset = std::min(0, x); | ||||
const int yOffset = std::min(0, y); | const int yOffset = std::min(0, y); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -106,7 +106,7 @@ Window::Window(Application& app, | |||||
const uint height, | const uint height, | ||||
const double scaleFactor, | const double scaleFactor, | ||||
const bool resizable) | const bool resizable) | ||||
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false)) | |||||
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false, false)) | |||||
{ | { | ||||
pData->initPost(); | pData->initPost(); | ||||
} | } | ||||
@@ -117,9 +117,11 @@ Window::Window(Application& app, | |||||
const uint height, | const uint height, | ||||
const double scaleFactor, | const double scaleFactor, | ||||
const bool resizable, | const bool resizable, | ||||
const bool isVST3, | |||||
const bool usesScheduledRepaints, | |||||
const bool usesSizeRequest, | |||||
const bool doPostInit) | const bool doPostInit) | ||||
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3)) | |||||
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, | |||||
usesScheduledRepaints, usesSizeRequest)) | |||||
{ | { | ||||
if (doPostInit) | if (doPostInit) | ||||
pData->initPost(); | pData->initPost(); | ||||
@@ -225,7 +227,7 @@ uint Window::getWidth() const noexcept | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | ||||
const double width = puglGetFrame(pData->view).width; | const double width = puglGetFrame(pData->view).width; | ||||
DISTRHO_SAFE_ASSERT_RETURN(width >= 0.0, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(width > 0.0, 0); | |||||
return static_cast<uint>(width + 0.5); | return static_cast<uint>(width + 0.5); | ||||
} | } | ||||
@@ -234,7 +236,7 @@ uint Window::getHeight() const noexcept | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | ||||
const double height = puglGetFrame(pData->view).height; | const double height = puglGetFrame(pData->view).height; | ||||
DISTRHO_SAFE_ASSERT_RETURN(height >= 0.0, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(height > 0.0, 0); | |||||
return static_cast<uint>(height + 0.5); | return static_cast<uint>(height + 0.5); | ||||
} | } | ||||
@@ -243,8 +245,8 @@ Size<uint> Window::getSize() const noexcept | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>()); | DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>()); | ||||
const PuglRect rect = puglGetFrame(pData->view); | const PuglRect rect = puglGetFrame(pData->view); | ||||
DISTRHO_SAFE_ASSERT_RETURN(rect.width >= 0.0, Size<uint>()); | |||||
DISTRHO_SAFE_ASSERT_RETURN(rect.height >= 0.0, Size<uint>()); | |||||
DISTRHO_SAFE_ASSERT_RETURN(rect.width > 0.0, Size<uint>()); | |||||
DISTRHO_SAFE_ASSERT_RETURN(rect.height > 0.0, Size<uint>()); | |||||
return Size<uint>(static_cast<uint>(rect.width + 0.5), | return Size<uint>(static_cast<uint>(rect.width + 0.5), | ||||
static_cast<uint>(rect.height + 0.5)); | static_cast<uint>(rect.height + 0.5)); | ||||
} | } | ||||
@@ -269,10 +271,10 @@ void Window::setSize(uint width, uint height) | |||||
uint minWidth = pData->minWidth; | uint minWidth = pData->minWidth; | ||||
uint minHeight = pData->minHeight; | uint minHeight = pData->minHeight; | ||||
if (pData->autoScaling && scaleFactor != 1.0) | |||||
if (pData->autoScaling && d_isNotEqual(scaleFactor, 1.0)) | |||||
{ | { | ||||
minWidth *= scaleFactor; | |||||
minHeight *= scaleFactor; | |||||
minWidth = d_roundToUnsignedInt(minWidth * scaleFactor); | |||||
minHeight = d_roundToUnsignedInt(minHeight * scaleFactor); | |||||
} | } | ||||
// handle geometry constraints here | // handle geometry constraints here | ||||
@@ -293,10 +295,10 @@ void Window::setSize(uint width, uint height) | |||||
{ | { | ||||
// fix width | // fix width | ||||
if (reqRatio > ratio) | if (reqRatio > ratio) | ||||
width = static_cast<uint>(height * ratio + 0.5); | |||||
width = d_roundToUnsignedInt(height * ratio); | |||||
// fix height | // fix height | ||||
else | else | ||||
height = static_cast<uint>(static_cast<double>(width) / ratio + 0.5); | |||||
height = d_roundToUnsignedInt(static_cast<double>(width) / ratio); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -313,6 +315,16 @@ void Window::setSize(uint width, uint height) | |||||
else if (pData->view != nullptr) | else if (pData->view != nullptr) | ||||
{ | { | ||||
puglSetSizeAndDefault(pData->view, width, height); | puglSetSizeAndDefault(pData->view, width, height); | ||||
// there are no resize events for closed windows, so short-circuit the top-level widgets here | |||||
if (pData->isClosed) | |||||
{ | |||||
for (std::list<TopLevelWidget*>::iterator it = pData->topLevelWidgets.begin(), | |||||
end = pData->topLevelWidgets.end(); it != end; ++it) | |||||
{ | |||||
((Widget*)*it)->setSize(width, height); | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -402,7 +414,7 @@ void Window::focus() | |||||
pData->focus(); | pData->focus(); | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
bool Window::openFileBrowser(const FileBrowserOptions& options) | bool Window::openFileBrowser(const FileBrowserOptions& options) | ||||
{ | { | ||||
return pData->openFileBrowser(options); | return pData->openFileBrowser(options); | ||||
@@ -411,8 +423,13 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||||
void Window::repaint() noexcept | void Window::repaint() noexcept | ||||
{ | { | ||||
if (pData->view != nullptr) | |||||
puglPostRedisplay(pData->view); | |||||
if (pData->view == nullptr) | |||||
return; | |||||
if (pData->usesScheduledRepaints) | |||||
pData->appData->needsRepaint = true; | |||||
puglPostRedisplay(pData->view); | |||||
} | } | ||||
void Window::repaint(const Rectangle<uint>& rect) noexcept | void Window::repaint(const Rectangle<uint>& rect) noexcept | ||||
@@ -420,6 +437,9 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||||
if (pData->view == nullptr) | if (pData->view == nullptr) | ||||
return; | return; | ||||
if (pData->usesScheduledRepaints) | |||||
pData->appData->needsRepaint = true; | |||||
PuglRect prect = { | PuglRect prect = { | ||||
static_cast<PuglCoord>(rect.getX()), | static_cast<PuglCoord>(rect.getX()), | ||||
static_cast<PuglCoord>(rect.getY()), | static_cast<PuglCoord>(rect.getY()), | ||||
@@ -430,10 +450,10 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||||
{ | { | ||||
const double autoScaleFactor = pData->autoScaleFactor; | const double autoScaleFactor = pData->autoScaleFactor; | ||||
prect.x *= autoScaleFactor; | |||||
prect.y *= autoScaleFactor; | |||||
prect.width *= autoScaleFactor; | |||||
prect.height *= autoScaleFactor; | |||||
prect.x = static_cast<PuglCoord>(prect.x * autoScaleFactor); | |||||
prect.y = static_cast<PuglCoord>(prect.y * autoScaleFactor); | |||||
prect.width = static_cast<PuglSpan>(prect.width * autoScaleFactor + 0.5); | |||||
prect.height = static_cast<PuglSpan>(prect.height * autoScaleFactor + 0.5); | |||||
} | } | ||||
puglPostRedisplayRect(pData->view, prect); | puglPostRedisplayRect(pData->view, prect); | ||||
} | } | ||||
@@ -479,8 +499,8 @@ void Window::setGeometryConstraints(uint minimumWidth, | |||||
if (automaticallyScale && scaleFactor != 1.0) | if (automaticallyScale && scaleFactor != 1.0) | ||||
{ | { | ||||
minimumWidth *= scaleFactor; | |||||
minimumHeight *= scaleFactor; | |||||
minimumWidth = d_roundToUnsignedInt(minimumWidth * scaleFactor); | |||||
minimumHeight = d_roundToUnsignedInt(minimumHeight * scaleFactor); | |||||
} | } | ||||
puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio); | puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio); | ||||
@@ -554,7 +574,7 @@ void Window::onScaleFactorChanged(double) | |||||
{ | { | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
void Window::onFileSelected(const char*) | void Window::onFileSelected(const char*) | ||||
{ | { | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -115,6 +115,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
isClosed(true), | isClosed(true), | ||||
isVisible(false), | isVisible(false), | ||||
isEmbed(false), | isEmbed(false), | ||||
usesScheduledRepaints(false), | |||||
usesSizeRequest(false), | usesSizeRequest(false), | ||||
scaleFactor(DGL_NAMESPACE::getScaleFactor(view)), | scaleFactor(DGL_NAMESPACE::getScaleFactor(view)), | ||||
autoScaling(false), | autoScaling(false), | ||||
@@ -127,7 +128,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
waitingForClipboardEvents(false), | waitingForClipboardEvents(false), | ||||
clipboardTypeId(0), | clipboardTypeId(0), | ||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | #endif | ||||
modal() | modal() | ||||
@@ -144,6 +145,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
isClosed(true), | isClosed(true), | ||||
isVisible(false), | isVisible(false), | ||||
isEmbed(false), | isEmbed(false), | ||||
usesScheduledRepaints(false), | |||||
usesSizeRequest(false), | usesSizeRequest(false), | ||||
scaleFactor(ppData->scaleFactor), | scaleFactor(ppData->scaleFactor), | ||||
autoScaling(false), | autoScaling(false), | ||||
@@ -156,7 +158,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
waitingForClipboardEvents(false), | waitingForClipboardEvents(false), | ||||
clipboardTypeId(0), | clipboardTypeId(0), | ||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | #endif | ||||
modal(ppData) | modal(ppData) | ||||
@@ -175,6 +177,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
isVisible(parentWindowHandle != 0), | isVisible(parentWindowHandle != 0), | ||||
isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
usesScheduledRepaints(false), | |||||
usesSizeRequest(false), | usesSizeRequest(false), | ||||
scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | ||||
autoScaling(false), | autoScaling(false), | ||||
@@ -187,7 +190,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
waitingForClipboardEvents(false), | waitingForClipboardEvents(false), | ||||
clipboardTypeId(0), | clipboardTypeId(0), | ||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | #endif | ||||
modal() | modal() | ||||
@@ -198,7 +201,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
Window::PrivateData::PrivateData(Application& a, Window* const s, | Window::PrivateData::PrivateData(Application& a, Window* const s, | ||||
const uintptr_t parentWindowHandle, | const uintptr_t parentWindowHandle, | ||||
const uint width, const uint height, | const uint width, const uint height, | ||||
const double scale, const bool resizable, const bool usesSizeRequest_) | |||||
const double scale, const bool resizable, | |||||
const bool _usesScheduledRepaints, | |||||
const bool _usesSizeRequest) | |||||
: app(a), | : app(a), | ||||
appData(a.pData), | appData(a.pData), | ||||
self(s), | self(s), | ||||
@@ -207,7 +212,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
isVisible(parentWindowHandle != 0 && view != nullptr), | isVisible(parentWindowHandle != 0 && view != nullptr), | ||||
isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
usesSizeRequest(usesSizeRequest_), | |||||
usesScheduledRepaints(_usesScheduledRepaints), | |||||
usesSizeRequest(_usesSizeRequest), | |||||
scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | ||||
autoScaling(false), | autoScaling(false), | ||||
autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
@@ -219,7 +225,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
waitingForClipboardEvents(false), | waitingForClipboardEvents(false), | ||||
clipboardTypeId(0), | clipboardTypeId(0), | ||||
filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
fileBrowserHandle(nullptr), | fileBrowserHandle(nullptr), | ||||
#endif | #endif | ||||
modal() | modal() | ||||
@@ -238,7 +244,7 @@ Window::PrivateData::~PrivateData() | |||||
if (isEmbed) | if (isEmbed) | ||||
{ | { | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
if (fileBrowserHandle != nullptr) | if (fileBrowserHandle != nullptr) | ||||
fileBrowserClose(fileBrowserHandle); | fileBrowserClose(fileBrowserHandle); | ||||
#endif | #endif | ||||
@@ -270,18 +276,18 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo | |||||
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | ||||
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE); | puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE); | ||||
#if DGL_USE_RGBA | |||||
#if defined(DGL_USE_RGBA) && DGL_USE_RGBA | |||||
puglSetViewHint(view, PUGL_DEPTH_BITS, 24); | puglSetViewHint(view, PUGL_DEPTH_BITS, 24); | ||||
#else | |||||
#else | |||||
puglSetViewHint(view, PUGL_DEPTH_BITS, 16); | puglSetViewHint(view, PUGL_DEPTH_BITS, 16); | ||||
#endif | |||||
#endif | |||||
puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | ||||
// PUGL_SAMPLES ?? | // PUGL_SAMPLES ?? | ||||
puglSetEventFunc(view, puglEventCallback); | puglSetEventFunc(view, puglEventCallback); | ||||
// setting default size triggers system-level calls, do it last | // setting default size triggers system-level calls, do it last | ||||
puglSetSizeHint(view, PUGL_DEFAULT_SIZE, width, height); | |||||
puglSetSizeHint(view, PUGL_DEFAULT_SIZE, static_cast<PuglSpan>(width), static_cast<PuglSpan>(height)); | |||||
} | } | ||||
bool Window::PrivateData::initPost() | bool Window::PrivateData::initPost() | ||||
@@ -388,7 +394,7 @@ void Window::PrivateData::hide() | |||||
if (modal.enabled) | if (modal.enabled) | ||||
stopModal(); | stopModal(); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
if (fileBrowserHandle != nullptr) | if (fileBrowserHandle != nullptr) | ||||
{ | { | ||||
fileBrowserClose(fileBrowserHandle); | fileBrowserClose(fileBrowserHandle); | ||||
@@ -429,7 +435,7 @@ void Window::PrivateData::setResizable(const bool resizable) | |||||
void Window::PrivateData::idleCallback() | void Window::PrivateData::idleCallback() | ||||
{ | { | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) | if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) | ||||
{ | { | ||||
self->onFileSelected(fileBrowserGetPath(fileBrowserHandle)); | self->onFileSelected(fileBrowserGetPath(fileBrowserHandle)); | ||||
@@ -471,7 +477,7 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | |||||
return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; | return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// file handling | // file handling | ||||
@@ -492,7 +498,7 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||||
return fileBrowserHandle != nullptr; | return fileBrowserHandle != nullptr; | ||||
} | } | ||||
#endif // ! DGL_FILE_BROWSER_DISABLED | |||||
#endif // DGL_USE_FILE_BROWSER | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// modal handling | // modal handling | ||||
@@ -598,7 +604,7 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh | |||||
#ifndef DPF_TEST_WINDOW_CPP | #ifndef DPF_TEST_WINDOW_CPP | ||||
FOR_EACH_TOP_LEVEL_WIDGET(it) | FOR_EACH_TOP_LEVEL_WIDGET(it) | ||||
{ | { | ||||
TopLevelWidget* const widget(*it); | |||||
TopLevelWidget* const widget = *it; | |||||
/* Some special care here, we call Widget::setSize instead of the TopLevelWidget one. | /* Some special care here, we call Widget::setSize instead of the TopLevelWidget one. | ||||
* This is because we want TopLevelWidget::setSize to handle both window and widget size, | * This is because we want TopLevelWidget::setSize to handle both window and widget size, | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -60,7 +60,10 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | ||||
const bool isEmbed; | const bool isEmbed; | ||||
/** Whether to ignore resize requests and feed them into the host instead. used for VST3 */ | |||||
/** Whether to schedule repaints on the next idle call, used for AU */ | |||||
const bool usesScheduledRepaints; | |||||
/** Whether to ignore resize requests and feed them into the host instead, used for CLAP and VST3 */ | |||||
const bool usesSizeRequest; | const bool usesSizeRequest; | ||||
/** Scale factor to report to widgets on request, purely informational. */ | /** Scale factor to report to widgets on request, purely informational. */ | ||||
@@ -87,10 +90,10 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Render to a picture file when non-null, automatically free+unset after saving. */ | /** Render to a picture file when non-null, automatically free+unset after saving. */ | ||||
char* filenameToRenderInto; | char* filenameToRenderInto; | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
/** Handle for file browser dialog operations. */ | /** Handle for file browser dialog operations. */ | ||||
DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle; | DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle; | ||||
#endif | |||||
#endif | |||||
/** Modal window setup. */ | /** Modal window setup. */ | ||||
struct Modal { | struct Modal { | ||||
@@ -131,7 +134,8 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Constructor for an embed Window, with a few extra hints from the host side. */ | /** Constructor for an embed Window, with a few extra hints from the host side. */ | ||||
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | ||||
uint width, uint height, double scaling, bool resizable, bool isVST3); | |||||
uint width, uint height, double scaling, bool resizable, | |||||
bool usesScheduledRepaints, bool usesSizeRequest); | |||||
/** Destructor. */ | /** Destructor. */ | ||||
~PrivateData() override; | ~PrivateData() override; | ||||
@@ -164,10 +168,10 @@ struct Window::PrivateData : IdleCallback { | |||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | ||||
bool removeIdleCallback(IdleCallback* callback); | bool removeIdleCallback(IdleCallback* callback); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
#ifdef DGL_USE_FILE_BROWSER | |||||
// file handling | // file handling | ||||
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); | bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); | ||||
#endif | |||||
#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); | ||||
@@ -6,9 +6,11 @@ Checks: > | |||||
-*-magic-numbers, | -*-magic-numbers, | ||||
-altera*, | -altera*, | ||||
-bugprone-assignment-in-if-condition, | -bugprone-assignment-in-if-condition, | ||||
-bugprone-switch-missing-default-case, | |||||
-clang-diagnostic-unused-function, | -clang-diagnostic-unused-function, | ||||
-clang-diagnostic-unused-macros, | -clang-diagnostic-unused-macros, | ||||
-llvmlibc-*, | -llvmlibc-*, | ||||
-misc-include-cleaner, | |||||
-readability-identifier-length, | -readability-identifier-length, | ||||
CheckOptions: | CheckOptions: | ||||
- key: hicpp-uppercase-literal-suffix.NewSuffixes | - key: hicpp-uppercase-literal-suffix.NewSuffixes | ||||
@@ -145,7 +145,7 @@ typedef uint32_t PuglEventFlags; | |||||
typedef enum { | typedef enum { | ||||
PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion | PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion | ||||
PUGL_CROSSING_GRAB, ///< Crossing due to a grab | PUGL_CROSSING_GRAB, ///< Crossing due to a grab | ||||
PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release | |||||
PUGL_CROSSING_UNGRAB, ///< Crossing due to a grab release | |||||
} PuglCrossingMode; | } PuglCrossingMode; | ||||
/// Common header for all event structs | /// Common header for all event structs | ||||
@@ -342,6 +342,7 @@ typedef struct { | |||||
*/ | */ | ||||
typedef enum { | typedef enum { | ||||
PUGL_KEY_BACKSPACE = 0x00000008U, ///< Backspace | PUGL_KEY_BACKSPACE = 0x00000008U, ///< Backspace | ||||
PUGL_KEY_TAB = 0x00000009U, ///< Tab | |||||
PUGL_KEY_ENTER = 0x0000000DU, ///< Enter | PUGL_KEY_ENTER = 0x0000000DU, ///< Enter | ||||
PUGL_KEY_ESCAPE = 0x0000001BU, ///< Escape | PUGL_KEY_ESCAPE = 0x0000001BU, ///< Escape | ||||
PUGL_KEY_DELETE = 0x0000007FU, ///< Delete | PUGL_KEY_DELETE = 0x0000007FU, ///< Delete | ||||
@@ -414,10 +415,13 @@ typedef enum { | |||||
/// Keyboard modifier flags | /// Keyboard modifier flags | ||||
typedef enum { | typedef enum { | ||||
PUGL_MOD_SHIFT = 1U << 0U, ///< Shift key | |||||
PUGL_MOD_CTRL = 1U << 1U, ///< Control key | |||||
PUGL_MOD_ALT = 1U << 2U, ///< Alt/Option key | |||||
PUGL_MOD_SUPER = 1U << 3U ///< Mod4/Command/Windows key | |||||
PUGL_MOD_SHIFT = 1U << 0U, ///< Shift pressed | |||||
PUGL_MOD_CTRL = 1U << 1U, ///< Control pressed | |||||
PUGL_MOD_ALT = 1U << 2U, ///< Alt/Option pressed | |||||
PUGL_MOD_SUPER = 1U << 3U, ///< Super/Command/Windows pressed | |||||
PUGL_MOD_NUM_LOCK = 1U << 4U, ///< Num lock enabled | |||||
PUGL_MOD_SCROLL_LOCK = 1U << 5U, ///< Scroll lock enabled | |||||
PUGL_MOD_CAPS_LOCK = 1U << 6U, ///< Caps lock enabled | |||||
} PuglMod; | } PuglMod; | ||||
/// Bitwise OR of #PuglMod values | /// Bitwise OR of #PuglMod values | ||||
@@ -505,11 +509,11 @@ typedef struct { | |||||
arbitrary scroll direction freedom, like some touchpads. | arbitrary scroll direction freedom, like some touchpads. | ||||
*/ | */ | ||||
typedef enum { | typedef enum { | ||||
PUGL_SCROLL_UP, ///< Scroll up | |||||
PUGL_SCROLL_DOWN, ///< Scroll down | |||||
PUGL_SCROLL_LEFT, ///< Scroll left | |||||
PUGL_SCROLL_RIGHT, ///< Scroll right | |||||
PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction | |||||
PUGL_SCROLL_UP, ///< Scroll up | |||||
PUGL_SCROLL_DOWN, ///< Scroll down | |||||
PUGL_SCROLL_LEFT, ///< Scroll left | |||||
PUGL_SCROLL_RIGHT, ///< Scroll right | |||||
PUGL_SCROLL_SMOOTH, ///< Smooth scroll in any direction | |||||
} PuglScrollDirection; | } PuglScrollDirection; | ||||
/** | /** | ||||
@@ -763,7 +767,7 @@ typedef void* PuglWorldHandle; | |||||
/// The type of a World | /// The type of a World | ||||
typedef enum { | typedef enum { | ||||
PUGL_PROGRAM, ///< Top-level application | PUGL_PROGRAM, ///< Top-level application | ||||
PUGL_MODULE ///< Plugin or module within a larger application | |||||
PUGL_MODULE, ///< Plugin or module within a larger application | |||||
} PuglWorldType; | } PuglWorldType; | ||||
/// World flags | /// World flags | ||||
@@ -773,7 +777,7 @@ typedef enum { | |||||
X11: Calls XInitThreads() which is required for some drivers. | X11: Calls XInitThreads() which is required for some drivers. | ||||
*/ | */ | ||||
PUGL_WORLD_THREADS = 1U << 0U | |||||
PUGL_WORLD_THREADS = 1U << 0U, | |||||
} PuglWorldFlag; | } PuglWorldFlag; | ||||
/// Bitwise OR of #PuglWorldFlag values | /// Bitwise OR of #PuglWorldFlag values | ||||
@@ -1023,7 +1027,7 @@ typedef enum { | |||||
If set, the view's size should be constrained to an aspect ratio no higher | If set, the view's size should be constrained to an aspect ratio no higher | ||||
than this. Mutually exclusive with #PUGL_FIXED_ASPECT. | than this. Mutually exclusive with #PUGL_FIXED_ASPECT. | ||||
*/ | */ | ||||
PUGL_MAX_ASPECT | |||||
PUGL_MAX_ASPECT, | |||||
} PuglSizeHint; | } PuglSizeHint; | ||||
/// The number of #PuglSizeHint values | /// The number of #PuglSizeHint values | ||||
@@ -1569,7 +1573,8 @@ puglGetClipboard(PuglView* view, uint32_t typeIndex, size_t* len); | |||||
for example if compiled on X11 without Xcursor support. | for example if compiled on X11 without Xcursor support. | ||||
@return #PUGL_BAD_PARAMETER if the given cursor is invalid, | @return #PUGL_BAD_PARAMETER if the given cursor is invalid, | ||||
#PUGL_FAILURE if the cursor is known but loading it system fails. | |||||
#PUGL_UNSUPPORTED if setting the cursor is not supported on this system, or | |||||
another error if the cursor is known but loading it fails. | |||||
*/ | */ | ||||
PUGL_API | PUGL_API | ||||
PuglStatus | PuglStatus | ||||
@@ -146,12 +146,20 @@ puglNewView(PuglWorld* const world) | |||||
puglSetDefaultHints(view->hints); | puglSetDefaultHints(view->hints); | ||||
// Add to world view list | |||||
++world->numViews; | |||||
world->views = | |||||
(PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*)); | |||||
// Enlarge world view list | |||||
const size_t newNumViews = world->numViews + 1U; | |||||
PuglView** const views = | |||||
(PuglView**)realloc(world->views, newNumViews * sizeof(PuglView*)); | |||||
if (!views) { | |||||
free(view); | |||||
return NULL; | |||||
} | |||||
world->views[world->numViews - 1] = view; | |||||
// Add to world view list | |||||
world->views = views; | |||||
world->views[world->numViews] = view; | |||||
world->numViews = newNumViews; | |||||
return view; | return view; | ||||
} | } | ||||
@@ -132,6 +132,12 @@ puglFilterMods(const PuglMods state, const PuglKey key) | |||||
case PUGL_KEY_SUPER_L: | case PUGL_KEY_SUPER_L: | ||||
case PUGL_KEY_SUPER_R: | case PUGL_KEY_SUPER_R: | ||||
return state & ~(PuglMods)PUGL_MOD_SUPER; | return state & ~(PuglMods)PUGL_MOD_SUPER; | ||||
case PUGL_KEY_NUM_LOCK: | |||||
return state & ~(PuglMods)PUGL_MOD_NUM_LOCK; | |||||
case PUGL_KEY_SCROLL_LOCK: | |||||
return state & ~(PuglMods)PUGL_MOD_SCROLL_LOCK; | |||||
case PUGL_KEY_CAPS_LOCK: | |||||
return state & ~(PuglMods)PUGL_MOD_CAPS_LOCK; | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
@@ -15,6 +15,7 @@ | |||||
#include <mach/mach_time.h> | #include <mach/mach_time.h> | ||||
#include <stdint.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#ifndef __MAC_10_10 | #ifndef __MAC_10_10 | ||||
@@ -325,11 +326,14 @@ dispatchCurrentChildViewConfiguration(PuglView* const view) | |||||
return; | return; | ||||
} | } | ||||
const double viewY = (double)puglview->lastConfigure.height - | |||||
((rect.origin.y + rect.size.height) * scaleFactor); | |||||
const PuglExposeEvent ev = { | const PuglExposeEvent ev = { | ||||
PUGL_EXPOSE, | PUGL_EXPOSE, | ||||
0, | 0, | ||||
(PuglCoord)(rect.origin.x * scaleFactor), | (PuglCoord)(rect.origin.x * scaleFactor), | ||||
(PuglCoord)(rect.origin.y * scaleFactor), | |||||
(PuglCoord)viewY, | |||||
(PuglSpan)(rect.size.width * scaleFactor), | (PuglSpan)(rect.size.width * scaleFactor), | ||||
(PuglSpan)(rect.size.height * scaleFactor), | (PuglSpan)(rect.size.height * scaleFactor), | ||||
}; | }; | ||||
@@ -371,7 +375,8 @@ getModifiers(const NSEvent* const ev) | |||||
return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) | | return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) | | ||||
((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) | | ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) | | ||||
((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) | | ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) | | ||||
((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0)); | |||||
((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0) | | |||||
((modifierFlags & (1U << 16U)) ? PUGL_MOD_CAPS_LOCK : 0)); | |||||
} | } | ||||
static PuglKey | static PuglKey | ||||
@@ -625,10 +630,16 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) | |||||
- (void)scrollWheel:(NSEvent*)event | - (void)scrollWheel:(NSEvent*)event | ||||
{ | { | ||||
const NSPoint wloc = [self eventLocation:event]; | |||||
const NSPoint rloc = [NSEvent mouseLocation]; | |||||
const double dx = -[event scrollingDeltaX]; | |||||
const double dy = [event scrollingDeltaY]; | |||||
const NSPoint wloc = [self eventLocation:event]; | |||||
const NSPoint rloc = [NSEvent mouseLocation]; | |||||
double dx = -[event scrollingDeltaX]; | |||||
double dy = [event scrollingDeltaY]; | |||||
if (![event hasPreciseScrollingDeltas]) { | |||||
dx *= 10.0; | |||||
dy *= 10.0; | |||||
} | |||||
const PuglScrollDirection dir = | const PuglScrollDirection dir = | ||||
((dx == 0.0 && dy > 0.0) | ((dx == 0.0 && dy > 0.0) | ||||
? PUGL_SCROLL_UP | ? PUGL_SCROLL_UP | ||||
@@ -648,7 +659,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) | |||||
rloc.x, | rloc.x, | ||||
[[NSScreen mainScreen] frame].size.height - rloc.y, | [[NSScreen mainScreen] frame].size.height - rloc.y, | ||||
getModifiers(event), | getModifiers(event), | ||||
[event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir, | |||||
dir, | |||||
dx, | dx, | ||||
dy, | dy, | ||||
}; | }; | ||||
@@ -836,32 +847,36 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) | |||||
} | } | ||||
} | } | ||||
static bool | |||||
flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask) | |||||
{ | |||||
return (lhs & mask) != (rhs & mask); | |||||
} | |||||
- (void)flagsChanged:(NSEvent*)event | - (void)flagsChanged:(NSEvent*)event | ||||
{ | { | ||||
const uint32_t mods = getModifiers(event); | const uint32_t mods = getModifiers(event); | ||||
PuglEventType type = PUGL_NOTHING; | |||||
PuglKey special = (PuglKey)0; | PuglKey special = (PuglKey)0; | ||||
if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) { | |||||
type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; | |||||
special = PUGL_KEY_SHIFT_L; | |||||
} else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) { | |||||
type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; | |||||
special = PUGL_KEY_CTRL_L; | |||||
} else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) { | |||||
type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; | |||||
special = PUGL_KEY_ALT_L; | |||||
} else if ((mods & PUGL_MOD_SUPER) != | |||||
(puglview->impl->mods & PUGL_MOD_SUPER)) { | |||||
type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; | |||||
special = PUGL_KEY_SUPER_L; | |||||
const uint16_t keyCode = [event keyCode]; | |||||
if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_SHIFT)) { | |||||
special = (keyCode == 0x3C) ? PUGL_KEY_SHIFT_R : PUGL_KEY_SHIFT_L; | |||||
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_CTRL)) { | |||||
special = (keyCode == 0x3E) ? PUGL_KEY_CTRL_R : PUGL_KEY_CTRL_L; | |||||
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_ALT)) { | |||||
special = (keyCode == 0x3D) ? PUGL_KEY_ALT_R : PUGL_KEY_ALT_L; | |||||
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_SUPER)) { | |||||
special = PUGL_KEY_SUPER_L; // Left and right command are identical | |||||
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_CAPS_LOCK)) { | |||||
special = PUGL_KEY_CAPS_LOCK; | |||||
} | } | ||||
if (special != 0) { | if (special != 0) { | ||||
const NSPoint wloc = [self eventLocation:event]; | |||||
const NSPoint rloc = [NSEvent mouseLocation]; | |||||
const NSPoint wloc = [self eventLocation:event]; | |||||
const NSPoint rloc = [NSEvent mouseLocation]; | |||||
const bool release = [event type] == NSEventTypeKeyUp; | |||||
const PuglKeyEvent ev = {type, | |||||
const PuglKeyEvent ev = {release ? PUGL_KEY_RELEASE : PUGL_KEY_PRESS, | |||||
0, | 0, | ||||
[event timestamp], | [event timestamp], | ||||
wloc.x, | wloc.x, | ||||
@@ -93,10 +93,8 @@ puglMacCairoEnter(PuglView* view, const PuglExposeEvent* expose) | |||||
const CGSize sizePx = {(CGFloat)view->lastConfigure.width, | const CGSize sizePx = {(CGFloat)view->lastConfigure.width, | ||||
(CGFloat)view->lastConfigure.height}; | (CGFloat)view->lastConfigure.height}; | ||||
const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); | |||||
// Convert coordinates to standard Cairo space | // Convert coordinates to standard Cairo space | ||||
CGContextTranslateCTM(context, 0.0, sizePt.height); | |||||
CGContextTranslateCTM(context, 0.0, sizePx.height * scale); | |||||
CGContextScaleCTM(context, scale, -scale); | CGContextScaleCTM(context, scale, -scale); | ||||
drawView->surface = cairo_quartz_surface_create_for_cg_context( | drawView->surface = cairo_quartz_surface_create_for_cg_context( | ||||
@@ -94,6 +94,12 @@ puglWinStatus(const BOOL success) | |||||
static bool | static bool | ||||
puglRegisterWindowClass(const char* name) | puglRegisterWindowClass(const char* name) | ||||
{ | { | ||||
#ifdef UNICODE | |||||
wchar_t* const wname = puglUtf8ToWideChar(name); | |||||
#else | |||||
const char* const wname = name; | |||||
#endif | |||||
HMODULE module = NULL; | HMODULE module = NULL; | ||||
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | | if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | | ||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | ||||
@@ -103,7 +109,7 @@ puglRegisterWindowClass(const char* name) | |||||
} | } | ||||
WNDCLASSEX wc = PUGL_INIT_STRUCT; | WNDCLASSEX wc = PUGL_INIT_STRUCT; | ||||
if (GetClassInfoEx(module, name, &wc)) { | |||||
if (GetClassInfoEx(module, wname, &wc)) { | |||||
return true; // Already registered | return true; // Already registered | ||||
} | } | ||||
@@ -114,9 +120,13 @@ puglRegisterWindowClass(const char* name) | |||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | ||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW); | wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||||
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | ||||
wc.lpszClassName = name; | |||||
wc.lpszClassName = wname; | |||||
return !!RegisterClassEx(&wc); | |||||
const bool success = !!RegisterClassEx(&wc); | |||||
#ifdef UNICODE | |||||
free(wname); | |||||
#endif | |||||
return success; | |||||
} | } | ||||
static unsigned | static unsigned | ||||
@@ -174,7 +184,7 @@ static double | |||||
puglWinGetViewScaleFactor(const PuglView* const view) | puglWinGetViewScaleFactor(const PuglView* const view) | ||||
{ | { | ||||
const HMODULE shcore = | const HMODULE shcore = | ||||
LoadLibraryEx("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); | |||||
LoadLibraryExA("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); | |||||
if (!shcore) { | if (!shcore) { | ||||
return 1.0; | return 1.0; | ||||
} | } | ||||
@@ -209,7 +219,7 @@ puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) | |||||
if (type == PUGL_PROGRAM) { | if (type == PUGL_PROGRAM) { | ||||
HMODULE user32 = | HMODULE user32 = | ||||
LoadLibraryEx("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); | |||||
LoadLibraryExA("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); | |||||
if (user32) { | if (user32) { | ||||
PFN_SetProcessDPIAware SetProcessDPIAware = | PFN_SetProcessDPIAware SetProcessDPIAware = | ||||
(PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware"); | (PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware"); | ||||
@@ -398,7 +408,14 @@ puglFreeViewInternals(PuglView* view) | |||||
void | void | ||||
puglFreeWorldInternals(PuglWorld* world) | puglFreeWorldInternals(PuglWorld* world) | ||||
{ | { | ||||
#ifdef UNICODE | |||||
wchar_t* const wname = puglUtf8ToWideChar(world->strings[PUGL_CLASS_NAME]); | |||||
UnregisterClass(wname, NULL); | |||||
free(wname); | |||||
#else | |||||
UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL); | UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL); | ||||
#endif | |||||
free(world->impl); | free(world->impl); | ||||
} | } | ||||
@@ -472,11 +489,15 @@ static uint32_t | |||||
getModifiers(void) | getModifiers(void) | ||||
{ | { | ||||
// clang-format off | // clang-format off | ||||
return (((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) | | |||||
((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) | | |||||
((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) | | |||||
((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) | | |||||
((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U)); | |||||
return ( | |||||
((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) | | |||||
((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) | | |||||
((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) | | |||||
((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) | | |||||
((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) | | |||||
((GetKeyState(VK_NUMLOCK) & 1U) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) | | |||||
((GetKeyState(VK_SCROLL) & 1U) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) | | |||||
((GetKeyState(VK_CAPITAL) & 1U) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U)); | |||||
// clang-format on | // clang-format on | ||||
} | } | ||||
@@ -1477,7 +1498,7 @@ puglPaste(PuglView* const view) | |||||
return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
} | } | ||||
static const char* const cursor_ids[] = { | |||||
static const TCHAR* const cursor_ids[] = { | |||||
IDC_ARROW, // ARROW | IDC_ARROW, // ARROW | ||||
IDC_IBEAM, // CARET | IDC_IBEAM, // CARET | ||||
IDC_CROSS, // CROSSHAIR | IDC_CROSS, // CROSSHAIR | ||||
@@ -1602,18 +1623,18 @@ puglWinCreateWindow(PuglView* const view, | |||||
AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); | AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); | ||||
// Create window and get drawing context | // Create window and get drawing context | ||||
if (!(*hwnd = CreateWindowEx(winExFlags, | |||||
className, | |||||
title, | |||||
winFlags, | |||||
wr.left, | |||||
wr.right, | |||||
wr.right - wr.left, | |||||
wr.bottom - wr.top, | |||||
(HWND)parent, | |||||
NULL, | |||||
NULL, | |||||
NULL))) { | |||||
if (!(*hwnd = CreateWindowExA(winExFlags, | |||||
className, | |||||
title, | |||||
winFlags, | |||||
wr.left, | |||||
wr.right, | |||||
wr.right - wr.left, | |||||
wr.bottom - wr.top, | |||||
(HWND)parent, | |||||
NULL, | |||||
NULL, | |||||
NULL))) { | |||||
return PUGL_REALIZE_FAILED; | return PUGL_REALIZE_FAILED; | ||||
} | } | ||||
@@ -288,7 +288,7 @@ puglGetProcAddress(const char* name) | |||||
return func | return func | ||||
? func | ? func | ||||
: (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name); | |||||
: (PuglGlFunc)GetProcAddress(GetModuleHandleA("opengl32.dll"), name); | |||||
} | } | ||||
PuglStatus | PuglStatus | ||||
@@ -32,7 +32,7 @@ puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world), | |||||
const char* const filename = libraryName ? libraryName : "vulkan-1.dll"; | const char* const filename = libraryName ? libraryName : "vulkan-1.dll"; | ||||
if (!(loader->libvulkan = | if (!(loader->libvulkan = | ||||
LoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS))) { | |||||
LoadLibraryExA(filename, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS))) { | |||||
free(loader); | free(loader); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
@@ -416,8 +416,9 @@ updateSizeHints(const PuglView* const view) | |||||
sizeHints.max_width = (int)frame.width; | sizeHints.max_width = (int)frame.width; | ||||
sizeHints.max_height = (int)frame.height; | sizeHints.max_height = (int)frame.height; | ||||
} else { | } else { | ||||
// Avoid setting PBaseSize for top level views to avoid window manager bugs | |||||
const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; | const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; | ||||
if (puglIsValidSize(defaultSize)) { | |||||
if (puglIsValidSize(defaultSize) && view->parent) { | |||||
sizeHints.flags |= PBaseSize; | sizeHints.flags |= PBaseSize; | ||||
sizeHints.base_width = defaultSize.width; | sizeHints.base_width = defaultSize.width; | ||||
sizeHints.base_height = defaultSize.height; | sizeHints.base_height = defaultSize.height; | ||||
@@ -881,7 +882,8 @@ translateKey(PuglView* const view, XEvent* const xevent, PuglEvent* const event) | |||||
event->key.keycode = xevent->xkey.keycode; | event->key.keycode = xevent->xkey.keycode; | ||||
// Mask off the control and shift bits to get the lowercase "main" symbol | // Mask off the control and shift bits to get the lowercase "main" symbol | ||||
xevent->xkey.state = xevent->xkey.state & ~(unsigned)(ControlMask|ShiftMask); | |||||
xevent->xkey.state = | |||||
xevent->xkey.state & ~(unsigned)(ControlMask | ShiftMask); | |||||
// Lookup unshifted key | // Lookup unshifted key | ||||
char ustr[8] = PUGL_INIT_STRUCT; | char ustr[8] = PUGL_INIT_STRUCT; | ||||
@@ -919,7 +921,10 @@ translateModifiers(const unsigned xstate) | |||||
return (((xstate & ShiftMask) ? (uint32_t)PUGL_MOD_SHIFT : 0U) | | return (((xstate & ShiftMask) ? (uint32_t)PUGL_MOD_SHIFT : 0U) | | ||||
((xstate & ControlMask) ? (uint32_t)PUGL_MOD_CTRL : 0U) | | ((xstate & ControlMask) ? (uint32_t)PUGL_MOD_CTRL : 0U) | | ||||
((xstate & Mod1Mask) ? (uint32_t)PUGL_MOD_ALT : 0U) | | ((xstate & Mod1Mask) ? (uint32_t)PUGL_MOD_ALT : 0U) | | ||||
((xstate & Mod4Mask) ? (uint32_t)PUGL_MOD_SUPER : 0U)); | |||||
((xstate & Mod4Mask) ? (uint32_t)PUGL_MOD_SUPER : 0U) | | |||||
((xstate & Mod2Mask) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) | | |||||
((xstate & Mod3Mask) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) | | |||||
((xstate & LockMask) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U)); | |||||
} | } | ||||
static PuglStatus | static PuglStatus | ||||
@@ -957,28 +962,37 @@ getX11SelectionClipboard(PuglView* const view, const Atom selection) | |||||
: NULL; | : NULL; | ||||
} | } | ||||
static void | |||||
static PuglStatus | |||||
setClipboardFormats(PuglView* const view, | setClipboardFormats(PuglView* const view, | ||||
PuglX11Clipboard* const board, | PuglX11Clipboard* const board, | ||||
const unsigned long numFormats, | const unsigned long numFormats, | ||||
const Atom* const formats) | const Atom* const formats) | ||||
{ | { | ||||
Atom* const newFormats = | |||||
(Atom*)realloc(board->formats, numFormats * sizeof(Atom)); | |||||
if (!newFormats) { | |||||
return; | |||||
} | |||||
// Clear current board formats | |||||
for (unsigned long i = 0; i < board->numFormats; ++i) { | for (unsigned long i = 0; i < board->numFormats; ++i) { | ||||
free(board->formatStrings[i]); | free(board->formatStrings[i]); | ||||
board->formatStrings[i] = NULL; | board->formatStrings[i] = NULL; | ||||
} | } | ||||
board->formats = newFormats; | |||||
board->numFormats = 0; | board->numFormats = 0; | ||||
board->formatStrings = | |||||
// Enlarge formats array | |||||
Atom* const newFormats = | |||||
(Atom*)realloc(board->formats, numFormats * sizeof(Atom)); | |||||
if (!newFormats) { | |||||
return PUGL_NO_MEMORY; | |||||
} | |||||
board->formats = newFormats; | |||||
// Enlarge format strings array | |||||
char** const newFormatStrings = | |||||
(char**)realloc(board->formatStrings, numFormats * sizeof(char*)); | (char**)realloc(board->formatStrings, numFormats * sizeof(char*)); | ||||
if (!newFormatStrings) { | |||||
return PUGL_NO_MEMORY; | |||||
} | |||||
board->formatStrings = newFormatStrings; | |||||
for (unsigned long i = 0; i < numFormats; ++i) { | for (unsigned long i = 0; i < numFormats; ++i) { | ||||
if (formats[i]) { | if (formats[i]) { | ||||
@@ -1005,6 +1019,8 @@ setClipboardFormats(PuglView* const view, | |||||
XFree(name); | XFree(name); | ||||
} | } | ||||
} | } | ||||
return PUGL_SUCCESS; | |||||
} | } | ||||
static PuglEvent | static PuglEvent | ||||
@@ -1390,10 +1406,13 @@ puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout) | |||||
} | } | ||||
// Add new timer | // Add new timer | ||||
const size_t size = ++w->numTimers * sizeof(timer); | |||||
w->timers = (PuglTimer*)realloc(w->timers, size); | |||||
w->timers[w->numTimers - 1] = timer; | |||||
return PUGL_SUCCESS; | |||||
const size_t size = ++w->numTimers * sizeof(timer); | |||||
PuglTimer* const newTimers = (PuglTimer*)realloc(w->timers, size); | |||||
if (newTimers) { | |||||
w->timers = newTimers; | |||||
w->timers[w->numTimers - 1] = timer; | |||||
return PUGL_SUCCESS; | |||||
} | |||||
} | } | ||||
} | } | ||||
#else | #else | ||||
@@ -1583,7 +1602,7 @@ retrieveSelection(const PuglWorld* const world, | |||||
return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
} | } | ||||
static void | |||||
static PuglStatus | |||||
handleSelectionNotify(const PuglWorld* const world, | handleSelectionNotify(const PuglWorld* const world, | ||||
PuglView* const view, | PuglView* const view, | ||||
const XSelectionEvent* const event) | const XSelectionEvent* const event) | ||||
@@ -1600,9 +1619,8 @@ handleSelectionNotify(const PuglWorld* const world, | |||||
unsigned long numFormats = 0; | unsigned long numFormats = 0; | ||||
Atom* formats = NULL; | Atom* formats = NULL; | ||||
if (!getAtomProperty( | if (!getAtomProperty( | ||||
view, event->requestor, event->property, &numFormats, &formats)) { | |||||
setClipboardFormats(view, board, numFormats, formats); | |||||
view, event->requestor, event->property, &numFormats, &formats) && | |||||
!setClipboardFormats(view, board, numFormats, formats)) { | |||||
const PuglDataOfferEvent offer = { | const PuglDataOfferEvent offer = { | ||||
PUGL_DATA_OFFER, 0, (double)event->time / 1e3}; | PUGL_DATA_OFFER, 0, (double)event->time / 1e3}; | ||||
@@ -1628,7 +1646,7 @@ handleSelectionNotify(const PuglWorld* const world, | |||||
} | } | ||||
} | } | ||||
puglDispatchEvent(view, &puglEvent); | |||||
return puglDispatchEvent(view, &puglEvent); | |||||
} | } | ||||
static PuglStatus | static PuglStatus | ||||
@@ -1754,8 +1772,7 @@ handleTimerEvent(PuglWorld* const world, const XEvent xevent) | |||||
static PuglStatus | static PuglStatus | ||||
dispatchX11Events(PuglWorld* const world) | dispatchX11Events(PuglWorld* const world) | ||||
{ | { | ||||
PuglStatus st0 = PUGL_SUCCESS; | |||||
PuglStatus st1 = PUGL_SUCCESS; | |||||
PuglStatus st = PUGL_SUCCESS; | |||||
// Flush output to the server once at the start | // Flush output to the server once at the start | ||||
Display* display = world->impl->display; | Display* display = world->impl->display; | ||||
@@ -1791,9 +1808,13 @@ dispatchX11Events(PuglWorld* const world) | |||||
clearX11Clipboard(board); | clearX11Clipboard(board); | ||||
} | } | ||||
} else if (xevent.type == SelectionNotify) { | } else if (xevent.type == SelectionNotify) { | ||||
handleSelectionNotify(world, view, &xevent.xselection); | |||||
st = handleSelectionNotify(world, view, &xevent.xselection); | |||||
} else if (xevent.type == SelectionRequest) { | } else if (xevent.type == SelectionRequest) { | ||||
handleSelectionRequest(world, view, &xevent.xselectionrequest); | |||||
st = handleSelectionRequest(world, view, &xevent.xselectionrequest); | |||||
} | |||||
if (st) { | |||||
break; | |||||
} | } | ||||
// Translate X11 event to Pugl event | // Translate X11 event to Pugl event | ||||
@@ -1822,12 +1843,12 @@ dispatchX11Events(PuglWorld* const world) | |||||
break; | break; | ||||
default: | default: | ||||
// Dispatch event to application immediately | // Dispatch event to application immediately | ||||
st0 = puglDispatchEvent(view, &event); | |||||
st = puglDispatchEvent(view, &event); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return st0 ? st0 : st1; | |||||
return st; | |||||
} | } | ||||
#ifndef PUGL_DISABLE_DEPRECATED | #ifndef PUGL_DISABLE_DEPRECATED | ||||
@@ -2042,7 +2063,7 @@ puglSetTransientParent(PuglView* const view, const PuglNativeView parent) | |||||
view->transientParent = parent; | view->transientParent = parent; | ||||
if (view->impl->win) { | |||||
if (view->impl->win && view->transientParent) { | |||||
XSetTransientForHint( | XSetTransientForHint( | ||||
display, view->impl->win, (Window)view->transientParent); | display, view->impl->win, (Window)view->transientParent); | ||||
} | } | ||||
@@ -2138,12 +2159,12 @@ puglSetClipboard(PuglView* const view, | |||||
PuglInternals* const impl = view->impl; | PuglInternals* const impl = view->impl; | ||||
Display* const display = view->world->impl->display; | Display* const display = view->world->impl->display; | ||||
PuglX11Clipboard* const board = &view->impl->clipboard; | PuglX11Clipboard* const board = &view->impl->clipboard; | ||||
const PuglStatus st = puglSetBlob(&board->data, data, len); | |||||
PuglStatus st = puglSetBlob(&board->data, data, len); | |||||
if (!st) { | if (!st) { | ||||
const Atom format = {XInternAtom(display, type, 0)}; | const Atom format = {XInternAtom(display, type, 0)}; | ||||
setClipboardFormats(view, board, 1, &format); | |||||
st = setClipboardFormats(view, board, 1, &format); | |||||
XSetSelectionOwner(display, board->selection, impl->win, CurrentTime); | XSetSelectionOwner(display, board->selection, impl->win, CurrentTime); | ||||
board->source = impl->win; | board->source = impl->win; | ||||
@@ -2174,7 +2195,7 @@ puglSetCursor(PuglView* const view, const PuglCursor cursor) | |||||
#else | #else | ||||
(void)view; | (void)view; | ||||
(void)cursor; | (void)cursor; | ||||
return PUGL_FAILURE; | |||||
return PUGL_UNSUPPORTED; | |||||
#endif | #endif | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -138,15 +138,18 @@ START_NAMESPACE_DGL | |||||
# endif | # endif | ||||
#elif defined(DISTRHO_OS_MAC) | #elif defined(DISTRHO_OS_MAC) | ||||
# ifndef DISTRHO_MACOS_NAMESPACE_MACRO | # ifndef DISTRHO_MACOS_NAMESPACE_MACRO | ||||
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE | |||||
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE) | |||||
# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglCairoView) | |||||
# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglOpenGLView) | |||||
# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView) | |||||
# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglVulkanView) | |||||
# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow) | |||||
# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindowDelegate) | |||||
# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView) | |||||
# ifndef DISTRHO_MACOS_NAMESPACE_TIME | |||||
# define DISTRHO_MACOS_NAMESPACE_TIME __apple_build_version__ | |||||
# endif | |||||
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, TIME, INTERFACE) NS ## SEP ## TIME ## SEP ## INTERFACE | |||||
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, TIME, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, TIME, INTERFACE) | |||||
# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglCairoView) | |||||
# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglOpenGLView) | |||||
# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglStubView) | |||||
# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglVulkanView) | |||||
# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindow) | |||||
# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindowDelegate) | |||||
# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWrapperView) | |||||
# endif | # endif | ||||
# pragma clang diagnostic push | # pragma clang diagnostic push | ||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations" | # pragma clang diagnostic ignored "-Wdeprecated-declarations" | ||||
@@ -181,7 +184,14 @@ START_NAMESPACE_DGL | |||||
# include "pugl-upstream/src/win_vulkan.c" | # include "pugl-upstream/src/win_vulkan.c" | ||||
# endif | # endif | ||||
#elif defined(HAVE_X11) | #elif defined(HAVE_X11) | ||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wsign-conversion" | |||||
# endif | |||||
# include "pugl-upstream/src/x11.c" | # include "pugl-upstream/src/x11.c" | ||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
# include "pugl-upstream/src/x11_stub.c" | # include "pugl-upstream/src/x11_stub.c" | ||||
# ifdef DGL_CAIRO | # ifdef DGL_CAIRO | ||||
# include "pugl-upstream/src/x11_cairo.c" | # include "pugl-upstream/src/x11_cairo.c" | ||||
@@ -277,13 +287,13 @@ void puglRaiseWindow(PuglView* const view) | |||||
PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect) | PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect) | ||||
{ | { | ||||
view->sizeHints[PUGL_MIN_SIZE].width = width; | |||||
view->sizeHints[PUGL_MIN_SIZE].height = height; | |||||
view->sizeHints[PUGL_MIN_SIZE].width = static_cast<PuglSpan>(width); | |||||
view->sizeHints[PUGL_MIN_SIZE].height = static_cast<PuglSpan>(height); | |||||
if (aspect) | if (aspect) | ||||
{ | { | ||||
view->sizeHints[PUGL_FIXED_ASPECT].width = width; | |||||
view->sizeHints[PUGL_FIXED_ASPECT].height = height; | |||||
view->sizeHints[PUGL_FIXED_ASPECT].width = static_cast<PuglSpan>(width); | |||||
view->sizeHints[PUGL_FIXED_ASPECT].height = static_cast<PuglSpan>(height); | |||||
} | } | ||||
#if defined(DISTRHO_OS_HAIKU) | #if defined(DISTRHO_OS_HAIKU) | ||||
@@ -353,7 +363,7 @@ 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) | |||||
if (view->impl->win && !view->parent && !view->transientParent) | |||||
{ | { | ||||
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; | ||||
} | } | ||||
@@ -397,9 +407,16 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) | |||||
if (const PuglStatus status = puglSetSize(view, width, height)) | if (const PuglStatus status = puglSetSize(view, width, height)) | ||||
return status; | return status; | ||||
// handle new PUGL_DEFAULT_SIZE hint | |||||
if (const PuglStatus status = updateSizeHints(view)) | |||||
return status; | |||||
// updateSizeHints will use last known size, which is not yet updated | |||||
const PuglSpan lastWidth = view->lastConfigure.width; | |||||
const PuglSpan lastHeight = view->lastConfigure.height; | |||||
view->lastConfigure.width = static_cast<PuglSpan>(width); | |||||
view->lastConfigure.height = static_cast<PuglSpan>(height); | |||||
updateSizeHints(view); | |||||
view->lastConfigure.width = lastWidth; | |||||
view->lastConfigure.height = lastHeight; | |||||
// flush size changes | // flush size changes | ||||
XFlush(view->world->impl->display); | XFlush(view->world->impl->display); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -511,15 +511,6 @@ struct ParameterEnumerationValue { | |||||
ParameterEnumerationValue(float v, const char* l) noexcept | ParameterEnumerationValue(float v, const char* l) noexcept | ||||
: value(v), | : value(v), | ||||
label(l) {} | label(l) {} | ||||
#if __cplusplus >= 201703L | |||||
/** | |||||
Constructor using custom values, constexpr compatible variant. | |||||
*/ | |||||
constexpr ParameterEnumerationValue(float v, const std::string_view& l) noexcept | |||||
: value(v), | |||||
label(l) {} | |||||
#endif | |||||
}; | }; | ||||
/** | /** | ||||
@@ -566,7 +557,7 @@ struct ParameterEnumerationValues { | |||||
When using this constructor the pointer to @values MUST have been statically declared.@n | When using this constructor the pointer to @values MUST have been statically declared.@n | ||||
It will not be automatically deleted later. | It will not be automatically deleted later. | ||||
*/ | */ | ||||
constexpr ParameterEnumerationValues(uint32_t c, bool r, ParameterEnumerationValue* v) noexcept | |||||
constexpr ParameterEnumerationValues(uint8_t c, bool r, ParameterEnumerationValue* v) noexcept | |||||
: count(c), | : count(c), | ||||
restrictedMode(r), | restrictedMode(r), | ||||
values(v), | values(v), | ||||
@@ -578,6 +569,8 @@ struct ParameterEnumerationValues { | |||||
if (deleteLater) | if (deleteLater) | ||||
delete[] values; | delete[] values; | ||||
} | } | ||||
DISTRHO_DECLARE_NON_COPYABLE(ParameterEnumerationValues) | |||||
}; | }; | ||||
/** | /** | ||||
@@ -669,6 +662,7 @@ struct Parameter { | |||||
shortName(), | shortName(), | ||||
symbol(), | symbol(), | ||||
unit(), | unit(), | ||||
description(), | |||||
ranges(), | ranges(), | ||||
enumValues(), | enumValues(), | ||||
designation(kParameterDesignationNull), | designation(kParameterDesignationNull), | ||||
@@ -684,6 +678,7 @@ struct Parameter { | |||||
shortName(), | shortName(), | ||||
symbol(s), | symbol(s), | ||||
unit(u), | unit(u), | ||||
description(), | |||||
ranges(def, min, max), | ranges(def, min, max), | ||||
enumValues(), | enumValues(), | ||||
designation(kParameterDesignationNull), | designation(kParameterDesignationNull), | ||||
@@ -702,6 +697,7 @@ struct Parameter { | |||||
shortName(), | shortName(), | ||||
symbol(s), | symbol(s), | ||||
unit(u), | unit(u), | ||||
description(), | |||||
ranges(def, min, max), | ranges(def, min, max), | ||||
enumValues(evcount, true, ev), | enumValues(evcount, true, ev), | ||||
designation(kParameterDesignationNull), | designation(kParameterDesignationNull), | ||||
@@ -709,29 +705,6 @@ struct Parameter { | |||||
groupId(kPortGroupNone) {} | groupId(kPortGroupNone) {} | ||||
#endif | #endif | ||||
#if __cplusplus >= 201703L | |||||
/** | |||||
Constructor for constexpr compatible data. | |||||
*/ | |||||
constexpr Parameter(uint32_t h, | |||||
const std::string_view& n, | |||||
const std::string_view& sn, | |||||
const std::string_view& sym, | |||||
const std::string_view& u, | |||||
const std::string_view& desc) noexcept | |||||
: hints(h), | |||||
name(n), | |||||
shortName(sn), | |||||
symbol(sym), | |||||
unit(u), | |||||
description(desc), | |||||
ranges(), | |||||
enumValues(), | |||||
designation(kParameterDesignationNull), | |||||
midiCC(0), | |||||
groupId(kPortGroupNone) {} | |||||
#endif | |||||
/** | /** | ||||
Initialize a parameter for a specific designation. | Initialize a parameter for a specific designation. | ||||
*/ | */ | ||||
@@ -757,17 +730,57 @@ struct Parameter { | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
}; | |||||
#if __cplusplus >= 202001L /* TODO */ | |||||
/** | |||||
Bypass parameter definition in constexpr form. | |||||
*/ | |||||
static constexpr const Parameter kParameterBypass = { | |||||
kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger, | |||||
"Bypass", "Bypass", ParameterDesignationSymbols::bypass, "", "", {}, {}, 0, kPortGroupNone, | |||||
Parameter& operator=(Parameter& other) noexcept | |||||
{ | |||||
hints = other.hints; | |||||
name = other.name; | |||||
shortName = other.shortName; | |||||
symbol = other.symbol; | |||||
unit = other.unit; | |||||
description = other.description; | |||||
ranges = other.ranges; | |||||
designation = other.designation; | |||||
midiCC = other.midiCC; | |||||
groupId = other.groupId; | |||||
// enumValues needs special handling | |||||
enumValues.count = other.enumValues.count; | |||||
enumValues.restrictedMode = other.enumValues.restrictedMode; | |||||
enumValues.values = other.enumValues.values; | |||||
enumValues.deleteLater = other.enumValues.deleteLater; | |||||
// make sure to not delete data twice | |||||
other.enumValues.deleteLater = false; | |||||
return *this; | |||||
} | |||||
Parameter& operator=(const Parameter& other) noexcept | |||||
{ | |||||
hints = other.hints; | |||||
name = other.name; | |||||
shortName = other.shortName; | |||||
symbol = other.symbol; | |||||
unit = other.unit; | |||||
description = other.description; | |||||
ranges = other.ranges; | |||||
designation = other.designation; | |||||
midiCC = other.midiCC; | |||||
groupId = other.groupId; | |||||
// make sure to not delete data twice | |||||
DISTRHO_SAFE_ASSERT_RETURN(other.enumValues.values == nullptr || !other.enumValues.deleteLater, *this); | |||||
// enumValues needs special handling | |||||
enumValues.count = other.enumValues.count; | |||||
enumValues.restrictedMode = other.enumValues.restrictedMode; | |||||
enumValues.values = other.enumValues.values; | |||||
enumValues.deleteLater = other.enumValues.deleteLater; | |||||
return *this; | |||||
} | |||||
}; | }; | ||||
#endif | |||||
/** | /** | ||||
Port Group.@n | Port Group.@n | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -603,6 +603,12 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | ||||
/** | |||||
Whether the %UI uses Cairo for drawing instead of the default OpenGL mode.@n | |||||
When enabled your %UI instance will subclass @ref CairoTopLevelWidget instead of @ref TopLevelWidget. | |||||
*/ | |||||
#define DISTRHO_UI_USE_CAIRO 1 | |||||
/** | /** | ||||
Whether the %UI uses a custom toolkit implementation based on OpenGL.@n | Whether the %UI uses a custom toolkit implementation based on OpenGL.@n | ||||
When enabled, the macros @ref DISTRHO_UI_CUSTOM_INCLUDE_PATH and @ref DISTRHO_UI_CUSTOM_WIDGET_TYPE are required. | When enabled, the macros @ref DISTRHO_UI_CUSTOM_INCLUDE_PATH and @ref DISTRHO_UI_CUSTOM_WIDGET_TYPE are required. | ||||
@@ -616,6 +622,12 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DISTRHO_UI_CUSTOM_INCLUDE_PATH | #define DISTRHO_UI_CUSTOM_INCLUDE_PATH | ||||
/** | |||||
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL mode.@n | |||||
When enabled your %UI instance will subclass @ref NanoTopLevelWidget instead of @ref TopLevelWidget. | |||||
*/ | |||||
#define DISTRHO_UI_USE_NANOVG 1 | |||||
/** | /** | ||||
The top-level-widget typedef to use for the custom toolkit. | The top-level-widget typedef to use for the custom toolkit. | ||||
This widget class MUST be a subclass of DGL TopLevelWindow class. | This widget class MUST be a subclass of DGL TopLevelWindow class. | ||||
@@ -648,25 +660,54 @@ START_NAMESPACE_DISTRHO | |||||
#define DISTRHO_UI_DEFAULT_HEIGHT 300 | #define DISTRHO_UI_DEFAULT_HEIGHT 300 | ||||
/** | /** | ||||
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n | |||||
When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget. | |||||
*/ | |||||
#define DISTRHO_UI_USE_NANOVG 1 | |||||
/** | |||||
Whether the %UI is resizable to any size by the user.@n | |||||
By default this is false, and resizing is only allowed under the plugin UI control,@n | |||||
Whether the %UI is resizable to any size by the user and OS.@n | |||||
By default this is false, with resizing only allowed when coded from the the plugin UI side.@n | |||||
Enabling this options makes it possible for the user to resize the plugin UI at anytime. | Enabling this options makes it possible for the user to resize the plugin UI at anytime. | ||||
@see UI::setGeometryConstraints(uint, uint, bool, bool) | @see UI::setGeometryConstraints(uint, uint, bool, bool) | ||||
*/ | */ | ||||
#define DISTRHO_UI_USER_RESIZABLE 1 | #define DISTRHO_UI_USER_RESIZABLE 1 | ||||
/** | |||||
Whether to %UI is going to use file browser dialogs.@n | |||||
By default this is false, with the file browser APIs not available for use. | |||||
*/ | |||||
#define DISTRHO_UI_FILE_BROWSER 1 | |||||
/** | |||||
Whether to %UI is going to use web browser views.@n | |||||
By default this is false, with the web browser APIs not available for use. | |||||
*/ | |||||
#define DISTRHO_UI_WEB_VIEW 1 | |||||
/** | /** | ||||
The %UI URI when exporting in LV2 format.@n | The %UI URI when exporting in LV2 format.@n | ||||
By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix. | By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix. | ||||
*/ | */ | ||||
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | #define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | ||||
/** | |||||
The AudioUnit type for a plugin.@n | |||||
This is a 4-character symbol, automatically set by DPF based on other plugin macros. | |||||
See https://developer.apple.com/documentation/audiotoolbox/1584142-audio_unit_types for more information. | |||||
*/ | |||||
#define DISTRHO_PLUGIN_AU_TYPE aufx | |||||
/** | |||||
A 4-character symbol that identifies a brand or manufacturer, with at least one non-lower case character.@n | |||||
Plugins from the same brand should use the same symbol. | |||||
@note This macro is required when building AU plugins, and used for VST3 if present | |||||
@note Setting this macro will change the uid of a VST3 plugin. | |||||
If you already released a DPF-based VST3 plugin make sure to also enable DPF_VST3_DONT_USE_BRAND_ID | |||||
*/ | |||||
#define DISTRHO_PLUGIN_BRAND_ID Dstr | |||||
/** | |||||
A 4-character symbol which identifies a plugin.@n | |||||
It must be unique within at least a set of plugins from the brand. | |||||
@note This macro is required when building AU plugins | |||||
*/ | |||||
#define DISTRHO_PLUGIN_UNIQUE_ID test | |||||
/** | /** | ||||
Custom LV2 category for the plugin.@n | Custom LV2 category for the plugin.@n | ||||
This is a single string, and can be one of the following values: | This is a single string, and can be one of the following values: | ||||
@@ -842,7 +883,7 @@ START_NAMESPACE_DISTRHO | |||||
/** | /** | ||||
Whether to enable runtime plugin tests.@n | Whether to enable runtime plugin tests.@n | ||||
This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n | This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n | ||||
Useful to enable as part of CI, can safely be skipped.@n | |||||
Useful to enable as part of CI, can be safely skipped.@n | |||||
Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`. | Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`. | ||||
@note Some checks are only available with the GCC compiler, | @note Some checks are only available with the GCC compiler, | ||||
@@ -857,10 +898,10 @@ START_NAMESPACE_DISTRHO | |||||
#define DPF_VST_SHOW_PARAMETER_OUTPUTS | #define DPF_VST_SHOW_PARAMETER_OUTPUTS | ||||
/** | /** | ||||
Disable all file browser related code.@n | |||||
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_FILE_BROWSER_DISABLED"`) | |||||
Forcibly ignore DISTRHO_PLUGIN_BRAND_ID for VST3 plugins.@n | |||||
This is required for DPF-based VST3 plugins that got released without setting DISTRHO_PLUGIN_BRAND_ID first. | |||||
*/ | */ | ||||
#define DGL_FILE_BROWSER_DISABLED | |||||
#define DPF_VST3_DONT_USE_BRAND_ID | |||||
/** | /** | ||||
Disable resource files, like internally used fonts.@n | Disable resource files, like internally used fonts.@n | ||||
@@ -868,14 +909,6 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DGL_NO_SHARED_RESOURCES | #define DGL_NO_SHARED_RESOURCES | ||||
/** | |||||
Whether to use OpenGL3 instead of the default OpenGL2 compatility profile. | |||||
Under DPF makefiles this can be enabled by using `make USE_OPENGL3=true` on the dgl build step. | |||||
@note This is experimental and incomplete, contributions are welcome and appreciated. | |||||
*/ | |||||
#define DGL_USE_OPENGL3 | |||||
/** @} */ | /** @} */ | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -189,30 +189,65 @@ protected: | |||||
Get the plugin label.@n | Get the plugin label.@n | ||||
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. | This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. | ||||
*/ | */ | ||||
#ifdef DISTRHO_PLUGIN_LABEL | |||||
virtual const char* getLabel() const | |||||
{ | |||||
return DISTRHO_PLUGIN_LABEL; | |||||
} | |||||
#else | |||||
virtual const char* getLabel() const = 0; | virtual const char* getLabel() const = 0; | ||||
#endif | |||||
/** | /** | ||||
Get an extensive comment/description about the plugin.@n | Get an extensive comment/description about the plugin.@n | ||||
Optional, returns nothing by default. | Optional, returns nothing by default. | ||||
*/ | */ | ||||
virtual const char* getDescription() const { return ""; } | |||||
virtual const char* getDescription() const | |||||
{ | |||||
#ifdef DISTRHO_PLUGIN_DESCRIPTION | |||||
return DISTRHO_PLUGIN_DESCRIPTION; | |||||
#else | |||||
return ""; | |||||
#endif | |||||
} | |||||
/** | /** | ||||
Get the plugin author/maker. | Get the plugin author/maker. | ||||
*/ | */ | ||||
#ifdef DISTRHO_PLUGIN_MAKER | |||||
virtual const char* getMaker() const | |||||
{ | |||||
return DISTRHO_PLUGIN_MAKER; | |||||
} | |||||
#else | |||||
virtual const char* getMaker() const = 0; | virtual const char* getMaker() const = 0; | ||||
#endif | |||||
/** | /** | ||||
Get the plugin homepage.@n | Get the plugin homepage.@n | ||||
Optional, returns nothing by default. | Optional, returns nothing by default. | ||||
*/ | */ | ||||
virtual const char* getHomePage() const { return ""; } | |||||
virtual const char* getHomePage() const | |||||
{ | |||||
#ifdef DISTRHO_PLUGIN_HOMEPAGE | |||||
return DISTRHO_PLUGIN_HOMEPAGE; | |||||
#else | |||||
return ""; | |||||
#endif | |||||
} | |||||
/** | /** | ||||
Get the plugin license (a single line of text or a URL).@n | Get the plugin license (a single line of text or a URL).@n | ||||
For commercial plugins this should return some short copyright information. | For commercial plugins this should return some short copyright information. | ||||
*/ | */ | ||||
#ifdef DISTRHO_PLUGIN_LICENSE | |||||
virtual const char* getLicense() const | |||||
{ | |||||
return DISTRHO_PLUGIN_LICENSE; | |||||
} | |||||
#else | |||||
virtual const char* getLicense() const = 0; | virtual const char* getLicense() const = 0; | ||||
#endif | |||||
/** | /** | ||||
Get the plugin version, in hexadecimal. | Get the plugin version, in hexadecimal. | ||||
@@ -222,10 +257,19 @@ protected: | |||||
/** | /** | ||||
Get the plugin unique Id.@n | Get the plugin unique Id.@n | ||||
This value is used by LADSPA, DSSI, VST2 and VST3 plugin formats. | |||||
This value is used by LADSPA, DSSI, VST2, VST3 and AUv2 plugin formats.@n | |||||
@note It is preferred that you set DISTRHO_PLUGIN_UNIQUE_ID macro instead of overriding this call, | |||||
as that is required for AUv2 plugins anyhow. | |||||
@see d_cconst() | @see d_cconst() | ||||
*/ | */ | ||||
#ifdef DISTRHO_PLUGIN_UNIQUE_ID | |||||
virtual int64_t getUniqueId() const | |||||
{ | |||||
return d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)); | |||||
} | |||||
#else | |||||
virtual int64_t getUniqueId() const = 0; | virtual int64_t getUniqueId() const = 0; | ||||
#endif | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* Init */ | * Init */ | ||||
@@ -364,6 +408,14 @@ protected: | |||||
*/ | */ | ||||
virtual void sampleRateChanged(double newSampleRate); | virtual void sampleRateChanged(double newSampleRate); | ||||
/** | |||||
Optional callback to inform the plugin about audio port IO changes.@n | |||||
This function will only be called when the plugin is deactivated.@n | |||||
Only used in AU (AudioUnit) format when DISTRHO_PLUGIN_EXTRA_IO is defined. | |||||
@see DISTRHO_PLUGIN_EXTRA_IO | |||||
*/ | |||||
virtual void ioChanged(uint16_t numInputs, uint16_t numOutputs); | |||||
// ------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------- | ||||
private: | private: | ||||
@@ -0,0 +1,392 @@ | |||||
#pragma once | |||||
/** | |||||
This file contains C Macros that describe this plugin. | |||||
With these macros we can tell the host what features the plugin requires. | |||||
New functions will be available to call and/or override depending on which macros are enabled. | |||||
All values are either integer or strings. | |||||
For boolean-like values 1 means 'on' and 0 means 'off'. | |||||
*/ | |||||
/** | |||||
The plugin name. | |||||
This is used to identify your plugin before a Plugin instance can be created. | |||||
@note This macro is required. | |||||
*/ | |||||
#define DISTRHO_PLUGIN_NAME "Plugin Name" | |||||
/** | |||||
Number of audio inputs the plugin has. | |||||
@note This macro is required. | |||||
*/ | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||||
/** | |||||
Number of audio outputs the plugin has. | |||||
@note This macro is required. | |||||
*/ | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||||
/** | |||||
The plugin URI when exporting in LV2 format. | |||||
TODO describe what a URI is | |||||
@note This macro is required. | |||||
*/ | |||||
#define DISTRHO_PLUGIN_URI "urn:distrho:name" | |||||
/** | |||||
Whether the plugin has a custom UI. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_HAS_UI 0 | |||||
/** | |||||
Whether the plugin processing is realtime-safe. | |||||
TODO - list rtsafe requirements | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_IS_RT_SAFE 0 | |||||
/** | |||||
Whether the plugin is a synth. | |||||
@ref DISTRHO_PLUGIN_WANT_MIDI_INPUT is automatically enabled when this is too. | |||||
@see DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||||
/** | |||||
Request the minimum buffer size for the input and output event ports. | |||||
Currently only used in LV2, with a default value of 2048 if unset. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048 | |||||
/** | |||||
Whether the plugin has an LV2 modgui. | |||||
This will simply add a "rdfs:seeAlso <modgui.ttl>" on the LV2 manifest. | |||||
It is up to you to create this file. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_USES_MODGUI 0 | |||||
/** | |||||
Enable direct access between the UI and plugin code. | |||||
@see UI::getPluginInstancePointer() | |||||
@note DO NOT USE THIS UNLESS STRICTLY NECESSARY!! | |||||
Try to avoid it at all costs! | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||||
/** | |||||
Whether the plugin introduces latency during audio or midi processing. | |||||
@see Plugin::setLatency(uint32_t) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||||
/** | |||||
Whether the plugin wants MIDI input. | |||||
This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 0 | |||||
/** | |||||
Whether the plugin wants MIDI output. | |||||
@see Plugin::writeMidiEvent(const MidiEvent&) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||||
/** | |||||
Whether the plugin wants to change its own parameter inputs. | |||||
Not all hosts or plugin formats support this, | |||||
so Plugin::canRequestParameterValueChanges() can be used to query support at runtime. | |||||
@see Plugin::requestParameterValueChange(uint32_t, float) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0 | |||||
/** | |||||
Whether the plugin provides its own internal programs. | |||||
@see Plugin::initProgramName(uint32_t, String&) | |||||
@see Plugin::loadProgram(uint32_t) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_PROGRAMS 0 | |||||
/** | |||||
Whether the plugin uses internal non-parameter data. | |||||
@see Plugin::initState(uint32_t, String&, String&) | |||||
@see Plugin::setState(const char*, const char*) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_STATE 0 | |||||
/** | |||||
Whether the plugin implements the full state API. | |||||
When this macro is enabled, the plugin must implement a new getState(const char* key) function, which the host calls when saving its session/project. | |||||
This is useful for plugins that have custom internal values not exposed to the host as key-value state pairs or parameters. | |||||
Most simple effects and synths will not need this. | |||||
@note this macro is automatically enabled if a plugin has programs and state, as the key-value state pairs need to be updated when the current program changes. | |||||
@see Plugin::getState(const char*) | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_FULL_STATE 0 | |||||
/** | |||||
Whether the plugin wants time position information from the host. | |||||
@see Plugin::getTimePosition() | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | |||||
/** | |||||
Whether the UI uses Cairo for drawing instead of the default OpenGL mode. | |||||
When enabled your UI instance will subclass CairoTopLevelWidget instead of TopLevelWidget. | |||||
*/ | |||||
// #define DISTRHO_UI_USE_CAIRO 0 | |||||
/** | |||||
Whether the UI uses a custom toolkit implementation based on OpenGL. | |||||
When enabled, the macros DISTRHO_UI_CUSTOM_INCLUDE_PATH and DISTRHO_UI_CUSTOM_WIDGET_TYPE are required. | |||||
*/ | |||||
// #define DISTRHO_UI_USE_CUSTOM 0 | |||||
/** | |||||
The include path to the header file used by the custom toolkit implementation. | |||||
This path must be relative to dpf/distrho/DistrhoUI.hpp | |||||
*/ | |||||
// #define DISTRHO_UI_CUSTOM_INCLUDE_PATH | |||||
/** | |||||
The top-level-widget typedef to use for the custom toolkit. | |||||
This widget class MUST be a subclass of DGL TopLevelWindow class. | |||||
It is recommended that you keep this widget class inside the DGL namespace, | |||||
and define widget type as e.g. DGL_NAMESPACE::MyCustomTopLevelWidget. | |||||
*/ | |||||
// #define DISTRHO_UI_CUSTOM_WIDGET_TYPE | |||||
/** | |||||
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL mode.@n | |||||
When enabled your %UI instance will subclass NanoTopLevelWidget instead of TopLevelWidget. | |||||
*/ | |||||
// #define DISTRHO_UI_USE_NANOVG 0 | |||||
/** | |||||
Default UI width to use when creating initial and temporary windows. | |||||
Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts. | |||||
(which would normally be done for knowing the UI size before host creates a window for it) | |||||
Value must match 1x scale factor. | |||||
When this macro is defined, the companion DISTRHO_UI_DEFAULT_HEIGHT macro must be defined as well. | |||||
*/ | |||||
// #define DISTRHO_UI_DEFAULT_WIDTH 300 | |||||
/** | |||||
Default UI height to use when creating initial and temporary windows. | |||||
Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts. | |||||
(which would normally be done for knowing the UI size before host creates a window for it) | |||||
Value must match 1x scale factor. | |||||
When this macro is defined, the companion DISTRHO_UI_DEFAULT_WIDTH macro must be defined as well. | |||||
*/ | |||||
// #define DISTRHO_UI_DEFAULT_HEIGHT 300 | |||||
/** | |||||
Whether the UI is resizable to any size by the user and OS. | |||||
By default this is false, with resizing only allowed when coded from the the plugin UI side. | |||||
Enabling this options makes it possible for the user to resize the plugin UI at anytime. | |||||
@see UI::setGeometryConstraints(uint, uint, bool, bool) | |||||
*/ | |||||
// #define DISTRHO_UI_USER_RESIZABLE 0 | |||||
/** | |||||
Whether to UI is going to use file browser dialogs. | |||||
By default this is false, with the file browser APIs not available for use. | |||||
*/ | |||||
// #define DISTRHO_UI_FILE_BROWSER 0 | |||||
/** | |||||
Whether to UI is going to use web browser views. | |||||
By default this is false, with the web browser APIs not available for use. | |||||
*/ | |||||
// #define DISTRHO_UI_WEB_VIEW 0 | |||||
/** | |||||
The UI URI when exporting in LV2 format. | |||||
By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix. | |||||
*/ | |||||
// #define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | |||||
/** | |||||
The AudioUnit type for a plugin. | |||||
This is a 4-character symbol, automatically set by DPF based on other plugin macros. | |||||
See https://developer.apple.com/documentation/audiotoolbox/1584142-audio_unit_types for more information. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_AU_TYPE aufx | |||||
/** | |||||
A 4-character symbol that identifies a brand or manufacturer, with at least one non-lower case character. | |||||
Plugins from the same brand should use the same symbol. | |||||
@note This macro is required when building AU plugins, and used for VST3 if present | |||||
@note Setting this macro will change the uid of a VST3 plugin. | |||||
If you already released a DPF-based VST3 plugin make sure to also enable DPF_VST3_DONT_USE_BRAND_ID | |||||
*/ | |||||
#define DISTRHO_PLUGIN_BRAND_ID Dstr | |||||
/** | |||||
A 4-character symbol which identifies a plugin. | |||||
It must be unique within at least a set of plugins from the brand. | |||||
@note This macro is required when building AU plugins | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_UNIQUE_ID test | |||||
/** | |||||
Custom LV2 category for the plugin. | |||||
This is a single string, and can be one of the following values: | |||||
- lv2:AllpassPlugin | |||||
- lv2:AmplifierPlugin | |||||
- lv2:AnalyserPlugin | |||||
- lv2:BandpassPlugin | |||||
- lv2:ChorusPlugin | |||||
- lv2:CombPlugin | |||||
- lv2:CompressorPlugin | |||||
- lv2:ConstantPlugin | |||||
- lv2:ConverterPlugin | |||||
- lv2:DelayPlugin | |||||
- lv2:DistortionPlugin | |||||
- lv2:DynamicsPlugin | |||||
- lv2:EQPlugin | |||||
- lv2:EnvelopePlugin | |||||
- lv2:ExpanderPlugin | |||||
- lv2:FilterPlugin | |||||
- lv2:FlangerPlugin | |||||
- lv2:FunctionPlugin | |||||
- lv2:GatePlugin | |||||
- lv2:GeneratorPlugin | |||||
- lv2:HighpassPlugin | |||||
- lv2:InstrumentPlugin | |||||
- lv2:LimiterPlugin | |||||
- lv2:LowpassPlugin | |||||
- lv2:MIDIPlugin | |||||
- lv2:MixerPlugin | |||||
- lv2:ModulatorPlugin | |||||
- lv2:MultiEQPlugin | |||||
- lv2:OscillatorPlugin | |||||
- lv2:ParaEQPlugin | |||||
- lv2:PhaserPlugin | |||||
- lv2:PitchPlugin | |||||
- lv2:ReverbPlugin | |||||
- lv2:SimulatorPlugin | |||||
- lv2:SpatialPlugin | |||||
- lv2:SpectralPlugin | |||||
- lv2:UtilityPlugin | |||||
- lv2:WaveshaperPlugin | |||||
See http://lv2plug.in/ns/lv2core for more information. | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:Plugin" | |||||
/** | |||||
Custom VST3 categories for the plugin. | |||||
This is a single concatenated string of categories, separated by a @c |. | |||||
Each effect category can be one of the following values: | |||||
- Fx | |||||
- Fx|Ambisonics | |||||
- Fx|Analyzer | |||||
- Fx|Delay | |||||
- Fx|Distortion | |||||
- Fx|Dynamics | |||||
- Fx|EQ | |||||
- Fx|Filter | |||||
- Fx|Instrument | |||||
- Fx|Instrument|External | |||||
- Fx|Spatial | |||||
- Fx|Generator | |||||
- Fx|Mastering | |||||
- Fx|Modulation | |||||
- Fx|Network | |||||
- Fx|Pitch Shift | |||||
- Fx|Restoration | |||||
- Fx|Reverb | |||||
- Fx|Surround | |||||
- Fx|Tools | |||||
Each instrument category can be one of the following values: | |||||
- Instrument | |||||
- Instrument|Drum | |||||
- Instrument|External | |||||
- Instrument|Piano | |||||
- Instrument|Sampler | |||||
- Instrument|Synth | |||||
- Instrument|Synth|Sampler | |||||
And extra categories possible for any plugin type: | |||||
- Mono | |||||
- Stereo | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Stereo" | |||||
/** | |||||
Custom CLAP features for the plugin. | |||||
This is a list of features defined as a string array body, without the terminating @c , or nullptr. | |||||
A top-level category can be set as feature and be one of the following values: | |||||
- instrument | |||||
- audio-effect | |||||
- note-effect | |||||
- analyzer | |||||
The following sub-categories can also be set: | |||||
- synthesizer | |||||
- sampler | |||||
- drum | |||||
- drum-machine | |||||
- filter | |||||
- phaser | |||||
- equalizer | |||||
- de-esser | |||||
- phase-vocoder | |||||
- granular | |||||
- frequency-shifter | |||||
- pitch-shifter | |||||
- distortion | |||||
- transient-shaper | |||||
- compressor | |||||
- limiter | |||||
- flanger | |||||
- chorus | |||||
- delay | |||||
- reverb | |||||
- tremolo | |||||
- glitch | |||||
- utility | |||||
- pitch-correction | |||||
- restoration | |||||
- multi-effects | |||||
- mixing | |||||
- mastering | |||||
And finally the following audio capabilities can be set: | |||||
- mono | |||||
- stereo | |||||
- surround | |||||
- ambisonic | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "stereo" | |||||
/** | |||||
The plugin id when exporting in CLAP format, in reverse URI form. | |||||
@note This macro is required when building CLAP plugins | |||||
*/ | |||||
// #define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.effect" | |||||
/** @} */ |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -16,7 +16,9 @@ | |||||
#include "src/DistrhoPlugin.cpp" | #include "src/DistrhoPlugin.cpp" | ||||
#if defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) | |||||
# include "src/DistrhoPluginAU.cpp" | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
# include "src/DistrhoPluginCarla.cpp" | # include "src/DistrhoPluginCarla.cpp" | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP) | #elif defined(DISTRHO_PLUGIN_TARGET_CLAP) | ||||
# include "src/DistrhoPluginCLAP.cpp" | # include "src/DistrhoPluginCLAP.cpp" | ||||
@@ -31,6 +33,8 @@ | |||||
# include "src/DistrhoPluginVST2.cpp" | # include "src/DistrhoPluginVST2.cpp" | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_VST3) | #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | ||||
# include "src/DistrhoPluginVST3.cpp" | # include "src/DistrhoPluginVST3.cpp" | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_EXPORT) | |||||
# include "src/DistrhoPluginExport.cpp" | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_SHARED) | #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) | ||||
DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); | DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); | ||||
DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); } | DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -53,13 +53,15 @@ const char* getPluginFormatName() noexcept; | |||||
Returns a path inside the bundle where the plugin is meant to store its resources in.@n | Returns a path inside the bundle where the plugin is meant to store its resources in.@n | ||||
This path varies between systems and plugin formats, like so: | This path varies between systems and plugin formats, like so: | ||||
- AU: <bundle>/Contents/Resources | |||||
- CLAP+VST2 macOS: <bundle>/Contents/Resources | |||||
- CLAP+VST2 non-macOS: <bundle>/resources (see note) | |||||
- LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DPF just uses this one) | - LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DPF just uses this one) | ||||
- VST2 macOS: <bundle>/Contents/Resources | |||||
- VST2 non-macOS: <bundle>/resources (see note) | |||||
- VST3: <bundle>/Contents/Resources | |||||
The other non-mentioned formats do not support bundles.@n | The other non-mentioned formats do not support bundles.@n | ||||
@note For VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory | |||||
@note For CLAP and VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory | |||||
rather than only shipping with the binary (e.g. <myplugin.vst>/myplugin.dll) | rather than only shipping with the binary (e.g. <myplugin.vst>/myplugin.dll) | ||||
*/ | */ | ||||
const char* getResourcePath(const char* bundlePath) noexcept; | const char* getResourcePath(const char* bundlePath) noexcept; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,11 +31,7 @@ | |||||
# include "Vulkan.hpp" | # include "Vulkan.hpp" | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include "../dgl/Base.hpp" | |||||
# include "extra/ExternalWindow.hpp" | |||||
typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | |||||
#elif DISTRHO_UI_USE_CUSTOM | |||||
#if DISTRHO_UI_USE_CUSTOM | |||||
# include DISTRHO_UI_CUSTOM_INCLUDE_PATH | # include DISTRHO_UI_CUSTOM_INCLUDE_PATH | ||||
typedef DISTRHO_UI_CUSTOM_WIDGET_TYPE UIWidget; | typedef DISTRHO_UI_CUSTOM_WIDGET_TYPE UIWidget; | ||||
#elif DISTRHO_UI_USE_CAIRO | #elif DISTRHO_UI_USE_CAIRO | ||||
@@ -52,9 +48,8 @@ typedef DGL_NAMESPACE::TopLevelWidget UIWidget; | |||||
#if DISTRHO_UI_FILE_BROWSER | #if DISTRHO_UI_FILE_BROWSER | ||||
# include "extra/FileBrowserDialog.hpp" | # include "extra/FileBrowserDialog.hpp" | ||||
#endif | #endif | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include <vector> | |||||
#endif | |||||
#include <vector> | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
@@ -197,8 +192,7 @@ public: | |||||
This function does not block the event loop. | This function does not block the event loop. | ||||
@note This is exactly the same API as provided by the Window class, | |||||
but redeclared here so that non-embed/DGL based UIs can still use file browser related functions. | |||||
@note This is exactly the same API as provided by the Window class, but redeclared here for convenience. | |||||
*/ | */ | ||||
bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | ||||
#endif | #endif | ||||
@@ -214,34 +208,6 @@ public: | |||||
void* getPluginInstancePointer() const noexcept; | void* getPluginInstancePointer() const noexcept; | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* External UI helpers */ | |||||
/** | |||||
Get the bundle path that will be used for the next UI. | |||||
@note: This function is only valid during createUI(), | |||||
it will return null when called from anywhere else. | |||||
*/ | |||||
static const char* getNextBundlePath() noexcept; | |||||
/** | |||||
Get the scale factor that will be used for the next UI. | |||||
@note: This function is only valid during createUI(), | |||||
it will return 1.0 when called from anywhere else. | |||||
*/ | |||||
static double getNextScaleFactor() noexcept; | |||||
# if DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
/** | |||||
Get the Window Id that will be used for the next created window. | |||||
@note: This function is only valid during createUI(), | |||||
it will return 0 when called from anywhere else. | |||||
*/ | |||||
static uintptr_t getNextWindowId() noexcept; | |||||
# endif | |||||
#endif | |||||
protected: | protected: | ||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* DSP/Plugin Callbacks */ | * DSP/Plugin Callbacks */ | ||||
@@ -250,14 +216,14 @@ protected: | |||||
A parameter has changed on the plugin side.@n | A parameter has changed on the plugin side.@n | ||||
This is called by the host to inform the UI about parameter changes. | This is called by the host to inform the UI about parameter changes. | ||||
*/ | */ | ||||
virtual void parameterChanged(uint32_t index, float value) = 0; | |||||
virtual void parameterChanged(uint32_t index, float value); | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
/** | /** | ||||
A program has been loaded on the plugin side.@n | A program has been loaded on the plugin side.@n | ||||
This is called by the host to inform the UI about program changes. | This is called by the host to inform the UI about program changes. | ||||
*/ | */ | ||||
virtual void programLoaded(uint32_t index) = 0; | |||||
virtual void programLoaded(uint32_t index); | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
@@ -265,7 +231,7 @@ protected: | |||||
A state has changed on the plugin side.@n | A state has changed on the plugin side.@n | ||||
This is called by the host to inform the UI about state changes. | This is called by the host to inform the UI about state changes. | ||||
*/ | */ | ||||
virtual void stateChanged(const char* key, const char* value) = 0; | |||||
virtual void stateChanged(const char* key, const char* value); | |||||
#endif | #endif | ||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
@@ -297,7 +263,6 @@ protected: | |||||
*/ | */ | ||||
virtual void uiScaleFactorChanged(double scaleFactor); | virtual void uiScaleFactorChanged(double scaleFactor); | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | /** | ||||
Get the types available for the data in a clipboard. | Get the types available for the data in a clipboard. | ||||
Must only be called within the context of uiClipboardDataOffer. | Must only be called within the context of uiClipboardDataOffer. | ||||
@@ -334,7 +299,6 @@ protected: | |||||
The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code. | The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code. | ||||
*/ | */ | ||||
virtual void uiReshape(uint width, uint height); | virtual void uiReshape(uint width, uint height); | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_UI_FILE_BROWSER | #if DISTRHO_UI_FILE_BROWSER | ||||
/** | /** | ||||
@@ -352,21 +316,12 @@ protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | |||||
External Window resize function, called when the window is resized. | |||||
This is overriden here so the host knows when the UI is resized by you. | |||||
@see ExternalWindow::sizeChanged(uint,uint) | |||||
*/ | |||||
void sizeChanged(uint width, uint height) override; | |||||
#else | |||||
/** | /** | ||||
Widget resize function, called when the widget is resized. | Widget resize function, called when the widget is resized. | ||||
This is overriden here so the host knows when the UI is resized by you. | This is overriden here so the host knows when the UI is resized by you. | ||||
@see Widget::onResize(const ResizeEvent&) | @see Widget::onResize(const ResizeEvent&) | ||||
*/ | */ | ||||
void onResize(const ResizeEvent& ev) override; | void onResize(const ResizeEvent& ev) override; | ||||
#endif | |||||
// ------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------- | ||||
@@ -375,10 +330,8 @@ private: | |||||
PrivateData* const uiData; | PrivateData* const uiData; | ||||
friend class PluginWindow; | friend class PluginWindow; | ||||
friend class UIExporter; | friend class UIExporter; | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** @internal */ | /** @internal */ | ||||
void requestSizeChange(uint width, uint height) override; | void requestSizeChange(uint width, uint height) override; | ||||
#endif | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | ||||
}; | }; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,7 +23,10 @@ | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
#if defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) | |||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | |||||
# import "src/DistrhoUIAU.mm" | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP) | #elif defined(DISTRHO_PLUGIN_TARGET_CLAP) | ||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | ||||
@@ -40,6 +43,8 @@ | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_VST3) | #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | ||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | ||||
# include "src/DistrhoUIVST3.cpp" | # include "src/DistrhoUIVST3.cpp" | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_EXPORT) | |||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_SHARED) || defined(DISTRHO_PLUGIN_TARGET_STATIC) | #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) || defined(DISTRHO_PLUGIN_TARGET_STATIC) | ||||
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | ||||
#else | #else | ||||
@@ -53,6 +58,19 @@ | |||||
# define DISTRHO_IS_STANDALONE 0 | # define DISTRHO_IS_STANDALONE 0 | ||||
# endif | # endif | ||||
# include "src/DistrhoUtils.cpp" | # include "src/DistrhoUtils.cpp" | ||||
#else | |||||
# ifdef DISTRHO_PLUGIN_TARGET_JACK | |||||
# define DISTRHO_IS_STANDALONE 1 | |||||
# else | |||||
# define DISTRHO_IS_STANDALONE 0 | |||||
# endif | |||||
#endif | |||||
#if defined(DPF_USING_LD_LINUX_WEBVIEW) && !DISTRHO_IS_STANDALONE | |||||
int main(int argc, char* argv[]) | |||||
{ | |||||
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | |||||
} | |||||
#endif | #endif | ||||
#endif | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -20,9 +20,11 @@ | |||||
#include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
#include "src/DistrhoDefines.h" | #include "src/DistrhoDefines.h" | ||||
#if DISTRHO_UI_FILE_BROWSER || DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# import <Cocoa/Cocoa.h> | |||||
#endif | |||||
#define Point CocoaPoint | |||||
#define Size CocoaSize | |||||
#import <Cocoa/Cocoa.h> | |||||
#undef Point | |||||
#undef Size | |||||
#if DISTRHO_UI_FILE_BROWSER | #if DISTRHO_UI_FILE_BROWSER | ||||
# define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | # define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | ||||
@@ -34,9 +36,19 @@ END_NAMESPACE_DISTRHO | |||||
# include "extra/FileBrowserDialogImpl.cpp" | # include "extra/FileBrowserDialogImpl.cpp" | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include <algorithm> | |||||
# include <cmath> | |||||
#if DISTRHO_UI_WEB_VIEW | |||||
# define DISTRHO_WEB_VIEW_HPP_INCLUDED | |||||
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE | |||||
# define WEB_VIEW_DISTRHO_NAMESPACE | |||||
START_NAMESPACE_DISTRHO | |||||
# include "extra/WebViewImpl.hpp" | |||||
END_NAMESPACE_DISTRHO | |||||
# include "extra/WebViewImpl.cpp" | |||||
#endif | |||||
#include <algorithm> | |||||
#include <cmath> | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | ||||
{ | { | ||||
@@ -51,4 +63,3 @@ double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
return [NSScreen mainScreen].backingScaleFactor; | return [NSScreen mainScreen].backingScaleFactor; | ||||
} | } | ||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
#endif |
@@ -0,0 +1,27 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
// Include CHOC separately because it requires C++17 | |||||
#include "DistrhoDetails.hpp" | |||||
#include "src/DistrhoPluginChecks.h" | |||||
#include "src/DistrhoDefines.h" | |||||
#if DISTRHO_UI_WEB_VIEW | |||||
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||||
# include "extra/WebView.hpp" | |||||
# include "extra/WebViewWin32.hpp" | |||||
#endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,7 +38,7 @@ | |||||
typedef SSIZE_T ssize_t; | typedef SSIZE_T ssize_t; | ||||
#endif | #endif | ||||
#if ! defined(CARLA_MATH_UTILS_HPP_INCLUDED) && ! defined(DISTRHO_PROPER_CPP11_SUPPORT) | |||||
#if ! defined(CARLA_MATH_UTILS_HPP_INCLUDED) && ! defined(DISTRHO_PROPER_CPP11_SUPPORT) && ! defined(DISTRHO_OS_MAC) | |||||
namespace std { | namespace std { | ||||
inline float fmin(float __x, float __y) | inline float fmin(float __x, float __y) | ||||
{ return __builtin_fminf(__x, __y); } | { return __builtin_fminf(__x, __y); } | ||||
@@ -55,9 +55,6 @@ inline float round(float __x) | |||||
# define M_PI 3.14159265358979323846 | # define M_PI 3.14159265358979323846 | ||||
#endif | #endif | ||||
#define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO | |||||
#define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO) | |||||
/* -------------------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------------------- | ||||
* misc functions */ | * misc functions */ | ||||
@@ -77,6 +74,15 @@ int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_ | |||||
return (a << 24) | (b << 16) | (c << 8) | (d << 0); | return (a << 24) | (b << 16) | (c << 8) | (d << 0); | ||||
} | } | ||||
/** | |||||
Return a 32-bit number from 4 ASCII characters. | |||||
*/ | |||||
static inline constexpr | |||||
uint32_t d_cconst(const char str[4]) | |||||
{ | |||||
return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3]; | |||||
} | |||||
/** | /** | ||||
Return an hexadecimal representation of a MAJ.MIN.MICRO version number. | Return an hexadecimal representation of a MAJ.MIN.MICRO version number. | ||||
*/ | */ | ||||
@@ -103,6 +109,27 @@ void d_pass() noexcept {} | |||||
@{ | @{ | ||||
*/ | */ | ||||
/* | |||||
* Internal noexcept-safe fopen function. | |||||
*/ | |||||
static inline | |||||
FILE* __d_fopen(const char* const filename, FILE* const fallback) noexcept | |||||
{ | |||||
if (std::getenv("DPF_CAPTURE_CONSOLE_OUTPUT") == nullptr) | |||||
return fallback; | |||||
FILE* ret = nullptr; | |||||
try { | |||||
ret = std::fopen(filename, "a+"); | |||||
} catch (...) {} | |||||
if (ret == nullptr) | |||||
ret = fallback; | |||||
return ret; | |||||
} | |||||
/** | /** | ||||
Print a string to stdout with newline (gray color). | Print a string to stdout with newline (gray color). | ||||
Does nothing if DEBUG is not defined. | Does nothing if DEBUG is not defined. | ||||
@@ -113,12 +140,30 @@ void d_pass() noexcept {} | |||||
static inline | static inline | ||||
void d_debug(const char* const fmt, ...) noexcept | void d_debug(const char* const fmt, ...) noexcept | ||||
{ | { | ||||
static FILE* const output = __d_fopen("/tmp/dpf.debug.log", stdout); | |||||
try { | try { | ||||
va_list args; | va_list args; | ||||
va_start(args, fmt); | va_start(args, fmt); | ||||
std::fprintf(stdout, "\x1b[30;1m"); | |||||
std::vfprintf(stdout, fmt, args); | |||||
std::fprintf(stdout, "\x1b[0m\n"); | |||||
if (output == stdout) | |||||
{ | |||||
#ifdef DISTRHO_OS_MAC | |||||
std::fprintf(output, "\x1b[37;1m[dpf] "); | |||||
#else | |||||
std::fprintf(output, "\x1b[30;1m[dpf] "); | |||||
#endif | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\x1b[0m\n"); | |||||
} | |||||
else | |||||
{ | |||||
std::fprintf(output, "[dpf] "); | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\n"); | |||||
} | |||||
std::fflush(output); | |||||
va_end(args); | va_end(args); | ||||
} catch (...) {} | } catch (...) {} | ||||
} | } | ||||
@@ -130,11 +175,18 @@ void d_debug(const char* const fmt, ...) noexcept | |||||
static inline | static inline | ||||
void d_stdout(const char* const fmt, ...) noexcept | void d_stdout(const char* const fmt, ...) noexcept | ||||
{ | { | ||||
static FILE* const output = __d_fopen("/tmp/dpf.stdout.log", stdout); | |||||
try { | try { | ||||
va_list args; | va_list args; | ||||
va_start(args, fmt); | va_start(args, fmt); | ||||
std::vfprintf(stdout, fmt, args); | |||||
std::fprintf(stdout, "\n"); | |||||
std::fprintf(output, "[dpf] "); | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\n"); | |||||
#ifndef DEBUG | |||||
if (output != stdout) | |||||
#endif | |||||
std::fflush(output); | |||||
va_end(args); | va_end(args); | ||||
} catch (...) {} | } catch (...) {} | ||||
} | } | ||||
@@ -145,11 +197,18 @@ void d_stdout(const char* const fmt, ...) noexcept | |||||
static inline | static inline | ||||
void d_stderr(const char* const fmt, ...) noexcept | void d_stderr(const char* const fmt, ...) noexcept | ||||
{ | { | ||||
static FILE* const output = __d_fopen("/tmp/dpf.stderr.log", stderr); | |||||
try { | try { | ||||
va_list args; | va_list args; | ||||
va_start(args, fmt); | va_start(args, fmt); | ||||
std::vfprintf(stderr, fmt, args); | |||||
std::fprintf(stderr, "\n"); | |||||
std::fprintf(output, "[dpf] "); | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\n"); | |||||
#ifndef DEBUG | |||||
if (output != stderr) | |||||
#endif | |||||
std::fflush(output); | |||||
va_end(args); | va_end(args); | ||||
} catch (...) {} | } catch (...) {} | ||||
} | } | ||||
@@ -160,12 +219,26 @@ void d_stderr(const char* const fmt, ...) noexcept | |||||
static inline | static inline | ||||
void d_stderr2(const char* const fmt, ...) noexcept | void d_stderr2(const char* const fmt, ...) noexcept | ||||
{ | { | ||||
static FILE* const output = __d_fopen("/tmp/dpf.stderr2.log", stderr); | |||||
try { | try { | ||||
va_list args; | va_list args; | ||||
va_start(args, fmt); | va_start(args, fmt); | ||||
std::fprintf(stderr, "\x1b[31m"); | |||||
std::vfprintf(stderr, fmt, args); | |||||
std::fprintf(stderr, "\x1b[0m\n"); | |||||
if (output == stdout) | |||||
{ | |||||
std::fprintf(output, "\x1b[31m[dpf] "); | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\x1b[0m\n"); | |||||
} | |||||
else | |||||
{ | |||||
std::fprintf(output, "[dpf] "); | |||||
std::vfprintf(output, fmt, args); | |||||
std::fprintf(output, "\n"); | |||||
} | |||||
std::fflush(output); | |||||
va_end(args); | va_end(args); | ||||
} catch (...) {} | } catch (...) {} | ||||
} | } | ||||
@@ -310,7 +383,7 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept | |||||
} | } | ||||
/** | /** | ||||
Round a floating point number to integer. | |||||
Round a floating point number to an integer. | |||||
Fast operation for values known to be 0 or positive. | Fast operation for values known to be 0 or positive. | ||||
*/ | */ | ||||
template<typename T> | template<typename T> | ||||
@@ -321,7 +394,18 @@ int32_t d_roundToIntPositive(const T& value) | |||||
} | } | ||||
/** | /** | ||||
Round a floating point number to integer. | |||||
Round a floating point number to an unsigned integer. | |||||
Fast operation for values known to be 0 or positive. | |||||
*/ | |||||
template<typename T> | |||||
static inline constexpr | |||||
uint32_t d_roundToUnsignedInt(const T& value) | |||||
{ | |||||
return static_cast<uint32_t>(value + static_cast<T>(0.5)); | |||||
} | |||||
/** | |||||
Round a floating point number to an integer. | |||||
Fast operation for values known to be 0 or negative. | Fast operation for values known to be 0 or negative. | ||||
*/ | */ | ||||
template<typename T> | template<typename T> | ||||
@@ -345,13 +429,15 @@ int32_t d_roundToInt(const T& value) | |||||
/** @} */ | /** @} */ | ||||
/* -------------------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------------------- | ||||
* math functions */ | |||||
* other stuff */ | |||||
#ifndef DONT_SET_USING_DISTRHO_NAMESPACE | #ifndef DONT_SET_USING_DISTRHO_NAMESPACE | ||||
// If your code uses a lot of DISTRHO classes, then this will obviously save you | |||||
// a lot of typing, but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE. | |||||
namespace DISTRHO_NAMESPACE {} | |||||
using namespace DISTRHO_NAMESPACE; | |||||
/** | |||||
If your code uses a lot of DISTRHO classes, then this will obviously save you a lot of typing, | |||||
but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE. | |||||
*/ | |||||
namespace DISTRHO_NAMESPACE {} | |||||
using namespace DISTRHO_NAMESPACE; | |||||
#endif | #endif | ||||
#endif // DISTRHO_UTILS_HPP_INCLUDED | #endif // DISTRHO_UTILS_HPP_INCLUDED |
@@ -0,0 +1,276 @@ | |||||
// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG | |||||
// SPDX-License-Identifier: AGPL-3.0-or-later | |||||
#pragma once | |||||
#include "Sleep.hpp" | |||||
#include "Time.hpp" | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# include <string> | |||||
# include <winsock2.h> | |||||
# include <windows.h> | |||||
#else | |||||
# include <cerrno> | |||||
# include <ctime> | |||||
# include <signal.h> | |||||
# include <sys/wait.h> | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
class ChildProcess | |||||
{ | |||||
#ifdef _WIN32 | |||||
PROCESS_INFORMATION pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 }; | |||||
#else | |||||
pid_t pid = -1; | |||||
#endif | |||||
public: | |||||
ChildProcess() | |||||
{ | |||||
} | |||||
~ChildProcess() | |||||
{ | |||||
stop(); | |||||
} | |||||
#ifdef _WIN32 | |||||
bool start(const char* const args[], const WCHAR* const envp) | |||||
#else | |||||
bool start(const char* const args[], char* const* const envp = nullptr) | |||||
#endif | |||||
{ | |||||
#ifdef _WIN32 | |||||
std::string cmd; | |||||
for (uint i = 0; args[i] != nullptr; ++i) | |||||
{ | |||||
if (i != 0) | |||||
cmd += " "; | |||||
if (args[i][0] != '"' && std::strchr(args[i], ' ') != nullptr) | |||||
{ | |||||
cmd += "\""; | |||||
cmd += args[i]; | |||||
cmd += "\""; | |||||
} | |||||
else | |||||
{ | |||||
cmd += args[i]; | |||||
} | |||||
} | |||||
wchar_t wcmd[PATH_MAX]; | |||||
if (MultiByteToWideChar(CP_UTF8, 0, cmd.data(), -1, wcmd, PATH_MAX) <= 0) | |||||
return false; | |||||
STARTUPINFOW si = {}; | |||||
si.cb = sizeof(si); | |||||
d_stdout("will start process with args '%s'", cmd.data()); | |||||
return CreateProcessW(nullptr, // lpApplicationName | |||||
wcmd, // lpCommandLine | |||||
nullptr, // lpProcessAttributes | |||||
nullptr, // lpThreadAttributes | |||||
TRUE, // bInheritHandles | |||||
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags | |||||
const_cast<LPWSTR>(envp), // lpEnvironment | |||||
nullptr, // lpCurrentDirectory | |||||
&si, // lpStartupInfo | |||||
&pinfo) != FALSE; | |||||
#else | |||||
const pid_t ret = pid = vfork(); | |||||
switch (ret) | |||||
{ | |||||
// child process | |||||
case 0: | |||||
if (envp != nullptr) | |||||
execve(args[0], const_cast<char* const*>(args), envp); | |||||
else | |||||
execvp(args[0], const_cast<char* const*>(args)); | |||||
d_stderr2("exec failed: %d:%s", errno, std::strerror(errno)); | |||||
_exit(1); | |||||
break; | |||||
// error | |||||
case -1: | |||||
d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno)); | |||||
break; | |||||
} | |||||
return ret > 0; | |||||
#endif | |||||
} | |||||
void stop(const uint32_t timeoutInMilliseconds = 2000) | |||||
{ | |||||
const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds; | |||||
bool sendTerminate = true; | |||||
#ifdef _WIN32 | |||||
if (pinfo.hProcess == INVALID_HANDLE_VALUE) | |||||
return; | |||||
const PROCESS_INFORMATION opinfo = pinfo; | |||||
pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 }; | |||||
for (DWORD exitCode;;) | |||||
{ | |||||
if (GetExitCodeProcess(opinfo.hProcess, &exitCode) == FALSE || | |||||
exitCode != STILL_ACTIVE || | |||||
WaitForSingleObject(opinfo.hProcess, 0) != WAIT_TIMEOUT) | |||||
{ | |||||
CloseHandle(opinfo.hThread); | |||||
CloseHandle(opinfo.hProcess); | |||||
return; | |||||
} | |||||
if (sendTerminate) | |||||
{ | |||||
sendTerminate = false; | |||||
TerminateProcess(opinfo.hProcess, ERROR_BROKEN_PIPE); | |||||
} | |||||
if (d_gettime_ms() < timeout) | |||||
{ | |||||
d_msleep(5); | |||||
continue; | |||||
} | |||||
d_stderr("ChildProcess::stop() - timed out"); | |||||
TerminateProcess(opinfo.hProcess, 9); | |||||
d_msleep(5); | |||||
CloseHandle(opinfo.hThread); | |||||
CloseHandle(opinfo.hProcess); | |||||
break; | |||||
} | |||||
#else | |||||
if (pid <= 0) | |||||
return; | |||||
const pid_t opid = pid; | |||||
pid = -1; | |||||
for (pid_t ret;;) | |||||
{ | |||||
try { | |||||
ret = ::waitpid(opid, nullptr, WNOHANG); | |||||
} DISTRHO_SAFE_EXCEPTION_BREAK("waitpid"); | |||||
switch (ret) | |||||
{ | |||||
case -1: | |||||
if (errno == ECHILD) | |||||
{ | |||||
// success, child doesn't exist | |||||
return; | |||||
} | |||||
else | |||||
{ | |||||
d_stderr("ChildProcess::stop() - waitpid failed: %d:%s", errno, std::strerror(errno)); | |||||
return; | |||||
} | |||||
break; | |||||
case 0: | |||||
if (sendTerminate) | |||||
{ | |||||
sendTerminate = false; | |||||
kill(opid, SIGTERM); | |||||
} | |||||
if (d_gettime_ms() < timeout) | |||||
{ | |||||
d_msleep(5); | |||||
continue; | |||||
} | |||||
d_stderr("ChildProcess::stop() - timed out"); | |||||
kill(opid, SIGKILL); | |||||
waitpid(opid, nullptr, WNOHANG); | |||||
break; | |||||
default: | |||||
if (ret == opid) | |||||
{ | |||||
// success | |||||
return; | |||||
} | |||||
else | |||||
{ | |||||
d_stderr("ChildProcess::stop() - got wrong pid %i (requested was %i)", int(ret), int(opid)); | |||||
return; | |||||
} | |||||
} | |||||
break; | |||||
} | |||||
#endif | |||||
} | |||||
bool isRunning() | |||||
{ | |||||
#ifdef _WIN32 | |||||
if (pinfo.hProcess == INVALID_HANDLE_VALUE) | |||||
return false; | |||||
DWORD exitCode; | |||||
if (GetExitCodeProcess(pinfo.hProcess, &exitCode) == FALSE || | |||||
exitCode != STILL_ACTIVE || | |||||
WaitForSingleObject(pinfo.hProcess, 0) != WAIT_TIMEOUT) | |||||
{ | |||||
const PROCESS_INFORMATION opinfo = pinfo; | |||||
pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 }; | |||||
CloseHandle(opinfo.hThread); | |||||
CloseHandle(opinfo.hProcess); | |||||
return false; | |||||
} | |||||
return true; | |||||
#else | |||||
if (pid <= 0) | |||||
return false; | |||||
const pid_t ret = ::waitpid(pid, nullptr, WNOHANG); | |||||
if (ret == pid || (ret == -1 && errno == ECHILD)) | |||||
{ | |||||
pid = 0; | |||||
return false; | |||||
} | |||||
return true; | |||||
#endif | |||||
} | |||||
#ifndef _WIN32 | |||||
void signal(const int sig) | |||||
{ | |||||
if (pid > 0) | |||||
kill(pid, sig); | |||||
} | |||||
#endif | |||||
void terminate() | |||||
{ | |||||
#ifdef _WIN32 | |||||
if (pinfo.hProcess != INVALID_HANDLE_VALUE) | |||||
TerminateProcess(pinfo.hProcess, 15); | |||||
#else | |||||
if (pid > 0) | |||||
kill(pid, SIGTERM); | |||||
#endif | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE(ChildProcess) | |||||
}; | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -27,10 +27,12 @@ | |||||
#ifdef DISTRHO_OS_MAC | #ifdef DISTRHO_OS_MAC | ||||
# import <Cocoa/Cocoa.h> | # import <Cocoa/Cocoa.h> | ||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WASM | #ifdef DISTRHO_OS_WASM | ||||
# include <emscripten/emscripten.h> | # include <emscripten/emscripten.h> | ||||
# include <sys/stat.h> | # include <sys/stat.h> | ||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
# include <direct.h> | # include <direct.h> | ||||
# include <process.h> | # include <process.h> | ||||
@@ -41,13 +43,30 @@ | |||||
#else | #else | ||||
# include <unistd.h> | # include <unistd.h> | ||||
#endif | #endif | ||||
#ifdef HAVE_DBUS | #ifdef HAVE_DBUS | ||||
# include <dbus/dbus.h> | # include <dbus/dbus.h> | ||||
#endif | #endif | ||||
#ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
# define DBLCLKTME 400 | # define DBLCLKTME 400 | ||||
# include "sofd/libsofd.h" | # include "sofd/libsofd.h" | ||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wcast-qual" | |||||
# pragma GCC diagnostic ignored "-Wconversion" | |||||
# pragma GCC diagnostic ignored "-Wfloat-conversion" | |||||
# pragma GCC diagnostic ignored "-Wshadow" | |||||
# pragma GCC diagnostic ignored "-Wsign-conversion" | |||||
# pragma GCC diagnostic ignored "-Wstrict-overflow" | |||||
# endif | |||||
# include "sofd/libsofd.c" | # include "sofd/libsofd.c" | ||||
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
# undef HAVE_MNTENT | |||||
# undef MAX | |||||
# undef MIN | |||||
#endif | #endif | ||||
#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE | #ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE | ||||
@@ -329,6 +348,16 @@ struct FileBrowserData { | |||||
#else // DISTRHO_OS_WINDOWS | #else // DISTRHO_OS_WINDOWS | ||||
FileBrowserData(const bool save) | FileBrowserData(const bool save) | ||||
: selectedFile(nullptr) | : selectedFile(nullptr) | ||||
#ifdef DISTRHO_OS_MAC | |||||
, nsBasePanel(nullptr) | |||||
, nsOpenPanel(nullptr) | |||||
#endif | |||||
#ifdef HAVE_DBUS | |||||
, dbuscon(nullptr) | |||||
#endif | |||||
#ifdef HAVE_X11 | |||||
, x11display(nullptr) | |||||
#endif | |||||
{ | { | ||||
#ifdef DISTRHO_OS_MAC | #ifdef DISTRHO_OS_MAC | ||||
if (save) | if (save) | ||||
@@ -393,6 +422,8 @@ struct FileBrowserData { | |||||
std::free(const_cast<char*>(selectedFile)); | std::free(const_cast<char*>(selectedFile)); | ||||
selectedFile = nullptr; | selectedFile = nullptr; | ||||
} | } | ||||
DISTRHO_DECLARE_NON_COPYABLE(FileBrowserData) | |||||
}; | }; | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -463,7 +494,11 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, | |||||
[nsOpenPanel setCanChooseFiles:YES]; | [nsOpenPanel setCanChooseFiles:YES]; | ||||
} | } | ||||
[nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; | |||||
NSString* const startDirString = [[NSString alloc] | |||||
initWithBytes:startDir | |||||
length:strlen(startDir) | |||||
encoding:NSUTF8StringEncoding]; | |||||
[nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:startDirString]]; | |||||
// TODO file filter using allowedContentTypes: [UTType] | // TODO file filter using allowedContentTypes: [UTType] | ||||
@@ -496,6 +531,9 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, | |||||
} | } | ||||
}]; | }]; | ||||
}); | }); | ||||
[startDirString release]; | |||||
[titleString release]; | |||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -590,7 +628,8 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, | |||||
dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant); | dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant); | ||||
dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray); | dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray); | ||||
dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE, | dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE, | ||||
¤t_folder_val, startDir.length()+1); | |||||
¤t_folder_val, | |||||
static_cast<int>(startDir.length() + 1)); | |||||
dbus_message_iter_close_container(&variant, &variantArray); | dbus_message_iter_close_container(&variant, &variantArray); | ||||
dbus_message_iter_close_container(&dict, &variant); | dbus_message_iter_close_container(&dict, &variant); | ||||
dbus_message_iter_close_container(&array, &dict); | dbus_message_iter_close_container(&array, &dict); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,6 +18,10 @@ | |||||
# error bad include | # error bad include | ||||
#endif | #endif | ||||
#if !defined(DGL_USE_FILE_BROWSER) && defined(DISTRHO_UI_FILE_BROWSER) && DISTRHO_UI_FILE_BROWSER == 0 | |||||
# error To use File Browser in DPF plugins please set DISTRHO_UI_FILE_BROWSER to 1 | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// File Browser Dialog stuff | // File Browser Dialog stuff | ||||
@@ -109,17 +113,17 @@ FileBrowserHandle fileBrowserCreate(bool isEmbed, | |||||
in which case this idle function must not be called anymore for this handle. | in which case this idle function must not be called anymore for this handle. | ||||
You can then call fileBrowserGetPath to know the selected file (or null if cancelled). | You can then call fileBrowserGetPath to know the selected file (or null if cancelled). | ||||
*/ | */ | ||||
bool fileBrowserIdle(const FileBrowserHandle handle); | |||||
bool fileBrowserIdle(FileBrowserHandle handle); | |||||
/** | /** | ||||
Close and free the file browser dialog, handle must not be used afterwards. | Close and free the file browser dialog, handle must not be used afterwards. | ||||
*/ | */ | ||||
void fileBrowserClose(const FileBrowserHandle handle); | |||||
void fileBrowserClose(FileBrowserHandle handle); | |||||
/** | /** | ||||
Get the path chosen by the user or null.@n | Get the path chosen by the user or null.@n | ||||
Should only be called after fileBrowserIdle returns true. | Should only be called after fileBrowserIdle returns true. | ||||
*/ | */ | ||||
const char* fileBrowserGetPath(const FileBrowserHandle handle); | |||||
const char* fileBrowserGetPath(FileBrowserHandle handle); | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- |
@@ -404,6 +404,36 @@ public: | |||||
return false; | return false; | ||||
} | } | ||||
// ------------------------------------------------------------------- | |||||
// peek operations (returns a value without advancing read position) | |||||
/* | |||||
* Peek for an unsigned 32-bit integer. | |||||
* Returns 0 if reading fails. | |||||
*/ | |||||
uint32_t peekUInt() const noexcept | |||||
{ | |||||
uint32_t ui = 0; | |||||
return tryPeek(&ui, sizeof(int32_t)) ? ui : 0; | |||||
} | |||||
/*! | |||||
* Peek for a custom data type specified by the template typename used, | |||||
* with size being automatically deduced by the compiler (through the use of sizeof). | |||||
* | |||||
* Returns true if peeking succeeds. | |||||
* In case of failure, @a type value is automatically cleared by its deduced size. | |||||
*/ | |||||
template <typename T> | |||||
bool peekCustomType(T& type) const noexcept | |||||
{ | |||||
if (tryPeek(&type, sizeof(T))) | |||||
return true; | |||||
std::memset(&type, 0, sizeof(T)); | |||||
return false; | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// write operations | // write operations | ||||
@@ -601,7 +631,7 @@ protected: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
const uint32_t firstpart(buffer->size - tail); | |||||
const uint32_t firstpart = buffer->size - tail; | |||||
std::memcpy(bytebuf, buffer->buf + tail, firstpart); | std::memcpy(bytebuf, buffer->buf + tail, firstpart); | ||||
std::memcpy(bytebuf + firstpart, buffer->buf, readto); | std::memcpy(bytebuf + firstpart, buffer->buf, readto); | ||||
} | } | ||||
@@ -619,6 +649,63 @@ protected: | |||||
return true; | return true; | ||||
} | } | ||||
/** @internal try reading from the buffer, can fail. */ | |||||
bool tryPeek(void* const buf, const uint32_t size) const noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false); | |||||
#if defined(__clang__) | |||||
#pragma clang diagnostic push | |||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare" | |||||
#endif | |||||
DISTRHO_SAFE_ASSERT_RETURN(buffer->buf != nullptr, false); | |||||
#if defined(__clang__) | |||||
#pragma clang diagnostic pop | |||||
#endif | |||||
DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(size > 0, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(size < buffer->size, false); | |||||
// empty | |||||
if (buffer->head == buffer->tail) | |||||
return false; | |||||
uint8_t* const bytebuf = static_cast<uint8_t*>(buf); | |||||
const uint32_t head = buffer->head; | |||||
const uint32_t tail = buffer->tail; | |||||
const uint32_t wrap = head > tail ? 0 : buffer->size; | |||||
if (size > wrap + head - tail) | |||||
return false; | |||||
uint32_t readto = tail + size; | |||||
if (readto > buffer->size) | |||||
{ | |||||
readto -= buffer->size; | |||||
if (size == 1) | |||||
{ | |||||
std::memcpy(bytebuf, buffer->buf + tail, 1); | |||||
} | |||||
else | |||||
{ | |||||
const uint32_t firstpart = buffer->size - tail; | |||||
std::memcpy(bytebuf, buffer->buf + tail, firstpart); | |||||
std::memcpy(bytebuf + firstpart, buffer->buf, readto); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
std::memcpy(bytebuf, buffer->buf + tail, size); | |||||
if (readto == buffer->size) | |||||
readto = 0; | |||||
} | |||||
return true; | |||||
} | |||||
/** @internal try writing to the buffer, can fail. */ | /** @internal try writing to the buffer, can fail. */ | ||||
bool tryWrite(const void* const buf, const uint32_t size) noexcept | bool tryWrite(const void* const buf, const uint32_t size) noexcept | ||||
{ | { | ||||
@@ -656,7 +743,7 @@ protected: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
const uint32_t firstpart(buffer->size - wrtn); | |||||
const uint32_t firstpart = buffer->size - wrtn; | |||||
std::memcpy(buffer->buf + wrtn, bytebuf, firstpart); | std::memcpy(buffer->buf + wrtn, bytebuf, firstpart); | ||||
std::memcpy(buffer->buf, bytebuf + firstpart, writeto); | std::memcpy(buffer->buf, bytebuf + firstpart, writeto); | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -29,7 +29,9 @@ | |||||
# include <unistd.h> | # include <unistd.h> | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
// d_*sleep | // d_*sleep | ||||
/* | /* | ||||
@@ -66,6 +68,8 @@ void d_msleep(const uint msecs) noexcept | |||||
} DISTRHO_SAFE_EXCEPTION("d_msleep"); | } DISTRHO_SAFE_EXCEPTION("d_msleep"); | ||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_SLEEP_HPP_INCLUDED | #endif // DISTRHO_SLEEP_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -22,10 +22,6 @@ | |||||
#include <algorithm> | #include <algorithm> | ||||
#if __cplusplus >= 201703L | |||||
# include <string_view> | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -91,16 +87,6 @@ public: | |||||
_dup(strBuf); | _dup(strBuf); | ||||
} | } | ||||
#if __cplusplus >= 201703L | |||||
/* | |||||
* constexpr compatible variant. | |||||
*/ | |||||
explicit constexpr String(const std::string_view& strView) noexcept | |||||
: fBuffer(const_cast<char*>(strView.data())), | |||||
fBufferLen(strView.size()), | |||||
fBufferAlloc(false) {} | |||||
#endif | |||||
/* | /* | ||||
* Integer. | * Integer. | ||||
*/ | */ | ||||
@@ -695,11 +681,11 @@ public: | |||||
"abcdefghijklmnopqrstuvwxyz" | "abcdefghijklmnopqrstuvwxyz" | ||||
"0123456789+/"; | "0123456789+/"; | ||||
#ifndef _MSC_VER | |||||
#ifndef _MSC_VER | |||||
const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U); | const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U); | ||||
#else | |||||
#else | |||||
constexpr std::size_t kTmpBufSize = 65536U; | constexpr std::size_t kTmpBufSize = 65536U; | ||||
#endif | |||||
#endif | |||||
const uchar* bytesToEncode((const uchar*)data); | const uchar* bytesToEncode((const uchar*)data); | ||||
@@ -0,0 +1,127 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_TIME_HPP_INCLUDED | |||||
#define DISTRHO_TIME_HPP_INCLUDED | |||||
#include "../DistrhoUtils.hpp" | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# include <winsock2.h> | |||||
# include <windows.h> | |||||
# include <mmsystem.h> | |||||
#else | |||||
# include <ctime> | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
// d_gettime_* | |||||
/* | |||||
* Get a monotonically-increasing time in milliseconds. | |||||
*/ | |||||
static inline | |||||
uint32_t d_gettime_ms() noexcept | |||||
{ | |||||
#if defined(DISTRHO_OS_MAC) | |||||
static const time_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000; | |||||
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000) - s; | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
return static_cast<uint32_t>(timeGetTime()); | |||||
#else | |||||
static struct { | |||||
timespec ts; | |||||
int r; | |||||
uint32_t ms; | |||||
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint32_t>(s.ts.tv_sec * 1000 + | |||||
s.ts.tv_nsec / 1000000) }; | |||||
timespec ts; | |||||
clock_gettime(CLOCK_MONOTONIC, &ts); | |||||
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) - s.ms; | |||||
#endif | |||||
} | |||||
/* | |||||
* Get a monotonically-increasing time in microseconds. | |||||
*/ | |||||
static inline | |||||
uint64_t d_gettime_us() noexcept | |||||
{ | |||||
#if defined(DISTRHO_OS_MAC) | |||||
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000; | |||||
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000) - s; | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
static struct { | |||||
LARGE_INTEGER freq; | |||||
LARGE_INTEGER counter; | |||||
BOOL r1, r2; | |||||
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) }; | |||||
LARGE_INTEGER counter; | |||||
QueryPerformanceCounter(&counter); | |||||
return (counter.QuadPart - s.counter.QuadPart) * 1000000 / s.freq.QuadPart; | |||||
#else | |||||
static struct { | |||||
timespec ts; | |||||
int r; | |||||
uint64_t us; | |||||
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000 + | |||||
s.ts.tv_nsec / 1000) }; | |||||
timespec ts; | |||||
clock_gettime(CLOCK_MONOTONIC, &ts); | |||||
return (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) - s.us; | |||||
#endif | |||||
} | |||||
/* | |||||
* Get a monotonically-increasing time in nanoseconds. | |||||
*/ | |||||
static inline | |||||
uint64_t d_gettime_ns() noexcept | |||||
{ | |||||
#if defined(DISTRHO_OS_MAC) | |||||
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); | |||||
return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) - s; | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
static struct { | |||||
LARGE_INTEGER freq; | |||||
LARGE_INTEGER counter; | |||||
BOOL r1, r2; | |||||
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) }; | |||||
LARGE_INTEGER counter; | |||||
QueryPerformanceCounter(&counter); | |||||
return (counter.QuadPart - s.counter.QuadPart) * 1000000000ULL / s.freq.QuadPart; | |||||
#else | |||||
static struct { | |||||
timespec ts; | |||||
int r; | |||||
uint64_t ns; | |||||
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000000ULL + | |||||
s.ts.tv_nsec) }; | |||||
timespec ts; | |||||
clock_gettime(CLOCK_MONOTONIC, &ts); | |||||
return (ts.tv_sec * 1000000000ULL + ts.tv_nsec) - s.ns; | |||||
#endif | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_TIME_HPP_INCLUDED |
@@ -0,0 +1,28 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_WEB_VIEW_HPP_INCLUDED | |||||
#define DISTRHO_WEB_VIEW_HPP_INCLUDED | |||||
#include "../DistrhoUtils.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
#include "WebViewImpl.hpp" | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_WEB_VIEW_HPP_INCLUDED |
@@ -0,0 +1,126 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED) | |||||
# error bad include | |||||
#endif | |||||
#if !defined(DGL_UI_USE_WEB_VIEW) && defined(DISTRHO_UI_WEB_VIEW) && DISTRHO_UI_WEB_VIEW == 0 | |||||
# error To use WebViews in DPF plugins please set DISTRHO_UI_WEB_VIEW to 1 | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Web View stuff | |||||
struct WebViewData; | |||||
typedef WebViewData* WebViewHandle; | |||||
typedef void (*WebViewMessageCallback)(void* arg, char* msg); | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Web view options, for customizing web view details. | |||||
*/ | |||||
struct WebViewOptions { | |||||
/** | |||||
Position offset, for cases of mixing regular widgets with web views. | |||||
*/ | |||||
struct PositionOffset { | |||||
/** Horizontal offset, with scale factor pre-applied */ | |||||
int x; | |||||
/** Vertical offset, with scale factor pre-applied */ | |||||
int y; | |||||
/** Constructor for default values */ | |||||
PositionOffset() : x(0), y(0) {} | |||||
} offset; | |||||
/** | |||||
Set some JavaScript to evalute on every new page load. | |||||
*/ | |||||
const char* initialJS; | |||||
/** | |||||
Message callback triggered from JavaScript code inside the WebView. | |||||
*/ | |||||
WebViewMessageCallback callback; | |||||
void* callbackPtr; | |||||
/** Constructor for default values */ | |||||
WebViewOptions() | |||||
: offset(), | |||||
initialJS(nullptr), | |||||
callback(nullptr), | |||||
callbackPtr(nullptr) {} | |||||
/** Constructor providing a callback */ | |||||
WebViewOptions(const WebViewMessageCallback cb, void* const ptr) | |||||
: offset(), | |||||
initialJS(nullptr), | |||||
callback(cb), | |||||
callbackPtr(ptr) {} | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Create a new web view. | |||||
The web view will be added on top of an existing platform-specific view/window. | |||||
This means it will draw on top of whatever is below it, | |||||
something to take into consideration if mixing regular widgets with web views. | |||||
Provided metrics must have scale factor pre-applied. | |||||
@p windowId: The native window id to attach this view to (X11 Window, HWND or NSView*) | |||||
@p scaleFactor: Scale factor in use | |||||
@p options: Extra options, optional | |||||
*/ | |||||
WebViewHandle webViewCreate(const char* url, | |||||
uintptr_t windowId, | |||||
uint initialWidth, | |||||
uint initialHeight, | |||||
double scaleFactor, | |||||
const WebViewOptions& options = WebViewOptions()); | |||||
/** | |||||
Destroy the web view, handle must not be used afterwards. | |||||
*/ | |||||
void webViewDestroy(WebViewHandle webview); | |||||
/** | |||||
Idle the web view, to be called on regular intervals. | |||||
Can cause callbacks to trigger. | |||||
*/ | |||||
void webViewIdle(WebViewHandle webview); | |||||
/** | |||||
Evaluate/run JavaScript on the web view. | |||||
*/ | |||||
void webViewEvaluateJS(WebViewHandle webview, const char* js); | |||||
/** | |||||
Reload the web view current page. | |||||
*/ | |||||
void webViewReload(WebViewHandle webview); | |||||
/** | |||||
Resize the web view. | |||||
*/ | |||||
void webViewResize(WebViewHandle webview, uint width, uint height, double scaleFactor); | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,101 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED) | |||||
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||||
# include "WebView.hpp" | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Web View stuff | |||||
START_NAMESPACE_DISTRHO | |||||
class WebView; | |||||
WebView* webview_choc_create(const WebViewOptions& opts); | |||||
void webview_choc_destroy(WebView*); | |||||
void* webview_choc_handle(WebView*); | |||||
void webview_choc_eval(WebView*, const char* js); | |||||
void webview_choc_navigate(WebView*, const char* url); | |||||
END_NAMESPACE_DISTRHO | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifdef DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||||
# define WC_ERR_INVALID_CHARS 0 | |||||
# include "choc/choc_WebView.h" | |||||
START_NAMESPACE_DISTRHO | |||||
WebView* webview_choc_create(const WebViewOptions& opts) | |||||
{ | |||||
WebView::Options wopts; | |||||
wopts.acceptsFirstMouseClick = true; | |||||
wopts.enableDebugMode = true; | |||||
std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts); | |||||
DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr); | |||||
if (const WebViewMessageCallback callback = opts.callback) | |||||
{ | |||||
webview->addInitScript("function postMessage(m){window.chrome.webview.postMessage(m);}"); | |||||
void* const callbackPtr = opts.callbackPtr; | |||||
webview->bind([callback, callbackPtr](const std::string& value) { | |||||
char* const data = strdup(value.data()); | |||||
callback(callbackPtr, data); | |||||
std::free(data); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
webview->addInitScript("function postMessage(m){}"); | |||||
} | |||||
if (opts.initialJS != nullptr) | |||||
webview->addInitScript(opts.initialJS); | |||||
return webview.release(); | |||||
} | |||||
void webview_choc_destroy(WebView* const webview) | |||||
{ | |||||
delete webview; | |||||
} | |||||
void* webview_choc_handle(WebView* const webview) | |||||
{ | |||||
return webview->getViewHandle(); | |||||
} | |||||
void webview_choc_eval(WebView* const webview, const char* const js) | |||||
{ | |||||
webview->evaluateJavascript(js); | |||||
} | |||||
void webview_choc_navigate(WebView* const webview, const char* const url) | |||||
{ | |||||
webview->navigate(url); | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -0,0 +1,15 @@ | |||||
## CHOC: licensing | |||||
I'd like anyone to feel able to use this library code without worrying about the legal implications, so it's released under the permissive ISC license: | |||||
---- | |||||
**Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.** | |||||
**THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.** | |||||
https://en.wikipedia.org/wiki/ISC_license | |||||
---- | |||||
Note that if you use the `choc::ui::WebView` class on Windows, it embeds some Microsoft redistributable code which has its own (permissive) license that you should be aware of. See inside the file `choc_WebView.h` for more details. |
@@ -0,0 +1,22 @@ | |||||
Taken from https://github.com/Tracktion/choc | |||||
``` | |||||
commit 2512542b2d65f3e92df7f2f1f7eeb712fa41a0de (HEAD -> main, origin/main, origin/HEAD) | |||||
Author: Cesare Ferrari <cesare.ferrari@gmail.com> | |||||
Date: Sun Apr 28 12:53:17 2024 +0100 | |||||
Disable additional gcc warnin | |||||
``` | |||||
With the big [choc.patch](./choc.patch) patch applied to top for: | |||||
- remove everything not related to windows | |||||
- remove everything unused by DPF | |||||
- convert webview JS callbacks to pass raw strings instead of json | |||||
- remove even more stuff (json no longer needed) | |||||
- convert choc asserts into distrho ones | |||||
- put everything inside distrho namespace | |||||
And then backported: | |||||
- https://github.com/Tracktion/choc/commit/792e4bd9bedf38b9a28f12be0535c90649d5616b |
@@ -0,0 +1,154 @@ | |||||
// | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes ** | |||||
// ██ ███████ ██ ██ ██ | |||||
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// | |||||
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license: | |||||
// | |||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or | |||||
// without fee is hereby granted, provided that the above copyright notice and this permission | |||||
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |||||
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
#ifndef CHOC_DESKTOPWINDOW_HEADER_INCLUDED | |||||
#define CHOC_DESKTOPWINDOW_HEADER_INCLUDED | |||||
#include "choc_Platform.h" | |||||
//============================================================================== | |||||
// _ _ _ _ | |||||
// __| | ___ | |_ __ _ (_)| | ___ | |||||
// / _` | / _ \| __| / _` || || |/ __| | |||||
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _ | |||||
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_) | |||||
// | |||||
// Code beyond this point is implementation detail... | |||||
// | |||||
//============================================================================== | |||||
#undef WIN32_LEAN_AND_MEAN | |||||
#define WIN32_LEAN_AND_MEAN | |||||
#undef NOMINMAX | |||||
#define NOMINMAX | |||||
#define Rectangle Rectangle_renamed_to_avoid_name_collisions | |||||
#include <windows.h> | |||||
#undef Rectangle | |||||
START_NAMESPACE_DISTRHO | |||||
struct HWNDHolder | |||||
{ | |||||
HWNDHolder() = default; | |||||
HWNDHolder (HWND h) : hwnd (h) {} | |||||
HWNDHolder (const HWNDHolder&) = delete; | |||||
HWNDHolder& operator= (const HWNDHolder&) = delete; | |||||
HWNDHolder (HWNDHolder&& other) : hwnd (other.hwnd) { other.hwnd = {}; } | |||||
HWNDHolder& operator= (HWNDHolder&& other) { reset(); hwnd = other.hwnd; other.hwnd = {}; return *this; } | |||||
~HWNDHolder() { reset(); } | |||||
operator HWND() const { return hwnd; } | |||||
operator void*() const { return (void*) hwnd; } | |||||
void reset() { if (IsWindow (hwnd)) DestroyWindow (hwnd); hwnd = {}; } | |||||
HWND hwnd = {}; | |||||
}; | |||||
struct WindowClass | |||||
{ | |||||
WindowClass (std::wstring name, WNDPROC wndProc) | |||||
{ | |||||
name += std::to_wstring (static_cast<uint32_t> (GetTickCount())); | |||||
moduleHandle = GetModuleHandle (nullptr); | |||||
auto icon = (HICON) LoadImage (moduleHandle, IDI_APPLICATION, IMAGE_ICON, | |||||
GetSystemMetrics (SM_CXSMICON), | |||||
GetSystemMetrics (SM_CYSMICON), | |||||
LR_DEFAULTCOLOR); | |||||
WNDCLASSEXW wc; | |||||
ZeroMemory (&wc, sizeof(wc)); | |||||
wc.cbSize = sizeof(wc); | |||||
wc.style = CS_OWNDC; | |||||
wc.hInstance = moduleHandle; | |||||
wc.lpszClassName = name.c_str(); | |||||
wc.hIcon = icon; | |||||
wc.hIconSm = icon; | |||||
wc.lpfnWndProc = wndProc; | |||||
classAtom = (LPCWSTR) (uintptr_t) RegisterClassExW (&wc); | |||||
DISTRHO_SAFE_ASSERT (classAtom != 0); | |||||
} | |||||
~WindowClass() | |||||
{ | |||||
UnregisterClassW (classAtom, moduleHandle); | |||||
} | |||||
HWNDHolder createWindow (DWORD style, int w, int h, void* userData) | |||||
{ | |||||
if (auto hwnd = CreateWindowW (classAtom, L"", style, CW_USEDEFAULT, CW_USEDEFAULT, | |||||
w, h, nullptr, nullptr, moduleHandle, nullptr)) | |||||
{ | |||||
SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) userData); | |||||
return hwnd; | |||||
} | |||||
return {}; | |||||
} | |||||
auto getClassName() const { return classAtom; } | |||||
HINSTANCE moduleHandle = {}; | |||||
LPCWSTR classAtom = {}; | |||||
}; | |||||
static std::string createUTF8FromUTF16 (const std::wstring& utf16) | |||||
{ | |||||
if (! utf16.empty()) | |||||
{ | |||||
auto numWideChars = static_cast<int> (utf16.size()); | |||||
auto resultSize = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, nullptr, 0, nullptr, nullptr); | |||||
if (resultSize > 0) | |||||
{ | |||||
std::string result; | |||||
result.resize (static_cast<size_t> (resultSize)); | |||||
if (WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, result.data(), resultSize, nullptr, nullptr) > 0) | |||||
return result; | |||||
} | |||||
} | |||||
return {}; | |||||
} | |||||
static std::wstring createUTF16StringFromUTF8 (std::string_view utf8) | |||||
{ | |||||
if (! utf8.empty()) | |||||
{ | |||||
auto numUTF8Bytes = static_cast<int> (utf8.size()); | |||||
auto resultSize = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, nullptr, 0); | |||||
if (resultSize > 0) | |||||
{ | |||||
std::wstring result; | |||||
result.resize (static_cast<size_t> (resultSize)); | |||||
if (MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, result.data(), resultSize) > 0) | |||||
return result; | |||||
} | |||||
} | |||||
return {}; | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // CHOC_DESKTOPWINDOW_HEADER_INCLUDED |
@@ -0,0 +1,141 @@ | |||||
// | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes ** | |||||
// ██ ███████ ██ ██ ██ | |||||
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// | |||||
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license: | |||||
// | |||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or | |||||
// without fee is hereby granted, provided that the above copyright notice and this permission | |||||
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |||||
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
#ifndef CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED | |||||
#define CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED | |||||
#include <string> | |||||
START_NAMESPACE_DISTRHO | |||||
//============================================================================== | |||||
/** | |||||
A minimal cross-platform loader for .dll/.so files. | |||||
*/ | |||||
struct DynamicLibrary | |||||
{ | |||||
DynamicLibrary() = default; | |||||
/// Attempts to load a library with the given name or path. | |||||
DynamicLibrary (std::string_view library); | |||||
DynamicLibrary (const DynamicLibrary&) = delete; | |||||
DynamicLibrary& operator= (const DynamicLibrary&) = delete; | |||||
DynamicLibrary (DynamicLibrary&&); | |||||
DynamicLibrary& operator= (DynamicLibrary&&); | |||||
/// On destruction, this object releases the library that was loaded | |||||
~DynamicLibrary(); | |||||
/// Returns a pointer to the function with this name, or nullptr if not found. | |||||
void* findFunction (std::string_view functionName); | |||||
/// Returns true if the library was successfully loaded | |||||
operator bool() const noexcept { return handle != nullptr; } | |||||
/// Releases any handle that this object is holding | |||||
void close(); | |||||
/// platform-specific handle. Will be nullptr if not loaded | |||||
void* handle = nullptr; | |||||
}; | |||||
//============================================================================== | |||||
// _ _ _ _ | |||||
// __| | ___ | |_ __ _ (_)| | ___ | |||||
// / _` | / _ \| __| / _` || || |/ __| | |||||
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _ | |||||
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_) | |||||
// | |||||
// Code beyond this point is implementation detail... | |||||
// | |||||
//============================================================================== | |||||
inline DynamicLibrary::~DynamicLibrary() | |||||
{ | |||||
close(); | |||||
} | |||||
inline DynamicLibrary::DynamicLibrary (DynamicLibrary&& other) : handle (other.handle) | |||||
{ | |||||
other.handle = nullptr; | |||||
} | |||||
inline DynamicLibrary& DynamicLibrary::operator= (DynamicLibrary&& other) | |||||
{ | |||||
close(); | |||||
handle = other.handle; | |||||
other.handle = nullptr; | |||||
return *this; | |||||
} | |||||
//============================================================================== | |||||
namespace win32_defs | |||||
{ | |||||
#if ! (defined (_WINDOWS_) || defined (_APISETLIBLOADER_)) // only use these local definitions if windows.h isn't already included | |||||
using CHOC_HMODULE = void*; | |||||
#ifdef _MSC_VER | |||||
extern "C" CHOC_HMODULE __stdcall choc_LoadLibraryA (const char*); | |||||
extern "C" int __stdcall choc_FreeLibrary (CHOC_HMODULE); | |||||
extern "C" void* __stdcall choc_GetProcAddress (CHOC_HMODULE, const char*); | |||||
#pragma comment(linker,"/alternatename:choc_LoadLibraryA=LoadLibraryA") | |||||
#pragma comment(linker,"/alternatename:choc_FreeLibrary=FreeLibrary") | |||||
#pragma comment(linker,"/alternatename:choc_GetProcAddress=GetProcAddress") | |||||
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return choc_LoadLibraryA (l); } | |||||
static inline int FreeLibrary (CHOC_HMODULE m) { return choc_FreeLibrary (m); } | |||||
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return choc_GetProcAddress (m, f); } | |||||
#else | |||||
extern "C" __declspec(dllimport) CHOC_HMODULE __stdcall LoadLibraryA (const char*); | |||||
extern "C" __declspec(dllimport) int __stdcall FreeLibrary (CHOC_HMODULE); | |||||
extern "C" __declspec(dllimport) void* __stdcall GetProcAddress (CHOC_HMODULE, const char*); | |||||
#endif | |||||
#else | |||||
using CHOC_HMODULE = HMODULE; | |||||
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return ::LoadLibraryA (l); } | |||||
static inline int FreeLibrary (CHOC_HMODULE m) { return ::FreeLibrary (m); } | |||||
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return (void*) ::GetProcAddress (m, f); } | |||||
#endif | |||||
} | |||||
inline DynamicLibrary::DynamicLibrary (std::string_view library) | |||||
{ | |||||
handle = (void*) win32_defs::LoadLibraryA (std::string (library).c_str()); | |||||
} | |||||
inline void DynamicLibrary::close() | |||||
{ | |||||
if (handle != nullptr) | |||||
{ | |||||
win32_defs::FreeLibrary ((win32_defs::CHOC_HMODULE) handle); | |||||
handle = nullptr; | |||||
} | |||||
} | |||||
inline void* DynamicLibrary::findFunction (std::string_view name) | |||||
{ | |||||
if (handle != nullptr) | |||||
return (void*) win32_defs::GetProcAddress ((win32_defs::CHOC_HMODULE) handle, std::string (name).c_str()); | |||||
return {}; | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED |
@@ -0,0 +1,511 @@ | |||||
// | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes ** | |||||
// ██ ███████ ██ ██ ██ | |||||
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// | |||||
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license: | |||||
// | |||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or | |||||
// without fee is hereby granted, provided that the above copyright notice and this permission | |||||
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |||||
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
#ifndef CHOC_MEMORYDLL_HEADER_INCLUDED | |||||
#define CHOC_MEMORYDLL_HEADER_INCLUDED | |||||
#include <stddef.h> | |||||
#include <memory> | |||||
#include <string> | |||||
START_NAMESPACE_DISTRHO | |||||
/** | |||||
MemoryDLL is an egregious hack that allows you to load DLL files from a chunk | |||||
of memory in the same way you might load them from a file on disk. | |||||
This opens up the ability to do horrible things such as embedding a random DLL | |||||
in a chunk of C++ code, so that it gets baked directly into your executable.. | |||||
That means that if your app requires a 3rd-party DLL but you don't want the hassle | |||||
of having to install the DLL file in the right place on your users' machines, you | |||||
could use this trick to embed it invisibly inside your executable... | |||||
Currently this is only implemented for Windows DLLs, but a linux/OSX loader for | |||||
.dylibs is also totally feasible if anyone fancies having a go :) | |||||
@see DynamicLibrary | |||||
*/ | |||||
struct MemoryDLL | |||||
{ | |||||
MemoryDLL() = default; | |||||
MemoryDLL (MemoryDLL&&) = default; | |||||
MemoryDLL& operator= (MemoryDLL&&) = default; | |||||
~MemoryDLL(); | |||||
/// Attempts to load a chunk of memory that contains a DLL file image. | |||||
MemoryDLL (const void* data, size_t size); | |||||
/// Returns a pointer to the function with this name, or nullptr if not found. | |||||
void* findFunction (std::string_view functionName); | |||||
/// Returns true if the library was successfully loaded | |||||
operator bool() const { return pimpl != nullptr; } | |||||
private: | |||||
struct Pimpl; | |||||
std::unique_ptr<Pimpl> pimpl; | |||||
}; | |||||
END_NAMESPACE_DISTRHO | |||||
//============================================================================== | |||||
// _ _ _ _ | |||||
// __| | ___ | |_ __ _ (_)| | ___ | |||||
// / _` | / _ \| __| / _` || || |/ __| | |||||
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _ | |||||
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_) | |||||
// | |||||
// Code beyond this point is implementation detail... | |||||
// | |||||
//============================================================================== | |||||
#include <vector> | |||||
#include <unordered_map> | |||||
#undef WIN32_LEAN_AND_MEAN | |||||
#define WIN32_LEAN_AND_MEAN | |||||
#undef NOMINMAX | |||||
#define NOMINMAX | |||||
#define Rectangle Rectangle_renamed_to_avoid_name_collisions | |||||
#include <windows.h> | |||||
#undef Rectangle | |||||
START_NAMESPACE_DISTRHO | |||||
struct MemoryDLL::Pimpl | |||||
{ | |||||
Pimpl() = default; | |||||
~Pimpl() | |||||
{ | |||||
if (entryFunction != nullptr) | |||||
(*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_DETACH, nullptr); | |||||
for (auto& m : loadedModules) | |||||
FreeLibrary (m); | |||||
if (imageData != nullptr) | |||||
VirtualFree (imageData, 0, MEM_RELEASE); | |||||
for (auto m : virtualBlocks) | |||||
VirtualFree (m, 0, MEM_RELEASE); | |||||
} | |||||
bool initialise (const void* data, size_t size) | |||||
{ | |||||
if (size < sizeof (IMAGE_DOS_HEADER)) | |||||
return false; | |||||
auto dosHeader = static_cast<const IMAGE_DOS_HEADER*> (data); | |||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE | |||||
|| size < static_cast<size_t> (dosHeader->e_lfanew) + sizeof (IMAGE_NT_HEADERS)) | |||||
return false; | |||||
const auto& headers = *getOffsetAs<IMAGE_NT_HEADERS> (data, dosHeader->e_lfanew); | |||||
if (headers.Signature != IMAGE_NT_SIGNATURE | |||||
|| (headers.OptionalHeader.SectionAlignment & 1) != 0) | |||||
return false; | |||||
#ifdef _M_ARM64 | |||||
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_ARM64) return false; | |||||
#elif defined (_WIN64) | |||||
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) return false; | |||||
#else | |||||
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_I386) return false; | |||||
#endif | |||||
SYSTEM_INFO systemInfo; | |||||
GetNativeSystemInfo (std::addressof (systemInfo)); | |||||
auto alignedImageSize = roundUp (headers.OptionalHeader.SizeOfImage, systemInfo.dwPageSize); | |||||
if (alignedImageSize != roundUp (getLastSectionEnd (headers), systemInfo.dwPageSize)) | |||||
return false; | |||||
imageData = VirtualAlloc (reinterpret_cast<void*> (headers.OptionalHeader.ImageBase), | |||||
alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |||||
if (imageData == nullptr) | |||||
{ | |||||
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |||||
if (imageData == nullptr) | |||||
return false; | |||||
} | |||||
while ((((uint64_t) imageData) >> 32) < (((uint64_t) imageData + alignedImageSize) >> 32)) | |||||
{ | |||||
virtualBlocks.push_back (imageData); | |||||
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); | |||||
if (imageData == nullptr) | |||||
return false; | |||||
} | |||||
isDLL = (headers.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; | |||||
pageSize = systemInfo.dwPageSize; | |||||
if (size < headers.OptionalHeader.SizeOfHeaders) | |||||
return false; | |||||
auto newHeaders = VirtualAlloc (imageData, headers.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); | |||||
memcpy (newHeaders, dosHeader, headers.OptionalHeader.SizeOfHeaders); | |||||
imageHeaders = getOffsetAs<IMAGE_NT_HEADERS> (newHeaders, dosHeader->e_lfanew); | |||||
imageHeaders->OptionalHeader.ImageBase = reinterpret_cast<uintptr_t> (imageData); | |||||
if (copySections (data, size, headers.OptionalHeader.SectionAlignment)) | |||||
{ | |||||
if (auto locationDelta = (ptrdiff_t) (imageHeaders->OptionalHeader.ImageBase - headers.OptionalHeader.ImageBase)) | |||||
performRelocation (locationDelta); | |||||
if (loadImports() && prepareSections()) | |||||
{ | |||||
executeTLS(); | |||||
loadNameTable(); | |||||
if (imageHeaders->OptionalHeader.AddressOfEntryPoint != 0) | |||||
{ | |||||
entryFunction = getOffsetAs<char> (imageData, imageHeaders->OptionalHeader.AddressOfEntryPoint); | |||||
if (isDLL) | |||||
return (*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_ATTACH, nullptr); | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
void* findFunction (std::string_view name) | |||||
{ | |||||
if (auto found = exportedFunctionOffsets.find (std::string (name)); found != exportedFunctionOffsets.end()) | |||||
return getOffsetAs<char> (imageData, found->second); | |||||
return {}; | |||||
} | |||||
private: | |||||
PIMAGE_NT_HEADERS imageHeaders = {}; | |||||
void* imageData = nullptr; | |||||
std::vector<HMODULE> loadedModules; | |||||
uint32_t pageSize = 0; | |||||
bool isDLL = false; | |||||
std::vector<void*> virtualBlocks; | |||||
std::unordered_map<std::string, size_t> exportedFunctionOffsets; | |||||
using DLLEntryFn = BOOL(WINAPI*)(HINSTANCE, DWORD, void*); | |||||
void* entryFunction = {}; | |||||
template <typename Type, typename Diff> | |||||
static const Type* getOffsetAs (const void* address, Diff offset) | |||||
{ | |||||
return reinterpret_cast<const Type*> (static_cast<const char*> (address) + offset); | |||||
} | |||||
template <typename Type, typename Diff> | |||||
static Type* getOffsetAs (void* address, Diff offset) | |||||
{ | |||||
return reinterpret_cast<Type*> (static_cast<char*> (address) + offset); | |||||
} | |||||
template <typename Type> | |||||
Type* getDataDirectoryAddress (int type) const | |||||
{ | |||||
auto& dd = imageHeaders->OptionalHeader.DataDirectory[type]; | |||||
if (dd.Size > 0) | |||||
return getOffsetAs<Type> (imageData, dd.VirtualAddress); | |||||
return {}; | |||||
} | |||||
static size_t getLastSectionEnd (const IMAGE_NT_HEADERS& headers) | |||||
{ | |||||
auto section = IMAGE_FIRST_SECTION (&headers); | |||||
auto optionalSectionSize = headers.OptionalHeader.SectionAlignment; | |||||
size_t lastSectionEnd = 0; | |||||
for (uint32_t i = 0; i < headers.FileHeader.NumberOfSections; ++i, ++section) | |||||
{ | |||||
auto end = section->VirtualAddress + (section->SizeOfRawData == 0 ? optionalSectionSize | |||||
: section->SizeOfRawData); | |||||
if (end > lastSectionEnd) | |||||
lastSectionEnd = end; | |||||
} | |||||
return lastSectionEnd; | |||||
} | |||||
void loadNameTable() | |||||
{ | |||||
if (auto exports = getDataDirectoryAddress<IMAGE_EXPORT_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_EXPORT)) | |||||
{ | |||||
if (exports->NumberOfNames > 0 && exports->NumberOfFunctions > 0) | |||||
{ | |||||
auto name = getOffsetAs<const DWORD> (imageData, exports->AddressOfNames); | |||||
auto ordinal = getOffsetAs<const WORD> (imageData, exports->AddressOfNameOrdinals); | |||||
exportedFunctionOffsets.reserve (exports->NumberOfNames); | |||||
for (size_t i = 0; i < exports->NumberOfNames; ++i, ++name, ++ordinal) | |||||
if (*ordinal <= exports->NumberOfFunctions) | |||||
exportedFunctionOffsets[std::string (getOffsetAs<const char> (imageData, *name))] | |||||
= getOffsetAs<DWORD> (imageData, exports->AddressOfFunctions)[*ordinal]; | |||||
} | |||||
} | |||||
} | |||||
void executeTLS() | |||||
{ | |||||
if (auto tls = getDataDirectoryAddress<IMAGE_TLS_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_TLS)) | |||||
if (auto callback = reinterpret_cast<PIMAGE_TLS_CALLBACK*> (tls->AddressOfCallBacks)) | |||||
while (*callback != nullptr) | |||||
(*callback++) ((void*) imageData, DLL_PROCESS_ATTACH, nullptr); | |||||
} | |||||
bool prepareSections() | |||||
{ | |||||
auto section = IMAGE_FIRST_SECTION (imageHeaders); | |||||
auto size = getSectionSize (*section); | |||||
auto address = getSectionAddress (*section); | |||||
auto addressPage = getPageBase (address); | |||||
auto characteristics = section->Characteristics; | |||||
for (WORD i = 1; i < imageHeaders->FileHeader.NumberOfSections; ++i) | |||||
{ | |||||
++section; | |||||
auto nextSize = getSectionSize (*section); | |||||
auto nextAddress = getSectionAddress (*section); | |||||
auto nextAddressPage = getPageBase (nextAddress); | |||||
if (addressPage == nextAddressPage || address + size > nextAddressPage) | |||||
{ | |||||
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) | |||||
characteristics = (characteristics | section->Characteristics) & ~static_cast<DWORD> (IMAGE_SCN_MEM_DISCARDABLE); | |||||
else | |||||
characteristics |= section->Characteristics; | |||||
size = static_cast<size_t> ((nextAddress + nextSize) - address); | |||||
continue; | |||||
} | |||||
if (! setProtectionFlags (size, characteristics, address, addressPage, false)) | |||||
return false; | |||||
size = nextSize; | |||||
address = nextAddress; | |||||
addressPage = nextAddressPage; | |||||
characteristics = section->Characteristics; | |||||
} | |||||
return setProtectionFlags (size, characteristics, address, addressPage, true); | |||||
} | |||||
bool setProtectionFlags (size_t sectionSize, DWORD sectionCharacteristics, void* sectionAddress, void* addressPage, bool isLast) | |||||
{ | |||||
if (sectionSize == 0) | |||||
return true; | |||||
if ((sectionCharacteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) | |||||
{ | |||||
if (sectionAddress == addressPage | |||||
&& (isLast || imageHeaders->OptionalHeader.SectionAlignment == pageSize || (sectionSize % pageSize) == 0)) | |||||
VirtualFree (sectionAddress, sectionSize, MEM_DECOMMIT); | |||||
return true; | |||||
} | |||||
auto getProtectionFlags = [] (DWORD type) | |||||
{ | |||||
return ((type & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0) | |||||
| ((type & IMAGE_SCN_MEM_EXECUTE) | |||||
? ((type & IMAGE_SCN_MEM_READ) | |||||
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ) | |||||
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_WRITECOPY : PAGE_EXECUTE)) | |||||
: ((type & IMAGE_SCN_MEM_READ) | |||||
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_READWRITE : PAGE_READONLY) | |||||
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_WRITECOPY : PAGE_NOACCESS))); | |||||
}; | |||||
DWORD oldProtectValue; | |||||
return VirtualProtect (sectionAddress, sectionSize, | |||||
static_cast<DWORD> (getProtectionFlags (sectionCharacteristics)), | |||||
std::addressof (oldProtectValue)) != 0; | |||||
} | |||||
bool loadImports() | |||||
{ | |||||
auto imp = getDataDirectoryAddress<IMAGE_IMPORT_DESCRIPTOR> (IMAGE_DIRECTORY_ENTRY_IMPORT); | |||||
if (imp == nullptr) | |||||
return false; | |||||
while (! IsBadReadPtr (imp, sizeof (IMAGE_IMPORT_DESCRIPTOR)) && imp->Name != 0) | |||||
{ | |||||
auto handle = LoadLibraryA (getOffsetAs<const char> (imageData, imp->Name)); | |||||
if (handle == nullptr) | |||||
return false; | |||||
loadedModules.push_back (handle); | |||||
auto thunkRef = getOffsetAs<uintptr_t> (imageData, imp->OriginalFirstThunk ? imp->OriginalFirstThunk | |||||
: imp->FirstThunk); | |||||
auto funcRef = getOffsetAs<FARPROC> (imageData, imp->FirstThunk); | |||||
for (; *thunkRef != 0; ++thunkRef, ++funcRef) | |||||
{ | |||||
auto name = IMAGE_SNAP_BY_ORDINAL(*thunkRef) | |||||
? (LPCSTR) IMAGE_ORDINAL(*thunkRef) | |||||
: (LPCSTR) std::addressof (getOffsetAs<IMAGE_IMPORT_BY_NAME> (imageData, *thunkRef)->Name); | |||||
*funcRef = GetProcAddress (handle, name); | |||||
if (*funcRef == 0) | |||||
return false; | |||||
} | |||||
++imp; | |||||
} | |||||
return true; | |||||
} | |||||
size_t getSectionSize (const IMAGE_SECTION_HEADER& section) const | |||||
{ | |||||
if (auto size = section.SizeOfRawData) | |||||
return size; | |||||
if (section.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) | |||||
return imageHeaders->OptionalHeader.SizeOfInitializedData; | |||||
if (section.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) | |||||
return imageHeaders->OptionalHeader.SizeOfUninitializedData; | |||||
return 0; | |||||
} | |||||
static size_t roundUp (size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } | |||||
char* getPageBase (void* address) const { return (char*) (reinterpret_cast<uintptr_t> (address) & ~static_cast<uintptr_t> (pageSize - 1)); } | |||||
char* getSectionAddress (const IMAGE_SECTION_HEADER& section) const | |||||
{ | |||||
#ifdef _WIN64 | |||||
return reinterpret_cast<char*> (static_cast<uintptr_t> (section.Misc.PhysicalAddress) | |||||
| (static_cast<uintptr_t> (imageHeaders->OptionalHeader.ImageBase & 0xffffffff00000000))); | |||||
#else | |||||
return reinterpret_cast<char*> (section.Misc.PhysicalAddress); | |||||
#endif | |||||
} | |||||
bool copySections (const void* data, size_t size, size_t sectionAlignment) const | |||||
{ | |||||
auto section = IMAGE_FIRST_SECTION (imageHeaders); | |||||
for (int i = 0; i < imageHeaders->FileHeader.NumberOfSections; ++i, ++section) | |||||
{ | |||||
if (section->SizeOfRawData == 0) | |||||
{ | |||||
if (sectionAlignment == 0) | |||||
continue; | |||||
if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress), | |||||
sectionAlignment, MEM_COMMIT, PAGE_READWRITE)) | |||||
{ | |||||
dest = getOffsetAs<char> (imageData, section->VirtualAddress); | |||||
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest)); | |||||
memset (dest, 0, sectionAlignment); | |||||
continue; | |||||
} | |||||
return false; | |||||
} | |||||
if (size < section->PointerToRawData + section->SizeOfRawData) | |||||
return false; | |||||
if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress), | |||||
section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE)) | |||||
{ | |||||
dest = getOffsetAs<char> (imageData, section->VirtualAddress); | |||||
memcpy (dest, static_cast<const char*> (data) + section->PointerToRawData, section->SizeOfRawData); | |||||
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest)); | |||||
continue; | |||||
} | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
void performRelocation (ptrdiff_t delta) | |||||
{ | |||||
auto directory = imageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; | |||||
if (directory.Size != 0) | |||||
{ | |||||
auto relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (imageData, directory.VirtualAddress); | |||||
while (relocation->VirtualAddress > 0) | |||||
{ | |||||
auto dest = getOffsetAs<char> (imageData, relocation->VirtualAddress); | |||||
auto offset = getOffsetAs<uint16_t> (relocation, sizeof (IMAGE_BASE_RELOCATION)); | |||||
for (uint32_t i = 0; i < (relocation->SizeOfBlock - sizeof (IMAGE_BASE_RELOCATION)) / 2; ++i, ++offset) | |||||
{ | |||||
switch (*offset >> 12) | |||||
{ | |||||
case IMAGE_REL_BASED_HIGHLOW: addDelta<uint32_t> (dest + (*offset & 0xfff), delta); break; | |||||
case IMAGE_REL_BASED_DIR64: addDelta<uint64_t> (dest + (*offset & 0xfff), delta); break; | |||||
case IMAGE_REL_BASED_ABSOLUTE: | |||||
default: break; | |||||
} | |||||
} | |||||
relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (relocation, relocation->SizeOfBlock); | |||||
} | |||||
} | |||||
} | |||||
template <typename Type> | |||||
static void addDelta (char* addr, ptrdiff_t delta) | |||||
{ | |||||
*reinterpret_cast<Type*> (addr) = static_cast<Type> (static_cast<ptrdiff_t> (*reinterpret_cast<Type*> (addr)) + delta); | |||||
} | |||||
}; | |||||
inline MemoryDLL::~MemoryDLL() = default; | |||||
inline MemoryDLL::MemoryDLL (const void* data, size_t size) : pimpl (std::make_unique<Pimpl>()) | |||||
{ | |||||
if (! pimpl->initialise (data, size)) | |||||
pimpl.reset(); | |||||
} | |||||
inline void* MemoryDLL::findFunction (std::string_view name) | |||||
{ | |||||
return pimpl != nullptr ? pimpl->findFunction (name) : nullptr; | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // CHOC_MEMORYDLL_HEADER_INCLUDED |
@@ -0,0 +1,67 @@ | |||||
// | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes ** | |||||
// ██ ███████ ██ ██ ██ | |||||
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// | |||||
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license: | |||||
// | |||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or | |||||
// without fee is hereby granted, provided that the above copyright notice and this permission | |||||
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |||||
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
#ifndef CHOC_PLATFORM_DETECT_HEADER_INCLUDED | |||||
#define CHOC_PLATFORM_DETECT_HEADER_INCLUDED | |||||
/* | |||||
These conditionals declare the macros | |||||
- CHOC_WINDOWS | |||||
- CHOC_ANDROID | |||||
- CHOC_LINUX | |||||
- CHOC_OSX | |||||
- CHOC_IOS | |||||
...based on the current operating system. | |||||
It also declares a string literal macro CHOC_OPERATING_SYSTEM_NAME | |||||
which can be used if you need a text description of the OS. | |||||
*/ | |||||
#if defined (_WIN32) || defined (_WIN64) | |||||
#define CHOC_WINDOWS 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "Windows" | |||||
#elif __ANDROID__ | |||||
#define CHOC_ANDROID 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "Android" | |||||
#elif defined (LINUX) || defined (__linux__) | |||||
#define CHOC_LINUX 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "Linux" | |||||
#elif __APPLE__ | |||||
#define CHOC_APPLE 1 | |||||
#include <TargetConditionals.h> | |||||
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR | |||||
#define CHOC_IOS 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "iOS" | |||||
#else | |||||
#define CHOC_OSX 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "OSX" | |||||
#endif | |||||
#elif defined (__FreeBSD__) || (__OpenBSD__) | |||||
#define CHOC_BSD 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "BSD" | |||||
#elif defined (_POSIX_VERSION) | |||||
#define CHOC_POSIX 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "Posix" | |||||
#elif defined (__EMSCRIPTEN__) | |||||
#define CHOC_EMSCRIPTEN 1 | |||||
#define CHOC_OPERATING_SYSTEM_NAME "Emscripten" | |||||
#else | |||||
#error "Unknown platform!" | |||||
#endif | |||||
#endif // CHOC_PLATFORM_DETECT_HEADER_INCLUDED |
@@ -0,0 +1,74 @@ | |||||
// | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes ** | |||||
// ██ ███████ ██ ██ ██ | |||||
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc | |||||
// ██████ ██ ██ ██████ ██████ | |||||
// | |||||
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license: | |||||
// | |||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or | |||||
// without fee is hereby granted, provided that the above copyright notice and this permission | |||||
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |||||
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |||||
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
#ifndef CHOC_STRING_UTILS_HEADER_INCLUDED | |||||
#define CHOC_STRING_UTILS_HEADER_INCLUDED | |||||
#include <cctype> | |||||
#include <string> | |||||
#include <vector> | |||||
#include <cmath> | |||||
#include <chrono> | |||||
#include <memory> | |||||
#include <algorithm> | |||||
#include <cwctype> | |||||
START_NAMESPACE_DISTRHO | |||||
//============================================================================== | |||||
/// Returns a hex string for the given value. | |||||
/// If the minimum number of digits is non-zero, it will be zero-padded to fill this length; | |||||
template <typename IntegerType> | |||||
std::string createHexString (IntegerType value); | |||||
//============================================================================== | |||||
// _ _ _ _ | |||||
// __| | ___ | |_ __ _ (_)| | ___ | |||||
// / _` | / _ \| __| / _` || || |/ __| | |||||
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _ | |||||
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_) | |||||
// | |||||
// Code beyond this point is implementation detail... | |||||
// | |||||
//============================================================================== | |||||
template <typename IntegerType> | |||||
std::string createHexString (IntegerType v) | |||||
{ | |||||
static_assert (std::is_integral<IntegerType>::value, "Need to pass integers into this method"); | |||||
auto value = static_cast<typename std::make_unsigned<IntegerType>::type> (v); | |||||
char hex[40]; | |||||
const auto end = hex + sizeof (hex) - 1; | |||||
auto d = end; | |||||
*d = 0; | |||||
for (;;) | |||||
{ | |||||
*--d = "0123456789abcdef"[static_cast<uint32_t> (value) & 15u]; | |||||
value = static_cast<decltype (value)> (value >> 4); | |||||
if (value == 0) | |||||
return std::string (d, end); | |||||
} | |||||
} | |||||
END_NAMESPACE_DISTRHO | |||||
#endif |
@@ -212,6 +212,8 @@ private: \ | |||||
/* Useful macros */ | /* Useful macros */ | ||||
#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0])) | #define ARRAY_SIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0])) | ||||
#define STRINGIFY2(s) #s | |||||
#define STRINGIFY(s) STRINGIFY2(s) | |||||
/* Useful typedefs */ | /* Useful typedefs */ | ||||
typedef unsigned char uchar; | typedef unsigned char uchar; | ||||
@@ -223,5 +225,6 @@ typedef unsigned long long int ulonglong; | |||||
/* Deprecated macros */ | /* Deprecated macros */ | ||||
#define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName) | #define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName) | ||||
#define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) DISTRHO_DECLARE_NON_COPYABLE(StructName) | #define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) DISTRHO_DECLARE_NON_COPYABLE(StructName) | ||||
#define DISTRHO_MACRO_AS_STRING(MACRO) STRINGIFY2(MACRO) | |||||
#endif // DISTRHO_DEFINES_H_INCLUDED | #endif // DISTRHO_DEFINES_H_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -246,6 +246,7 @@ void Plugin::setState(const char*, const char*) {} | |||||
void Plugin::bufferSizeChanged(uint32_t) {} | void Plugin::bufferSizeChanged(uint32_t) {} | ||||
void Plugin::sampleRateChanged(double) {} | void Plugin::sampleRateChanged(double) {} | ||||
void Plugin::ioChanged(uint16_t, uint16_t) {} | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -29,7 +29,7 @@ | |||||
# error DISTRHO_PLUGIN_CLAP_ID undefined! | # error DISTRHO_PLUGIN_CLAP_ID undefined! | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | # undef DISTRHO_PLUGIN_HAS_UI | ||||
# define DISTRHO_PLUGIN_HAS_UI 0 | # define DISTRHO_PLUGIN_HAS_UI 0 | ||||
#endif | #endif | ||||
@@ -57,7 +57,7 @@ | |||||
#include "clap/ext/thread-check.h" | #include "clap/ext/thread-check.h" | ||||
#include "clap/ext/timer-support.h" | #include "clap/ext/timer-support.h" | ||||
#if (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) | |||||
# define DPF_CLAP_USING_HOST_TIMER 0 | # define DPF_CLAP_USING_HOST_TIMER 0 | ||||
#else | #else | ||||
# define DPF_CLAP_USING_HOST_TIMER 1 | # define DPF_CLAP_USING_HOST_TIMER 1 | ||||
@@ -211,7 +211,9 @@ public: | |||||
#endif | #endif | ||||
const bool isFloating) | const bool isFloating) | ||||
: fPlugin(plugin), | : fPlugin(plugin), | ||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
fPluginEventQueue(eventQueue), | fPluginEventQueue(eventQueue), | ||||
#endif | |||||
fEventQueue(eventQueue->fEventQueue), | fEventQueue(eventQueue->fEventQueue), | ||||
fCachedParameters(eventQueue->fCachedParameters), | fCachedParameters(eventQueue->fCachedParameters), | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
@@ -280,10 +282,10 @@ public: | |||||
double scaleFactor = fScaleFactor; | double scaleFactor = fScaleFactor; | ||||
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | #if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | ||||
*width = DISTRHO_UI_DEFAULT_WIDTH; | |||||
*height = DISTRHO_UI_DEFAULT_HEIGHT; | |||||
if (d_isZero(scaleFactor)) | if (d_isZero(scaleFactor)) | ||||
scaleFactor = 1.0; | scaleFactor = 1.0; | ||||
*width = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor; | |||||
*height = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor; | |||||
#else | #else | ||||
UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | ||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | ||||
@@ -371,10 +373,10 @@ public: | |||||
{ | { | ||||
// fix width | // fix width | ||||
if (reqRatio > ratio) | if (reqRatio > ratio) | ||||
*width = static_cast<int32_t>(*height * ratio + 0.5); | |||||
*width = d_roundToIntPositive(*height * ratio); | |||||
// fix height | // fix height | ||||
else | else | ||||
*height = static_cast<int32_t>(static_cast<double>(*width) / ratio + 0.5); | |||||
*height = d_roundToIntPositive(static_cast<double>(*width) / ratio); | |||||
} | } | ||||
} | } | ||||
@@ -534,7 +536,9 @@ public: | |||||
private: | private: | ||||
// Plugin and UI | // Plugin and UI | ||||
PluginExporter& fPlugin; | PluginExporter& fPlugin; | ||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
ClapEventQueue* const fPluginEventQueue; | ClapEventQueue* const fPluginEventQueue; | ||||
#endif | |||||
ClapEventQueue::Queue& fEventQueue; | ClapEventQueue::Queue& fEventQueue; | ||||
ClapEventQueue::CachedParameters& fCachedParameters; | ClapEventQueue::CachedParameters& fCachedParameters; | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
@@ -600,8 +604,8 @@ private: | |||||
// Set state | // Set state | ||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& value = cit->second; | |||||
const String& key(cit->first); | |||||
const String& value(cit->second); | |||||
// TODO skip DSP only states | // TODO skip DSP only states | ||||
@@ -1433,7 +1437,7 @@ public: | |||||
// Update current state | // Update current state | ||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& key(cit->first); | |||||
fStateMap[key] = fPlugin.getStateValue(key); | fStateMap[key] = fPlugin.getStateValue(key); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -1457,8 +1461,8 @@ public: | |||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& value = cit->second; | |||||
const String& key(cit->first); | |||||
const String& value(cit->second); | |||||
// join key and value | // join key and value | ||||
String tmpStr; | String tmpStr; | ||||
@@ -1764,23 +1768,11 @@ public: | |||||
{ | { | ||||
fPlugin.setState(key, value); | fPlugin.setState(key, value); | ||||
// check if we want to save this key | |||||
if (! fPlugin.wantStateKey(key)) | |||||
return; | |||||
// check if key already exists | |||||
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||||
if (fPlugin.wantStateKey(key)) | |||||
{ | { | ||||
const String& dkey(it->first); | |||||
if (dkey == key) | |||||
{ | |||||
it->second = value; | |||||
return; | |||||
} | |||||
const String dkey(key); | |||||
fStateMap[dkey] = value; | |||||
} | } | ||||
d_stderr("Failed to find plugin state with key \"%s\"", key); | |||||
} | } | ||||
#endif | #endif | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,7 +23,7 @@ | |||||
#include "DistrhoPluginInfo.h" | #include "DistrhoPluginInfo.h" | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Check if all required macros are defined | // Check if all required macros are defined | ||||
#ifndef DISTRHO_PLUGIN_NAME | #ifndef DISTRHO_PLUGIN_NAME | ||||
@@ -42,17 +42,13 @@ | |||||
# error DISTRHO_PLUGIN_URI undefined! | # error DISTRHO_PLUGIN_URI undefined! | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Define optional macros if not done yet | // Define optional macros if not done yet | ||||
#ifndef DISTRHO_PLUGIN_HAS_UI | #ifndef DISTRHO_PLUGIN_HAS_UI | ||||
# define DISTRHO_PLUGIN_HAS_UI 0 | # define DISTRHO_PLUGIN_HAS_UI 0 | ||||
#endif | #endif | ||||
#ifndef DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 0 | |||||
#endif | |||||
#ifndef DISTRHO_PLUGIN_IS_RT_SAFE | #ifndef DISTRHO_PLUGIN_IS_RT_SAFE | ||||
# define DISTRHO_PLUGIN_IS_RT_SAFE 0 | # define DISTRHO_PLUGIN_IS_RT_SAFE 0 | ||||
#endif | #endif | ||||
@@ -95,47 +91,94 @@ | |||||
#endif | #endif | ||||
#ifndef DISTRHO_UI_FILE_BROWSER | #ifndef DISTRHO_UI_FILE_BROWSER | ||||
# if defined(DGL_FILE_BROWSER_DISABLED) || DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# define DISTRHO_UI_FILE_BROWSER 0 | |||||
# else | |||||
# define DISTRHO_UI_FILE_BROWSER 1 | |||||
# endif | |||||
# define DISTRHO_UI_FILE_BROWSER 0 | |||||
#endif | |||||
#ifndef DISTRHO_UI_WEB_VIEW | |||||
# define DISTRHO_UI_WEB_VIEW 0 | |||||
#endif | #endif | ||||
#ifndef DISTRHO_UI_USER_RESIZABLE | #ifndef DISTRHO_UI_USER_RESIZABLE | ||||
# define DISTRHO_UI_USER_RESIZABLE 0 | # define DISTRHO_UI_USER_RESIZABLE 0 | ||||
#endif | #endif | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// set UI type | |||||
#ifndef DISTRHO_UI_USE_CAIRO | |||||
# define DISTRHO_UI_USE_CAIRO 0 | |||||
#endif | |||||
#ifndef DISTRHO_UI_USE_CUSTOM | |||||
# define DISTRHO_UI_USE_CUSTOM 0 | |||||
#endif | |||||
#ifndef DISTRHO_UI_USE_EXTERNAL | |||||
# define DISTRHO_UI_USE_EXTERNAL 0 | |||||
#endif | |||||
#ifndef DISTRHO_UI_USE_NANOVG | #ifndef DISTRHO_UI_USE_NANOVG | ||||
# define DISTRHO_UI_USE_NANOVG 0 | # define DISTRHO_UI_USE_NANOVG 0 | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// Define DISTRHO_PLUGIN_HAS_EMBED_UI if needed | |||||
#ifndef DISTRHO_UI_USE_WEB_VIEW | |||||
# define DISTRHO_UI_USE_WEB_VIEW 0 | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Define DISTRHO_UI_WEB_VIEW if needed | |||||
#ifndef DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
# if (defined(DGL_CAIRO) && defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && defined(HAVE_OPENGL)) | |||||
# define DISTRHO_PLUGIN_HAS_EMBED_UI 1 | |||||
# else | |||||
# define DISTRHO_PLUGIN_HAS_EMBED_UI 0 | |||||
# endif | |||||
#if DISTRHO_UI_USE_WEB_VIEW && !DISTRHO_UI_WEB_VIEW | |||||
# undef DISTRHO_UI_WEB_VIEW | |||||
# define DISTRHO_UI_WEB_VIEW 1 | |||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Define DISTRHO_UI_URI if needed | // Define DISTRHO_UI_URI if needed | ||||
#ifndef DISTRHO_UI_URI | #ifndef DISTRHO_UI_URI | ||||
# define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#DPF_UI" | # define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#DPF_UI" | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Test for wrong compiler macros | |||||
#if defined(DISTRHO_PLUGIN_HAS_EMBED_UI) | |||||
# warning DISTRHO_PLUGIN_HAS_EMBED_UI has been removed, it is now always on | |||||
#endif | |||||
#if defined(DISTRHO_PLUGIN_HAS_EXTERNAL_UI) | |||||
# error DISTRHO_PLUGIN_HAS_EXTERNAL_UI has been replaced by DISTRHO_UI_USE_EXTERNAL | |||||
#endif | |||||
#ifdef DISTRHO_UI_FILEBROWSER | |||||
# error typo detected use DISTRHO_UI_FILE_BROWSER instead of DISTRHO_UI_FILEBROWSER | |||||
#endif | |||||
#ifdef DISTRHO_UI_WEBVIEW | |||||
# error typo detected use DISTRHO_UI_WEB_VIEW instead of DISTRHO_UI_WEBVIEW | |||||
#endif | |||||
#ifdef DISTRHO_UI_USE_WEBVIEW | |||||
# error typo detected use DISTRHO_UI_USE_WEB_VIEW instead of DISTRHO_UI_USE_WEBVIEW | |||||
#endif | |||||
#if DISTRHO_UI_FILE_BROWSER && !defined(DGL_USE_FILE_BROWSER) | |||||
# error invalid build config: file browser requested but `USE_FILE_BROWSER` build option is not set | |||||
#endif | |||||
#if DISTRHO_UI_WEB_VIEW && !defined(DGL_USE_WEB_VIEW) | |||||
# error invalid build config: web view requested but `USE_WEB_VIEW` build option is not set | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Test if synth has audio outputs | // Test if synth has audio outputs | ||||
#if DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | #if DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | ||||
# error Synths need audio output to work! | # error Synths need audio output to work! | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Enable MIDI input if synth, test if midi-input disabled when synth | // Enable MIDI input if synth, test if midi-input disabled when synth | ||||
#ifndef DISTRHO_PLUGIN_WANT_MIDI_INPUT | #ifndef DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
@@ -144,7 +187,7 @@ | |||||
# error Synths need MIDI input to work! | # error Synths need MIDI input to work! | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Enable state if plugin wants state files (deprecated) | // Enable state if plugin wants state files (deprecated) | ||||
#ifdef DISTRHO_PLUGIN_WANT_STATEFILES | #ifdef DISTRHO_PLUGIN_WANT_STATEFILES | ||||
@@ -156,7 +199,7 @@ | |||||
# endif | # endif | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Enable full state if plugin exports presets | // Enable full state if plugin exports presets | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && defined(DISTRHO_PLUGIN_WANT_FULL_STATE_WAS_NOT_SET) | #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && defined(DISTRHO_PLUGIN_WANT_FULL_STATE_WAS_NOT_SET) | ||||
@@ -165,29 +208,15 @@ | |||||
# define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// Disable file browser if using external UI | |||||
#if DISTRHO_UI_FILE_BROWSER && DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# warning file browser APIs do not work for external UIs | |||||
# undef DISTRHO_UI_FILE_BROWSER 0 | |||||
# define DISTRHO_UI_FILE_BROWSER 0 | |||||
#endif | |||||
// ----------------------------------------------------------------------- | |||||
// Disable UI if DGL or external UI is not available | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Disable UI if DGL is not available | |||||
#if (defined(DGL_CAIRO) && ! defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && ! defined(HAVE_OPENGL)) | |||||
# undef DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
# define DISTRHO_PLUGIN_HAS_EMBED_UI 0 | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI && !defined(HAVE_DGL) | |||||
# undef DISTRHO_PLUGIN_HAS_UI | # undef DISTRHO_PLUGIN_HAS_UI | ||||
# define DISTRHO_PLUGIN_HAS_UI 0 | # define DISTRHO_PLUGIN_HAS_UI 0 | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Make sure both default width and height are provided | // Make sure both default width and height are provided | ||||
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && !defined(DISTRHO_UI_DEFAULT_HEIGHT) | #if defined(DISTRHO_UI_DEFAULT_WIDTH) && !defined(DISTRHO_UI_DEFAULT_HEIGHT) | ||||
@@ -198,13 +227,65 @@ | |||||
# error DISTRHO_UI_DEFAULT_HEIGHT is defined but DISTRHO_UI_DEFAULT_WIDTH is not | # error DISTRHO_UI_DEFAULT_HEIGHT is defined but DISTRHO_UI_DEFAULT_WIDTH is not | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Define DISTRHO_PLUGIN_AU_TYPE if needed | |||||
#ifndef DISTRHO_PLUGIN_AU_TYPE | |||||
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) && DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||||
# define DISTRHO_PLUGIN_AU_TYPE aumf /* kAudioUnitType_MusicEffect */ | |||||
# elif (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) && DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||||
# define DISTRHO_PLUGIN_AU_TYPE aumu /* kAudioUnitType_MusicDevice */ | |||||
# elif DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||||
# define DISTRHO_PLUGIN_AU_TYPE aumi /* kAudioUnitType_MIDIProcessor */ | |||||
# elif DISTRHO_PLUGIN_NUM_INPUTS == 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||||
# define DISTRHO_PLUGIN_AU_TYPE augn /* kAudioUnitType_Generator */ | |||||
# else | |||||
# define DISTRHO_PLUGIN_AU_TYPE aufx /* kAudioUnitType_Effect */ | |||||
# endif | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Check that symbol macros are well defined | |||||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||||
#ifdef DISTRHO_PLUGIN_AU_TYPE | |||||
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_AU_TYPE)) == 5, "The macro DISTRHO_PLUGIN_AU_TYPE has incorrect length"); | |||||
# if DISTRHO_PLUGIN_NUM_INPUTS == 0 || DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | |||||
static constexpr const char _aut[5] = STRINGIFY(DISTRHO_PLUGIN_AU_TYPE); | |||||
static_assert(_aut[0] != 'a' || _aut[0] != 'u' || _aut[0] != 'm' || _aut[0] != 'u', | |||||
"The 'aumu' type requires both audio input and output"); | |||||
# endif | |||||
#endif | |||||
#ifdef DISTRHO_PLUGIN_BRAND_ID | |||||
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)) == 5, "The macro DISTRHO_PLUGIN_BRAND_ID has incorrect length"); | |||||
#endif | |||||
#ifdef DISTRHO_PLUGIN_UNIQUE_ID | |||||
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)) == 5, "The macro DISTRHO_PLUGIN_UNIQUE_ID has incorrect length"); | |||||
#endif | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Prevent users from messing about with DPF internals | // Prevent users from messing about with DPF internals | ||||
#ifdef DISTRHO_UI_IS_STANDALONE | #ifdef DISTRHO_UI_IS_STANDALONE | ||||
# 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 | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED | #endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED |
@@ -0,0 +1,281 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoPluginInternal.hpp" | |||||
#include "../DistrhoPluginUtils.hpp" | |||||
#ifndef DISTRHO_PLUGIN_BRAND_ID | |||||
# error DISTRHO_PLUGIN_BRAND_ID undefined! | |||||
#endif | |||||
#ifndef DISTRHO_PLUGIN_UNIQUE_ID | |||||
# error DISTRHO_PLUGIN_UNIQUE_ID undefined! | |||||
#endif | |||||
#include <fstream> | |||||
#include <iostream> | |||||
USE_NAMESPACE_DISTRHO | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void generate_au_plist(const PluginExporter& plugin, | |||||
const char* const basename, | |||||
const char* const license) | |||||
{ | |||||
std::cout << "Writing Info.plist..."; std::cout.flush(); | |||||
std::fstream outputFile("Info.plist", std::ios::out); | |||||
const uint32_t version = plugin.getVersion(); | |||||
const uint32_t majorVersion = (version & 0xFF0000) >> 16; | |||||
const uint32_t minorVersion = (version & 0x00FF00) >> 8; | |||||
const uint32_t microVersion = (version & 0x0000FF) >> 0; | |||||
outputFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | |||||
outputFile << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"; | |||||
outputFile << "<plist>\n"; | |||||
outputFile << " <dict>\n"; | |||||
outputFile << " <key>CFBundleExecutable</key>\n"; | |||||
outputFile << " <string>" << basename << "</string>\n"; | |||||
outputFile << " <key>CFBundleIconFile</key>\n"; | |||||
outputFile << " <string></string>\n"; | |||||
outputFile << " <key>CFBundleIdentifier</key>\n"; | |||||
outputFile << " <string>" DISTRHO_PLUGIN_CLAP_ID "</string>\n"; | |||||
outputFile << " <key>CFBundleName</key>\n"; | |||||
outputFile << " <string>" << basename << "</string>\n"; | |||||
outputFile << " <key>CFBundleDisplayName</key>\n"; | |||||
outputFile << " <string>" << plugin.getName() << "</string>\n"; | |||||
outputFile << " <key>CFBundlePackageType</key>\n"; | |||||
outputFile << " <string>BNDL</string>\n"; | |||||
outputFile << " <key>CFBundleSignature</key>\n"; | |||||
outputFile << " <string>" << "????" << "</string>\n"; | |||||
outputFile << " <key>CFBundleShortVersionString</key>\n"; | |||||
outputFile << " <string>" << majorVersion << "." << minorVersion << "." << microVersion << "</string>\n"; | |||||
outputFile << " <key>CFBundleVersion</key>\n"; | |||||
outputFile << " <string>" << majorVersion << "." << minorVersion << "." << microVersion << "</string>\n"; | |||||
if (license != nullptr && license[0] != '\0') | |||||
{ | |||||
outputFile << " <key>NSHumanReadableCopyright</key>\n"; | |||||
outputFile << " <string>" << license << "</string>\n"; | |||||
} | |||||
outputFile << " <key>NSHighResolutionCapable</key>\n"; | |||||
outputFile << " <true/>\n"; | |||||
outputFile << " <key>AudioComponents</key>\n"; | |||||
outputFile << " <array>\n"; | |||||
outputFile << " <dict>\n"; | |||||
outputFile << " <key>name</key>\n"; | |||||
outputFile << " <string>" << plugin.getMaker() << ": " << plugin.getName() << "</string>\n"; | |||||
outputFile << " <key>description</key>\n"; | |||||
outputFile << " <string>" << plugin.getDescription() << "</string>\n"; | |||||
outputFile << " <key>factoryFunction</key>\n"; | |||||
outputFile << " <string>PluginAUFactory</string>\n"; | |||||
outputFile << " <key>type</key>\n"; | |||||
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_AU_TYPE) "</string>\n"; | |||||
outputFile << " <key>subtype</key>\n"; | |||||
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID) "</string>\n"; | |||||
outputFile << " <key>manufacturer</key>\n"; | |||||
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_BRAND_ID) "</string>\n"; | |||||
outputFile << " <key>version</key>\n"; | |||||
outputFile << " <integer>" << version << "</integer>\n"; | |||||
outputFile << " <key>resourceUsage</key>\n"; | |||||
outputFile << " <dict>\n"; | |||||
outputFile << " <key>network.client</key>\n"; | |||||
outputFile << " <true/>\n"; | |||||
outputFile << " <key>temporary-exception.files.all.read-write</key>\n"; | |||||
outputFile << " <true/>\n"; | |||||
outputFile << " </dict>\n"; | |||||
outputFile << " </dict>\n"; | |||||
outputFile << " </array>\n"; | |||||
outputFile << " </dict>\n"; | |||||
outputFile << "</plist>\n"; | |||||
outputFile.close(); | |||||
std::cout << " done!" << std::endl; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
int main(int argc, char* argv[]) | |||||
{ | |||||
if (argc <= 1) | |||||
return 1; | |||||
// Dummy plugin to get data from | |||||
d_nextBufferSize = 512; | |||||
d_nextSampleRate = 44100.0; | |||||
d_nextPluginIsDummy = true; | |||||
PluginExporter plugin(nullptr, nullptr, nullptr, nullptr); | |||||
d_nextBufferSize = 0; | |||||
d_nextSampleRate = 0.0; | |||||
d_nextPluginIsDummy = false; | |||||
String license(plugin.getLicense()); | |||||
if (license.isEmpty()) | |||||
{} | |||||
// License as URL, use as-is | |||||
else if (license.contains("://")) | |||||
{} | |||||
// License contains quotes, use as-is | |||||
else if (license.contains('"')) | |||||
{} | |||||
// Regular license string, convert to URL as much as we can | |||||
else | |||||
{ | |||||
const String uplicense(license.asUpper()); | |||||
// for reference, see https://spdx.org/licenses/ | |||||
// common licenses | |||||
/**/ if (uplicense == "AGPL-1.0-ONLY" || | |||||
uplicense == "AGPL1" || | |||||
uplicense == "AGPLV1") | |||||
{ | |||||
license = "http://spdx.org/licenses/AGPL-1.0-only.html"; | |||||
} | |||||
else if (uplicense == "AGPL-1.0-OR-LATER" || | |||||
uplicense == "AGPL1+" || | |||||
uplicense == "AGPLV1+") | |||||
{ | |||||
license = "http://spdx.org/licenses/AGPL-1.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "AGPL-3.0-ONLY" || | |||||
uplicense == "AGPL3" || | |||||
uplicense == "AGPLV3") | |||||
{ | |||||
license = "http://spdx.org/licenses/AGPL-3.0-only.html"; | |||||
} | |||||
else if (uplicense == "AGPL-3.0-OR-LATER" || | |||||
uplicense == "AGPL3+" || | |||||
uplicense == "AGPLV3+") | |||||
{ | |||||
license = "http://spdx.org/licenses/AGPL-3.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "APACHE-2.0" || | |||||
uplicense == "APACHE2" || | |||||
uplicense == "APACHE-2") | |||||
{ | |||||
license = "http://spdx.org/licenses/Apache-2.0.html"; | |||||
} | |||||
else if (uplicense == "BSD-2-CLAUSE" || | |||||
uplicense == "BSD2" || | |||||
uplicense == "BSD-2") | |||||
{ | |||||
license = "http://spdx.org/licenses/BSD-2-Clause.html"; | |||||
} | |||||
else if (uplicense == "BSD-3-CLAUSE" || | |||||
uplicense == "BSD3" || | |||||
uplicense == "BSD-3") | |||||
{ | |||||
license = "http://spdx.org/licenses/BSD-3-Clause.html"; | |||||
} | |||||
else if (uplicense == "GPL-2.0-ONLY" || | |||||
uplicense == "GPL2" || | |||||
uplicense == "GPLV2") | |||||
{ | |||||
license = "http://spdx.org/licenses/GPL-2.0-only.html"; | |||||
} | |||||
else if (uplicense == "GPL-2.0-OR-LATER" || | |||||
uplicense == "GPL2+" || | |||||
uplicense == "GPLV2+" || | |||||
uplicense == "GPLV2.0+" || | |||||
uplicense == "GPL V2+") | |||||
{ | |||||
license = "http://spdx.org/licenses/GPL-2.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "GPL-3.0-ONLY" || | |||||
uplicense == "GPL3" || | |||||
uplicense == "GPLV3") | |||||
{ | |||||
license = "http://spdx.org/licenses/GPL-3.0-only.html"; | |||||
} | |||||
else if (uplicense == "GPL-3.0-OR-LATER" || | |||||
uplicense == "GPL3+" || | |||||
uplicense == "GPLV3+" || | |||||
uplicense == "GPLV3.0+" || | |||||
uplicense == "GPL V3+") | |||||
{ | |||||
license = "http://spdx.org/licenses/GPL-3.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "ISC") | |||||
{ | |||||
license = "http://spdx.org/licenses/ISC.html"; | |||||
} | |||||
else if (uplicense == "LGPL-2.0-ONLY" || | |||||
uplicense == "LGPL2" || | |||||
uplicense == "LGPLV2") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-2.0-only.html"; | |||||
} | |||||
else if (uplicense == "LGPL-2.0-OR-LATER" || | |||||
uplicense == "LGPL2+" || | |||||
uplicense == "LGPLV2+") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-2.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "LGPL-2.1-ONLY" || | |||||
uplicense == "LGPL2.1" || | |||||
uplicense == "LGPLV2.1") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-2.1-only.html"; | |||||
} | |||||
else if (uplicense == "LGPL-2.1-OR-LATER" || | |||||
uplicense == "LGPL2.1+" || | |||||
uplicense == "LGPLV2.1+") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-2.1-or-later.html"; | |||||
} | |||||
else if (uplicense == "LGPL-3.0-ONLY" || | |||||
uplicense == "LGPL3" || | |||||
uplicense == "LGPLV3") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-2.0-only.html"; | |||||
} | |||||
else if (uplicense == "LGPL-3.0-OR-LATER" || | |||||
uplicense == "LGPL3+" || | |||||
uplicense == "LGPLV3+") | |||||
{ | |||||
license = "http://spdx.org/licenses/LGPL-3.0-or-later.html"; | |||||
} | |||||
else if (uplicense == "MIT") | |||||
{ | |||||
license = "http://spdx.org/licenses/MIT.html"; | |||||
} | |||||
// generic fallbacks | |||||
else if (uplicense.startsWith("GPL")) | |||||
{ | |||||
license = "http://opensource.org/licenses/gpl-license"; | |||||
} | |||||
else if (uplicense.startsWith("LGPL")) | |||||
{ | |||||
license = "http://opensource.org/licenses/lgpl-license"; | |||||
} | |||||
// unknown or not handled yet, log a warning | |||||
else | |||||
{ | |||||
d_stderr("Unknown license string '%s'", license.buffer()); | |||||
} | |||||
} | |||||
generate_au_plist(plugin, argv[1], license); | |||||
return 0; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -309,6 +309,9 @@ struct Plugin::PrivateData { | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
bool updateStateValueCallback(const char* const key, const char* const value) | bool updateStateValueCallback(const char* const key, const char* const value) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, false); | |||||
d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc); | d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc); | ||||
if (updateStateValueCallbackFunc != nullptr) | if (updateStateValueCallbackFunc != nullptr) | ||||
return updateStateValueCallbackFunc(callbacksPtr, key, value); | return updateStateValueCallbackFunc(callbacksPtr, key, value); | ||||
@@ -756,6 +759,24 @@ public: | |||||
fPlugin->setParameterValue(index, value); | fPlugin->setParameterValue(index, value); | ||||
} | } | ||||
/* | |||||
bool getParameterIndexForSymbol(const char* const symbol, uint32_t& index) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false); | |||||
for (uint32_t i=0; i < fData->parameterCount; ++i) | |||||
{ | |||||
if (fData->parameters[i].symbol == symbol) | |||||
{ | |||||
index = i; | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
*/ | |||||
uint32_t getPortGroupCount() const noexcept | uint32_t getPortGroupCount() const noexcept | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | ||||
@@ -868,7 +889,7 @@ public: | |||||
} | } | ||||
#endif | #endif | ||||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
#if DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
String getStateValue(const char* const key) const | String getStateValue(const char* const key) const | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString); | ||||
@@ -876,7 +897,7 @@ public: | |||||
return fPlugin->getState(key); | return fPlugin->getState(key); | ||||
} | } | ||||
# endif | |||||
#endif | |||||
void setState(const char* const key, const char* const value) | void setState(const char* const key, const char* const value) | ||||
{ | { | ||||
@@ -947,7 +968,7 @@ public: | |||||
} | } | ||||
} | } | ||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
void run(const float** const inputs, float** const outputs, const uint32_t frames, | void run(const float** const inputs, float** const outputs, const uint32_t frames, | ||||
const MidiEvent* const midiEvents, const uint32_t midiEventCount) | const MidiEvent* const midiEvents, const uint32_t midiEventCount) | ||||
{ | { | ||||
@@ -964,7 +985,7 @@ public: | |||||
fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount); | fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount); | ||||
fData->isProcessing = false; | fData->isProcessing = false; | ||||
} | } | ||||
#else | |||||
#else | |||||
void run(const float** const inputs, float** const outputs, const uint32_t frames) | void run(const float** const inputs, float** const outputs, const uint32_t frames) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | ||||
@@ -980,7 +1001,21 @@ public: | |||||
fPlugin->run(inputs, outputs, frames); | fPlugin->run(inputs, outputs, frames); | ||||
fData->isProcessing = false; | fData->isProcessing = false; | ||||
} | } | ||||
#endif | |||||
#endif | |||||
// ------------------------------------------------------------------- | |||||
#ifdef DISTRHO_PLUGIN_TARGET_AU | |||||
void setAudioPortIO(const uint16_t numInputs, const uint16_t numOutputs) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||||
if (fIsActive) fPlugin->deactivate(); | |||||
fPlugin->ioChanged(numInputs, numOutputs); | |||||
if (fIsActive) fPlugin->activate(); | |||||
} | |||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -996,14 +1031,14 @@ public: | |||||
return fData->sampleRate; | return fData->sampleRate; | ||||
} | } | ||||
void setBufferSize(const uint32_t bufferSize, const bool doCallback = false) | |||||
bool setBufferSize(const uint32_t bufferSize, const bool doCallback = false) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, false); | |||||
DISTRHO_SAFE_ASSERT(bufferSize >= 2); | DISTRHO_SAFE_ASSERT(bufferSize >= 2); | ||||
if (fData->bufferSize == bufferSize) | if (fData->bufferSize == bufferSize) | ||||
return; | |||||
return false; | |||||
fData->bufferSize = bufferSize; | fData->bufferSize = bufferSize; | ||||
@@ -1013,6 +1048,8 @@ public: | |||||
fPlugin->bufferSizeChanged(bufferSize); | fPlugin->bufferSizeChanged(bufferSize); | ||||
if (fIsActive) fPlugin->activate(); | if (fIsActive) fPlugin->activate(); | ||||
} | } | ||||
return true; | |||||
} | } | ||||
void setSampleRate(const double sampleRate, const bool doCallback = false) | void setSampleRate(const double sampleRate, const bool doCallback = false) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -44,7 +44,9 @@ | |||||
# undef Point | # undef Point | ||||
#endif | #endif | ||||
#ifndef DISTRHO_OS_WINDOWS | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# include <objbase.h> | |||||
#else | |||||
# include <signal.h> | # include <signal.h> | ||||
# include <unistd.h> | # include <unistd.h> | ||||
#endif | #endif | ||||
@@ -86,6 +88,10 @@ 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; | ||||
@@ -234,20 +240,26 @@ public: | |||||
std::fflush(stdout); | std::fflush(stdout); | ||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
String title(fPlugin.getMaker()); | |||||
if (title.isNotEmpty()) | |||||
title += ": "; | |||||
if (const char* const name = jackbridge_get_client_name(fClient)) | if (const char* const name = jackbridge_get_client_name(fClient)) | ||||
fUI.setWindowTitle(name); | |||||
title += name; | |||||
else | else | ||||
fUI.setWindowTitle(fPlugin.getName()); | |||||
title += fPlugin.getName(); | |||||
fUI.setWindowTitle(title); | |||||
fUI.exec(this); | fUI.exec(this); | ||||
#else | |||||
#else | |||||
while (! gCloseSignalReceived) | while (! gCloseSignalReceived) | ||||
d_sleep(1); | d_sleep(1); | ||||
// unused | // unused | ||||
(void)winId; | (void)winId; | ||||
#endif | |||||
#endif | |||||
} | } | ||||
~PluginJack() | ~PluginJack() | ||||
@@ -955,6 +967,11 @@ int main(int argc, char* argv[]) | |||||
{ | { | ||||
USE_NAMESPACE_DISTRHO; | USE_NAMESPACE_DISTRHO; | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
OleInitialize(nullptr); | |||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); | |||||
#endif | |||||
initSignalHandler(); | initSignalHandler(); | ||||
#ifndef STATIC_BUILD | #ifndef STATIC_BUILD | ||||
@@ -965,15 +982,11 @@ int main(int argc, char* argv[]) | |||||
String tmpPath(getBinaryFilename()); | String tmpPath(getBinaryFilename()); | ||||
tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); | tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); | ||||
#if defined(DISTRHO_OS_MAC) | #if defined(DISTRHO_OS_MAC) | ||||
if (tmpPath.endsWith("/MacOS")) | |||||
if (tmpPath.endsWith("/Contents/MacOS")) | |||||
{ | { | ||||
tmpPath.truncate(tmpPath.rfind('/')); | |||||
if (tmpPath.endsWith("/Contents")) | |||||
{ | |||||
tmpPath.truncate(tmpPath.rfind('/')); | |||||
bundlePath = tmpPath; | |||||
d_nextBundlePath = bundlePath.buffer(); | |||||
} | |||||
tmpPath.truncate(tmpPath.length() - 15); | |||||
bundlePath = tmpPath; | |||||
d_nextBundlePath = bundlePath.buffer(); | |||||
} | } | ||||
#else | #else | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
@@ -990,6 +1003,11 @@ int main(int argc, char* argv[]) | |||||
} | } | ||||
#endif | #endif | ||||
#ifdef DPF_USING_LD_LINUX_WEBVIEW | |||||
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) | |||||
return dpf_webview_start(argc, argv); | |||||
#endif | |||||
if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | ||||
{ | { | ||||
#ifdef DPF_RUNTIME_TESTING | #ifdef DPF_RUNTIME_TESTING | ||||
@@ -1027,6 +1045,10 @@ int main(int argc, char* argv[]) | |||||
} | } | ||||
hasConsole = true; | hasConsole = true; | ||||
// tell windows to output console output as utf-8 | |||||
SetConsoleCP(CP_UTF8); | |||||
SetConsoleOutputCP(CP_UTF8); | |||||
} | } | ||||
#endif | #endif | ||||
@@ -1155,6 +1177,11 @@ int main(int argc, char* argv[]) | |||||
} | } | ||||
#endif | #endif | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
CoUninitialize(); | |||||
OleUninitialize(); | |||||
#endif | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -459,7 +459,7 @@ public: | |||||
if (fLastPositionData.barBeat >= 0.0f) | if (fLastPositionData.barBeat >= 0.0f) | ||||
{ | { | ||||
const double rest = std::fmod(fLastPositionData.barBeat, 1.0f); | |||||
const double rest = std::fmod(fLastPositionData.barBeat, 1.0); | |||||
fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat - rest + 1.0); | fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat - rest + 1.0); | ||||
fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; | fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; | ||||
} | } | ||||
@@ -590,7 +590,7 @@ public: | |||||
const LV2_Atom* property = nullptr; | const LV2_Atom* property = nullptr; | ||||
const LV2_Atom* value = nullptr; | const LV2_Atom* value = nullptr; | ||||
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); | |||||
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, 0); | |||||
if (property != nullptr && property->type == fURIDs.atomURID && | if (property != nullptr && property->type == fURIDs.atomURID && | ||||
value != nullptr && (value->type == fURIDs.atomPath || value->type == fURIDs.atomString)) | value != nullptr && (value->type == fURIDs.atomPath || value->type == fURIDs.atomString)) | ||||
@@ -1122,7 +1122,7 @@ public: | |||||
const LV2_Atom* property = nullptr; | const LV2_Atom* property = nullptr; | ||||
const LV2_Atom* value = nullptr; | const LV2_Atom* value = nullptr; | ||||
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); | |||||
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, 0); | |||||
DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN); | DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN); | ||||
DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN); | DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN); | ||||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN); | DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN); | ||||
@@ -1353,38 +1353,26 @@ private: | |||||
// save this key if necessary | // save this key if necessary | ||||
if (fPlugin.wantStateKey(key)) | if (fPlugin.wantStateKey(key)) | ||||
updateInternalState(key, newValue, false); | |||||
{ | |||||
const String dkey(key); | |||||
fStateMap[dkey] = newValue; | |||||
} | |||||
} | } | ||||
bool updateState(const char* const key, const char* const newValue) | bool updateState(const char* const key, const char* const newValue) | ||||
{ | { | ||||
fPlugin.setState(key, newValue); | fPlugin.setState(key, newValue); | ||||
return updateInternalState(key, newValue, true); | |||||
} | |||||
bool updateInternalState(const char* const key, const char* const newValue, const bool sendToUI) | |||||
{ | |||||
// key must already exist | // key must already exist | ||||
for (StringToStringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||||
{ | { | ||||
const String& dkey(it->first); | |||||
if (dkey == key) | |||||
if (fPlugin.getStateKey(i) == key) | |||||
{ | { | ||||
it->second = newValue; | |||||
const String dkey(key); | |||||
fStateMap[dkey] = newValue; | |||||
if (sendToUI) | |||||
{ | |||||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||||
{ | |||||
if (fPlugin.getStateKey(i) == key) | |||||
{ | |||||
if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0) | |||||
fNeededUiSends[i] = true; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0) | |||||
fNeededUiSends[i] = true; | |||||
return true; | return true; | ||||
} | } | ||||
@@ -74,12 +74,12 @@ | |||||
# define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 0 | # define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 0 | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
# if DISTRHO_OS_HAIKU | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
# if defined(DISTRHO_OS_HAIKU) | |||||
# define DISTRHO_LV2_UI_TYPE "BeUI" | # define DISTRHO_LV2_UI_TYPE "BeUI" | ||||
# elif DISTRHO_OS_MAC | |||||
# elif defined(DISTRHO_OS_MAC) | |||||
# define DISTRHO_LV2_UI_TYPE "CocoaUI" | # define DISTRHO_LV2_UI_TYPE "CocoaUI" | ||||
# elif DISTRHO_OS_WINDOWS | |||||
# elif defined(DISTRHO_OS_WINDOWS) | |||||
# define DISTRHO_LV2_UI_TYPE "WindowsUI" | # define DISTRHO_LV2_UI_TYPE "WindowsUI" | ||||
# else | # else | ||||
# define DISTRHO_LV2_UI_TYPE "X11UI" | # define DISTRHO_LV2_UI_TYPE "X11UI" | ||||
@@ -155,7 +155,7 @@ static constexpr const char* const lv2ManifestUiExtensionData[] = { | |||||
}; | }; | ||||
static constexpr const char* const lv2ManifestUiOptionalFeatures[] = { | static constexpr const char* const lv2ManifestUiOptionalFeatures[] = { | ||||
#if DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
#if !DISTRHO_UI_USER_RESIZABLE | #if !DISTRHO_UI_USER_RESIZABLE | ||||
"ui:noUserResize", | "ui:noUserResize", | ||||
#endif | #endif | ||||
@@ -1003,8 +1003,10 @@ void lv2_generate_ttl(const char* const basename) | |||||
{ | { | ||||
const String license(plugin.getLicense()); | const String license(plugin.getLicense()); | ||||
if (license.isEmpty()) | |||||
{} | |||||
// Using URL as license | // Using URL as license | ||||
if (license.contains("://")) | |||||
else if (license.contains("://")) | |||||
{ | { | ||||
pluginString += " doap:license <" + license + "> ;\n\n"; | pluginString += " doap:license <" + license + "> ;\n\n"; | ||||
} | } | ||||
@@ -1253,7 +1255,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
std::cout << " done!" << std::endl; | std::cout << " done!" << std::endl; | ||||
} | } | ||||
#if DISTRHO_PLUGIN_USES_MODGUI && DISTRHO_PLUGIN_HAS_EMBED_UI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI | |||||
#if DISTRHO_PLUGIN_USES_MODGUI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI | |||||
{ | { | ||||
std::cout << "Writing modgui.ttl..."; std::cout.flush(); | std::cout << "Writing modgui.ttl..."; std::cout.flush(); | ||||
std::fstream modguiFile("modgui.ttl", std::ios::out); | std::fstream modguiFile("modgui.ttl", std::ios::out); | ||||
@@ -1548,7 +1550,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
stylesheetFile.close(); | stylesheetFile.close(); | ||||
std::cout << " done!" << std::endl; | std::cout << " done!" << std::endl; | ||||
} | } | ||||
#endif // DISTRHO_PLUGIN_USES_MODGUI && DISTRHO_PLUGIN_HAS_EMBED_UI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI | |||||
#endif // DISTRHO_PLUGIN_USES_MODGUI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI | |||||
// --------------------------------------------- | // --------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,17 +23,7 @@ | |||||
#include <algorithm> | #include <algorithm> | ||||
#include <cmath> | #include <cmath> | ||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
# include "Base.hpp" | # include "Base.hpp" | ||||
#endif | #endif | ||||
@@ -45,7 +35,7 @@ | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||||
#if defined(DISTRHO_PROPER_CPP11_SUPPORT) || defined(DISTRHO_OS_MAC) | |||||
# include <atomic> | # include <atomic> | ||||
#else | #else | ||||
// quick and dirty std::atomic replacement for the things we need | // quick and dirty std::atomic replacement for the things we need | ||||
@@ -224,7 +214,7 @@ void snprintf_u32_utf16(int16_t* const dst, const uint32_t value, const size_t s | |||||
return snprintf_utf16_t<uint32_t>(dst, value, "%u", size); | return snprintf_utf16_t<uint32_t>(dst, value, "%u", size); | ||||
} | } | ||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// translate a vstgui-based key character and code to matching values used by DPF | // translate a vstgui-based key character and code to matching values used by DPF | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -178,10 +178,8 @@ public: | |||||
nullptr, // TODO file request | nullptr, // TODO file request | ||||
d_nextBundlePath, | d_nextBundlePath, | ||||
plugin->getInstancePointer(), | plugin->getInstancePointer(), | ||||
scaleFactor) | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
, fKeyboardModifiers(0) | |||||
#endif | |||||
scaleFactor), | |||||
fKeyboardModifiers(0) | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
, fNotesRingBuffer() | , fNotesRingBuffer() | ||||
#endif | #endif | ||||
@@ -242,7 +240,6 @@ public: | |||||
} | } | ||||
#endif | #endif | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
int handlePluginKeyEvent(const bool down, const int32_t index, const intptr_t value) | int handlePluginKeyEvent(const bool down, const int32_t index, const intptr_t value) | ||||
{ | { | ||||
d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); | d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); | ||||
@@ -281,7 +278,6 @@ public: | |||||
value >= 0 ? static_cast<uint>(value) : 0, | value >= 0 ? static_cast<uint>(value) : 0, | ||||
fKeyboardModifiers) ? 1 : 0; | fKeyboardModifiers) ? 1 : 0; | ||||
} | } | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ---------------------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------------------- | ||||
@@ -347,9 +343,7 @@ private: | |||||
// Plugin UI | // Plugin UI | ||||
UIExporter fUI; | UIExporter fUI; | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uint16_t fKeyboardModifiers; | uint16_t fKeyboardModifiers; | ||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
RingBufferControl<SmallStackBuffer> fNotesRingBuffer; | RingBufferControl<SmallStackBuffer> fNotesRingBuffer; | ||||
#endif | #endif | ||||
@@ -429,7 +423,7 @@ public: | |||||
memset(parameterChecks, 0, sizeof(bool)*parameterCount); | memset(parameterChecks, 0, sizeof(bool)*parameterCount); | ||||
} | } | ||||
#if DISTRHO_OS_MAC | |||||
#ifdef DISTRHO_OS_MAC | |||||
#ifdef __LP64__ | #ifdef __LP64__ | ||||
fUsingNsView = true; | fUsingNsView = true; | ||||
#else | #else | ||||
@@ -602,10 +596,10 @@ public: | |||||
{ | { | ||||
double scaleFactor = fLastScaleFactor; | double scaleFactor = fLastScaleFactor; | ||||
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | #if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | ||||
fVstRect.right = DISTRHO_UI_DEFAULT_WIDTH; | |||||
fVstRect.bottom = DISTRHO_UI_DEFAULT_HEIGHT; | |||||
if (d_isZero(scaleFactor)) | if (d_isZero(scaleFactor)) | ||||
scaleFactor = 1.0; | scaleFactor = 1.0; | ||||
fVstRect.right = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor; | |||||
fVstRect.bottom = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor; | |||||
#else | #else | ||||
UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | ||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | ||||
@@ -627,7 +621,7 @@ public: | |||||
delete fVstUI; // for hosts which don't pair create/destroy calls (Minihost Modular) | delete fVstUI; // for hosts which don't pair create/destroy calls (Minihost Modular) | ||||
fVstUI = nullptr; | fVstUI = nullptr; | ||||
#if DISTRHO_OS_MAC | |||||
#ifdef DISTRHO_OS_MAC | |||||
if (! fUsingNsView) | if (! fUsingNsView) | ||||
{ | { | ||||
d_stderr("Host doesn't support hasCockosViewAsConfig, cannot use UI"); | d_stderr("Host doesn't support hasCockosViewAsConfig, cannot use UI"); | ||||
@@ -678,7 +672,6 @@ public: | |||||
fVstUI->idle(); | fVstUI->idle(); | ||||
break; | break; | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
case VST_EFFECT_OPCODE_3B: // key down | case VST_EFFECT_OPCODE_3B: // key down | ||||
if (fVstUI != nullptr) | if (fVstUI != nullptr) | ||||
return fVstUI->handlePluginKeyEvent(true, index, value); | return fVstUI->handlePluginKeyEvent(true, index, value); | ||||
@@ -688,7 +681,6 @@ public: | |||||
if (fVstUI != nullptr) | if (fVstUI != nullptr) | ||||
return fVstUI->handlePluginKeyEvent(false, index, value); | return fVstUI->handlePluginKeyEvent(false, index, value); | ||||
break; | break; | ||||
#endif | |||||
#endif // DISTRHO_PLUGIN_HAS_UI | #endif // DISTRHO_PLUGIN_HAS_UI | ||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
@@ -917,7 +909,7 @@ public: | |||||
case VST_EFFECT_OPCODE_SUPPORTS: | case VST_EFFECT_OPCODE_SUPPORTS: | ||||
if (const char* const canDo = (const char*)ptr) | if (const char* const canDo = (const char*)ptr) | ||||
{ | { | ||||
#if DISTRHO_OS_MAC && DISTRHO_PLUGIN_HAS_UI | |||||
#if defined(DISTRHO_OS_MAC) && DISTRHO_PLUGIN_HAS_UI | |||||
if (std::strcmp(canDo, "hasCockosViewAsConfig") == 0) | if (std::strcmp(canDo, "hasCockosViewAsConfig") == 0) | ||||
{ | { | ||||
fUsingNsView = true; | fUsingNsView = true; | ||||
@@ -1084,7 +1076,7 @@ public: | |||||
if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading()) | if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading()) | ||||
{ | { | ||||
uint8_t midiData[3]; | uint8_t midiData[3]; | ||||
uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount-1].frame : 0; | |||||
const uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount - 1].frame : 0; | |||||
while (fNotesRingBuffer.isDataAvailableForReading()) | while (fNotesRingBuffer.isDataAvailableForReading()) | ||||
{ | { | ||||
@@ -1140,7 +1132,7 @@ private: | |||||
UIVst* fVstUI; | UIVst* fVstUI; | ||||
vst_rect fVstRect; | vst_rect fVstRect; | ||||
float fLastScaleFactor; | float fLastScaleFactor; | ||||
#if DISTRHO_OS_MAC | |||||
#ifdef DISTRHO_OS_MAC | |||||
bool fUsingNsView; | bool fUsingNsView; | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
@@ -1286,22 +1278,11 @@ private: | |||||
fPlugin.setState(key, value); | fPlugin.setState(key, value); | ||||
// check if we want to save this key | // check if we want to save this key | ||||
if (! fPlugin.wantStateKey(key)) | |||||
return; | |||||
// check if key already exists | |||||
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||||
if (fPlugin.wantStateKey(key)) | |||||
{ | { | ||||
const String& dkey(it->first); | |||||
if (dkey == key) | |||||
{ | |||||
it->second = value; | |||||
return; | |||||
} | |||||
const String dkey(key); | |||||
fStateMap[dkey] = value; | |||||
} | } | ||||
d_stderr("Failed to find plugin state with key \"%s\"", key); | |||||
} | } | ||||
#endif | #endif | ||||
}; | }; | ||||
@@ -1607,11 +1588,7 @@ static void VST_FUNCTION_INTERFACE vst_processReplacingCallback(vst_effect* cons | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
DISTRHO_PLUGIN_EXPORT | DISTRHO_PLUGIN_EXPORT | ||||
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) | |||||
const vst_effect* VSTPluginMain(vst_host_callback audioMaster); | |||||
#else | |||||
const vst_effect* VSTPluginMain(vst_host_callback audioMaster) asm ("main"); | |||||
#endif | |||||
const vst_effect* VSTPluginMain(vst_host_callback); | |||||
DISTRHO_PLUGIN_EXPORT | DISTRHO_PLUGIN_EXPORT | ||||
const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) | const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) | ||||
@@ -1735,4 +1712,19 @@ const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) | |||||
return effect; | return effect; | ||||
} | } | ||||
#if !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) || DISTRHO_UI_WEB_VIEW) | |||||
DISTRHO_PLUGIN_EXPORT | |||||
const vst_effect* VSTPluginMainCompat(vst_host_callback) asm ("main"); | |||||
DISTRHO_PLUGIN_EXPORT | |||||
const vst_effect* VSTPluginMainCompat(const vst_host_callback audioMaster) | |||||
{ | |||||
// protect main symbol against running as executable | |||||
if (reinterpret_cast<uintptr_t>(audioMaster) < 0xff) | |||||
return nullptr; | |||||
return VSTPluginMain(audioMaster); | |||||
} | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -92,11 +92,17 @@ static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w'); | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// plugin specific uids (values are filled in during plugin init) | // plugin specific uids (values are filled in during plugin init) | ||||
static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 }; | |||||
static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 }; | |||||
static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 }; | |||||
static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 }; | |||||
static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 }; | |||||
#if defined(DISTRHO_PLUGIN_BRAND_ID) && !defined(DPF_VST3_DONT_USE_BRAND_ID) | |||||
static constexpr const uint32_t dpf_id_brand = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)); | |||||
#else | |||||
static constexpr const uint32_t dpf_id_brand = 0; | |||||
#endif | |||||
static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, dpf_id_brand }; | |||||
static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, dpf_id_brand }; | |||||
static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, dpf_id_brand }; | |||||
static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, dpf_id_brand }; | |||||
static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, dpf_id_brand }; | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
// Utility functions | // Utility functions | ||||
@@ -1180,7 +1186,7 @@ public: | |||||
// Update current state | // Update current state | ||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& key(cit->first); | |||||
fStateMap[key] = fPlugin.getStateValue(key); | fStateMap[key] = fPlugin.getStateValue(key); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -1204,8 +1210,8 @@ public: | |||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& value = cit->second; | |||||
const String& key(cit->first); | |||||
const String& value(cit->second); | |||||
// join key and value | // join key and value | ||||
String tmpStr; | String tmpStr; | ||||
@@ -1419,7 +1425,7 @@ public: | |||||
fTimePosition.bbt.valid = true; | fTimePosition.bbt.valid = true; | ||||
fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1; | fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1; | ||||
fTimePosition.bbt.beat = d_roundToIntPositive<int32_t>(barBeats - rest) + 1; | |||||
fTimePosition.bbt.beat = static_cast<int32_t>(barBeats - rest) + 1; | |||||
fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; | fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; | ||||
fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator; | fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator; | ||||
fTimePosition.bbt.beatType = ctx->time_sig_denom; | fTimePosition.bbt.beatType = ctx->time_sig_denom; | ||||
@@ -1968,24 +1974,24 @@ public: | |||||
{ | { | ||||
#if DPF_VST3_USES_SEPARATE_CONTROLLER | #if DPF_VST3_USES_SEPARATE_CONTROLLER | ||||
case kVst3InternalParameterBufferSize: | case kVst3InternalParameterBufferSize: | ||||
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_BUFFER_SIZE)); | |||||
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_BUFFER_SIZE)); | |||||
case kVst3InternalParameterSampleRate: | case kVst3InternalParameterSampleRate: | ||||
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_SAMPLE_RATE)); | |||||
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_SAMPLE_RATE)); | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
case kVst3InternalParameterLatency: | case kVst3InternalParameterLatency: | ||||
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_LATENCY)); | |||||
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_LATENCY)); | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
case kVst3InternalParameterProgram: | case kVst3InternalParameterProgram: | ||||
return std::max(0.0, std::min(1.0, plain / fProgramCountMinusOne)); | |||||
return std::max<double>(0.0, std::min<double>(1.0, plain / fProgramCountMinusOne)); | |||||
#endif | #endif | ||||
} | } | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
if (rindex < kVst3InternalParameterCount) | if (rindex < kVst3InternalParameterCount) | ||||
return std::max(0.0, std::min(1.0, plain / 127)); | |||||
return std::max<double>(0.0, std::min<double>(1.0, plain / 127)); | |||||
#endif | #endif | ||||
const uint32_t index = static_cast<uint32_t>(rindex - kVst3InternalParameterCount); | const uint32_t index = static_cast<uint32_t>(rindex - kVst3InternalParameterCount); | ||||
@@ -2194,7 +2200,7 @@ public: | |||||
// Update current state from plugin side | // Update current state from plugin side | ||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& key(cit->first); | |||||
fStateMap[key] = fPlugin.getStateValue(key); | fStateMap[key] = fPlugin.getStateValue(key); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -2203,8 +2209,8 @@ public: | |||||
// Set state | // Set state | ||||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | ||||
{ | { | ||||
const String& key = cit->first; | |||||
const String& value = cit->second; | |||||
const String& key(cit->first); | |||||
const String& value(cit->second); | |||||
sendStateSetToUI(key, value); | sendStateSetToUI(key, value); | ||||
} | } | ||||
@@ -2399,20 +2405,8 @@ public: | |||||
// save this key as needed | // save this key as needed | ||||
if (fPlugin.wantStateKey(key)) | if (fPlugin.wantStateKey(key)) | ||||
{ | { | ||||
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||||
{ | |||||
const String& dkey(it->first); | |||||
if (dkey == key) | |||||
{ | |||||
it->second = value; | |||||
std::free(key16); | |||||
std::free(value16); | |||||
return V3_OK; | |||||
} | |||||
} | |||||
d_stderr("Failed to find plugin state with key \"%s\"", key); | |||||
const String dkey(key); | |||||
fStateMap[dkey] = value; | |||||
} | } | ||||
std::free(key16); | std::free(key16); | ||||
@@ -3103,7 +3097,7 @@ private: | |||||
event.midi_cc_out.cc_number = data[1]; | event.midi_cc_out.cc_number = data[1]; | ||||
event.midi_cc_out.value = data[2]; | event.midi_cc_out.value = data[2]; | ||||
if (midiEvent.size == 4) | if (midiEvent.size == 4) | ||||
event.midi_cc_out.value2 = midiEvent.size == 4; | |||||
event.midi_cc_out.value2 = data[3]; | |||||
break; | break; | ||||
/* TODO how do we deal with program changes?? | /* TODO how do we deal with program changes?? | ||||
case 0xC0: | case 0xC0: | ||||
@@ -4577,8 +4571,13 @@ static const char* getPluginCategories() | |||||
categories = DISTRHO_PLUGIN_VST3_CATEGORIES; | categories = DISTRHO_PLUGIN_VST3_CATEGORIES; | ||||
#elif DISTRHO_PLUGIN_IS_SYNTH | #elif DISTRHO_PLUGIN_IS_SYNTH | ||||
categories = "Instrument"; | categories = "Instrument"; | ||||
#else | |||||
categories = "Fx"; | |||||
#endif | #endif | ||||
firstInit = false; | firstInit = false; | ||||
// An empty category is considered invalid in Cubase | |||||
DISTRHO_SAFE_ASSERT(categories.isNotEmpty()); | |||||
} | } | ||||
return categories.buffer(); | return categories.buffer(); | ||||
@@ -4864,7 +4863,7 @@ struct dpf_factory : v3_plugin_factory_cpp { | |||||
DISTRHO_NAMESPACE::strncpy_utf16(info->name, sPlugin->getName(), ARRAY_SIZE(info->name)); | DISTRHO_NAMESPACE::strncpy_utf16(info->name, sPlugin->getName(), ARRAY_SIZE(info->name)); | ||||
DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, sPlugin->getMaker(), ARRAY_SIZE(info->vendor)); | DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, sPlugin->getMaker(), ARRAY_SIZE(info->vendor)); | ||||
DISTRHO_NAMESPACE::strncpy_utf16(info->version, getPluginVersion(), ARRAY_SIZE(info->version)); | DISTRHO_NAMESPACE::strncpy_utf16(info->version, getPluginVersion(), ARRAY_SIZE(info->version)); | ||||
DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty 3.7.4", ARRAY_SIZE(info->sdk_version)); | |||||
DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "VST 3.7.4", ARRAY_SIZE(info->sdk_version)); | |||||
if (idx == 0) | if (idx == 0) | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -15,8 +15,8 @@ | |||||
*/ | */ | ||||
#include "DistrhoDetails.hpp" | #include "DistrhoDetails.hpp" | ||||
#include "DistrhoPluginUtils.hpp" | |||||
#include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
#include "src/DistrhoDefines.h" | |||||
#include <cstddef> | #include <cstddef> | ||||
@@ -26,6 +26,15 @@ | |||||
# include <stdint.h> | # include <stdint.h> | ||||
#endif | #endif | ||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
# include <winsock2.h> | |||||
# include <windows.h> | |||||
#elif defined(HAVE_X11) | |||||
# define Window X11Window | |||||
# include <X11/Xresource.h> | |||||
# undef Window | |||||
#endif | |||||
#if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC) | #if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC) | ||||
# define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION | # define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION | ||||
# define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) | # define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) | ||||
@@ -50,35 +59,29 @@ | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
# include "../extra/FileBrowserDialogImpl.hpp" | # include "../extra/FileBrowserDialogImpl.hpp" | ||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
# define Window X11Window | |||||
# include "../extra/FileBrowserDialogImpl.cpp" | # include "../extra/FileBrowserDialogImpl.cpp" | ||||
# undef Window | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# if defined(DISTRHO_OS_WINDOWS) | |||||
# include <winsock2.h> | |||||
# include <windows.h> | |||||
# elif defined(HAVE_X11) | |||||
# include <X11/Xresource.h> | |||||
# endif | |||||
#else | |||||
# include "src/TopLevelWidgetPrivateData.hpp" | |||||
# include "src/WindowPrivateData.hpp" | |||||
#if DISTRHO_UI_WEB_VIEW && !defined(DISTRHO_OS_MAC) | |||||
# define DISTRHO_WEB_VIEW_HPP_INCLUDED | |||||
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE | |||||
# define WEB_VIEW_DISTRHO_NAMESPACE | |||||
START_NAMESPACE_DISTRHO | |||||
# include "../extra/WebViewImpl.hpp" | |||||
END_NAMESPACE_DISTRHO | |||||
# define Window X11Window | |||||
# include "../extra/WebViewImpl.cpp" | |||||
# undef Window | |||||
#endif | #endif | ||||
#include "src/TopLevelWidgetPrivateData.hpp" | |||||
#include "src/WindowPrivateData.hpp" | |||||
#include "DistrhoUIPrivateData.hpp" | #include "DistrhoUIPrivateData.hpp" | ||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
/* ------------------------------------------------------------------------------------------------------------ | |||||
* Static data, see DistrhoUIInternal.hpp */ | |||||
const char* g_nextBundlePath = nullptr; | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uintptr_t g_nextWindowId = 0; | |||||
double g_nextScaleFactor = 1.0; | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* get global scale factor */ | * get global scale factor */ | ||||
@@ -91,23 +94,23 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
if (const char* const scale = getenv("DPF_SCALE_FACTOR")) | if (const char* const scale = getenv("DPF_SCALE_FACTOR")) | ||||
return std::max(1.0, std::atof(scale)); | return std::max(1.0, std::atof(scale)); | ||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) | if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) | ||||
{ | { | ||||
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); | ||||
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); | ||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic push | |||||
# pragma GCC diagnostic ignored "-Wcast-function-type" | |||||
# endif | |||||
#if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
#pragma GCC diagnostic push | |||||
#pragma GCC diagnostic ignored "-Wcast-function-type" | |||||
#endif | |||||
const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | const PFN_GetProcessDpiAwareness GetProcessDpiAwareness | ||||
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness"); | ||||
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor | ||||
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor"); | ||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
#if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
#pragma GCC diagnostic pop | |||||
#endif | |||||
DWORD dpiAware = 0; | DWORD dpiAware = 0; | ||||
DWORD scaleFactor = 100; | DWORD scaleFactor = 100; | ||||
@@ -123,7 +126,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
FreeLibrary(Shcore); | FreeLibrary(Shcore); | ||||
return static_cast<double>(scaleFactor) / 100.0; | return static_cast<double>(scaleFactor) / 100.0; | ||||
} | } | ||||
#elif defined(HAVE_X11) | |||||
#elif defined(HAVE_X11) | |||||
::Display* const display = XOpenDisplay(nullptr); | ::Display* const display = XOpenDisplay(nullptr); | ||||
DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0); | DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0); | ||||
@@ -154,7 +157,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
XCloseDisplay(display); | XCloseDisplay(display); | ||||
return dpi / 96; | return dpi / 96; | ||||
#endif | |||||
#endif | |||||
return 1.0; | return 1.0; | ||||
@@ -163,80 +166,167 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
} | } | ||||
#endif // !DISTRHO_OS_MAC | #endif // !DISTRHO_OS_MAC | ||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI::PrivateData special handling */ | * UI::PrivateData special handling */ | ||||
UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr; | UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr; | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
ExternalWindow::PrivateData | |||||
#else | |||||
PluginWindow& | |||||
#endif | |||||
UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const bool adjustForScaleFactor) | |||||
PluginWindow& UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height) | |||||
{ | { | ||||
UI::PrivateData* const pData = s_nextPrivateData; | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
const double scaleFactor = d_isNotZero(pData->scaleFactor) ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); | |||||
UI::PrivateData* const uiData = s_nextPrivateData; | |||||
const double scaleFactor = d_isNotZero(uiData->scaleFactor) ? uiData->scaleFactor : getDesktopScaleFactor(uiData->winId); | |||||
if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) | |||||
if (d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) | |||||
{ | { | ||||
width *= scaleFactor; | width *= scaleFactor; | ||||
height *= scaleFactor; | height *= scaleFactor; | ||||
} | } | ||||
pData->window = new PluginWindow(ui, pData->app); | |||||
ExternalWindow::PrivateData ewData; | |||||
ewData.parentWindowHandle = pData->winId; | |||||
ewData.width = width; | |||||
ewData.height = height; | |||||
ewData.scaleFactor = scaleFactor; | |||||
ewData.title = DISTRHO_PLUGIN_NAME; | |||||
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; | |||||
return ewData; | |||||
#else | |||||
const double scaleFactor = pData->scaleFactor; | |||||
d_stdout("createNextWindow %u %u %f", width, height, scaleFactor); | |||||
uiData->window = new PluginWindow(ui, uiData->app, uiData->winId, width, height, scaleFactor); | |||||
if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) | |||||
if (uiData->callbacksPtr != nullptr) | |||||
{ | { | ||||
width *= scaleFactor; | |||||
height *= scaleFactor; | |||||
} | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
String path; | |||||
if (uiData->bundlePath != nullptr) | |||||
{ | |||||
path = getResourcePath(uiData->bundlePath); | |||||
} | |||||
else | |||||
{ | |||||
path = getBinaryFilename(); | |||||
path.truncate(path.rfind(DISTRHO_OS_SEP)); | |||||
path += "/resources"; | |||||
} | |||||
pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, scaleFactor); | |||||
// TODO convert win32 paths to web | |||||
// TODO encode paths (e.g. %20 for space) | |||||
WebViewOptions opts; | |||||
opts.initialJS = "" | |||||
"editParameter = function(index, started){ postMessage('editparam '+index+' '+(started ? 1 : 0)) };" | |||||
"setParameterValue = function(index, value){ postMessage('setparam '+index+' '+value) };" | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
"setState = function(key, value){ postMessage('setstate '+key+' '+value) };" | |||||
"requestStateFile = function(key){ postMessage('reqstatefile '+key) };" | |||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
"sendNote = function(channel, note, velocity){ postMessage('sendnote '+channel+' '+note+' '+velocity) };" | |||||
#endif | |||||
; | |||||
opts.callback = webViewMessageCallback; | |||||
opts.callbackPtr = uiData; | |||||
uiData->webview = webViewCreate("file://" + path + "/index.html", uiData->winId, width, height, scaleFactor, opts); | |||||
#endif | |||||
} | |||||
// If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks | // If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks | ||||
if (pData->callbacksPtr == nullptr) | |||||
pData->window->setIgnoreIdleCallbacks(); | |||||
else | |||||
{ | |||||
uiData->window->setIgnoreIdleCallbacks(); | |||||
} | |||||
return uiData->window.getObject(); | |||||
} | |||||
return pData->window.getObject(); | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
void UI::PrivateData::webViewMessageCallback(void* const arg, char* const msg) | |||||
{ | |||||
UI::PrivateData* const uiData = static_cast<UI::PrivateData*>(arg); | |||||
if (std::strncmp(msg, "setparam ", 9) == 0) | |||||
{ | |||||
const char* const strindex = msg + 9; | |||||
char* strvalue = nullptr; | |||||
const ulong index = std::strtoul(strindex, &strvalue, 10); | |||||
DISTRHO_SAFE_ASSERT_RETURN(strvalue != nullptr && strindex != strvalue,); | |||||
float value; | |||||
{ | |||||
const ScopedSafeLocale ssl; | |||||
value = std::atof(strvalue); | |||||
} | |||||
uiData->setParamCallback(index + uiData->parameterOffset, value); | |||||
return; | |||||
} | |||||
if (std::strncmp(msg, "editparam ", 10) == 0) | |||||
{ | |||||
const char* const strindex = msg + 10; | |||||
char* strvalue = nullptr; | |||||
const ulong index = std::strtoul(strindex, &strvalue, 10); | |||||
DISTRHO_SAFE_ASSERT_RETURN(strvalue != nullptr && strindex != strvalue,); | |||||
const bool started = strvalue[0] != '0'; | |||||
uiData->editParamCallback(index + uiData->parameterOffset, started); | |||||
return; | |||||
} | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
if (std::strncmp(msg, "setstate ", 9) == 0) | |||||
{ | |||||
char* const key = msg + 9; | |||||
char* const sep = std::strchr(key, ' '); | |||||
DISTRHO_SAFE_ASSERT_RETURN(sep != nullptr,); | |||||
*sep = 0; | |||||
char* const value = sep + 1; | |||||
uiData->setStateCallback(key, value); | |||||
return; | |||||
} | |||||
if (std::strncmp(msg, "reqstatefile ", 13) == 0) | |||||
{ | |||||
const char* const key = msg + 13; | |||||
uiData->fileRequestCallback(key); | |||||
return; | |||||
} | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
if (std::strncmp(msg, "sendnote ", 9) == 0) | |||||
{ | |||||
const char* const strchannel = msg + 9; | |||||
char* strnote = nullptr; | |||||
char* strvelocity = nullptr; | |||||
char* end = nullptr; | |||||
const ulong channel = std::strtoul(strchannel, &strnote, 10); | |||||
DISTRHO_SAFE_ASSERT_RETURN(strnote != nullptr && strchannel != strnote,); | |||||
const ulong note = std::strtoul(strnote, &strvelocity, 10); | |||||
DISTRHO_SAFE_ASSERT_RETURN(strvelocity != nullptr && strchannel != strvelocity,); | |||||
const ulong velocity = std::strtoul(strvelocity, &end, 10); | |||||
DISTRHO_SAFE_ASSERT_RETURN(end != nullptr && strvelocity != end,); | |||||
uiData->sendNoteCallback(channel, note, velocity); | |||||
return; | |||||
} | |||||
#endif | |||||
d_stderr("UI received unknown message '%s'", msg); | |||||
} | } | ||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI */ | * UI */ | ||||
UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetAsMinimumSize) | UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetAsMinimumSize) | ||||
: UIWidget(UI::PrivateData::createNextWindow(this, | : UIWidget(UI::PrivateData::createNextWindow(this, | ||||
// width | |||||
#ifdef DISTRHO_UI_DEFAULT_WIDTH | #ifdef DISTRHO_UI_DEFAULT_WIDTH | ||||
width == 0 ? DISTRHO_UI_DEFAULT_WIDTH : | width == 0 ? DISTRHO_UI_DEFAULT_WIDTH : | ||||
#endif | #endif | ||||
width, | width, | ||||
// height | |||||
#ifdef DISTRHO_UI_DEFAULT_HEIGHT | #ifdef DISTRHO_UI_DEFAULT_HEIGHT | ||||
height == 0 ? DISTRHO_UI_DEFAULT_HEIGHT : | height == 0 ? DISTRHO_UI_DEFAULT_HEIGHT : | ||||
#endif | #endif | ||||
height, | |||||
#ifdef DISTRHO_UI_DEFAULT_WIDTH | |||||
width == 0 | |||||
#else | |||||
false | |||||
#endif | |||||
height | |||||
)), | )), | ||||
uiData(UI::PrivateData::s_nextPrivateData) | uiData(UI::PrivateData::s_nextPrivateData) | ||||
{ | { | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
if (width != 0 && height != 0) | if (width != 0 && height != 0) | ||||
{ | { | ||||
Widget::setSize(width, height); | Widget::setSize(width, height); | ||||
@@ -250,14 +340,14 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA | |||||
Widget::setSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); | Widget::setSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); | ||||
} | } | ||||
#endif | #endif | ||||
#else | |||||
// unused | |||||
(void)automaticallyScaleAndSetAsMinimumSize; | |||||
#endif | |||||
} | } | ||||
UI::~UI() | UI::~UI() | ||||
{ | { | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
webViewDestroy(uiData->webview); | |||||
#endif | |||||
} | } | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -265,15 +355,11 @@ UI::~UI() | |||||
bool UI::isResizable() const noexcept | bool UI::isResizable() const noexcept | ||||
{ | { | ||||
#if DISTRHO_UI_USER_RESIZABLE | |||||
# if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
return true; | |||||
# else | |||||
#if DISTRHO_UI_USER_RESIZABLE | |||||
return uiData->window->isResizable(); | return uiData->window->isResizable(); | ||||
# endif | |||||
#else | |||||
#else | |||||
return false; | return false; | ||||
#endif | |||||
#endif | |||||
} | } | ||||
uint UI::getBackgroundColor() const noexcept | uint UI::getBackgroundColor() const noexcept | ||||
@@ -344,33 +430,94 @@ void* UI::getPluginInstancePointer() const noexcept | |||||
} | } | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* External UI helpers (static calls) */ | |||||
* DSP/Plugin Callbacks */ | |||||
const char* UI::getNextBundlePath() noexcept | |||||
void UI::parameterChanged(const uint32_t index, const float value) | |||||
{ | { | ||||
return g_nextBundlePath; | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
{ | |||||
char msg[128]; | |||||
{ | |||||
const ScopedSafeLocale ssl; | |||||
std::snprintf(msg, sizeof(msg) - 1, | |||||
"typeof(parameterChanged) === 'function' && parameterChanged(%u,%f)", index, value); | |||||
} | |||||
webViewEvaluateJS(uiData->webview, msg); | |||||
} | |||||
#else | |||||
// unused | |||||
(void)index; | |||||
(void)value; | |||||
#endif | |||||
} | } | ||||
double UI::getNextScaleFactor() noexcept | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
void UI::programLoaded(const uint32_t index) | |||||
{ | { | ||||
return g_nextScaleFactor; | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
{ | |||||
char msg[128]; | |||||
std::snprintf(msg, sizeof(msg) - 1, | |||||
"typeof(programLoaded) === 'function' && programLoaded(%u)", index); | |||||
webViewEvaluateJS(uiData->webview, msg); | |||||
} | |||||
#else | |||||
// unused | |||||
(void)index; | |||||
#endif | |||||
} | } | ||||
#endif | |||||
# if DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
uintptr_t UI::getNextWindowId() noexcept | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
void UI::stateChanged(const char* const key, const char* const value) | |||||
{ | { | ||||
return g_nextWindowId; | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
{ | |||||
const size_t keylen = std::strlen(key); | |||||
const size_t valuelen = std::strlen(value); | |||||
const size_t msglen = keylen + valuelen + 60; | |||||
if (char* const msg = static_cast<char*>(std::malloc(msglen))) | |||||
{ | |||||
// TODO escape \\' | |||||
std::snprintf(msg, msglen - 1, | |||||
"typeof(stateChanged) === 'function' && stateChanged('%s','%s')", key, value); | |||||
msg[msglen - 1] = '\0'; | |||||
webViewEvaluateJS(uiData->webview, msg); | |||||
std::free(msg); | |||||
} | |||||
} | |||||
#else | |||||
// unused | |||||
(void)key; | |||||
(void)value; | |||||
#endif | |||||
} | } | ||||
# endif | |||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* DSP/Plugin Callbacks (optional) */ | * DSP/Plugin Callbacks (optional) */ | ||||
void UI::sampleRateChanged(double) | |||||
void UI::sampleRateChanged(const double sampleRate) | |||||
{ | { | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
{ | |||||
char msg[128]; | |||||
{ | |||||
const ScopedSafeLocale ssl; | |||||
std::snprintf(msg, sizeof(msg) - 1, | |||||
"typeof(sampleRateChanged) === 'function' && sampleRateChanged(%f)", sampleRate); | |||||
} | |||||
webViewEvaluateJS(uiData->webview, msg); | |||||
} | |||||
#else | |||||
// unused | |||||
(void)sampleRate; | |||||
#endif | |||||
} | } | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -380,7 +527,6 @@ void UI::uiScaleFactorChanged(double) | |||||
{ | { | ||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
std::vector<DGL_NAMESPACE::ClipboardDataOffer> UI::getClipboardDataOfferTypes() | std::vector<DGL_NAMESPACE::ClipboardDataOffer> UI::getClipboardDataOfferTypes() | ||||
{ | { | ||||
return uiData->window->getClipboardDataOfferTypes(); | return uiData->window->getClipboardDataOfferTypes(); | ||||
@@ -409,7 +555,6 @@ void UI::uiReshape(const uint width, const uint height) | |||||
// NOTE this must be the same as Window::onReshape | // NOTE this must be the same as Window::onReshape | ||||
pData->fallbackOnResize(width, height); | pData->fallbackOnResize(width, height); | ||||
} | } | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_UI_FILE_BROWSER | #if DISTRHO_UI_FILE_BROWSER | ||||
void UI::uiFileBrowserSelected(const char*) | void UI::uiFileBrowserSelected(const char*) | ||||
@@ -420,19 +565,11 @@ void UI::uiFileBrowserSelected(const char*) | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void UI::sizeChanged(const uint width, const uint height) | |||||
{ | |||||
UIWidget::sizeChanged(width, height); | |||||
uiData->setSizeCallback(width, height); | |||||
} | |||||
#else | |||||
void UI::onResize(const ResizeEvent& ev) | void UI::onResize(const ResizeEvent& ev) | ||||
{ | { | ||||
UIWidget::onResize(ev); | UIWidget::onResize(ev); | ||||
#if !(defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)) | |||||
#if ! DISTRHO_UI_USES_SIZE_REQUEST | |||||
if (uiData->initializing) | if (uiData->initializing) | ||||
return; | return; | ||||
@@ -442,10 +579,10 @@ void UI::onResize(const ResizeEvent& ev) | |||||
#endif | #endif | ||||
} | } | ||||
// NOTE: only used for VST3 and CLAP | |||||
// NOTE: only used for CLAP and VST3 | |||||
void UI::requestSizeChange(const uint width, const uint height) | void UI::requestSizeChange(const uint width, const uint height) | ||||
{ | { | ||||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
#if DISTRHO_UI_USES_SIZE_REQUEST | |||||
if (uiData->initializing) | if (uiData->initializing) | ||||
uiData->window->setSizeFromHost(width, height); | uiData->window->setSizeFromHost(width, height); | ||||
else | else | ||||
@@ -456,7 +593,6 @@ void UI::requestSizeChange(const uint width, const uint height) | |||||
(void)height; | (void)height; | ||||
#endif | #endif | ||||
} | } | ||||
#endif | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -0,0 +1,502 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoUIInternal.hpp" | |||||
#define Point AudioUnitPoint | |||||
#define Size AudioUnitSize | |||||
#include <AudioUnit/AudioUnit.h> | |||||
#include <AudioUnit/AUCocoaUIView.h> | |||||
#include <Cocoa/Cocoa.h> | |||||
#undef Point | |||||
#undef Size | |||||
#ifndef DISTRHO_PLUGIN_BRAND_ID | |||||
# error DISTRHO_PLUGIN_BRAND_ID undefined! | |||||
#endif | |||||
#ifndef DISTRHO_PLUGIN_UNIQUE_ID | |||||
# error DISTRHO_PLUGIN_UNIQUE_ID undefined! | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#if ! DISTRHO_PLUGIN_WANT_STATE | |||||
static constexpr const setStateFunc setStateCallback = nullptr; | |||||
#endif | |||||
#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
static constexpr const sendNoteFunc sendNoteCallback = nullptr; | |||||
#endif | |||||
// unsupported in AU | |||||
static constexpr const fileRequestFunc fileRequestCallback = nullptr; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Static data, see DistrhoPlugin.cpp | |||||
extern double d_nextSampleRate; | |||||
extern const char* d_nextBundlePath; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
class DPF_UI_AU | |||||
{ | |||||
public: | |||||
DPF_UI_AU(const AudioUnit component, | |||||
NSView* const view, | |||||
const double sampleRate, | |||||
void* const instancePointer) | |||||
: fComponent(component), | |||||
fParentView(view), | |||||
fTimerRef(nullptr), | |||||
fUI(this, | |||||
reinterpret_cast<uintptr_t>(view), | |||||
sampleRate, | |||||
editParameterCallback, | |||||
setParameterCallback, | |||||
setStateCallback, | |||||
sendNoteCallback, | |||||
setSizeCallback, | |||||
fileRequestCallback, | |||||
d_nextBundlePath, | |||||
instancePointer) | |||||
{ | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
// create state keys | |||||
{ | |||||
CFArrayRef keysRef = nullptr; | |||||
UInt32 dataSize = sizeof(CFArrayRef); | |||||
if (AudioUnitGetProperty(fComponent, 'DPFl', kAudioUnitScope_Global, 0, &keysRef, &dataSize) == noErr | |||||
&& dataSize == sizeof(CFArrayRef)) | |||||
{ | |||||
const CFIndex numStates = CFArrayGetCount(keysRef); | |||||
char* key = nullptr; | |||||
CFIndex keyLen = -1; | |||||
fStateKeys.resize(numStates); | |||||
for (CFIndex i=0; i<numStates; ++i) | |||||
{ | |||||
const CFStringRef keyRef = static_cast<CFStringRef>(CFArrayGetValueAtIndex(keysRef, i)); | |||||
DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(keyRef) == CFStringGetTypeID()); | |||||
const CFIndex keyRefLen = CFStringGetLength(keyRef); | |||||
if (keyLen < keyRefLen) | |||||
{ | |||||
keyLen = keyRefLen; | |||||
key = static_cast<char*>(std::realloc(key, keyLen + 1)); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(keyRef, key, keyLen + 1, kCFStringEncodingASCII)); | |||||
fStateKeys[i] = key; | |||||
} | |||||
CFRelease(keysRef); | |||||
std::free(key); | |||||
} | |||||
} | |||||
#endif | |||||
// setup idle timer | |||||
constexpr const CFTimeInterval interval = 60 * 0.0001; | |||||
CFRunLoopTimerContext context = {}; | |||||
context.info = this; | |||||
fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0, | |||||
_idleCallback, &context); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,); | |||||
CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | |||||
AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); | |||||
AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this); | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
AudioUnitAddPropertyListener(fComponent, 'DPFo', auPropertyChangedCallback, this); | |||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
AudioUnitAddPropertyListener(fComponent, 'DPFs', auPropertyChangedCallback, this); | |||||
#endif | |||||
} | |||||
~DPF_UI_AU() | |||||
{ | |||||
AudioUnitRemovePropertyListenerWithUserData(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); | |||||
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFp', auPropertyChangedCallback, this); | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFo', auPropertyChangedCallback, this); | |||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFs', auPropertyChangedCallback, this); | |||||
#endif | |||||
if (fTimerRef != nullptr) | |||||
{ | |||||
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | |||||
CFRelease(fTimerRef); | |||||
} | |||||
} | |||||
void postSetup() | |||||
{ | |||||
const double scaleFactor = fUI.getScaleFactor(); | |||||
const NSSize size = NSMakeSize(fUI.getWidth() / scaleFactor, fUI.getHeight() / scaleFactor); | |||||
[fParentView setFrameSize:size]; | |||||
[fParentView setHidden:NO]; | |||||
} | |||||
private: | |||||
const AudioUnit fComponent; | |||||
NSView* const fParentView; | |||||
CFRunLoopTimerRef fTimerRef; | |||||
UIExporter fUI; | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
std::vector<String> fStateKeys; | |||||
#endif | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
// Idle setup | |||||
void idleCallback() | |||||
{ | |||||
fUI.idleFromNativeIdle(); | |||||
} | |||||
static void _idleCallback(CFRunLoopTimerRef, void* const info) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(info)->idleCallback(); | |||||
} | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
// AU callbacks | |||||
void auSampleRateChanged(const AudioUnitScope scope) | |||||
{ | |||||
Float64 sampleRate = 0; | |||||
UInt32 dataSize = sizeof(Float64); | |||||
if (AudioUnitGetProperty(fComponent, kAudioUnitProperty_SampleRate, scope, 0, &sampleRate, &dataSize) == noErr | |||||
&& dataSize == sizeof(Float64)) | |||||
{ | |||||
fUI.setSampleRate(sampleRate, true); | |||||
} | |||||
} | |||||
void auParameterChanged(const AudioUnitElement elem) | |||||
{ | |||||
float value = 0; | |||||
UInt32 dataSize = sizeof(float); | |||||
if (AudioUnitGetProperty(fComponent, 'DPFp', kAudioUnitScope_Global, elem, &value, &dataSize) == noErr | |||||
&& dataSize == sizeof(float)) | |||||
{ | |||||
fUI.parameterChanged(elem, value); | |||||
} | |||||
} | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
void auProgramChanged() | |||||
{ | |||||
uint32_t program = 0; | |||||
UInt32 dataSize = sizeof(uint32_t); | |||||
if (AudioUnitGetProperty(fComponent, 'DPFo', kAudioUnitScope_Global, 0, &program, &dataSize) == noErr | |||||
&& dataSize == sizeof(uint32_t)) | |||||
{ | |||||
fUI.programLoaded(program); | |||||
} | |||||
} | |||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
void auStateChanged(const AudioUnitElement elem) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(elem < fStateKeys.size(),); | |||||
CFStringRef valueRef = nullptr; | |||||
UInt32 dataSize = sizeof(valueRef); | |||||
if (AudioUnitGetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, elem, &valueRef, &dataSize) == noErr | |||||
&& dataSize == sizeof(CFStringRef) | |||||
&& valueRef != nullptr | |||||
&& CFGetTypeID(valueRef) == CFStringGetTypeID()) | |||||
{ | |||||
const CFIndex valueLen = CFStringGetLength(valueRef); | |||||
char* const value = static_cast<char*>(std::malloc(valueLen + 1)); | |||||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8),); | |||||
fUI.stateChanged(fStateKeys[elem], value); | |||||
CFRelease(valueRef); | |||||
std::free(value); | |||||
} | |||||
} | |||||
#endif | |||||
static void auPropertyChangedCallback(void* const userData, | |||||
const AudioUnit component, | |||||
const AudioUnitPropertyID prop, | |||||
const AudioUnitScope scope, | |||||
const AudioUnitElement elem) | |||||
{ | |||||
DPF_UI_AU* const self = static_cast<DPF_UI_AU*>(userData); | |||||
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(self->fComponent == component,); | |||||
switch (prop) | |||||
{ | |||||
case kAudioUnitProperty_SampleRate: | |||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope,); | |||||
self->auSampleRateChanged(scope); | |||||
break; | |||||
case 'DPFp': | |||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); | |||||
self->auParameterChanged(elem); | |||||
break; | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
case 'DPFo': | |||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); | |||||
self->auProgramChanged(); | |||||
break; | |||||
#endif | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
case 'DPFs': | |||||
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); | |||||
self->auStateChanged(elem); | |||||
break; | |||||
#endif | |||||
} | |||||
} | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
// DPF callbacks | |||||
void editParameter(const uint32_t rindex, const bool started) const | |||||
{ | |||||
const uint8_t flag = started ? 1 : 2; | |||||
AudioUnitSetProperty(fComponent, 'DPFe', kAudioUnitScope_Global, rindex, &flag, sizeof(uint8_t)); | |||||
if (! started) | |||||
{ | |||||
const uint8_t cancel = 0; | |||||
AudioUnitSetProperty(fComponent, 'DPFe', kAudioUnitScope_Global, rindex, &cancel, sizeof(uint8_t)); | |||||
} | |||||
} | |||||
static void editParameterCallback(void* const ptr, const uint32_t rindex, const bool started) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(ptr)->editParameter(rindex, started); | |||||
} | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
void setParameter(const uint32_t rindex, const float value) | |||||
{ | |||||
AudioUnitSetProperty(fComponent, 'DPFp', kAudioUnitScope_Global, rindex, &value, sizeof(float)); | |||||
} | |||||
static void setParameterCallback(void* const ptr, const uint32_t rindex, const float value) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(ptr)->setParameter(rindex, value); | |||||
} | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
void setState(const char* const key, const char* const value) | |||||
{ | |||||
const std::vector<String>::iterator it = std::find(fStateKeys.begin(), fStateKeys.end(), key); | |||||
DISTRHO_SAFE_ASSERT_RETURN(it != fStateKeys.end(),); | |||||
if (const CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8)) | |||||
{ | |||||
const uint32_t index = it - fStateKeys.begin(); | |||||
AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, index, &valueRef, sizeof(CFStringRef)); | |||||
CFRelease(valueRef); | |||||
} | |||||
} | |||||
static void setStateCallback(void* const ptr, const char* const key, const char* const value) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(ptr)->setState(key, value); | |||||
} | |||||
#endif | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||||
{ | |||||
const uint8_t data[3] = { static_cast<uint8_t>((velocity != 0 ? 0x90 : 0x80) | channel), note, velocity }; | |||||
AudioUnitSetProperty(fComponent, 'DPFn', kAudioUnitScope_Global, 0, data, sizeof(data)); | |||||
const uint8_t cancel[3] = { 0, 0, 0 }; | |||||
AudioUnitSetProperty(fComponent, 'DPFn', kAudioUnitScope_Global, 0, cancel, sizeof(cancel)); | |||||
} | |||||
static void sendNoteCallback(void* const ptr, const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(ptr)->sendNote(channel, note, velocity); | |||||
} | |||||
#endif | |||||
// ---------------------------------------------------------------------------------------------------------------- | |||||
void setSize(const uint width, const uint height) | |||||
{ | |||||
const double scaleFactor = fUI.getScaleFactor(); | |||||
const NSSize size = NSMakeSize(width / scaleFactor, height / scaleFactor); | |||||
[fParentView setFrameSize:size]; | |||||
} | |||||
static void setSizeCallback(void* const ptr, const uint width, const uint height) | |||||
{ | |||||
static_cast<DPF_UI_AU*>(ptr)->setSize(width, height); | |||||
} | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#define MACRO_NAME2(a, b, c, d, e, f) a ## b ## c ## d ## e ## f | |||||
#define MACRO_NAME(a, b, c, d, e, f) MACRO_NAME2(a, b, c, d, e, f) | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#define COCOA_VIEW_CLASS_NAME \ | |||||
MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) | |||||
@interface COCOA_VIEW_CLASS_NAME : NSView | |||||
{ | |||||
@public | |||||
DPF_UI_AU* ui; | |||||
} | |||||
@end | |||||
@implementation COCOA_VIEW_CLASS_NAME | |||||
- (id) initWithPreferredSize:(NSSize)size | |||||
{ | |||||
ui = nullptr; | |||||
self = [super initWithFrame: NSMakeRect(0, 0, size.width, size.height)]; | |||||
[self setHidden:YES]; | |||||
return self; | |||||
} | |||||
- (BOOL) acceptsFirstResponder | |||||
{ | |||||
return YES; | |||||
} | |||||
- (void) dealloc | |||||
{ | |||||
delete ui; | |||||
ui = nullptr; | |||||
[super dealloc]; | |||||
} | |||||
- (BOOL) isFlipped | |||||
{ | |||||
return YES; | |||||
} | |||||
@end | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#define COCOA_UI_CLASS_NAME \ | |||||
MACRO_NAME(CocoaAUView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) | |||||
@interface COCOA_UI_CLASS_NAME : NSObject<AUCocoaUIBase> | |||||
{ | |||||
COCOA_VIEW_CLASS_NAME* view; | |||||
} | |||||
@end | |||||
@implementation COCOA_UI_CLASS_NAME | |||||
- (NSString*) description | |||||
{ | |||||
return @DISTRHO_PLUGIN_NAME; | |||||
} | |||||
- (unsigned) interfaceVersion | |||||
{ | |||||
return 0; | |||||
} | |||||
- (NSView*) uiViewForAudioUnit:(AudioUnit)component withSize:(NSSize)inPreferredSize | |||||
{ | |||||
Float64 sampleRate = d_nextSampleRate; | |||||
void* instancePointer = nullptr; | |||||
AudioUnitScope scope; | |||||
UInt32 dataSize; | |||||
// fetch direct access pointer | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
dataSize = sizeof(void*); | |||||
AudioUnitGetProperty(component, 'DPFa', kAudioUnitScope_Global, 0, &instancePointer, &dataSize); | |||||
#endif | |||||
// fetch current sample rate | |||||
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||||
dataSize = sizeof(Float64); | |||||
AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRate, &dataSize); | |||||
#elif DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||||
dataSize = sizeof(Float64); | |||||
AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, &dataSize); | |||||
#endif | |||||
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | |||||
inPreferredSize = NSMakeSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); | |||||
#endif | |||||
// create view | |||||
view = [[[COCOA_VIEW_CLASS_NAME alloc] initWithPreferredSize:inPreferredSize] autorelease]; | |||||
view->ui = new DPF_UI_AU(component, view, sampleRate, instancePointer); | |||||
view->ui->postSetup(); | |||||
// request data from DSP side | |||||
{ | |||||
const uint16_t magic = 1337; | |||||
AudioUnitSetProperty(component, 'DPFi', kAudioUnitScope_Global, 0, &magic, sizeof(uint16_t)); | |||||
const uint16_t cancel = 0; | |||||
AudioUnitSetProperty(component, 'DPFi', kAudioUnitScope_Global, 0, &cancel, sizeof(uint16_t)); | |||||
} | |||||
return view; | |||||
// maybe unused | |||||
(void)scope; | |||||
} | |||||
@end | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#undef MACRO_NAME | |||||
#undef MACRO_NAME2 | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,11 +26,24 @@ | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
static constexpr const sendNoteFunc sendNoteCallback = nullptr; | static constexpr const sendNoteFunc sendNoteCallback = nullptr; | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// unused in DSSI, we only use external and standalone UIs | |||||
static constexpr const setSizeFunc setSizeCallback = nullptr; | |||||
// unsupported in DSSI | |||||
static constexpr const fileRequestFunc fileRequestCallback = nullptr; | |||||
#ifdef DPF_USING_LD_LINUX_WEBVIEW | |||||
int dpf_webview_start(int argc, char* argv[]); | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
struct OscData { | struct OscData { | ||||
lo_address addr; | lo_address addr; | ||||
@@ -98,7 +111,7 @@ class UIDssi : public DGL_NAMESPACE::IdleCallback | |||||
public: | public: | ||||
UIDssi(const OscData& oscData, const char* const uiTitle, const double sampleRate) | UIDssi(const OscData& oscData, const char* const uiTitle, const double sampleRate) | ||||
: fUI(this, 0, sampleRate, nullptr, | : fUI(this, 0, sampleRate, nullptr, | ||||
setParameterCallback, setStateCallback, sendNoteCallback, nullptr, nullptr), | |||||
setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, fileRequestCallback), | |||||
fHostClosed(false), | fHostClosed(false), | ||||
fOscData(oscData) | fOscData(oscData) | ||||
{ | { | ||||
@@ -378,6 +391,11 @@ int main(int argc, char* argv[]) | |||||
{ | { | ||||
USE_NAMESPACE_DISTRHO | USE_NAMESPACE_DISTRHO | ||||
#ifdef DPF_USING_LD_LINUX_WEBVIEW | |||||
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) | |||||
return dpf_webview_start(argc - 1, argv + 1); | |||||
#endif | |||||
// dummy test mode | // dummy test mode | ||||
if (argc == 1) | if (argc == 1) | ||||
{ | { | ||||
@@ -395,7 +413,7 @@ int main(int argc, char* argv[]) | |||||
if (argc != 5) | if (argc != 5) | ||||
{ | { | ||||
fprintf(stderr, "Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>\n", argv[0]); | |||||
d_stderr("Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>", argv[0]); | |||||
return 1; | return 1; | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -21,15 +21,6 @@ | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------- | |||||
// Static data, see DistrhoUI.cpp | |||||
extern const char* g_nextBundlePath; | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
extern uintptr_t g_nextWindowId; | |||||
extern double g_nextScaleFactor; | |||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// UI exporter class | // UI exporter class | ||||
@@ -79,41 +70,23 @@ public: | |||||
uiData->setSizeCallbackFunc = setSizeCall; | uiData->setSizeCallbackFunc = setSizeCall; | ||||
uiData->fileRequestCallbackFunc = fileRequestCall; | uiData->fileRequestCallbackFunc = fileRequestCall; | ||||
g_nextBundlePath = bundlePath; | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
g_nextWindowId = winId; | |||||
g_nextScaleFactor = scaleFactor; | |||||
#endif | |||||
UI::PrivateData::s_nextPrivateData = uiData; | UI::PrivateData::s_nextPrivateData = uiData; | ||||
UI* const uiPtr = createUI(); | UI* const uiPtr = createUI(); | ||||
g_nextBundlePath = nullptr; | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
g_nextWindowId = 0; | |||||
g_nextScaleFactor = 0.0; | |||||
#else | |||||
// enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | // enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | ||||
uiData->window->leaveContext(); | uiData->window->leaveContext(); | ||||
#endif | |||||
UI::PrivateData::s_nextPrivateData = nullptr; | UI::PrivateData::s_nextPrivateData = nullptr; | ||||
DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,); | ||||
ui = uiPtr; | ui = uiPtr; | ||||
uiData->initializing = false; | uiData->initializing = false; | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// unused | |||||
(void)bundlePath; | |||||
#endif | |||||
} | } | ||||
~UIExporter() | ~UIExporter() | ||||
{ | { | ||||
quit(); | quit(); | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uiData->window->enterContextForDeletion(); | uiData->window->enterContextForDeletion(); | ||||
#endif | |||||
delete ui; | delete ui; | ||||
delete uiData; | delete uiData; | ||||
} | } | ||||
@@ -137,13 +110,9 @@ public: | |||||
bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uiData->window->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); | |||||
#else | |||||
const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio)); | const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio)); | ||||
minimumWidth = size.getWidth(); | minimumWidth = size.getWidth(); | ||||
minimumHeight = size.getHeight(); | minimumHeight = size.getHeight(); | ||||
#endif | |||||
return true; | return true; | ||||
} | } | ||||
@@ -225,13 +194,20 @@ public: | |||||
uiData->window->focus(); | uiData->window->focus(); | ||||
uiData->app.addIdleCallback(cb); | uiData->app.addIdleCallback(cb); | ||||
uiData->app.exec(); | uiData->app.exec(); | ||||
uiData->app.removeIdleCallback(cb); | |||||
} | } | ||||
void exec_idle() | void exec_idle() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, ); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, ); | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
webViewIdle(uiData->webview); | |||||
#endif | |||||
ui->uiIdle(); | ui->uiIdle(); | ||||
uiData->app.repaintIfNeeeded(); | |||||
} | } | ||||
void showAndFocus() | void showAndFocus() | ||||
@@ -246,7 +222,14 @@ public: | |||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | ||||
uiData->app.idle(); | uiData->app.idle(); | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
webViewIdle(uiData->webview); | |||||
#endif | |||||
ui->uiIdle(); | ui->uiIdle(); | ||||
uiData->app.repaintIfNeeeded(); | |||||
return ! uiData->app.isQuitting(); | return ! uiData->app.isQuitting(); | ||||
} | } | ||||
@@ -261,25 +244,29 @@ public: | |||||
uiData->app.quit(); | uiData->app.quit(); | ||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void repaint() | void repaint() | ||||
{ | { | ||||
uiData->window->repaint(); | uiData->window->repaint(); | ||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) | |||||
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) | |||||
void idleFromNativeIdle() | void idleFromNativeIdle() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | ||||
uiData->app.triggerIdleCallbacks(); | uiData->app.triggerIdleCallbacks(); | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
if (uiData->webview != nullptr) | |||||
webViewIdle(uiData->webview); | |||||
#endif | |||||
ui->uiIdle(); | ui->uiIdle(); | ||||
uiData->app.repaintIfNeeeded(); | |||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) | void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) | ||||
{ | { | ||||
uiData->window->addIdleCallback(cb, timerFrequencyInMs); | uiData->window->addIdleCallback(cb, timerFrequencyInMs); | ||||
@@ -290,28 +277,18 @@ public: | |||||
uiData->window->removeIdleCallback(cb); | uiData->window->removeIdleCallback(cb); | ||||
} | } | ||||
#endif | #endif | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
void setWindowOffset(const int x, const int y) | void setWindowOffset(const int x, const int y) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// TODO | |||||
(void)x; (void)y; | |||||
#else | |||||
uiData->window->setOffset(x, y); | uiData->window->setOffset(x, y); | ||||
#endif | |||||
} | } | ||||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
#if DISTRHO_UI_USES_SIZE_REQUEST | |||||
void setWindowSizeFromHost(const uint width, const uint height) | void setWindowSizeFromHost(const uint width, const uint height) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
ui->setSize(width, height); | |||||
#else | |||||
uiData->window->setSizeFromHost(width, height); | uiData->window->setSizeFromHost(width, height); | ||||
#endif | |||||
} | } | ||||
#endif | #endif | ||||
@@ -322,11 +299,7 @@ public: | |||||
void setWindowTransientWinId(const uintptr_t transientParentWindowHandle) | void setWindowTransientWinId(const uintptr_t transientParentWindowHandle) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
ui->setTransientWindowId(transientParentWindowHandle); | |||||
#else | |||||
uiData->window->setTransientParent(transientParentWindowHandle); | uiData->window->setTransientParent(transientParentWindowHandle); | ||||
#endif | |||||
} | } | ||||
bool setWindowVisible(const bool yesNo) | bool setWindowVisible(const bool yesNo) | ||||
@@ -336,7 +309,6 @@ public: | |||||
return ! uiData->app.isQuitting(); | return ! uiData->app.isQuitting(); | ||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods) | bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods) | ||||
{ | { | ||||
using namespace DGL_NAMESPACE; | using namespace DGL_NAMESPACE; | ||||
@@ -369,7 +341,6 @@ public: | |||||
return ret; | return ret; | ||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -380,14 +351,12 @@ public: | |||||
ui->uiScaleFactorChanged(scaleFactor); | ui->uiScaleFactorChanged(scaleFactor); | ||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void notifyFocusChanged(const bool focus) | void notifyFocusChanged(const bool focus) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | ||||
ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal); | ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal); | ||||
} | } | ||||
#endif | |||||
void setSampleRate(const double sampleRate, const bool doCallback = false) | void setSampleRate(const double sampleRate, const bool doCallback = false) | ||||
{ | { | ||||
@@ -49,6 +49,9 @@ static constexpr const setStateFunc setStateCallback = nullptr; | |||||
static constexpr const sendNoteFunc sendNoteCallback = nullptr; | static constexpr const sendNoteFunc sendNoteCallback = nullptr; | ||||
#endif | #endif | ||||
// unwanted in LV2, resize extension is deprecated and hosts can do it without extensions | |||||
static constexpr const setSizeFunc setSizeCallback = nullptr; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
template <class LV2F> | template <class LV2F> | ||||
@@ -96,7 +99,7 @@ public: | |||||
setParameterCallback, | setParameterCallback, | ||||
setStateCallback, | setStateCallback, | ||||
sendNoteCallback, | sendNoteCallback, | ||||
nullptr, // resize is very messy, hosts can do it without extensions | |||||
setSizeCallback, | |||||
fileRequestCallback, | fileRequestCallback, | ||||
bundlePath, dspPtr, scaleFactor, bgColor, fgColor, appClassName) | bundlePath, dspPtr, scaleFactor, bgColor, fgColor, appClassName) | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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,33 +23,38 @@ | |||||
# include "DistrhoPluginVST.hpp" | # include "DistrhoPluginVST.hpp" | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include "../extra/Sleep.hpp" | |||||
// TODO import and use file browser here | |||||
#else | |||||
# include "../../dgl/src/ApplicationPrivateData.hpp" | |||||
# include "../../dgl/src/WindowPrivateData.hpp" | |||||
# include "../../dgl/src/pugl.hpp" | |||||
#endif | |||||
#include "../../dgl/src/ApplicationPrivateData.hpp" | |||||
#include "../../dgl/src/WindowPrivateData.hpp" | |||||
#include "../../dgl/src/pugl.hpp" | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER | |||||
# include <map> | # include <map> | ||||
# include <string> | # include <string> | ||||
#endif | #endif | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
# include "extra/WebView.hpp" | |||||
#endif | |||||
#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) | #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) | ||||
# define DISTRHO_UI_IS_STANDALONE 1 | # define DISTRHO_UI_IS_STANDALONE 1 | ||||
#else | #else | ||||
# define DISTRHO_UI_IS_STANDALONE 0 | # define DISTRHO_UI_IS_STANDALONE 0 | ||||
#endif | #endif | ||||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
# define DISTRHO_UI_USES_SIZE_REQUEST true | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) | |||||
# define DISTRHO_UI_USES_SCHEDULED_REPAINTS 1 | |||||
#else | #else | ||||
# define DISTRHO_UI_USES_SIZE_REQUEST false | |||||
# define DISTRHO_UI_USES_SCHEDULED_REPAINTS 0 | |||||
#endif | #endif | ||||
#ifdef DISTRHO_PLUGIN_TARGET_VST2 | |||||
#if defined(DISTRHO_PLUGIN_TARGET_CLAP) || defined(DISTRHO_PLUGIN_TARGET_VST3) | |||||
# define DISTRHO_UI_USES_SIZE_REQUEST 1 | |||||
#else | |||||
# define DISTRHO_UI_USES_SIZE_REQUEST 0 | |||||
#endif | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) || defined(DISTRHO_PLUGIN_TARGET_VST2) | |||||
# undef DISTRHO_UI_USER_RESIZABLE | # undef DISTRHO_UI_USER_RESIZABLE | ||||
# define DISTRHO_UI_USER_RESIZABLE 0 | # define DISTRHO_UI_USER_RESIZABLE 0 | ||||
#endif | #endif | ||||
@@ -59,54 +64,6 @@ START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Plugin Application, will set class name based on plugin details | // Plugin Application, will set class name based on plugin details | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
struct PluginApplication | |||||
{ | |||||
DGL_NAMESPACE::IdleCallback* idleCallback; | |||||
UI* ui; | |||||
explicit PluginApplication(const char*) | |||||
: idleCallback(nullptr), | |||||
ui(nullptr) {} | |||||
void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,); | |||||
idleCallback = cb; | |||||
} | |||||
bool isQuitting() const noexcept | |||||
{ | |||||
return ui->isQuitting(); | |||||
} | |||||
bool isStandalone() const noexcept | |||||
{ | |||||
return DISTRHO_UI_IS_STANDALONE; | |||||
} | |||||
void exec() | |||||
{ | |||||
while (ui->isRunning()) | |||||
{ | |||||
d_msleep(30); | |||||
idleCallback->idleCallback(); | |||||
} | |||||
if (! ui->isQuitting()) | |||||
ui->close(); | |||||
} | |||||
// these are not needed | |||||
void idle() {} | |||||
void quit() {} | |||||
void triggerIdleCallbacks() {} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||||
}; | |||||
#else | |||||
class PluginApplication : public DGL_NAMESPACE::Application | class PluginApplication : public DGL_NAMESPACE::Application | ||||
{ | { | ||||
public: | public: | ||||
@@ -137,49 +94,17 @@ public: | |||||
pData->triggerIdleCallbacks(); | pData->triggerIdleCallbacks(); | ||||
} | } | ||||
void repaintIfNeeeded() | |||||
{ | |||||
pData->repaintIfNeeeded(); | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | ||||
}; | }; | ||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Plugin Window, will pass some Window events to UI | // Plugin Window, will pass some Window events to UI | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
class PluginWindow | |||||
{ | |||||
UI* const ui; | |||||
public: | |||||
explicit PluginWindow(UI* const uiPtr, PluginApplication& app) | |||||
: ui(uiPtr) | |||||
{ | |||||
app.ui = ui; | |||||
} | |||||
// fetch cached data | |||||
uint getWidth() const noexcept { return ui->pData.width; } | |||||
uint getHeight() const noexcept { return ui->pData.height; } | |||||
double getScaleFactor() const noexcept { return ui->pData.scaleFactor; } | |||||
// direct mappings | |||||
void close() { ui->close(); } | |||||
void focus() { ui->focus(); } | |||||
void show() { ui->show(); } | |||||
bool isResizable() const noexcept { return ui->isResizable(); } | |||||
bool isVisible() const noexcept { return ui->isVisible(); } | |||||
void setTitle(const char* const title) { ui->setTitle(title); } | |||||
void setVisible(const bool visible) { ui->setVisible(visible); } | |||||
uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); } | |||||
void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | |||||
{ | |||||
minimumWidth = ui->pData.minWidth; | |||||
minimumHeight = ui->pData.minHeight; | |||||
keepAspectRatio = ui->pData.keepAspectRatio; | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||||
}; | |||||
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
class PluginWindow : public DGL_NAMESPACE::Window | class PluginWindow : public DGL_NAMESPACE::Window | ||||
{ | { | ||||
UI* const ui; | UI* const ui; | ||||
@@ -194,7 +119,10 @@ public: | |||||
const uint height, | const uint height, | ||||
const double scaleFactor) | const double scaleFactor) | ||||
: Window(app, parentWindowHandle, width, height, scaleFactor, | : Window(app, parentWindowHandle, width, height, scaleFactor, | ||||
DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false), | |||||
DISTRHO_UI_USER_RESIZABLE, | |||||
DISTRHO_UI_USES_SCHEDULED_REPAINTS, | |||||
DISTRHO_UI_USES_SIZE_REQUEST, | |||||
false), | |||||
ui(uiPtr), | ui(uiPtr), | ||||
initializing(true), | initializing(true), | ||||
receivedReshapeDuringInit(false) | receivedReshapeDuringInit(false) | ||||
@@ -219,11 +147,15 @@ public: | |||||
if (pData->view == nullptr) | if (pData->view == nullptr) | ||||
return; | return; | ||||
if (receivedReshapeDuringInit) | |||||
ui->uiReshape(getWidth(), getHeight()); | |||||
initializing = false; | initializing = false; | ||||
puglBackendLeave(pData->view); | puglBackendLeave(pData->view); | ||||
if (receivedReshapeDuringInit) | |||||
{ | |||||
puglBackendEnter(pData->view); | |||||
ui->uiReshape(getWidth(), getHeight()); | |||||
puglBackendLeave(pData->view); | |||||
} | |||||
} | } | ||||
// used for temporary windows (VST/CLAP get size without active/visible view) | // used for temporary windows (VST/CLAP get size without active/visible view) | ||||
@@ -239,7 +171,7 @@ public: | |||||
puglBackendEnter(pData->view); | puglBackendEnter(pData->view); | ||||
} | } | ||||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
#if DISTRHO_UI_USES_SIZE_REQUEST | |||||
void setSizeFromHost(const uint width, const uint height) | void setSizeFromHost(const uint width, const uint height) | ||||
{ | { | ||||
puglSetSizeAndDefault(pData->view, width, height); | puglSetSizeAndDefault(pData->view, width, height); | ||||
@@ -295,13 +227,12 @@ protected: | |||||
ui->uiScaleFactorChanged(scaleFactor); | ui->uiScaleFactorChanged(scaleFactor); | ||||
} | } | ||||
# if DISTRHO_UI_FILE_BROWSER | |||||
#if DISTRHO_UI_FILE_BROWSER | |||||
void onFileSelected(const char* filename) override; | void onFileSelected(const char* filename) override; | ||||
# endif | |||||
#endif | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | ||||
}; | }; | ||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// UI callbacks | // UI callbacks | ||||
@@ -320,6 +251,9 @@ struct UI::PrivateData { | |||||
// DGL | // DGL | ||||
PluginApplication app; | PluginApplication app; | ||||
ScopedPointer<PluginWindow> window; | ScopedPointer<PluginWindow> window; | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
WebViewHandle webview; | |||||
#endif | |||||
// DSP | // DSP | ||||
double sampleRate; | double sampleRate; | ||||
@@ -331,7 +265,7 @@ struct UI::PrivateData { | |||||
uint fgColor; | uint fgColor; | ||||
double scaleFactor; | double scaleFactor; | ||||
uintptr_t winId; | uintptr_t winId; | ||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER | |||||
char* uiStateFileKeyRequest; | char* uiStateFileKeyRequest; | ||||
std::map<std::string,std::string> lastUsedDirnames; | std::map<std::string,std::string> lastUsedDirnames; | ||||
#endif | #endif | ||||
@@ -352,6 +286,9 @@ struct UI::PrivateData { | |||||
PrivateData(const char* const appClassName) noexcept | PrivateData(const char* const appClassName) noexcept | ||||
: app(appClassName), | : app(appClassName), | ||||
window(nullptr), | window(nullptr), | ||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
webview(nullptr), | |||||
#endif | |||||
sampleRate(0), | sampleRate(0), | ||||
parameterOffset(0), | parameterOffset(0), | ||||
dspPtr(nullptr), | dspPtr(nullptr), | ||||
@@ -359,7 +296,7 @@ struct UI::PrivateData { | |||||
fgColor(0xffffffff), | fgColor(0xffffffff), | ||||
scaleFactor(1.0), | scaleFactor(1.0), | ||||
winId(0), | winId(0), | ||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER | |||||
uiStateFileKeyRequest(nullptr), | uiStateFileKeyRequest(nullptr), | ||||
#endif | #endif | ||||
bundlePath(nullptr), | bundlePath(nullptr), | ||||
@@ -395,7 +332,7 @@ struct UI::PrivateData { | |||||
~PrivateData() noexcept | ~PrivateData() noexcept | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER | |||||
std::free(uiStateFileKeyRequest); | std::free(uiStateFileKeyRequest); | ||||
#endif | #endif | ||||
std::free(bundlePath); | std::free(bundlePath); | ||||
@@ -415,6 +352,9 @@ struct UI::PrivateData { | |||||
void setStateCallback(const char* const key, const char* const value) | void setStateCallback(const char* const key, const char* const value) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | |||||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); | |||||
if (setStateCallbackFunc != nullptr) | if (setStateCallbackFunc != nullptr) | ||||
setStateCallbackFunc(callbacksPtr, key, value); | setStateCallbackFunc(callbacksPtr, key, value); | ||||
} | } | ||||
@@ -427,19 +367,20 @@ struct UI::PrivateData { | |||||
void setSizeCallback(const uint width, const uint height) | void setSizeCallback(const uint width, const uint height) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(width != 0 && height != 0,); | |||||
if (setSizeCallbackFunc != nullptr) | if (setSizeCallbackFunc != nullptr) | ||||
setSizeCallbackFunc(callbacksPtr, width, height); | setSizeCallbackFunc(callbacksPtr, width, height); | ||||
} | } | ||||
// implemented below, after PluginWindow | // implemented below, after PluginWindow | ||||
bool fileRequestCallback(const char* const key); | |||||
bool fileRequestCallback(const char* key); | |||||
static UI::PrivateData* s_nextPrivateData; | static UI::PrivateData* s_nextPrivateData; | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); | |||||
#else | |||||
static PluginWindow& createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); | |||||
#endif | |||||
static PluginWindow& createNextWindow(UI* ui, uint width, uint height); | |||||
#if DISTRHO_UI_USE_WEB_VIEW | |||||
static void webViewMessageCallback(void* arg, char* msg); | |||||
#endif | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -450,7 +391,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||||
if (fileRequestCallbackFunc != nullptr) | if (fileRequestCallbackFunc != nullptr) | ||||
return fileRequestCallbackFunc(callbacksPtr, key); | return fileRequestCallbackFunc(callbacksPtr, key); | ||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER | |||||
std::free(uiStateFileKeyRequest); | std::free(uiStateFileKeyRequest); | ||||
uiStateFileKeyRequest = strdup(key); | uiStateFileKeyRequest = strdup(key); | ||||
DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); | ||||
@@ -472,7 +413,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// PluginWindow onFileSelected that require UI::PrivateData definitions | // PluginWindow onFileSelected that require UI::PrivateData definitions | ||||
#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_UI_FILE_BROWSER | |||||
inline void PluginWindow::onFileSelected(const char* const filename) | inline void PluginWindow::onFileSelected(const char* const filename) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | ||||
@@ -480,7 +421,7 @@ inline void PluginWindow::onFileSelected(const char* const filename) | |||||
if (initializing) | if (initializing) | ||||
return; | return; | ||||
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
#if DISTRHO_PLUGIN_WANT_STATE | |||||
if (char* const key = ui->uiData->uiStateFileKeyRequest) | if (char* const key = ui->uiData->uiStateFileKeyRequest) | ||||
{ | { | ||||
ui->uiData->uiStateFileKeyRequest = nullptr; | ui->uiData->uiStateFileKeyRequest = nullptr; | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -21,15 +21,6 @@ | |||||
#include "travesty/host.h" | #include "travesty/host.h" | ||||
#include "travesty/view.h" | #include "travesty/view.h" | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# if defined(DISTRHO_OS_MAC) | |||||
# include <CoreFoundation/CoreFoundation.h> | |||||
# elif defined(DISTRHO_OS_WINDOWS) | |||||
# include <winuser.h> | |||||
# define DPF_VST3_WIN32_TIMER_ID 1 | |||||
# endif | |||||
#endif | |||||
/* TODO items: | /* TODO items: | ||||
* - mousewheel event | * - mousewheel event | ||||
* - file request? | * - file request? | ||||
@@ -92,10 +83,10 @@ static void applyGeometryConstraints(const uint minimumWidth, | |||||
{ | { | ||||
// fix width | // fix width | ||||
if (reqRatio > ratio) | if (reqRatio > ratio) | ||||
rect->right = static_cast<int32_t>(rect->bottom * ratio + 0.5); | |||||
rect->right = d_roundToIntPositive(rect->bottom * ratio); | |||||
// fix height | // fix height | ||||
else | else | ||||
rect->bottom = static_cast<int32_t>(static_cast<double>(rect->right) / ratio + 0.5); | |||||
rect->bottom = d_roundToIntPositive(static_cast<double>(rect->right) / ratio); | |||||
} | } | ||||
} | } | ||||
@@ -110,7 +101,6 @@ static void applyGeometryConstraints(const uint minimumWidth, | |||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static uint translateVST3Modifiers(const int64_t modifiers) noexcept | static uint translateVST3Modifiers(const int64_t modifiers) noexcept | ||||
{ | { | ||||
using namespace DGL_NAMESPACE; | using namespace DGL_NAMESPACE; | ||||
@@ -134,115 +124,9 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept | |||||
return dglmods; | return dglmods; | ||||
} | } | ||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !DPF_VST3_USING_HOST_RUN_LOOP | |||||
/** | /** | ||||
* Helper class for getting a native idle timer via native APIs. | |||||
*/ | |||||
class NativeIdleHelper | |||||
{ | |||||
public: | |||||
NativeIdleHelper(IdleCallback* const callback) | |||||
: fCallback(callback), | |||||
#ifdef DISTRHO_OS_MAC | |||||
fTimerRef(nullptr) | |||||
#else | |||||
fTimerWindow(nullptr), | |||||
fTimerWindowClassName() | |||||
#endif | |||||
{ | |||||
} | |||||
void registerNativeIdleCallback() | |||||
{ | |||||
#ifdef DISTRHO_OS_MAC | |||||
constexpr const CFTimeInterval interval = DPF_VST3_TIMER_INTERVAL * 0.0001; | |||||
CFRunLoopTimerContext context = {}; | |||||
context.info = this; | |||||
fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0, | |||||
platformIdleTimerCallback, &context); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,); | |||||
CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | |||||
#else | |||||
/* | |||||
* Create an invisible window to handle a timer. | |||||
* There is no need for implementing a window proc because DefWindowProc already calls the | |||||
* callback function when processing WM_TIMER messages. | |||||
*/ | |||||
fTimerWindowClassName = ( | |||||
#ifdef DISTRHO_PLUGIN_BRAND | |||||
DISTRHO_PLUGIN_BRAND | |||||
#else | |||||
DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) | |||||
#endif | |||||
"-" DISTRHO_PLUGIN_NAME "-" | |||||
); | |||||
char suffix[9]; | |||||
std::snprintf(suffix, sizeof(suffix), "%08x", std::rand()); | |||||
suffix[sizeof(suffix)-1] = '\0'; | |||||
fTimerWindowClassName += suffix; | |||||
WNDCLASSEX cls; | |||||
ZeroMemory(&cls, sizeof(cls)); | |||||
cls.cbSize = sizeof(WNDCLASSEX); | |||||
cls.cbWndExtra = sizeof(LONG_PTR); | |||||
cls.lpszClassName = fTimerWindowClassName.buffer(); | |||||
cls.lpfnWndProc = DefWindowProc; | |||||
RegisterClassEx(&cls); | |||||
fTimerWindow = CreateWindowEx(0, cls.lpszClassName, "DPF Timer Helper", | |||||
0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,); | |||||
SetWindowLongPtr(fTimerWindow, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(static_cast<void*>(this))); | |||||
SetTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID, DPF_VST3_TIMER_INTERVAL, | |||||
static_cast<TIMERPROC>(platformIdleTimerCallback)); | |||||
#endif | |||||
} | |||||
void unregisterNativeIdleCallback() | |||||
{ | |||||
#ifdef DISTRHO_OS_MAC | |||||
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | |||||
CFRelease(fTimerRef); | |||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,); | |||||
KillTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID); | |||||
DestroyWindow(fTimerWindow); | |||||
UnregisterClass(fTimerWindowClassName, nullptr); | |||||
#endif | |||||
} | |||||
private: | |||||
IdleCallback* const fCallback; | |||||
#ifdef DISTRHO_OS_MAC | |||||
CFRunLoopTimerRef fTimerRef; | |||||
static void platformIdleTimerCallback(CFRunLoopTimerRef, void* const info) | |||||
{ | |||||
static_cast<NativeIdleHelper*>(info)->fCallback->idleCallback(); | |||||
} | |||||
#else | |||||
HWND fTimerWindow; | |||||
String fTimerWindowClassName; | |||||
static void WINAPI platformIdleTimerCallback(const HWND hwnd, UINT, UINT_PTR, DWORD) | |||||
{ | |||||
reinterpret_cast<NativeIdleHelper*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))->fCallback->idleCallback(); | |||||
} | |||||
#endif | |||||
}; | |||||
#endif | |||||
/** | |||||
* Helper class for getting a native idle timer, either through pugl or via native APIs. | |||||
* Helper class for getting a native idle timer. | |||||
*/ | */ | ||||
#if !DPF_VST3_USING_HOST_RUN_LOOP | #if !DPF_VST3_USING_HOST_RUN_LOOP | ||||
class NativeIdleCallback : public IdleCallback | class NativeIdleCallback : public IdleCallback | ||||
@@ -250,49 +134,25 @@ class NativeIdleCallback : public IdleCallback | |||||
public: | public: | ||||
NativeIdleCallback(UIExporter& ui) | NativeIdleCallback(UIExporter& ui) | ||||
: fCallbackRegistered(false), | : fCallbackRegistered(false), | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
fIdleHelper(this) | |||||
#else | |||||
fUI(ui) | |||||
#endif | |||||
{ | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// unused | |||||
(void)ui; | |||||
#endif | |||||
} | |||||
fUI(ui) {} | |||||
void registerNativeIdleCallback() | void registerNativeIdleCallback() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(!fCallbackRegistered,); | DISTRHO_SAFE_ASSERT_RETURN(!fCallbackRegistered,); | ||||
fCallbackRegistered = true; | fCallbackRegistered = true; | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
fIdleHelper.registerNativeIdleCallback(); | |||||
#else | |||||
fUI.addIdleCallbackForNativeIdle(this, DPF_VST3_TIMER_INTERVAL); | fUI.addIdleCallbackForNativeIdle(this, DPF_VST3_TIMER_INTERVAL); | ||||
#endif | |||||
} | } | ||||
void unregisterNativeIdleCallback() | void unregisterNativeIdleCallback() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fCallbackRegistered,); | DISTRHO_SAFE_ASSERT_RETURN(fCallbackRegistered,); | ||||
fCallbackRegistered = false; | fCallbackRegistered = false; | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
fIdleHelper.unregisterNativeIdleCallback(); | |||||
#else | |||||
fUI.removeIdleCallbackForNativeIdle(this); | fUI.removeIdleCallbackForNativeIdle(this); | ||||
#endif | |||||
} | } | ||||
private: | private: | ||||
bool fCallbackRegistered; | bool fCallbackRegistered; | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
NativeIdleHelper fIdleHelper; | |||||
#else | |||||
UIExporter& fUI; | UIExporter& fUI; | ||||
#endif | |||||
}; | }; | ||||
#endif | #endif | ||||
@@ -392,7 +252,6 @@ public: | |||||
// ---------------------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------------------- | ||||
// v3_plugin_view interface calls | // v3_plugin_view interface calls | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
v3_result onWheel(float /*distance*/) | v3_result onWheel(float /*distance*/) | ||||
{ | { | ||||
// TODO | // TODO | ||||
@@ -432,7 +291,6 @@ public: | |||||
fUI.notifyFocusChanged(state); | fUI.notifyFocusChanged(state); | ||||
return V3_OK; | return V3_OK; | ||||
} | } | ||||
#endif | |||||
v3_result getSize(v3_view_rect* const rect) const noexcept | v3_result getSize(v3_view_rect* const rect) const noexcept | ||||
{ | { | ||||
@@ -889,6 +747,7 @@ private: | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fView != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(width != 0 && height != 0,); | |||||
#ifdef DISTRHO_OS_MAC | #ifdef DISTRHO_OS_MAC | ||||
const double scaleFactor = fUI.getScaleFactor(); | const double scaleFactor = fUI.getScaleFactor(); | ||||
@@ -1463,7 +1322,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
static v3_result V3_API on_wheel(void* const self, const float distance) | static v3_result V3_API on_wheel(void* const self, const float distance) | ||||
{ | { | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
d_debug("dpf_plugin_view::on_wheel => %p %f", self, distance); | d_debug("dpf_plugin_view::on_wheel => %p %f", self, distance); | ||||
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | ||||
@@ -1471,16 +1329,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | ||||
return uivst3->onWheel(distance); | return uivst3->onWheel(distance); | ||||
#else | |||||
return V3_NOT_IMPLEMENTED; | |||||
// unused | |||||
(void)self; (void)distance; | |||||
#endif | |||||
} | } | ||||
static v3_result V3_API on_key_down(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers) | static v3_result V3_API on_key_down(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers) | ||||
{ | { | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
d_debug("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); | d_debug("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); | ||||
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | ||||
@@ -1488,16 +1340,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | ||||
return uivst3->onKeyDown(key_char, key_code, modifiers); | return uivst3->onKeyDown(key_char, key_code, modifiers); | ||||
#else | |||||
return V3_NOT_IMPLEMENTED; | |||||
// unused | |||||
(void)self; (void)key_char; (void)key_code; (void)modifiers; | |||||
#endif | |||||
} | } | ||||
static v3_result V3_API on_key_up(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers) | static v3_result V3_API on_key_up(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers) | ||||
{ | { | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
d_debug("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); | d_debug("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); | ||||
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | ||||
@@ -1505,11 +1351,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | ||||
return uivst3->onKeyUp(key_char, key_code, modifiers); | return uivst3->onKeyUp(key_char, key_code, modifiers); | ||||
#else | |||||
return V3_NOT_IMPLEMENTED; | |||||
// unused | |||||
(void)self; (void)key_char; (void)key_code; (void)modifiers; | |||||
#endif | |||||
} | } | ||||
static v3_result V3_API get_size(void* const self, v3_view_rect* const rect) | static v3_result V3_API get_size(void* const self, v3_view_rect* const rect) | ||||
@@ -1526,10 +1367,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
double scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0; | double scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0; | ||||
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | #if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | ||||
rect->right = DISTRHO_UI_DEFAULT_WIDTH; | |||||
rect->bottom = DISTRHO_UI_DEFAULT_HEIGHT; | |||||
if (d_isZero(scaleFactor)) | if (d_isZero(scaleFactor)) | ||||
scaleFactor = 1.0; | scaleFactor = 1.0; | ||||
rect->right = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor; | |||||
rect->bottom = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor; | |||||
#else | #else | ||||
UIExporter tmpUI(nullptr, 0, view->sampleRate, | UIExporter tmpUI(nullptr, 0, view->sampleRate, | ||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | ||||
@@ -1539,6 +1380,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
scaleFactor = tmpUI.getScaleFactor(); | scaleFactor = tmpUI.getScaleFactor(); | ||||
tmpUI.quit(); | tmpUI.quit(); | ||||
#endif | #endif | ||||
rect->left = rect->top = 0; | rect->left = rect->top = 0; | ||||
#ifdef DISTRHO_OS_MAC | #ifdef DISTRHO_OS_MAC | ||||
rect->right /= scaleFactor; | rect->right /= scaleFactor; | ||||
@@ -1567,7 +1409,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
static v3_result V3_API on_focus(void* const self, const v3_bool state) | static v3_result V3_API on_focus(void* const self, const v3_bool state) | ||||
{ | { | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
d_debug("dpf_plugin_view::on_focus => %p %u", self, state); | d_debug("dpf_plugin_view::on_focus => %p %u", self, state); | ||||
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self); | ||||
@@ -1575,11 +1416,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); | ||||
return uivst3->onFocus(state); | return uivst3->onFocus(state); | ||||
#else | |||||
return V3_NOT_IMPLEMENTED; | |||||
// unused | |||||
(void)self; (void)state; | |||||
#endif | |||||
} | } | ||||
static v3_result V3_API set_frame(void* const self, v3_plugin_frame** const frame) | static v3_result V3_API set_frame(void* const self, v3_plugin_frame** const frame) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2024 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 | ||||
@@ -19,6 +19,7 @@ | |||||
#endif | #endif | ||||
#include "../extra/String.hpp" | #include "../extra/String.hpp" | ||||
#include "../DistrhoPluginUtils.hpp" | |||||
#include "../DistrhoStandaloneUtils.hpp" | #include "../DistrhoStandaloneUtils.hpp" | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
@@ -49,7 +50,7 @@ BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID) | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
const char* getBinaryFilename() | const char* getBinaryFilename() | ||||
{ | { | ||||
@@ -77,7 +78,9 @@ const char* getBinaryFilename() | |||||
const char* getPluginFormatName() noexcept | const char* getPluginFormatName() noexcept | ||||
{ | { | ||||
#if defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) | |||||
return "AudioUnit"; | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
return "Carla"; | return "Carla"; | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_JACK) | #elif defined(DISTRHO_PLUGIN_TARGET_JACK) | ||||
#if defined(DISTRHO_OS_WASM) | #if defined(DISTRHO_OS_WASM) | ||||
@@ -110,7 +113,7 @@ const char* getResourcePath(const char* const bundlePath) noexcept | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(bundlePath != nullptr, nullptr); | DISTRHO_SAFE_ASSERT_RETURN(bundlePath != nullptr, nullptr); | ||||
#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
#if defined(DISTRHO_PLUGIN_TARGET_AU) || defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||||
static String resourcePath; | static String resourcePath; | ||||
if (resourcePath.isEmpty()) | if (resourcePath.isEmpty()) | ||||
@@ -163,6 +166,11 @@ 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 |
@@ -475,12 +475,12 @@ struct JackBridge { | |||||
if (lib == nullptr) | if (lib == nullptr) | ||||
{ | { | ||||
fprintf(stderr, "Failed to load JACK DLL, reason:\n%s\n", lib_error(filename)); | |||||
d_stderr("Failed to load JACK DLL, reason:\n%s", lib_error(filename)); | |||||
return; | return; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
fprintf(stdout, "%s loaded successfully!\n", filename); | |||||
d_stdout("%s loaded successfully!", filename); | |||||
} | } | ||||
#define JOIN(a, b) a ## b | #define JOIN(a, b) a ## b | ||||
@@ -49,10 +49,10 @@ struct NativeBridge { | |||||
uint numMidiOuts; | uint numMidiOuts; | ||||
// JACK callbacks | // JACK callbacks | ||||
JackProcessCallback jackProcessCallback = nullptr; | |||||
JackBufferSizeCallback bufferSizeCallback = nullptr; | |||||
void* jackProcessArg = nullptr; | |||||
void* jackBufferSizeArg = nullptr; | |||||
JackProcessCallback jackProcessCallback; | |||||
JackBufferSizeCallback bufferSizeCallback; | |||||
void* jackProcessArg; | |||||
void* jackBufferSizeArg; | |||||
// Runtime buffers | // Runtime buffers | ||||
enum PortMask { | enum PortMask { | ||||
@@ -0,0 +1,7 @@ | |||||
#!/bin/bash | |||||
rm -f "~/Library/Application Support/AU Lab/com.apple.audio.aulab_componentcache.plist" | |||||
rm -rf "~/Library/Caches/AudioUnitCache" | |||||
killall -9 AudioComponentRegistrar | |||||
sudo killall -9 AudioComponentRegistrar | |||||
exit 0 |
@@ -1,6 +1,6 @@ | |||||
#!/bin/bash | #!/bin/bash | ||||
# function not available on some systems | |||||
# the realpath function is not available on some systems | |||||
if ! which realpath &>/dev/null; then | if ! which realpath &>/dev/null; then | ||||
function realpath() { | function realpath() { | ||||
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" | [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" | ||||
@@ -9,7 +9,13 @@ fi | |||||
set -e | set -e | ||||
if [ ! -d bin ]; then | |||||
BIN_DIR=${1} | |||||
if [ -z "${BIN_DIR}" ]; then | |||||
BIN_DIR=bin | |||||
fi | |||||
if [ ! -d ${BIN_DIR} ]; then | |||||
echo "Please run this script from the source root folder" | echo "Please run this script from the source root folder" | ||||
exit | exit | ||||
fi | fi | ||||
@@ -17,7 +23,7 @@ fi | |||||
PWD="$(dirname "${0}")" | PWD="$(dirname "${0}")" | ||||
if [ -f "${PWD}/lv2_ttl_generator.exe" ]; then | if [ -f "${PWD}/lv2_ttl_generator.exe" ]; then | ||||
GEN="${PWD}/lv2_ttl_generator.exe" | |||||
GEN="$(realpath ${PWD}/lv2_ttl_generator.exe)" | |||||
EXT=dll | EXT=dll | ||||
else | else | ||||
GEN="$(realpath ${PWD}/lv2_ttl_generator)" | GEN="$(realpath ${PWD}/lv2_ttl_generator)" | ||||
@@ -28,7 +34,7 @@ else | |||||
fi | fi | ||||
fi | fi | ||||
cd bin | |||||
cd ${BIN_DIR} | |||||
FOLDERS=`find . -type d -name \*.lv2` | FOLDERS=`find . -type d -name \*.lv2` | ||||
for i in ${FOLDERS}; do | for i in ${FOLDERS}; do | ||||
@@ -1,32 +1,63 @@ | |||||
#!/bin/bash | #!/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 | set -e | ||||
DPF_UTILS_DIR="$(dirname $(realpath ${0}))" | |||||
if [ -d bin ]; then | if [ -d bin ]; then | ||||
cd bin | cd bin | ||||
elif [ -d build/bin ]; then | |||||
cd build/bin | |||||
else | else | ||||
echo "Please run this script from the root folder" | echo "Please run this script from the root folder" | ||||
exit | exit | ||||
fi | fi | ||||
NAME="$(basename $(git rev-parse --show-toplevel))" | |||||
SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')" | |||||
# can be overridden by environment variables | |||||
MACOS_PKG_LICENSE_FILE=${MACOS_PKG_LICENSE_FILE:=""} | |||||
MACOS_PKG_NAME=${MACOS_PKG_NAME:="$(basename $(git rev-parse --show-toplevel))"} | |||||
MACOS_PKG_SNAME=${MACOS_PKG_SNAME:="$(echo ${MACOS_PKG_NAME} | tr -d ' ' | tr '/' '-')"} | |||||
MACOS_PKG_SYMBOL=${MACOS_PKG_SYMBOL:="studio.kx.distrho.plugins.${MACOS_PKG_SNAME}"} | |||||
MACOS_PKG_WELCOME_TXT=${MACOS_PKG_WELCOME_TXT:=${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in} | |||||
# backwards compat | |||||
if [ -n "${WELCOME_TXT}" ]; then | |||||
MACOS_PKG_WELCOME_TXT="${WELCOME_TXT}" | |||||
fi | |||||
SKIP_START="<!--" | SKIP_START="<!--" | ||||
SKIP_END="-->" | SKIP_END="-->" | ||||
if [ -n "${MACOS_INSTALLER_DEV_ID}" ]; then | |||||
PKG_SIGN_ARGS=(--sign "${MACOS_INSTALLER_DEV_ID}") | |||||
fi | |||||
rm -rf pkg | rm -rf pkg | ||||
mkdir pkg | mkdir pkg | ||||
if [ -z "${MACOS_PKG_LICENSE_FILE}" ]; then | |||||
SKIP_LICENSE_START="${SKIP_START}" | |||||
SKIP_LICENSE_END="${SKIP_END}" | |||||
fi | |||||
ENABLE_AU=$(find . -maxdepth 1 -name '*.component' -print -quit | grep -q '.component' && echo 1 || echo) | ENABLE_AU=$(find . -maxdepth 1 -name '*.component' -print -quit | grep -q '.component' && echo 1 || echo) | ||||
if [ -n "${ENABLE_AU}" ]; then | if [ -n "${ENABLE_AU}" ]; then | ||||
mkdir pkg/au | mkdir pkg/au | ||||
cp -RL *.component pkg/au/ | cp -RL *.component pkg/au/ | ||||
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/au/*.component | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.components" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}-components" \ | |||||
--install-location "/Library/Audio/Plug-Ins/Components/" \ | --install-location "/Library/Audio/Plug-Ins/Components/" \ | ||||
--root "${PWD}/pkg/au/" \ | --root "${PWD}/pkg/au/" \ | ||||
../dpf-${SNAME}-components.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
../dpf-${MACOS_PKG_SNAME}-components.pkg | |||||
else | else | ||||
SKIP_AU_START="${SKIP_START}" | SKIP_AU_START="${SKIP_START}" | ||||
SKIP_AU_END="${SKIP_END}" | SKIP_AU_END="${SKIP_END}" | ||||
@@ -36,11 +67,13 @@ ENABLE_CLAP=$(find . -maxdepth 1 -name '*.clap' -print -quit | grep -q '.clap' & | |||||
if [ -n "${ENABLE_CLAP}" ]; then | if [ -n "${ENABLE_CLAP}" ]; then | ||||
mkdir pkg/clap | mkdir pkg/clap | ||||
cp -RL *.clap pkg/clap/ | cp -RL *.clap pkg/clap/ | ||||
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/clap/*.clap | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.clapbundles" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}-clapbundles" \ | |||||
--install-location "/Library/Audio/Plug-Ins/CLAP/" \ | --install-location "/Library/Audio/Plug-Ins/CLAP/" \ | ||||
--root "${PWD}/pkg/clap/" \ | --root "${PWD}/pkg/clap/" \ | ||||
../dpf-${SNAME}-clapbundles.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
../dpf-${MACOS_PKG_SNAME}-clapbundles.pkg | |||||
else | else | ||||
SKIP_CLAP_START="${SKIP_START}" | SKIP_CLAP_START="${SKIP_START}" | ||||
SKIP_CLAP_END="${SKIP_END}" | SKIP_CLAP_END="${SKIP_END}" | ||||
@@ -50,11 +83,13 @@ ENABLE_LV2=$(find . -maxdepth 1 -name '*.lv2' -print -quit | grep -q '.lv2' && e | |||||
if [ -n "${ENABLE_LV2}" ]; then | if [ -n "${ENABLE_LV2}" ]; then | ||||
mkdir pkg/lv2 | mkdir pkg/lv2 | ||||
cp -RL *.lv2 pkg/lv2/ | cp -RL *.lv2 pkg/lv2/ | ||||
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --force --verbose --option=runtime pkg/lv2/*.lv2/*.dylib | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}-lv2bundles" \ | |||||
--install-location "/Library/Audio/Plug-Ins/LV2/" \ | --install-location "/Library/Audio/Plug-Ins/LV2/" \ | ||||
--root "${PWD}/pkg/lv2/" \ | --root "${PWD}/pkg/lv2/" \ | ||||
../dpf-${SNAME}-lv2bundles.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
../dpf-${MACOS_PKG_SNAME}-lv2bundles.pkg | |||||
else | else | ||||
SKIP_LV2_START="${SKIP_START}" | SKIP_LV2_START="${SKIP_START}" | ||||
SKIP_LV2_END="${SKIP_END}" | SKIP_LV2_END="${SKIP_END}" | ||||
@@ -64,11 +99,13 @@ ENABLE_VST2=$(find . -maxdepth 1 -name '*.vst' -print -quit | grep -q '.vst' && | |||||
if [ -n "${ENABLE_VST2}" ]; then | if [ -n "${ENABLE_VST2}" ]; then | ||||
mkdir pkg/vst2 | mkdir pkg/vst2 | ||||
cp -RL *.vst pkg/vst2/ | cp -RL *.vst pkg/vst2/ | ||||
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/vst2/*.vst | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.vst2bundles" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}-vst2bundles" \ | |||||
--install-location "/Library/Audio/Plug-Ins/VST/" \ | --install-location "/Library/Audio/Plug-Ins/VST/" \ | ||||
--root "${PWD}/pkg/vst2/" \ | --root "${PWD}/pkg/vst2/" \ | ||||
../dpf-${SNAME}-vst2bundles.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
../dpf-${MACOS_PKG_SNAME}-vst2bundles.pkg | |||||
else | else | ||||
SKIP_VST2_START="${SKIP_START}" | SKIP_VST2_START="${SKIP_START}" | ||||
SKIP_VST2_END="${SKIP_END}" | SKIP_VST2_END="${SKIP_END}" | ||||
@@ -78,11 +115,13 @@ ENABLE_VST3=$(find . -maxdepth 1 -name '*.vst3' -print -quit | grep -q '.vst3' & | |||||
if [ -n "${ENABLE_VST3}" ]; then | if [ -n "${ENABLE_VST3}" ]; then | ||||
mkdir pkg/vst3 | mkdir pkg/vst3 | ||||
cp -RL *.vst3 pkg/vst3/ | cp -RL *.vst3 pkg/vst3/ | ||||
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/vst3/*.vst3 | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.vst3bundles" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}-vst3bundles" \ | |||||
--install-location "/Library/Audio/Plug-Ins/VST3/" \ | --install-location "/Library/Audio/Plug-Ins/VST3/" \ | ||||
--root "${PWD}/pkg/vst3/" \ | --root "${PWD}/pkg/vst3/" \ | ||||
../dpf-${SNAME}-vst3bundles.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
../dpf-${MACOS_PKG_SNAME}-vst3bundles.pkg | |||||
else | else | ||||
SKIP_VST3_START="${SKIP_START}" | SKIP_VST3_START="${SKIP_START}" | ||||
SKIP_VST3_END="${SKIP_END}" | SKIP_VST3_END="${SKIP_END}" | ||||
@@ -90,36 +129,34 @@ fi | |||||
cd .. | cd .. | ||||
DPF_UTILS_DIR=$(dirname ${0}) | |||||
# can be overridden by environment variables | |||||
WELCOME_TXT=${WELCOME_TXT:=${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in} | |||||
mkdir -p build | mkdir -p build | ||||
sed -e "s|@name@|${NAME}|" "${WELCOME_TXT}" > build/welcome.txt | |||||
sed -e "s|@name@|${MACOS_PKG_NAME}|" "${MACOS_PKG_WELCOME_TXT}" > build/welcome.txt | |||||
sed -e "s|@builddir@|${PWD}/build|" \ | sed -e "s|@builddir@|${PWD}/build|" \ | ||||
-e "s|@skip_license_start@|${SKIP_LICENSE_START}|" \ | |||||
-e "s|@skip_au_start@|${SKIP_AU_START}|" \ | -e "s|@skip_au_start@|${SKIP_AU_START}|" \ | ||||
-e "s|@skip_clap_start@|${SKIP_CLAP_START}|" \ | -e "s|@skip_clap_start@|${SKIP_CLAP_START}|" \ | ||||
-e "s|@skip_lv2_start@|${SKIP_LV2_START}|" \ | -e "s|@skip_lv2_start@|${SKIP_LV2_START}|" \ | ||||
-e "s|@skip_vst2_start@|${SKIP_VST2_START}|" \ | -e "s|@skip_vst2_start@|${SKIP_VST2_START}|" \ | ||||
-e "s|@skip_vst3_start@|${SKIP_VST3_START}|" \ | -e "s|@skip_vst3_start@|${SKIP_VST3_START}|" \ | ||||
-e "s|@skip_license_end@|${SKIP_LICENSE_END}|" \ | |||||
-e "s|@skip_au_end@|${SKIP_AU_END}|" \ | -e "s|@skip_au_end@|${SKIP_AU_END}|" \ | ||||
-e "s|@skip_clap_end@|${SKIP_CLAP_END}|" \ | -e "s|@skip_clap_end@|${SKIP_CLAP_END}|" \ | ||||
-e "s|@skip_lv2_end@|${SKIP_LV2_END}|" \ | -e "s|@skip_lv2_end@|${SKIP_LV2_END}|" \ | ||||
-e "s|@skip_vst2_end@|${SKIP_VST2_END}|" \ | -e "s|@skip_vst2_end@|${SKIP_VST2_END}|" \ | ||||
-e "s|@skip_vst3_end@|${SKIP_VST3_END}|" \ | -e "s|@skip_vst3_end@|${SKIP_VST3_END}|" \ | ||||
-e "s|@aubundleref@|dpf-${SNAME}-components.pkg|" \ | |||||
-e "s|@clapbundleref@|dpf-${SNAME}-clapbundles.pkg|" \ | |||||
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ | |||||
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ | |||||
-e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \ | |||||
-e "s|@name@|${NAME}|g" \ | |||||
-e "s|@sname@|${SNAME}|g" \ | |||||
-e "s|@license_file@|${MACOS_PKG_LICENSE_FILE}|" \ | |||||
-e "s|@name@|${MACOS_PKG_NAME}|g" \ | |||||
-e "s|@sname@|${MACOS_PKG_SNAME}|g" \ | |||||
-e "s|@symbol@|${MACOS_PKG_SYMBOL}|g" \ | |||||
${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml | ${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml | ||||
productbuild \ | productbuild \ | ||||
--distribution build/package.xml \ | --distribution build/package.xml \ | ||||
--identifier "studio.kx.distrho.${SNAME}" \ | |||||
--identifier "${MACOS_PKG_SYMBOL}" \ | |||||
--package-path "${PWD}" \ | --package-path "${PWD}" \ | ||||
--version 0 \ | --version 0 \ | ||||
${SNAME}-macOS.pkg | |||||
"${PKG_SIGN_ARGS[@]}" \ | |||||
${MACOS_PKG_SNAME}-macOS.pkg | |||||
# xcrun notarytool submit build/*-macOS.pkg --keychain-profile "build-notary" --wait | |||||
# xcrun notarytool log --keychain-profile "build-notary" 00000000-0000-0000-0000-000000000000 |
@@ -2,39 +2,40 @@ | |||||
<installer-gui-script minSpecVersion="1"> | <installer-gui-script minSpecVersion="1"> | ||||
<title>@name@</title> | <title>@name@</title> | ||||
<domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true" /> | <domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true" /> | ||||
@skip_license_start@<license file="@license_file@" mime-type="text/plain" />@skip_license_end@ | |||||
<options customize="always" hostArchitectures="arm64,x86_64" require-scripts="false" rootVolumeOnly="true" /> | <options customize="always" hostArchitectures="arm64,x86_64" require-scripts="false" rootVolumeOnly="true" /> | ||||
<pkg-ref id="studio.kx.distrho.@sname@" /> | |||||
<pkg-ref id="@symbol@" /> | |||||
<welcome file="@builddir@/welcome.txt" mime-type="text/plain" /> | <welcome file="@builddir@/welcome.txt" mime-type="text/plain" /> | ||||
@skip_au_start@ | @skip_au_start@ | ||||
<choice id="studio.kx.distrho.@sname@-au" title="AU" description="Install AU plugins" visible="true"> | |||||
<pkg-ref id="studio.kx.distrho.@sname@-components" version="0">@aubundleref@</pkg-ref> | |||||
<choice id="@symbol@-au" title="AU" description="Install AU plugins" visible="true"> | |||||
<pkg-ref id="@symbol@-components" version="0">dpf-@sname@-components.pkg</pkg-ref> | |||||
</choice> | </choice> | ||||
@skip_au_end@ | @skip_au_end@ | ||||
@skip_clap_start@ | @skip_clap_start@ | ||||
<choice id="studio.kx.distrho.@sname@-clap" title="CLAP" description="Install CLAP plugins" visible="true"> | |||||
<pkg-ref id="studio.kx.distrho.@sname@-clapbundles" version="0">@clapbundleref@</pkg-ref> | |||||
<choice id="@symbol@-clap" title="CLAP" description="Install CLAP plugins" visible="true"> | |||||
<pkg-ref id="@symbol@-clapbundles" version="0">dpf-@sname@-clapbundles.pkg</pkg-ref> | |||||
</choice> | </choice> | ||||
@skip_clap_end@ | @skip_clap_end@ | ||||
@skip_lv2_start@ | @skip_lv2_start@ | ||||
<choice id="studio.kx.distrho.@sname@-lv2" title="LV2" description="Install LV2 plugins" visible="true"> | |||||
<pkg-ref id="studio.kx.distrho.@sname@-lv2bundles" version="0">@lv2bundleref@</pkg-ref> | |||||
<choice id="@symbol@-lv2" title="LV2" description="Install LV2 plugins" visible="true"> | |||||
<pkg-ref id="@symbol@-lv2bundles" version="0">dpf-@sname@-lv2bundles.pkg</pkg-ref> | |||||
</choice> | </choice> | ||||
@skip_lv2_end@ | @skip_lv2_end@ | ||||
@skip_vst2_start@ | @skip_vst2_start@ | ||||
<choice id="studio.kx.distrho.@sname@-vst2" title="VST2" description="Install VST2 plugins" visible="true"> | |||||
<pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref> | |||||
<choice id="@symbol@-vst2" title="VST2" description="Install VST2 plugins" visible="true"> | |||||
<pkg-ref id="@symbol@-vst2bundles" version="0">dpf-@sname@-vst2bundles.pkg</pkg-ref> | |||||
</choice> | </choice> | ||||
@skip_vst2_end@ | @skip_vst2_end@ | ||||
@skip_vst3_start@ | @skip_vst3_start@ | ||||
<choice id="studio.kx.distrho.@sname@-vst3" title="VST3" description="Install VST3 plugins" visible="true"> | |||||
<pkg-ref id="studio.kx.distrho.@sname@-vst3bundles" version="0">@vst3bundleref@</pkg-ref> | |||||
<choice id="@symbol@-vst3" title="VST3" description="Install VST3 plugins" visible="true"> | |||||
<pkg-ref id="@symbol@-vst3bundles" version="0">dpf-@sname@-vst3bundles.pkg</pkg-ref> | |||||
</choice> | </choice> | ||||
@skip_vst3_end@ | @skip_vst3_end@ | ||||
<choices-outline> | <choices-outline> | ||||
@skip_au_start@<line choice="studio.kx.distrho.@sname@-au"/>@skip_au_end@ | |||||
@skip_clap_start@<line choice="studio.kx.distrho.@sname@-clap"/>@skip_clap_end@ | |||||
@skip_lv2_start@<line choice="studio.kx.distrho.@sname@-lv2"/>@skip_lv2_end@ | |||||
@skip_vst2_start@<line choice="studio.kx.distrho.@sname@-vst2"/>@skip_vst2_end@ | |||||
@skip_vst3_start@<line choice="studio.kx.distrho.@sname@-vst3"/>@skip_vst3_end@ | |||||
@skip_au_start@<line choice="@symbol@-au"/>@skip_au_end@ | |||||
@skip_clap_start@<line choice="@symbol@-clap"/>@skip_clap_end@ | |||||
@skip_lv2_start@<line choice="@symbol@-lv2"/>@skip_lv2_end@ | |||||
@skip_vst2_start@<line choice="@symbol@-vst2"/>@skip_vst2_end@ | |||||
@skip_vst3_start@<line choice="@symbol@-vst3"/>@skip_vst3_end@ | |||||
</choices-outline> | </choices-outline> | ||||
</installer-gui-script> | </installer-gui-script> |
@@ -0,0 +1 @@ | |||||
_PluginAUFactory |
@@ -74,11 +74,6 @@ protected: | |||||
return d_version(1, 0, 0); | return d_version(1, 0, 0); | ||||
} | } | ||||
int64_t getUniqueId() const noexcept override | |||||
{ | |||||
return d_cconst('D', '3', 'E', 'Q'); | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Init | // Init | ||||