Signed-off-by: falkTX <falktx@gmail.com>vstgui
@@ -16,6 +16,7 @@ ifeq ($(HAVE_DGL),true) | |||||
endif | endif | ||||
examples: dgl | examples: dgl | ||||
$(MAKE) all -C examples/ExternalUI | |||||
$(MAKE) all -C examples/Info | $(MAKE) all -C examples/Info | ||||
$(MAKE) all -C examples/Latency | $(MAKE) all -C examples/Latency | ||||
$(MAKE) all -C examples/Meters | $(MAKE) all -C examples/Meters | ||||
@@ -23,6 +24,13 @@ examples: dgl | |||||
$(MAKE) all -C examples/Parameters | $(MAKE) all -C examples/Parameters | ||||
$(MAKE) all -C examples/States | $(MAKE) all -C examples/States | ||||
# ExternalUI launcher | |||||
install -d bin/d_extui-dssi | |||||
install -d bin/d_extui.lv2 | |||||
install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.sh | |||||
install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui-dssi/d_extui.sh | |||||
install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.lv2/d_extui.sh | |||||
ifneq ($(CROSS_COMPILING),true) | ifneq ($(CROSS_COMPILING),true) | ||||
gen: examples utils/lv2_ttl_generator | gen: examples utils/lv2_ttl_generator | ||||
@$(CURDIR)/utils/generate-ttl.sh | @$(CURDIR)/utils/generate-ttl.sh | ||||
@@ -40,6 +48,7 @@ endif | |||||
clean: | clean: | ||||
$(MAKE) clean -C dgl | $(MAKE) clean -C dgl | ||||
$(MAKE) clean -C examples/ExternalUI | |||||
$(MAKE) clean -C examples/Info | $(MAKE) clean -C examples/Info | ||||
$(MAKE) clean -C examples/Latency | $(MAKE) clean -C examples/Latency | ||||
$(MAKE) clean -C examples/Meters | $(MAKE) clean -C examples/Meters | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -20,7 +20,8 @@ | |||||
#include "extra/LeakDetector.hpp" | #include "extra/LeakDetector.hpp" | ||||
#include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
#ifndef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include "../dgl/Base.hpp" | |||||
# include "extra/ExternalWindow.hpp" | # include "extra/ExternalWindow.hpp" | ||||
typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | ||||
#elif DISTRHO_UI_USE_NANOVG | #elif DISTRHO_UI_USE_NANOVG | ||||
@@ -67,7 +68,7 @@ public: | |||||
*/ | */ | ||||
bool isUserResizable() const noexcept; | bool isUserResizable() const noexcept; | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | /** | ||||
Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. | Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. | ||||
@see Window::setGeometryConstraints(uint,uint,bool) | @see Window::setGeometryConstraints(uint,uint,bool) | ||||
@@ -181,7 +182,7 @@ protected: | |||||
*/ | */ | ||||
virtual void sampleRateChanged(double newSampleRate); | virtual void sampleRateChanged(double newSampleRate); | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* UI Callbacks (optional) */ | * UI Callbacks (optional) */ | ||||
@@ -191,13 +192,13 @@ protected: | |||||
*/ | */ | ||||
virtual void uiIdle() {} | virtual void uiIdle() {} | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | /** | ||||
File browser selected function. | File browser selected function. | ||||
@see Window::fileBrowserSelected(const char*) | @see Window::fileBrowserSelected(const char*) | ||||
*/ | */ | ||||
virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
#endif | |||||
# endif | |||||
/** | /** | ||||
OpenGL window reshape function, called when parent window is resized. | OpenGL window reshape function, called when parent window is resized. | ||||
@@ -225,7 +226,7 @@ private: | |||||
friend class UIExporter; | friend class UIExporter; | ||||
friend class UIExporterWindow; | friend class UIExporterWindow; | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// these should not be used | // these should not be used | ||||
void setAbsoluteX(int) const noexcept {} | void setAbsoluteX(int) const noexcept {} | ||||
void setAbsoluteY(int) const noexcept {} | void setAbsoluteY(int) const noexcept {} | ||||
@@ -40,6 +40,8 @@ public: | |||||
: width(w), | : width(w), | ||||
height(h), | height(h), | ||||
title(t), | title(t), | ||||
transientWinId(0), | |||||
visible(false), | |||||
pid(0) {} | pid(0) {} | ||||
virtual ~ExternalWindow() | virtual ~ExternalWindow() | ||||
@@ -62,9 +64,14 @@ public: | |||||
return title; | return title; | ||||
} | } | ||||
void setTitle(const char* const t) noexcept | |||||
uintptr_t getTransientWinId() const noexcept | |||||
{ | { | ||||
title = t; | |||||
return transientWinId; | |||||
} | |||||
bool isVisible() const noexcept | |||||
{ | |||||
return visible; | |||||
} | } | ||||
bool isRunning() noexcept | bool isRunning() noexcept | ||||
@@ -84,6 +91,27 @@ public: | |||||
return true; | return true; | ||||
} | } | ||||
virtual void setSize(uint w, uint h) | |||||
{ | |||||
width = w; | |||||
height = h; | |||||
} | |||||
virtual void setTitle(const char* const t) | |||||
{ | |||||
title = t; | |||||
} | |||||
virtual void setTransientWinId(const uintptr_t winId) | |||||
{ | |||||
transientWinId = winId; | |||||
} | |||||
virtual void setVisible(const bool yesNo) | |||||
{ | |||||
visible = yesNo; | |||||
} | |||||
protected: | protected: | ||||
bool startExternalProcess(const char* args[]) | bool startExternalProcess(const char* args[]) | ||||
{ | { | ||||
@@ -107,14 +135,6 @@ protected: | |||||
} | } | ||||
} | } | ||||
private: | |||||
uint width; | |||||
uint height; | |||||
String title; | |||||
pid_t pid; | |||||
friend class UIExporter; | |||||
void terminateAndWaitForProcess() | void terminateAndWaitForProcess() | ||||
{ | { | ||||
if (pid <= 0) | if (pid <= 0) | ||||
@@ -162,6 +182,16 @@ private: | |||||
} | } | ||||
} | } | ||||
private: | |||||
uint width; | |||||
uint height; | |||||
String title; | |||||
uintptr_t transientWinId; | |||||
bool visible; | |||||
pid_t pid; | |||||
friend class UIExporter; | |||||
DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | ||||
}; | }; | ||||
@@ -16,11 +16,6 @@ | |||||
#include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
# undef DISTRHO_PLUGIN_HAS_UI | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
# include "DistrhoUIInternal.hpp" | # include "DistrhoUIInternal.hpp" | ||||
#else | #else | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,8 +15,7 @@ | |||||
*/ | */ | ||||
#include "DistrhoUIInternal.hpp" | #include "DistrhoUIInternal.hpp" | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include "src/WidgetPrivateData.hpp" | # include "src/WidgetPrivateData.hpp" | ||||
#endif | #endif | ||||
@@ -27,16 +26,21 @@ START_NAMESPACE_DISTRHO | |||||
double d_lastUiSampleRate = 0.0; | double d_lastUiSampleRate = 0.0; | ||||
void* d_lastUiDspPtr = nullptr; | void* d_lastUiDspPtr = nullptr; | ||||
#ifdef HAVE_DGL | |||||
Window* d_lastUiWindow = nullptr; | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uintptr_t g_nextWindowId = 0; | uintptr_t g_nextWindowId = 0; | ||||
const char* g_nextBundlePath = nullptr; | const char* g_nextBundlePath = nullptr; | ||||
#else | |||||
Window* d_lastUiWindow = nullptr; | |||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI */ | * UI */ | ||||
#ifdef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
UI::UI(uint width, uint height, bool userResizable) | |||||
: UIWidget(width, height), | |||||
pData(new PrivateData(userResizable)) {} | |||||
#else | |||||
UI::UI(uint width, uint height, bool userResizable) | UI::UI(uint width, uint height, bool userResizable) | ||||
: UIWidget(*d_lastUiWindow), | : UIWidget(*d_lastUiWindow), | ||||
pData(new PrivateData(userResizable)) | pData(new PrivateData(userResizable)) | ||||
@@ -46,10 +50,6 @@ UI::UI(uint width, uint height, bool userResizable) | |||||
if (width > 0 && height > 0) | if (width > 0 && height > 0) | ||||
setSize(width, height); | setSize(width, height); | ||||
} | } | ||||
#else | |||||
UI::UI(uint width, uint height, bool userResizable) | |||||
: UIWidget(width, height), | |||||
pData(new PrivateData(userResizable)) {} | |||||
#endif | #endif | ||||
UI::~UI() | UI::~UI() | ||||
@@ -62,7 +62,7 @@ bool UI::isUserResizable() const noexcept | |||||
return pData->userResizable; | return pData->userResizable; | ||||
} | } | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) | void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); | DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); | ||||
@@ -73,7 +73,6 @@ void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRa | |||||
pData->minHeight = minHeight; | pData->minHeight = minHeight; | ||||
getParentWindow().setGeometryConstraints(minWidth, minHeight, keepAspectRatio); | getParentWindow().setGeometryConstraints(minWidth, minHeight, keepAspectRatio); | ||||
} | } | ||||
#endif | #endif | ||||
@@ -141,15 +140,15 @@ uintptr_t UI::getNextWindowId() noexcept | |||||
void UI::sampleRateChanged(double) {} | void UI::sampleRateChanged(double) {} | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI Callbacks (optional) */ | * UI Callbacks (optional) */ | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | |||||
void UI::uiFileBrowserSelected(const char*) | void UI::uiFileBrowserSelected(const char*) | ||||
{ | { | ||||
} | } | ||||
#endif | |||||
# endif | |||||
void UI::uiReshape(uint width, uint height) | void UI::uiReshape(uint width, uint height) | ||||
{ | { | ||||
@@ -173,7 +172,7 @@ void UI::onResize(const ResizeEvent& ev) | |||||
pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); | pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); | ||||
} | } | ||||
#endif | |||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
@@ -112,6 +112,7 @@ public: | |||||
void exec() | void exec() | ||||
{ | { | ||||
d_stdout("exec 1"); | |||||
for (;;) | for (;;) | ||||
{ | { | ||||
fOscData.idle(); | fOscData.idle(); | ||||
@@ -121,6 +122,7 @@ public: | |||||
d_msleep(30); | d_msleep(30); | ||||
} | } | ||||
d_stdout("exec 3"); | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -19,7 +19,10 @@ | |||||
#include "../DistrhoUI.hpp" | #include "../DistrhoUI.hpp" | ||||
#ifdef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
# include "../extra/Sleep.hpp" | |||||
using DGL_NAMESPACE::IdleCallback; | |||||
#else | |||||
# include "../../dgl/Application.hpp" | # include "../../dgl/Application.hpp" | ||||
# include "../../dgl/Window.hpp" | # include "../../dgl/Window.hpp" | ||||
using DGL_NAMESPACE::Application; | using DGL_NAMESPACE::Application; | ||||
@@ -34,7 +37,7 @@ START_NAMESPACE_DISTRHO | |||||
extern double d_lastUiSampleRate; | extern double d_lastUiSampleRate; | ||||
extern void* d_lastUiDspPtr; | extern void* d_lastUiDspPtr; | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
extern Window* d_lastUiWindow; | extern Window* d_lastUiWindow; | ||||
#endif | #endif | ||||
extern uintptr_t g_nextWindowId; | extern uintptr_t g_nextWindowId; | ||||
@@ -146,7 +149,20 @@ struct UI::PrivateData { | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Plugin Window, needed to take care of resize properly | // Plugin Window, needed to take care of resize properly | ||||
#ifdef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static inline | |||||
UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
g_nextWindowId = winId; | |||||
g_nextBundlePath = bundlePath; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
g_nextWindowId = 0; | |||||
g_nextBundlePath = nullptr; | |||||
return ret; | |||||
} | |||||
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static inline | static inline | ||||
UI* createUiWrapper(void* const dspPtr, Window* const window) | UI* createUiWrapper(void* const dspPtr, Window* const window) | ||||
{ | { | ||||
@@ -212,7 +228,7 @@ protected: | |||||
fIsReady = true; | fIsReady = true; | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | |||||
// custom file-browser selected | // custom file-browser selected | ||||
void fileBrowserSelected(const char* filename) override | void fileBrowserSelected(const char* filename) override | ||||
{ | { | ||||
@@ -220,26 +236,13 @@ protected: | |||||
fUI->uiFileBrowserSelected(filename); | fUI->uiFileBrowserSelected(filename); | ||||
} | } | ||||
#endif | |||||
# endif | |||||
private: | private: | ||||
UI* const fUI; | UI* const fUI; | ||||
bool fIsReady; | bool fIsReady; | ||||
}; | }; | ||||
#else | |||||
static inline | |||||
UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
g_nextWindowId = winId; | |||||
g_nextBundlePath = bundlePath; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
g_nextWindowId = 0; | |||||
g_nextBundlePath = nullptr; | |||||
return ret; | |||||
} | |||||
#endif | |||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// UI exporter class | // UI exporter class | ||||
@@ -256,13 +259,13 @@ public: | |||||
const setSizeFunc setSizeCall, | const setSizeFunc setSizeCall, | ||||
void* const dspPtr = nullptr, | void* const dspPtr = nullptr, | ||||
const char* const bundlePath = nullptr) | const char* const bundlePath = nullptr) | ||||
#ifdef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
: fUI(createUiWrapper(dspPtr, winId, bundlePath)), | |||||
#else | |||||
: glApp(), | : glApp(), | ||||
glWindow(glApp, winId, dspPtr), | glWindow(glApp, winId, dspPtr), | ||||
fChangingSize(false), | fChangingSize(false), | ||||
fUI(glWindow.getUI()), | fUI(glWindow.getUI()), | ||||
#else | |||||
: fUI(createUiWrapper(dspPtr, winId, bundlePath)), | |||||
#endif | #endif | ||||
fData((fUI != nullptr) ? fUI->pData : nullptr) | fData((fUI != nullptr) ? fUI->pData : nullptr) | ||||
{ | { | ||||
@@ -276,54 +279,65 @@ public: | |||||
fData->sendNoteCallbackFunc = sendNoteCall; | fData->sendNoteCallbackFunc = sendNoteCall; | ||||
fData->setSizeCallbackFunc = setSizeCall; | fData->setSizeCallbackFunc = setSizeCall; | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// unused | // unused | ||||
return; (void)bundlePath; | return; (void)bundlePath; | ||||
#endif | #endif | ||||
} | } | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
~UIExporter() | |||||
{ | |||||
delete fUI; | |||||
} | |||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uint getWidth() const noexcept | uint getWidth() const noexcept | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
return glWindow.getWidth(); | |||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | ||||
return fUI->getWidth(); | return fUI->getWidth(); | ||||
#endif | |||||
} | } | ||||
uint getHeight() const noexcept | uint getHeight() const noexcept | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
return glWindow.getHeight(); | |||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | ||||
return fUI->getHeight(); | return fUI->getHeight(); | ||||
#endif | |||||
} | } | ||||
bool isVisible() const noexcept | bool isVisible() const noexcept | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
return glWindow.isVisible(); | |||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | ||||
return fUI->isRunning(); | return fUI->isRunning(); | ||||
#endif | |||||
} | } | ||||
// ------------------------------------------------------------------- | |||||
intptr_t getWindowId() const noexcept | |||||
{ | |||||
return 0; | |||||
} | |||||
#else | |||||
uint getWidth() const noexcept | |||||
{ | |||||
return glWindow.getWidth(); | |||||
} | |||||
uint getHeight() const noexcept | |||||
{ | |||||
return glWindow.getHeight(); | |||||
} | |||||
bool isVisible() const noexcept | |||||
{ | |||||
return glWindow.isVisible(); | |||||
} | |||||
intptr_t getWindowId() const noexcept | intptr_t getWindowId() const noexcept | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
return glWindow.getWindowId(); | return glWindow.getWindowId(); | ||||
#else | |||||
return 0; | |||||
#endif | |||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -365,7 +379,39 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
#ifdef HAVE_DGL | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void exec(IdleCallback* const cb) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
fUI->setVisible(true); | |||||
cb->idleCallback(); | |||||
while (fUI->isRunning()) | |||||
{ | |||||
d_msleep(10); | |||||
cb->idleCallback(); | |||||
} | |||||
} | |||||
void exec_idle() | |||||
{ | |||||
} | |||||
bool idle() | |||||
{ | |||||
return true; | |||||
} | |||||
void quit() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
fUI->setVisible(false); | |||||
fUI->terminateAndWaitForProcess(); | |||||
} | |||||
#else | |||||
void exec(IdleCallback* const cb) | void exec(IdleCallback* const cb) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | ||||
@@ -381,48 +427,64 @@ public: | |||||
if (glWindow.isReady()) | if (glWindow.isReady()) | ||||
fUI->uiIdle(); | fUI->uiIdle(); | ||||
} | } | ||||
#endif | |||||
bool idle() | bool idle() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | ||||
#ifdef HAVE_DGL | |||||
glApp.idle(); | glApp.idle(); | ||||
if (glWindow.isReady()) | if (glWindow.isReady()) | ||||
fUI->uiIdle(); | fUI->uiIdle(); | ||||
return ! glApp.isQuiting(); | return ! glApp.isQuiting(); | ||||
#else | |||||
return fUI->isRunning(); | |||||
#endif | |||||
} | } | ||||
void quit() | void quit() | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
glWindow.close(); | glWindow.close(); | ||||
glApp.quit(); | glApp.quit(); | ||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
fUI->terminateAndWaitForProcess(); | |||||
#endif | |||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void setWindowTitle(const char* const uiTitle) | void setWindowTitle(const char* const uiTitle) | ||||
{ | { | ||||
#ifdef HAVE_DGL | |||||
glWindow.setTitle(uiTitle); | |||||
#else | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
fUI->setTitle(uiTitle); | fUI->setTitle(uiTitle); | ||||
#endif | |||||
} | } | ||||
#ifdef HAVE_DGL | |||||
void setWindowSize(const uint width, const uint height, const bool = false) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
fUI->setSize(width, height); | |||||
} | |||||
void setWindowTransientWinId(const uintptr_t winId) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
fUI->setTransientWinId(winId); | |||||
} | |||||
bool setWindowVisible(const bool yesNo) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||||
fUI->setVisible(yesNo); | |||||
return fUI->isRunning(); | |||||
} | |||||
#else | |||||
void setWindowTitle(const char* const uiTitle) | |||||
{ | |||||
glWindow.setTitle(uiTitle); | |||||
} | |||||
void setWindowSize(const uint width, const uint height, const bool updateUI = false) | void setWindowSize(const uint width, const uint height, const bool updateUI = false) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
@@ -459,10 +521,6 @@ public: | |||||
{ | { | ||||
return glWindow.handlePluginSpecial(press, key); | return glWindow.handlePluginSpecial(press, key); | ||||
} | } | ||||
#else | |||||
void setWindowSize(const uint, const uint, const bool = false) {} | |||||
void setWindowTransientWinId(const uintptr_t) {} | |||||
bool setWindowVisible(const bool) { return true; } | |||||
#endif | #endif | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -483,7 +541,7 @@ public: | |||||
} | } | ||||
private: | private: | ||||
#ifdef HAVE_DGL | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// DGL Application and Window for this widget | // DGL Application and Window for this widget | ||||
@@ -0,0 +1,36 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||||
#define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||||
#define DISTRHO_PLUGIN_NAME "ExternalUI" | |||||
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/ExternalUI" | |||||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||||
#define DISTRHO_PLUGIN_HAS_EMBED_UI 0 | |||||
#define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 1 | |||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 1 | |||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | |||||
enum Parameters { | |||||
kParameterLevel = 0, | |||||
kParameterCount | |||||
}; | |||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED |
@@ -0,0 +1,188 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoPlugin.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Plugin to show how to get some basic information sent to the UI. | |||||
*/ | |||||
class ExternalExamplePlugin : public Plugin | |||||
{ | |||||
public: | |||||
ExternalExamplePlugin() | |||||
: Plugin(kParameterCount, 0, 0), | |||||
fValue(0.0f) | |||||
{ | |||||
} | |||||
protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* Information */ | |||||
/** | |||||
Get the plugin label. | |||||
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. | |||||
*/ | |||||
const char* getLabel() const override | |||||
{ | |||||
return "ExternalUI"; | |||||
} | |||||
/** | |||||
Get an extensive comment/description about the plugin. | |||||
*/ | |||||
const char* getDescription() const override | |||||
{ | |||||
return "Plugin to show how to use an external / remote UI."; | |||||
} | |||||
/** | |||||
Get the plugin author/maker. | |||||
*/ | |||||
const char* getMaker() const override | |||||
{ | |||||
return "DISTRHO"; | |||||
} | |||||
/** | |||||
Get the plugin homepage. | |||||
*/ | |||||
const char* getHomePage() const override | |||||
{ | |||||
return "https://github.com/DISTRHO/DPF"; | |||||
} | |||||
/** | |||||
Get the plugin license name (a single line of text). | |||||
For commercial plugins this should return some short copyright information. | |||||
*/ | |||||
const char* getLicense() const override | |||||
{ | |||||
return "ISC"; | |||||
} | |||||
/** | |||||
Get the plugin version, in hexadecimal. | |||||
*/ | |||||
uint32_t getVersion() const override | |||||
{ | |||||
return d_version(1, 0, 0); | |||||
} | |||||
/** | |||||
Get the plugin unique Id. | |||||
This value is used by LADSPA, DSSI and VST plugin formats. | |||||
*/ | |||||
int64_t getUniqueId() const override | |||||
{ | |||||
return d_cconst('d', 'E', 'x', 't'); | |||||
} | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* Init */ | |||||
/** | |||||
Initialize the parameter @a index. | |||||
This function will be called once, shortly after the plugin is created. | |||||
*/ | |||||
void initParameter(uint32_t index, Parameter& parameter) override | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.max = 100.0f; | |||||
parameter.name = "Value"; | |||||
parameter.symbol = "value"; | |||||
} | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* Internal data */ | |||||
/** | |||||
Get the current value of a parameter. | |||||
The host may call this function from any context, including realtime processing. | |||||
*/ | |||||
float getParameterValue(uint32_t index) const override | |||||
{ | |||||
if (index != 0) | |||||
return 0.0f; | |||||
return fValue; | |||||
} | |||||
/** | |||||
Change a parameter value. | |||||
The host may call this function from any context, including realtime processing. | |||||
When a parameter is marked as automable, you must ensure no non-realtime operations are performed. | |||||
@note This function will only be called for parameter inputs. | |||||
*/ | |||||
void setParameterValue(uint32_t index, float value) override | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
fValue = value; | |||||
} | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* Audio/MIDI Processing */ | |||||
/** | |||||
Run/process function for plugins without MIDI input. | |||||
@note Some parameters might be null if there are no audio inputs or outputs. | |||||
*/ | |||||
void run(const float** inputs, float** outputs, uint32_t frames) override | |||||
{ | |||||
/** | |||||
This plugin does nothing, it just demonstrates information usage. | |||||
So here we directly copy inputs over outputs, leaving the audio untouched. | |||||
We need to be careful in case the host re-uses the same buffer for both ins and outs. | |||||
*/ | |||||
if (outputs[0] != inputs[0]) | |||||
std::memcpy(outputs[0], inputs[0], sizeof(float)*frames); | |||||
} | |||||
// ------------------------------------------------------------------------------------------------------- | |||||
private: | |||||
// Parameters | |||||
float fValue; | |||||
/** | |||||
Set our plugin class as non-copyable and add a leak detector just in case. | |||||
*/ | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExternalExamplePlugin) | |||||
}; | |||||
/* ------------------------------------------------------------------------------------------------------------ | |||||
* Plugin entry point, called by DPF to create a new plugin instance. */ | |||||
Plugin* createPlugin() | |||||
{ | |||||
return new ExternalExamplePlugin(); | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,187 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "DistrhoUI.hpp" | |||||
// Extra includes for current path and fifo stuff | |||||
#include <dlfcn.h> | |||||
#include <fcntl.h> | |||||
#include <sys/stat.h> | |||||
#include <sys/types.h> | |||||
START_NAMESPACE_DISTRHO | |||||
// TODO: generate a random, not-yet-existing, filename | |||||
const char* const kFifoFilename = "/tmp/dpf-fifo-test"; | |||||
// Helper to get current path of this plugin | |||||
static const char* getCurrentPluginFilename() | |||||
{ | |||||
Dl_info exeInfo; | |||||
void* localSymbol = (void*)kFifoFilename; | |||||
dladdr(localSymbol, &exeInfo); | |||||
return exeInfo.dli_fname; | |||||
} | |||||
// Helper to check if a file exists | |||||
static bool fileExists(const char* const filename) | |||||
{ | |||||
return access(filename, F_OK) != -1; | |||||
} | |||||
// Helper function to keep trying to write until it succeeds or really errors out | |||||
static ssize_t | |||||
writeRetry(int fd, const void* src, size_t size) | |||||
{ | |||||
ssize_t error; | |||||
do { | |||||
error = write(fd, src, size); | |||||
} while (error == -1 && (errno == EINTR || errno == EPIPE)); | |||||
return error; | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
class ExternalExampleUI : public UI | |||||
{ | |||||
public: | |||||
ExternalExampleUI() | |||||
: UI(405, 256, true), | |||||
fFifo(-1), | |||||
fValue(0.0f), | |||||
fExternalScript(getNextBundlePath()) | |||||
{ | |||||
if (fExternalScript.isEmpty()) | |||||
{ | |||||
fExternalScript = getCurrentPluginFilename(); | |||||
fExternalScript.truncate(fExternalScript.rfind('/')); | |||||
} | |||||
fExternalScript += "/d_extui.sh"; | |||||
d_stdout("External script = %s", fExternalScript.buffer()); | |||||
} | |||||
protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* DSP/Plugin Callbacks */ | |||||
/** | |||||
A parameter has changed on the plugin side. | |||||
This is called by the host to inform the UI about parameter changes. | |||||
*/ | |||||
void parameterChanged(uint32_t index, float value) override | |||||
{ | |||||
if (index != 0) | |||||
return; | |||||
fValue = value; | |||||
if (fFifo == -1) | |||||
return; | |||||
// NOTE: This is a terrible way to pass values, also locale might get in the way... | |||||
char valueStr[24]; | |||||
std::memset(valueStr, 0, sizeof(valueStr)); | |||||
std::snprintf(valueStr, 23, "%i\n", static_cast<int>(value + 0.5f)); | |||||
DISTRHO_SAFE_ASSERT(writeRetry(fFifo, valueStr, 24) == sizeof(valueStr)); | |||||
} | |||||
/* -------------------------------------------------------------------------------------------------------- | |||||
* External Window overrides */ | |||||
/** | |||||
Manage external process and IPC when UI is requested to be visible. | |||||
*/ | |||||
void setVisible(const bool yesNo) override | |||||
{ | |||||
if (yesNo) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(fileExists(fExternalScript),); | |||||
mkfifo(kFifoFilename, 0666); | |||||
sync(); | |||||
char winIdStr[24]; | |||||
std::memset(winIdStr, 0, sizeof(winIdStr)); | |||||
std::snprintf(winIdStr, 23, "%lu", getTransientWinId()); | |||||
const char* args[] = { | |||||
fExternalScript.buffer(), | |||||
kFifoFilename, | |||||
"--progressbar", "External UI example", | |||||
"--title", getTitle(), | |||||
nullptr, | |||||
}; | |||||
DISTRHO_SAFE_ASSERT_RETURN(startExternalProcess(args),); | |||||
// NOTE: this can lockup the current thread if the other side does not read the file! | |||||
fFifo = open(kFifoFilename, O_WRONLY); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fFifo != -1,); | |||||
parameterChanged(0, fValue); | |||||
} | |||||
else | |||||
{ | |||||
if (fFifo != -1) | |||||
{ | |||||
if (isRunning()) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(writeRetry(fFifo, "quit\n", 5) == 5); | |||||
fsync(fFifo); | |||||
} | |||||
close(fFifo); | |||||
fFifo = -1; | |||||
} | |||||
unlink(kFifoFilename); | |||||
terminateAndWaitForProcess(); | |||||
} | |||||
UI::setVisible(yesNo); | |||||
} | |||||
// ------------------------------------------------------------------------------------------------------- | |||||
private: | |||||
// IPC Stuff | |||||
int fFifo; | |||||
// Current value, cached for when UI becomes visible | |||||
float fValue; | |||||
// Path to external ui script | |||||
String fExternalScript; | |||||
/** | |||||
Set our UI class as non-copyable and add a leak detector just in case. | |||||
*/ | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExternalExampleUI) | |||||
}; | |||||
/* ------------------------------------------------------------------------------------------------------------ | |||||
* UI entry point, called by DPF to create a new UI instance. */ | |||||
UI* createUI() | |||||
{ | |||||
return new ExternalExampleUI(); | |||||
} | |||||
// ----------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,40 @@ | |||||
#!/bin/bash | |||||
# Read FIFO argument from CLI | |||||
FIFO=${1} | |||||
shift | |||||
if [ ! -e "${FIFO}" ]; then | |||||
echo "Fifo file ${FIFO} does not exist, cannot run" | |||||
exit 1 | |||||
fi | |||||
# Start kdialog with all other arguments and get dbus reference | |||||
dbusRef=$(kdialog "$@" 100) | |||||
if [ $? -ne 0 ] || [ -z "${dbusRef}" ]; then | |||||
echo "Failed to start kdialog" | |||||
exit 1 | |||||
fi | |||||
# Setup cancellation point for this script | |||||
quitfn() { | |||||
qdbus ${dbusRef} close 2>/dev/null | |||||
} | |||||
trap quitfn SIGINT | |||||
trap quitfn SIGTERM | |||||
# Read Fifo for new values or a quit message | |||||
while read line <"${FIFO}"; do | |||||
if echo "${line}" | grep -q "quit"; then | |||||
break | |||||
fi | |||||
if ! qdbus ${dbusRef} Set "" value "${line}"; then | |||||
break | |||||
fi | |||||
done | |||||
# Cleanup | |||||
rm -f "${FIFO}" | |||||
quitfn |
@@ -0,0 +1,40 @@ | |||||
#!/usr/bin/make -f | |||||
# Makefile for DISTRHO Plugins # | |||||
# ---------------------------- # | |||||
# Created by falkTX | |||||
# | |||||
# -------------------------------------------------------------- | |||||
# Project name, used for binaries | |||||
NAME = d_extui | |||||
# -------------------------------------------------------------- | |||||
# Files to build | |||||
FILES_DSP = \ | |||||
ExternalExamplePlugin.cpp | |||||
FILES_UI = \ | |||||
ExternalExampleUI.cpp | |||||
# -------------------------------------------------------------- | |||||
# Do some magic | |||||
include ../../Makefile.plugins.mk | |||||
LINK_FLAGS += -ldl | |||||
# -------------------------------------------------------------- | |||||
# Enable all possible plugin types | |||||
ifeq ($(HAVE_JACK),true) | |||||
TARGETS += jack | |||||
endif | |||||
TARGETS += dssi | |||||
TARGETS += lv2_sep | |||||
all: $(TARGETS) | |||||
# -------------------------------------------------------------- |
@@ -0,0 +1,11 @@ | |||||
# External UI example | |||||
This example will show how to use an external / remote UI together with DPF.<br/> | |||||
The Plugin has a shell script that calls kdialog and uses qdbus for sending values to it.<br/> | |||||
It is a very ugly way to show a remote UI (using a shell script!), but it is only to prove the point.<br/> | |||||
Note that everything regarding external UIs is still a bit experimental in DPF.<br/> | |||||
There is Unix-specific code in there.<br/> | |||||
If this is something you are interested on using and contributing to, please let us know.<br/> |