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.

394 lines
10KB

  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. # ifndef BRIDGE_X11
  39. typedef QWidget QEmbedContainer;
  40. # else
  41. # ifdef Q_WS_X11
  42. typedef QX11EmbedContainer QEmbedContainer;
  43. # else
  44. # warning Using X11 UI bridge without QX11EmbedContainer
  45. typedef QWidget QEmbedContainer;
  46. # endif
  47. # endif
  48. #endif
  49. CARLA_BRIDGE_START_NAMESPACE
  50. // -------------------------------------------------------------------------
  51. #if defined(BRIDGE_QT4)
  52. static const char* const appName = "Carla-Qt4UIs";
  53. #elif defined(BRIDGE_QT5)
  54. static const char* const appName = "Carla-Qt5UIs";
  55. #elif defined(BRIDGE_COCOA)
  56. static const char* const appName = "Carla-CocoaUIs";
  57. #elif defined(BRIDGE_HWND)
  58. static const char* const appName = "Carla-HWNDUIs";
  59. #elif defined(BRIDGE_X11)
  60. static const char* const appName = "Carla-X11UIs";
  61. #else
  62. static const char* const appName = "Carla-UIs";
  63. #endif
  64. static int qargc = 0;
  65. static char* qargv[0] = {};
  66. // -------------------------------------------------------------------------
  67. class CarlaBridgeToolkitQt: public QObject,
  68. public CarlaBridgeToolkit
  69. {
  70. Q_OBJECT
  71. public:
  72. CarlaBridgeToolkitQt(CarlaBridgeClient* const client, const char* const uiTitle)
  73. : QObject(nullptr),
  74. CarlaBridgeToolkit(client, uiTitle),
  75. fApp(nullptr),
  76. fWindow(nullptr),
  77. #ifdef BRIDGE_CONTAINER
  78. fEmbedContainer(nullptr),
  79. #endif
  80. fMsgTimer(0),
  81. fNeedsShow(false)
  82. {
  83. carla_debug("CarlaBridgeToolkitQt::CarlaBridgeToolkitQt(%p, \"%s\")", client, uiTitle);
  84. connect(this, SIGNAL(setSizeSafeSignal(int,int)), SLOT(setSizeSafeSlot(int,int)));
  85. }
  86. ~CarlaBridgeToolkitQt() override
  87. {
  88. CARLA_ASSERT(fApp == nullptr);
  89. CARLA_ASSERT(fWindow == nullptr);
  90. CARLA_ASSERT(fMsgTimer == 0);
  91. carla_debug("CarlaBridgeToolkitQt::~CarlaBridgeToolkitQt()");
  92. }
  93. void init() override
  94. {
  95. CARLA_ASSERT(fApp == nullptr);
  96. CARLA_ASSERT(fWindow == nullptr);
  97. CARLA_ASSERT(fMsgTimer == 0);
  98. carla_debug("CarlaBridgeToolkitQt::init()");
  99. fApp = new QApplication(qargc, qargv);
  100. {
  101. QSettings settings("falkTX", "Carla");
  102. if (settings.value("Main/UseProTheme", true).toBool())
  103. {
  104. CarlaStyle* const style(new CarlaStyle());
  105. fApp->setStyle(style);
  106. //style->ready(fApp);
  107. // QString color(settings.value("Main/ProThemeColor", "Black").toString());
  108. //
  109. // if (color == "System")
  110. // pass(); //style->setColorScheme(CarlaStyle::COLOR_SYSTEM);
  111. // else
  112. // style->setColorScheme(CarlaStyle::COLOR_BLACK);
  113. }
  114. }
  115. fWindow = new QMainWindow(nullptr);
  116. fWindow->resize(30, 30);
  117. fWindow->hide();
  118. }
  119. void exec(const bool showGui) override
  120. {
  121. CARLA_ASSERT(kClient != nullptr);
  122. CARLA_ASSERT(fApp != nullptr);
  123. CARLA_ASSERT(fWindow != nullptr);
  124. carla_debug("CarlaBridgeToolkitQt::exec(%s)", bool2str(showGui));
  125. #if defined(BRIDGE_QT4) || defined(BRIDGE_QT5)
  126. QWidget* const widget((QWidget*)kClient->getWidget());
  127. fWindow->setCentralWidget(widget);
  128. fWindow->adjustSize();
  129. widget->setParent(fWindow);
  130. widget->show();
  131. #endif
  132. if (! kClient->isResizable())
  133. {
  134. fWindow->setFixedSize(fWindow->width(), fWindow->height());
  135. #ifdef Q_OS_WIN
  136. fWindow->setWindowFlags(fWindow->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
  137. #endif
  138. }
  139. fWindow->setWindowIcon(QIcon::fromTheme("carla", QIcon(":/scalable/carla.svg")));
  140. fWindow->setWindowTitle(kUiTitle);
  141. {
  142. QSettings settings("falkTX", appName);
  143. if (settings.contains(QString("%1/pos_x").arg(kUiTitle)))
  144. {
  145. bool hasX, hasY;
  146. const int posX(settings.value(QString("%1/pos_x").arg(kUiTitle), fWindow->x()).toInt(&hasX));
  147. const int posY(settings.value(QString("%1/pos_y").arg(kUiTitle), fWindow->y()).toInt(&hasY));
  148. if (hasX && hasY)
  149. fWindow->move(posX, posY);
  150. if (kClient->isResizable())
  151. {
  152. bool hasWidth, hasHeight;
  153. const int width(settings.value(QString("%1/width").arg(kUiTitle), fWindow->width()).toInt(&hasWidth));
  154. const int height(settings.value(QString("%1/height").arg(kUiTitle), fWindow->height()).toInt(&hasHeight));
  155. if (hasWidth && hasHeight)
  156. fWindow->resize(width, height);
  157. }
  158. }
  159. if (settings.value("Engine/UIsAlwaysOnTop", true).toBool())
  160. fWindow->setWindowFlags(fWindow->windowFlags() | Qt::WindowStaysOnTopHint);
  161. }
  162. if (showGui || fNeedsShow)
  163. {
  164. show();
  165. fNeedsShow = false;
  166. }
  167. fMsgTimer = startTimer(30);
  168. // First idle
  169. handleTimeout();
  170. // Main loop
  171. fApp->exec();
  172. }
  173. void quit() override
  174. {
  175. CARLA_ASSERT(kClient != nullptr);
  176. CARLA_ASSERT(fApp != nullptr);
  177. CARLA_ASSERT(fWindow != nullptr);
  178. carla_debug("CarlaBridgeToolkitQt::quit()");
  179. if (fMsgTimer != 0)
  180. {
  181. killTimer(fMsgTimer);
  182. fMsgTimer = 0;
  183. }
  184. if (fWindow != nullptr)
  185. {
  186. QSettings settings("falkTX", appName);
  187. settings.setValue(QString("%1/pos_x").arg(kUiTitle), fWindow->x());
  188. settings.setValue(QString("%1/pos_y").arg(kUiTitle), fWindow->y());
  189. settings.setValue(QString("%1/width").arg(kUiTitle), fWindow->width());
  190. settings.setValue(QString("%1/height").arg(kUiTitle), fWindow->height());
  191. settings.sync();
  192. fWindow->close();
  193. #ifdef BRIDGE_CONTAINER
  194. if (fEmbedContainer != nullptr)
  195. {
  196. fEmbedContainer->close();
  197. delete fEmbedContainer;
  198. fEmbedContainer = nullptr;
  199. }
  200. #endif
  201. delete fWindow;
  202. fWindow = nullptr;
  203. }
  204. if (fApp != nullptr)
  205. {
  206. if (! fApp->closingDown())
  207. fApp->quit();
  208. delete fApp;
  209. fApp = nullptr;
  210. }
  211. }
  212. void show() override
  213. {
  214. carla_debug("CarlaBridgeToolkitQt::show()");
  215. fNeedsShow = true;
  216. if (fWindow != nullptr)
  217. fWindow->show();
  218. }
  219. void hide() override
  220. {
  221. carla_debug("CarlaBridgeToolkitQt::hide()");
  222. fNeedsShow = false;
  223. if (fWindow != nullptr)
  224. fWindow->hide();
  225. }
  226. void resize(const int width, const int height) override
  227. {
  228. CARLA_ASSERT_INT(width > 0, width);
  229. CARLA_ASSERT_INT(height > 0, height);
  230. carla_debug("CarlaBridgeToolkitQt::resize(%i, %i)", width, height);
  231. if (width <= 0)
  232. return;
  233. if (height <= 0)
  234. return;
  235. emit setSizeSafeSignal(width, height);
  236. }
  237. #ifdef BRIDGE_CONTAINER
  238. void* getContainerId()
  239. {
  240. CARLA_ASSERT(fWindow != nullptr);
  241. carla_debug("CarlaBridgeToolkitQt::getContainerId()");
  242. if (fEmbedContainer == nullptr)
  243. {
  244. fEmbedContainer = new QEmbedContainer(fWindow);
  245. fWindow->setCentralWidget(fEmbedContainer);
  246. fWindow->adjustSize();
  247. fEmbedContainer->setParent(fWindow);
  248. fEmbedContainer->show();
  249. }
  250. return (void*)fEmbedContainer->winId();
  251. }
  252. #endif
  253. protected:
  254. QApplication* fApp;
  255. QMainWindow* fWindow;
  256. #ifdef BRIDGE_CONTAINER
  257. QEmbedContainer* fEmbedContainer;
  258. #endif
  259. int fMsgTimer;
  260. bool fNeedsShow;
  261. void handleTimeout()
  262. {
  263. if (kClient == nullptr)
  264. return;
  265. kClient->uiIdle();
  266. if (! kClient->oscIdle())
  267. {
  268. killTimer(fMsgTimer);
  269. fMsgTimer = 0;
  270. }
  271. }
  272. private:
  273. void timerEvent(QTimerEvent* const event)
  274. {
  275. if (event->timerId() == fMsgTimer)
  276. handleTimeout();
  277. QObject::timerEvent(event);
  278. }
  279. signals:
  280. void setSizeSafeSignal(int, int);
  281. private slots:
  282. void setSizeSafeSlot(int width, int height)
  283. {
  284. CARLA_ASSERT(kClient != nullptr && ! kClient->isResizable());
  285. CARLA_ASSERT(fWindow != nullptr);
  286. if (kClient == nullptr || fWindow == nullptr)
  287. return;
  288. if (kClient->isResizable())
  289. fWindow->resize(width, height);
  290. else
  291. fWindow->setFixedSize(width, height);
  292. #ifdef BRIDGE_CONTAINER
  293. if (fEmbedContainer != nullptr)
  294. fEmbedContainer->setFixedSize(width, height);
  295. #endif
  296. }
  297. };
  298. #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  299. # include "CarlaBridgeToolkitQt5.moc"
  300. #else
  301. # include "CarlaBridgeToolkitQt4.moc"
  302. #endif
  303. // -------------------------------------------------------------------------
  304. CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const uiTitle)
  305. {
  306. return new CarlaBridgeToolkitQt(client, uiTitle);
  307. }
  308. // -------------------------------------------------------------------------
  309. CARLA_BRIDGE_END_NAMESPACE
  310. #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  311. # include "resources.qt5.cpp"
  312. #else
  313. # include "resources.qt4.cpp"
  314. #endif
  315. // -------------------------------------------------------------------------