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.

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