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.

431 lines
11KB

  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 "WindowPrivateData.hpp"
  17. #include "pugl.hpp"
  18. START_NAMESPACE_DGL
  19. // -----------------------------------------------------------------------
  20. // ScopedGraphicsContext
  21. Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win)
  22. : window(win),
  23. ppData(nullptr),
  24. active(puglBackendEnter(window.pData->view)) {}
  25. Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transientWin)
  26. : window(win),
  27. ppData(transientWin.pData),
  28. active(false)
  29. {
  30. puglBackendLeave(ppData->view);
  31. active = puglBackendEnter(window.pData->view);
  32. }
  33. Window::ScopedGraphicsContext::~ScopedGraphicsContext()
  34. {
  35. done();
  36. }
  37. void Window::ScopedGraphicsContext::done()
  38. {
  39. if (active)
  40. {
  41. puglBackendLeave(window.pData->view);
  42. active = false;
  43. }
  44. if (ppData != nullptr)
  45. {
  46. puglBackendEnter(ppData->view);
  47. ppData = nullptr;
  48. }
  49. }
  50. // -----------------------------------------------------------------------
  51. // Window
  52. Window::Window(Application& app)
  53. : pData(new PrivateData(app, this))
  54. {
  55. pData->initPost();
  56. }
  57. Window::Window(Application& app, Window& transientParentWindow)
  58. : pData(new PrivateData(app, this, transientParentWindow.pData))
  59. {
  60. pData->initPost();
  61. }
  62. Window::Window(Application& app,
  63. const uintptr_t parentWindowHandle,
  64. const double scaleFactor,
  65. const bool resizable)
  66. : pData(new PrivateData(app, this, parentWindowHandle, scaleFactor, resizable))
  67. {
  68. pData->initPost();
  69. }
  70. Window::Window(Application& app,
  71. const uintptr_t parentWindowHandle,
  72. const uint width,
  73. const uint height,
  74. const double scaleFactor,
  75. const bool resizable)
  76. : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable))
  77. {
  78. pData->initPost();
  79. }
  80. Window::Window(Application& app,
  81. const uintptr_t parentWindowHandle,
  82. const uint width,
  83. const uint height,
  84. const double scaleFactor,
  85. const bool resizable,
  86. const bool doPostInit)
  87. : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable))
  88. {
  89. if (doPostInit)
  90. pData->initPost();
  91. }
  92. Window::~Window()
  93. {
  94. delete pData;
  95. }
  96. bool Window::isEmbed() const noexcept
  97. {
  98. return pData->isEmbed;
  99. }
  100. bool Window::isVisible() const noexcept
  101. {
  102. return pData->isVisible;
  103. }
  104. void Window::setVisible(const bool visible)
  105. {
  106. if (visible)
  107. pData->show();
  108. else
  109. pData->hide();
  110. }
  111. void Window::show()
  112. {
  113. pData->show();
  114. }
  115. void Window::hide()
  116. {
  117. pData->hide();
  118. }
  119. void Window::close()
  120. {
  121. pData->close();
  122. }
  123. bool Window::isResizable() const noexcept
  124. {
  125. return puglGetViewHint(pData->view, PUGL_RESIZABLE) == PUGL_TRUE;
  126. }
  127. void Window::setResizable(const bool resizable)
  128. {
  129. pData->setResizable(resizable);
  130. }
  131. uint Window::getWidth() const noexcept
  132. {
  133. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  134. const double width = puglGetFrame(pData->view).width;
  135. DISTRHO_SAFE_ASSERT_RETURN(width >= 0.0, 0);
  136. return static_cast<uint>(width + 0.5);
  137. }
  138. uint Window::getHeight() const noexcept
  139. {
  140. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  141. const double height = puglGetFrame(pData->view).height;
  142. DISTRHO_SAFE_ASSERT_RETURN(height >= 0.0, 0);
  143. return static_cast<uint>(height + 0.5);
  144. }
  145. Size<uint> Window::getSize() const noexcept
  146. {
  147. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>());
  148. const PuglRect rect = puglGetFrame(pData->view);
  149. DISTRHO_SAFE_ASSERT_RETURN(rect.width >= 0.0, Size<uint>());
  150. DISTRHO_SAFE_ASSERT_RETURN(rect.height >= 0.0, Size<uint>());
  151. return Size<uint>(static_cast<uint>(rect.width + 0.5),
  152. static_cast<uint>(rect.height + 0.5));
  153. }
  154. void Window::setWidth(const uint width)
  155. {
  156. setSize(width, getHeight());
  157. }
  158. void Window::setHeight(const uint height)
  159. {
  160. setSize(getWidth(), height);
  161. }
  162. void Window::setSize(uint width, uint height)
  163. {
  164. DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,);
  165. if (pData->isEmbed)
  166. {
  167. const double scaleFactor = pData->scaleFactor;
  168. const uint minWidth = static_cast<uint>(pData->minWidth * scaleFactor + 0.5);
  169. const uint minHeight = static_cast<uint>(pData->minHeight * scaleFactor + 0.5);
  170. // handle geometry constraints here
  171. if (width < minWidth)
  172. width = minWidth;
  173. if (height < minHeight)
  174. height = minHeight;
  175. if (pData->keepAspectRatio)
  176. {
  177. const double ratio = static_cast<double>(pData->minWidth)
  178. / static_cast<double>(pData->minHeight);
  179. const double reqRatio = static_cast<double>(width)
  180. / static_cast<double>(height);
  181. if (d_isNotEqual(ratio, reqRatio))
  182. {
  183. // fix width
  184. if (reqRatio > ratio)
  185. width = static_cast<uint>(height * ratio + 0.5);
  186. // fix height
  187. else
  188. height = static_cast<uint>(static_cast<double>(width) / ratio + 0.5);
  189. }
  190. }
  191. }
  192. puglSetWindowSize(pData->view, width, height);
  193. }
  194. void Window::setSize(const Size<uint>& size)
  195. {
  196. setSize(size.getWidth(), size.getHeight());
  197. }
  198. const char* Window::getTitle() const noexcept
  199. {
  200. return puglGetWindowTitle(pData->view);
  201. }
  202. void Window::setTitle(const char* const title)
  203. {
  204. if (pData->view != nullptr)
  205. puglSetWindowTitle(pData->view, title);
  206. }
  207. bool Window::isIgnoringKeyRepeat() const noexcept
  208. {
  209. return puglGetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT) == PUGL_TRUE;
  210. }
  211. void Window::setIgnoringKeyRepeat(const bool ignore) noexcept
  212. {
  213. puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore);
  214. }
  215. bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize)
  216. {
  217. return puglSetClipboard(pData->view, mimeType, data, dataSize) == PUGL_SUCCESS;
  218. }
  219. const void* Window::getClipboard(const char*& mimeType, size_t& dataSize)
  220. {
  221. return puglGetClipboard(pData->view, &mimeType, &dataSize);
  222. }
  223. bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
  224. {
  225. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  226. return pData->addIdleCallback(callback, timerFrequencyInMs);
  227. }
  228. bool Window::removeIdleCallback(IdleCallback* const callback)
  229. {
  230. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  231. return pData->removeIdleCallback(callback);
  232. }
  233. Application& Window::getApp() const noexcept
  234. {
  235. return pData->app;
  236. }
  237. #ifndef DPF_TEST_WINDOW_CPP
  238. const GraphicsContext& Window::getGraphicsContext() const noexcept
  239. {
  240. return pData->getGraphicsContext();
  241. }
  242. #endif
  243. uintptr_t Window::getNativeWindowHandle() const noexcept
  244. {
  245. return puglGetNativeWindow(pData->view);
  246. }
  247. double Window::getScaleFactor() const noexcept
  248. {
  249. return pData->scaleFactor;
  250. }
  251. void Window::focus()
  252. {
  253. pData->focus();
  254. }
  255. #ifndef DGL_FILE_BROWSER_DISABLED
  256. bool Window::openFileBrowser(const FileBrowserOptions& options)
  257. {
  258. return pData->openFileBrowser(options);
  259. }
  260. #endif
  261. void Window::repaint() noexcept
  262. {
  263. if (pData->view == nullptr)
  264. return;
  265. puglPostRedisplay(pData->view);
  266. }
  267. void Window::repaint(const Rectangle<uint>& rect) noexcept
  268. {
  269. if (pData->view == nullptr)
  270. return;
  271. PuglRect prect = {
  272. static_cast<double>(rect.getX()),
  273. static_cast<double>(rect.getY()),
  274. static_cast<double>(rect.getWidth()),
  275. static_cast<double>(rect.getHeight()),
  276. };
  277. if (pData->autoScaling)
  278. {
  279. const double autoScaleFactor = pData->autoScaleFactor;
  280. prect.x *= autoScaleFactor;
  281. prect.y *= autoScaleFactor;
  282. prect.width *= autoScaleFactor;
  283. prect.height *= autoScaleFactor;
  284. }
  285. puglPostRedisplayRect(pData->view, prect);
  286. }
  287. void Window::renderToPicture(const char* const filename)
  288. {
  289. pData->filenameToRenderInto = strdup(filename);
  290. }
  291. void Window::runAsModal(bool blockWait)
  292. {
  293. pData->runAsModal(blockWait);
  294. }
  295. Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio)
  296. {
  297. keepAspectRatio = pData->keepAspectRatio;
  298. return Size<uint>(pData->minWidth, pData->minHeight);
  299. }
  300. void Window::setGeometryConstraints(const uint minimumWidth,
  301. const uint minimumHeight,
  302. const bool keepAspectRatio,
  303. const bool automaticallyScale)
  304. {
  305. DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,);
  306. DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,);
  307. pData->minWidth = minimumWidth;
  308. pData->minHeight = minimumHeight;
  309. pData->autoScaling = automaticallyScale;
  310. pData->keepAspectRatio = keepAspectRatio;
  311. if (pData->view == nullptr)
  312. return;
  313. const double scaleFactor = pData->scaleFactor;
  314. puglSetGeometryConstraints(pData->view,
  315. static_cast<uint>(minimumWidth * scaleFactor + 0.5),
  316. static_cast<uint>(minimumHeight * scaleFactor + 0.5),
  317. keepAspectRatio);
  318. if (scaleFactor != 1.0)
  319. {
  320. const Size<uint> size(getSize());
  321. setSize(static_cast<uint>(size.getWidth() * scaleFactor + 0.5),
  322. static_cast<uint>(size.getHeight() * scaleFactor + 0.5));
  323. }
  324. }
  325. bool Window::onClose()
  326. {
  327. return true;
  328. }
  329. void Window::onFocus(bool, CrossingMode)
  330. {
  331. }
  332. void Window::onReshape(uint, uint)
  333. {
  334. puglFallbackOnResize(pData->view);
  335. }
  336. void Window::onScaleFactorChanged(double)
  337. {
  338. }
  339. #ifndef DGL_FILE_BROWSER_DISABLED
  340. void Window::onFileSelected(const char*)
  341. {
  342. }
  343. #endif
  344. #if 0
  345. void Window::setTransientWinId(const uintptr_t winId)
  346. {
  347. puglSetTransientFor(pData->view, winId);
  348. }
  349. #endif
  350. // -----------------------------------------------------------------------
  351. END_NAMESPACE_DGL