diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index ef9de80c..6adfba8c 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -30,6 +30,7 @@ jobs:
liblo-dev \
libgl-dev \
libcairo2-dev \
+ libdbus-1-dev \
libx11-dev
- name: Create Build Environment
shell: bash
@@ -55,7 +56,7 @@ jobs:
path: ${{runner.workspace}}/build/bin/
cmake_macos:
- runs-on: macos-10.15
+ runs-on: macos-11
steps:
- uses: actions/checkout@v2
with:
diff --git a/.github/workflows/example-plugins.yml b/.github/workflows/example-plugins.yml
index 818dd474..ee00f28a 100644
--- a/.github/workflows/example-plugins.yml
+++ b/.github/workflows/example-plugins.yml
@@ -26,7 +26,7 @@ jobs:
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports bionic-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-arm64.list
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports bionic-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-arm64.list
sudo apt-get update -qq
- sudo apt-get install -yq g++-aarch64-linux-gnu libasound2-dev:arm64 libcairo2-dev:arm64 libgl1-mesa-dev:arm64 liblo-dev:arm64 libpulse-dev:arm64 libx11-dev:arm64 libxcursor-dev:arm64 libxext-dev:arm64 libxrandr-dev:arm64 qemu-user-static
+ sudo apt-get install -yq g++-aarch64-linux-gnu libasound2-dev:arm64 libcairo2-dev:arm64 libdbus-1-dev:arm64 libgl1-mesa-dev:arm64 liblo-dev:arm64 libpulse-dev:arm64 libx11-dev:arm64 libxcursor-dev:arm64 libxext-dev:arm64 libxrandr-dev:arm64 qemu-user-static
# fix broken Ubuntu packages missing pkg-config file in multi-arch package
sudo apt-get install -yq libasound2-dev libgl1-mesa-dev liblo-dev libpulse-dev libxcursor-dev libxrandr-dev
sudo ln -s /usr/lib/aarch64-linux-gnu/liblo.so.7 /usr/lib/aarch64-linux-gnu/liblo.so
@@ -63,7 +63,7 @@ jobs:
echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports bionic-updates main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-armhf.list
echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports bionic-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ports-armhf.list
sudo apt-get update -qq
- sudo apt-get install -yq g++-arm-linux-gnueabihf libasound2-dev:armhf libcairo2-dev:armhf libgl1-mesa-dev:armhf liblo-dev:armhf libpulse-dev:armhf libx11-dev:armhf libxcursor-dev:armhf libxext-dev:armhf libxrandr-dev:armhf qemu-user-static
+ sudo apt-get install -yq g++-arm-linux-gnueabihf libasound2-dev:armhf libcairo2-dev:armhf libdbus-1-dev:armhf libgl1-mesa-dev:armhf liblo-dev:armhf libpulse-dev:armhf libx11-dev:armhf libxcursor-dev:armhf libxext-dev:armhf libxrandr-dev:armhf qemu-user-static
# fix broken Ubuntu packages missing pkg-config file in multi-arch package
sudo apt-get install -yq libasound2-dev libgl1-mesa-dev liblo-dev libpulse-dev libxcursor-dev libxrandr-dev
sudo ln -s /usr/lib/arm-linux-gnueabihf/liblo.so.7 /usr/lib/arm-linux-gnueabihf/liblo.so
@@ -96,7 +96,7 @@ jobs:
run: |
sudo dpkg --add-architecture i386
sudo apt-get update -qq
- sudo apt-get install -yq g++-multilib libasound2-dev:i386 libcairo2-dev:i386 libgl1-mesa-dev:i386 liblo-dev:i386 libpulse-dev:i386 libx11-dev:i386 libxcursor-dev:i386 libxext-dev:i386 libxrandr-dev:i386
+ sudo apt-get install -yq g++-multilib libasound2-dev:i386 libcairo2-dev:i386 libdbus-1-dev:i386 libgl1-mesa-dev:i386 liblo-dev:i386 libpulse-dev:i386 libx11-dev:i386 libxcursor-dev:i386 libxext-dev:i386 libxrandr-dev:i386
- name: Build linux x86
env:
CFLAGS: -m32
@@ -124,7 +124,7 @@ jobs:
- name: Set up dependencies
run: |
sudo apt-get update -qq
- sudo apt-get install -yq libasound2-dev libcairo2-dev libgl1-mesa-dev liblo-dev libpulse-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev
+ sudo apt-get install -yq libasound2-dev libcairo2-dev libdbus-1-dev libgl1-mesa-dev liblo-dev libpulse-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev
- name: Build linux x86_64
env:
LDFLAGS: -static-libgcc -static-libstdc++
@@ -141,15 +141,11 @@ jobs:
bin/*
macos-universal:
- runs-on: macos-10.15
+ runs-on: macos-11
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- - name: Fix up Xcode
- run: |
- sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*
- sudo xcode-select -s "/Applications/Xcode_12.3.app"
- name: Build macOS universal
env:
CFLAGS: -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_12 -mmacosx-version-min=10.12 -mtune=generic -msse -msse2
@@ -157,7 +153,7 @@ jobs:
LDFLAGS: -arch x86_64 -arch arm64 -mmacosx-version-min=10.12
run: |
make features
- make NOOPT=true -j $(sysctl -n hw.logicalcpu)
+ make HAVE_CAIRO=false NOOPT=true -j $(sysctl -n hw.logicalcpu)
./utils/package-osx-bundles.sh
- name: Set sha8
id: slug
@@ -172,9 +168,10 @@ jobs:
!bin/*-dssi.dylib
!bin/lv2
!bin/vst2
+ !bin/vst3
win32:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
@@ -235,3 +232,100 @@ jobs:
bin/*
!bin/*-ladspa.dll
!bin/*-dssi.dll
+
+ plugin-validation:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: recursive
+ - name: Set up dependencies
+ run: |
+ # custom repos
+ wget https://launchpad.net/~kxstudio-debian/+archive/kxstudio/+files/kxstudio-repos_10.0.3_all.deb
+ sudo dpkg -i kxstudio-repos_10.0.3_all.deb
+ sudo apt-get update -qq
+ # build-deps
+ sudo apt-get install -yq libasound2-dev libcairo2-dev libdbus-1-dev libgl1-mesa-dev liblo-dev libpulse-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev
+ # runtime testing
+ sudo apt-get install -yq carla-git lilv-utils lv2-dev lv2lint valgrind
+ - name: Build plugins
+ env:
+ CFLAGS: -g
+ CXXFLAGS: -g -DDPF_ABORT_ON_ERROR
+ LDFLAGS: -static-libgcc -static-libstdc++
+ run: |
+ make features
+ make NOOPT=true SKIP_STRIPPING=true -j $(nproc)
+ - name: Validate LV2 ttl syntax
+ run: |
+ lv2_validate \
+ /usr/lib/lv2/mod.lv2/*.ttl \
+ /usr/lib/lv2/kx-meta/*.ttl \
+ /usr/lib/lv2/kx-control-input-port-change-request.lv2/*.ttl \
+ /usr/lib/lv2/kx-programs.lv2/*.ttl \
+ ./bin/*.lv2/*.ttl
+ - name: Validate LV2 metadata and binaries
+ run: |
+ export LV2_PATH=/tmp/lv2-path
+ mkdir ${LV2_PATH}
+ cp -r bin/*.lv2 \
+ /usr/lib/lv2/{atom,buf-size,core,data-access,kx-control-input-port-change-request,kx-programs,instance-access,midi,parameters,port-groups,port-props,options,patch,presets,resize-port,state,time,ui,units,urid,worker}.lv2 \
+ ${LV2_PATH}
+ lv2lint -s lv2_generate_ttl -l ld-linux-x86-64.so.2 -M nopack $(lv2ls)
+ - name: Test LADSPA plugins
+ run: |
+ for p in $(ls bin/ | grep ladspa.so); do \
+ env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \
+ valgrind \
+ --error-exitcode=255 \
+ --leak-check=full \
+ --track-origins=yes \
+ --suppressions=./utils/valgrind-dpf.supp \
+ /usr/lib/carla/carla-bridge-native ladspa ./bin/${p} "" 1>/dev/null; \
+ done
+ - name: Test DSSI plugins
+ run: |
+ for p in $(ls bin/ | grep dssi.so); do \
+ env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \
+ valgrind \
+ --error-exitcode=255 \
+ --leak-check=full \
+ --track-origins=yes \
+ --suppressions=./utils/valgrind-dpf.supp \
+ /usr/lib/carla/carla-bridge-native dssi ./bin/${p} "" 1>/dev/null; \
+ done
+ - name: Test LV2 plugins
+ run: |
+ export LV2_PATH=/tmp/lv2-path
+ for p in $(lv2ls); do \
+ env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \
+ valgrind \
+ --error-exitcode=255 \
+ --leak-check=full \
+ --track-origins=yes \
+ --suppressions=./utils/valgrind-dpf.supp \
+ /usr/lib/carla/carla-bridge-native lv2 "" ${p} 1>/dev/null; \
+ done
+ - name: Test VST2 plugins
+ run: |
+ for p in $(ls bin/ | grep vst.so); do \
+ env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \
+ valgrind \
+ --error-exitcode=255 \
+ --leak-check=full \
+ --track-origins=yes \
+ --suppressions=./utils/valgrind-dpf.supp \
+ /usr/lib/carla/carla-bridge-native vst2 ./bin/${p} "" 1>/dev/null; \
+ done
+ - name: Test VST3 plugins
+ run: |
+ for p in $(ls bin/ | grep vst3); do \
+ env CARLA_BRIDGE_DUMMY=1 CARLA_BRIDGE_TESTING=native \
+ valgrind \
+ --error-exitcode=255 \
+ --leak-check=full \
+ --track-origins=yes \
+ --suppressions=./utils/valgrind-dpf.supp \
+ /usr/lib/carla/carla-bridge-native vst3 ./bin/${p} "" 1>/dev/null; \
+ done
diff --git a/.github/workflows/irc.yml b/.github/workflows/irc.yml
new file mode 100644
index 00000000..539fa1d2
--- /dev/null
+++ b/.github/workflows/irc.yml
@@ -0,0 +1,20 @@
+name: irc
+
+on: [push]
+
+jobs:
+ notification:
+ runs-on: ubuntu-latest
+ name: IRC notification
+ steps:
+ - name: Format message
+ id: message
+ run: |
+ message="${{ github.actor }} pushed $(echo '${{ github.event.commits[0].message }}' | head -n 1) ${{ github.event.commits[0].url }}"
+ echo ::set-output name=message::"${message}"
+ - name: IRC notification
+ uses: Gottox/irc-message-action@v2
+ with:
+ channel: '#kxstudio'
+ nickname: kxstudio-bot
+ message: ${{ steps.message.outputs.message }}
diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml
index 9bacad75..ea456232 100644
--- a/.github/workflows/makefile.yml
+++ b/.github/workflows/makefile.yml
@@ -20,7 +20,7 @@ jobs:
- name: Set up dependencies
run: |
sudo apt-get update -qq
- sudo apt-get install -yq libasound2-dev libcairo2-dev libgl1-mesa-dev liblo-dev libpulse-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev xvfb
+ sudo apt-get install -yq libasound2-dev libcairo2-dev libdbus-1-dev libgl1-mesa-dev liblo-dev libpulse-dev libx11-dev libxcursor-dev libxext-dev libxrandr-dev xvfb
- name: Without any warnings
env:
CFLAGS: -Werror
@@ -40,7 +40,7 @@ jobs:
CXXFLAGS: -Werror -std=gnu++98
run: |
make clean >/dev/null
- make -j $(nproc) VST3_FILENAME=
+ make -j $(nproc)
- name: No namespace
env:
CFLAGS: -Werror
diff --git a/.gitignore b/.gitignore
index 77927d98..a8090013 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ bin/
build/
docs/
utils/lv2_ttl_generator
+utils/lv2_ttl_generator.dSYM/
diff --git a/FEATURES.md b/FEATURES.md
new file mode 100644
index 00000000..3bba8f14
--- /dev/null
+++ b/FEATURES.md
@@ -0,0 +1,93 @@
+# DPF - DISTRHO Plugin Framework
+
+This file describes the available features for each plugin format.
+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.
+
+| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | Feature |
+|---------------------|---------------------------------------|-------------------------|---------------------|-------------------------------|--------------------------------|----------------------------------|---------------------|
+| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port groups |
+| Audio port as CV | Yes | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port as CV |
+| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Audio sidechan |
+| Bypass control | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Bypass control |
+| MIDI input | Yes | No | Yes | Yes | Yes | Yes | MIDI input |
+| MIDI output | Yes | No | No | Yes | Yes | Yes | MIDI output |
+| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Parameter changes |
+| Parameter groups | No | No | No | Yes | Yes | [No*](#vst3-is-work-in-progress) | Parameter groups |
+| Parameter outputs | No | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Parameter outputs |
+| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers |
+| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-programs) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | Programs |
+| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | States |
+| Full/internal state | Yes | No | No | Yes | Yes | Yes | Full/internal state |
+| Time position | Yes | No | No | Yes | Yes | Yes | Time position |
+| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | UI |
+| UI bg/fg colors | No | No | No | Yes | No | No? | UI bg/fg colors |
+| UI direct access | Yes | No | No | Yes | Yes | Yes | UI direct access |
+| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | UI host-filebrowser |
+| UI host-resize | Yes | No | Yes | Yes | No | [No*](#vst3-is-work-in-progress) | UI host-resize |
+| UI remote control | No | No | Yes | Yes | No | Yes | UI remote control |
+| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | UI send midi note |
+
+For things that could be unclear:
+
+- "States" refers to DPF API support, supporting key-value string pairs for internal state saving
+- "Full state" refers to plugins updating their state internally without outside intervention (like host or UI)
+- "UI direct access" means `DISTRHO_PLUGIN_WANT_DIRECT_ACCESS` is possible, that is, running DSP and UI on the same process
+- "UI remote control" means running the UI on a separate machine (for example over the network)
+- An external UI on this table means that it cannot be embed into the host window, but the plugin can still provide one
+
+# Special notes
+
+## Parameter triggers
+
+Trigger-style parameters (parameters which value is reset to its default every run) are only supported in JACK and LV2.
+For all other plugin formats DPF will simulate the behaviour through a parameter change request.
+
+## JACK audio port groups
+
+DPF will set JACK metadata information for grouping audio ports.
+This is not supported by most JACK applications at the moment.
+
+## JACK parameters and programs
+
+Under JACK/Stanlone mode, MIDI input events will trigger program and parameter changes.
+MIDI program change events work as expected (that is, MIDI program change 0 will load 1st plugin program).
+MIDI CCs are used for parameter changes (matching the `midiCC` value you set on each parameter).
+
+## JACK custom UI only
+
+There is no generic plugin editor view.
+If your plugin has no custom UI, the standalone executable will run but not show any window.
+
+## LADSPA programs
+
+Programs for LADSPA could be done via LRDF but this is not supported in DPF.
+
+## DSSI State
+
+DSSI only supports state changes when called via UI, no "full state" possible.
+This also makes it impossibe to use programs and state at the same time with DSSI,
+because in DPF changing programs can lead to state changes but there is no way to fetch this information on DSSI plugins.
+
+To make it simpler to understand, think of DSSI programs and states as UI properties.
+Because in DPF changing the state happens from UI to DSP side, regular DSSI can be supported.
+But if we involve programs, they would need to pass through the UI in order to work. Which goes against DPF's design.
+
+## LV2 parameter changes
+
+Although this is already implemented in DPF (through a custom extension), this is not implemented on most hosts.
+So for now you can pretty much treat it as if not supported.
+
+## VST2 potential support
+
+Not supported in DPF at the moment.
+It could eventually be, but likely not due to VST2 being phased out by Steinberg.
+Contact DPF authors if you require such a feature.
+
+## VST2 programs
+
+VST2 program support requires saving state of all programs in memory, which is very expensive and thus not done in DPF.
+
+## VST3 is work in progress
+
+Feature is possible, just not implemented yet in DPF.
diff --git a/LICENSING.md b/LICENSING.md
new file mode 100644
index 00000000..ad0a4c40
--- /dev/null
+++ b/LICENSING.md
@@ -0,0 +1,47 @@
+# DPF - DISTRHO Plugin Framework
+
+Even though DPF is quite liberally licensed, not all plugin formats follow the same ideals.
+This is usually due to plugin APIs/headers being tied to a specific license or having commercial restrictions.
+This file describes the licensing that applies to each individual plugin format as a way to make it clear what is possible and compatible.
+Note that if you are making GPLv2+ licensed plugins this does not apply to you, as so far everything is GPLv2+ compatible.
+
+Regardless of target format, DPF itself needs to be mentioned in attribution.
+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;
**ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai |
+| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;
2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld |
+| VST2 | GPLv2+ or commercial | Must be GPLv2+ compatible or alternatively use Steinberg VST2 SDK (no longer available for new plugins) | GPLv2+ compatible license or custom agreement with Steinberg |
+| VST3 | ISC | Copyright attribution | (none, only DPF files used) |
+
+### LADSPA and DSSI special note
+
+The header files on LADSPA and DSSI are LGPLv2.1+ licensed, which is unusual for pure APIs without libraries.
+LADSPA authors mention this on ladspa.org homepage:
+
+> LADSPA has been released under LGPL (GNU Lesser General Public License).
+> This is not intended to be the final license for LADSPA.
+> In the long term it is hoped that LADSPA will have a public license that is even less restrictive, so that commercial applications can use it (in a protected way) without having to use a derived LGPL library.
+> It may be that LGPL is already free enough for this, but we aren't sure.
+
+So the situation for LADSPA/DSSI plugins is unclear for commercial plugins.
+These formats are very limited and not much used anymore anyway, feel free to skip them if this situation is a potential issue for you.
+
+### VST2 special note
+
+By default DPF uses the free reverse-engineered [vestige header](distrho/src/vestige/vestige.h) file.
+This file is GPLv2+ licensed, so that applies to plugins built with it as well.
+You can alternatively build DPF-based VST2 plugins using the official Steinberg VST2 SDK,
+simply set the `VESTIGE_HEADER` compiler macro to `0` during build.
+You will need to provide your own VST2 SDK files then, as DPF does not ship with them.
+Note there are legal issues surrounding releasing new VST2 plugins using the official SDK, as that is no longer supported by Steinberg.
+
+### VST3 special note
+
+Contrary to most plugins, DPF does not use the official VST3 SDK.
+Instead, the API definitions are provided by the [travesty](distrho/src/travesty/) sub-project, licensed in the same way as DPF.
+This allows us to freely build plugins without being encumbered by restrictive licensing deals.
+It makes the internal implementation much harder for DPF, but this is not an issue for external developers.
diff --git a/Makefile b/Makefile
index 15922367..df63731e 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,6 @@ dgl:
examples: dgl
$(MAKE) all -C examples/CVPort
- $(MAKE) all -C examples/EmbedExternalUI
$(MAKE) all -C examples/FileHandling
$(MAKE) all -C examples/Info
$(MAKE) all -C examples/Latency
@@ -34,13 +33,13 @@ examples: dgl
ifeq ($(HAVE_CAIRO),true)
$(MAKE) all -C examples/CairoUI
endif
+ifeq ($(HAVE_DGL),true)
+ $(MAKE) all -C examples/EmbedExternalUI
+endif
ifeq ($(CAN_GENERATE_TTL),true)
gen: examples utils/lv2_ttl_generator
@$(CURDIR)/utils/generate-ttl.sh
-ifeq ($(MACOS),true)
- @$(CURDIR)/utils/generate-vst-bundles.sh
-endif
utils/lv2_ttl_generator:
$(MAKE) -C utils/lv2-ttl-generator
diff --git a/Makefile.base.mk b/Makefile.base.mk
index dfa64dd9..87ae06bd 100644
--- a/Makefile.base.mk
+++ b/Makefile.base.mk
@@ -25,35 +25,36 @@ ifneq ($(HAIKU),true)
ifneq ($(HURD),true)
ifneq ($(LINUX),true)
ifneq ($(MACOS),true)
+ifneq ($(WASM),true)
ifneq ($(WINDOWS),true)
ifneq (,$(findstring bsd,$(TARGET_MACHINE)))
-BSD=true
-endif
-ifneq (,$(findstring haiku,$(TARGET_MACHINE)))
-HAIKU=true
-endif
-ifneq (,$(findstring linux,$(TARGET_MACHINE)))
-LINUX=true
+BSD = true
+else ifneq (,$(findstring haiku,$(TARGET_MACHINE)))
+HAIKU = true
+else ifneq (,$(findstring linux,$(TARGET_MACHINE)))
+LINUX = true
else ifneq (,$(findstring gnu,$(TARGET_MACHINE)))
-HURD=true
-endif
-ifneq (,$(findstring apple,$(TARGET_MACHINE)))
-MACOS=true
-endif
-ifneq (,$(findstring mingw,$(TARGET_MACHINE)))
-WINDOWS=true
-endif
-ifneq (,$(findstring windows,$(TARGET_MACHINE)))
-WINDOWS=true
-endif
-
-endif
-endif
-endif
-endif
-endif
-endif
+HURD = true
+else ifneq (,$(findstring apple,$(TARGET_MACHINE)))
+MACOS = true
+else ifneq (,$(findstring mingw,$(TARGET_MACHINE)))
+WINDOWS = true
+else ifneq (,$(findstring msys,$(TARGET_MACHINE)))
+WINDOWS = true
+else ifneq (,$(findstring wasm,$(TARGET_MACHINE)))
+WASM = true
+else ifneq (,$(findstring windows,$(TARGET_MACHINE)))
+WINDOWS = true
+endif
+
+endif # WINDOWS
+endif # WASM
+endif # MACOS
+endif # LINUX
+endif # HURD
+endif # HAIKU
+endif # BSD
# ---------------------------------------------------------------------------------------------------------------------
# Auto-detect the processor
@@ -61,81 +62,105 @@ endif
TARGET_PROCESSOR := $(firstword $(subst -, ,$(TARGET_MACHINE)))
ifneq (,$(filter i%86,$(TARGET_PROCESSOR)))
-CPU_I386=true
-CPU_I386_OR_X86_64=true
+CPU_I386 = true
+CPU_I386_OR_X86_64 = true
+endif
+ifneq (,$(filter wasm32,$(TARGET_PROCESSOR)))
+CPU_I386 = true
+CPU_I386_OR_X86_64 = true
endif
ifneq (,$(filter x86_64,$(TARGET_PROCESSOR)))
-CPU_X86_64=true
-CPU_I386_OR_X86_64=true
+CPU_X86_64 = true
+CPU_I386_OR_X86_64 = true
endif
ifneq (,$(filter arm%,$(TARGET_PROCESSOR)))
-CPU_ARM=true
-CPU_ARM_OR_AARCH64=true
+CPU_ARM = true
+CPU_ARM_OR_AARCH64 = true
endif
ifneq (,$(filter arm64%,$(TARGET_PROCESSOR)))
-CPU_ARM64=true
-CPU_ARM_OR_AARCH64=true
+CPU_ARM64 = true
+CPU_ARM_OR_AARCH64 = true
endif
ifneq (,$(filter aarch64%,$(TARGET_PROCESSOR)))
-CPU_AARCH64=true
-CPU_ARM_OR_AARCH64=true
+CPU_AARCH64 = true
+CPU_ARM_OR_AARCH64 = true
endif
# ---------------------------------------------------------------------------------------------------------------------
# Set PKG_CONFIG (can be overridden by environment variable)
-ifeq ($(WINDOWS),true)
+ifeq ($(WASM),true)
+# Skip on wasm by default
+PKG_CONFIG ?= false
+else ifeq ($(WINDOWS),true)
# Build statically on Windows by default
PKG_CONFIG ?= pkg-config --static
else
PKG_CONFIG ?= pkg-config
endif
+# ---------------------------------------------------------------------------------------------------------------------
+# Set cross compiling flag
+
+ifeq ($(WASM),true)
+CROSS_COMPILING = true
+endif
+
# ---------------------------------------------------------------------------------------------------------------------
# Set LINUX_OR_MACOS
ifeq ($(LINUX),true)
-LINUX_OR_MACOS=true
+LINUX_OR_MACOS = true
endif
ifeq ($(MACOS),true)
-LINUX_OR_MACOS=true
+LINUX_OR_MACOS = true
endif
# ---------------------------------------------------------------------------------------------------------------------
-# Set MACOS_OR_WINDOWS and HAIKU_OR_MACOS_OR_WINDOWS
+# Set MACOS_OR_WINDOWS, MACOS_OR_WASM_OR_WINDOWS, HAIKU_OR_MACOS_OR_WINDOWS and HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS
ifeq ($(HAIKU),true)
-HAIKU_OR_MACOS_OR_WINDOWS=true
+HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true
+HAIKU_OR_MACOS_OR_WINDOWS = true
endif
ifeq ($(MACOS),true)
-MACOS_OR_WINDOWS=true
-HAIKU_OR_MACOS_OR_WINDOWS=true
+HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true
+HAIKU_OR_MACOS_OR_WINDOWS = true
+MACOS_OR_WASM_OR_WINDOWS = true
+MACOS_OR_WINDOWS = true
+endif
+
+ifeq ($(WASM),true)
+HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true
+MACOS_OR_WASM_OR_WINDOWS = true
endif
ifeq ($(WINDOWS),true)
-MACOS_OR_WINDOWS=true
-HAIKU_OR_MACOS_OR_WINDOWS=true
+HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS = true
+HAIKU_OR_MACOS_OR_WINDOWS = true
+MACOS_OR_WASM_OR_WINDOWS = true
+MACOS_OR_WINDOWS = true
endif
# ---------------------------------------------------------------------------------------------------------------------
# Set UNIX
ifeq ($(BSD),true)
-UNIX=true
+UNIX = true
endif
ifeq ($(HURD),true)
-UNIX=true
+UNIX = true
endif
ifeq ($(LINUX),true)
-UNIX=true
+UNIX = true
endif
ifeq ($(MACOS),true)
-UNIX=true
+UNIX = true
endif
# ---------------------------------------------------------------------------------------------------------------------
@@ -145,7 +170,12 @@ BASE_FLAGS = -Wall -Wextra -pipe -MD -MP
BASE_OPTS = -O3 -ffast-math -fdata-sections -ffunction-sections
ifeq ($(CPU_I386_OR_X86_64),true)
-BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse
+BASE_OPTS += -mtune=generic
+ifeq ($(WASM),true)
+BASE_OPTS += -msse -msse2 -msse3 -msimd128
+else
+BASE_OPTS += -msse -msse2 -mfpmath=sse
+endif
endif
ifeq ($(CPU_ARM),true)
@@ -155,27 +185,49 @@ endif
endif
ifeq ($(MACOS),true)
+
# MacOS linker flags
-LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip -Wl,-dead_strip_dylibs
+LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip,-dead_strip_dylibs
ifneq ($(SKIP_STRIPPING),true)
LINK_OPTS += -Wl,-x
endif
+
else
+
# Common linker flags
-LINK_OPTS = -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed
+LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-O1,--gc-sections
+ifeq ($(WASM),true)
+LINK_OPTS += -O3
+LINK_OPTS += -sAGGRESSIVE_VARIABLE_ELIMINATION=1
+else
+LINK_OPTS += -Wl,--as-needed
ifneq ($(SKIP_STRIPPING),true)
LINK_OPTS += -Wl,--strip-all
endif
endif
+endif
+
+ifeq ($(SKIP_STRIPPING),true)
+BASE_FLAGS += -g
+endif
+
ifeq ($(NOOPT),true)
# Non-CPU-specific optimization flags
BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections
endif
+ifneq ($(MACOS_OR_WASM_OR_WINDOWS),true)
+ifneq ($(BSD),true)
+BASE_FLAGS += -fno-gnu-unique
+endif
+endif
+
ifeq ($(WINDOWS),true)
+# Assume we want posix
+BASE_FLAGS += -posix -D__STDC_FORMAT_MACROS=1 -D__USE_MINGW_ANSI_STDIO=1
# Needed for windows, see https://github.com/falkTX/Carla/issues/855
-BASE_OPTS += -mstackrealign
+BASE_FLAGS += -mstackrealign
else
# Not needed for Windows
BASE_FLAGS += -fPIC -DPIC
@@ -184,24 +236,50 @@ endif
ifeq ($(DEBUG),true)
BASE_FLAGS += -DDEBUG -O0 -g
LINK_OPTS =
+ifeq ($(WASM),true)
+LINK_OPTS += -sASSERTIONS=1
+endif
else
BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden
CXXFLAGS += -fvisibility-inlines-hidden
endif
+ifeq ($(STATIC_BUILD),true)
+BASE_FLAGS += -DSTATIC_BUILD
+# LINK_OPTS += -static
+endif
+
+ifeq ($(WITH_LTO),true)
+BASE_FLAGS += -fno-strict-aliasing -flto
+LINK_OPTS += -fno-strict-aliasing -flto -Werror=odr -Werror=lto-type-mismatch
+endif
+
BUILD_C_FLAGS = $(BASE_FLAGS) -std=gnu99 $(CFLAGS)
BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=gnu++11 $(CXXFLAGS)
LINK_FLAGS = $(LINK_OPTS) $(LDFLAGS)
-ifneq ($(MACOS),true)
+ifeq ($(WASM),true)
+# Special flag for emscripten
+LINK_FLAGS += -sENVIRONMENT=web -sLLD_REPORT_UNDEFINED
+else ifneq ($(MACOS),true)
# Not available on MacOS
-LINK_FLAGS += -Wl,--no-undefined
+LINK_FLAGS += -Wl,--no-undefined
endif
ifeq ($(MACOS_OLD),true)
BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS) -DHAVE_CPP11_SUPPORT=0
endif
+ifeq ($(WASM_CLIPBOARD),true)
+BUILD_CXX_FLAGS += -DPUGL_WASM_ASYNC_CLIPBOARD
+LINK_FLAGS += -sASYNCIFY -sASYNCIFY_IMPORTS=puglGetAsyncClipboardData
+endif
+
+ifeq ($(WASM_EXCEPTIONS),true)
+BUILD_CXX_FLAGS += -fexceptions
+LINK_FLAGS += -fexceptions
+endif
+
ifeq ($(WINDOWS),true)
# Always build statically on windows
LINK_FLAGS += -static -static-libgcc -static-libstdc++
@@ -235,33 +313,36 @@ endif
HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true)
-# Vulkan is not supported yet
-# HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true)
-
-ifeq ($(MACOS_OR_WINDOWS),true)
+ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true)
HAVE_OPENGL = true
else
-HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true)
-ifneq ($(HAIKU),true)
+HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true)
+HAVE_DBUS = $(shell $(PKG_CONFIG) --exists dbus-1 && echo true)
HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true)
HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true)
HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true)
HAVE_XRANDR = $(shell $(PKG_CONFIG) --exists xrandr && echo true)
endif
-endif
+
+# Vulkan is not supported yet
+# HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true)
# ---------------------------------------------------------------------------------------------------------------------
# Check for optional libraries
HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true)
+ifneq ($(SKIP_NATIVE_AUDIO_FALLBACK),true)
+ifneq ($(SKIP_RTAUDIO_FALLBACK),true)
+
ifeq ($(MACOS),true)
HAVE_RTAUDIO = true
else ifeq ($(WINDOWS),true)
HAVE_RTAUDIO = true
-else ifneq ($(HAIKU),true)
+else
HAVE_ALSA = $(shell $(PKG_CONFIG) --exists alsa && echo true)
HAVE_PULSEAUDIO = $(shell $(PKG_CONFIG) --exists libpulse-simple && echo true)
+HAVE_SDL2 = $(shell $(PKG_CONFIG) --exists sdl2 && echo true)
ifeq ($(HAVE_ALSA),true)
HAVE_RTAUDIO = true
else ifeq ($(HAVE_PULSEAUDIO),true)
@@ -269,31 +350,39 @@ HAVE_RTAUDIO = true
endif
endif
-# backwards compat
+endif
+endif
+
+# backwards compat, always available/enabled
+ifneq ($(FORCE_NATIVE_AUDIO_FALLBACK),true)
+ifeq ($(STATIC_BUILD),true)
+HAVE_JACK = $(shell $(PKG_CONFIG) --exists jack && echo true)
+else
HAVE_JACK = true
+endif
+endif
# ---------------------------------------------------------------------------------------------------------------------
# Set Generic DGL stuff
ifeq ($(HAIKU),true)
DGL_SYSTEM_LIBS += -lbe
-endif
-
-ifeq ($(MACOS),true)
+else ifeq ($(MACOS),true)
DGL_SYSTEM_LIBS += -framework Cocoa -framework CoreVideo
-endif
-
-ifeq ($(WINDOWS),true)
+else ifeq ($(WASM),true)
+else ifeq ($(WINDOWS),true)
DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32
+# -lole32
+else
+ifeq ($(HAVE_DBUS),true)
+DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS
+DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1)
endif
-
-ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true)
ifeq ($(HAVE_X11),true)
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11)
ifeq ($(HAVE_XCURSOR),true)
-# TODO -DHAVE_XCURSOR
-DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor)
+DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor) -DHAVE_XCURSOR
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xcursor)
endif
ifeq ($(HAVE_XEXT),true)
@@ -331,18 +420,20 @@ DGL_FLAGS += -DHAVE_OPENGL
ifeq ($(HAIKU),true)
OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl)
OPENGL_LIBS = $(shell $(PKG_CONFIG) --libs gl)
-endif
-
-ifeq ($(MACOS),true)
+else ifeq ($(MACOS),true)
OPENGL_FLAGS = -DGL_SILENCE_DEPRECATION=1 -Wno-deprecated-declarations
OPENGL_LIBS = -framework OpenGL
+else ifeq ($(WASM),true)
+ifeq ($(USE_GLES2),true)
+OPENGL_LIBS = -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2
+else
+ifneq ($(USE_GLES3),true)
+OPENGL_LIBS = -sLEGACY_GL_EMULATION -sGL_UNSAFE_OPTS=0
endif
-
-ifeq ($(WINDOWS),true)
-OPENGL_LIBS = -lopengl32
endif
-
-ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true)
+else ifeq ($(WINDOWS),true)
+OPENGL_LIBS = -lopengl32
+else
OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl x11)
OPENGL_LIBS = $(shell $(PKG_CONFIG) --libs gl x11)
endif
@@ -354,7 +445,7 @@ endif
# ---------------------------------------------------------------------------------------------------------------------
# Set Stub specific stuff
-ifeq ($(HAIKU_OR_MACOS_OR_WINDOWS),true)
+ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true)
HAVE_STUB = true
else
HAVE_STUB = $(HAVE_X11)
@@ -394,41 +485,105 @@ PULSEAUDIO_FLAGS = $(shell $(PKG_CONFIG) --cflags libpulse-simple)
PULSEAUDIO_LIBS = $(shell $(PKG_CONFIG) --libs libpulse-simple)
endif
-ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true)
+ifeq ($(HAVE_SDL2),true)
+SDL2_FLAGS = $(shell $(PKG_CONFIG) --cflags sdl2)
+SDL2_LIBS = $(shell $(PKG_CONFIG) --libs sdl2)
+endif
+
+ifeq ($(HAVE_JACK),true)
+ifeq ($(STATIC_BUILD),true)
+JACK_FLAGS = $(shell $(PKG_CONFIG) --cflags jack)
+JACK_LIBS = $(shell $(PKG_CONFIG) --libs jack)
+endif
+endif
+
+ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true)
SHARED_MEMORY_LIBS = -lrt
endif
# ---------------------------------------------------------------------------------------------------------------------
# Backwards-compatible HAVE_DGL
-ifeq ($(MACOS_OR_WINDOWS),true)
+ifeq ($(MACOS_OR_WASM_OR_WINDOWS),true)
HAVE_DGL = true
else ifeq ($(HAVE_OPENGL),true)
-ifeq ($(HAIKU),true)
-HAVE_DGL = true
-else
HAVE_DGL = $(HAVE_X11)
endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Namespace flags
+
+ifneq ($(DISTRHO_NAMESPACE),)
+BUILD_CXX_FLAGS += -DDISTRHO_NAMESPACE=$(DISTRHO_NAMESPACE)
+endif
+
+ifneq ($(DGL_NAMESPACE),)
+BUILD_CXX_FLAGS += -DDGL_NAMESPACE=$(DGL_NAMESPACE)
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Optional flags
+
+ifeq ($(NVG_DISABLE_SKIPPING_WHITESPACE),true)
+BUILD_CXX_FLAGS += -DNVG_DISABLE_SKIPPING_WHITESPACE
+endif
+
+ifneq ($(NVG_FONT_TEXTURE_FLAGS),)
+BUILD_CXX_FLAGS += -DNVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS)
+endif
+
+ifeq ($(FILE_BROWSER_DISABLED),true)
+BUILD_CXX_FLAGS += -DDGL_FILE_BROWSER_DISABLED
+endif
+
+ifneq ($(WINDOWS_ICON_ID),)
+BUILD_CXX_FLAGS += -DDGL_WINDOWS_ICON_ID=$(WINDOWS_ICON_ID)
+endif
+
+ifeq ($(USE_GLES2),true)
+BUILD_CXX_FLAGS += -DDGL_USE_GLES -DDGL_USE_GLES2
+endif
+
+ifeq ($(USE_GLES3),true)
+BUILD_CXX_FLAGS += -DDGL_USE_GLES -DDGL_USE_GLES3
+endif
+
+ifeq ($(USE_OPENGL3),true)
+BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3
+endif
+
+ifeq ($(USE_NANOVG_FBO),true)
+BUILD_CXX_FLAGS += -DDGL_USE_NANOVG_FBO
+endif
+
+ifeq ($(USE_NANOVG_FREETYPE),true)
+BUILD_CXX_FLAGS += -DFONS_USE_FREETYPE $(shell $(PKG_CONFIG) --cflags freetype2)
+endif
+
+ifeq ($(USE_RGBA),true)
+BUILD_CXX_FLAGS += -DDGL_USE_RGBA
endif
# ---------------------------------------------------------------------------------------------------------------------
# Set app extension
-ifeq ($(WINDOWS),true)
+ifeq ($(WASM),true)
+APP_EXT = .html
+else ifeq ($(WINDOWS),true)
APP_EXT = .exe
endif
# ---------------------------------------------------------------------------------------------------------------------
# Set shared lib extension
-LIB_EXT = .so
-
ifeq ($(MACOS),true)
LIB_EXT = .dylib
-endif
-
-ifeq ($(WINDOWS),true)
+else ifeq ($(WASM),true)
+LIB_EXT = .wasm
+else ifeq ($(WINDOWS),true)
LIB_EXT = .dll
+else
+LIB_EXT = .so
endif
# ---------------------------------------------------------------------------------------------------------------------
@@ -436,6 +591,8 @@ endif
ifeq ($(MACOS),true)
SHARED = -dynamiclib
+else ifeq ($(WASM),true)
+SHARED = -sSIDE_MODULE=2
else
SHARED = -shared
endif
@@ -443,8 +600,12 @@ endif
# ---------------------------------------------------------------------------------------------------------------------
# Handle the verbosity switch
-ifeq ($(VERBOSE),true)
SILENT =
+
+ifeq ($(VERBOSE),1)
+else ifeq ($(VERBOSE),y)
+else ifeq ($(VERBOSE),yes)
+else ifeq ($(VERBOSE),true)
else
SILENT = @
endif
@@ -473,19 +634,24 @@ features:
$(call print_available,HURD)
$(call print_available,LINUX)
$(call print_available,MACOS)
+ $(call print_available,WASM)
$(call print_available,WINDOWS)
+ $(call print_available,HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS)
$(call print_available,HAIKU_OR_MACOS_OR_WINDOWS)
$(call print_available,LINUX_OR_MACOS)
+ $(call print_available,MACOS_OR_WASM_OR_WINDOWS)
$(call print_available,MACOS_OR_WINDOWS)
$(call print_available,UNIX)
@echo === Detected features
$(call print_available,HAVE_ALSA)
+ $(call print_available,HAVE_DBUS)
$(call print_available,HAVE_CAIRO)
$(call print_available,HAVE_DGL)
$(call print_available,HAVE_LIBLO)
$(call print_available,HAVE_OPENGL)
$(call print_available,HAVE_PULSEAUDIO)
$(call print_available,HAVE_RTAUDIO)
+ $(call print_available,HAVE_SDL2)
$(call print_available,HAVE_STUB)
$(call print_available,HAVE_VULKAN)
$(call print_available,HAVE_X11)
diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk
index d057e28c..4794a08c 100644
--- a/Makefile.plugins.mk
+++ b/Makefile.plugins.mk
@@ -38,6 +38,10 @@ ifeq ($(HAVE_ALSA),true)
BASE_FLAGS += -DHAVE_ALSA
endif
+ifeq ($(HAVE_JACK),true)
+BASE_FLAGS += -DHAVE_JACK
+endif
+
ifeq ($(HAVE_LIBLO),true)
BASE_FLAGS += -DHAVE_LIBLO
endif
@@ -46,41 +50,66 @@ ifeq ($(HAVE_PULSEAUDIO),true)
BASE_FLAGS += -DHAVE_PULSEAUDIO
endif
+ifeq ($(HAVE_RTAUDIO),true)
+BASE_FLAGS += -DHAVE_RTAUDIO
+endif
+
+ifeq ($(HAVE_SDL2),true)
+BASE_FLAGS += -DHAVE_SDL2
+endif
+
+# always needed
+ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true)
+ifneq ($(STATIC_BUILD),true)
+LINK_FLAGS += -ldl
+endif
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# JACK/Standalone setup
+
+ifeq ($(WASM),true)
+
+JACK_FLAGS += -sUSE_SDL=2
+JACK_LIBS += -sUSE_SDL=2
+JACK_LIBS += -sMAIN_MODULE -ldl
+
+ifneq ($(FILE_BROWSER_DISABLED),true)
+JACK_LIBS += -sEXPORTED_RUNTIME_METHODS=FS,cwrap
+endif
+
+else ifneq ($(SKIP_RTAUDIO_FALLBACK),true)
+
ifeq ($(MACOS),true)
-JACK_LIBS += -framework CoreAudio -framework CoreFoundation
+JACK_LIBS += -framework CoreAudio -framework CoreFoundation -framework CoreMIDI
else ifeq ($(WINDOWS),true)
-JACK_LIBS += -lksuser -lmfplat -lmfuuid -lole32 -lwinmm -lwmcodecdspuuid
-else ifneq ($(HAIKU),true)
-JACK_LIBS = -ldl
+JACK_LIBS += -lole32 -lwinmm
+# DirectSound
+JACK_LIBS += -ldsound
+# WASAPI
+# JACK_LIBS += -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid
+else
+ifeq ($(HAVE_PULSEAUDIO),true)
+JACK_FLAGS += $(PULSEAUDIO_FLAGS)
+JACK_LIBS += $(PULSEAUDIO_LIBS)
+endif
ifeq ($(HAVE_ALSA),true)
JACK_FLAGS += $(ALSA_FLAGS)
JACK_LIBS += $(ALSA_LIBS)
endif
-ifeq ($(HAVE_PULSEAUDIO),true)
-JACK_FLAGS += $(PULSEAUDIO_FLAGS)
-JACK_LIBS += $(PULSEAUDIO_LIBS)
endif
+
ifeq ($(HAVE_RTAUDIO),true)
+ifneq ($(HAIKU),true)
JACK_LIBS += -lpthread
-endif # !HAIKU
-endif
-
-# backwards compat
-BASE_FLAGS += -DHAVE_JACK
-
-# ---------------------------------------------------------------------------------------------------------------------
-# Set VST3 filename, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html
-
-ifeq ($(LINUX),true)
-VST3_FILENAME = $(TARGET_PROCESSOR)-linux/$(NAME).so
endif
-ifeq ($(MACOS),true)
-ifneq ($(MACOS_OLD),true)
-VST3_FILENAME = MacOS/$(NAME)
endif
+
+ifeq ($(HAVE_SDL2),true)
+JACK_FLAGS += $(SDL2_FLAGS)
+JACK_LIBS += $(SDL2_LIBS)
endif
-ifeq ($(WINDOWS),true)
-VST3_FILENAME = $(TARGET_PROCESSOR)-win/$(NAME).vst3
+
endif
# ---------------------------------------------------------------------------------------------------------------------
@@ -93,33 +122,6 @@ ifeq ($(MACOS),true)
OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o
endif
-# ---------------------------------------------------------------------------------------------------------------------
-# Set plugin binary file targets
-
-jack = $(TARGET_DIR)/$(NAME)$(APP_EXT)
-ladspa_dsp = $(TARGET_DIR)/$(NAME)-ladspa$(LIB_EXT)
-dssi_dsp = $(TARGET_DIR)/$(NAME)-dssi$(LIB_EXT)
-dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui$(APP_EXT)
-lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT)
-lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT)
-lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT)
-vst2 = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT)
-ifneq ($(VST3_FILENAME),)
-vst3 = $(TARGET_DIR)/$(NAME).vst3/Contents/$(VST3_FILENAME)
-endif
-
-# ---------------------------------------------------------------------------------------------------------------------
-# Set plugin symbols to export
-
-ifeq ($(MACOS),true)
-SYMBOLS_LADSPA = -Wl,-exported_symbol,_ladspa_descriptor
-SYMBOLS_DSSI = -Wl,-exported_symbol,_ladspa_descriptor -Wl,-exported_symbol,_dssi_descriptor
-SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2_generate_ttl
-SYMBOLS_LV2UI = -Wl,-exported_symbol,_lv2ui_descriptor
-SYMBOLS_VST2 = -Wl,-exported_symbol,_VSTPluginMain
-SYMBOLS_VST3 = -Wl,-exported_symbol,_GetPluginFactory -Wl,-exported_symbol,_bundleEntry -Wl,-exported_symbol,_bundleExit
-endif
-
# ---------------------------------------------------------------------------------------------------------------------
# Handle UI stuff, disable UI support automatically
@@ -164,6 +166,18 @@ HAVE_DGL = false
endif
endif
+ifeq ($(UI_TYPE),opengl3)
+ifeq ($(HAVE_OPENGL),true)
+DGL_FLAGS += -DDGL_OPENGL -DDGL_USE_OPENGL3 -DHAVE_DGL
+DGL_FLAGS += $(OPENGL_FLAGS)
+DGL_LIBS += $(OPENGL_LIBS)
+DGL_LIB = $(DPF_PATH)/build/libdgl-opengl3.a
+HAVE_DGL = true
+else
+HAVE_DGL = false
+endif
+endif
+
ifeq ($(UI_TYPE),vulkan)
ifeq ($(HAVE_VULKAN),true)
DGL_FLAGS += -DDGL_VULKAN -DHAVE_DGL
@@ -192,6 +206,76 @@ endif
DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm
+# TODO split dsp and ui object build flags
+BASE_FLAGS += $(DGL_FLAGS)
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Set VST2 filename, either single binary or inside a bundle
+
+ifeq ($(MACOS),true)
+VST2_CONTENTS = $(NAME).vst/Contents
+VST2_FILENAME = $(VST2_CONTENTS)/MacOS/$(NAME)
+else ifeq ($(USE_VST2_BUNDLE),true)
+VST2_FILENAME = $(NAME).vst/$(NAME)$(LIB_EXT)
+else
+VST2_FILENAME = $(NAME)-vst$(LIB_EXT)
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Set VST3 filename, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html
+
+ifeq ($(LINUX),true)
+VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-linux/$(NAME).so
+else ifeq ($(MACOS),true)
+VST3_CONTENTS = $(NAME).vst3/Contents
+VST3_FILENAME = $(VST3_CONTENTS)/MacOS/$(NAME)
+else ifeq ($(WASM),true)
+VST3_FILENAME = $(NAME).vst3/Contents/wasm/$(NAME).vst3
+else ifeq ($(WINDOWS),true)
+ifeq ($(CPU_I386),true)
+VST3_FILENAME = $(NAME).vst3/Contents/x86-win/$(NAME).vst3
+else ifeq ($(CPU_X86_64),true)
+VST3_FILENAME = $(NAME).vst3/Contents/x86_64-win/$(NAME).vst3
+endif
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Set plugin binary file targets
+
+ifeq ($(MACOS),true)
+ifeq ($(HAVE_DGL),true)
+MACOS_APP_BUNDLE = true
+endif
+endif
+
+ifeq ($(MACOS_APP_BUNDLE),true)
+jack = $(TARGET_DIR)/$(NAME).app/Contents/MacOS/$(NAME)
+jackfiles = $(TARGET_DIR)/$(NAME).app/Contents/Info.plist
+else
+jack = $(TARGET_DIR)/$(NAME)$(APP_EXT)
+endif
+ladspa_dsp = $(TARGET_DIR)/$(NAME)-ladspa$(LIB_EXT)
+dssi_dsp = $(TARGET_DIR)/$(NAME)-dssi$(LIB_EXT)
+dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui$(APP_EXT)
+lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT)
+lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT)
+lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT)
+vst2 = $(TARGET_DIR)/$(VST2_FILENAME)
+ifneq ($(VST3_FILENAME),)
+vst3 = $(TARGET_DIR)/$(VST3_FILENAME)
+endif
+shared = $(TARGET_DIR)/$(NAME)$(LIB_EXT)
+static = $(TARGET_DIR)/$(NAME).a
+
+ifeq ($(MACOS),true)
+vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/Info.plist
+vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/PkgInfo
+vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/Resources/empty.lproj
+vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/Info.plist
+vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/PkgInfo
+vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/Resources/empty.lproj
+endif
+
ifneq ($(HAVE_DGL),true)
dssi_ui =
lv2_ui =
@@ -203,8 +287,53 @@ ifneq ($(HAVE_LIBLO),true)
dssi_ui =
endif
-# TODO split dsp and ui object build flags
-BASE_FLAGS += $(DGL_FLAGS)
+# ---------------------------------------------------------------------------------------------------------------------
+# Set plugin symbols to export
+
+ifeq ($(MACOS),true)
+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_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp
+SYMBOLS_LV2UI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-ui.exp
+SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp
+SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp
+SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp
+SYMBOLS_SHARED = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/shared.exp
+else ifeq ($(WASM),true)
+SYMBOLS_LADSPA = -sEXPORTED_FUNCTIONS="['ladspa_descriptor']"
+SYMBOLS_DSSI = -sEXPORTED_FUNCTIONS="['ladspa_descriptor','dssi_descriptor']"
+SYMBOLS_LV2DSP = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl']"
+SYMBOLS_LV2UI = -sEXPORTED_FUNCTIONS="['lv2ui_descriptor']"
+SYMBOLS_LV2 = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl','lv2ui_descriptor']"
+SYMBOLS_VST2 = -sEXPORTED_FUNCTIONS="['VSTPluginMain']"
+SYMBOLS_VST3 = -sEXPORTED_FUNCTIONS="['GetPluginFactory','ModuleEntry','ModuleExit']"
+SYMBOLS_SHARED = -sEXPORTED_FUNCTIONS="['createSharedPlugin']"
+else ifeq ($(WINDOWS),true)
+SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def
+SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def
+SYMBOLS_LV2DSP = $(DPF_PATH)/utils/symbols/lv2-dsp.def
+SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def
+SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def
+SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def
+SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def
+SYMBOLS_SHARED = $(DPF_PATH)/utils/symbols/shared.def
+else ifneq ($(DEBUG),true)
+SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version
+SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version
+SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version
+SYMBOLS_LV2UI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-ui.version
+SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version
+SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version
+SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version
+SYMBOLS_SHARED = -Wl,--version-script=$(DPF_PATH)/utils/symbols/shared.version
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Runtime test build
+
+ifeq ($(DPF_RUNTIME_TESTING),true)
+BUILD_CXX_FLAGS += -DDPF_RUNTIME_TESTING -Wno-pmf-conversions
+endif
# ---------------------------------------------------------------------------------------------------------------------
# all needs to be first
@@ -234,9 +363,23 @@ $(BUILD_DIR)/%.cpp.o: %.cpp
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@
+$(BUILD_DIR)/%.m.o: %.m
+ -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)"
+ @echo "Compiling $<"
+ $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@
+
+$(BUILD_DIR)/%.mm.o: %.mm
+ -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)"
+ @echo "Compiling $<"
+ $(SILENT)$(CC) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
+
clean:
rm -rf $(BUILD_DIR)
- rm -rf $(TARGET_DIR)/$(NAME) $(TARGET_DIR)/$(NAME)-* $(TARGET_DIR)/$(NAME).lv2
+ rm -rf $(TARGET_DIR)/$(NAME)
+ rm -rf $(TARGET_DIR)/$(NAME)-*
+ rm -rf $(TARGET_DIR)/$(NAME).lv2
+ rm -rf $(TARGET_DIR)/$(NAME).vst
+ rm -rf $(TARGET_DIR)/$(NAME).vst3
# ---------------------------------------------------------------------------------------------------------------------
# DGL
@@ -247,6 +390,9 @@ $(DPF_PATH)/build/libdgl-cairo.a:
$(DPF_PATH)/build/libdgl-opengl.a:
$(MAKE) -C $(DPF_PATH)/dgl opengl
+$(DPF_PATH)/build/libdgl-opengl3.a:
+ $(MAKE) -C $(DPF_PATH)/dgl opengl3
+
$(DPF_PATH)/build/libdgl-stub.a:
$(MAKE) -C $(DPF_PATH)/dgl stub
@@ -255,37 +401,35 @@ $(DPF_PATH)/build/libdgl-vulkan.a:
# ---------------------------------------------------------------------------------------------------------------------
-AS_PUGL_NAMESPACE = $(subst -,_,$(1))
-
-$(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp
+$(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoPluginMain.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@
-$(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp
+$(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUIMain.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@
-$(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm
+$(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm $(EXTRA_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUI_macOS.mm ($*)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DPUGL_NAMESPACE=$(call AS_PUGL_NAMESPACE,$*) -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -I$(DPF_PATH)/dgl/src -I$(DPF_PATH)/dgl/src/pugl-upstream/include -ObjC++ -c -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
-$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp
+$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoPluginMain.cpp (JACK)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@
-$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp
+$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUIMain.cpp (DSSI)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(LIBLO_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI $(LIBLO_FLAGS) -c -o $@
# ---------------------------------------------------------------------------------------------------------------------
# JACK
-jack: $(jack)
+jack: $(jack) $(jackfiles)
ifeq ($(HAVE_DGL),true)
$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB)
@@ -294,7 +438,7 @@ $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating JACK standalone for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(JACK_LIBS) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(JACK_LIBS) -o $@
# ---------------------------------------------------------------------------------------------------------------------
# LADSPA
@@ -337,22 +481,22 @@ $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating LV2 plugin for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) $(SYMBOLS_LV2UI) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) -o $@
$(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
-@mkdir -p $(shell dirname $@)
@echo "Creating LV2 plugin library for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB)
-@mkdir -p $(shell dirname $@)
@echo "Creating LV2 plugin UI for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@
# ---------------------------------------------------------------------------------------------------------------------
# VST2
-vst2 vst: $(vst2)
+vst2 vst: $(vst2) $(vst2files)
ifeq ($(HAVE_DGL),true)
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB)
@@ -361,17 +505,73 @@ $(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating VST2 plugin for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@
# ---------------------------------------------------------------------------------------------------------------------
# VST3
-vst3: $(vst3)
+vst3: $(vst3) $(vst3files)
+ifeq ($(HAVE_DGL),true)
+$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB)
+else
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o
+endif
-@mkdir -p $(shell dirname $@)
@echo "Creating VST3 plugin for $(NAME)"
- $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Shared
+
+shared: $(shared)
+
+ifeq ($(HAVE_DGL),true)
+$(shared): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.o $(DGL_LIB)
+else
+$(shared): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o
+endif
+ -@mkdir -p $(shell dirname $@)
+ @echo "Creating shared library for $(NAME)"
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_SHARED) -o $@
+
+# ---------------------------------------------------------------------------------------------------------------------
+# Static
+
+static: $(static)
+
+ifeq ($(HAVE_DGL),true)
+$(static): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.o $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.o
+else
+$(static): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.o
+endif
+ -@mkdir -p $(shell dirname $@)
+ @echo "Creating static library for $(NAME)"
+ $(SILENT)rm -f $@
+ $(SILENT)$(AR) crs $@ $^
+
+# ---------------------------------------------------------------------------------------------------------------------
+# macOS files
+
+$(TARGET_DIR)/%.app/Contents/Info.plist: $(DPF_PATH)/utils/plugin.app/Contents/Info.plist
+ -@mkdir -p $(shell dirname $@)
+ $(SILENT)sed -e "s/@INFO_PLIST_PROJECT_NAME@/$(NAME)/" $< > $@
+
+$(TARGET_DIR)/%.vst/Contents/Info.plist: $(DPF_PATH)/utils/plugin.vst/Contents/Info.plist
+ -@mkdir -p $(shell dirname $@)
+ $(SILENT)sed -e "s/@INFO_PLIST_PROJECT_NAME@/$(NAME)/" $< > $@
+
+$(TARGET_DIR)/%.vst3/Contents/Info.plist: $(DPF_PATH)/utils/plugin.vst/Contents/Info.plist
+ -@mkdir -p $(shell dirname $@)
+ $(SILENT)sed -e "s/@INFO_PLIST_PROJECT_NAME@/$(NAME)/" $< > $@
+
+$(TARGET_DIR)/%/Contents/PkgInfo: $(DPF_PATH)/utils/plugin.vst/Contents/PkgInfo
+ -@mkdir -p $(shell dirname $@)
+ $(SILENT)cp $< $@
+
+$(TARGET_DIR)/%/Resources/empty.lproj: $(DPF_PATH)/utils/plugin.vst/Contents/Resources/empty.lproj
+ -@mkdir -p $(shell dirname $@)
+ $(SILENT)cp $< $@
# ---------------------------------------------------------------------------------------------------------------------
@@ -386,11 +586,15 @@ endif
-include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d
+-include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d
+-include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d
+-include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d
+-include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d
# ---------------------------------------------------------------------------------------------------------------------
diff --git a/README.md b/README.md
index 0392faa0..95003a9c 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ DPF is designed to make development of new plugins an easy and enjoyable task.
The framework facilitates exporting various different plugin formats from the same code-base.
-DPF can build for LADSPA, DSSI, LV2 and VST formats.
+DPF can build for LADSPA, DSSI, LV2, VST2 and VST3 formats.
All current plugin format implementations are complete.
A JACK/Standalone mode is also available, allowing you to quickly test plugins.
@@ -19,6 +19,12 @@ Getting time information from the host is possible.
It uses the same format as the JACK Transport API, making porting some code easier.
+## Licensing
+
+DPF is released under ISC, which basically means you can do whatever you want as long as you credit the original authors.
+Some plugin formats may have additional restrictions, see [LICENSING.md](LICENSING.md) for details.
+
+
## Help and documentation
Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues).
diff --git a/cmake/DPF-plugin.cmake b/cmake/DPF-plugin.cmake
index 0253dbca..858c49c8 100644
--- a/cmake/DPF-plugin.cmake
+++ b/cmake/DPF-plugin.cmake
@@ -22,7 +22,7 @@
# add_subdirectory(DPF)
#
# dpf_add_plugin(MyPlugin
-# TARGETS lv2 vst2
+# TARGETS lv2 vst2 vst3
# UI_TYPE opengl
# FILES_DSP
# src/MyPlugin.cpp
@@ -71,7 +71,7 @@ include(CMakeParseArguments)
#
# `TARGETS` ...
# a list of one of more of the following target types:
-# `jack`, `ladspa`, `dssi`, `lv2`, `vst2`
+# `jack`, `ladspa`, `dssi`, `lv2`, `vst2`, `vst3`
#
# `UI_TYPE`
# the user interface type: `opengl` (default), `cairo`
@@ -122,6 +122,10 @@ function(dpf_add_plugin NAME)
target_include_directories("${NAME}" PUBLIC
"${DPF_ROOT_DIR}/distrho")
+ if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
+ target_link_libraries("${NAME}" PRIVATE "dl")
+ endif()
+
if(_dgl_library)
# make sure that all code will see DGL_* definitions
target_link_libraries("${NAME}" PUBLIC
@@ -135,7 +139,10 @@ function(dpf_add_plugin NAME)
if(_dgl_library)
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI})
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library})
- # add the files containing Objective-C classes, recompiled under namespace
+ 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")
else()
add_library("${NAME}-ui" INTERFACE)
@@ -153,6 +160,8 @@ function(dpf_add_plugin NAME)
dpf__build_lv2("${NAME}" "${_dgl_library}" "${_dpf_plugin_MONOLITHIC}")
elseif(_target STREQUAL "vst2")
dpf__build_vst2("${NAME}" "${_dgl_library}")
+ elseif(_target STREQUAL "vst3")
+ dpf__build_vst3("${NAME}" "${_dgl_library}")
else()
message(FATAL_ERROR "Unrecognized target type for plugin: ${_target}")
endif()
@@ -183,11 +192,6 @@ function(dpf__build_jack NAME DGL_LIBRARY)
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
OUTPUT_NAME "${NAME}")
- # Note: libjack will be linked at runtime
- if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
- target_link_libraries("${NAME}-jack" PRIVATE "dl")
- endif()
-
# for RtAudio native fallback
if(APPLE)
find_library(APPLE_COREAUDIO_FRAMEWORK "CoreAudio")
@@ -199,13 +203,14 @@ endfunction()
# dpf__build_ladspa
# ------------------------------------------------------------------------------
#
-# Add build rules for a DSSI plugin.
+# Add build rules for a LADSPA plugin.
#
function(dpf__build_ladspa NAME)
dpf__create_dummy_source_list(_no_srcs)
dpf__add_module("${NAME}-ladspa" ${_no_srcs})
dpf__add_plugin_main("${NAME}-ladspa" "ladspa")
+ dpf__set_module_export_list("${NAME}-ladspa" "ladspa")
target_link_libraries("${NAME}-ladspa" PRIVATE "${NAME}-dsp")
set_target_properties("${NAME}-ladspa" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
@@ -234,6 +239,7 @@ function(dpf__build_dssi NAME DGL_LIBRARY)
dpf__add_module("${NAME}-dssi" ${_no_srcs})
dpf__add_plugin_main("${NAME}-dssi" "dssi")
+ dpf__set_module_export_list("${NAME}-dssi" "dssi")
target_link_libraries("${NAME}-dssi" PRIVATE "${NAME}-dsp")
set_target_properties("${NAME}-dssi" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
@@ -257,13 +263,18 @@ endfunction()
# dpf__build_lv2
# ------------------------------------------------------------------------------
#
-# Add build rules for a LV2 plugin.
+# Add build rules for an LV2 plugin.
#
function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC)
dpf__create_dummy_source_list(_no_srcs)
dpf__add_module("${NAME}-lv2" ${_no_srcs})
dpf__add_plugin_main("${NAME}-lv2" "lv2")
+ if(DGL_LIBRARY AND MONOLITHIC)
+ dpf__set_module_export_list("${NAME}-lv2" "lv2")
+ else()
+ dpf__set_module_export_list("${NAME}-lv2" "lv2-dsp")
+ endif()
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-dsp")
set_target_properties("${NAME}-lv2" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>"
@@ -280,6 +291,7 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC)
else()
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs})
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${DGL_LIBRARY}")
+ dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui")
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui")
set_target_properties("${NAME}-lv2-ui" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>"
@@ -293,7 +305,7 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC)
add_dependencies("${NAME}-lv2" lv2_ttl_generator)
add_custom_command(TARGET "${NAME}-lv2" POST_BUILD
- COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR}
+ COMMAND
"$"
"$"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2"
@@ -311,6 +323,7 @@ function(dpf__build_vst2 NAME DGL_LIBRARY)
dpf__add_module("${NAME}-vst2" ${_no_srcs})
dpf__add_plugin_main("${NAME}-vst2" "vst2")
dpf__add_ui_main("${NAME}-vst2" "vst2" "${DGL_LIBRARY}")
+ dpf__set_module_export_list("${NAME}-vst2" "vst2")
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui")
set_target_properties("${NAME}-vst2" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
@@ -330,6 +343,95 @@ function(dpf__build_vst2 NAME DGL_LIBRARY)
endif()
endfunction()
+# dpf__determine_vst3_package_architecture
+# ------------------------------------------------------------------------------
+#
+# Determines the package architecture for a VST3 plugin target.
+#
+function(dpf__determine_vst3_package_architecture OUTPUT_VARIABLE)
+ # if set by variable, override the detection
+ if(DPF_VST3_ARCHITECTURE)
+ set("${OUTPUT_VARIABLE}" "${DPF_VST3_ARCHITECTURE}" PARENT_SCOPE)
+ return()
+ endif()
+
+ # not used on Apple, which supports universal binary
+ if(APPLE)
+ set("${OUTPUT_VARIABLE}" "universal" PARENT_SCOPE)
+ return()
+ endif()
+
+ # identify the target processor (special case of MSVC, problematic sometimes)
+ if(MSVC)
+ set(vst3_system_arch "${MSVC_CXX_ARCHITECTURE_ID}")
+ else()
+ set(vst3_system_arch "${CMAKE_SYSTEM_PROCESSOR}")
+ endif()
+
+ # transform the processor name to a format that VST3 recognizes
+ if(vst3_system_arch MATCHES "^(x86_64|amd64|AMD64|x64|X64)$")
+ set(vst3_package_arch "x86_64")
+ elseif(vst3_system_arch MATCHES "^(i.86|x86|X86)$")
+ if(WIN32)
+ set(vst3_package_arch "x86")
+ else()
+ set(vst3_package_arch "i386")
+ endif()
+ elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*)$")
+ set(vst3_package_arch "${vst3_system_arch}")
+ elseif(vst3_system_arch MATCHES "^(aarch64)$")
+ set(vst3_package_arch "aarch64")
+ else()
+ message(FATAL_ERROR "We don't know this architecture for VST3: ${vst3_system_arch}.")
+ endif()
+
+ # TODO: the detections for Windows arm/arm64 when supported
+
+ set("${OUTPUT_VARIABLE}" "${vst3_package_arch}" PARENT_SCOPE)
+endfunction()
+
+# dpf__build_vst3
+# ------------------------------------------------------------------------------
+#
+# Add build rules for a VST3 plugin.
+#
+function(dpf__build_vst3 NAME DGL_LIBRARY)
+ dpf__determine_vst3_package_architecture(vst3_arch)
+
+ dpf__create_dummy_source_list(_no_srcs)
+
+ dpf__add_module("${NAME}-vst3" ${_no_srcs})
+ dpf__add_plugin_main("${NAME}-vst3" "vst3")
+ dpf__add_ui_main("${NAME}-vst3" "vst3" "${DGL_LIBRARY}")
+ dpf__set_module_export_list("${NAME}-vst3" "vst3")
+ target_link_libraries("${NAME}-vst3" PRIVATE "${NAME}-dsp" "${NAME}-ui")
+ set_target_properties("${NAME}-vst3" PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst3/$<0:>"
+ OUTPUT_NAME "${NAME}"
+ PREFIX "")
+
+ if(APPLE)
+ set_target_properties("${NAME}-vst3" PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/MacOS/$<0:>"
+ SUFFIX "")
+ elseif(WIN32)
+ set_target_properties("${NAME}-vst3" PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-win/$<0:>" SUFFIX ".vst3")
+ else()
+ set_target_properties("${NAME}-vst3" PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-linux/$<0:>")
+ endif()
+
+ if(APPLE)
+ # Uses the same macOS bundle template as VST2
+ set(INFO_PLIST_PROJECT_NAME "${NAME}")
+ configure_file("${DPF_ROOT_DIR}/utils/plugin.vst/Contents/Info.plist"
+ "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/Info.plist" @ONLY)
+ file(COPY "${DPF_ROOT_DIR}/utils/plugin.vst/Contents/PkgInfo"
+ DESTINATION "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents")
+ endif()
+endfunction()
+
# dpf__add_dgl_cairo
# ------------------------------------------------------------------------------
#
@@ -366,9 +468,9 @@ function(dpf__add_dgl_cairo)
if(NOT APPLE)
target_sources(dgl-cairo PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
- else() # Note: macOS pugl will be built as part of DistrhoUI_macOS.mm
- #target_sources(dgl-opengl PRIVATE
- # "${DPF_ROOT_DIR}/dgl/src/pugl.mm")
+ else()
+ target_sources(dgl-opengl PRIVATE
+ "${DPF_ROOT_DIR}/dgl/src/pugl.mm")
endif()
target_include_directories(dgl-cairo PUBLIC
"${DPF_ROOT_DIR}/dgl")
@@ -428,9 +530,9 @@ function(dpf__add_dgl_opengl)
if(NOT APPLE)
target_sources(dgl-opengl PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
- else() # Note: macOS pugl will be built as part of DistrhoUI_macOS.mm
- #target_sources(dgl-opengl PRIVATE
- # "${DPF_ROOT_DIR}/dgl/src/pugl.mm")
+ else()
+ target_sources(dgl-opengl PRIVATE
+ "${DPF_ROOT_DIR}/dgl/src/pugl.mm")
endif()
target_include_directories(dgl-opengl PUBLIC
"${DPF_ROOT_DIR}/dgl")
@@ -454,19 +556,12 @@ endfunction()
# dpf__add_plugin_specific_ui_sources
# ------------------------------------------------------------------------------
#
-# Compile plugin-specific UI sources into the target designated by the given
-# name. There are some special considerations here:
-# - On most platforms, sources can be compiled only once, as part of DGL;
-# - On macOS, for any sources which define Objective-C interfaces, these must
-# be recompiled for each plugin under a unique namespace. In this case, the
-# name must be a plugin-specific identifier, and it will be used for computing
-# the unique ID along with the project version.
+# Compile system specific files, for now it is just Objective-C code
+#
function(dpf__add_plugin_specific_ui_sources NAME)
if(APPLE)
target_sources("${NAME}" PRIVATE
"${DPF_ROOT_DIR}/distrho/DistrhoUI_macOS.mm")
- string(SHA256 _hash "${NAME}:${PROJECT_VERSION}")
- target_compile_definitions("${NAME}" PUBLIC "PUGL_NAMESPACE=${_hash}")
endif()
endfunction()
@@ -494,22 +589,22 @@ function(dpf__add_dgl_system_libs)
target_include_directories(dgl-system-libs INTERFACE "${X11_INCLUDE_DIR}")
target_link_libraries(dgl-system-libs INTERFACE "${X11_X11_LIB}")
target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_X11")
+ if(X11_Xcursor_FOUND)
+ target_link_libraries(dgl-system-libs INTERFACE "${X11_Xcursor_LIB}")
+ target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XCURSOR")
+ endif()
if(X11_Xext_FOUND)
target_link_libraries(dgl-system-libs INTERFACE "${X11_Xext_LIB}")
target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XEXT")
endif()
- if(X11_XSync_FOUND)
- target_link_libraries(dgl-system-libs INTERFACE "${X11_XSync_LIB}")
- target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XSYNC")
- endif()
if(X11_Xrandr_FOUND)
target_link_libraries(dgl-system-libs INTERFACE "${X11_Xrandr_LIB}")
target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XRANDR")
endif()
- #if(X11_Xcursor_FOUND)
- # target_link_libraries(dgl-system-libs INTERFACE "${X11_Xcursor_LIB}")
- # target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XCURSOR")
- #endif()
+ if(X11_XSync_FOUND)
+ target_link_libraries(dgl-system-libs INTERFACE "${X11_XSync_LIB}")
+ target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_XSYNC")
+ endif()
endif()
if(MSVC)
@@ -566,6 +661,24 @@ function(dpf__add_static_library NAME)
dpf__set_target_defaults("${NAME}")
endfunction()
+# dpf__set_module_export_list
+# ------------------------------------------------------------------------------
+#
+# Applies a list of exported symbols to the module target.
+#
+function(dpf__set_module_export_list NAME EXPORTS)
+ if(WIN32)
+ target_sources("${NAME}" PRIVATE "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.def")
+ elseif(APPLE)
+ set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS
+ "-Xlinker" "-exported_symbols_list"
+ "-Xlinker" "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.exp")
+ else()
+ set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS
+ "-Xlinker" "--version-script=${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.version")
+ endif()
+endfunction()
+
# dpf__set_target_defaults
# ------------------------------------------------------------------------------
#
diff --git a/dgl/Application.hpp b/dgl/Application.hpp
index 0979987a..ed25a64b 100644
--- a/dgl/Application.hpp
+++ b/dgl/Application.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -19,6 +19,12 @@
#include "Base.hpp"
+#ifdef DISTRHO_NAMESPACE
+START_NAMESPACE_DISTRHO
+class PluginApplication;
+END_NAMESPACE_DISTRHO
+#endif
+
START_NAMESPACE_DGL
// --------------------------------------------------------------------------------------------------------------------
@@ -33,7 +39,7 @@ START_NAMESPACE_DGL
Unless stated otherwise, functions within this class are not thread-safe.
*/
-class Application
+class DISTRHO_API Application
{
public:
/**
@@ -80,6 +86,15 @@ public:
*/
bool isStandalone() const noexcept;
+ /**
+ Return the time in seconds.
+
+ This is a monotonically increasing clock with high resolution.@n
+ The returned time is only useful to compare against other times returned by this function,
+ its absolute value has no meaning.
+ */
+ double getTime() const;
+
/**
Add a callback function to be triggered on every idle cycle.
You can add more than one, and remove them at anytime with removeIdleCallback().
@@ -94,7 +109,7 @@ public:
void removeIdleCallback(IdleCallback* callback);
/**
- Set the class name of the application.
+ Get the class name of the application.
This is a stable identifier for the application, used as the window class/instance name on X11 and Windows.
It is not displayed to the user, but can be used in scripts and by window managers,
@@ -102,12 +117,21 @@ public:
Plugins created with DPF have their class name automatically set based on DGL_NAMESPACE and plugin name.
*/
+ const char* getClassName() const noexcept;
+
+ /**
+ Set the class name of the application.
+ @see getClassName
+ */
void setClassName(const char* name);
private:
struct PrivateData;
PrivateData* const pData;
friend class Window;
+ #ifdef DISTRHO_NAMESPACE
+ friend class DISTRHO_NAMESPACE::PluginApplication;
+ #endif
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application)
};
diff --git a/dgl/Base.hpp b/dgl/Base.hpp
index d726c6fc..1ecdb64d 100644
--- a/dgl/Base.hpp
+++ b/dgl/Base.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -49,16 +49,16 @@ enum Modifier {
/**
Keyboard key codepoints.
- All keys are identified by a Unicode code point in PuglEventKey::key. This
- enumeration defines constants for special keys that do not have a standard
- code point, and some convenience constants for control characters. Note
- that all keys are handled in the same way, this enumeration is just for
+ All keys are identified by a Unicode code point in Widget::KeyboardEvent::key.
+ This enumeration defines constants for special keys that do not have a standard
+ code point, and some convenience constants for control characters.
+ Note that all keys are handled in the same way, this enumeration is just for
convenience when writing hard-coded key bindings.
Keys that do not have a standard code point use values in the Private Use
- Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications
- must take care to not interpret these values beyond key detection, the
- mapping used here is arbitrary and specific to DPF.
+ Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`).
+ Applications must take care to not interpret these values beyond key detection,
+ the mapping used here is arbitrary and specific to DPF.
*/
enum Key {
// Convenience symbols for ASCII control characters
@@ -116,7 +116,7 @@ enum Key {
/**
Common flags for all events.
*/
-enum Flag {
+enum EventFlag {
kFlagSendEvent = 1, ///< Event is synthetic
kFlagIsHint = 2 ///< Event is a hint (not direct user input)
};
@@ -130,6 +130,46 @@ enum CrossingMode {
kCrossingUngrab ///< Crossing due to a grab release
};
+/**
+ A mouse button.
+
+ Mouse button numbers start from 1, and are ordered: primary, secondary, middle.
+ So, on a typical right-handed mouse, the button numbers are:
+
+ Left: 1
+ Right: 2
+ Middle (often a wheel): 3
+
+ Higher button numbers are reported in the same order they are represented on the system.
+ There is no universal standard here, but buttons 4 and 5 are typically a pair of buttons or a rocker,
+ which are usually bound to "back" and "forward" operations.
+
+ Note that these numbers may differ from those used on the underlying
+ platform, since they are manipulated to provide a consistent portable API.
+*/
+enum MouseButton {
+ kMouseButtonLeft = 1,
+ kMouseButtonRight,
+ kMouseButtonMiddle,
+};
+
+/**
+ A mouse cursor type.
+
+ This is a portable subset of mouse cursors that exist on X11, MacOS, and Windows.
+*/
+enum MouseCursor {
+ kMouseCursorArrow, ///< Default pointing arrow
+ kMouseCursorCaret, ///< Caret (I-Beam) for text entry
+ kMouseCursorCrosshair, ///< Cross-hair
+ kMouseCursorHand, ///< Hand with a pointing finger
+ kMouseCursorNotAllowed, ///< Operation not allowed
+ kMouseCursorLeftRight, ///< Left/right arrow for horizontal resize
+ kMouseCursorUpDown, ///< Up/down arrow for vertical resize
+ kMouseCursorDiagonal, ///< Top-left to bottom-right arrow for diagonal resize
+ kMouseCursorAntiDiagonal ///< Bottom-left to top-right arrow for diagonal resize
+};
+
/**
Scroll direction.
@@ -138,11 +178,29 @@ enum CrossingMode {
while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads.
*/
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
+};
+
+/**
+ A clipboard data offer.
+ @see Window::onClipboardDataOffer
+*/
+struct ClipboardDataOffer {
+ /**
+ The id of this data offer.
+ @note The value 0 is reserved for null/invalid.
+ */
+ uint32_t id;
+
+ /**
+ The type of this data offer.
+ Usually a MIME type, but may also be another platform-specific type identifier.
+ */
+ const char* type;
};
// --------------------------------------------------------------------------------------------------------------------
diff --git a/dgl/Cairo.hpp b/dgl/Cairo.hpp
index 567aa63f..87970c99 100644
--- a/dgl/Cairo.hpp
+++ b/dgl/Cairo.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -20,7 +20,7 @@
#include "ImageBase.hpp"
#include "ImageBaseWidgets.hpp"
-#include
+#include
START_NAMESPACE_DGL
@@ -151,7 +151,7 @@ public:
/**
Destructor.
*/
- virtual ~CairoBaseWidget() {}
+ ~CairoBaseWidget() override {}
protected:
/**
diff --git a/dgl/EventHandlers.hpp b/dgl/EventHandlers.hpp
index dddeb427..a460440e 100644
--- a/dgl/EventHandlers.hpp
+++ b/dgl/EventHandlers.hpp
@@ -52,7 +52,7 @@ public:
};
explicit ButtonEventHandler(SubWidget* self);
- ~ButtonEventHandler();
+ virtual ~ButtonEventHandler();
bool isActive() noexcept;
void setActive(bool active, bool sendCallback) noexcept;
@@ -117,7 +117,7 @@ public:
explicit KnobEventHandler(SubWidget* self);
explicit KnobEventHandler(SubWidget* self, const KnobEventHandler& other);
KnobEventHandler& operator=(const KnobEventHandler& other);
- ~KnobEventHandler();
+ virtual ~KnobEventHandler();
// returns raw value, is assumed to be scaled if using log
float getValue() const noexcept;
@@ -154,6 +154,15 @@ private:
struct PrivateData;
PrivateData* const pData;
+ /* not for use */
+#ifdef DISTRHO_PROPER_CPP11_SUPPORT
+ KnobEventHandler(KnobEventHandler& other) = delete;
+ KnobEventHandler(const KnobEventHandler& other) = delete;
+#else
+ KnobEventHandler(KnobEventHandler& other);
+ KnobEventHandler(const KnobEventHandler& other);
+#endif
+
DISTRHO_LEAK_DETECTOR(KnobEventHandler)
};
diff --git a/examples/ImguiSimpleGain/ImGuiSrc.cpp b/dgl/FileBrowserDialog.hpp
similarity index 60%
rename from examples/ImguiSimpleGain/ImGuiSrc.cpp
rename to dgl/FileBrowserDialog.hpp
index ad4c106c..05c53e04 100644
--- a/examples/ImguiSimpleGain/ImGuiSrc.cpp
+++ b/dgl/FileBrowserDialog.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2021 Jean Pierre Cimalando
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -14,22 +14,15 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include
-#if !defined(IMGUI_GL2) && !defined(IMGUI_GL3)
-# define IMGUI_GL2 1
-#endif
-#if defined(IMGUI_GL2)
-# include
-#elif defined(IMGUI_GL3)
-# include
-#endif
+#ifndef DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
+#define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
-#include
-#include
-#include
-#include
-#if defined(IMGUI_GL2)
-#include
-#elif defined(IMGUI_GL3)
-#include
-#endif
+#include "Base.hpp"
+
+START_NAMESPACE_DGL
+
+#include "../distrho/extra/FileBrowserDialogImpl.hpp"
+
+END_NAMESPACE_DGL
+
+#endif // DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
diff --git a/dgl/ImageBase.hpp b/dgl/ImageBase.hpp
index 36c2ab28..e7e84792 100644
--- a/dgl/ImageBase.hpp
+++ b/dgl/ImageBase.hpp
@@ -39,7 +39,7 @@ enum ImageFormat {
It is an abstract class that provides the common methods to build on top.
Cairo and OpenGL Image classes are based upon this one.
- @see Image
+ @see CairoImage, OpenGLImage
*/
class ImageBase
{
diff --git a/dgl/ImageBaseWidgets.hpp b/dgl/ImageBaseWidgets.hpp
index 44011a92..1a4fbbea 100644
--- a/dgl/ImageBaseWidgets.hpp
+++ b/dgl/ImageBaseWidgets.hpp
@@ -25,13 +25,36 @@ START_NAMESPACE_DGL
// --------------------------------------------------------------------------------------------------------------------
+/**
+ DGL Image About Window class.
+
+ This is a Window attached (transient) to another Window that simply shows an Image as its content.
+ It is typically used for "about this project" style pop-up Windows.
+
+ Pressing 'Esc' or clicking anywhere on the window will automatically close it.
+
+ @see CairoImageAboutWindow, OpenGLImageAboutWindow, Window::runAsModal(bool)
+ */
template
class ImageBaseAboutWindow : public StandaloneWindow
{
public:
- explicit ImageBaseAboutWindow(Window& parentWindow, const ImageType& image = ImageType());
- explicit ImageBaseAboutWindow(TopLevelWidget* parentTopLevelWidget, const ImageType& image = ImageType());
-
+ /**
+ Constructor taking an existing Window as the parent transient window and an optional image.
+ If @a image is valid, the about window size will match the image size.
+ */
+ explicit ImageBaseAboutWindow(Window& transientParentWindow, const ImageType& image = ImageType());
+
+ /**
+ Constructor taking a top-level-widget's Window as the parent transient window and an optional image.
+ If @a image is valid, the about window size will match the image size.
+ */
+ explicit ImageBaseAboutWindow(TopLevelWidget* topLevelWidget, const ImageType& image = ImageType());
+
+ /**
+ Set a new image to use as background for this window.
+ Window size will adjust to match the image size.
+ */
void setImage(const ImageType& image);
protected:
@@ -47,6 +70,16 @@ private:
// --------------------------------------------------------------------------------------------------------------------
+/**
+ DGL Image Button class.
+
+ This is a typical button, where the drawing comes from a pregenerated set of images.
+ The button can be under "normal", "hover" and "down" states, with one separate image possible for each.
+
+ The event logic for this button comes from the ButtonEventHandler class.
+
+ @see CairoImageButton, OpenGLImageButton
+ */
template
class ImageBaseButton : public SubWidget,
public ButtonEventHandler
@@ -81,6 +114,18 @@ private:
// --------------------------------------------------------------------------------------------------------------------
+/**
+ DGL Image Knob class.
+
+ This is a typical knob/dial, where the drawing comes from a pregenerated image "filmstrip".
+ The knob's "filmstrip" image can be either horizontal or vertical,
+ with the number of steps automatically based on the largest value (ie, horizontal if width>height, vertical if height>width).
+ There are no different images for "hover" or "down" states.
+
+ The event logic for this knob comes from the KnobEventHandler class.
+
+ @see CairoImageKnob, OpenGLImageKnob
+ */
template
class ImageBaseKnob : public SubWidget,
public KnobEventHandler
diff --git a/dgl/Makefile b/dgl/Makefile
index bac32fc9..be92632c 100644
--- a/dgl/Makefile
+++ b/dgl/Makefile
@@ -13,14 +13,10 @@ BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-un
BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include
LINK_FLAGS += $(DGL_LIBS)
-ifeq ($(USE_OPENGL3),true)
-BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3
-endif
-
-# TODO fix these after pugl-upstream is done
-BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers
-ifneq ($(MACOS),true)
-BUILD_CXX_FLAGS += -Wno-narrowing
+ifeq ($(MACOS),true)
+BUILD_CXX_FLAGS += -Wno-deprecated-declarations
+else
+PUGL_EXTRA_FLAGS = -Wno-extra -Wmissing-field-initializers
endif
# ifneq ($(MACOS_OLD),true)
@@ -73,6 +69,18 @@ endif
# ---------------------------------------------------------------------------------------------------------------------
+OBJS_opengl3 = $(OBJS_common) \
+ ../build/dgl/OpenGL.cpp.opengl3.o \
+ ../build/dgl/NanoVG.cpp.opengl3.o
+
+ifeq ($(MACOS),true)
+OBJS_opengl3 += ../build/dgl/pugl.mm.opengl3.o
+else
+OBJS_opengl3 += ../build/dgl/pugl.cpp.opengl3.o
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
+
OBJS_stub = $(OBJS_common)
ifeq ($(MACOS),true)
@@ -116,10 +124,11 @@ endif
all: $(TARGETS)
-cairo: ../build/libdgl-cairo.a
-opengl: ../build/libdgl-opengl.a
-stub: ../build/libdgl-stub.a
-vulkan: ../build/libdgl-vulkan.a
+cairo: ../build/libdgl-cairo.a
+opengl: ../build/libdgl-opengl.a
+opengl3: ../build/libdgl-opengl3.a
+stub: ../build/libdgl-stub.a
+vulkan: ../build/libdgl-vulkan.a
# ---------------------------------------------------------------------------------------------------------------------
@@ -135,6 +144,12 @@ vulkan: ../build/libdgl-vulkan.a
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^
+../build/libdgl-opengl3.a: $(OBJS_opengl3)
+ -@mkdir -p ../build
+ @echo "Creating libdgl-opengl3.a"
+ $(SILENT)rm -f $@
+ $(SILENT)$(AR) crs $@ $^
+
../build/libdgl-stub.a: $(OBJS_stub)
-@mkdir -p ../build
@echo "Creating libdgl-stub.a"
@@ -171,39 +186,63 @@ vulkan: ../build/libdgl-vulkan.a
# ---------------------------------------------------------------------------------------------------------------------
+../build/dgl/pugl.cpp.o: src/pugl.cpp
+ -@mkdir -p ../build/dgl
+ @echo "Compiling $<"
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -o $@
+
+../build/dgl/pugl.mm.o: src/pugl.mm
+ -@mkdir -p ../build/dgl
+ @echo "Compiling $<"
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -ObjC++ -o $@
+
+# ---------------------------------------------------------------------------------------------------------------------
+
../build/dgl/%.cpp.cairo.o: src/%.cpp
-@mkdir -p ../build/dgl
@echo "Compiling $< (Cairo variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@
../build/dgl/%.mm.cairo.o: src/%.mm
-@mkdir -p ../build/dgl
@echo "Compiling $< (Cairo variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -ObjC++ -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -ObjC++ -o $@
# ---------------------------------------------------------------------------------------------------------------------
../build/dgl/%.cpp.opengl.o: src/%.cpp
-@mkdir -p ../build/dgl
@echo "Compiling $< (OpenGL variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@
../build/dgl/%.mm.opengl.o: src/%.mm
-@mkdir -p ../build/dgl
@echo "Compiling $< (OpenGL variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -ObjC++ -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -ObjC++ -o $@
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+../build/dgl/%.cpp.opengl3.o: src/%.cpp
+ -@mkdir -p ../build/dgl
+ @echo "Compiling $< (OpenGL3 variant)"
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -o $@
+
+../build/dgl/%.mm.opengl3.o: src/%.mm
+ -@mkdir -p ../build/dgl
+ @echo "Compiling $< (OpenGL3 variant)"
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -c -ObjC++ -o $@
# ---------------------------------------------------------------------------------------------------------------------
../build/dgl/%.cpp.vulkan.o: src/%.cpp
-@mkdir -p ../build/dgl
@echo "Compiling $< (Vulkan variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -o $@
../build/dgl/%.mm.vulkan.o: src/%.mm
-@mkdir -p ../build/dgl
@echo "Compiling $< (Vulkan variant)"
- $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@
+ $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@
# ---------------------------------------------------------------------------------------------------------------------
@@ -218,6 +257,7 @@ debug:
-include $(OBJS_common:%.o=%.d)
-include $(OBJS_cairo:%.o=%.d)
-include $(OBJS_opengl:%.o=%.d)
+-include $(OBJS_opengl3:%.o=%.d)
-include $(OBJS_stub:%.o=%.d)
-include $(OBJS_vulkan:%.o=%.d)
diff --git a/dgl/NanoVG.hpp b/dgl/NanoVG.hpp
index e1462a5d..bae8f27a 100644
--- a/dgl/NanoVG.hpp
+++ b/dgl/NanoVG.hpp
@@ -23,6 +23,11 @@
#include "TopLevelWidget.hpp"
#include "StandaloneWindow.hpp"
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4661) /* instantiated template classes whose methods are defined elsewhere */
+#endif
+
#ifndef DGL_NO_SHARED_RESOURCES
# define NANOVG_DEJAVU_SANS_TTF "__dpf_dejavusans_ttf__"
#endif
@@ -37,6 +42,15 @@ START_NAMESPACE_DGL
class NanoVG;
+// -----------------------------------------------------------------------
+// Helper methods
+
+/**
+ Create a NanoVG context using the DPF-provided NanoVG library.
+ On Windows this will load a few extra OpenGL functions required for NanoVG to work.
+ */
+NVGcontext* nvgCreateGL(int flags);
+
// -----------------------------------------------------------------------
// NanoImage
@@ -439,6 +453,11 @@ public:
*/
void globalAlpha(float alpha);
+ /**
+ Sets the color tint applied to all rendered shapes.
+ */
+ void globalTint(Color tint);
+
/* --------------------------------------------------------------------
* Transforms */
@@ -582,12 +601,26 @@ public:
NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags);
/**
- Creates image from specified image data.
+ Creates image from specified raw format image data.
+ */
+ NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data,
+ ImageFlags imageFlags, ImageFormat format);
+
+ /**
+ Creates image from specified raw format image data.
+ Overloaded function for convenience.
+ @see ImageFlags
+ */
+ NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data,
+ int imageFlags, ImageFormat format);
+
+ /**
+ Creates image from specified RGBA image data.
*/
NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags);
/**
- Creates image from specified image data.
+ Creates image from specified RGBA image data.
Overloaded function for convenience.
@see ImageFlags
*/
@@ -884,7 +917,7 @@ public:
Constructor for a NanoSubWidget.
@see CreateFlags
*/
- explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS);
+ explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS);
/**
Constructor for a NanoTopLevelWidget.
@@ -893,21 +926,21 @@ public:
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS);
/**
- Constructor for a NanoStandaloneWindow without parent window.
+ Constructor for a NanoStandaloneWindow without transient parent window.
@see CreateFlags
*/
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS);
/**
- Constructor for a NanoStandaloneWindow with parent window.
+ Constructor for a NanoStandaloneWindow with transient parent window.
@see CreateFlags
*/
- explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS);
+ explicit NanoBaseWidget(Application& app, Window& transientParentWindow, int flags = CREATE_ANTIALIAS);
/**
Destructor.
*/
- virtual ~NanoBaseWidget() {}
+ ~NanoBaseWidget() override {}
protected:
/**
@@ -950,4 +983,8 @@ typedef NanoSubWidget NanoWidget;
END_NAMESPACE_DGL
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
#endif // DGL_NANO_WIDGET_HPP_INCLUDED
diff --git a/dgl/OpenGL-include.hpp b/dgl/OpenGL-include.hpp
new file mode 100644
index 00000000..4f4bb0c1
--- /dev/null
+++ b/dgl/OpenGL-include.hpp
@@ -0,0 +1,112 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2021 Filipe Coelho
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DGL_OPENGL_INCLUDE_HPP_INCLUDED
+#define DGL_OPENGL_INCLUDE_HPP_INCLUDED
+
+#include "../distrho/src/DistrhoDefines.h"
+
+// --------------------------------------------------------------------------------------------------------------------
+// Fix OpenGL includes for Windows, based on glfw code (part 1)
+
+#undef DGL_CALLBACK_DEFINED
+#undef DGL_WINGDIAPI_DEFINED
+
+#ifdef DISTRHO_OS_WINDOWS
+
+#ifndef APIENTRY
+# define APIENTRY __stdcall
+#endif // APIENTRY
+
+/* We need WINGDIAPI defined */
+#ifndef WINGDIAPI
+# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)
+# define WINGDIAPI __declspec(dllimport)
+# elif defined(__LCC__)
+# define WINGDIAPI __stdcall
+# else
+# define WINGDIAPI extern
+# endif
+# define DGL_WINGDIAPI_DEFINED
+#endif // WINGDIAPI
+
+/* Some files also need CALLBACK defined */
+#ifndef CALLBACK
+# if defined(_MSC_VER)
+# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS)
+# define CALLBACK __stdcall
+# else
+# define CALLBACK
+# endif
+# else
+# define CALLBACK __stdcall
+# endif
+# define DGL_CALLBACK_DEFINED
+#endif // CALLBACK
+
+#endif // DISTRHO_OS_WINDOWS
+
+// --------------------------------------------------------------------------------------------------------------------
+// OpenGL includes
+
+#ifdef DISTRHO_OS_MAC
+# ifdef DGL_USE_OPENGL3
+# include
+# include
+# else
+# include
+# endif
+#else
+# ifndef DISTRHO_OS_WINDOWS
+# define GL_GLEXT_PROTOTYPES
+# endif
+# ifndef __GLEW_H__
+# include
+# include
+# endif
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+// Missing OpenGL defines
+
+#if defined(GL_BGR_EXT) && !defined(GL_BGR)
+# define GL_BGR GL_BGR_EXT
+#endif
+
+#if defined(GL_BGRA_EXT) && !defined(GL_BGRA)
+# define GL_BGRA GL_BGRA_EXT
+#endif
+
+#ifndef GL_CLAMP_TO_BORDER
+# define GL_CLAMP_TO_BORDER 0x812D
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+// Fix OpenGL includes for Windows, based on glfw code (part 2)
+
+#ifdef DGL_CALLBACK_DEFINED
+# undef CALLBACK
+# undef DGL_CALLBACK_DEFINED
+#endif
+
+#ifdef DGL_WINGDIAPI_DEFINED
+# undef WINGDIAPI
+# undef DGL_WINGDIAPI_DEFINED
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+
+#endif
diff --git a/dgl/OpenGL.hpp b/dgl/OpenGL.hpp
index 67a0ddd2..91da7e3c 100644
--- a/dgl/OpenGL.hpp
+++ b/dgl/OpenGL.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -20,96 +20,7 @@
#include "ImageBase.hpp"
#include "ImageBaseWidgets.hpp"
-// -----------------------------------------------------------------------
-// Fix OpenGL includes for Windows, based on glfw code (part 1)
-
-#undef DGL_CALLBACK_DEFINED
-#undef DGL_WINGDIAPI_DEFINED
-
-#ifdef DISTRHO_OS_WINDOWS
-
-#ifndef APIENTRY
-# define APIENTRY __stdcall
-#endif // APIENTRY
-
-/* We need WINGDIAPI defined */
-#ifndef WINGDIAPI
-# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__)
-# define WINGDIAPI __declspec(dllimport)
-# elif defined(__LCC__)
-# define WINGDIAPI __stdcall
-# else
-# define WINGDIAPI extern
-# endif
-# define DGL_WINGDIAPI_DEFINED
-#endif // WINGDIAPI
-
-/* Some files also need CALLBACK defined */
-#ifndef CALLBACK
-# if defined(_MSC_VER)
-# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS)
-# define CALLBACK __stdcall
-# else
-# define CALLBACK
-# endif
-# else
-# define CALLBACK __stdcall
-# endif
-# define DGL_CALLBACK_DEFINED
-#endif // CALLBACK
-
-/* Most GL/glu.h variants on Windows need wchar_t */
-#include
-
-#endif // DISTRHO_OS_WINDOWS
-
-// -----------------------------------------------------------------------
-// OpenGL includes
-
-#ifdef DISTRHO_OS_MAC
-# ifdef DGL_USE_OPENGL3
-# include
-# include
-# else
-# include
-# endif
-#else
-# ifndef DISTRHO_OS_WINDOWS
-# define GL_GLEXT_PROTOTYPES
-# endif
-# ifndef __GLEW_H__
-# include
-# include
-# endif
-#endif
-
-// -----------------------------------------------------------------------
-// Missing OpenGL defines
-
-#if defined(GL_BGR_EXT) && !defined(GL_BGR)
-# define GL_BGR GL_BGR_EXT
-#endif
-
-#if defined(GL_BGRA_EXT) && !defined(GL_BGRA)
-# define GL_BGRA GL_BGRA_EXT
-#endif
-
-#ifndef GL_CLAMP_TO_BORDER
-# define GL_CLAMP_TO_BORDER 0x812D
-#endif
-
-// -----------------------------------------------------------------------
-// Fix OpenGL includes for Windows, based on glfw code (part 2)
-
-#ifdef DGL_CALLBACK_DEFINED
-# undef CALLBACK
-# undef DGL_CALLBACK_DEFINED
-#endif
-
-#ifdef DGL_WINGDIAPI_DEFINED
-# undef WINGDIAPI
-# undef DGL_WINGDIAPI_DEFINED
-#endif
+#include "OpenGL-include.hpp"
START_NAMESPACE_DGL
@@ -120,6 +31,8 @@ START_NAMESPACE_DGL
*/
struct OpenGLGraphicsContext : GraphicsContext
{
+#ifdef DGL_USE_OPENGL3
+#endif
};
// -----------------------------------------------------------------------
@@ -129,7 +42,11 @@ ImageFormat asDISTRHOImageFormat(const GLenum format)
{
switch (format)
{
+#ifdef DGL_USE_OPENGL3
+ case GL_RED:
+#else
case GL_LUMINANCE:
+#endif
return kImageFormatGrayscale;
case GL_BGR:
return kImageFormatBGR;
@@ -152,7 +69,11 @@ GLenum asOpenGLImageFormat(const ImageFormat format)
case kImageFormatNull:
break;
case kImageFormatGrayscale:
+#ifdef DGL_USE_OPENGL3
+ return GL_RED;
+#else
return GL_LUMINANCE;
+#endif
case kImageFormatBGR:
return GL_BGR;
case kImageFormatBGRA:
@@ -230,11 +151,11 @@ public:
// FIXME this should not be needed
inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA)
- { loadFromMemory(rdata, Size(w, h), fmt); };
+ { loadFromMemory(rdata, Size(w, h), fmt); }
inline void draw(const GraphicsContext& context)
- { drawAt(context, Point(0, 0)); };
+ { drawAt(context, Point(0, 0)); }
inline void drawAt(const GraphicsContext& context, int x, int y)
- { drawAt(context, Point(x, y)); };
+ { drawAt(context, Point(x, y)); }
/**
Constructor using raw image data, specifying an OpenGL image format.
@@ -297,4 +218,4 @@ typedef ImageBaseSwitch OpenGLImageSwitch;
END_NAMESPACE_DGL
-#endif
+#endif // DGL_OPENGL_HPP_INCLUDED
diff --git a/dgl/StandaloneWindow.hpp b/dgl/StandaloneWindow.hpp
index f86e4c39..673a85e6 100644
--- a/dgl/StandaloneWindow.hpp
+++ b/dgl/StandaloneWindow.hpp
@@ -71,6 +71,7 @@ public:
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0)
{ return Window::addIdleCallback(callback, timerFrequencyInMs); }
bool removeIdleCallback(IdleCallback* callback) { return Window::removeIdleCallback(callback); }
+ Application& getApp() const noexcept { return Window::getApp(); }
const GraphicsContext& getGraphicsContext() const noexcept { return Window::getGraphicsContext(); }
double getScaleFactor() const noexcept { return Window::getScaleFactor(); }
void setGeometryConstraints(uint minimumWidth, uint minimumHeight,
diff --git a/dgl/SubWidget.hpp b/dgl/SubWidget.hpp
index eab84b74..eefb4c5a 100644
--- a/dgl/SubWidget.hpp
+++ b/dgl/SubWidget.hpp
@@ -47,7 +47,7 @@ public:
/**
Destructor.
*/
- virtual ~SubWidget();
+ ~SubWidget() override;
/**
Check if this widget contains the point defined by @a x and @a y.
diff --git a/dgl/TopLevelWidget.hpp b/dgl/TopLevelWidget.hpp
index 6c014296..47015a62 100644
--- a/dgl/TopLevelWidget.hpp
+++ b/dgl/TopLevelWidget.hpp
@@ -54,7 +54,7 @@ public:
/**
Destructor.
*/
- virtual ~TopLevelWidget();
+ ~TopLevelWidget() override;
/**
Get the application associated with this top-level widget's window.
@@ -101,13 +101,17 @@ public:
void repaint(const Rectangle& rect) noexcept;
// TODO group stuff after here, convenience functions present in Window class
+ const void* getClipboard(size_t& dataSize);
+ bool setClipboard(const char* mimeType, const void* data, size_t dataSize);
+ bool setCursor(MouseCursor cursor);
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
bool removeIdleCallback(IdleCallback* callback);
double getScaleFactor() const noexcept;
void setGeometryConstraints(uint minimumWidth,
uint minimumHeight,
bool keepAspectRatio = false,
- bool automaticallyScale = false);
+ bool automaticallyScale = false,
+ bool resizeNowIfAutoScaling = true);
DISTRHO_DEPRECATED_BY("getApp()")
Application& getParentApp() const noexcept { return getApp(); }
@@ -117,7 +121,6 @@ public:
protected:
bool onKeyboard(const KeyboardEvent&) override;
- bool onSpecial(const SpecialEvent&) override;
bool onCharacterInput(const CharacterInputEvent&) override;
bool onMouse(const MouseEvent&) override;
bool onMotion(const MotionEvent&) override;
@@ -130,6 +133,8 @@ private:
#ifdef DISTRHO_DEFINES_H_INCLUDED
friend class DISTRHO_NAMESPACE::UI;
#endif
+ /** @internal */
+ virtual void requestSizeChange(uint width, uint height);
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopLevelWidget)
};
diff --git a/dgl/Widget.hpp b/dgl/Widget.hpp
index 904e0057..38a49b1f 100644
--- a/dgl/Widget.hpp
+++ b/dgl/Widget.hpp
@@ -56,17 +56,16 @@ public:
/**
Base event data.
These are the fields present on all Widget events.
-
- @a mod Currently active keyboard modifiers, @see Modifier.
- @a mod Event flags, @see Flag.
- @a time Event timestamp (if any).
*/
struct BaseEvent {
+ /** Currently active keyboard modifiers. @see Modifier */
uint mod;
+ /** Event flags. @see EventFlag */
uint flags;
+ /** Event timestamp (if any). */
uint time;
- /** Constructor */
+ /** Constructor for default/null values */
BaseEvent() noexcept : mod(0x0), flags(0x0), time(0) {}
/** Destuctor */
virtual ~BaseEvent() noexcept {}
@@ -86,17 +85,17 @@ public:
Alternatively, the raw @a keycode can be used to work directly with physical keys,
but note that this value is not portable and differs between platforms and hardware.
- @a press True if the key was pressed, false if released.
- @a key Unicode point of the key pressed.
- @a keycode Raw keycode.
@see onKeyboard
*/
struct KeyboardEvent : BaseEvent {
+ /** True if the key was pressed, false if released. */
bool press;
+ /** Unicode point of the key pressed. */
uint key;
+ /** Raw keycode. */
uint keycode;
- /** Constructor */
+ /** Constructor for default/null values */
KeyboardEvent() noexcept
: BaseEvent(),
press(false),
@@ -107,18 +106,14 @@ public:
/**
Special keyboard event.
- This event allows the use of keys that do not have unicode points.
- Note that some are non-printable keys.
-
- @a press True if the key was pressed, false if released.
- @a key The key pressed.
- @see onSpecial
+ DEPRECATED This used to be part of DPF due to pugl, but now deprecated and simply non-functional.
+ All events go through KeyboardEvent or CharacterInputEvent, use those instead.
*/
- struct SpecialEvent : BaseEvent {
+ struct DISTRHO_DEPRECATED_BY("KeyboardEvent") SpecialEvent : BaseEvent {
bool press;
- Key key;
+ Key key;
- /** Constructor */
+ /** Constructor for default/null values */
SpecialEvent() noexcept
: BaseEvent(),
press(false),
@@ -135,17 +130,17 @@ public:
so there is not necessarily a direct correspondence between text events and physical key presses.
For example, with some input methods a sequence of several key presses will generate a single character.
- @a keycode Raw key code.
- @a character Unicode character code.
- @a string UTF-8 string.
@see onCharacterInput
*/
struct CharacterInputEvent : BaseEvent {
+ /** Raw key code. */
uint keycode;
+ /** Unicode character code. */
uint character;
+ /** UTF-8 string. */
char string[8];
- /** Constructor */
+ /** Constructor for default/null values */
CharacterInputEvent() noexcept
: BaseEvent(),
keycode(0),
@@ -159,20 +154,19 @@ public:
/**
Mouse press or release event.
-
- @a button The button number starting from 1 (1 = left, 2 = middle, 3 = right).
- @a press True if the button was pressed, false if released.
- @a pos The widget-relative coordinates of the pointer.
- @a absolutePos The absolute coordinates of the pointer.
@see onMouse
*/
struct MouseEvent : BaseEvent {
+ /** The button number starting from 1. @see MouseButton */
uint button;
+ /** True if the button was pressed, false if released. */
bool press;
+ /** The widget-relative coordinates of the pointer. */
Point pos;
+ /** The absolute coordinates of the pointer. */
Point absolutePos;
- /** Constructor */
+ /** Constructor for default/null values */
MouseEvent() noexcept
: BaseEvent(),
button(0),
@@ -183,16 +177,15 @@ public:
/**
Mouse motion event.
-
- @a pos The widget-relative coordinates of the pointer.
- @a absolutePos The absolute coordinates of the pointer.
@see onMotion
*/
struct MotionEvent : BaseEvent {
+ /** The widget-relative coordinates of the pointer. */
Point pos;
+ /** The absolute coordinates of the pointer. */
Point absolutePos;
- /** Constructor */
+ /** Constructor for default/null values */
MotionEvent() noexcept
: BaseEvent(),
pos(0.0, 0.0),
@@ -208,19 +201,19 @@ public:
Some systems and devices support finer resolution and/or higher values for fast scrolls,
so programs should handle any value gracefully.
- @a pos The widget-relative coordinates of the pointer.
- @a absolutePos The absolute coordinates of the pointer.
- @a delta The scroll distance.
- @a direction The direction of the scroll or "smooth".
@see onScroll
*/
struct ScrollEvent : BaseEvent {
+ /** The widget-relative coordinates of the pointer. */
Point pos;
+ /** The absolute coordinates of the pointer. */
Point absolutePos;
+ /** The scroll distance. */
Point delta;
+ /** The direction of the scroll or "smooth". */
ScrollDirection direction;
- /** Constructor */
+ /** Constructor for default/null values */
ScrollEvent() noexcept
: BaseEvent(),
pos(0.0, 0.0),
@@ -231,15 +224,15 @@ public:
/**
Resize event.
- @a size The new widget size.
- @a oldSize The previous size, may be null.
@see onResize
*/
struct ResizeEvent {
+ /** The new widget size. */
Size size;
+ /** The previous size, can be null. */
Size oldSize;
- /** Constructor */
+ /** Constructor for default/null values */
ResizeEvent() noexcept
: size(0, 0),
oldSize(0, 0) {}
@@ -247,15 +240,15 @@ public:
/**
Widget position changed event.
- @a pos The new absolute position of the widget.
- @a oldPos The previous absolute position of the widget.
@see onPositionChanged
*/
struct PositionChangedEvent {
+ /** The new absolute position of the widget. */
Point pos;
+ /** The previous absolute position of the widget. */
Point oldPos;
- /** Constructor */
+ /** Constructor for default/null values */
PositionChangedEvent() noexcept
: pos(0, 0),
oldPos(0, 0) {}
@@ -398,12 +391,6 @@ protected:
*/
virtual bool onKeyboard(const KeyboardEvent&);
- /**
- A function called when a special key is pressed or released.
- @return True to stop event propagation, false otherwise.
- */
- virtual bool onSpecial(const SpecialEvent&);
-
/**
A function called when an UTF-8 character is received.
@return True to stop event propagation, false otherwise.
@@ -433,6 +420,24 @@ protected:
*/
virtual void onResize(const ResizeEvent&);
+ /**
+ A function called when a special key is pressed or released.
+ DEPRECATED use onKeyboard or onCharacterInput
+ */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ virtual bool onSpecial(const SpecialEvent&) { return false; }
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
+# pragma GCC diagnostic pop
+#endif
+
private:
struct PrivateData;
PrivateData* const pData;
diff --git a/dgl/Window.hpp b/dgl/Window.hpp
index 744f7f2d..c32ba0fd 100644
--- a/dgl/Window.hpp
+++ b/dgl/Window.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -19,6 +19,18 @@
#include "Geometry.hpp"
+#ifndef DGL_FILE_BROWSER_DISABLED
+# include "FileBrowserDialog.hpp"
+#endif
+
+#include
+
+#ifdef DISTRHO_NAMESPACE
+START_NAMESPACE_DISTRHO
+class PluginWindow;
+END_NAMESPACE_DISTRHO
+#endif
+
START_NAMESPACE_DGL
class Application;
@@ -47,60 +59,11 @@ class TopLevelWidget;
...
*/
-class Window
+class DISTRHO_API Window
{
struct PrivateData;
public:
-#ifndef DGL_FILE_BROWSER_DISABLED
- /**
- File browser options.
- @see Window::openFileBrowser
- */
- struct FileBrowserOptions {
- /**
- File browser button state.
- This allows to customize the behaviour of the file browse dialog buttons.
- Note these are merely hints, not all systems support them.
- */
- enum ButtonState {
- kButtonInvisible,
- kButtonVisibleUnchecked,
- kButtonVisibleChecked,
- };
-
- /** Start directory, uses current working directory if null */
- const char* startDir;
- /** File browser dialog window title, uses "FileBrowser" if null */
- const char* title;
- // TODO file filter
-
- /**
- File browser buttons.
- */
- struct Buttons {
- /** Whether to list all files vs only those with matching file extension */
- ButtonState listAllFiles;
- /** Whether to show hidden files */
- ButtonState showHidden;
- /** Whether to show list of places (bookmarks) */
- ButtonState showPlaces;
-
- /** Constructor for default values */
- Buttons()
- : listAllFiles(kButtonVisibleChecked),
- showHidden(kButtonVisibleUnchecked),
- showPlaces(kButtonVisibleChecked) {}
- } buttons;
-
- /** Constructor for default values */
- FileBrowserOptions()
- : startDir(nullptr),
- title(nullptr),
- buttons() {}
- };
-#endif // DGL_FILE_BROWSER_DISABLED
-
/**
Window graphics context as a scoped struct.
This class gives graphics context drawing time to a window's widgets.
@@ -157,10 +120,10 @@ public:
explicit Window(Application& app);
/**
- Constructor for a modal window, by having another window as its parent.
+ Constructor for a modal window, by having another window as its transient parent.
The Application instance must be the same between the 2 windows.
*/
- explicit Window(Application& app, Window& parent);
+ explicit Window(Application& app, Window& transientParentWindow);
/**
Constructor for an embed Window without known size,
@@ -245,6 +208,41 @@ public:
*/
void setResizable(bool resizable);
+ /**
+ Get X offset, typically 0.
+ */
+ int getOffsetX() const noexcept;
+
+ /**
+ Get Y offset, typically 0.
+ */
+ int getOffsetY() const noexcept;
+
+ /**
+ Get offset.
+ */
+ Point getOffset() const noexcept;
+
+ /**
+ Set X offset.
+ */
+ void setOffsetX(int x);
+
+ /**
+ Set Y offset.
+ */
+ void setOffsetY(int y);
+
+ /**
+ Set offset using @a x and @a y values.
+ */
+ void setOffset(int x, int y);
+
+ /**
+ Set offset.
+ */
+ void setOffset(const Point& offset);
+
/**
Get width.
*/
@@ -302,6 +300,39 @@ public:
*/
void setIgnoringKeyRepeat(bool ignore) noexcept;
+ /**
+ Get the clipboard contents.
+
+ This gets the system clipboard contents,
+ which may have been set with setClipboard() or copied from another application.
+
+ Returns the clipboard contents, or null.
+
+ @note By default only "text/plain" mimetype is supported and returned.
+ Override onClipboardDataOffer for supporting other types.
+ */
+ const void* getClipboard(size_t& dataSize);
+
+ /**
+ Set the clipboard contents.
+
+ This sets the system clipboard contents,
+ which can be retrieved with getClipboard() or pasted into other applications.
+
+ If using a string, the use of a null terminator is required (and must be part of dataSize).@n
+ The MIME type of the data "text/plain" is assumed if null is used.
+ */
+ bool setClipboard(const char* mimeType, const void* data, size_t dataSize);
+
+ /**
+ Set the mouse cursor.
+
+ This changes the system cursor that is displayed when the pointer is inside the window.
+ May fail if setting the cursor is not supported on this system,
+ for example if compiled on X11 without Xcursor support.
+ */
+ bool setCursor(MouseCursor cursor);
+
/**
Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
You can add more than one, and remove them at anytime with removeIdleCallback().
@@ -361,7 +392,7 @@ public:
#ifndef DGL_FILE_BROWSER_DISABLED
/**
- Open a file browser dialog with this window as parent.
+ Open a file browser dialog with this window as transient parent.
A few options can be specified to setup the dialog.
If a path is selected, onFileSelected() will be called with the user chosen path.
@@ -369,7 +400,7 @@ public:
This function does not block the event loop.
*/
- bool openFileBrowser(const FileBrowserOptions& options);
+ bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif
/**
@@ -382,6 +413,13 @@ public:
*/
void repaint(const Rectangle& rect) noexcept;
+ /**
+ Render this window's content into a picture file, specified by @a filename.
+ Window must be visible and on screen.
+ Written picture format is PPM.
+ */
+ void renderToPicture(const char* filename);
+
/**
Run this window as a modal, blocking input events from the parent.
Only valid for windows that have been created with another window as parent (as passed in the constructor).
@@ -389,13 +427,28 @@ public:
*/
void runAsModal(bool blockWait = false);
+ /**
+ Get the geometry constraints set for the Window.
+ @see setGeometryConstraints
+ */
+ Size getGeometryConstraints(bool& keepAspectRatio);
+
/**
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
*/
void setGeometryConstraints(uint minimumWidth,
uint minimumHeight,
bool keepAspectRatio = false,
- bool automaticallyScale = false);
+ bool automaticallyScale = false,
+ bool resizeNowIfAutoScaling = true);
+
+ /**
+ Set the transient parent of the window.
+
+ Set this for transient children like dialogs, to have them properly associated with their parent window.
+ This should be not be called for embed windows, or after making the window visible.
+ */
+ void setTransientParent(uintptr_t transientParentWindowHandle);
/** DEPRECATED Use isIgnoringKeyRepeat(). */
DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
@@ -410,6 +463,23 @@ public:
inline void exec(bool blockWait = false) { runAsModal(blockWait); }
protected:
+ /**
+ Get the types available for the data in a clipboard.
+ Must only be called within the context of onClipboardDataOffer.
+ */
+ std::vector getClipboardDataOfferTypes();
+
+ /**
+ A function called when clipboard has data present, possibly with several datatypes.
+ While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer.
+
+ Reimplement and return a non-zero id to accept the clipboard data offer for a particular type.
+ Applications must ignore any type they do not recognize.
+
+ The default implementation accepts the "text/plain" mimetype.
+ */
+ virtual uint32_t onClipboardDataOffer();
+
/**
A function called when the window is attempted to be closed.
Returning true closes the window, which is the default behaviour.
@@ -459,8 +529,10 @@ protected:
private:
PrivateData* const pData;
friend class Application;
- friend class PluginWindow;
friend class TopLevelWidget;
+ #ifdef DISTRHO_NAMESPACE
+ friend class DISTRHO_NAMESPACE::PluginWindow;
+ #endif
/** @internal */
explicit Window(Application& app,
@@ -469,9 +541,10 @@ private:
uint height,
double scaleFactor,
bool resizable,
+ bool isVST3,
bool doPostInit);
- DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window);
+ DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window)
};
// -----------------------------------------------------------------------
diff --git a/dgl/src/Application.cpp b/dgl/src/Application.cpp
index 12191f7a..5fe05dea 100644
--- a/dgl/src/Application.cpp
+++ b/dgl/src/Application.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -16,10 +16,23 @@
#include "ApplicationPrivateData.hpp"
+#if defined(__EMSCRIPTEN__)
+# include
+#elif defined(DISTRHO_OS_MAC)
+# include
+#endif
+
START_NAMESPACE_DGL
// --------------------------------------------------------------------------------------------------------------------
+#ifdef __EMSCRIPTEN__
+static void app_idle(void* const app)
+{
+ static_cast(app)->idle();
+}
+#endif
+
Application::Application(const bool isStandalone)
: pData(new PrivateData(isStandalone)) {}
@@ -37,8 +50,22 @@ void Application::exec(const uint idleTimeInMs)
{
DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,);
+#if defined(__EMSCRIPTEN__)
+ emscripten_set_main_loop_arg(app_idle, this, 0, true);
+#elif defined(DISTRHO_OS_MAC)
+ const CFTimeInterval idleTimeInSecs = static_cast(idleTimeInMs) / 1000;
+
+ while (! pData->isQuitting)
+ {
+ pData->idle(0);
+
+ if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, idleTimeInSecs, true) == kCFRunLoopRunFinished)
+ break;
+ }
+#else
while (! pData->isQuitting)
pData->idle(idleTimeInMs);
+#endif
}
void Application::quit()
@@ -56,6 +83,11 @@ bool Application::isStandalone() const noexcept
return pData->isStandalone;
}
+double Application::getTime() const
+{
+ return pData->getTime();
+}
+
void Application::addIdleCallback(IdleCallback* const callback)
{
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
diff --git a/dgl/src/ApplicationPrivateData.cpp b/dgl/src/ApplicationPrivateData.cpp
index 1de1fc76..ca06a1bb 100644
--- a/dgl/src/ApplicationPrivateData.cpp
+++ b/dgl/src/ApplicationPrivateData.cpp
@@ -45,6 +45,13 @@ static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept
// --------------------------------------------------------------------------------------------------------------------
+const char* Application::getClassName() const noexcept
+{
+ return puglGetClassName(pData->world);
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
Application::PrivateData::PrivateData(const bool standalone)
: world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE,
standalone ? PUGL_WORLD_THREADS : 0x0)),
@@ -60,11 +67,8 @@ Application::PrivateData::PrivateData(const bool standalone)
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);
puglSetWorldHandle(world, this);
+#ifndef __EMSCRIPTEN__
puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE));
-
-#ifdef DISTRHO_OS_MAC
- if (standalone)
- puglMacOSActivateApp();
#endif
}
@@ -118,6 +122,11 @@ void Application::PrivateData::idle(const uint timeoutInMs)
puglUpdate(world, timeoutInSeconds);
}
+ triggerIdleCallbacks();
+}
+
+void Application::PrivateData::triggerIdleCallbacks()
+{
for (std::list::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it)
{
IdleCallback* const idleCallback(*it);
@@ -147,6 +156,13 @@ void Application::PrivateData::quit()
#endif
}
+double Application::PrivateData::getTime() const
+{
+ DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, 0.0);
+
+ return puglGetTime(world);
+}
+
void Application::PrivateData::setClassName(const char* const name)
{
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);
diff --git a/dgl/src/ApplicationPrivateData.hpp b/dgl/src/ApplicationPrivateData.hpp
index e35328d3..0e33c985 100644
--- a/dgl/src/ApplicationPrivateData.hpp
+++ b/dgl/src/ApplicationPrivateData.hpp
@@ -22,6 +22,9 @@
#include
#ifdef DISTRHO_OS_WINDOWS
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
# include
# include
typedef HANDLE d_ThreadHandle;
@@ -30,12 +33,18 @@ typedef HANDLE d_ThreadHandle;
typedef pthread_t d_ThreadHandle;
#endif
+#ifdef DISTRHO_OS_MAC
typedef struct PuglWorldImpl PuglWorld;
+#endif
START_NAMESPACE_DGL
class Window;
+#ifndef DISTRHO_OS_MAC
+typedef struct PuglWorldImpl PuglWorld;
+#endif
+
// --------------------------------------------------------------------------------------------------------------------
struct Application::PrivateData {
@@ -84,10 +93,16 @@ struct Application::PrivateData {
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */
void idle(uint timeoutInMs);
+ /** Run each idle callback without updating pugl world. */
+ void triggerIdleCallbacks();
+
/** Set flag indicating application is quitting, and close all windows in reverse order of registration.
For standalone mode only. */
void quit();
+ /** Get time via pugl */
+ double getTime() const;
+
/** Set pugl world class name. */
void setClassName(const char* name);
diff --git a/dgl/src/Cairo.cpp b/dgl/src/Cairo.cpp
index ebefaa56..1a5b69ec 100644
--- a/dgl/src/Cairo.cpp
+++ b/dgl/src/Cairo.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
* Copyright (C) 2019-2021 Jean Pierre Cimalando
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -384,8 +384,8 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size& s, co
cairo_surface_t* const newsurface = cairo_image_surface_create_for_data(newdata, cairoformat, width, height, stride);
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);
- DISTRHO_SAFE_ASSERT_RETURN(s.getWidth() == cairo_image_surface_get_width(newsurface),);
- DISTRHO_SAFE_ASSERT_RETURN(s.getHeight() == cairo_image_surface_get_height(newsurface),);
+ DISTRHO_SAFE_ASSERT_RETURN(static_cast(s.getWidth()) == cairo_image_surface_get_width(newsurface),);
+ DISTRHO_SAFE_ASSERT_RETURN(static_cast(s.getHeight()) == cairo_image_surface_get_height(newsurface),);
cairo_surface_destroy(surface);
@@ -808,6 +808,13 @@ 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);
diff --git a/dgl/src/Color.cpp b/dgl/src/Color.cpp
index 4aa6b45d..10382fbd 100644
--- a/dgl/src/Color.cpp
+++ b/dgl/src/Color.cpp
@@ -114,10 +114,10 @@ Color::Color(const Color& color1, const Color& color2, const float u) noexcept
interpolate(color2, u);
}
-Color Color::withAlpha(const float alpha) noexcept
+Color Color::withAlpha(const float alpha2) noexcept
{
Color color(*this);
- color.alpha = alpha;
+ color.alpha = alpha2;
return color;
}
diff --git a/dgl/src/Geometry.cpp b/dgl/src/Geometry.cpp
index 44e99185..eb8df6e5 100644
--- a/dgl/src/Geometry.cpp
+++ b/dgl/src/Geometry.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2019 Filipe Coelho
+ * Copyright (C) 2012-2021 Filipe Coelho
*
* 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
@@ -15,8 +15,10 @@
*/
#ifdef _MSC_VER
-// instantiated template classes whose methods are defined elsewhere
-# pragma warning(disable:4661)
+# pragma warning(disable:4661) /* instantiated template classes whose methods are defined elsewhere */
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
#endif
#include "../Geometry.hpp"
diff --git a/dgl/src/ImageBaseWidgets.cpp b/dgl/src/ImageBaseWidgets.cpp
index 039f7f15..bb16f0ce 100644
--- a/dgl/src/ImageBaseWidgets.cpp
+++ b/dgl/src/ImageBaseWidgets.cpp
@@ -22,8 +22,8 @@ START_NAMESPACE_DGL
// --------------------------------------------------------------------------------------------------------------------
template
-ImageBaseAboutWindow::ImageBaseAboutWindow(Window& parentWindow, const ImageType& image)
- : StandaloneWindow(parentWindow.getApp(), parentWindow),
+ImageBaseAboutWindow::ImageBaseAboutWindow(Window& transientParentWindow, const ImageType& image)
+ : StandaloneWindow(transientParentWindow.getApp(), transientParentWindow),
img(image)
{
setResizable(false);
@@ -39,8 +39,8 @@ ImageBaseAboutWindow::ImageBaseAboutWindow(Window& parentWindow, cons
}
template
-ImageBaseAboutWindow::ImageBaseAboutWindow(TopLevelWidget* const parentTopLevelWidget, const ImageType& image)
- : StandaloneWindow(parentTopLevelWidget->getApp(), parentTopLevelWidget->getWindow()),
+ImageBaseAboutWindow::ImageBaseAboutWindow(TopLevelWidget* const topLevelWidget, const ImageType& image)
+ : StandaloneWindow(topLevelWidget->getApp(), topLevelWidget->getWindow()),
img(image)
{
setResizable(false);
diff --git a/dgl/src/NanoVG.cpp b/dgl/src/NanoVG.cpp
index 7b0cf0cc..42c0fcde 100644
--- a/dgl/src/NanoVG.cpp
+++ b/dgl/src/NanoVG.cpp
@@ -54,6 +54,18 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
+# ifdef DGL_USE_NANOVG_FBO
+DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus)
+DGL_EXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer)
+DGL_EXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
+DGL_EXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers)
+DGL_EXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers)
+DGL_EXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D)
+DGL_EXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
+DGL_EXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers)
+DGL_EXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
+DGL_EXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
+# endif
# ifdef DGL_USE_OPENGL3
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
@@ -70,13 +82,15 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
// Include NanoVG OpenGL implementation
//#define STB_IMAGE_STATIC
-#ifdef DGL_USE_OPENGL3
+#if defined(DGL_USE_GLES2)
+# define NANOVG_GLES2_IMPLEMENTATION
+#elif defined(DGL_USE_OPENGL3)
# define NANOVG_GL3_IMPLEMENTATION
#else
# define NANOVG_GL2_IMPLEMENTATION
#endif
-#if defined(DISTRHO_OS_MAC) && defined(NANOVG_GL3_IMPLEMENTATION)
+#if defined(DISTRHO_OS_MAC) && defined(NANOVG_GL2_IMPLEMENTATION)
# define glBindVertexArray glBindVertexArrayAPPLE
# define glDeleteVertexArrays glDeleteVertexArraysAPPLE
# define glGenVertexArrays glGenVertexArraysAPPLE
@@ -84,29 +98,38 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
#include "nanovg/nanovg_gl.h"
+#ifdef DGL_USE_NANOVG_FBO
+# define NANOVG_FBO_VALID 1
+# include "nanovg/nanovg_gl_utils.h"
+#endif
+
#if defined(NANOVG_GL2)
-# define nvgCreateGL nvgCreateGL2
+# define nvgCreateGLfn nvgCreateGL2
# define nvgDeleteGL nvgDeleteGL2
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGL2
# define nvglImageHandle nvglImageHandleGL2
#elif defined(NANOVG_GL3)
-# define nvgCreateGL nvgCreateGL3
+# define nvgCreateGLfn nvgCreateGL3
# define nvgDeleteGL nvgDeleteGL3
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGL3
# define nvglImageHandle nvglImageHandleGL3
#elif defined(NANOVG_GLES2)
-# define nvgCreateGL nvgCreateGLES2
+# define nvgCreateGLfn nvgCreateGLES2
# define nvgDeleteGL nvgDeleteGLES2
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES2
# define nvglImageHandle nvglImageHandleGLES2
#elif defined(NANOVG_GLES3)
-# define nvgCreateGL nvgCreateGLES3
+# define nvgCreateGLfn nvgCreateGLES3
# define nvgDeleteGL nvgDeleteGLES3
# define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES3
# define nvglImageHandle nvglImageHandleGLES3
#endif
-static NVGcontext* nvgCreateGL_helper(int flags)
+// -----------------------------------------------------------------------
+
+START_NAMESPACE_DGL
+
+NVGcontext* nvgCreateGL(int flags)
{
#if defined(DISTRHO_OS_WINDOWS)
# if defined(__GNUC__) && (__GNUC__ >= 9)
@@ -117,6 +140,11 @@ static NVGcontext* nvgCreateGL_helper(int flags)
# define DGL_EXT(PROC, func) \
if (needsInit) func = (PROC) wglGetProcAddress ( #func ); \
DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr);
+# define DGL_EXT2(PROC, func, fallback) \
+ if (needsInit) { \
+ func = (PROC) wglGetProcAddress ( #func ); \
+ if (func == nullptr) func = (PROC) wglGetProcAddress ( #fallback ); \
+ } DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr);
DGL_EXT(PFNGLACTIVETEXTUREPROC, glActiveTexture)
DGL_EXT(PFNGLATTACHSHADERPROC, glAttachShader)
DGL_EXT(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation)
@@ -145,6 +173,18 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
+# ifdef DGL_USE_NANOVG_FBO
+DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus)
+DGL_EXT2(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer, glBindFramebufferEXT)
+DGL_EXT2(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer, glBindRenderbufferEXT)
+DGL_EXT2(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers, glDeleteFramebuffersEXT)
+DGL_EXT2(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers, glDeleteRenderbuffersEXT)
+DGL_EXT2(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D, glFramebufferTexture2DEXT)
+DGL_EXT2(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer, glFramebufferRenderbufferEXT)
+DGL_EXT2(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers, glGenFramebuffersEXT)
+DGL_EXT2(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers, glGenRenderbuffersEXT)
+DGL_EXT2(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage, glRenderbufferStorageEXT)
+# endif
# ifdef DGL_USE_OPENGL3
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)
@@ -155,18 +195,15 @@ DGL_EXT(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)
DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
# endif
# undef DGL_EXT
+# undef DGL_EXT2
needsInit = false;
# if defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic pop
# endif
#endif
- return nvgCreateGL(flags);
+ return nvgCreateGLfn(flags);
}
-// -----------------------------------------------------------------------
-
-START_NAMESPACE_DGL
-
// -----------------------------------------------------------------------
// DGL Color class conversion
@@ -215,6 +252,7 @@ NanoImage& NanoImage::operator=(const Handle& handle)
fHandle.context = handle.context;
fHandle.imageId = handle.imageId;
+ _updateSize();
return *this;
}
@@ -282,13 +320,16 @@ NanoVG::Paint::operator NVGpaint() const noexcept
// NanoVG
NanoVG::NanoVG(int flags)
- : fContext(nvgCreateGL_helper(flags)),
+ : fContext(nvgCreateGL(flags)),
fInFrame(false),
- fIsSubWidget(false) {}
+ fIsSubWidget(false)
+{
+ DISTRHO_CUSTOM_SAFE_ASSERT("Failed to create NanoVG context, expect a black screen", fContext != nullptr);
+}
NanoVG::~NanoVG()
{
- DISTRHO_SAFE_ASSERT(! fInFrame);
+ DISTRHO_CUSTOM_SAFE_ASSERT("Destroying NanoVG context with still active frame", ! fInFrame);
if (fContext != nullptr && ! fIsSubWidget)
nvgDeleteGL(fContext);
@@ -483,6 +524,12 @@ void NanoVG::globalAlpha(float alpha)
nvgGlobalAlpha(fContext, alpha);
}
+void NanoVG::globalTint(Color tint)
+{
+ if (fContext != nullptr)
+ nvgGlobalTint(fContext, tint);
+}
+
// -----------------------------------------------------------------------
// Transforms
@@ -631,6 +678,45 @@ NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int
return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast(dataSize)));
}
+NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data,
+ ImageFlags imageFlags, ImageFormat format)
+{
+ return createImageFromRawMemory(w, h, data, static_cast(imageFlags), format);
+}
+
+NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data,
+ int imageFlags, ImageFormat format)
+{
+ if (fContext == nullptr) return NanoImage::Handle();
+ DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle());
+
+ NVGtexture nvgformat;
+ switch (format)
+ {
+ case kImageFormatGrayscale:
+ nvgformat = NVG_TEXTURE_ALPHA;
+ break;
+ case kImageFormatBGR:
+ nvgformat = NVG_TEXTURE_BGR;
+ break;
+ case kImageFormatBGRA:
+ nvgformat = NVG_TEXTURE_BGRA;
+ break;
+ case kImageFormatRGB:
+ nvgformat = NVG_TEXTURE_RGB;
+ break;
+ case kImageFormatRGBA:
+ nvgformat = NVG_TEXTURE_RGBA;
+ break;
+ default:
+ return NanoImage::Handle();
+ }
+
+ return NanoImage::Handle(fContext, nvgCreateImageRaw(fContext,
+ static_cast(w),
+ static_cast(h), imageFlags, nvgformat, data));
+}
+
NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags)
{
return createImageFromRGBA(w, h, data, static_cast(imageFlags));
@@ -646,12 +732,14 @@ NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data,
static_cast(h), imageFlags, data));
}
-NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture)
+NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h,
+ ImageFlags imageFlags, bool deleteTexture)
{
return createImageFromTextureHandle(textureId, w, h, static_cast(imageFlags), deleteTexture);
}
-NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture)
+NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h,
+ int imageFlags, bool deleteTexture)
{
if (fContext == nullptr) return NanoImage::Handle();
DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle());
diff --git a/dgl/src/OpenGL.cpp b/dgl/src/OpenGL.cpp
index 098c33e6..b7426370 100644
--- a/dgl/src/OpenGL.cpp
+++ b/dgl/src/OpenGL.cpp
@@ -33,20 +33,48 @@
START_NAMESPACE_DGL
+// -----------------------------------------------------------------------
+
+#if defined(DGL_USE_GLES2)
+static void notImplemented(const char* const name)
+{
+// d_stderr2("GLES2 function not implemented: %s", name);
+}
+#elif defined(DGL_USE_GLES3)
+static void notImplemented(const char* const name)
+{
+ d_stderr2("GLES3 function not implemented: %s", name);
+}
+#elif defined(DGL_USE_OPENGL3)
+static void notImplemented(const char* const name)
+{
+ d_stderr2("OpenGL3 function not implemented: %s", name);
+}
+#else
+# define DGL_USE_COMPAT_OPENGL
+#endif
+
// -----------------------------------------------------------------------
// Color
void Color::setFor(const GraphicsContext&, const bool includeAlpha)
{
+#ifdef DGL_USE_COMPAT_OPENGL
if (includeAlpha)
glColor4f(red, green, blue, alpha);
else
glColor3f(red, green, blue);
+#else
+ notImplemented("Color::setFor");
+ // unused
+ (void)includeAlpha;
+#endif
}
// -----------------------------------------------------------------------
// Line
+#ifdef DGL_USE_COMPAT_OPENGL
template
static void drawLine(const Point& posStart, const Point& posEnd)
{
@@ -61,21 +89,30 @@ static void drawLine(const Point& posStart, const Point& posEnd)
glEnd();
}
+#endif
template
void Line::draw(const GraphicsContext&, const T width)
{
+#ifdef DGL_USE_COMPAT_OPENGL
DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
glLineWidth(static_cast(width));
drawLine(posStart, posEnd);
+#else
+ notImplemented("Line::draw");
+#endif
}
// deprecated calls
template
void Line::draw()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawLine(posStart, posEnd);
+#else
+ notImplemented("Line::draw");
+#endif
}
template class Line;
@@ -88,6 +125,7 @@ template class Line;
// -----------------------------------------------------------------------
// Circle
+#ifdef DGL_USE_COMPAT_OPENGL
template
static void drawCircle(const Point& pos,
const uint numSegments,
@@ -115,11 +153,16 @@ static void drawCircle(const Point& pos,
glEnd();
}
+#endif
template
void Circle::draw(const GraphicsContext&)
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawCircle(fPos, fNumSegments, fSize, fSin, fCos, false);
+#else
+ notImplemented("Circle::draw");
+#endif
}
template
@@ -128,20 +171,32 @@ void Circle::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
glLineWidth(static_cast(lineWidth));
+#ifdef DGL_USE_COMPAT_OPENGL
drawCircle(fPos, fNumSegments, fSize, fSin, fCos, true);
+#else
+ notImplemented("Circle::drawOutline");
+#endif
}
// deprecated calls
template
void Circle::draw()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawCircle(fPos, fNumSegments, fSize, fSin, fCos, false);
+#else
+ notImplemented("Circle::draw");
+#endif
}
template
void Circle::drawOutline()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawCircle(fPos, fNumSegments, fSize, fSin, fCos, true);
+#else
+ notImplemented("Circle::drawOutline");
+#endif
}
template class Circle;
@@ -154,6 +209,7 @@ template class Circle;
// -----------------------------------------------------------------------
// Triangle
+#ifdef DGL_USE_COMPAT_OPENGL
template
static void drawTriangle(const Point& pos1,
const Point& pos2,
@@ -172,11 +228,16 @@ static void drawTriangle(const Point& pos1,
glEnd();
}
+#endif
template
void Triangle::draw(const GraphicsContext&)
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle(pos1, pos2, pos3, false);
+#else
+ notImplemented("Triangle::draw");
+#endif
}
template
@@ -185,20 +246,32 @@ void Triangle::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
glLineWidth(static_cast(lineWidth));
+#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle(pos1, pos2, pos3, true);
+#else
+ notImplemented("Triangle::drawOutline");
+#endif
}
// deprecated calls
template
void Triangle::draw()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle(pos1, pos2, pos3, false);
+#else
+ notImplemented("Triangle::draw");
+#endif
}
template
void Triangle::drawOutline()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle(pos1, pos2, pos3, true);
+#else
+ notImplemented("Triangle::drawOutline");
+#endif
}
template class Triangle;
@@ -211,6 +284,7 @@ template class Triangle;
// -----------------------------------------------------------------------
// Rectangle
+#ifdef DGL_USE_COMPAT_OPENGL
template
static void drawRectangle(const Rectangle& rect, const bool outline)
{
@@ -239,11 +313,16 @@ static void drawRectangle(const Rectangle& rect, const bool outline)
glEnd();
}
+#endif
template
void Rectangle::draw(const GraphicsContext&)
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle(*this, false);
+#else
+ notImplemented("Rectangle::draw");
+#endif
}
template
@@ -252,20 +331,32 @@ void Rectangle::drawOutline(const GraphicsContext&, const T lineWidth)
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
glLineWidth(static_cast(lineWidth));
+#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle(*this, true);
+#else
+ notImplemented("Rectangle::drawOutline");
+#endif
}
// deprecated calls
template
void Rectangle::draw()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle(*this, false);
+#else
+ notImplemented("Rectangle::draw");
+#endif
}
template
void Rectangle::drawOutline()
{
+#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle(*this, true);
+#else
+ notImplemented("Rectangle::drawOutline");
+#endif
}
template class Rectangle;
@@ -316,11 +407,14 @@ static void drawOpenGLImage(const OpenGLImage& image, const Point& pos, con
setupCalled = true;
}
+#ifdef DGL_USE_COMPAT_OPENGL
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+#endif
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
+#ifdef DGL_USE_COMPAT_OPENGL
glBegin(GL_QUADS);
{
@@ -343,6 +437,7 @@ static void drawOpenGLImage(const OpenGLImage& image, const Point& pos, con
}
glEnd();
+#endif
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
@@ -533,17 +628,23 @@ void ImageBaseKnob::onDisplay()
if (pData->rotationAngle != 0)
{
+#ifdef DGL_USE_COMPAT_OPENGL
glPushMatrix();
+#endif
const int w2 = w/2;
const int h2 = h/2;
+#ifdef DGL_USE_COMPAT_OPENGL
glTranslatef(static_cast(w2), static_cast(h2), 0.0f);
glRotatef(normValue*static_cast(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
+#endif
Rectangle(-w2, -h2, w, h).draw(context);
+#ifdef DGL_USE_COMPAT_OPENGL
glPopMatrix();
+#endif
}
else
{
@@ -667,6 +768,36 @@ void TopLevelWidget::PrivateData::display()
// -----------------------------------------------------------------------
+void Window::PrivateData::renderToPicture(const char* const filename,
+ const GraphicsContext&,
+ const uint width,
+ const uint height)
+{
+ FILE* const f = fopen(filename, "w");
+ DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,);
+
+ GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)];
+
+ glFlush();
+ glReadPixels(0, 0, static_cast(width), static_cast(height), GL_RGB, GL_UNSIGNED_BYTE, pixels);
+
+ fprintf(f, "P3\n%d %d\n255\n", width, height);
+ for (uint y = 0; y < height; y++)
+ {
+ for (uint i, x = 0; x < width; x++)
+ {
+ i = 3 * ((height - y - 1) * width + x);
+ fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]);
+ }
+ fprintf(f, "\n");
+ }
+
+ delete[] pixels;
+ fclose(f);
+}
+
+// -----------------------------------------------------------------------
+
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
return (const GraphicsContext&)graphicsContext;
diff --git a/dgl/src/SubWidget.cpp b/dgl/src/SubWidget.cpp
index c4cfd0b8..d0f38917 100644
--- a/dgl/src/SubWidget.cpp
+++ b/dgl/src/SubWidget.cpp
@@ -34,7 +34,9 @@ SubWidget::~SubWidget()
template
bool SubWidget::contains(const T x, const T y) const noexcept
{
- return Rectangle(0, 0, getWidth()-pData->margin.getX(), getHeight()-pData->margin.getY()).contains(x, y);
+ return Rectangle(0, 0,
+ static_cast(getWidth()),
+ static_cast(getHeight())).contains(x, y);
}
template
@@ -65,9 +67,18 @@ Rectangle SubWidget::getAbsoluteArea() const noexcept
Rectangle SubWidget::getConstrainedAbsoluteArea() const noexcept
{
- return Rectangle(static_cast(std::max(0, getAbsoluteX())),
- static_cast(std::max(0, getAbsoluteY())),
- getSize());
+ const int x = getAbsoluteX();
+ const int y = getAbsoluteY();
+
+ if (x >= 0 && y >= 0)
+ return Rectangle(x, y, getSize());
+
+ const int xOffset = std::min(0, x);
+ const int yOffset = std::min(0, y);
+ const int width = std::max(0, static_cast(getWidth()) + xOffset);
+ const int height = std::max(0, static_cast(getHeight()) + yOffset);
+
+ return Rectangle(0, 0, static_cast(width), static_cast(height));
}
void SubWidget::setAbsoluteX(const int x) noexcept
diff --git a/dgl/src/TopLevelWidget.cpp b/dgl/src/TopLevelWidget.cpp
index e044b03d..ab1fa4bf 100644
--- a/dgl/src/TopLevelWidget.cpp
+++ b/dgl/src/TopLevelWidget.cpp
@@ -60,6 +60,21 @@ void TopLevelWidget::setSize(const Size& size)
pData->window.setSize(size);
}
+const void* TopLevelWidget::getClipboard(size_t& dataSize)
+{
+ return pData->window.getClipboard(dataSize);
+}
+
+bool TopLevelWidget::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize)
+{
+ return pData->window.setClipboard(mimeType, data, dataSize);
+}
+
+bool TopLevelWidget::setCursor(const MouseCursor cursor)
+{
+ return pData->window.setCursor(cursor);
+}
+
bool TopLevelWidget::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
{
return pData->window.addIdleCallback(callback, timerFrequencyInMs);
@@ -88,41 +103,47 @@ void TopLevelWidget::repaint(const Rectangle& rect) noexcept
void TopLevelWidget::setGeometryConstraints(const uint minimumWidth,
const uint minimumHeight,
const bool keepAspectRatio,
- const bool automaticallyScale)
+ const bool automaticallyScale,
+ const bool resizeNowIfAutoScaling)
{
- pData->window.setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale);
+ pData->window.setGeometryConstraints(minimumWidth,
+ minimumHeight,
+ keepAspectRatio,
+ automaticallyScale,
+ resizeNowIfAutoScaling);
}
// --------------------------------------------------------------------------------------------------------------------
-bool TopLevelWidget::onKeyboard(const KeyboardEvent&)
+bool TopLevelWidget::onKeyboard(const KeyboardEvent& ev)
{
- return false;
+ return pData->keyboardEvent(ev);
}
-bool TopLevelWidget::onSpecial(const SpecialEvent&)
+bool TopLevelWidget::onCharacterInput(const CharacterInputEvent& ev)
{
- return false;
+ return pData->characterInputEvent(ev);
}
-bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&)
+bool TopLevelWidget::onMouse(const MouseEvent& ev)
{
- return false;
+ return pData->mouseEvent(ev);
}
-bool TopLevelWidget::onMouse(const MouseEvent&)
+bool TopLevelWidget::onMotion(const MotionEvent& ev)
{
- return false;
+ return pData->motionEvent(ev);
}
-bool TopLevelWidget::onMotion(const MotionEvent&)
+bool TopLevelWidget::onScroll(const ScrollEvent& ev)
{
- return false;
+ return pData->scrollEvent(ev);
}
-bool TopLevelWidget::onScroll(const ScrollEvent&)
+// --------------------------------------------------------------------------------------------------------------------
+
+void TopLevelWidget::requestSizeChange(uint, uint)
{
- return false;
}
// --------------------------------------------------------------------------------------------------------------------
diff --git a/dgl/src/TopLevelWidgetPrivateData.cpp b/dgl/src/TopLevelWidgetPrivateData.cpp
index 618cf357..fc862250 100644
--- a/dgl/src/TopLevelWidgetPrivateData.cpp
+++ b/dgl/src/TopLevelWidgetPrivateData.cpp
@@ -42,38 +42,16 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev)
if (! selfw->pData->visible)
return false;
- // give top-level widget chance to catch this event first
- if (self->onKeyboard(ev))
- return true;
-
// propagate event to all subwidgets recursively
return selfw->pData->giveKeyboardEventForSubWidgets(ev);
}
-bool TopLevelWidget::PrivateData::specialEvent(const SpecialEvent& ev)
-{
- // ignore event if we are not visible
- if (! selfw->pData->visible)
- return false;
-
- // give top-level widget chance to catch this event first
- if (self->onSpecial(ev))
- return true;
-
- // propagate event to all subwidgets recursively
- return selfw->pData->giveSpecialEventForSubWidgets(ev);
-}
-
bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev)
{
// ignore event if we are not visible
if (! selfw->pData->visible)
return false;
- // give top-level widget chance to catch this event first
- if (self->onCharacterInput(ev))
- return true;
-
// propagate event to all subwidgets recursively
return selfw->pData->giveCharacterInputEventForSubWidgets(ev);
}
@@ -96,10 +74,6 @@ bool TopLevelWidget::PrivateData::mouseEvent(const MouseEvent& ev)
rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor);
}
- // give top-level widget chance to catch this event first
- if (self->onMouse(ev))
- return true;
-
// propagate event to all subwidgets recursively
return selfw->pData->giveMouseEventForSubWidgets(rev);
}
@@ -122,10 +96,6 @@ bool TopLevelWidget::PrivateData::motionEvent(const MotionEvent& ev)
rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor);
}
- // give top-level widget chance to catch this event first
- if (self->onMotion(ev))
- return true;
-
// propagate event to all subwidgets recursively
return selfw->pData->giveMotionEventForSubWidgets(rev);
}
@@ -150,10 +120,6 @@ bool TopLevelWidget::PrivateData::scrollEvent(const ScrollEvent& ev)
rev.delta.setY(ev.delta.getY() / autoScaleFactor);
}
- // give top-level widget chance to catch this event first
- if (self->onScroll(ev))
- return true;
-
// propagate event to all subwidgets recursively
return selfw->pData->giveScrollEventForSubWidgets(rev);
}
diff --git a/dgl/src/TopLevelWidgetPrivateData.hpp b/dgl/src/TopLevelWidgetPrivateData.hpp
index 6c882868..fb4e77b2 100644
--- a/dgl/src/TopLevelWidgetPrivateData.hpp
+++ b/dgl/src/TopLevelWidgetPrivateData.hpp
@@ -30,11 +30,10 @@ struct TopLevelWidget::PrivateData {
Widget* const selfw;
Window& window;
- explicit PrivateData(TopLevelWidget* const s, Window& w);
+ explicit PrivateData(TopLevelWidget* self, Window& window);
~PrivateData();
void display();
bool keyboardEvent(const KeyboardEvent& ev);
- bool specialEvent(const SpecialEvent& ev);
bool characterInputEvent(const CharacterInputEvent& ev);
bool mouseEvent(const MouseEvent& ev);
bool motionEvent(const MotionEvent& ev);
diff --git a/dgl/src/Vulkan.cpp b/dgl/src/Vulkan.cpp
index d18b3c32..2fc97589 100644
--- a/dgl/src/Vulkan.cpp
+++ b/dgl/src/Vulkan.cpp
@@ -231,6 +231,13 @@ 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
{
return (const GraphicsContext&)graphicsContext;
diff --git a/dgl/src/Widget.cpp b/dgl/src/Widget.cpp
index e6e41d5a..8aaa90d5 100644
--- a/dgl/src/Widget.cpp
+++ b/dgl/src/Widget.cpp
@@ -167,11 +167,6 @@ bool Widget::onKeyboard(const KeyboardEvent& ev)
return pData->giveKeyboardEventForSubWidgets(ev);
}
-bool Widget::onSpecial(const SpecialEvent& ev)
-{
- return pData->giveSpecialEventForSubWidgets(ev);
-}
-
bool Widget::onCharacterInput(const CharacterInputEvent& ev)
{
return pData->giveCharacterInputEventForSubWidgets(ev);
diff --git a/dgl/src/WidgetPrivateData.cpp b/dgl/src/WidgetPrivateData.cpp
index 304ad6ef..59b87901 100644
--- a/dgl/src/WidgetPrivateData.cpp
+++ b/dgl/src/WidgetPrivateData.cpp
@@ -87,24 +87,6 @@ bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev
return false;
}
-bool Widget::PrivateData::giveSpecialEventForSubWidgets(const SpecialEvent& ev)
-{
- if (! visible)
- return false;
- if (subWidgets.size() == 0)
- return false;
-
- FOR_EACH_SUBWIDGET_INV(rit)
- {
- SubWidget* const widget(*rit);
-
- if (widget->isVisible() && widget->onSpecial(ev))
- return true;
- }
-
- return false;
-}
-
bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev)
{
if (! visible)
@@ -130,18 +112,15 @@ bool Widget::PrivateData::giveMouseEventForSubWidgets(MouseEvent& ev)
if (subWidgets.size() == 0)
return false;
- double x = ev.absolutePos.getX();
- double y = ev.absolutePos.getY();
+ const double x = ev.absolutePos.getX();
+ const double y = ev.absolutePos.getY();
if (SubWidget* const selfw = dynamic_cast(self))
{
if (selfw->pData->needsViewportScaling)
{
- x -= selfw->getAbsoluteX();
- y -= selfw->getAbsoluteY();
-
- ev.absolutePos.setX(x);
- ev.absolutePos.setY(y);
+ ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX());
+ ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY());
}
}
@@ -169,18 +148,15 @@ bool Widget::PrivateData::giveMotionEventForSubWidgets(MotionEvent& ev)
if (subWidgets.size() == 0)
return false;
- double x = ev.absolutePos.getX();
- double y = ev.absolutePos.getY();
+ const double x = ev.absolutePos.getX();
+ const double y = ev.absolutePos.getY();
if (SubWidget* const selfw = dynamic_cast(self))
{
if (selfw->pData->needsViewportScaling)
{
- x -= selfw->getAbsoluteX();
- y -= selfw->getAbsoluteY();
-
- ev.absolutePos.setX(x);
- ev.absolutePos.setY(y);
+ ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX());
+ ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY());
}
}
@@ -208,18 +184,15 @@ bool Widget::PrivateData::giveScrollEventForSubWidgets(ScrollEvent& ev)
if (subWidgets.size() == 0)
return false;
- double x = ev.absolutePos.getX();
- double y = ev.absolutePos.getY();
+ const double x = ev.absolutePos.getX();
+ const double y = ev.absolutePos.getY();
if (SubWidget* const selfw = dynamic_cast(self))
{
if (selfw->pData->needsViewportScaling)
{
- x -= selfw->getAbsoluteX();
- y -= selfw->getAbsoluteY();
-
- ev.absolutePos.setX(x);
- ev.absolutePos.setY(y);
+ ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX());
+ ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY());
}
}
diff --git a/dgl/src/WidgetPrivateData.hpp b/dgl/src/WidgetPrivateData.hpp
index ab388522..15b84097 100644
--- a/dgl/src/WidgetPrivateData.hpp
+++ b/dgl/src/WidgetPrivateData.hpp
@@ -44,7 +44,6 @@ struct Widget::PrivateData {
void displaySubWidgets(uint width, uint height, double autoScaleFactor);
bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev);
- bool giveSpecialEventForSubWidgets(const SpecialEvent& ev);
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev);
bool giveMouseEventForSubWidgets(MouseEvent& ev);
bool giveMotionEventForSubWidgets(MotionEvent& ev);
diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp
index b418fdad..37c61d11 100644
--- a/dgl/src/Window.cpp
+++ b/dgl/src/Window.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -15,6 +15,7 @@
*/
#include "WindowPrivateData.hpp"
+#include "../TopLevelWidget.hpp"
#include "pugl.hpp"
@@ -66,8 +67,8 @@ Window::Window(Application& app)
pData->initPost();
}
-Window::Window(Application& app, Window& parent)
- : pData(new PrivateData(app, this, parent.pData))
+Window::Window(Application& app, Window& transientParentWindow)
+ : pData(new PrivateData(app, this, transientParentWindow.pData))
{
pData->initPost();
}
@@ -87,7 +88,7 @@ Window::Window(Application& app,
const uint height,
const double scaleFactor,
const bool resizable)
- : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable))
+ : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false))
{
pData->initPost();
}
@@ -98,8 +99,9 @@ Window::Window(Application& app,
const uint height,
const double scaleFactor,
const bool resizable,
+ const bool isVST3,
const bool doPostInit)
- : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable))
+ : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3))
{
if (doPostInit)
pData->initPost();
@@ -153,6 +155,48 @@ void Window::setResizable(const bool resizable)
pData->setResizable(resizable);
}
+int Window::getOffsetX() const noexcept
+{
+ DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
+
+ return puglGetFrame(pData->view).x;
+}
+
+int Window::getOffsetY() const noexcept
+{
+ DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
+
+ return puglGetFrame(pData->view).y;
+}
+
+Point Window::getOffset() const noexcept
+{
+ DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point());
+
+ const PuglRect rect = puglGetFrame(pData->view);
+ return Point(rect.x, rect.y);
+}
+
+void Window::setOffsetX(const int x)
+{
+ setOffset(x, getOffsetY());
+}
+
+void Window::setOffsetY(const int y)
+{
+ setOffset(getOffsetX(), y);
+}
+
+void Window::setOffset(const int x, const int y)
+{
+ puglSetPosition(pData->view, x, y);
+}
+
+void Window::setOffset(const Point& offset)
+{
+ setOffset(offset.getX(), offset.getY());
+}
+
uint Window::getWidth() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
@@ -199,8 +243,14 @@ void Window::setSize(uint width, uint height)
if (pData->isEmbed)
{
const double scaleFactor = pData->scaleFactor;
- const uint minWidth = static_cast(pData->minWidth * scaleFactor + 0.5);
- const uint minHeight = static_cast(pData->minHeight * scaleFactor + 0.5);
+ uint minWidth = pData->minWidth;
+ uint minHeight = pData->minHeight;
+
+ if (pData->autoScaling && scaleFactor != 1.0)
+ {
+ minWidth *= scaleFactor;
+ minHeight *= scaleFactor;
+ }
// handle geometry constraints here
if (width < minWidth)
@@ -220,15 +270,27 @@ void Window::setSize(uint width, uint height)
{
// fix width
if (reqRatio > ratio)
- width = height * ratio;
+ width = static_cast(height * ratio + 0.5);
// fix height
else
- height = width / ratio;
+ height = static_cast(static_cast(width) / ratio + 0.5);
}
}
}
- puglSetWindowSize(pData->view, width, height);
+ if (pData->usesSizeRequest)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(pData->topLevelWidgets.size() != 0,);
+
+ TopLevelWidget* const topLevelWidget = pData->topLevelWidgets.front();
+ DISTRHO_SAFE_ASSERT_RETURN(topLevelWidget != nullptr,);
+
+ topLevelWidget->requestSizeChange(width, height);
+ }
+ else
+ {
+ puglSetSizeAndDefault(pData->view, width, height);
+ }
}
void Window::setSize(const Size& size)
@@ -257,6 +319,21 @@ void Window::setIgnoringKeyRepeat(const bool ignore) noexcept
puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore);
}
+const void* Window::getClipboard(size_t& dataSize)
+{
+ return pData->getClipboard(dataSize);
+}
+
+bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize)
+{
+ return puglSetClipboard(pData->view, mimeType != nullptr ? mimeType : "text/plain", data, dataSize) == PUGL_SUCCESS;
+}
+
+bool Window::setCursor(const MouseCursor cursor)
+{
+ return puglSetCursor(pData->view, static_cast(cursor)) == PUGL_SUCCESS;
+}
+
bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
{
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
@@ -285,7 +362,7 @@ const GraphicsContext& Window::getGraphicsContext() const noexcept
uintptr_t Window::getNativeWindowHandle() const noexcept
{
- return puglGetNativeWindow(pData->view);
+ return puglGetNativeView(pData->view);
}
double Window::getScaleFactor() const noexcept
@@ -319,10 +396,10 @@ void Window::repaint(const Rectangle& rect) noexcept
return;
PuglRect prect = {
- static_cast(rect.getX()),
- static_cast(rect.getY()),
- static_cast(rect.getWidth()),
- static_cast(rect.getHeight()),
+ static_cast(rect.getX()),
+ static_cast(rect.getY()),
+ static_cast(rect.getWidth()),
+ static_cast(rect.getHeight()),
};
if (pData->autoScaling)
{
@@ -336,15 +413,27 @@ void Window::repaint(const Rectangle& rect) noexcept
puglPostRedisplayRect(pData->view, prect);
}
+void Window::renderToPicture(const char* const filename)
+{
+ pData->filenameToRenderInto = strdup(filename);
+}
+
void Window::runAsModal(bool blockWait)
{
pData->runAsModal(blockWait);
}
-void Window::setGeometryConstraints(const uint minimumWidth,
- const uint minimumHeight,
+Size Window::getGeometryConstraints(bool& keepAspectRatio)
+{
+ keepAspectRatio = pData->keepAspectRatio;
+ return Size(pData->minWidth, pData->minHeight);
+}
+
+void Window::setGeometryConstraints(uint minimumWidth,
+ uint minimumHeight,
const bool keepAspectRatio,
- const bool automaticallyScale)
+ const bool automaticallyScale,
+ const bool resizeNowIfAutoScaling)
{
DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,);
DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,);
@@ -359,12 +448,15 @@ void Window::setGeometryConstraints(const uint minimumWidth,
const double scaleFactor = pData->scaleFactor;
- puglSetGeometryConstraints(pData->view,
- static_cast(minimumWidth * scaleFactor + 0.5),
- static_cast(minimumHeight * scaleFactor + 0.5),
- keepAspectRatio);
+ if (automaticallyScale && scaleFactor != 1.0)
+ {
+ minimumWidth *= scaleFactor;
+ minimumHeight *= scaleFactor;
+ }
- if (scaleFactor != 1.0)
+ puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio);
+
+ if (scaleFactor != 1.0 && automaticallyScale && resizeNowIfAutoScaling)
{
const Size size(getSize());
@@ -373,50 +465,64 @@ void Window::setGeometryConstraints(const uint minimumWidth,
}
}
-bool Window::onClose()
+void Window::setTransientParent(const uintptr_t transientParentWindowHandle)
{
- return true;
+ puglSetTransientParent(pData->view, transientParentWindowHandle);
}
-void Window::onFocus(bool, CrossingMode)
+std::vector Window::getClipboardDataOfferTypes()
{
+ std::vector offerTypes;
+
+ if (const uint32_t numTypes = puglGetNumClipboardTypes(pData->view))
+ {
+ offerTypes.reserve(numTypes);
+
+ for (uint32_t i=0; iview, i) };
+ offerTypes.push_back(offer);
+ }
+ }
+
+ return offerTypes;
}
-void Window::onReshape(uint, uint)
+uint32_t Window::onClipboardDataOffer()
{
- puglFallbackOnResize(pData->view);
+ std::vector offers(getClipboardDataOfferTypes());
+
+ for (std::vector::iterator it=offers.begin(), end=offers.end(); it != end;++it)
+ {
+ const ClipboardDataOffer offer = *it;
+ if (std::strcmp(offer.type, "text/plain") == 0)
+ return offer.id;
+ }
+
+ return 0;
}
-void Window::onScaleFactorChanged(double)
+bool Window::onClose()
{
+ return true;
}
-#ifndef DGL_FILE_BROWSER_DISABLED
-void Window::onFileSelected(const char*)
+void Window::onFocus(bool, CrossingMode)
{
}
-#endif
-#if 0
-void Window::setTransientWinId(const uintptr_t winId)
+void Window::onReshape(uint, uint)
{
- puglSetTransientFor(pData->view, winId);
+ puglFallbackOnResize(pData->view);
}
-// -----------------------------------------------------------------------
-
-bool Window::handlePluginKeyboard(const bool press, const uint key)
+void Window::onScaleFactorChanged(double)
{
- // TODO
- return false;
- // return pData->handlePluginKeyboard(press, key);
}
-bool Window::handlePluginSpecial(const bool press, const Key key)
+#ifndef DGL_FILE_BROWSER_DISABLED
+void Window::onFileSelected(const char*)
{
- // TODO
- return false;
- // return pData->handlePluginSpecial(press, key);
}
#endif
diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp
index deaa5595..6b32e0ce 100644
--- a/dgl/src/WindowPrivateData.cpp
+++ b/dgl/src/WindowPrivateData.cpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho
+ * Copyright (C) 2012-2022 Filipe Coelho
*
* 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
@@ -19,26 +19,19 @@
#include "pugl.hpp"
-#include "../../distrho/extra/String.hpp"
-
-#ifdef DISTRHO_OS_WINDOWS
-# include
-# include
-# include
-# include
-#else
-# include
-#endif
-
-#define DGL_DEBUG_EVENTS
+// #define DGL_DEBUG_EVENTS
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
-# include
+# ifdef DISTRHO_PROPER_CPP11_SUPPORT
+# include
+# else
+# include
+# endif
#endif
START_NAMESPACE_DGL
-#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
+#ifdef DGL_DEBUG_EVENTS
# define DGL_DBG(msg) std::fprintf(stderr, "%s", msg);
# define DGL_DBGp(...) std::fprintf(stderr, __VA_ARGS__);
# define DGL_DBGF std::fflush(stderr);
@@ -59,44 +52,69 @@ START_NAMESPACE_DGL
// -----------------------------------------------------------------------
-#ifdef DISTRHO_OS_WINDOWS
-// static pointer used for direct comparisons
-static const char* const kWin32SelectedFileCancelled = "__dpf_cancelled__";
-#endif
-
-static double getDesktopScaleFactor(const PuglView* const view)
+static double getScaleFactorFromParent(const PuglView* const view)
{
// allow custom scale for testing
if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
return std::max(1.0, std::atof(scale));
if (view != nullptr)
- return puglGetDesktopScaleFactor(view);
+ return puglGetScaleFactorFromParent(view);
return 1.0;
}
+static PuglView* puglNewViewWithTransientParent(PuglWorld* const world, PuglView* const transientParentView)
+{
+ DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr);
+
+ if (PuglView* const view = puglNewView(world))
+ {
+ puglSetTransientParent(view, puglGetNativeView(transientParentView));
+ return view;
+ }
+
+ return nullptr;
+}
+
+static PuglView* puglNewViewWithParentWindow(PuglWorld* const world, const uintptr_t parentWindowHandle)
+{
+ DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr);
+
+ if (PuglView* const view = puglNewView(world))
+ {
+ puglSetParentWindow(view, parentWindowHandle);
+ return view;
+ }
+
+ return nullptr;
+}
+
// -----------------------------------------------------------------------
Window::PrivateData::PrivateData(Application& a, Window* const s)
: app(a),
appData(a.pData),
self(s),
- view(puglNewView(appData->world)),
- transientParentView(nullptr),
+ view(appData->world != nullptr ? puglNewView(appData->world) : nullptr),
topLevelWidgets(),
isClosed(true),
isVisible(false),
isEmbed(false),
- scaleFactor(getDesktopScaleFactor(view)),
+ usesSizeRequest(false),
+ scaleFactor(getScaleFactorFromParent(view)),
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0),
keepAspectRatio(false),
ignoreIdleCallbacks(false),
-#ifdef DISTRHO_OS_WINDOWS
- win32SelectedFile(nullptr),
+ waitingForClipboardData(false),
+ waitingForClipboardEvents(false),
+ clipboardTypeId(0),
+ filenameToRenderInto(nullptr),
+#ifndef DGL_FILE_BROWSER_DISABLED
+ fileBrowserHandle(nullptr),
#endif
modal()
{
@@ -107,12 +125,12 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c
: app(a),
appData(a.pData),
self(s),
- view(puglNewView(appData->world)),
- transientParentView(ppData->view),
+ view(puglNewViewWithTransientParent(appData->world, ppData->view)),
topLevelWidgets(),
isClosed(true),
isVisible(false),
isEmbed(false),
+ usesSizeRequest(false),
scaleFactor(ppData->scaleFactor),
autoScaling(false),
autoScaleFactor(1.0),
@@ -120,13 +138,15 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c
minHeight(0),
keepAspectRatio(false),
ignoreIdleCallbacks(false),
-#ifdef DISTRHO_OS_WINDOWS
- win32SelectedFile(nullptr),
+ waitingForClipboardData(false),
+ waitingForClipboardEvents(false),
+ clipboardTypeId(0),
+ filenameToRenderInto(nullptr),
+#ifndef DGL_FILE_BROWSER_DISABLED
+ fileBrowserHandle(nullptr),
#endif
modal(ppData)
{
- puglSetTransientFor(view, puglGetNativeWindow(transientParentView));
-
initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
}
@@ -136,52 +156,57 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
: app(a),
appData(a.pData),
self(s),
- view(puglNewView(appData->world)),
- transientParentView(nullptr),
+ view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)),
topLevelWidgets(),
isClosed(parentWindowHandle == 0),
isVisible(parentWindowHandle != 0),
isEmbed(parentWindowHandle != 0),
- scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)),
+ usesSizeRequest(false),
+ scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)),
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0),
keepAspectRatio(false),
ignoreIdleCallbacks(false),
-#ifdef DISTRHO_OS_WINDOWS
- win32SelectedFile(nullptr),
+ waitingForClipboardData(false),
+ waitingForClipboardEvents(false),
+ clipboardTypeId(0),
+ filenameToRenderInto(nullptr),
+#ifndef DGL_FILE_BROWSER_DISABLED
+ fileBrowserHandle(nullptr),
#endif
modal()
{
- if (isEmbed)
- puglSetParentWindow(view, parentWindowHandle);
-
initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, resizable);
}
Window::PrivateData::PrivateData(Application& a, Window* const s,
const uintptr_t parentWindowHandle,
const uint width, const uint height,
- const double scale, const bool resizable)
+ const double scale, const bool resizable, const bool isVST3)
: app(a),
appData(a.pData),
self(s),
- view(appData->world != nullptr ? puglNewView(appData->world) : nullptr),
- transientParentView(nullptr),
+ view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)),
topLevelWidgets(),
isClosed(parentWindowHandle == 0),
isVisible(parentWindowHandle != 0 && view != nullptr),
isEmbed(parentWindowHandle != 0),
- scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)),
+ usesSizeRequest(isVST3),
+ scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)),
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
minHeight(0),
keepAspectRatio(false),
ignoreIdleCallbacks(false),
-#ifdef DISTRHO_OS_WINDOWS
- win32SelectedFile(nullptr),
+ waitingForClipboardData(false),
+ waitingForClipboardEvents(false),
+ clipboardTypeId(0),
+ filenameToRenderInto(nullptr),
+#ifndef DGL_FILE_BROWSER_DISABLED
+ fileBrowserHandle(nullptr),
#endif
modal()
{
@@ -195,14 +220,16 @@ Window::PrivateData::~PrivateData()
{
appData->idleCallbacks.remove(this);
appData->windows.remove(self);
+ std::free(filenameToRenderInto);
if (view == nullptr)
return;
if (isEmbed)
{
-#ifdef HAVE_X11
- sofdFileDialogClose();
+#ifndef DGL_FILE_BROWSER_DISABLED
+ if (fileBrowserHandle != nullptr)
+ fileBrowserClose(fileBrowserHandle);
#endif
puglHide(view);
appData->oneWindowClosed();
@@ -210,11 +237,6 @@ Window::PrivateData::~PrivateData()
isVisible = false;
}
-#ifdef DISTRHO_OS_WINDOWS
- if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled)
- std::free(const_cast(win32SelectedFile));
-#endif
-
puglFreeView(view);
}
@@ -233,21 +255,33 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo
}
puglSetMatchingBackendForCurrentBuild(view);
-
- puglClearMinSize(view);
- puglSetWindowSize(view, width, height);
-
puglSetHandle(view, this);
+
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE);
+#if DGL_USE_RGBA
+ puglSetViewHint(view, PUGL_DEPTH_BITS, 24);
+#else
puglSetViewHint(view, PUGL_DEPTH_BITS, 16);
+#endif
puglSetViewHint(view, PUGL_STENCIL_BITS, 8);
-#ifdef DGL_USE_OPENGL3
+
+#if defined(DGL_USE_OPENGL3) || defined(DGL_USE_GLES3)
puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
+#elif defined(DGL_USE_GLES2)
+ puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
+ puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
+#else
+ puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_TRUE);
+ puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
#endif
+
// PUGL_SAMPLES ??
puglSetEventFunc(view, puglEventCallback);
+
+ // setting default size triggers system-level calls, do it last
+ puglSetSizeHint(view, PUGL_DEFAULT_SIZE, width, height);
}
bool Window::PrivateData::initPost()
@@ -313,8 +347,8 @@ void Window::PrivateData::show()
appData->oneWindowShown();
// FIXME
- PuglRect rect = puglGetFrame(view);
- puglSetWindowSize(view, static_cast(rect.width), static_cast(rect.height));
+// PuglRect rect = puglGetFrame(view);
+// puglSetWindowSize(view, static_cast(rect.width), static_cast(rect.height));
#if defined(DISTRHO_OS_WINDOWS)
puglWin32ShowCentered(view);
@@ -354,9 +388,14 @@ void Window::PrivateData::hide()
if (modal.enabled)
stopModal();
-#ifdef HAVE_X11
- sofdFileDialogClose();
+#ifndef DGL_FILE_BROWSER_DISABLED
+ if (fileBrowserHandle != nullptr)
+ {
+ fileBrowserClose(fileBrowserHandle);
+ fileBrowserHandle = nullptr;
+ }
#endif
+
puglHide(view);
isVisible = false;
@@ -372,11 +411,7 @@ void Window::PrivateData::focus()
if (! isEmbed)
puglRaiseWindow(view);
-#ifdef HAVE_X11
- puglX11GrabFocus(view);
-#else
puglGrabFocus(view);
-#endif
}
// -----------------------------------------------------------------------
@@ -387,10 +422,7 @@ void Window::PrivateData::setResizable(const bool resizable)
DGL_DBG("Window setResizable called\n");
- puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
-#ifdef DISTRHO_OS_WINDOWS
- puglWin32SetWindowResizable(view, resizable);
-#endif
+ puglSetResizable(view, resizable);
}
// -----------------------------------------------------------------------
@@ -398,20 +430,12 @@ void Window::PrivateData::setResizable(const bool resizable)
void Window::PrivateData::idleCallback()
{
#ifndef DGL_FILE_BROWSER_DISABLED
-# ifdef DISTRHO_OS_WINDOWS
- if (const char* path = win32SelectedFile)
+ if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle))
{
- win32SelectedFile = nullptr;
- if (path == kWin32SelectedFileCancelled)
- path = nullptr;
- self->onFileSelected(path);
- std::free(const_cast(path));
+ self->onFileSelected(fileBrowserGetPath(fileBrowserHandle));
+ fileBrowserClose(fileBrowserHandle);
+ fileBrowserHandle = nullptr;
}
-# endif
-# ifdef HAVE_X11
- if (sofdFileDialogIdle(view))
- self->onFileSelected(sofdFileDialogGetPath());
-# endif
#endif
}
@@ -451,164 +475,23 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback)
// -----------------------------------------------------------------------
// file handling
-bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& options)
+bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)
{
- using DISTRHO_NAMESPACE::String;
-
- // --------------------------------------------------------------------------
- // configure start dir
-
- // TODO: get abspath if needed
- // TODO: cross-platform
-
- String startDir(options.startDir);
-
- if (startDir.isEmpty())
- {
- // TESTING verify this whole thing...
-# ifdef DISTRHO_OS_WINDOWS
- if (char* const cwd = _getcwd(nullptr, 0))
- {
- startDir = cwd;
- std::free(cwd);
- }
-# else
- if (char* const cwd = getcwd(nullptr, 0))
- {
- startDir = cwd;
- std::free(cwd);
- }
-# endif
- }
-
- DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false);
-
- if (! startDir.endsWith(DISTRHO_OS_SEP))
- startDir += DISTRHO_OS_SEP_STR;
-
- // --------------------------------------------------------------------------
- // configure title
-
- String title(options.title);
-
- if (title.isEmpty())
- {
- title = puglGetWindowTitle(view);
-
- if (title.isEmpty())
- title = "FileBrowser";
- }
+ if (fileBrowserHandle != nullptr)
+ fileBrowserClose(fileBrowserHandle);
- // --------------------------------------------------------------------------
- // show
+ FileBrowserOptions options2 = options;
-# ifdef DISTRHO_OS_MAC
- uint flags = 0x0;
+ if (options2.title == nullptr)
+ options2.title = puglGetWindowTitle(view);
- if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked)
- flags |= 0x001;
- else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked)
- flags |= 0x002;
+ fileBrowserHandle = fileBrowserCreate(isEmbed,
+ puglGetNativeView(view),
+ autoScaling ? autoScaleFactor : scaleFactor,
+ options2);
- if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
- flags |= 0x010;
- else if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked)
- flags |= 0x020;
-
- if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked)
- flags |= 0x100;
- else if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked)
- flags |= 0x200;
-
- return puglMacOSFilePanelOpen(view, startDir, title, flags, openPanelCallback);
-# endif
-
-# ifdef DISTRHO_OS_WINDOWS
- // the old and compatible dialog API
- OPENFILENAMEW ofn;
- memset(&ofn, 0, sizeof(ofn));
- if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled)
- std::free(const_cast(win32SelectedFile));
- win32SelectedFile = nullptr;
-
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = (HWND)puglGetNativeWindow(view);
-
- // set start directory in UTF-16 encoding
- std::vector startDirW;
- startDirW.resize(startDir.length() + 1);
- if (MultiByteToWideChar(CP_UTF8, 0, startDir.buffer(), -1, startDirW.data(), startDirW.size()))
- ofn.lpstrInitialDir = startDirW.data();
-
- // set title in UTF-16 encoding
- std::vector titleW;
- titleW.resize(title.length() + 1);
- if (MultiByteToWideChar(CP_UTF8, 0, title.buffer(), -1, titleW.data(), titleW.size()))
- ofn.lpstrTitle = titleW.data();
-
- // prepare a buffer to receive the result
- std::vector fileNameW(32768); // the Unicode maximum
- ofn.lpstrFile = fileNameW.data();
- ofn.nMaxFile = (DWORD)fileNameW.size();
-
- // flags
- ofn.Flags = OFN_PATHMUSTEXIST;
- if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
- ofn.Flags |= OFN_FORCESHOWHIDDEN;
- if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible)
- ofn.FlagsEx |= OFN_EX_NOPLACESBAR;
-
- // TODO synchronous only, can't do better with WinAPI native dialogs.
- // threading might work, if someone is motivated to risk it.
- if (GetOpenFileNameW(&ofn))
- {
- // back to UTF-8
- std::vector