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.

283 lines
7.3KB

  1. /*
  2. * Carla Bridge Toolkit, Qt version
  3. * Copyright (C) 2011-2014 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 doc/GPL.txt file.
  16. */
  17. #include "CarlaBridgeClient.hpp"
  18. #include "CarlaBridgeToolkit.hpp"
  19. #include "CarlaStyle.hpp"
  20. #include <QtCore/QThread>
  21. #include <QtCore/QTimerEvent>
  22. #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
  23. # include <QtWidgets/QApplication>
  24. # include <QtWidgets/QMainWindow>
  25. #else
  26. # include <QtGui/QApplication>
  27. # include <QtGui/QMainWindow>
  28. #endif
  29. #if defined(CARLA_OS_LINUX) && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  30. # include <QtGui/QX11Info>
  31. # include <X11/Xlib.h>
  32. #endif
  33. CARLA_BRIDGE_START_NAMESPACE
  34. // -------------------------------------------------------------------------
  35. static int qargc = 0;
  36. static char* qargv[0] = {};
  37. // -------------------------------------------------------------------------
  38. class CarlaBridgeToolkitQt: public QObject,
  39. public CarlaBridgeToolkit
  40. {
  41. Q_OBJECT
  42. public:
  43. CarlaBridgeToolkitQt(CarlaBridgeClient* const client, const char* const windowTitle)
  44. : QObject(nullptr),
  45. CarlaBridgeToolkit(client, windowTitle),
  46. fApp(nullptr),
  47. fWindow(nullptr),
  48. fMsgTimer(0),
  49. fNeedsShow(false),
  50. leakDetector_CarlaBridgeToolkitQt()
  51. {
  52. carla_debug("CarlaBridgeToolkitQt::CarlaBridgeToolkitQt(%p, \"%s\")", client, windowTitle);
  53. connect(this, SIGNAL(setSizeSafeSignal(int,int)), SLOT(setSizeSafeSlot(int,int)));
  54. }
  55. ~CarlaBridgeToolkitQt() override
  56. {
  57. CARLA_SAFE_ASSERT(fApp == nullptr);
  58. CARLA_SAFE_ASSERT(fWindow == nullptr);
  59. CARLA_SAFE_ASSERT(fMsgTimer == 0);
  60. carla_debug("CarlaBridgeToolkitQt::~CarlaBridgeToolkitQt()");
  61. }
  62. void init() override
  63. {
  64. CARLA_SAFE_ASSERT_RETURN(fApp == nullptr,);
  65. CARLA_SAFE_ASSERT_RETURN(fWindow == nullptr,);
  66. CARLA_SAFE_ASSERT_RETURN(fMsgTimer == 0,);
  67. carla_debug("CarlaBridgeToolkitQt::init()");
  68. fApp = new QApplication(qargc, qargv);
  69. fWindow = new QMainWindow(nullptr);
  70. fWindow->resize(30, 30);
  71. fWindow->hide();
  72. }
  73. void exec(const bool showUI) override
  74. {
  75. CARLA_SAFE_ASSERT_RETURN(kClient != nullptr,);
  76. CARLA_SAFE_ASSERT_RETURN(fApp != nullptr,);
  77. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  78. carla_debug("CarlaBridgeToolkitQt::exec(%s)", bool2str(showUI));
  79. QWidget* const widget((QWidget*)kClient->getWidget());
  80. fWindow->setCentralWidget(widget);
  81. fWindow->adjustSize();
  82. widget->setParent(fWindow);
  83. widget->show();
  84. if (! kClient->isResizable())
  85. {
  86. fWindow->setFixedSize(fWindow->width(), fWindow->height());
  87. #ifdef CARLA_OS_WIN
  88. fWindow->setWindowFlags(fWindow->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
  89. #endif
  90. }
  91. fWindow->setWindowIcon(QIcon::fromTheme("carla", QIcon(":/scalable/carla.svg")));
  92. fWindow->setWindowTitle(kWindowTitle.buffer());
  93. if (const char* const winIdStr = std::getenv("ENGINE_OPTION_FRONTEND_WIN_ID"))
  94. {
  95. if (const long long winId = std::strtoll(winIdStr, nullptr, 16))
  96. {
  97. #if defined(CARLA_OS_LINUX) && QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  98. XSetTransientForHint(QX11Info::display(), static_cast<::Window>(fWindow->winId()), static_cast<::Window>(winId));
  99. #else
  100. (void)winId;
  101. #endif
  102. }
  103. }
  104. if (showUI || fNeedsShow)
  105. {
  106. show();
  107. fNeedsShow = false;
  108. }
  109. fMsgTimer = startTimer(30);
  110. // First idle
  111. handleTimeout();
  112. // Main loop
  113. fApp->exec();
  114. }
  115. void quit() override
  116. {
  117. CARLA_SAFE_ASSERT_RETURN(kClient != nullptr,);
  118. CARLA_SAFE_ASSERT_RETURN(fApp != nullptr,);
  119. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  120. carla_debug("CarlaBridgeToolkitQt::quit()");
  121. if (fMsgTimer != 0)
  122. {
  123. killTimer(fMsgTimer);
  124. fMsgTimer = 0;
  125. }
  126. if (fWindow != nullptr)
  127. {
  128. fWindow->close();
  129. delete fWindow;
  130. fWindow = nullptr;
  131. }
  132. if (fApp != nullptr)
  133. {
  134. if (! fApp->closingDown())
  135. fApp->quit();
  136. delete fApp;
  137. fApp = nullptr;
  138. }
  139. }
  140. void show() override
  141. {
  142. carla_debug("CarlaBridgeToolkitQt::show()");
  143. fNeedsShow = true;
  144. if (fWindow != nullptr)
  145. fWindow->show();
  146. }
  147. void hide() override
  148. {
  149. carla_debug("CarlaBridgeToolkitQt::hide()");
  150. fNeedsShow = false;
  151. if (fWindow != nullptr)
  152. fWindow->hide();
  153. }
  154. void resize(const int width, const int height) override
  155. {
  156. CARLA_SAFE_ASSERT_RETURN(width > 0,);
  157. CARLA_SAFE_ASSERT_RETURN(height > 0,);
  158. carla_debug("CarlaBridgeToolkitQt::resize(%i, %i)", width, height);
  159. emit setSizeSafeSignal(static_cast<uint>(width), static_cast<uint>(height));
  160. }
  161. protected:
  162. QApplication* fApp;
  163. QMainWindow* fWindow;
  164. int fMsgTimer;
  165. bool fNeedsShow;
  166. void handleTimeout()
  167. {
  168. if (kClient == nullptr)
  169. return;
  170. kClient->uiIdle();
  171. if (! kClient->oscIdle())
  172. {
  173. killTimer(fMsgTimer);
  174. fMsgTimer = 0;
  175. fApp->quit();
  176. }
  177. }
  178. private:
  179. void timerEvent(QTimerEvent* const ev)
  180. {
  181. if (ev->timerId() == fMsgTimer)
  182. handleTimeout();
  183. QObject::timerEvent(ev);
  184. }
  185. signals:
  186. void setSizeSafeSignal(int, int);
  187. private slots:
  188. void setSizeSafeSlot(uint width, uint height)
  189. {
  190. CARLA_SAFE_ASSERT_RETURN(kClient != nullptr,);
  191. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  192. if (kClient->isResizable())
  193. fWindow->resize(width, height);
  194. else
  195. fWindow->setFixedSize(width, height);
  196. }
  197. #ifndef MOC_PARSING
  198. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaBridgeToolkitQt)
  199. #endif
  200. };
  201. #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  202. # include "CarlaBridgeToolkitQt5.moc"
  203. #else
  204. # include "CarlaBridgeToolkitQt4.moc"
  205. #endif
  206. // -------------------------------------------------------------------------
  207. CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const windowTitle)
  208. {
  209. return new CarlaBridgeToolkitQt(client, windowTitle);
  210. }
  211. // -------------------------------------------------------------------------
  212. CARLA_BRIDGE_END_NAMESPACE
  213. // -------------------------------------------------------------------------
  214. // missing declaration
  215. int qInitResources();
  216. int qCleanupResources();
  217. #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
  218. # include "resources.qt5.cpp"
  219. #else
  220. # include "resources.qt4.cpp"
  221. #endif
  222. // -------------------------------------------------------------------------