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.

875 lines
19KB

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