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.

334 lines
9.3KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 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. #include "src/DistrhoPluginChecks.h"
  17. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  18. # if defined(DISTRHO_OS_WINDOWS)
  19. # define WIN32_LEAN_AND_MEAN
  20. # include <windows.h>
  21. # elif defined(HAVE_X11)
  22. # include <X11/Xresource.h>
  23. # endif
  24. #else
  25. # include "src/TopLevelWidgetPrivateData.hpp"
  26. # include "src/WindowPrivateData.hpp"
  27. #endif
  28. #include "DistrhoUIPrivateData.hpp"
  29. START_NAMESPACE_DISTRHO
  30. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  31. /* ------------------------------------------------------------------------------------------------------------
  32. * Static data, see DistrhoUIInternal.hpp */
  33. uintptr_t g_nextWindowId = 0;
  34. double g_nextScaleFactor = 1.0;
  35. const char* g_nextBundlePath = nullptr;
  36. /* ------------------------------------------------------------------------------------------------------------
  37. * get global scale factor */
  38. #ifdef DISTRHO_OS_MAC
  39. double getDesktopScaleFactor(uintptr_t parentWindowHandle);
  40. #else
  41. static double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
  42. {
  43. // allow custom scale for testing
  44. if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
  45. return std::max(1.0, std::atof(scale));
  46. #if defined(DISTRHO_OS_WINDOWS)
  47. if (const HMODULE Shcore = LoadLibraryA("Shcore.dll"))
  48. {
  49. typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*);
  50. typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*);
  51. # if defined(__GNUC__) && (__GNUC__ >= 9)
  52. # pragma GCC diagnostic push
  53. # pragma GCC diagnostic ignored "-Wcast-function-type"
  54. # endif
  55. const PFN_GetProcessDpiAwareness GetProcessDpiAwareness
  56. = (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness");
  57. const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor
  58. = (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor");
  59. # if defined(__GNUC__) && (__GNUC__ >= 9)
  60. # pragma GCC diagnostic pop
  61. # endif
  62. DWORD dpiAware = 0;
  63. if (GetProcessDpiAwareness && GetScaleFactorForMonitor
  64. && GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0)
  65. {
  66. const HMONITOR hMon = parentWindowHandle != 0
  67. ? MonitorFromWindow((HWND)parentWindowHandle, MONITOR_DEFAULTTOPRIMARY)
  68. : MonitorFromPoint(POINT{0,0}, MONITOR_DEFAULTTOPRIMARY);
  69. DWORD scaleFactor = 0;
  70. if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0)
  71. {
  72. FreeLibrary(Shcore);
  73. return static_cast<double>(scaleFactor) / 100.0;
  74. }
  75. }
  76. FreeLibrary(Shcore);
  77. }
  78. #elif defined(HAVE_X11)
  79. ::Display* const display = XOpenDisplay(nullptr);
  80. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0);
  81. XrmInitialize();
  82. if (char* const rms = XResourceManagerString(display))
  83. {
  84. if (const XrmDatabase sdb = XrmGetStringDatabase(rms))
  85. {
  86. char* type = nullptr;
  87. XrmValue ret;
  88. if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret)
  89. && ret.addr != nullptr
  90. && type != nullptr
  91. && std::strncmp("String", type, 6) == 0)
  92. {
  93. if (const double dpi = std::atof(ret.addr))
  94. {
  95. XCloseDisplay(display);
  96. return dpi / 96;
  97. }
  98. }
  99. }
  100. }
  101. XCloseDisplay(display);
  102. #endif
  103. return 1.0;
  104. // might be unused
  105. (void)parentWindowHandle;
  106. }
  107. #endif // !DISTRHO_OS_MAC
  108. #endif
  109. /* ------------------------------------------------------------------------------------------------------------
  110. * UI::PrivateData special handling */
  111. UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr;
  112. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  113. ExternalWindow::PrivateData
  114. #else
  115. PluginWindow&
  116. #endif
  117. UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint height)
  118. {
  119. UI::PrivateData* const pData = s_nextPrivateData;
  120. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  121. pData->window = new PluginWindow(ui, pData->app);
  122. ExternalWindow::PrivateData ewData;
  123. ewData.parentWindowHandle = pData->winId;
  124. ewData.width = width;
  125. ewData.height = height;
  126. ewData.scaleFactor = pData->scaleFactor != 0.0 ? pData->scaleFactor : getDesktopScaleFactor(pData->winId);
  127. ewData.title = DISTRHO_PLUGIN_NAME;
  128. ewData.isStandalone = DISTRHO_UI_IS_STANDALONE;
  129. return ewData;
  130. #else
  131. pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor);
  132. return pData->window.getObject();
  133. #endif
  134. }
  135. /* ------------------------------------------------------------------------------------------------------------
  136. * UI */
  137. UI::UI(const uint width, const uint height, const bool automaticallyScale)
  138. : UIWidget(UI::PrivateData::createNextWindow(this, width, height)),
  139. uiData(UI::PrivateData::s_nextPrivateData)
  140. {
  141. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  142. if (width > 0 && height > 0)
  143. {
  144. Widget::setSize(width, height);
  145. if (automaticallyScale)
  146. setGeometryConstraints(width, height, true, true);
  147. }
  148. #else
  149. // unused
  150. return; (void)automaticallyScale;
  151. #endif
  152. }
  153. UI::~UI()
  154. {
  155. }
  156. /* ------------------------------------------------------------------------------------------------------------
  157. * Host state */
  158. bool UI::isResizable() const noexcept
  159. {
  160. #if DISTRHO_UI_USER_RESIZABLE
  161. # if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  162. return true;
  163. # else
  164. return uiData->window->isResizable();
  165. # endif
  166. #else
  167. return false;
  168. #endif
  169. }
  170. uint UI::getBackgroundColor() const noexcept
  171. {
  172. return uiData->bgColor;
  173. }
  174. uint UI::getForegroundColor() const noexcept
  175. {
  176. return uiData->fgColor;
  177. }
  178. double UI::getSampleRate() const noexcept
  179. {
  180. return uiData->sampleRate;
  181. }
  182. void UI::editParameter(uint32_t index, bool started)
  183. {
  184. uiData->editParamCallback(index + uiData->parameterOffset, started);
  185. }
  186. void UI::setParameterValue(uint32_t index, float value)
  187. {
  188. uiData->setParamCallback(index + uiData->parameterOffset, value);
  189. }
  190. #if DISTRHO_PLUGIN_WANT_STATE
  191. void UI::setState(const char* key, const char* value)
  192. {
  193. uiData->setStateCallback(key, value);
  194. }
  195. #endif
  196. #if DISTRHO_PLUGIN_WANT_STATEFILES
  197. bool UI::requestStateFile(const char* key)
  198. {
  199. return uiData->fileRequestCallback(key);
  200. }
  201. #endif
  202. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  203. void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity)
  204. {
  205. uiData->sendNoteCallback(channel, note, velocity);
  206. }
  207. #endif
  208. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  209. /* ------------------------------------------------------------------------------------------------------------
  210. * Direct DSP access */
  211. void* UI::getPluginInstancePointer() const noexcept
  212. {
  213. return uiData->dspPtr;
  214. }
  215. #endif
  216. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  217. /* ------------------------------------------------------------------------------------------------------------
  218. * External UI helpers */
  219. const char* UI::getNextBundlePath() noexcept
  220. {
  221. return g_nextBundlePath;
  222. }
  223. double UI::getNextScaleFactor() noexcept
  224. {
  225. return g_nextScaleFactor;
  226. }
  227. # if DISTRHO_PLUGIN_HAS_EMBED_UI
  228. uintptr_t UI::getNextWindowId() noexcept
  229. {
  230. return g_nextWindowId;
  231. }
  232. # endif
  233. #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  234. /* ------------------------------------------------------------------------------------------------------------
  235. * DSP/Plugin Callbacks (optional) */
  236. void UI::sampleRateChanged(double)
  237. {
  238. }
  239. /* ------------------------------------------------------------------------------------------------------------
  240. * UI Callbacks (optional) */
  241. void UI::uiScaleFactorChanged(double)
  242. {
  243. }
  244. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  245. void UI::uiFocus(bool, DGL_NAMESPACE::CrossingMode)
  246. {
  247. }
  248. void UI::uiReshape(uint, uint)
  249. {
  250. // NOTE this must be the same as Window::onReshape
  251. pData->fallbackOnResize();
  252. }
  253. # ifndef DGL_FILE_BROWSER_DISABLED
  254. void UI::uiFileBrowserSelected(const char*)
  255. {
  256. }
  257. # endif
  258. #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  259. /* ------------------------------------------------------------------------------------------------------------
  260. * UI Resize Handling, internal */
  261. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  262. void UI::sizeChanged(const uint width, const uint height)
  263. {
  264. UIWidget::sizeChanged(width, height);
  265. uiData->setSizeCallback(width, height);
  266. }
  267. #else
  268. void UI::onResize(const ResizeEvent& ev)
  269. {
  270. UIWidget::onResize(ev);
  271. const uint width = ev.size.getWidth();
  272. const uint height = ev.size.getHeight();
  273. uiData->setSizeCallback(width, height);
  274. }
  275. #endif
  276. // -----------------------------------------------------------------------------------------------------------
  277. END_NAMESPACE_DISTRHO