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.

525 lines
13KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2022 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 "../TopLevelWidget.hpp"
  18. #include "pugl.hpp"
  19. START_NAMESPACE_DGL
  20. // -----------------------------------------------------------------------
  21. // ScopedGraphicsContext
  22. Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win)
  23. : window(win),
  24. ppData(nullptr),
  25. active(puglBackendEnter(window.pData->view)) {}
  26. Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transientWin)
  27. : window(win),
  28. ppData(transientWin.pData),
  29. active(false)
  30. {
  31. puglBackendLeave(ppData->view);
  32. active = puglBackendEnter(window.pData->view);
  33. }
  34. Window::ScopedGraphicsContext::~ScopedGraphicsContext()
  35. {
  36. done();
  37. }
  38. void Window::ScopedGraphicsContext::done()
  39. {
  40. if (active)
  41. {
  42. puglBackendLeave(window.pData->view);
  43. active = false;
  44. }
  45. if (ppData != nullptr)
  46. {
  47. puglBackendEnter(ppData->view);
  48. ppData = nullptr;
  49. }
  50. }
  51. // -----------------------------------------------------------------------
  52. // Window
  53. Window::Window(Application& app)
  54. : pData(new PrivateData(app, this))
  55. {
  56. pData->initPost();
  57. }
  58. Window::Window(Application& app, Window& transientParentWindow)
  59. : pData(new PrivateData(app, this, transientParentWindow.pData))
  60. {
  61. pData->initPost();
  62. }
  63. Window::Window(Application& app,
  64. const uintptr_t parentWindowHandle,
  65. const double scaleFactor,
  66. const bool resizable)
  67. : pData(new PrivateData(app, this, parentWindowHandle, scaleFactor, resizable))
  68. {
  69. pData->initPost();
  70. }
  71. Window::Window(Application& app,
  72. const uintptr_t parentWindowHandle,
  73. const uint width,
  74. const uint height,
  75. const double scaleFactor,
  76. const bool resizable)
  77. : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false))
  78. {
  79. pData->initPost();
  80. }
  81. Window::Window(Application& app,
  82. const uintptr_t parentWindowHandle,
  83. const uint width,
  84. const uint height,
  85. const double scaleFactor,
  86. const bool resizable,
  87. const bool isVST3,
  88. const bool doPostInit)
  89. : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3))
  90. {
  91. if (doPostInit)
  92. pData->initPost();
  93. }
  94. Window::~Window()
  95. {
  96. delete pData;
  97. }
  98. bool Window::isEmbed() const noexcept
  99. {
  100. return pData->isEmbed;
  101. }
  102. bool Window::isVisible() const noexcept
  103. {
  104. return pData->isVisible;
  105. }
  106. void Window::setVisible(const bool visible)
  107. {
  108. if (visible)
  109. pData->show();
  110. else
  111. pData->hide();
  112. }
  113. void Window::show()
  114. {
  115. pData->show();
  116. }
  117. void Window::hide()
  118. {
  119. pData->hide();
  120. }
  121. void Window::close()
  122. {
  123. pData->close();
  124. }
  125. bool Window::isResizable() const noexcept
  126. {
  127. return puglGetViewHint(pData->view, PUGL_RESIZABLE) == PUGL_TRUE;
  128. }
  129. void Window::setResizable(const bool resizable)
  130. {
  131. pData->setResizable(resizable);
  132. }
  133. int Window::getOffsetX() const noexcept
  134. {
  135. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  136. return puglGetFrame(pData->view).x;
  137. }
  138. int Window::getOffsetY() const noexcept
  139. {
  140. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  141. return puglGetFrame(pData->view).y;
  142. }
  143. Point<int> Window::getOffset() const noexcept
  144. {
  145. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point<int>());
  146. const PuglRect rect = puglGetFrame(pData->view);
  147. return Point<int>(rect.x, rect.y);
  148. }
  149. void Window::setOffsetX(const int x)
  150. {
  151. setOffset(x, getOffsetY());
  152. }
  153. void Window::setOffsetY(const int y)
  154. {
  155. setOffset(getOffsetX(), y);
  156. }
  157. void Window::setOffset(const int x, const int y)
  158. {
  159. puglSetPosition(pData->view, x, y);
  160. }
  161. void Window::setOffset(const Point<int>& offset)
  162. {
  163. setOffset(offset.getX(), offset.getY());
  164. }
  165. uint Window::getWidth() const noexcept
  166. {
  167. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  168. const double width = puglGetFrame(pData->view).width;
  169. DISTRHO_SAFE_ASSERT_RETURN(width >= 0.0, 0);
  170. return static_cast<uint>(width + 0.5);
  171. }
  172. uint Window::getHeight() const noexcept
  173. {
  174. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);
  175. const double height = puglGetFrame(pData->view).height;
  176. DISTRHO_SAFE_ASSERT_RETURN(height >= 0.0, 0);
  177. return static_cast<uint>(height + 0.5);
  178. }
  179. Size<uint> Window::getSize() const noexcept
  180. {
  181. DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>());
  182. const PuglRect rect = puglGetFrame(pData->view);
  183. DISTRHO_SAFE_ASSERT_RETURN(rect.width >= 0.0, Size<uint>());
  184. DISTRHO_SAFE_ASSERT_RETURN(rect.height >= 0.0, Size<uint>());
  185. return Size<uint>(static_cast<uint>(rect.width + 0.5),
  186. static_cast<uint>(rect.height + 0.5));
  187. }
  188. void Window::setWidth(const uint width)
  189. {
  190. setSize(width, getHeight());
  191. }
  192. void Window::setHeight(const uint height)
  193. {
  194. setSize(getWidth(), height);
  195. }
  196. void Window::setSize(uint width, uint height)
  197. {
  198. DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,);
  199. if (pData->isEmbed)
  200. {
  201. const double scaleFactor = pData->scaleFactor;
  202. uint minWidth = pData->minWidth;
  203. uint minHeight = pData->minHeight;
  204. if (pData->autoScaling && scaleFactor != 1.0)
  205. {
  206. minWidth *= scaleFactor;
  207. minHeight *= scaleFactor;
  208. }
  209. // handle geometry constraints here
  210. if (width < minWidth)
  211. width = minWidth;
  212. if (height < minHeight)
  213. height = minHeight;
  214. if (pData->keepAspectRatio)
  215. {
  216. const double ratio = static_cast<double>(pData->minWidth)
  217. / static_cast<double>(pData->minHeight);
  218. const double reqRatio = static_cast<double>(width)
  219. / static_cast<double>(height);
  220. if (d_isNotEqual(ratio, reqRatio))
  221. {
  222. // fix width
  223. if (reqRatio > ratio)
  224. width = static_cast<uint>(height * ratio + 0.5);
  225. // fix height
  226. else
  227. height = static_cast<uint>(static_cast<double>(width) / ratio + 0.5);
  228. }
  229. }
  230. }
  231. if (pData->usesSizeRequest)
  232. {
  233. DISTRHO_SAFE_ASSERT_RETURN(pData->topLevelWidgets.size() != 0,);
  234. TopLevelWidget* const topLevelWidget = pData->topLevelWidgets.front();
  235. DISTRHO_SAFE_ASSERT_RETURN(topLevelWidget != nullptr,);
  236. topLevelWidget->requestSizeChange(width, height);
  237. }
  238. else
  239. {
  240. puglSetSizeAndDefault(pData->view, width, height);
  241. }
  242. }
  243. void Window::setSize(const Size<uint>& size)
  244. {
  245. setSize(size.getWidth(), size.getHeight());
  246. }
  247. const char* Window::getTitle() const noexcept
  248. {
  249. return puglGetWindowTitle(pData->view);
  250. }
  251. void Window::setTitle(const char* const title)
  252. {
  253. if (pData->view != nullptr)
  254. puglSetWindowTitle(pData->view, title);
  255. }
  256. bool Window::isIgnoringKeyRepeat() const noexcept
  257. {
  258. return puglGetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT) == PUGL_TRUE;
  259. }
  260. void Window::setIgnoringKeyRepeat(const bool ignore) noexcept
  261. {
  262. puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore);
  263. }
  264. const void* Window::getClipboard(size_t& dataSize)
  265. {
  266. return pData->getClipboard(dataSize);
  267. }
  268. bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize)
  269. {
  270. return puglSetClipboard(pData->view, mimeType != nullptr ? mimeType : "text/plain", data, dataSize) == PUGL_SUCCESS;
  271. }
  272. bool Window::setCursor(const MouseCursor cursor)
  273. {
  274. return puglSetCursor(pData->view, static_cast<PuglCursor>(cursor)) == PUGL_SUCCESS;
  275. }
  276. bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
  277. {
  278. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  279. return pData->addIdleCallback(callback, timerFrequencyInMs);
  280. }
  281. bool Window::removeIdleCallback(IdleCallback* const callback)
  282. {
  283. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false)
  284. return pData->removeIdleCallback(callback);
  285. }
  286. Application& Window::getApp() const noexcept
  287. {
  288. return pData->app;
  289. }
  290. #ifndef DPF_TEST_WINDOW_CPP
  291. const GraphicsContext& Window::getGraphicsContext() const noexcept
  292. {
  293. return pData->getGraphicsContext();
  294. }
  295. #endif
  296. uintptr_t Window::getNativeWindowHandle() const noexcept
  297. {
  298. return puglGetNativeWindow(pData->view);
  299. }
  300. double Window::getScaleFactor() const noexcept
  301. {
  302. return pData->scaleFactor;
  303. }
  304. void Window::focus()
  305. {
  306. pData->focus();
  307. }
  308. #ifndef DGL_FILE_BROWSER_DISABLED
  309. bool Window::openFileBrowser(const FileBrowserOptions& options)
  310. {
  311. return pData->openFileBrowser(options);
  312. }
  313. #endif
  314. void Window::repaint() noexcept
  315. {
  316. if (pData->view == nullptr)
  317. return;
  318. puglPostRedisplay(pData->view);
  319. }
  320. void Window::repaint(const Rectangle<uint>& rect) noexcept
  321. {
  322. if (pData->view == nullptr)
  323. return;
  324. PuglRect prect = {
  325. static_cast<PuglCoord>(rect.getX()),
  326. static_cast<PuglCoord>(rect.getY()),
  327. static_cast<PuglSpan>(rect.getWidth()),
  328. static_cast<PuglSpan>(rect.getHeight()),
  329. };
  330. if (pData->autoScaling)
  331. {
  332. const double autoScaleFactor = pData->autoScaleFactor;
  333. prect.x *= autoScaleFactor;
  334. prect.y *= autoScaleFactor;
  335. prect.width *= autoScaleFactor;
  336. prect.height *= autoScaleFactor;
  337. }
  338. puglPostRedisplayRect(pData->view, prect);
  339. }
  340. void Window::renderToPicture(const char* const filename)
  341. {
  342. pData->filenameToRenderInto = strdup(filename);
  343. }
  344. void Window::runAsModal(bool blockWait)
  345. {
  346. pData->runAsModal(blockWait);
  347. }
  348. Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio)
  349. {
  350. keepAspectRatio = pData->keepAspectRatio;
  351. return Size<uint>(pData->minWidth, pData->minHeight);
  352. }
  353. void Window::setGeometryConstraints(uint minimumWidth,
  354. uint minimumHeight,
  355. const bool keepAspectRatio,
  356. const bool automaticallyScale,
  357. const bool resizeNowIfAutoScaling)
  358. {
  359. DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,);
  360. DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,);
  361. pData->minWidth = minimumWidth;
  362. pData->minHeight = minimumHeight;
  363. pData->autoScaling = automaticallyScale;
  364. pData->keepAspectRatio = keepAspectRatio;
  365. if (pData->view == nullptr)
  366. return;
  367. const double scaleFactor = pData->scaleFactor;
  368. if (automaticallyScale && scaleFactor != 1.0)
  369. {
  370. minimumWidth *= scaleFactor;
  371. minimumHeight *= scaleFactor;
  372. }
  373. puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio);
  374. if (scaleFactor != 1.0 && automaticallyScale && resizeNowIfAutoScaling)
  375. {
  376. const Size<uint> size(getSize());
  377. setSize(static_cast<uint>(size.getWidth() * scaleFactor + 0.5),
  378. static_cast<uint>(size.getHeight() * scaleFactor + 0.5));
  379. }
  380. }
  381. std::vector<ClipboardDataOffer> Window::getClipboardDataOfferTypes()
  382. {
  383. std::vector<ClipboardDataOffer> offerTypes;
  384. if (const uint32_t numTypes = puglGetNumClipboardTypes(pData->view))
  385. {
  386. offerTypes.reserve(numTypes);
  387. for (uint32_t i=0; i<numTypes; ++i)
  388. {
  389. const ClipboardDataOffer offer = { i + 1, puglGetClipboardType(pData->view, i) };
  390. offerTypes.push_back(offer);
  391. }
  392. }
  393. return offerTypes;
  394. }
  395. uint32_t Window::onClipboardDataOffer()
  396. {
  397. return 0;
  398. }
  399. bool Window::onClose()
  400. {
  401. return true;
  402. }
  403. void Window::onFocus(bool, CrossingMode)
  404. {
  405. }
  406. void Window::onReshape(uint, uint)
  407. {
  408. puglFallbackOnResize(pData->view);
  409. }
  410. void Window::onScaleFactorChanged(double)
  411. {
  412. }
  413. #ifndef DGL_FILE_BROWSER_DISABLED
  414. void Window::onFileSelected(const char*)
  415. {
  416. }
  417. #endif
  418. #if 0
  419. void Window::setTransientWinId(const uintptr_t winId)
  420. {
  421. puglSetTransientFor(pData->view, winId);
  422. }
  423. #endif
  424. // -----------------------------------------------------------------------
  425. END_NAMESPACE_DGL