Audio plugin host https://kx.studio/carla
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.

907 lines
20KB

  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 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 "../App.hpp"
  17. #include "../Widget.hpp"
  18. #include "../Window.hpp"
  19. #include <cassert>
  20. #include <cstdio>
  21. #include <list>
  22. #include "pugl/pugl.h"
  23. #if defined(DGL_OS_WINDOWS)
  24. # include "pugl/pugl_win.cpp"
  25. #elif defined(DGL_OS_MAC)
  26. # include "pugl/pugl_osx_extended.h"
  27. extern "C" {
  28. struct PuglViewImpl {
  29. int width;
  30. int height;
  31. };}
  32. #elif defined(DGL_OS_LINUX)
  33. extern "C" {
  34. # include "pugl/pugl_x11.c"
  35. }
  36. #else
  37. # error Unsupported platform
  38. #endif
  39. #define FOR_EACH_WIDGET(it) \
  40. for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it)
  41. #define FOR_EACH_WIDGET_INV(rit) \
  42. for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit)
  43. #ifdef DEBUG
  44. # define DBG(msg) std::fprintf(stderr, "%s", msg);
  45. # define DBGp(...) std::fprintf(stderr, __VA_ARGS__);
  46. # define DBGF std::fflush(stderr);
  47. #else
  48. # define DBG(msg)
  49. # define DBGp(...)
  50. # define DBGF
  51. #endif
  52. START_NAMESPACE_DGL
  53. Window* dgl_lastUiParent = nullptr;
  54. // -----------------------------------------------------------------------
  55. // Window Private
  56. class Window::PrivateData
  57. {
  58. public:
  59. PrivateData(App& app, Window* const self)
  60. : fApp(app),
  61. fSelf(self),
  62. fView(puglCreate(0, "Window", 100, 100, true, false)),
  63. fFirstInit(true),
  64. fVisible(false),
  65. fResizable(true),
  66. fUsingEmbed(false),
  67. #if defined(DGL_OS_WINDOWS)
  68. hwnd(0)
  69. #elif defined(DGL_OS_LINUX)
  70. xDisplay(nullptr),
  71. xWindow(0)
  72. #else
  73. _dummy('\0')
  74. #endif
  75. {
  76. DBG("Creating window without parent..."); DBGF;
  77. init();
  78. }
  79. PrivateData(App& app, Window* const self, Window& parent)
  80. : fApp(app),
  81. fSelf(self),
  82. fView(puglCreate(0, "Window", 100, 100, true, false)),
  83. fFirstInit(true),
  84. fVisible(false),
  85. fResizable(true),
  86. fUsingEmbed(false),
  87. fModal(parent.pData),
  88. #if defined(DGL_OS_WINDOWS)
  89. hwnd(0)
  90. #elif defined(DGL_OS_LINUX)
  91. xDisplay(nullptr),
  92. xWindow(0)
  93. #else
  94. _dummy('\0')
  95. #endif
  96. {
  97. DBG("Creating window with parent..."); DBGF;
  98. init();
  99. #ifdef DGL_OS_LINUX
  100. const PuglInternals* const parentImpl(parent.pData->fView->impl);
  101. XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
  102. #endif
  103. }
  104. PrivateData(App& app, Window* const self, const intptr_t parentId)
  105. : fApp(app),
  106. fSelf(self),
  107. fView(puglCreate(parentId, "Window", 100, 100, (parentId == 0), (parentId != 0))),
  108. fFirstInit(true),
  109. fVisible(parentId != 0),
  110. fResizable(parentId == 0),
  111. fUsingEmbed(parentId != 0),
  112. #if defined(DGL_OS_WINDOWS)
  113. hwnd(0)
  114. #elif defined(DGL_OS_LINUX)
  115. xDisplay(nullptr),
  116. xWindow(0)
  117. #else
  118. _dummy('\0')
  119. #endif
  120. {
  121. if (parentId != 0) {
  122. DBG("Creating embedded window..."); DBGF;
  123. } else {
  124. DBG("Creating window without parent..."); DBGF;
  125. }
  126. init();
  127. if (parentId != 0)
  128. {
  129. DBG("NOTE: Embed window is always visible and non-resizable\n");
  130. fApp._oneShown();
  131. fFirstInit = false;
  132. }
  133. }
  134. void init()
  135. {
  136. if (fSelf == nullptr || fView == nullptr)
  137. {
  138. DBG("Failed!\n");
  139. dgl_lastUiParent = nullptr;
  140. return;
  141. }
  142. dgl_lastUiParent = fSelf;
  143. puglSetHandle(fView, this);
  144. puglSetDisplayFunc(fView, onDisplayCallback);
  145. puglSetKeyboardFunc(fView, onKeyboardCallback);
  146. puglSetMotionFunc(fView, onMotionCallback);
  147. puglSetMouseFunc(fView, onMouseCallback);
  148. puglSetScrollFunc(fView, onScrollCallback);
  149. puglSetSpecialFunc(fView, onSpecialCallback);
  150. puglSetReshapeFunc(fView, onReshapeCallback);
  151. puglSetCloseFunc(fView, onCloseCallback);
  152. #if defined(DGL_OS_WINDOWS)
  153. PuglInternals* impl = fView->impl;
  154. hwnd = impl->hwnd;
  155. assert(hwnd != 0);
  156. #elif defined(DGL_OS_LINUX)
  157. PuglInternals* impl = fView->impl;
  158. xDisplay = impl->display;
  159. xWindow = impl->win;
  160. assert(xWindow != 0);
  161. #endif
  162. DBG("Success!\n");
  163. // process any initial events
  164. puglProcessEvents(fView);
  165. fApp._addWindow(fSelf);
  166. }
  167. ~PrivateData()
  168. {
  169. DBG("Destroying window..."); DBGF;
  170. //fOnModal = false;
  171. fWidgets.clear();
  172. if (fSelf != nullptr)
  173. {
  174. fApp._removeWindow(fSelf);
  175. fSelf = nullptr;
  176. }
  177. if (fView != nullptr)
  178. {
  179. puglDestroy(fView);
  180. fView = nullptr;
  181. }
  182. #if defined(DGL_OS_WINDOWS)
  183. hwnd = 0;
  184. #elif defined(DGL_OS_LINUX)
  185. xDisplay = nullptr;
  186. xWindow = 0;
  187. #endif
  188. DBG("Success!\n");
  189. }
  190. // -------------------------------------------------------------------
  191. void close()
  192. {
  193. DBG("Window close\n");
  194. setVisible(false);
  195. if (! fFirstInit)
  196. {
  197. fApp._oneHidden();
  198. fFirstInit = true;
  199. }
  200. }
  201. void exec(const bool lockWait)
  202. {
  203. DBG("Window exec\n");
  204. exec_init();
  205. if (lockWait)
  206. {
  207. for (; fVisible && fModal.enabled;)
  208. {
  209. // idle()
  210. puglProcessEvents(fView);
  211. if (fModal.parent != nullptr)
  212. fModal.parent->idle();
  213. msleep(10);
  214. }
  215. exec_fini();
  216. }
  217. else
  218. {
  219. idle();
  220. }
  221. }
  222. // -------------------------------------------------------------------
  223. void focus()
  224. {
  225. DBG("Window focus\n");
  226. #if defined(DGL_OS_WINDOWS)
  227. SetForegroundWindow(hwnd);
  228. SetActiveWindow(hwnd);
  229. SetFocus(hwnd);
  230. #elif defined(DGL_OS_MAC)
  231. puglImplFocus(fView);
  232. #elif defined(DGL_OS_LINUX)
  233. XRaiseWindow(xDisplay, xWindow);
  234. XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
  235. XFlush(xDisplay);
  236. #endif
  237. }
  238. void repaint()
  239. {
  240. //DBG("Window repaint\n");
  241. puglPostRedisplay(fView);
  242. }
  243. // -------------------------------------------------------------------
  244. bool isVisible() const noexcept
  245. {
  246. return fVisible;
  247. }
  248. void setVisible(const bool yesNo)
  249. {
  250. if (fVisible == yesNo)
  251. {
  252. DBG("Window setVisible matches current state, ignoring request\n");
  253. return;
  254. }
  255. if (fUsingEmbed)
  256. {
  257. DBG("Window setVisible cannot be called when embedded\n");
  258. return;
  259. }
  260. DBG("Window setVisible called\n");
  261. fVisible = yesNo;
  262. if (yesNo && fFirstInit)
  263. setSize(static_cast<unsigned int>(fView->width), static_cast<unsigned int>(fView->height), true);
  264. #if defined(DGL_OS_WINDOWS)
  265. if (yesNo)
  266. ShowWindow(hwnd, fFirstInit ? SW_SHOWNORMAL : SW_RESTORE);
  267. else
  268. ShowWindow(hwnd, SW_HIDE);
  269. UpdateWindow(hwnd);
  270. #elif defined(DGL_OS_MAC)
  271. puglImplSetVisible(fView, yesNo);
  272. #elif defined(DGL_OS_LINUX)
  273. if (yesNo)
  274. XMapRaised(xDisplay, xWindow);
  275. else
  276. XUnmapWindow(xDisplay, xWindow);
  277. XFlush(xDisplay);
  278. #endif
  279. if (yesNo)
  280. {
  281. if (fFirstInit)
  282. {
  283. fApp._oneShown();
  284. fFirstInit = false;
  285. }
  286. }
  287. else if (fModal.enabled)
  288. exec_fini();
  289. }
  290. // -------------------------------------------------------------------
  291. bool isResizable() const noexcept
  292. {
  293. return fResizable;
  294. }
  295. void setResizable(const bool yesNo)
  296. {
  297. if (fResizable == yesNo)
  298. {
  299. DBG("Window setResizable matches current state, ignoring request\n");
  300. return;
  301. }
  302. if (fUsingEmbed)
  303. {
  304. DBG("Window setResizable cannot be called when embedded\n");
  305. return;
  306. }
  307. DBG("Window setResizable called\n");
  308. fResizable = yesNo;
  309. setSize(static_cast<unsigned int>(fView->width), static_cast<unsigned int>(fView->height), true);
  310. }
  311. // -------------------------------------------------------------------
  312. int getWidth() const noexcept
  313. {
  314. return fView->width;
  315. }
  316. int getHeight() const noexcept
  317. {
  318. return fView->height;
  319. }
  320. Size<int> getSize() const noexcept
  321. {
  322. return Size<int>(fView->width, fView->height);
  323. }
  324. void setSize(unsigned int width, unsigned int height, const bool forced = false)
  325. {
  326. if (width == 0 || height == 0)
  327. {
  328. DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height);
  329. return;
  330. }
  331. if (fView->width == static_cast<int>(width) && fView->height == static_cast<int>(height) && ! forced)
  332. {
  333. DBG("Window setSize matches current size, ignoring request\n");
  334. return;
  335. }
  336. fView->width = static_cast<int>(width);
  337. fView->height = static_cast<int>(height);
  338. DBGp("Window setSize called %s\n", forced ? "(forced)" : "(not forced)");
  339. #if defined(DGL_OS_WINDOWS)
  340. int winFlags = WS_POPUPWINDOW | WS_CAPTION;
  341. if (fResizable)
  342. winFlags |= WS_SIZEBOX;
  343. RECT wr = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
  344. AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
  345. SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
  346. if (! forced)
  347. UpdateWindow(hwnd);
  348. #elif defined(DGL_OS_MAC)
  349. puglImplSetSize(fView, width, height, forced);
  350. #elif defined(DGL_OS_LINUX)
  351. XResizeWindow(xDisplay, xWindow, width, height);
  352. if (! fResizable)
  353. {
  354. XSizeHints sizeHints;
  355. memset(&sizeHints, 0, sizeof(sizeHints));
  356. sizeHints.flags = PMinSize|PMaxSize;
  357. sizeHints.min_width = static_cast<int>(width);
  358. sizeHints.min_height = static_cast<int>(height);
  359. sizeHints.max_width = static_cast<int>(width);
  360. sizeHints.max_height = static_cast<int>(height);
  361. XSetNormalHints(xDisplay, xWindow, &sizeHints);
  362. }
  363. if (! forced)
  364. XFlush(xDisplay);
  365. #endif
  366. repaint();
  367. }
  368. // -------------------------------------------------------------------
  369. void setTitle(const char* const title)
  370. {
  371. DBGp("Window setTitle \"%s\"\n", title);
  372. #if defined(DGL_OS_WINDOWS)
  373. SetWindowTextA(hwnd, title);
  374. #elif defined(DGL_OS_MAC)
  375. puglImplSetTitle(fView, title);
  376. #elif defined(DGL_OS_LINUX)
  377. XStoreName(xDisplay, xWindow, title);
  378. #endif
  379. }
  380. App& getApp() const noexcept
  381. {
  382. return fApp;
  383. }
  384. int getModifiers() const
  385. {
  386. return puglGetModifiers(fView);
  387. }
  388. uint32_t getEventTimestamp() const
  389. {
  390. return puglGetEventTimestamp(fView);
  391. }
  392. intptr_t getWindowId() const
  393. {
  394. return puglGetNativeWindow(fView);
  395. }
  396. // -------------------------------------------------------------------
  397. void addWidget(Widget* const widget)
  398. {
  399. fWidgets.push_back(widget);
  400. }
  401. void removeWidget(Widget* const widget)
  402. {
  403. fWidgets.remove(widget);
  404. }
  405. void idle()
  406. {
  407. puglProcessEvents(fView);
  408. if (fModal.enabled && fModal.parent != nullptr)
  409. fModal.parent->idle();
  410. }
  411. // -------------------------------------------------------------------
  412. void exec_init()
  413. {
  414. DBG("Window modal loop starting..."); DBGF;
  415. assert(fModal.parent != nullptr);
  416. if (fModal.parent == nullptr)
  417. {
  418. DBG("Failed, there's no modal parent!\n");
  419. return setVisible(true);
  420. }
  421. fModal.enabled = true;
  422. fModal.parent->fModal.childFocus = this;
  423. #ifdef DGL_OS_WINDOWS
  424. // Center this window
  425. PuglInternals* const parentImpl = fModal.parent->fView->impl;
  426. RECT curRect;
  427. RECT parentRect;
  428. GetWindowRect(hwnd, &curRect);
  429. GetWindowRect(parentImpl->hwnd, &parentRect);
  430. int x = parentRect.left+(parentRect.right-curRect.right)/2;
  431. int y = parentRect.top +(parentRect.bottom-curRect.bottom)/2;
  432. SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
  433. UpdateWindow(hwnd);
  434. #endif
  435. fModal.parent->setVisible(true);
  436. setVisible(true);
  437. DBG("Ok\n");
  438. }
  439. void exec_fini()
  440. {
  441. DBG("Window modal loop stopping..."); DBGF;
  442. fModal.enabled = false;
  443. if (fModal.parent != nullptr)
  444. fModal.parent->fModal.childFocus = nullptr;
  445. DBG("Ok\n");
  446. }
  447. // -------------------------------------------------------------------
  448. protected:
  449. void onDisplay()
  450. {
  451. //DBG("PUGL: onDisplay\n");
  452. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  453. FOR_EACH_WIDGET(it)
  454. {
  455. Widget* const widget(*it);
  456. if (widget->isVisible())
  457. widget->onDisplay();
  458. }
  459. }
  460. void onKeyboard(const bool press, const uint32_t key)
  461. {
  462. DBGp("PUGL: onKeyboard : %i %i\n", press, key);
  463. if (fModal.childFocus != nullptr)
  464. return fModal.childFocus->focus();
  465. FOR_EACH_WIDGET_INV(rit)
  466. {
  467. Widget* const widget(*rit);
  468. if (widget->isVisible() && widget->onKeyboard(press, key))
  469. break;
  470. }
  471. }
  472. void onMouse(const int button, const bool press, const int x, const int y)
  473. {
  474. DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y);
  475. if (fModal.childFocus != nullptr)
  476. return fModal.childFocus->focus();
  477. FOR_EACH_WIDGET_INV(rit)
  478. {
  479. Widget* const widget(*rit);
  480. if (widget->isVisible() && widget->onMouse(button, press, x, y))
  481. break;
  482. }
  483. }
  484. void onMotion(const int x, const int y)
  485. {
  486. DBGp("PUGL: onMotion : %i %i\n", x, y);
  487. if (fModal.childFocus != nullptr)
  488. return;
  489. FOR_EACH_WIDGET_INV(rit)
  490. {
  491. Widget* const widget(*rit);
  492. if (widget->isVisible() && widget->onMotion(x, y))
  493. break;
  494. }
  495. }
  496. void onScroll(const int x, const int y, const float dx, const float dy)
  497. {
  498. DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy);
  499. if (fModal.childFocus != nullptr)
  500. return;
  501. FOR_EACH_WIDGET_INV(rit)
  502. {
  503. Widget* const widget(*rit);
  504. if (widget->isVisible() && widget->onScroll(x, y, dx, dy))
  505. break;
  506. }
  507. }
  508. void onSpecial(const bool press, const Key key)
  509. {
  510. DBGp("PUGL: onSpecial : %i %i\n", press, key);
  511. if (fModal.childFocus != nullptr)
  512. return;
  513. FOR_EACH_WIDGET_INV(rit)
  514. {
  515. Widget* const widget(*rit);
  516. if (widget->isVisible() && widget->onSpecial(press, key))
  517. break;
  518. }
  519. }
  520. void onReshape(const int width, const int height)
  521. {
  522. DBGp("PUGL: onReshape : %i %i\n", width, height);
  523. FOR_EACH_WIDGET(it)
  524. {
  525. Widget* const widget(*it);
  526. widget->onReshape(width, height);
  527. }
  528. }
  529. void onClose()
  530. {
  531. DBG("PUGL: onClose\n");
  532. if (fModal.enabled && fModal.parent != nullptr)
  533. exec_fini();
  534. if (fModal.childFocus != nullptr)
  535. fModal.childFocus->onClose();
  536. FOR_EACH_WIDGET(it)
  537. {
  538. Widget* const widget(*it);
  539. widget->onClose();
  540. }
  541. close();
  542. }
  543. // -------------------------------------------------------------------
  544. private:
  545. App& fApp;
  546. Window* fSelf;
  547. PuglView* fView;
  548. bool fFirstInit;
  549. bool fVisible;
  550. bool fResizable;
  551. bool fUsingEmbed;
  552. std::list<Widget*> fWidgets;
  553. struct Modal {
  554. bool enabled;
  555. PrivateData* parent;
  556. PrivateData* childFocus;
  557. Modal()
  558. : enabled(false),
  559. parent(nullptr),
  560. childFocus(nullptr) {}
  561. Modal(PrivateData* const p)
  562. : enabled(false),
  563. parent(p),
  564. childFocus(nullptr) {}
  565. ~Modal()
  566. {
  567. assert(! enabled);
  568. assert(childFocus == nullptr);
  569. }
  570. } fModal;
  571. #if defined(DGL_OS_WINDOWS)
  572. HWND hwnd;
  573. #elif defined(DGL_OS_LINUX)
  574. Display* xDisplay;
  575. ::Window xWindow;
  576. #else
  577. char _dummy;
  578. #endif
  579. // -------------------------------------------------------------------
  580. // Callbacks
  581. #define handlePtr ((PrivateData*)puglGetHandle(view))
  582. static void onDisplayCallback(PuglView* view)
  583. {
  584. handlePtr->onDisplay();
  585. }
  586. static void onKeyboardCallback(PuglView* view, bool press, uint32_t key)
  587. {
  588. handlePtr->onKeyboard(press, key);
  589. }
  590. static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
  591. {
  592. handlePtr->onMouse(button, press, x, y);
  593. }
  594. static void onMotionCallback(PuglView* view, int x, int y)
  595. {
  596. handlePtr->onMotion(x, y);
  597. }
  598. static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy)
  599. {
  600. handlePtr->onScroll(x, y, dx, dy);
  601. }
  602. static void onSpecialCallback(PuglView* view, bool press, PuglKey key)
  603. {
  604. handlePtr->onSpecial(press, static_cast<Key>(key));
  605. }
  606. static void onReshapeCallback(PuglView* view, int width, int height)
  607. {
  608. handlePtr->onReshape(width, height);
  609. }
  610. static void onCloseCallback(PuglView* view)
  611. {
  612. handlePtr->onClose();
  613. }
  614. #undef handlePtr
  615. };
  616. // -----------------------------------------------------------------------
  617. // Window
  618. Window::Window(App& app)
  619. : pData(new PrivateData(app, this))
  620. {
  621. }
  622. Window::Window(App& app, Window& parent)
  623. : pData(new PrivateData(app, this, parent))
  624. {
  625. }
  626. Window::Window(App& app, intptr_t parentId)
  627. : pData(new PrivateData(app, this, parentId))
  628. {
  629. }
  630. Window::~Window()
  631. {
  632. delete pData;
  633. }
  634. void Window::show()
  635. {
  636. pData->setVisible(true);
  637. }
  638. void Window::hide()
  639. {
  640. pData->setVisible(false);
  641. }
  642. void Window::close()
  643. {
  644. pData->close();
  645. }
  646. void Window::exec(bool lockWait)
  647. {
  648. pData->exec(lockWait);
  649. }
  650. void Window::focus()
  651. {
  652. pData->focus();
  653. }
  654. void Window::repaint()
  655. {
  656. pData->repaint();
  657. }
  658. bool Window::isVisible() const noexcept
  659. {
  660. return pData->isVisible();
  661. }
  662. void Window::setVisible(bool yesNo)
  663. {
  664. pData->setVisible(yesNo);
  665. }
  666. bool Window::isResizable() const noexcept
  667. {
  668. return pData->isResizable();
  669. }
  670. void Window::setResizable(bool yesNo)
  671. {
  672. pData->setResizable(yesNo);
  673. }
  674. int Window::getWidth() const noexcept
  675. {
  676. return pData->getWidth();
  677. }
  678. int Window::getHeight() const noexcept
  679. {
  680. return pData->getHeight();
  681. }
  682. Size<int> Window::getSize() const noexcept
  683. {
  684. return pData->getSize();
  685. }
  686. void Window::setSize(unsigned int width, unsigned int height)
  687. {
  688. pData->setSize(width, height);
  689. }
  690. void Window::setTitle(const char* title)
  691. {
  692. pData->setTitle(title);
  693. }
  694. App& Window::getApp() const noexcept
  695. {
  696. return pData->getApp();
  697. }
  698. int Window::getModifiers() const
  699. {
  700. return pData->getModifiers();
  701. }
  702. uint32_t Window::getEventTimestamp() const
  703. {
  704. return pData->getEventTimestamp();
  705. }
  706. intptr_t Window::getWindowId() const
  707. {
  708. return pData->getWindowId();
  709. }
  710. void Window::_addWidget(Widget* const widget)
  711. {
  712. pData->addWidget(widget);
  713. }
  714. void Window::_removeWidget(Widget* const widget)
  715. {
  716. pData->removeWidget(widget);
  717. }
  718. void Window::_idle()
  719. {
  720. pData->idle();
  721. }
  722. // -----------------------------------------------------------------------
  723. END_NAMESPACE_DGL
  724. #undef DBG
  725. #undef DBGF