@@ -163,14 +163,20 @@ LINK_OPTS += -Wl,--strip-all | |||
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 | |||
ifeq ($(WINDOWS),true) | |||
# Assume we want posix | |||
BASE_FLAGS += -posix -D__STDC_FORMAT_MACROS | |||
# 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,6 +190,11 @@ BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden | |||
CXXFLAGS += -fvisibility-inlines-hidden | |||
endif | |||
ifeq ($(WITH_LTO),true) | |||
BASE_FLAGS += -fno-strict-aliasing -flto | |||
LINK_FLAGS += -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) | |||
@@ -238,6 +249,7 @@ HAVE_OPENGL = true | |||
else | |||
HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) | |||
ifneq ($(HAIKU),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) | |||
@@ -250,6 +262,9 @@ endif | |||
HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) | |||
ifeq ($(SKIP_RTAUDIO_FALLBACK),true) | |||
CXXFLAGS += -DDPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK | |||
else | |||
ifeq ($(MACOS),true) | |||
HAVE_RTAUDIO = true | |||
else ifeq ($(WINDOWS),true) | |||
@@ -263,6 +278,7 @@ else ifeq ($(HAVE_PULSEAUDIO),true) | |||
HAVE_RTAUDIO = true | |||
endif | |||
endif | |||
endif | |||
# backwards compat | |||
HAVE_JACK = true | |||
@@ -280,15 +296,19 @@ endif | |||
ifeq ($(WINDOWS),true) | |||
DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32 | |||
# -lole32 | |||
endif | |||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||
ifeq ($(HAVE_DBUS),true) | |||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS | |||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) | |||
endif | |||
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) | |||
@@ -475,6 +495,7 @@ features: | |||
$(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) | |||
@@ -49,9 +49,12 @@ endif | |||
ifeq ($(MACOS),true) | |||
JACK_LIBS += -framework CoreAudio -framework CoreFoundation | |||
else ifeq ($(WINDOWS),true) | |||
JACK_LIBS += -lksuser -lmfplat -lmfuuid -lole32 -lwinmm -lwmcodecdspuuid | |||
JACK_LIBS += -lole32 -lwinmm | |||
# DirectSound | |||
JACK_LIBS += -ldsound | |||
# WASAPI | |||
# JACK_LIBS += -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid | |||
else ifneq ($(HAIKU),true) | |||
JACK_LIBS = -ldl | |||
ifeq ($(HAVE_ALSA),true) | |||
JACK_FLAGS += $(ALSA_FLAGS) | |||
JACK_LIBS += $(ALSA_LIBS) | |||
@@ -68,19 +71,9 @@ 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 | |||
endif | |||
ifeq ($(WINDOWS),true) | |||
VST3_FILENAME = $(TARGET_PROCESSOR)-win/$(NAME).vst3 | |||
# always needed | |||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||
LINK_FLAGS += -ldl | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -93,6 +86,32 @@ ifeq ($(MACOS),true) | |||
OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# 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 | |||
endif | |||
ifeq ($(MACOS),true) | |||
VST3_CONTENTS = $(NAME).vst3/Contents | |||
VST3_FILENAME = $(VST3_CONTENTS)/MacOS/$(NAME) | |||
endif | |||
ifeq ($(WINDOWS),true) | |||
VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-win/$(NAME).vst3 | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Set plugin binary file targets | |||
@@ -103,9 +122,19 @@ 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) | |||
vst2 = $(TARGET_DIR)/$(VST2_FILENAME) | |||
ifneq ($(VST3_FILENAME),) | |||
vst3 = $(TARGET_DIR)/$(NAME).vst3/Contents/$(VST3_FILENAME) | |||
vst3 = $(TARGET_DIR)/$(VST3_FILENAME) | |||
endif | |||
shared = $(TARGET_DIR)/$(NAME)$(LIB_EXT) | |||
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 | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -119,6 +148,7 @@ 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 ($(WINDOWS),true) | |||
SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | |||
SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | |||
@@ -127,6 +157,7 @@ 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 | |||
@@ -135,6 +166,7 @@ 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 | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -238,32 +270,32 @@ all: | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Common | |||
$(BUILD_DIR)/%.S.o: %.S $(EXTRA_LIBS) | |||
$(BUILD_DIR)/%.S.o: %.S | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
@$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.c.o: %.c $(EXTRA_LIBS) | |||
$(BUILD_DIR)/%.c.o: %.c | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cc.o: %.cc $(EXTRA_LIBS) | |||
$(BUILD_DIR)/%.cc.o: %.cc | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cpp.o: %.cpp $(EXTRA_LIBS) | |||
$(BUILD_DIR)/%.cpp.o: %.cpp | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.m.o: %.m $(EXTRA_LIBS) | |||
$(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 $(EXTRA_LIBS) | |||
$(BUILD_DIR)/%.mm.o: %.mm | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||
@@ -291,27 +323,27 @@ $(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 $@ | |||
$(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 $@ | |||
@@ -322,13 +354,13 @@ $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||
jack: $(jack) | |||
ifeq ($(HAVE_DGL),true) | |||
$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) | |||
else | |||
$(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 | |||
@@ -365,13 +397,13 @@ lv2_dsp: $(lv2_dsp) | |||
lv2_sep: $(lv2_dsp) $(lv2_ui) | |||
ifeq ($(HAVE_DGL),true) | |||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||
else | |||
$(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) -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 $@) | |||
@@ -386,30 +418,59 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# 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) $(EXTRA_LIBS) | |||
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) | |||
else | |||
$(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) $(EXTRA_LIBS) | |||
$(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 $@ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# macOS files | |||
$(TARGET_DIR)/%/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 $< $@ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -424,11 +485,13 @@ 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)/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 | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -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,6 +139,9 @@ 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}) | |||
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||
target_link_libraries("${NAME}-ui" PRIVATE "dl") | |||
endif() | |||
# add the files containing Objective-C classes, recompiled under namespace | |||
dpf__add_plugin_specific_ui_sources("${NAME}-ui") | |||
else() | |||
@@ -185,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") | |||
@@ -303,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 | |||
"$<TARGET_FILE:lv2_ttl_generator>" | |||
"$<TARGET_FILE:${NAME}-lv2>" | |||
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2" | |||
@@ -414,7 +416,7 @@ function(dpf__build_vst3 NAME DGL_LIBRARY) | |||
SUFFIX "") | |||
elseif(WIN32) | |||
set_target_properties("${NAME}-vst3" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-win/$<0:>") | |||
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:>") | |||
@@ -80,6 +80,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(). | |||
@@ -130,6 +130,23 @@ enum CrossingMode { | |||
kCrossingUngrab ///< Crossing due to a grab release | |||
}; | |||
/** | |||
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. | |||
@@ -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 | |||
{ | |||
@@ -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 ImageType> | |||
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 ImageType> | |||
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 ImageType> | |||
class ImageBaseKnob : public SubWidget, | |||
public KnobEventHandler | |||
@@ -13,6 +13,12 @@ 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 ($(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 ($(USE_OPENGL3),true) | |||
BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | |||
endif | |||
@@ -42,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 | |||
@@ -444,6 +453,11 @@ public: | |||
*/ | |||
void globalAlpha(float alpha); | |||
/** | |||
Sets the color tint applied to all rendered shapes. | |||
*/ | |||
void globalTint(Color tint); | |||
/* -------------------------------------------------------------------- | |||
* Transforms */ | |||
@@ -943,7 +957,6 @@ private: | |||
inline void onDisplay() override | |||
{ | |||
// NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | |||
NanoVG::reset(); | |||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | |||
onNanoDisplay(); | |||
NanoVG::endFrame(); | |||
@@ -101,13 +101,17 @@ public: | |||
void repaint(const Rectangle<uint>& rect) noexcept; | |||
// TODO group stuff after here, convenience functions present in Window class | |||
bool setClipboard(const char* mimeType, const void* data, size_t dataSize); | |||
const void* getClipboard(const char*& mimeType, 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(); } | |||
@@ -129,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) | |||
}; | |||
@@ -19,9 +19,14 @@ | |||
#include "Geometry.hpp" | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
# include "../distrho/extra/FileBrowserDialog.hpp" | |||
#endif | |||
START_NAMESPACE_DGL | |||
class Application; | |||
class PluginWindow; | |||
class TopLevelWidget; | |||
// ----------------------------------------------------------------------- | |||
@@ -53,53 +58,9 @@ class Window | |||
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 | |||
typedef DISTRHO_NAMESPACE::FileBrowserHandle FileBrowserHandle; | |||
typedef DISTRHO_NAMESPACE::FileBrowserOptions FileBrowserOptions; | |||
#endif | |||
/** | |||
Window graphics context as a scoped struct. | |||
@@ -302,6 +263,36 @@ public: | |||
*/ | |||
void setIgnoringKeyRepeat(bool ignore) noexcept; | |||
/** | |||
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); | |||
/** | |||
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. | |||
*/ | |||
const void* getClipboard(const char*& mimeType, 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 +352,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. | |||
@@ -408,7 +399,8 @@ public: | |||
void setGeometryConstraints(uint minimumWidth, | |||
uint minimumHeight, | |||
bool keepAspectRatio = false, | |||
bool automaticallyScale = false); | |||
bool automaticallyScale = false, | |||
bool resizeNowIfAutoScaling = true); | |||
/** DEPRECATED Use isIgnoringKeyRepeat(). */ | |||
DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | |||
@@ -482,6 +474,7 @@ private: | |||
uint height, | |||
double scaleFactor, | |||
bool resizable, | |||
bool isVST3, | |||
bool doPostInit); | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); | |||
@@ -56,6 +56,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,) | |||
@@ -152,6 +152,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,); | |||
@@ -30,12 +30,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 { | |||
@@ -91,6 +97,9 @@ struct Application::PrivateData { | |||
For standalone mode only. */ | |||
void quit(); | |||
/** Get time via pugl */ | |||
double getTime() const; | |||
/** Set pugl world class name. */ | |||
void setClassName(const char* name); | |||
@@ -22,8 +22,8 @@ START_NAMESPACE_DGL | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
template <class ImageType> | |||
ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, const ImageType& image) | |||
: StandaloneWindow(parentWindow.getApp(), parentWindow), | |||
ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& transientParentWindow, const ImageType& image) | |||
: StandaloneWindow(transientParentWindow.getApp(), transientParentWindow), | |||
img(image) | |||
{ | |||
setResizable(false); | |||
@@ -39,8 +39,8 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, cons | |||
} | |||
template <class ImageType> | |||
ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const parentTopLevelWidget, const ImageType& image) | |||
: StandaloneWindow(parentTopLevelWidget->getApp(), parentTopLevelWidget->getWindow()), | |||
ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const topLevelWidget, const ImageType& image) | |||
: StandaloneWindow(topLevelWidget->getApp(), topLevelWidget->getWindow()), | |||
img(image) | |||
{ | |||
setResizable(false); | |||
@@ -102,28 +102,32 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||
#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) | |||
@@ -189,13 +193,9 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||
# pragma GCC diagnostic pop | |||
# endif | |||
#endif | |||
return nvgCreateGL(flags); | |||
return nvgCreateGLfn(flags); | |||
} | |||
// ----------------------------------------------------------------------- | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
// DGL Color class conversion | |||
@@ -312,7 +312,7 @@ NanoVG::Paint::operator NVGpaint() const noexcept | |||
// NanoVG | |||
NanoVG::NanoVG(int flags) | |||
: fContext(nvgCreateGL_helper(flags)), | |||
: fContext(nvgCreateGL(flags)), | |||
fInFrame(false), | |||
fIsSubWidget(false) {} | |||
@@ -513,6 +513,12 @@ void NanoVG::globalAlpha(float alpha) | |||
nvgGlobalAlpha(fContext, alpha); | |||
} | |||
void NanoVG::globalTint(Color tint) | |||
{ | |||
if (fContext != nullptr) | |||
nvgGlobalTint(fContext, tint); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Transforms | |||
@@ -35,8 +35,8 @@ template<typename T> | |||
bool SubWidget::contains(const T x, const T y) const noexcept | |||
{ | |||
return Rectangle<double>(0, 0, | |||
static_cast<double>(getWidth()) - pData->margin.getX(), | |||
static_cast<double>(getHeight()) - pData->margin.getY()).contains(x, y); | |||
static_cast<double>(getWidth()), | |||
static_cast<double>(getHeight())).contains(x, y); | |||
} | |||
template<typename T> | |||
@@ -67,9 +67,18 @@ Rectangle<int> SubWidget::getAbsoluteArea() const noexcept | |||
Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept | |||
{ | |||
return Rectangle<uint>(static_cast<uint>(std::max(0, getAbsoluteX())), | |||
static_cast<uint>(std::max(0, getAbsoluteY())), | |||
getSize()); | |||
const int x = getAbsoluteX(); | |||
const int y = getAbsoluteY(); | |||
if (x >= 0 && y >= 0) | |||
return Rectangle<uint>(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<int>(getWidth()) + xOffset); | |||
const int height = std::max(0, static_cast<int>(getHeight()) + yOffset); | |||
return Rectangle<uint>(0, 0, static_cast<uint>(width), static_cast<uint>(height)); | |||
} | |||
void SubWidget::setAbsoluteX(const int x) noexcept | |||
@@ -60,6 +60,21 @@ void TopLevelWidget::setSize(const Size<uint>& size) | |||
pData->window.setSize(size); | |||
} | |||
bool TopLevelWidget::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) | |||
{ | |||
return pData->window.setClipboard(mimeType, data, dataSize); | |||
} | |||
const void* TopLevelWidget::getClipboard(const char*& mimeType, size_t& dataSize) | |||
{ | |||
return pData->window.getClipboard(mimeType, 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,36 +103,47 @@ void TopLevelWidget::repaint(const Rectangle<uint>& 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::onCharacterInput(const CharacterInputEvent&) | |||
bool TopLevelWidget::onCharacterInput(const CharacterInputEvent& ev) | |||
{ | |||
return false; | |||
return pData->characterInputEvent(ev); | |||
} | |||
bool TopLevelWidget::onMouse(const MouseEvent&) | |||
bool TopLevelWidget::onMouse(const MouseEvent& ev) | |||
{ | |||
return false; | |||
return pData->mouseEvent(ev); | |||
} | |||
bool TopLevelWidget::onMotion(const MotionEvent&) | |||
bool TopLevelWidget::onMotion(const MotionEvent& ev) | |||
{ | |||
return false; | |||
return pData->motionEvent(ev); | |||
} | |||
bool TopLevelWidget::onScroll(const ScrollEvent&) | |||
bool TopLevelWidget::onScroll(const ScrollEvent& ev) | |||
{ | |||
return pData->scrollEvent(ev); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
void TopLevelWidget::requestSizeChange(uint, uint) | |||
{ | |||
return false; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
@@ -42,10 +42,6 @@ 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); | |||
} | |||
@@ -56,10 +52,6 @@ bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& | |||
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); | |||
} | |||
@@ -82,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); | |||
} | |||
@@ -108,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); | |||
} | |||
@@ -136,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); | |||
} | |||
@@ -30,7 +30,7 @@ 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); | |||
@@ -112,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<SubWidget*>(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()); | |||
} | |||
} | |||
@@ -151,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<SubWidget*>(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()); | |||
} | |||
} | |||
@@ -190,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<SubWidget*>(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()); | |||
} | |||
} | |||
@@ -15,6 +15,7 @@ | |||
*/ | |||
#include "WindowPrivateData.hpp" | |||
#include "../TopLevelWidget.hpp" | |||
#include "pugl.hpp" | |||
@@ -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(); | |||
@@ -199,8 +201,14 @@ void Window::setSize(uint width, uint height) | |||
if (pData->isEmbed) | |||
{ | |||
const double scaleFactor = pData->scaleFactor; | |||
const uint minWidth = static_cast<uint>(pData->minWidth * scaleFactor + 0.5); | |||
const uint minHeight = static_cast<uint>(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) | |||
@@ -228,7 +236,19 @@ void Window::setSize(uint width, uint height) | |||
} | |||
} | |||
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 | |||
{ | |||
puglSetWindowSize(pData->view, width, height); | |||
} | |||
} | |||
void Window::setSize(const Size<uint>& size) | |||
@@ -257,6 +277,25 @@ void Window::setIgnoringKeyRepeat(const bool ignore) noexcept | |||
puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); | |||
} | |||
bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) | |||
{ | |||
return puglSetClipboard(pData->view, mimeType, data, dataSize) == PUGL_SUCCESS; | |||
} | |||
const void* Window::getClipboard(const char*& mimeType, size_t& dataSize) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(!pData->ignoreEvents, nullptr); | |||
pData->ignoreEvents = true; | |||
const void* const clipboard = puglGetClipboard(pData->view, &mimeType, &dataSize); | |||
pData->ignoreEvents = false; | |||
return clipboard; | |||
} | |||
bool Window::setCursor(const MouseCursor cursor) | |||
{ | |||
return puglSetCursor(pData->view, static_cast<PuglCursor>(cursor)) == PUGL_SUCCESS; | |||
} | |||
bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false) | |||
@@ -352,10 +391,11 @@ Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio) | |||
return Size<uint>(pData->minWidth, pData->minHeight); | |||
} | |||
void Window::setGeometryConstraints(const uint minimumWidth, | |||
const uint minimumHeight, | |||
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,); | |||
@@ -370,12 +410,15 @@ void Window::setGeometryConstraints(const uint minimumWidth, | |||
const double scaleFactor = pData->scaleFactor; | |||
puglSetGeometryConstraints(pData->view, | |||
static_cast<uint>(minimumWidth * scaleFactor + 0.5), | |||
static_cast<uint>(minimumHeight * scaleFactor + 0.5), | |||
keepAspectRatio); | |||
if (automaticallyScale && scaleFactor != 1.0) | |||
{ | |||
minimumWidth *= scaleFactor; | |||
minimumHeight *= scaleFactor; | |||
} | |||
puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio); | |||
if (scaleFactor != 1.0) | |||
if (scaleFactor != 1.0 && automaticallyScale && resizeNowIfAutoScaling) | |||
{ | |||
const Size<uint> size(getSize()); | |||
@@ -19,18 +19,7 @@ | |||
#include "pugl.hpp" | |||
#include "../../distrho/extra/String.hpp" | |||
#ifdef DISTRHO_OS_WINDOWS | |||
# include <direct.h> | |||
# include <winsock2.h> | |||
# include <windows.h> | |||
# include <vector> | |||
#else | |||
# include <unistd.h> | |||
#endif | |||
#define DGL_DEBUG_EVENTS | |||
// #define DGL_DEBUG_EVENTS | |||
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||
# ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||
@@ -63,11 +52,6 @@ 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) | |||
{ | |||
// allow custom scale for testing | |||
@@ -92,6 +76,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
isClosed(true), | |||
isVisible(false), | |||
isEmbed(false), | |||
usesSizeRequest(false), | |||
scaleFactor(getDesktopScaleFactor(view)), | |||
autoScaling(false), | |||
autoScaleFactor(1.0), | |||
@@ -99,9 +84,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
ignoreEvents(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
fileBrowserHandle(nullptr), | |||
#endif | |||
modal() | |||
{ | |||
@@ -118,6 +104,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
isClosed(true), | |||
isVisible(false), | |||
isEmbed(false), | |||
usesSizeRequest(false), | |||
scaleFactor(ppData->scaleFactor), | |||
autoScaling(false), | |||
autoScaleFactor(1.0), | |||
@@ -125,9 +112,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
ignoreEvents(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
fileBrowserHandle(nullptr), | |||
#endif | |||
modal(ppData) | |||
{ | |||
@@ -148,6 +136,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
isClosed(parentWindowHandle == 0), | |||
isVisible(parentWindowHandle != 0), | |||
isEmbed(parentWindowHandle != 0), | |||
usesSizeRequest(false), | |||
scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | |||
autoScaling(false), | |||
autoScaleFactor(1.0), | |||
@@ -155,9 +144,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
ignoreEvents(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
fileBrowserHandle(nullptr), | |||
#endif | |||
modal() | |||
{ | |||
@@ -170,7 +160,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
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), | |||
@@ -180,6 +170,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
isClosed(parentWindowHandle == 0), | |||
isVisible(parentWindowHandle != 0 && view != nullptr), | |||
isEmbed(parentWindowHandle != 0), | |||
usesSizeRequest(isVST3), | |||
scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | |||
autoScaling(false), | |||
autoScaleFactor(1.0), | |||
@@ -187,9 +178,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
ignoreEvents(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
fileBrowserHandle(nullptr), | |||
#endif | |||
modal() | |||
{ | |||
@@ -210,8 +202,9 @@ Window::PrivateData::~PrivateData() | |||
if (isEmbed) | |||
{ | |||
#ifdef HAVE_X11 | |||
sofdFileDialogClose(); | |||
#ifndef DGL_FILE_BROWSER_DISABLED | |||
if (fileBrowserHandle != nullptr) | |||
fileBrowserClose(fileBrowserHandle); | |||
#endif | |||
puglHide(view); | |||
appData->oneWindowClosed(); | |||
@@ -219,11 +212,6 @@ Window::PrivateData::~PrivateData() | |||
isVisible = false; | |||
} | |||
#ifdef DISTRHO_OS_WINDOWS | |||
if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) | |||
std::free(const_cast<char*>(win32SelectedFile)); | |||
#endif | |||
puglFreeView(view); | |||
} | |||
@@ -367,9 +355,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; | |||
@@ -411,20 +404,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<char*>(path)); | |||
self->onFileSelected(fileBrowserGetPath(fileBrowserHandle)); | |||
fileBrowserClose(fileBrowserHandle); | |||
fileBrowserHandle = nullptr; | |||
} | |||
# endif | |||
# ifdef HAVE_X11 | |||
if (sofdFileDialogIdle(view)) | |||
self->onFileSelected(sofdFileDialogGetPath()); | |||
# endif | |||
#endif | |||
} | |||
@@ -464,164 +449,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 | |||
} | |||
if (fileBrowserHandle != nullptr) | |||
fileBrowserClose(fileBrowserHandle); | |||
DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | |||
FileBrowserOptions options2 = options; | |||
if (! startDir.endsWith(DISTRHO_OS_SEP)) | |||
startDir += DISTRHO_OS_SEP_STR; | |||
if (options2.title == nullptr) | |||
options2.title = puglGetWindowTitle(view); | |||
// -------------------------------------------------------------------------- | |||
// configure title | |||
fileBrowserHandle = fileBrowserCreate(isEmbed, | |||
puglGetNativeWindow(view), | |||
autoScaling ? autoScaleFactor : scaleFactor, | |||
options2); | |||
String title(options.title); | |||
if (title.isEmpty()) | |||
{ | |||
title = puglGetWindowTitle(view); | |||
if (title.isEmpty()) | |||
title = "FileBrowser"; | |||
} | |||
// -------------------------------------------------------------------------- | |||
// show | |||
# ifdef DISTRHO_OS_MAC | |||
uint flags = 0x0; | |||
if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||
flags |= 0x001; | |||
else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||
flags |= 0x002; | |||
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<char*>(win32SelectedFile)); | |||
win32SelectedFile = nullptr; | |||
ofn.lStructSize = sizeof(ofn); | |||
ofn.hwndOwner = (HWND)puglGetNativeWindow(view); | |||
// set start directory in UTF-16 encoding | |||
std::vector<WCHAR> startDirW; | |||
startDirW.resize(startDir.length() + 1); | |||
if (MultiByteToWideChar(CP_UTF8, 0, startDir.buffer(), -1, startDirW.data(), static_cast<int>(startDirW.size()))) | |||
ofn.lpstrInitialDir = startDirW.data(); | |||
// set title in UTF-16 encoding | |||
std::vector<WCHAR> titleW; | |||
titleW.resize(title.length() + 1); | |||
if (MultiByteToWideChar(CP_UTF8, 0, title.buffer(), -1, titleW.data(), static_cast<int>(titleW.size()))) | |||
ofn.lpstrTitle = titleW.data(); | |||
// prepare a buffer to receive the result | |||
std::vector<WCHAR> 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<char> fileNameA(4 * 32768); | |||
if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, | |||
fileNameA.data(), (int)fileNameA.size(), | |||
nullptr, nullptr)) | |||
{ | |||
// handle it during the next idle cycle (fake async) | |||
win32SelectedFile = strdup(fileNameA.data()); | |||
} | |||
} | |||
if (win32SelectedFile == nullptr) | |||
win32SelectedFile = kWin32SelectedFileCancelled; | |||
return true; | |||
# endif | |||
# ifdef HAVE_X11 | |||
uint flags = 0x0; | |||
if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||
flags |= 0x001; | |||
else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||
flags |= 0x002; | |||
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 sofdFileDialogShow(view, startDir, title, flags, autoScaling ? autoScaleFactor : scaleFactor); | |||
# endif | |||
return false; | |||
} | |||
# ifdef DISTRHO_OS_MAC | |||
void Window::PrivateData::openPanelCallback(PuglView* const view, const char* const path) | |||
{ | |||
((Window::PrivateData*)puglGetHandle(view))->self->onFileSelected(path); | |||
return fileBrowserHandle != nullptr; | |||
} | |||
# endif | |||
#endif // ! DGL_FILE_BROWSER_DISABLED | |||
// ----------------------------------------------------------------------- | |||
@@ -822,7 +666,7 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->keyboardEvent(ev)) | |||
if (widget->isVisible() && widget->onKeyboard(ev)) | |||
break; | |||
} | |||
#endif | |||
@@ -840,7 +684,7 @@ void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->characterInputEvent(ev)) | |||
if (widget->isVisible() && widget->onCharacterInput(ev)) | |||
break; | |||
} | |||
#endif | |||
@@ -858,7 +702,7 @@ void Window::PrivateData::onPuglMouse(const Widget::MouseEvent& ev) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->mouseEvent(ev)) | |||
if (widget->isVisible() && widget->onMouse(ev)) | |||
break; | |||
} | |||
#endif | |||
@@ -876,7 +720,7 @@ void Window::PrivateData::onPuglMotion(const Widget::MotionEvent& ev) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->motionEvent(ev)) | |||
if (widget->isVisible() && widget->onMotion(ev)) | |||
break; | |||
} | |||
#endif | |||
@@ -894,7 +738,7 @@ void Window::PrivateData::onPuglScroll(const Widget::ScrollEvent& ev) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->scrollEvent(ev)) | |||
if (widget->isVisible() && widget->onScroll(ev)) | |||
break; | |||
} | |||
#endif | |||
@@ -908,7 +752,9 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
{ | |||
Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); | |||
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||
printEvent(event, "pugl event: ", true); | |||
if (event->type != PUGL_TIMER) { | |||
printEvent(event, "pugl event: ", true); | |||
} | |||
#endif | |||
switch (event->type) | |||
@@ -921,7 +767,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
case PUGL_CREATE: | |||
#ifdef HAVE_X11 | |||
if (! pData->isEmbed) | |||
puglX11SetWindowTypeAndPID(view); | |||
puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone); | |||
#endif | |||
break; | |||
@@ -949,6 +795,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< View must be drawn, a #PuglEventExpose | |||
case PUGL_EXPOSE: | |||
if (pData->ignoreEvents) | |||
break; | |||
// unused x, y, width, height (double) | |||
pData->onPuglExpose(); | |||
break; | |||
@@ -962,6 +810,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
case PUGL_FOCUS_IN: | |||
///< Keyboard focus left view, a #PuglEventFocus | |||
case PUGL_FOCUS_OUT: | |||
if (pData->ignoreEvents) | |||
break; | |||
pData->onPuglFocus(event->type == PUGL_FOCUS_IN, | |||
static_cast<CrossingMode>(event->focus.mode)); | |||
break; | |||
@@ -971,6 +821,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< Key released, a #PuglEventKey | |||
case PUGL_KEY_RELEASE: | |||
{ | |||
if (pData->ignoreEvents) | |||
break; | |||
// unused x, y, xRoot, yRoot (double) | |||
Widget::KeyboardEvent ev; | |||
ev.mod = event->key.state; | |||
@@ -994,6 +846,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< Character entered, a #PuglEventText | |||
case PUGL_TEXT: | |||
{ | |||
if (pData->ignoreEvents) | |||
break; | |||
// unused x, y, xRoot, yRoot (double) | |||
Widget::CharacterInputEvent ev; | |||
ev.mod = event->text.state; | |||
@@ -1018,6 +872,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< Mouse button released, a #PuglEventButton | |||
case PUGL_BUTTON_RELEASE: | |||
{ | |||
if (pData->ignoreEvents) | |||
break; | |||
Widget::MouseEvent ev; | |||
ev.mod = event->button.state; | |||
ev.flags = event->button.flags; | |||
@@ -1033,6 +889,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< Pointer moved, a #PuglEventMotion | |||
case PUGL_MOTION: | |||
{ | |||
if (pData->ignoreEvents) | |||
break; | |||
Widget::MotionEvent ev; | |||
ev.mod = event->motion.state; | |||
ev.flags = event->motion.flags; | |||
@@ -1046,6 +904,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
///< Scrolled, a #PuglEventScroll | |||
case PUGL_SCROLL: | |||
{ | |||
if (pData->ignoreEvents) | |||
break; | |||
Widget::ScrollEvent ev; | |||
ev.mod = event->scroll.state; | |||
ev.flags = event->scroll.flags; | |||
@@ -1064,6 +924,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||