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.

806 lines
17KB

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