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.

421 lines
10KB

  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::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
  216. {
  217. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  218. return pData->addIdleCallback(callback, timerFrequencyInMs);
  219. }
  220. bool Window::removeIdleCallback(IdleCallback* const callback)
  221. {
  222. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  223. return pData->removeIdleCallback(callback);
  224. }
  225. Application& Window::getApp() const noexcept
  226. {
  227. return pData->app;
  228. }
  229. #ifndef DPF_TEST_WINDOW_CPP
  230. const GraphicsContext& Window::getGraphicsContext() const noexcept
  231. {
  232. return pData->getGraphicsContext();
  233. }
  234. #endif
  235. uintptr_t Window::getNativeWindowHandle() const noexcept
  236. {
  237. return puglGetNativeWindow(pData->view);
  238. }
  239. double Window::getScaleFactor() const noexcept
  240. {
  241. return pData->scaleFactor;
  242. }
  243. void Window::focus()
  244. {
  245. pData->focus();
  246. }
  247. #ifndef DGL_FILE_BROWSER_DISABLED
  248. bool Window::openFileBrowser(const FileBrowserOptions& options)
  249. {
  250. return pData->openFileBrowser(options);
  251. }
  252. #endif
  253. void Window::repaint() noexcept
  254. {
  255. if (pData->view == nullptr)
  256. return;
  257. puglPostRedisplay(pData->view);
  258. }
  259. void Window::repaint(const Rectangle<uint>& rect) noexcept
  260. {
  261. if (pData->view == nullptr)
  262. return;
  263. PuglRect prect = {
  264. static_cast<double>(rect.getX()),
  265. static_cast<double>(rect.getY()),
  266. static_cast<double>(rect.getWidth()),
  267. static_cast<double>(rect.getHeight()),
  268. };
  269. if (pData->autoScaling)
  270. {
  271. const double autoScaleFactor = pData->autoScaleFactor;
  272. prect.x *= autoScaleFactor;
  273. prect.y *= autoScaleFactor;
  274. prect.width *= autoScaleFactor;
  275. prect.height *= autoScaleFactor;
  276. }
  277. puglPostRedisplayRect(pData->view, prect);
  278. }
  279. void Window::renderToPicture(const char* const filename)
  280. {
  281. pData->filenameToRenderInto = strdup(filename);
  282. }
  283. void Window::runAsModal(bool blockWait)
  284. {
  285. pData->runAsModal(blockWait);
  286. }
  287. Size<uint> Window::getMinimumSizeConstraint(bool& keepAspectRatio)
  288. {
  289. keepAspectRatio = pData->keepAspectRatio;
  290. return Size<uint>(pData->minWidth, pData->minHeight);
  291. }
  292. void Window::setGeometryConstraints(const uint minimumWidth,
  293. const uint minimumHeight,
  294. const bool keepAspectRatio,
  295. const bool automaticallyScale)
  296. {
  297. DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,);
  298. DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,);
  299. pData->minWidth = minimumWidth;
  300. pData->minHeight = minimumHeight;
  301. pData->autoScaling = automaticallyScale;
  302. pData->keepAspectRatio = keepAspectRatio;
  303. if (pData->view == nullptr)
  304. return;
  305. const double scaleFactor = pData->scaleFactor;
  306. puglSetGeometryConstraints(pData->view,
  307. static_cast<uint>(minimumWidth * scaleFactor + 0.5),
  308. static_cast<uint>(minimumHeight * scaleFactor + 0.5),
  309. keepAspectRatio);
  310. if (scaleFactor != 1.0)
  311. {
  312. const Size<uint> size(getSize());
  313. setSize(static_cast<uint>(size.getWidth() * scaleFactor + 0.5),
  314. static_cast<uint>(size.getHeight() * scaleFactor + 0.5));
  315. }
  316. }
  317. bool Window::onClose()
  318. {
  319. return true;
  320. }
  321. void Window::onFocus(bool, CrossingMode)
  322. {
  323. }
  324. void Window::onReshape(uint, uint)
  325. {
  326. puglFallbackOnResize(pData->view);
  327. }
  328. void Window::onScaleFactorChanged(double)
  329. {
  330. }
  331. #ifndef DGL_FILE_BROWSER_DISABLED
  332. void Window::onFileSelected(const char*)
  333. {
  334. }
  335. #endif
  336. #if 0
  337. void Window::setTransientWinId(const uintptr_t winId)
  338. {
  339. puglSetTransientFor(pData->view, winId);
  340. }
  341. #endif
  342. // -----------------------------------------------------------------------
  343. END_NAMESPACE_DGL