Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

367 lines
9.9KB

  1. /*
  2. * Carla Bridge Toolkit, Qt version
  3. * Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the GPL.txt file
  16. */
  17. #include "CarlaBridgeClient.hpp"
  18. #include "CarlaBridgeToolkit.hpp"
  19. #include "CarlaStyle.hpp"
  20. #include <QtCore/QSettings>
  21. #include <QtCore/QThread>
  22. #include <QtCore/QTimerEvent>
  23. #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  24. # include <QtWidgets/QApplication>
  25. # include <QtWidgets/QMainWindow>
  26. # ifdef Q_WS_X11
  27. # undef Q_WS_X11
  28. # endif
  29. #else
  30. # include <QtGui/QApplication>
  31. # include <QtGui/QMainWindow>
  32. # ifdef Q_WS_X11
  33. # include <QtGui/QX11EmbedContainer>
  34. # endif
  35. #endif
  36. #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
  37. # define BRIDGE_CONTAINER
  38. # ifdef Q_WS_X11
  39. typedef QX11EmbedContainer QEmbedContainer;
  40. # else
  41. typedef QWidget QEmbedContainer;
  42. # endif
  43. #endif
  44. CARLA_BRIDGE_START_NAMESPACE
  45. // -------------------------------------------------------------------------
  46. #if defined(BRIDGE_QT4)
  47. static const char* const appName = "Carla-Qt4UIs";
  48. #elif defined(BRIDGE_QT5)
  49. static const char* const appName = "Carla-Qt5UIs";
  50. #elif defined(BRIDGE_COCOA)
  51. static const char* const appName = "Carla-CocoaUIs";
  52. #elif defined(BRIDGE_HWND)
  53. static const char* const appName = "Carla-HWNDUIs";
  54. #elif defined(BRIDGE_X11)
  55. static const char* const appName = "Carla-X11UIs";
  56. #else
  57. static const char* const appName = "Carla-UIs";
  58. #endif
  59. static int qargc = 0;
  60. static char* qargv[0] = {};
  61. // -------------------------------------------------------------------------
  62. class CarlaBridgeToolkitQt: public QObject,
  63. public CarlaBridgeToolkit
  64. {
  65. Q_OBJECT
  66. public:
  67. CarlaBridgeToolkitQt(CarlaBridgeClient* const client, const char* const uiTitle)
  68. : QObject(nullptr),
  69. CarlaBridgeToolkit(client, uiTitle),
  70. fApp(nullptr),
  71. fWindow(nullptr),
  72. #ifdef BRIDGE_CONTAINER
  73. fEmbedContainer(nullptr),
  74. #endif
  75. fMsgTimer(0)
  76. {
  77. carla_debug("CarlaBridgeToolkitQt::CarlaBridgeToolkitQt(%p, \"%s\")", client, uiTitle);
  78. connect(this, SIGNAL(setSizeSafeSignal(int,int)), SLOT(setSizeSafeSlot(int,int)));
  79. }
  80. ~CarlaBridgeToolkitQt() override
  81. {
  82. CARLA_ASSERT(fApp == nullptr);
  83. CARLA_ASSERT(fWindow == nullptr);
  84. CARLA_ASSERT(fMsgTimer == 0);
  85. carla_debug("CarlaBridgeToolkitQt::~CarlaBridgeToolkitQt()");
  86. }
  87. void init() override
  88. {
  89. CARLA_ASSERT(fApp == nullptr);
  90. CARLA_ASSERT(fWindow == nullptr);
  91. CARLA_ASSERT(fMsgTimer == 0);
  92. carla_debug("CarlaBridgeToolkitQt::init()");
  93. fApp = new QApplication(qargc, qargv);
  94. {
  95. QSettings settings("falkTX", "Carla");
  96. if (settings.value("Main/UseProTheme", true).toBool())
  97. {
  98. CarlaStyle* const style(new CarlaStyle());
  99. fApp->setStyle(style);
  100. style->ready(fApp);
  101. QString color(settings.value("Main/ProThemeColor", "Black").toString());
  102. if (color == "System")
  103. pass(); //style->setColorScheme(CarlaStyle::COLOR_SYSTEM);
  104. else
  105. style->setColorScheme(CarlaStyle::COLOR_BLACK);
  106. }
  107. }
  108. fWindow = new QMainWindow(nullptr);
  109. fWindow->resize(30, 30);
  110. fWindow->hide();
  111. }
  112. void exec(const bool showGui) override
  113. {
  114. CARLA_ASSERT(kClient != nullptr);
  115. CARLA_ASSERT(fApp != nullptr);
  116. CARLA_ASSERT(fWindow != nullptr);
  117. carla_debug("CarlaBridgeToolkitQt::exec(%s)", bool2str(showGui));
  118. #if defined(BRIDGE_QT4) || defined(BRIDGE_QT5)
  119. QWidget* const widget((QWidget*)kClient->getWidget());
  120. fWindow->setCentralWidget(widget);
  121. fWindow->adjustSize();
  122. widget->setParent(fWindow);
  123. widget->show();
  124. #endif
  125. if (! kClient->isResizable())
  126. {
  127. fWindow->setFixedSize(fWindow->width(), fWindow->height());
  128. #ifdef Q_OS_WIN
  129. fWindow->setWindowFlags(fWindow->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
  130. #endif
  131. }
  132. {
  133. QSettings settings("falkTX", appName);
  134. if (settings.contains(QString("%1/pos_x").arg(kUiTitle)))
  135. {
  136. bool hasX, hasY;
  137. const int posX(settings.value(QString("%1/pos_x").arg(kUiTitle), fWindow->x()).toInt(&hasX));
  138. const int posY(settings.value(QString("%1/pos_y").arg(kUiTitle), fWindow->y()).toInt(&hasY));
  139. if (hasX && hasY)
  140. fWindow->move(posX, posY);
  141. if (kClient->isResizable())
  142. {
  143. bool hasWidth, hasHeight;
  144. const int width(settings.value(QString("%1/width").arg(kUiTitle), fWindow->width()).toInt(&hasWidth));
  145. const int height(settings.value(QString("%1/height").arg(kUiTitle), fWindow->height()).toInt(&hasHeight));
  146. if (hasWidth && hasHeight)
  147. fWindow->resize(width, height);
  148. }
  149. }
  150. if (settings.value("Engine/UIsAlwaysOnTop", true).toBool())
  151. fWindow->setWindowFlags(fWindow->windowFlags() | Qt::WindowStaysOnTopHint);
  152. }
  153. fWindow->setWindowTitle(kUiTitle);
  154. if (showGui)
  155. show();
  156. else
  157. kClient->sendOscUpdate();
  158. fMsgTimer = startTimer(50);
  159. // First idle
  160. handleTimeout();
  161. // Main loop
  162. fApp->exec();
  163. }
  164. void quit() override
  165. {
  166. CARLA_ASSERT(kClient != nullptr);
  167. CARLA_ASSERT(fApp != nullptr);
  168. CARLA_ASSERT(fWindow != nullptr);
  169. carla_debug("CarlaBridgeToolkitQt::quit()");
  170. if (fMsgTimer != 0)
  171. {
  172. killTimer(fMsgTimer);
  173. fMsgTimer = 0;
  174. }
  175. if (fWindow != nullptr)
  176. {
  177. QSettings settings("falkTX", appName);
  178. settings.setValue(QString("%1/pos_x").arg(kUiTitle), fWindow->x());
  179. settings.setValue(QString("%1/pos_y").arg(kUiTitle), fWindow->y());
  180. settings.setValue(QString("%1/width").arg(kUiTitle), fWindow->width());
  181. settings.setValue(QString("%1/height").arg(kUiTitle), fWindow->height());
  182. settings.sync();
  183. fWindow->close();
  184. #ifdef BRIDGE_CONTAINER
  185. if (fEmbedContainer != nullptr)
  186. {
  187. fEmbedContainer->close();
  188. delete fEmbedContainer;
  189. fEmbedContainer = nullptr;
  190. }
  191. #endif
  192. delete fWindow;
  193. fWindow = nullptr;
  194. }
  195. if (fApp != nullptr)
  196. {
  197. if (! fApp->closingDown())
  198. fApp->quit();
  199. delete fApp;
  200. fApp = nullptr;
  201. }
  202. }
  203. void show() override
  204. {
  205. CARLA_ASSERT(fWindow != nullptr);
  206. carla_debug("CarlaBridgeToolkitQt::show()");
  207. if (fWindow != nullptr)
  208. fWindow->show();
  209. }
  210. void hide() override
  211. {
  212. CARLA_ASSERT(fWindow != nullptr);
  213. carla_debug("CarlaBridgeToolkitQt::hide()");
  214. if (fWindow != nullptr)
  215. fWindow->hide();
  216. }
  217. void resize(const int width, const int height) override
  218. {
  219. CARLA_ASSERT_INT(width > 0, width);
  220. CARLA_ASSERT_INT(height > 0, height);
  221. carla_debug("CarlaBridgeToolkitQt::resize(%i, %i)", width, height);
  222. if (width <= 0)
  223. return;
  224. if (height <= 0)
  225. return;
  226. emit setSizeSafeSignal(width, height);
  227. }
  228. #ifdef BRIDGE_CONTAINER
  229. void* getContainerId()
  230. {
  231. CARLA_ASSERT(fWindow != nullptr);
  232. carla_debug("CarlaBridgeToolkitQt::getContainerId()");
  233. if (fEmbedContainer == nullptr)
  234. {
  235. fEmbedContainer = new QEmbedContainer(fWindow);
  236. fWindow->setCentralWidget(fEmbedContainer);
  237. fWindow->adjustSize();
  238. fEmbedContainer->setParent(fWindow);
  239. fEmbedContainer->show();
  240. }
  241. return (void*)fEmbedContainer->winId();
  242. }
  243. #endif
  244. protected:
  245. QApplication* fApp;
  246. QMainWindow* fWindow;
  247. #ifdef BRIDGE_CONTAINER
  248. QEmbedContainer* fEmbedContainer;
  249. #endif
  250. int fMsgTimer;
  251. void handleTimeout()
  252. {
  253. if (kClient == nullptr)
  254. return;
  255. if (kClient->isOscControlRegistered() && ! kClient->oscIdle())
  256. {
  257. killTimer(fMsgTimer);
  258. fMsgTimer = 0;
  259. }
  260. }
  261. private:
  262. void timerEvent(QTimerEvent* const event)
  263. {
  264. if (event->timerId() == fMsgTimer)
  265. handleTimeout();
  266. QObject::timerEvent(event);
  267. }
  268. signals:
  269. void setSizeSafeSignal(int, int);
  270. private slots:
  271. void setSizeSafeSlot(int width, int height)
  272. {
  273. CARLA_ASSERT(kClient != nullptr && kClient->isResizable());
  274. CARLA_ASSERT(fWindow != nullptr);
  275. if (kClient == nullptr || fWindow == nullptr)
  276. return;
  277. if (kClient->isResizable())
  278. fWindow->resize(width, height);
  279. else
  280. fWindow->setFixedSize(width, height);
  281. #ifdef BRIDGE_CONTAINER
  282. if (fEmbedContainer != nullptr)
  283. fEmbedContainer->setFixedSize(width, height);
  284. #endif
  285. }
  286. };
  287. #include "CarlaBridgeToolkitQt.moc"
  288. // -------------------------------------------------------------------------
  289. CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const uiTitle)
  290. {
  291. return new CarlaBridgeToolkitQt(client, uiTitle);
  292. }
  293. CARLA_BRIDGE_END_NAMESPACE