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.

559 lines
14KB

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