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.

1110 lines
28KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2014 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. // we need this for now
  17. //#define PUGL_GRAB_FOCUS 1
  18. #include "AppPrivateData.hpp"
  19. #include "../Widget.hpp"
  20. #include "../Window.hpp"
  21. #include "pugl/pugl.h"
  22. #if defined(DISTRHO_OS_WINDOWS)
  23. # include "pugl/pugl_win.cpp"
  24. #elif defined(DISTRHO_OS_MAC)
  25. # include "pugl/pugl_osx.m"
  26. #elif defined(DISTRHO_OS_LINUX)
  27. # include <sys/types.h>
  28. # include <unistd.h>
  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. #ifdef DEBUG
  40. # define DBG(msg) std::fprintf(stderr, "%s", msg);
  41. # define DBGp(...) std::fprintf(stderr, __VA_ARGS__);
  42. # define DBGF std::fflush(stderr);
  43. #else
  44. # define DBG(msg)
  45. # define DBGp(...)
  46. # define DBGF
  47. #endif
  48. START_NAMESPACE_DGL
  49. // -----------------------------------------------------------------------
  50. // Window Private
  51. struct Window::PrivateData {
  52. PrivateData(App& app, Window* const self)
  53. : fApp(app),
  54. fSelf(self),
  55. fView(puglInit()),
  56. fFirstInit(true),
  57. fVisible(false),
  58. fResizable(true),
  59. fUsingEmbed(false),
  60. fWidth(1),
  61. fHeight(1),
  62. fWidgets(),
  63. fModal(),
  64. #if defined(DISTRHO_OS_WINDOWS)
  65. hwnd(0),
  66. #elif defined(DISTRHO_OS_LINUX)
  67. xDisplay(nullptr),
  68. xWindow(0),
  69. #elif defined(DISTRHO_OS_MAC)
  70. fNeedsIdle(true),
  71. mView(nullptr),
  72. mWindow(nullptr),
  73. #endif
  74. leakDetector_PrivateData()
  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(puglInit()),
  83. fFirstInit(true),
  84. fVisible(false),
  85. fResizable(true),
  86. fUsingEmbed(false),
  87. fWidth(1),
  88. fHeight(1),
  89. fWidgets(),
  90. fModal(parent.pData),
  91. #if defined(DISTRHO_OS_WINDOWS)
  92. hwnd(0),
  93. #elif defined(DISTRHO_OS_LINUX)
  94. xDisplay(nullptr),
  95. xWindow(0),
  96. #elif defined(DISTRHO_OS_MAC)
  97. fNeedsIdle(false),
  98. mView(nullptr),
  99. mWindow(nullptr),
  100. #endif
  101. leakDetector_PrivateData()
  102. {
  103. DBG("Creating window with parent..."); DBGF;
  104. init();
  105. const PuglInternals* const parentImpl(parent.pData->fView->impl);
  106. #if defined(DISTRHO_OS_LINUX)
  107. XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
  108. //#elif defined(DISTRHO_OS_MAC)
  109. // [parentImpl->window orderWindow:NSWindowBelow relativeTo:[[mView window] windowNumber]];
  110. #else
  111. // unused
  112. return; (void)parentImpl;
  113. #endif
  114. }
  115. PrivateData(App& app, Window* const self, const intptr_t parentId)
  116. : fApp(app),
  117. fSelf(self),
  118. fView(puglInit()),
  119. fFirstInit(true),
  120. fVisible(parentId != 0),
  121. fResizable(parentId == 0),
  122. fUsingEmbed(parentId != 0),
  123. fWidth(1),
  124. fHeight(1),
  125. fWidgets(),
  126. fModal(),
  127. #if defined(DISTRHO_OS_WINDOWS)
  128. hwnd(0),
  129. #elif defined(DISTRHO_OS_LINUX)
  130. xDisplay(nullptr),
  131. xWindow(0),
  132. #elif defined(DISTRHO_OS_MAC)
  133. fNeedsIdle(false),
  134. mView(nullptr),
  135. mWindow(nullptr),
  136. #endif
  137. leakDetector_PrivateData()
  138. {
  139. if (fUsingEmbed)
  140. {
  141. DBG("Creating embedded window..."); DBGF;
  142. puglInitWindowParent(fView, parentId);
  143. }
  144. else
  145. {
  146. DBG("Creating window without parent..."); DBGF;
  147. }
  148. init();
  149. if (fUsingEmbed)
  150. {
  151. DBG("NOTE: Embed window is always visible and non-resizable\n");
  152. puglShowWindow(fView);
  153. fApp.pData->oneShown();
  154. fFirstInit = false;
  155. }
  156. }
  157. void init()
  158. {
  159. if (fSelf == nullptr || fView == nullptr)
  160. {
  161. DBG("Failed!\n");
  162. return;
  163. }
  164. puglInitResizable(fView, fResizable);
  165. puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight));
  166. puglSetHandle(fView, this);
  167. puglSetDisplayFunc(fView, onDisplayCallback);
  168. puglSetKeyboardFunc(fView, onKeyboardCallback);
  169. puglSetMotionFunc(fView, onMotionCallback);
  170. puglSetMouseFunc(fView, onMouseCallback);
  171. puglSetScrollFunc(fView, onScrollCallback);
  172. puglSetSpecialFunc(fView, onSpecialCallback);
  173. puglSetReshapeFunc(fView, onReshapeCallback);
  174. puglSetCloseFunc(fView, onCloseCallback);
  175. puglCreateWindow(fView, nullptr);
  176. PuglInternals* impl = fView->impl;
  177. #if defined(DISTRHO_OS_WINDOWS)
  178. hwnd = impl->hwnd;
  179. DISTRHO_SAFE_ASSERT(hwnd != 0);
  180. #elif defined(DISTRHO_OS_MAC)
  181. mView = impl->glview;
  182. mWindow = impl->window;
  183. DISTRHO_SAFE_ASSERT(mView != nullptr);
  184. if (fUsingEmbed) {
  185. DISTRHO_SAFE_ASSERT(mWindow == nullptr);
  186. } else {
  187. DISTRHO_SAFE_ASSERT(mWindow != nullptr);
  188. }
  189. #elif defined(DISTRHO_OS_LINUX)
  190. xDisplay = impl->display;
  191. xWindow = impl->win;
  192. DISTRHO_SAFE_ASSERT(xWindow != 0);
  193. if (! fUsingEmbed)
  194. {
  195. pid_t pid = getpid();
  196. Atom _nwp = XInternAtom(xDisplay, "_NET_WM_PID", True);
  197. XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
  198. }
  199. #endif
  200. fApp.pData->windows.push_back(fSelf);
  201. DBG("Success!\n");
  202. }
  203. ~PrivateData()
  204. {
  205. DBG("Destroying window..."); DBGF;
  206. if (fModal.enabled)
  207. {
  208. exec_fini();
  209. close();
  210. }
  211. fWidgets.clear();
  212. if (fUsingEmbed)
  213. {
  214. puglHideWindow(fView);
  215. fApp.pData->oneHidden();
  216. }
  217. if (fSelf != nullptr)
  218. {
  219. fApp.pData->windows.remove(fSelf);
  220. fSelf = nullptr;
  221. }
  222. if (fView != nullptr)
  223. {
  224. puglDestroy(fView);
  225. fView = nullptr;
  226. }
  227. #if defined(DISTRHO_OS_WINDOWS)
  228. hwnd = 0;
  229. #elif defined(DISTRHO_OS_MAC)
  230. mView = nullptr;
  231. mWindow = nullptr;
  232. #elif defined(DISTRHO_OS_LINUX)
  233. xDisplay = nullptr;
  234. xWindow = 0;
  235. #endif
  236. DBG("Success!\n");
  237. }
  238. // -------------------------------------------------------------------
  239. void close()
  240. {
  241. DBG("Window close\n");
  242. if (fUsingEmbed)
  243. return;
  244. setVisible(false);
  245. if (! fFirstInit)
  246. {
  247. fApp.pData->oneHidden();
  248. fFirstInit = true;
  249. }
  250. }
  251. void exec(const bool lockWait)
  252. {
  253. DBG("Window exec\n");
  254. exec_init();
  255. if (lockWait)
  256. {
  257. for (; fVisible && fModal.enabled;)
  258. {
  259. idle();
  260. d_msleep(10);
  261. }
  262. exec_fini();
  263. }
  264. else
  265. {
  266. idle();
  267. }
  268. }
  269. // -------------------------------------------------------------------
  270. void exec_init()
  271. {
  272. DBG("Window modal loop starting..."); DBGF;
  273. DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true));
  274. fModal.enabled = true;
  275. fModal.parent->fModal.childFocus = this;
  276. #ifdef DISTRHO_OS_WINDOWS
  277. // Center this window
  278. PuglInternals* const parentImpl = fModal.parent->fView->impl;
  279. RECT curRect;
  280. RECT parentRect;
  281. GetWindowRect(hwnd, &curRect);
  282. GetWindowRect(parentImpl->hwnd, &parentRect);
  283. int x = parentRect.left+(parentRect.right-curRect.right)/2;
  284. int y = parentRect.top +(parentRect.bottom-curRect.bottom)/2;
  285. SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
  286. UpdateWindow(hwnd);
  287. #endif
  288. fModal.parent->setVisible(true);
  289. setVisible(true);
  290. DBG("Ok\n");
  291. }
  292. void exec_fini()
  293. {
  294. DBG("Window modal loop stopping..."); DBGF;
  295. fModal.enabled = false;
  296. if (fModal.parent != nullptr)
  297. fModal.parent->fModal.childFocus = nullptr;
  298. DBG("Ok\n");
  299. }
  300. // -------------------------------------------------------------------
  301. void focus()
  302. {
  303. DBG("Window focus\n");
  304. #if defined(DISTRHO_OS_WINDOWS)
  305. SetForegroundWindow(hwnd);
  306. SetActiveWindow(hwnd);
  307. SetFocus(hwnd);
  308. #elif defined(DISTRHO_OS_MAC)
  309. if (mWindow != nullptr)
  310. {
  311. // TODO
  312. //[NSApp activateIgnoringOtherApps:YES];
  313. //[mWindow makeKeyAndOrderFront:mWindow];
  314. }
  315. #elif defined(DISTRHO_OS_LINUX)
  316. XRaiseWindow(xDisplay, xWindow);
  317. XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
  318. XFlush(xDisplay);
  319. #endif
  320. }
  321. // -------------------------------------------------------------------
  322. void setVisible(const bool yesNo)
  323. {
  324. if (fVisible == yesNo)
  325. {
  326. DBG("Window setVisible matches current state, ignoring request\n");
  327. return;
  328. }
  329. if (fUsingEmbed)
  330. {
  331. DBG("Window setVisible cannot be called when embedded\n");
  332. return;
  333. }
  334. DBG("Window setVisible called\n");
  335. fVisible = yesNo;
  336. if (yesNo && fFirstInit)
  337. setSize(fWidth, fHeight, true);
  338. #if defined(DISTRHO_OS_WINDOWS)
  339. if (yesNo)
  340. ShowWindow(hwnd, fFirstInit ? SW_SHOWNORMAL : SW_RESTORE);
  341. else
  342. ShowWindow(hwnd, SW_HIDE);
  343. UpdateWindow(hwnd);
  344. #elif defined(DISTRHO_OS_MAC)
  345. if (yesNo)
  346. {
  347. if (mWindow != nullptr)
  348. [mWindow setIsVisible:YES];
  349. else
  350. [mView setHidden:NO];
  351. }
  352. else
  353. {
  354. if (mWindow != nullptr)
  355. [mWindow setIsVisible:NO];
  356. else
  357. [mView setHidden:YES];
  358. }
  359. #elif defined(DISTRHO_OS_LINUX)
  360. if (yesNo)
  361. XMapRaised(xDisplay, xWindow);
  362. else
  363. XUnmapWindow(xDisplay, xWindow);
  364. XFlush(xDisplay);
  365. #endif
  366. if (yesNo)
  367. {
  368. if (fFirstInit)
  369. {
  370. fApp.pData->oneShown();
  371. fFirstInit = false;
  372. }
  373. }
  374. else if (fModal.enabled)
  375. exec_fini();
  376. }
  377. // -------------------------------------------------------------------
  378. void setResizable(const bool yesNo)
  379. {
  380. if (fResizable == yesNo)
  381. {
  382. DBG("Window setResizable matches current state, ignoring request\n");
  383. return;
  384. }
  385. if (fUsingEmbed)
  386. {
  387. DBG("Window setResizable cannot be called when embedded\n");
  388. return;
  389. }
  390. DBG("Window setResizable called\n");
  391. fResizable = yesNo;
  392. #if defined(DISTRHO_OS_WINDOWS)
  393. const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX
  394. : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX;
  395. SetWindowLong(hwnd, GWL_STYLE, winFlags);
  396. #elif defined(DISTRHO_OS_MAC)
  397. // FIXME?
  398. const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0);
  399. [mView setAutoresizingMask:flags];
  400. #endif
  401. setSize(fWidth, fHeight, true);
  402. }
  403. // -------------------------------------------------------------------
  404. void setSize(uint width, uint height, const bool forced = false)
  405. {
  406. if (width <= 1 || height <= 1)
  407. {
  408. DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height);
  409. return;
  410. }
  411. if (fWidth == width && fHeight == height && ! forced)
  412. {
  413. DBGp("Window setSize matches current size, ignoring request (%i %i)\n", width, height);
  414. return;
  415. }
  416. fWidth = width;
  417. fHeight = height;
  418. DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false");
  419. #if defined(DISTRHO_OS_WINDOWS)
  420. const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0);
  421. RECT wr = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
  422. AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST);
  423. SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
  424. SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
  425. if (! forced)
  426. UpdateWindow(hwnd);
  427. #elif defined(DISTRHO_OS_MAC)
  428. [mView setFrame:NSMakeRect(0, 0, width, height)];
  429. if (mWindow != nullptr)
  430. {
  431. [mWindow setContentSize:NSMakeSize(width, height)];
  432. }
  433. #elif defined(DISTRHO_OS_LINUX)
  434. XResizeWindow(xDisplay, xWindow, width, height);
  435. if (! fResizable)
  436. {
  437. XSizeHints sizeHints;
  438. memset(&sizeHints, 0, sizeof(sizeHints));
  439. sizeHints.flags = PSize|PMinSize|PMaxSize;
  440. sizeHints.width = static_cast<int>(width);
  441. sizeHints.height = static_cast<int>(height);
  442. sizeHints.min_width = static_cast<int>(width);
  443. sizeHints.min_height = static_cast<int>(height);
  444. sizeHints.max_width = static_cast<int>(width);
  445. sizeHints.max_height = static_cast<int>(height);
  446. XSetNormalHints(xDisplay, xWindow, &sizeHints);
  447. }
  448. if (! forced)
  449. XFlush(xDisplay);
  450. #endif
  451. puglPostRedisplay(fView);
  452. }
  453. // -------------------------------------------------------------------
  454. void setTitle(const char* const title)
  455. {
  456. DBGp("Window setTitle \"%s\"\n", title);
  457. #if defined(DISTRHO_OS_WINDOWS)
  458. SetWindowTextA(hwnd, title);
  459. #elif defined(DISTRHO_OS_MAC)
  460. if (mWindow != nullptr)
  461. {
  462. NSString* titleString = [[NSString alloc]
  463. initWithBytes:title
  464. length:strlen(title)
  465. encoding:NSUTF8StringEncoding];
  466. [mWindow setTitle:titleString];
  467. }
  468. #elif defined(DISTRHO_OS_LINUX)
  469. XStoreName(xDisplay, xWindow, title);
  470. #endif
  471. }
  472. void setTransientWinId(const uintptr_t winId)
  473. {
  474. #if defined(DISTRHO_OS_LINUX)
  475. XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId));
  476. #else
  477. return;
  478. // unused
  479. (void)winId;
  480. #endif
  481. }
  482. // -------------------------------------------------------------------
  483. void addWidget(Widget* const widget)
  484. {
  485. fWidgets.push_back(widget);
  486. }
  487. void removeWidget(Widget* const widget)
  488. {
  489. fWidgets.remove(widget);
  490. }
  491. void idle()
  492. {
  493. puglProcessEvents(fView);
  494. #ifdef DISTRHO_OS_MAC
  495. if (fNeedsIdle)
  496. {
  497. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  498. NSEvent* event;
  499. for (;;)
  500. {
  501. event = [NSApp
  502. nextEventMatchingMask:NSAnyEventMask
  503. untilDate:[NSDate distantPast]
  504. inMode:NSDefaultRunLoopMode
  505. dequeue:YES];
  506. if (event == nil)
  507. break;
  508. [NSApp sendEvent: event];
  509. }
  510. [pool release];
  511. }
  512. #endif
  513. if (fModal.enabled && fModal.parent != nullptr)
  514. fModal.parent->idle();
  515. }
  516. // -------------------------------------------------------------------
  517. void onPuglDisplay()
  518. {
  519. fSelf->onDisplayBefore();
  520. bool needsDisableScissor = false;
  521. FOR_EACH_WIDGET(it)
  522. {
  523. Widget* const widget(*it);
  524. if (widget->isVisible())
  525. {
  526. // reset color
  527. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  528. if (widget->fNeedsFullViewport || (widget->fAbsolutePos.isZero() && widget->fSize == Size<uint>(fWidth, fHeight)))
  529. {
  530. // full viewport size
  531. glViewport(0,
  532. 0,
  533. static_cast<GLsizei>(fWidth),
  534. static_cast<GLsizei>(fHeight));
  535. }
  536. else if (! widget->fNeedsScaling)
  537. {
  538. // only set viewport pos
  539. glViewport(widget->getAbsoluteX(),
  540. /*fView->height - static_cast<int>(widget->getHeight())*/ - widget->getAbsoluteY(),
  541. static_cast<GLsizei>(fWidth),
  542. static_cast<GLsizei>(fHeight));
  543. // then cut the outer bounds
  544. glScissor(widget->getAbsoluteX(),
  545. fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(),
  546. static_cast<GLsizei>(widget->getWidth()),
  547. static_cast<GLsizei>(widget->getHeight()));
  548. glEnable(GL_SCISSOR_TEST);
  549. needsDisableScissor = true;
  550. }
  551. else
  552. {
  553. // limit viewport to widget bounds
  554. glViewport(widget->getAbsoluteX(),
  555. fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(),
  556. static_cast<GLsizei>(widget->getWidth()),
  557. static_cast<GLsizei>(widget->getHeight()));
  558. }
  559. // display widget
  560. widget->onDisplay();
  561. if (needsDisableScissor)
  562. {
  563. glDisable(GL_SCISSOR_TEST);
  564. needsDisableScissor = false;
  565. }
  566. }
  567. }
  568. fSelf->onDisplayAfter();
  569. }
  570. void onPuglKeyboard(const bool press, const uint key)
  571. {
  572. DBGp("PUGL: onKeyboard : %i %i\n", press, key);
  573. if (fModal.childFocus != nullptr)
  574. return fModal.childFocus->focus();
  575. Widget::KeyboardEvent ev;
  576. ev.press = press;
  577. ev.key = key;
  578. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  579. ev.time = puglGetEventTimestamp(fView);
  580. FOR_EACH_WIDGET_INV(rit)
  581. {
  582. Widget* const widget(*rit);
  583. if (widget->isVisible() && widget->onKeyboard(ev))
  584. break;
  585. }
  586. }
  587. void onPuglSpecial(const bool press, const Key key)
  588. {
  589. DBGp("PUGL: onSpecial : %i %i\n", press, key);
  590. if (fModal.childFocus != nullptr)
  591. return fModal.childFocus->focus();
  592. Widget::SpecialEvent ev;
  593. ev.press = press;
  594. ev.key = key;
  595. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  596. ev.time = puglGetEventTimestamp(fView);
  597. FOR_EACH_WIDGET_INV(rit)
  598. {
  599. Widget* const widget(*rit);
  600. if (widget->isVisible() && widget->onSpecial(ev))
  601. break;
  602. }
  603. }
  604. void onPuglMouse(const int button, const bool press, const int x, const int y)
  605. {
  606. DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y);
  607. // FIXME - pugl sends 2 of these for each window on init, don't ask me why. we'll ignore it
  608. if (press && button == 0 && x == 0 && y == 0) return;
  609. if (fModal.childFocus != nullptr)
  610. return fModal.childFocus->focus();
  611. Widget::MouseEvent ev;
  612. ev.button = button;
  613. ev.press = press;
  614. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  615. ev.time = puglGetEventTimestamp(fView);
  616. FOR_EACH_WIDGET_INV(rit)
  617. {
  618. Widget* const widget(*rit);
  619. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  620. if (widget->isVisible() && widget->onMouse(ev))
  621. break;
  622. }
  623. }
  624. void onPuglMotion(const int x, const int y)
  625. {
  626. DBGp("PUGL: onMotion : %i %i\n", x, y);
  627. if (fModal.childFocus != nullptr)
  628. return;
  629. Widget::MotionEvent ev;
  630. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  631. ev.time = puglGetEventTimestamp(fView);
  632. FOR_EACH_WIDGET_INV(rit)
  633. {
  634. Widget* const widget(*rit);
  635. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  636. if (widget->isVisible() && widget->onMotion(ev))
  637. break;
  638. }
  639. }
  640. void onPuglScroll(const int x, const int y, const float dx, const float dy)
  641. {
  642. DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy);
  643. if (fModal.childFocus != nullptr)
  644. return;
  645. Widget::ScrollEvent ev;
  646. ev.delta = Point<float>(dx, dy);
  647. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  648. ev.time = puglGetEventTimestamp(fView);
  649. FOR_EACH_WIDGET_INV(rit)
  650. {
  651. Widget* const widget(*rit);
  652. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  653. if (widget->isVisible() && widget->onScroll(ev))
  654. break;
  655. }
  656. }
  657. void onPuglReshape(const int width, const int height)
  658. {
  659. DBGp("PUGL: onReshape : %i %i\n", width, height);
  660. if (width <= 1 && height <= 1)
  661. return;
  662. fWidth = static_cast<uint>(width);
  663. fHeight = static_cast<uint>(height);
  664. fSelf->onReshape(fWidth, fHeight);
  665. FOR_EACH_WIDGET(it)
  666. {
  667. Widget* const widget(*it);
  668. if (widget->fNeedsFullViewport)
  669. widget->setSize(fWidth, fHeight);
  670. }
  671. }
  672. void onPuglClose()
  673. {
  674. DBG("PUGL: onClose\n");
  675. if (fModal.enabled)
  676. exec_fini();
  677. fSelf->onClose();
  678. if (fModal.childFocus != nullptr)
  679. fModal.childFocus->fSelf->onClose();
  680. close();
  681. }
  682. // -------------------------------------------------------------------
  683. App& fApp;
  684. Window* fSelf;
  685. PuglView* fView;
  686. bool fFirstInit;
  687. bool fVisible;
  688. bool fResizable;
  689. bool fUsingEmbed;
  690. uint fWidth;
  691. uint fHeight;
  692. std::list<Widget*> fWidgets;
  693. struct Modal {
  694. bool enabled;
  695. PrivateData* parent;
  696. PrivateData* childFocus;
  697. Modal()
  698. : enabled(false),
  699. parent(nullptr),
  700. childFocus(nullptr) {}
  701. Modal(PrivateData* const p)
  702. : enabled(false),
  703. parent(p),
  704. childFocus(nullptr) {}
  705. ~Modal()
  706. {
  707. DISTRHO_SAFE_ASSERT(! enabled);
  708. DISTRHO_SAFE_ASSERT(childFocus == nullptr);
  709. }
  710. DISTRHO_DECLARE_NON_COPY_STRUCT(Modal)
  711. } fModal;
  712. #if defined(DISTRHO_OS_WINDOWS)
  713. HWND hwnd;
  714. #elif defined(DISTRHO_OS_LINUX)
  715. Display* xDisplay;
  716. ::Window xWindow;
  717. #elif defined(DISTRHO_OS_MAC)
  718. bool fNeedsIdle;
  719. PuglOpenGLView* mView;
  720. id mWindow;
  721. #endif
  722. // -------------------------------------------------------------------
  723. // Callbacks
  724. #define handlePtr ((PrivateData*)puglGetHandle(view))
  725. static void onDisplayCallback(PuglView* view)
  726. {
  727. handlePtr->onPuglDisplay();
  728. }
  729. static void onKeyboardCallback(PuglView* view, bool press, uint32_t key)
  730. {
  731. handlePtr->onPuglKeyboard(press, key);
  732. }
  733. static void onSpecialCallback(PuglView* view, bool press, PuglKey key)
  734. {
  735. handlePtr->onPuglSpecial(press, static_cast<Key>(key));
  736. }
  737. static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
  738. {
  739. handlePtr->onPuglMouse(button, press, x, y);
  740. }
  741. static void onMotionCallback(PuglView* view, int x, int y)
  742. {
  743. handlePtr->onPuglMotion(x, y);
  744. }
  745. static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy)
  746. {
  747. handlePtr->onPuglScroll(x, y, dx, dy);
  748. }
  749. static void onReshapeCallback(PuglView* view, int width, int height)
  750. {
  751. handlePtr->onPuglReshape(width, height);
  752. }
  753. static void onCloseCallback(PuglView* view)
  754. {
  755. handlePtr->onPuglClose();
  756. }
  757. #undef handlePtr
  758. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  759. };
  760. // -----------------------------------------------------------------------
  761. // Window
  762. Window::Window(App& app)
  763. : pData(new PrivateData(app, this)),
  764. leakDetector_Window() {}
  765. Window::Window(App& app, Window& parent)
  766. : pData(new PrivateData(app, this, parent)),
  767. leakDetector_Window() {}
  768. Window::Window(App& app, intptr_t parentId)
  769. : pData(new PrivateData(app, this, parentId)),
  770. leakDetector_Window() {}
  771. Window::~Window()
  772. {
  773. delete pData;
  774. }
  775. void Window::show()
  776. {
  777. pData->setVisible(true);
  778. }
  779. void Window::hide()
  780. {
  781. pData->setVisible(false);
  782. }
  783. void Window::close()
  784. {
  785. pData->close();
  786. }
  787. void Window::exec(bool lockWait)
  788. {
  789. pData->exec(lockWait);
  790. }
  791. void Window::focus()
  792. {
  793. pData->focus();
  794. }
  795. void Window::repaint() noexcept
  796. {
  797. puglPostRedisplay(pData->fView);
  798. }
  799. bool Window::isVisible() const noexcept
  800. {
  801. return pData->fVisible;
  802. }
  803. void Window::setVisible(bool yesNo)
  804. {
  805. pData->setVisible(yesNo);
  806. }
  807. bool Window::isResizable() const noexcept
  808. {
  809. return pData->fResizable;
  810. }
  811. void Window::setResizable(bool yesNo)
  812. {
  813. pData->setResizable(yesNo);
  814. }
  815. uint Window::getWidth() const noexcept
  816. {
  817. return pData->fWidth;
  818. }
  819. uint Window::getHeight() const noexcept
  820. {
  821. return pData->fHeight;
  822. }
  823. Size<uint> Window::getSize() const noexcept
  824. {
  825. return Size<uint>(pData->fWidth, pData->fHeight);
  826. }
  827. void Window::setSize(uint width, uint height)
  828. {
  829. pData->setSize(width, height);
  830. }
  831. void Window::setSize(Size<uint> size)
  832. {
  833. pData->setSize(size.getWidth(), size.getHeight());
  834. }
  835. void Window::setTitle(const char* title)
  836. {
  837. pData->setTitle(title);
  838. }
  839. void Window::setTransientWinId(uintptr_t winId)
  840. {
  841. pData->setTransientWinId(winId);
  842. }
  843. App& Window::getApp() const noexcept
  844. {
  845. return pData->fApp;
  846. }
  847. intptr_t Window::getWindowId() const noexcept
  848. {
  849. return puglGetNativeWindow(pData->fView);
  850. }
  851. void Window::_addWidget(Widget* const widget)
  852. {
  853. pData->addWidget(widget);
  854. }
  855. void Window::_removeWidget(Widget* const widget)
  856. {
  857. pData->removeWidget(widget);
  858. }
  859. void Window::_idle()
  860. {
  861. pData->idle();
  862. }
  863. // -----------------------------------------------------------------------
  864. void Window::addIdleCallback(IdleCallback* const callback)
  865. {
  866. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  867. pData->fApp.pData->idleCallbacks.push_back(callback);
  868. }
  869. void Window::removeIdleCallback(IdleCallback* const callback)
  870. {
  871. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  872. pData->fApp.pData->idleCallbacks.remove(callback);
  873. }
  874. // -----------------------------------------------------------------------
  875. void Window::onDisplayBefore()
  876. {
  877. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  878. glLoadIdentity();
  879. }
  880. void Window::onDisplayAfter()
  881. {
  882. }
  883. void Window::onReshape(uint width, uint height)
  884. {
  885. glEnable(GL_BLEND);
  886. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  887. glMatrixMode(GL_PROJECTION);
  888. glLoadIdentity();
  889. glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0);
  890. glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
  891. glMatrixMode(GL_MODELVIEW);
  892. glLoadIdentity();
  893. }
  894. void Window::onClose()
  895. {
  896. }
  897. // -----------------------------------------------------------------------
  898. END_NAMESPACE_DGL
  899. #undef DBG
  900. #undef DBGF