DISTRHO Plugin Framework
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.

373 lines
10KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
  17. #define DISTRHO_UI_INTERNAL_HPP_INCLUDED
  18. #include "DistrhoUIPrivateData.hpp"
  19. START_NAMESPACE_DISTRHO
  20. // -----------------------------------------------------------------------
  21. // Static data, see DistrhoUI.cpp
  22. extern const char* g_nextBundlePath;
  23. // -----------------------------------------------------------------------
  24. // UI exporter class
  25. class UIExporter
  26. {
  27. // -------------------------------------------------------------------
  28. // UI Widget and its private data
  29. UI* ui;
  30. UI::PrivateData* uiData;
  31. // -------------------------------------------------------------------
  32. public:
  33. UIExporter(void* const callbacksPtr,
  34. const uintptr_t winId,
  35. const double sampleRate,
  36. const editParamFunc editParamCall,
  37. const setParamFunc setParamCall,
  38. const setStateFunc setStateCall,
  39. const sendNoteFunc sendNoteCall,
  40. const setSizeFunc setSizeCall,
  41. const fileRequestFunc fileRequestCall,
  42. const char* const bundlePath = nullptr,
  43. void* const dspPtr = nullptr,
  44. const double scaleFactor = 0.0,
  45. const uint32_t bgColor = 0,
  46. const uint32_t fgColor = 0xffffffff,
  47. const char* const appClassName = nullptr)
  48. : ui(nullptr),
  49. uiData(new UI::PrivateData(appClassName))
  50. {
  51. uiData->sampleRate = sampleRate;
  52. uiData->bundlePath = bundlePath != nullptr ? strdup(bundlePath) : nullptr;
  53. uiData->dspPtr = dspPtr;
  54. uiData->bgColor = bgColor;
  55. uiData->fgColor = fgColor;
  56. uiData->scaleFactor = scaleFactor;
  57. uiData->winId = winId;
  58. uiData->callbacksPtr = callbacksPtr;
  59. uiData->editParamCallbackFunc = editParamCall;
  60. uiData->setParamCallbackFunc = setParamCall;
  61. uiData->setStateCallbackFunc = setStateCall;
  62. uiData->sendNoteCallbackFunc = sendNoteCall;
  63. uiData->setSizeCallbackFunc = setSizeCall;
  64. uiData->fileRequestCallbackFunc = fileRequestCall;
  65. g_nextBundlePath = bundlePath;
  66. UI::PrivateData::s_nextPrivateData = uiData;
  67. UI* const uiPtr = createUI();
  68. g_nextBundlePath = nullptr;
  69. // enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
  70. uiData->window->leaveContext();
  71. UI::PrivateData::s_nextPrivateData = nullptr;
  72. DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
  73. ui = uiPtr;
  74. uiData->initializing = false;
  75. }
  76. ~UIExporter()
  77. {
  78. quit();
  79. uiData->window->enterContextForDeletion();
  80. delete ui;
  81. delete uiData;
  82. }
  83. // -------------------------------------------------------------------
  84. uint getWidth() const noexcept
  85. {
  86. return uiData->window->getWidth();
  87. }
  88. uint getHeight() const noexcept
  89. {
  90. return uiData->window->getHeight();
  91. }
  92. double getScaleFactor() const noexcept
  93. {
  94. return uiData->window->getScaleFactor();
  95. }
  96. bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
  97. {
  98. const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio));
  99. minimumWidth = size.getWidth();
  100. minimumHeight = size.getHeight();
  101. return true;
  102. }
  103. bool isResizable() const noexcept
  104. {
  105. return uiData->window->isResizable();
  106. }
  107. bool isVisible() const noexcept
  108. {
  109. return uiData->window->isVisible();
  110. }
  111. uintptr_t getNativeWindowHandle() const noexcept
  112. {
  113. return uiData->window->getNativeWindowHandle();
  114. }
  115. uint getBackgroundColor() const noexcept
  116. {
  117. DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
  118. return uiData->bgColor;
  119. }
  120. uint getForegroundColor() const noexcept
  121. {
  122. DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff);
  123. return uiData->fgColor;
  124. }
  125. // -------------------------------------------------------------------
  126. uint32_t getParameterOffset() const noexcept
  127. {
  128. DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
  129. return uiData->parameterOffset;
  130. }
  131. // -------------------------------------------------------------------
  132. void parameterChanged(const uint32_t index, const float value)
  133. {
  134. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  135. ui->parameterChanged(index, value);
  136. }
  137. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  138. void programLoaded(const uint32_t index)
  139. {
  140. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  141. ui->programLoaded(index);
  142. }
  143. #endif
  144. #if DISTRHO_PLUGIN_WANT_STATE
  145. void stateChanged(const char* const key, const char* const value)
  146. {
  147. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  148. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  149. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
  150. ui->stateChanged(key, value);
  151. }
  152. #endif
  153. // -------------------------------------------------------------------
  154. #if DISTRHO_UI_IS_STANDALONE
  155. void exec(DGL_NAMESPACE::IdleCallback* const cb)
  156. {
  157. DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
  158. uiData->window->show();
  159. uiData->window->focus();
  160. uiData->app.addIdleCallback(cb);
  161. uiData->app.exec();
  162. }
  163. void exec_idle()
  164. {
  165. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );
  166. ui->uiIdle();
  167. uiData->app.repaintIfNeeeded();
  168. }
  169. void showAndFocus()
  170. {
  171. uiData->window->show();
  172. uiData->window->focus();
  173. }
  174. #endif
  175. bool plugin_idle()
  176. {
  177. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);
  178. uiData->app.idle();
  179. ui->uiIdle();
  180. uiData->app.repaintIfNeeeded();
  181. return ! uiData->app.isQuitting();
  182. }
  183. void focus()
  184. {
  185. uiData->window->focus();
  186. }
  187. void quit()
  188. {
  189. uiData->window->close();
  190. uiData->app.quit();
  191. }
  192. void repaint()
  193. {
  194. uiData->window->repaint();
  195. }
  196. // -------------------------------------------------------------------
  197. #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)
  198. void idleFromNativeIdle()
  199. {
  200. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  201. uiData->app.triggerIdleCallbacks();
  202. ui->uiIdle();
  203. uiData->app.repaintIfNeeeded();
  204. }
  205. void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs)
  206. {
  207. uiData->window->addIdleCallback(cb, timerFrequencyInMs);
  208. }
  209. void removeIdleCallbackForNativeIdle(IdleCallback* const cb)
  210. {
  211. uiData->window->removeIdleCallback(cb);
  212. }
  213. #endif
  214. // -------------------------------------------------------------------
  215. void setWindowOffset(const int x, const int y)
  216. {
  217. uiData->window->setOffset(x, y);
  218. }
  219. #if DISTRHO_UI_USES_SIZE_REQUEST
  220. void setWindowSizeFromHost(const uint width, const uint height)
  221. {
  222. uiData->window->setSizeFromHost(width, height);
  223. }
  224. #endif
  225. void setWindowTitle(const char* const uiTitle)
  226. {
  227. uiData->window->setTitle(uiTitle);
  228. }
  229. void setWindowTransientWinId(const uintptr_t transientParentWindowHandle)
  230. {
  231. uiData->window->setTransientParent(transientParentWindowHandle);
  232. }
  233. bool setWindowVisible(const bool yesNo)
  234. {
  235. uiData->window->setVisible(yesNo);
  236. return ! uiData->app.isQuitting();
  237. }
  238. bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods)
  239. {
  240. using namespace DGL_NAMESPACE;
  241. Widget::KeyboardEvent ev;
  242. ev.mod = mods;
  243. ev.press = press;
  244. ev.key = keychar;
  245. ev.keycode = keycode;
  246. // keyboard events must always be lowercase
  247. if (ev.key >= 'A' && ev.key <= 'Z')
  248. ev.key += 'a' - 'A'; // A-Z -> a-z
  249. const bool ret = ui->onKeyboard(ev);
  250. if (press && !special && (mods & (kModifierControl|kModifierAlt|kModifierSuper)) == 0)
  251. {
  252. Widget::CharacterInputEvent cev;
  253. cev.mod = mods;
  254. cev.character = keychar;
  255. cev.keycode = keycode;
  256. // if shift modifier is on, convert a-z -> A-Z for character input
  257. if (cev.character >= 'a' && cev.character <= 'z' && (mods & kModifierShift) != 0)
  258. cev.character -= 'a' - 'A';
  259. ui->onCharacterInput(cev);
  260. }
  261. return ret;
  262. }
  263. // -------------------------------------------------------------------
  264. void notifyScaleFactorChanged(const double scaleFactor)
  265. {
  266. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  267. ui->uiScaleFactorChanged(scaleFactor);
  268. }
  269. void notifyFocusChanged(const bool focus)
  270. {
  271. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  272. ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal);
  273. }
  274. void setSampleRate(const double sampleRate, const bool doCallback = false)
  275. {
  276. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  277. DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,);
  278. DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
  279. if (d_isEqual(uiData->sampleRate, sampleRate))
  280. return;
  281. uiData->sampleRate = sampleRate;
  282. if (doCallback)
  283. ui->sampleRateChanged(sampleRate);
  284. }
  285. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
  286. };
  287. // -----------------------------------------------------------------------
  288. END_NAMESPACE_DISTRHO
  289. #endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED