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.

1058 lines
26KB

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