@@ -21,8 +21,7 @@ | |||
#include <QtCore/QFile> | |||
#include <QtCore/QTextStream> | |||
//#include <QtGui/QtEvents> | |||
#include <QtGui/QCloseEvent> | |||
CARLA_BACKEND_START_NAMESPACE | |||
@@ -1972,24 +1971,16 @@ CarlaPlugin::ScopedProcessLocker::~ScopedProcessLocker() | |||
// ------------------------------------------------------------------- | |||
// CarlaPluginGUI | |||
#if 0 | |||
CarlaPluginGUI::CarlaPluginGUI(QWidget* const parent, Callback* const callback) | |||
: 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); | |||
} | |||
@@ -1997,109 +1988,30 @@ CarlaPluginGUI::CarlaPluginGUI(QWidget* const parent, Callback* const callback) | |||
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 | |||
{ | |||
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) | |||
{ | |||
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; | |||
} | |||
event->ignore(); | |||
if (kCallback != nullptr) | |||
kCallback->guiClosedCallback(); | |||
QMainWindow::closeEvent(event); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
@@ -31,6 +31,14 @@ | |||
#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) \ | |||
structName(structName&) = delete; \ | |||
structName(const structName&) = delete; | |||
@@ -400,8 +408,14 @@ public: | |||
CarlaPluginGUI(QWidget* const parent, Callback* const callback); | |||
~CarlaPluginGUI(); | |||
WId getWinId() const; | |||
protected: | |||
void closeEvent(QCloseEvent* const event); | |||
private: | |||
Callback* const kCallback; | |||
GuiContainer fContainer; | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI) | |||
}; | |||
@@ -559,6 +573,24 @@ struct CarlaPluginProtectedData { | |||
CarlaPluginProtectedData(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) | |||
{ | |||
return plugin->kData->engine; | |||
@@ -587,104 +619,3 @@ struct CarlaPluginProtectedData { | |||
CARLA_BACKEND_END_NAMESPACE | |||
#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 | |||
/**@}*/ | |||
class VstPlugin : public CarlaPlugin | |||
class VstPlugin : public CarlaPlugin, | |||
public CarlaPluginGUI::Callback | |||
{ | |||
public: | |||
VstPlugin(CarlaEngine* const engine, const unsigned short id) | |||
@@ -332,39 +333,9 @@ public: | |||
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 | |||
if (effect->dispatcher(effect, effEditOpen, 0, value, ptr, 0.0f) == 1) | |||
{ | |||
// get UI size again, can't fail now | |||
vstRect = nullptr; | |||
@@ -398,7 +369,7 @@ public: | |||
m_hints &= ~PLUGIN_HAS_GUI; | |||
x_engine->callback(CALLBACK_SHOW_GUI, m_id, -1, 0, 0.0, nullptr); | |||
effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0.0f); | |||
} | |||
} | |||
#endif | |||
@@ -426,8 +397,49 @@ public: | |||
} | |||
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; | |||
@@ -1601,9 +1613,18 @@ public: | |||
// ------------------------------------------------------------------- | |||
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) | |||
{ | |||
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); | |||
return (fEffect != nullptr) ? fEffect->dispatcher(fEffect, opcode, index, value, ptr, opt) : 0; | |||
@@ -1649,21 +1670,38 @@ protected: | |||
switch (opcode) | |||
{ | |||
case audioMasterAutomate: | |||
CARLA_ASSERT(fEnabled); | |||
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) | |||
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); | |||
postponeRtEvent(kPluginPostRtEventParameterChange, index, 0, opt); | |||
} | |||
else if (fGui.isVisible) | |||
{ | |||
// Called from GUI | |||
setParameterValue(index, opt, false, true, true); | |||
} | |||
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; | |||
@@ -1802,8 +1840,7 @@ protected: | |||
break; | |||
case audioMasterSizeWindow: | |||
fGui.width = index; | |||
fGui.height = value; | |||
CARLA_ASSERT(kData->gui != nullptr); | |||
// FIXME - ensure thread safe | |||
if (kData->gui != nullptr) | |||
@@ -2125,14 +2162,10 @@ private: | |||
struct GuiInfo { | |||
bool isOsc; | |||
bool isVisible; | |||
int width; | |||
int height; | |||
GuiInfo() | |||
: isOsc(false), | |||
isVisible(false), | |||
width(0), | |||
height(0) {} | |||
isVisible(false) {} | |||
} fGui; | |||
bool fIsProcessing; | |||
@@ -1541,7 +1541,7 @@ def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): | |||
#elif action == CALLBACK_NSM_SAVE: | |||
#Carla.gui.emit(SIGNAL("NSM_SaveCallback()")) | |||
elif action == CALLBACK_ERROR: | |||
Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), valueStr) | |||
Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), cString(valueStr)) | |||
elif action == CALLBACK_QUIT: | |||
Carla.gui.emit(SIGNAL("QuitCallback()")) | |||
@@ -182,6 +182,10 @@ const char* vstEffectOpcode2str(const int32_t opcode) | |||
return "effEditMouse"; | |||
case effEditKey: | |||
return "effEditKey"; | |||
#endif | |||
case effEditIdle: | |||
return "effEditIdle"; | |||
#if ! VST_FORCE_DEPRECATED | |||
case effEditTop: | |||
return "effEditTop"; | |||
case effEditSleep: | |||