@@ -21,8 +21,7 @@ | |||||
#include <QtCore/QFile> | #include <QtCore/QFile> | ||||
#include <QtCore/QTextStream> | #include <QtCore/QTextStream> | ||||
//#include <QtGui/QtEvents> | |||||
#include <QtGui/QCloseEvent> | |||||
CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
@@ -1972,24 +1971,16 @@ CarlaPlugin::ScopedProcessLocker::~ScopedProcessLocker() | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// CarlaPluginGUI | // CarlaPluginGUI | ||||
#if 0 | |||||
CarlaPluginGUI::CarlaPluginGUI(QWidget* const parent, Callback* const callback) | CarlaPluginGUI::CarlaPluginGUI(QWidget* const parent, Callback* const callback) | ||||
: QMainWindow(parent), | : QMainWindow(parent), | ||||
kCallback(callback) | |||||
kCallback(callback), | |||||
fContainer(this) | |||||
{ | { | ||||
carla_debug("CarlaPluginGUI::CarlaPluginGUI(%p)", parent); | |||||
//CARLA_ASSERT(callback); | |||||
//m_container = new GuiContainer(this); | |||||
//setCentralWidget(m_container); | |||||
//adjustSize(); | |||||
//m_container->setParent(this); | |||||
//m_container->show(); | |||||
//m_resizable = true; | |||||
carla_debug("CarlaPluginGUI::CarlaPluginGUI(%p, %p)", parent, callback); | |||||
CARLA_ASSERT(callback != nullptr); | |||||
//setNewSize(50, 50); | |||||
setCentralWidget(&fContainer); | |||||
adjustSize(); | |||||
QMainWindow::setVisible(false); | QMainWindow::setVisible(false); | ||||
} | } | ||||
@@ -1997,109 +1988,30 @@ CarlaPluginGUI::CarlaPluginGUI(QWidget* const parent, Callback* const callback) | |||||
CarlaPluginGUI::~CarlaPluginGUI() | CarlaPluginGUI::~CarlaPluginGUI() | ||||
{ | { | ||||
carla_debug("CarlaPluginGUI::~CarlaPluginGUI()"); | carla_debug("CarlaPluginGUI::~CarlaPluginGUI()"); | ||||
//CARLA_ASSERT(m_container); | |||||
// FIXME, automatically deleted by parent ? | |||||
//delete m_container; | |||||
} | |||||
#endif | |||||
#if 0 | |||||
// ------------------------------------------------------------------- | |||||
GuiContainer* CarlaPluginGUI::getContainer() const | |||||
{ | |||||
return m_container; | |||||
} | } | ||||
WId CarlaPluginGUI::getWinId() const | WId CarlaPluginGUI::getWinId() const | ||||
{ | { | ||||
return m_container->winId(); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
void CarlaPluginGUI::setNewSize(int width, int height) | |||||
{ | |||||
carla_debug("CarlaPluginGUI::setNewSize(%i, %i)", width, height); | |||||
if (width < 30) | |||||
width = 30; | |||||
if (height < 30) | |||||
height = 30; | |||||
if (m_resizable) | |||||
{ | |||||
resize(width, height); | |||||
} | |||||
else | |||||
{ | |||||
setFixedSize(width, height); | |||||
m_container->setFixedSize(width, height); | |||||
} | |||||
} | |||||
void CarlaPluginGUI::setResizable(bool resizable) | |||||
{ | |||||
m_resizable = resizable; | |||||
setNewSize(width(), height()); | |||||
#ifdef Q_OS_WIN | |||||
if (! resizable) | |||||
setWindowFlags(windowFlags() | Qt::MSWindowsFixedSizeDialogHint); | |||||
#endif | |||||
} | |||||
void CarlaPluginGUI::setTitle(const char* const title) | |||||
{ | |||||
CARLA_ASSERT(title); | |||||
setWindowTitle(QString("%1 (GUI)").arg(title)); | |||||
} | |||||
void CarlaPluginGUI::setVisible(const bool yesNo) | |||||
{ | |||||
carla_debug("CarlaPluginGUI::setVisible(%s)", bool2str(yesNo)); | |||||
if (yesNo) | |||||
{ | |||||
if (! m_geometry.isNull()) | |||||
restoreGeometry(m_geometry); | |||||
} | |||||
else | |||||
m_geometry = saveGeometry(); | |||||
QMainWindow::setVisible(yesNo); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
void CarlaPluginGUI::hideEvent(QHideEvent* const event) | |||||
{ | |||||
carla_debug("CarlaPluginGUI::hideEvent(%p)", event); | |||||
CARLA_ASSERT(event); | |||||
event->accept(); | |||||
close(); | |||||
carla_debug("CarlaPluginGUI::getWinId()"); | |||||
return fContainer.winId(); | |||||
} | } | ||||
void CarlaPluginGUI::closeEvent(QCloseEvent* const event) | void CarlaPluginGUI::closeEvent(QCloseEvent* const event) | ||||
{ | { | ||||
carla_debug("CarlaPluginGUI::closeEvent(%p)", event); | carla_debug("CarlaPluginGUI::closeEvent(%p)", event); | ||||
CARLA_ASSERT(event); | |||||
CARLA_ASSERT(event != nullptr); | |||||
if (event->spontaneous()) | |||||
if (! event->spontaneous()) | |||||
{ | { | ||||
if (m_callback) | |||||
m_callback->guiClosedCallback(); | |||||
QMainWindow::closeEvent(event); | |||||
event->ignore(); | |||||
return; | return; | ||||
} | } | ||||
event->ignore(); | |||||
if (kCallback != nullptr) | |||||
kCallback->guiClosedCallback(); | |||||
QMainWindow::closeEvent(event); | |||||
} | } | ||||
#endif | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -31,6 +31,14 @@ | |||||
#include <QtGui/QMainWindow> | #include <QtGui/QMainWindow> | ||||
#ifdef Q_WS_X11 | |||||
# include <QtGui/QX11EmbedContainer> | |||||
typedef QX11EmbedContainer GuiContainer; | |||||
#else | |||||
# include <QtGui/QWidget> | |||||
typedef QWidget GuiContainer; | |||||
#endif | |||||
#define CARLA_DECLARE_NON_COPY_STRUCT(structName) \ | #define CARLA_DECLARE_NON_COPY_STRUCT(structName) \ | ||||
structName(structName&) = delete; \ | structName(structName&) = delete; \ | ||||
structName(const structName&) = delete; | structName(const structName&) = delete; | ||||
@@ -400,8 +408,14 @@ public: | |||||
CarlaPluginGUI(QWidget* const parent, Callback* const callback); | CarlaPluginGUI(QWidget* const parent, Callback* const callback); | ||||
~CarlaPluginGUI(); | ~CarlaPluginGUI(); | ||||
WId getWinId() const; | |||||
protected: | |||||
void closeEvent(QCloseEvent* const event); | |||||
private: | private: | ||||
Callback* const kCallback; | Callback* const kCallback; | ||||
GuiContainer fContainer; | |||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI) | ||||
}; | }; | ||||
@@ -559,6 +573,24 @@ struct CarlaPluginProtectedData { | |||||
CarlaPluginProtectedData(CarlaPluginProtectedData&) = delete; | CarlaPluginProtectedData(CarlaPluginProtectedData&) = delete; | ||||
CarlaPluginProtectedData(const CarlaPluginProtectedData&) = delete; | CarlaPluginProtectedData(const CarlaPluginProtectedData&) = delete; | ||||
void createUiIfNeeded(CarlaPluginGUI::Callback* const callback) | |||||
{ | |||||
if (gui != nullptr) | |||||
return; | |||||
gui = new CarlaPluginGUI(nullptr, callback); | |||||
} | |||||
void destroyUiIfNeeded() | |||||
{ | |||||
if (gui == nullptr) | |||||
return; | |||||
gui->close(); | |||||
delete gui; | |||||
gui = nullptr; | |||||
} | |||||
static CarlaEngine* getEngine(CarlaPlugin* const plugin) | static CarlaEngine* getEngine(CarlaPlugin* const plugin) | ||||
{ | { | ||||
return plugin->kData->engine; | return plugin->kData->engine; | ||||
@@ -587,104 +619,3 @@ struct CarlaPluginProtectedData { | |||||
CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE | ||||
#endif // __CARLA_PLUGIN_INTERNAL_HPP__ | #endif // __CARLA_PLUGIN_INTERNAL_HPP__ | ||||
// common includes | |||||
//#include <cmath> | |||||
//#include <vector> | |||||
//#include <QtCore/QMutex> | |||||
//#include <QtGui/QMainWindow> | |||||
//#ifdef Q_WS_X11 | |||||
//# include <QtGui/QX11EmbedContainer> | |||||
//typedef QX11EmbedContainer GuiContainer; | |||||
//#else | |||||
//# include <QtGui/QWidget> | |||||
//typedef QWidget GuiContainer; | |||||
//#endif | |||||
#if 0 | |||||
/*! | |||||
* \class CarlaPluginGUI | |||||
* | |||||
* \brief Carla Backend gui plugin class | |||||
* | |||||
* \see CarlaPlugin | |||||
*/ | |||||
class CarlaPluginGUI : public QMainWindow | |||||
{ | |||||
public: | |||||
/*! | |||||
* \class Callback | |||||
* | |||||
* \brief Carla plugin GUI callback | |||||
*/ | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void guiClosedCallback() = 0; | |||||
}; | |||||
// ------------------------------------------------------------------- | |||||
// Constructor and destructor | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
CarlaPluginGUI(QWidget* const parent, Callback* const callback); | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
~CarlaPluginGUI(); | |||||
// ------------------------------------------------------------------- | |||||
// Get data | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
GuiContainer* getContainer() const; | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
WId getWinId() const; | |||||
// ------------------------------------------------------------------- | |||||
// Set data | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
void setNewSize(const int width, const int height); | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
void setResizable(const bool resizable); | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
void setTitle(const char* const title); | |||||
/*! | |||||
* TODO | |||||
*/ | |||||
void setVisible(const bool yesNo); | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
Callback* const m_callback; | |||||
GuiContainer* m_container; | |||||
QByteArray m_geometry; | |||||
bool m_resizable; | |||||
void hideEvent(QHideEvent* const event); | |||||
void closeEvent(QCloseEvent* const event); | |||||
}; | |||||
#endif |
@@ -37,7 +37,8 @@ const unsigned int PLUGIN_USES_OLD_VSTSDK = 0x4000; //!< VST Plugin uses a | |||||
const unsigned int PLUGIN_WANTS_MIDI_INPUT = 0x8000; //!< VST Plugin wants MIDI input | const unsigned int PLUGIN_WANTS_MIDI_INPUT = 0x8000; //!< VST Plugin wants MIDI input | ||||
/**@}*/ | /**@}*/ | ||||
class VstPlugin : public CarlaPlugin | |||||
class VstPlugin : public CarlaPlugin, | |||||
public CarlaPluginGUI::Callback | |||||
{ | { | ||||
public: | public: | ||||
VstPlugin(CarlaEngine* const engine, const unsigned short id) | VstPlugin(CarlaEngine* const engine, const unsigned short id) | ||||
@@ -332,39 +333,9 @@ public: | |||||
void setGuiContainer(GuiContainer* const container) | void setGuiContainer(GuiContainer* const container) | ||||
{ | { | ||||
carla_debug("VstPlugin::setGuiContainer(%p)", container); | |||||
CARLA_ASSERT(container); | |||||
if (gui.type == GUI_EXTERNAL_OSC) | |||||
return; | |||||
int32_t value = 0; | |||||
void* const ptr = (void*)container->winId(); | |||||
ERect* vstRect = nullptr; | |||||
#ifdef Q_WS_X11 | |||||
value = (intptr_t)QX11Info::display(); | |||||
#endif | |||||
// get UI size before opening UI, plugin may refuse this | |||||
effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0.0f); | |||||
if (vstRect) | |||||
{ | |||||
int width = vstRect->right - vstRect->left; | |||||
int height = vstRect->bottom - vstRect->top; | |||||
if (width > 0 || height > 0) | |||||
{ | |||||
container->setFixedSize(width, height); | |||||
#ifdef BUILD_BRIDGE | |||||
x_engine->callback(CALLBACK_RESIZE_GUI, m_id, width, height, 1.0, nullptr); | |||||
#endif | |||||
} | |||||
} | |||||
// open UI | // open UI | ||||
if (effect->dispatcher(effect, effEditOpen, 0, value, ptr, 0.0f) == 1) | |||||
{ | { | ||||
// get UI size again, can't fail now | // get UI size again, can't fail now | ||||
vstRect = nullptr; | vstRect = nullptr; | ||||
@@ -398,7 +369,7 @@ public: | |||||
m_hints &= ~PLUGIN_HAS_GUI; | m_hints &= ~PLUGIN_HAS_GUI; | ||||
x_engine->callback(CALLBACK_SHOW_GUI, m_id, -1, 0, 0.0, nullptr); | x_engine->callback(CALLBACK_SHOW_GUI, m_id, -1, 0, 0.0, nullptr); | ||||
effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0.0f); | |||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
@@ -426,8 +397,49 @@ public: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (yesNo && fGui.width > 0 && fGui.height > 0 && kData->gui != nullptr) | |||||
kData->gui->setFixedSize(fGui.width, fGui.height); | |||||
if (yesNo) | |||||
{ | |||||
kData->createUiIfNeeded(this); | |||||
int32_t value = 0; | |||||
#ifdef Q_WS_X11 | |||||
//value = (intptr_t)QX11Info::display(); | |||||
#endif | |||||
void* const ptr = (void*)kData->gui->getWinId(); | |||||
if (dispatcher(effEditOpen, 0, value, ptr, 0.0f) == 1) | |||||
{ | |||||
ERect* vstRect = nullptr; | |||||
dispatcher(effEditGetRect, 0, 0, &vstRect, 0.0f); | |||||
if (vstRect != nullptr) | |||||
{ | |||||
const int16_t width = vstRect->right - vstRect->left; | |||||
const int16_t height = vstRect->bottom - vstRect->top; | |||||
if (width > 0 && height > 0) | |||||
{ | |||||
kData->gui->setFixedSize(width, height); | |||||
} | |||||
} | |||||
kData->gui->setWindowTitle(QString("%1 (GUI)").arg((const char*)fName)); | |||||
kData->gui->show(); | |||||
} | |||||
else | |||||
{ | |||||
kData->destroyUiIfNeeded(); | |||||
kData->engine->callback(CALLBACK_ERROR, fId, 0, 0, 0.0f, "Plugin refused to open its own UI"); | |||||
kData->engine->callback(CALLBACK_SHOW_GUI, fId, 0, 0, 0.0f, nullptr); | |||||
return; | |||||
} | |||||
} | |||||
else if (fGui.isVisible) | |||||
{ | |||||
dispatcher(effEditClose, 0, 0, nullptr, 0.0f); | |||||
kData->destroyUiIfNeeded(); | |||||
} | |||||
} | } | ||||
fGui.isVisible = yesNo; | fGui.isVisible = yesNo; | ||||
@@ -1601,9 +1613,18 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
protected: | protected: | ||||
void guiClosedCallback() | |||||
{ | |||||
showGui(false); | |||||
kData->engine->callback(CALLBACK_SHOW_GUI, fId, 0, 0, 0.0f, nullptr); | |||||
} | |||||
intptr_t dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | intptr_t dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) | ||||
{ | { | ||||
carla_debug("VstPlugin::dispatcher(%02i:%s, %i, " P_INTPTR ", %p, %f)", opcode, vstEffectOpcode2str(opcode), index, value, ptr, opt); | |||||
#if defined(DEBUG) && ! defined(CARLA_OS_WIN) | |||||
if (opcode != effEditIdle && opcode != effProcessEvents) | |||||
carla_debug("VstPlugin::dispatcher(%02i:%s, %i, " P_INTPTR ", %p, %f)", opcode, vstEffectOpcode2str(opcode), index, value, ptr, opt); | |||||
#endif | |||||
CARLA_ASSERT(fEffect != nullptr); | CARLA_ASSERT(fEffect != nullptr); | ||||
return (fEffect != nullptr) ? fEffect->dispatcher(fEffect, opcode, index, value, ptr, opt) : 0; | return (fEffect != nullptr) ? fEffect->dispatcher(fEffect, opcode, index, value, ptr, opt) : 0; | ||||
@@ -1649,21 +1670,38 @@ protected: | |||||
switch (opcode) | switch (opcode) | ||||
{ | { | ||||
case audioMasterAutomate: | case audioMasterAutomate: | ||||
CARLA_ASSERT(fEnabled); | |||||
CARLA_ASSERT_INT(index < static_cast<int32_t>(kData->param.count), index); | CARLA_ASSERT_INT(index < static_cast<int32_t>(kData->param.count), index); | ||||
CARLA_SAFE_ASSERT(fEnabled); // plugins should never do this! | |||||
if (index < 0 || index >= static_cast<int32_t>(kData->param.count) || ! fEnabled) | if (index < 0 || index >= static_cast<int32_t>(kData->param.count) || ! fEnabled) | ||||
break; | break; | ||||
if (fIsProcessing && ! kData->engine->isOffline()) | |||||
if (fIsProcessing) | |||||
{ | { | ||||
// Called from engine | |||||
if (kData->engine->isOffline()) | |||||
{ | |||||
setParameterValue(index, opt, true, true, true); | |||||
} | |||||
else | |||||
{ | |||||
setParameterValue(index, opt, false, false, false); | |||||
postponeRtEvent(kPluginPostRtEventParameterChange, index, 0, opt); | |||||
} | |||||
} | |||||
else if (! kData->active) | |||||
{ | |||||
// On init? | |||||
setParameterValue(index, opt, false, false, false); | setParameterValue(index, opt, false, false, false); | ||||
postponeRtEvent(kPluginPostRtEventParameterChange, index, 0, opt); | |||||
} | |||||
else if (fGui.isVisible) | |||||
{ | |||||
// Called from GUI | |||||
setParameterValue(index, opt, false, true, true); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
CARLA_ASSERT(fGui.isVisible); // FIXME - remove when offline is implemented | |||||
setParameterValue(index, opt, fIsProcessing, true, true); | |||||
carla_stdout("audioMasterAutomate called from unknown source"); | |||||
} | } | ||||
break; | break; | ||||
@@ -1802,8 +1840,7 @@ protected: | |||||
break; | break; | ||||
case audioMasterSizeWindow: | case audioMasterSizeWindow: | ||||
fGui.width = index; | |||||
fGui.height = value; | |||||
CARLA_ASSERT(kData->gui != nullptr); | |||||
// FIXME - ensure thread safe | // FIXME - ensure thread safe | ||||
if (kData->gui != nullptr) | if (kData->gui != nullptr) | ||||
@@ -2125,14 +2162,10 @@ private: | |||||
struct GuiInfo { | struct GuiInfo { | ||||
bool isOsc; | bool isOsc; | ||||
bool isVisible; | bool isVisible; | ||||
int width; | |||||
int height; | |||||
GuiInfo() | GuiInfo() | ||||
: isOsc(false), | : isOsc(false), | ||||
isVisible(false), | |||||
width(0), | |||||
height(0) {} | |||||
isVisible(false) {} | |||||
} fGui; | } fGui; | ||||
bool fIsProcessing; | bool fIsProcessing; | ||||
@@ -1541,7 +1541,7 @@ def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): | |||||
#elif action == CALLBACK_NSM_SAVE: | #elif action == CALLBACK_NSM_SAVE: | ||||
#Carla.gui.emit(SIGNAL("NSM_SaveCallback()")) | #Carla.gui.emit(SIGNAL("NSM_SaveCallback()")) | ||||
elif action == CALLBACK_ERROR: | elif action == CALLBACK_ERROR: | ||||
Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), valueStr) | |||||
Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), cString(valueStr)) | |||||
elif action == CALLBACK_QUIT: | elif action == CALLBACK_QUIT: | ||||
Carla.gui.emit(SIGNAL("QuitCallback()")) | Carla.gui.emit(SIGNAL("QuitCallback()")) | ||||
@@ -182,6 +182,10 @@ const char* vstEffectOpcode2str(const int32_t opcode) | |||||
return "effEditMouse"; | return "effEditMouse"; | ||||
case effEditKey: | case effEditKey: | ||||
return "effEditKey"; | return "effEditKey"; | ||||
#endif | |||||
case effEditIdle: | |||||
return "effEditIdle"; | |||||
#if ! VST_FORCE_DEPRECATED | |||||
case effEditTop: | case effEditTop: | ||||
return "effEditTop"; | return "effEditTop"; | ||||
case effEditSleep: | case effEditSleep: | ||||