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.

1400 lines
34KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2018 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 "../Base.hpp"
  19. #undef PUGL_HAVE_CAIRO
  20. #undef PUGL_HAVE_GL
  21. #define PUGL_HAVE_GL 1
  22. #include "pugl/pugl.h"
  23. #if defined(__GNUC__) && (__GNUC__ >= 7)
  24. # pragma GCC diagnostic push
  25. # pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
  26. #endif
  27. #if defined(DISTRHO_OS_WINDOWS)
  28. # include "pugl/pugl_win.cpp"
  29. #elif defined(DISTRHO_OS_MAC)
  30. # define PuglWindow DISTRHO_JOIN_MACRO(PuglWindow, DGL_NAMESPACE)
  31. # define PuglOpenGLView DISTRHO_JOIN_MACRO(PuglOpenGLView, DGL_NAMESPACE)
  32. # include "pugl/pugl_osx.m"
  33. #else
  34. # include <sys/types.h>
  35. # include <unistd.h>
  36. extern "C" {
  37. # include "pugl/pugl_x11.c"
  38. }
  39. #endif
  40. #if defined(__GNUC__) && (__GNUC__ >= 7)
  41. # pragma GCC diagnostic pop
  42. #endif
  43. #include "ApplicationPrivateData.hpp"
  44. #include "WidgetPrivateData.hpp"
  45. #include "../StandaloneWindow.hpp"
  46. #include "../../distrho/extra/String.hpp"
  47. #define FOR_EACH_WIDGET(it) \
  48. for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it)
  49. #define FOR_EACH_WIDGET_INV(rit) \
  50. for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit)
  51. #ifdef DEBUG
  52. # define DBG(msg) std::fprintf(stderr, "%s", msg);
  53. # define DBGp(...) std::fprintf(stderr, __VA_ARGS__);
  54. # define DBGF std::fflush(stderr);
  55. #else
  56. # define DBG(msg)
  57. # define DBGp(...)
  58. # define DBGF
  59. #endif
  60. START_NAMESPACE_DGL
  61. // -----------------------------------------------------------------------
  62. // Window Private
  63. struct Window::PrivateData {
  64. PrivateData(Application& app, Window* const self)
  65. : fApp(app),
  66. fSelf(self),
  67. fView(puglInit()),
  68. fFirstInit(true),
  69. fVisible(false),
  70. fResizable(true),
  71. fUsingEmbed(false),
  72. fWidth(1),
  73. fHeight(1),
  74. fTitle(nullptr),
  75. fWidgets(),
  76. fModal(),
  77. #if defined(DISTRHO_OS_WINDOWS)
  78. hwnd(nullptr),
  79. hwndParent(nullptr)
  80. #elif defined(DISTRHO_OS_MAC)
  81. fNeedsIdle(true),
  82. mView(nullptr),
  83. mWindow(nullptr),
  84. mParentWindow(nullptr)
  85. #else
  86. xDisplay(nullptr),
  87. xWindow(0)
  88. #endif
  89. {
  90. DBG("Creating window without parent..."); DBGF;
  91. init();
  92. }
  93. PrivateData(Application& app, Window* const self, Window& parent)
  94. : fApp(app),
  95. fSelf(self),
  96. fView(puglInit()),
  97. fFirstInit(true),
  98. fVisible(false),
  99. fResizable(true),
  100. fUsingEmbed(false),
  101. fWidth(1),
  102. fHeight(1),
  103. fTitle(nullptr),
  104. fWidgets(),
  105. fModal(parent.pData),
  106. #if defined(DISTRHO_OS_WINDOWS)
  107. hwnd(nullptr),
  108. hwndParent(nullptr)
  109. #elif defined(DISTRHO_OS_MAC)
  110. fNeedsIdle(false),
  111. mView(nullptr),
  112. mWindow(nullptr),
  113. mParentWindow(nullptr)
  114. #else
  115. xDisplay(nullptr),
  116. xWindow(0)
  117. #endif
  118. {
  119. DBG("Creating window with parent..."); DBGF;
  120. init();
  121. const PuglInternals* const parentImpl(parent.pData->fView->impl);
  122. // NOTE: almost a 1:1 copy of setTransientWinId()
  123. #if defined(DISTRHO_OS_WINDOWS)
  124. hwndParent = parentImpl->hwnd;
  125. SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)hwndParent);
  126. #elif defined(DISTRHO_OS_MAC)
  127. mParentWindow = parentImpl->window;
  128. #else
  129. XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
  130. #endif
  131. }
  132. PrivateData(Application& app, Window* const self, const intptr_t parentId)
  133. : fApp(app),
  134. fSelf(self),
  135. fView(puglInit()),
  136. fFirstInit(true),
  137. fVisible(parentId != 0),
  138. fResizable(parentId == 0),
  139. fUsingEmbed(parentId != 0),
  140. fWidth(1),
  141. fHeight(1),
  142. fTitle(nullptr),
  143. fWidgets(),
  144. fModal(),
  145. #if defined(DISTRHO_OS_WINDOWS)
  146. hwnd(nullptr),
  147. hwndParent(nullptr)
  148. #elif defined(DISTRHO_OS_MAC)
  149. fNeedsIdle(parentId == 0),
  150. mView(nullptr),
  151. mWindow(nullptr),
  152. mParentWindow(nullptr)
  153. #else
  154. xDisplay(nullptr),
  155. xWindow(0)
  156. #endif
  157. {
  158. if (fUsingEmbed)
  159. {
  160. DBG("Creating embedded window..."); DBGF;
  161. puglInitWindowParent(fView, parentId);
  162. }
  163. else
  164. {
  165. DBG("Creating window without parent..."); DBGF;
  166. }
  167. init();
  168. if (fUsingEmbed)
  169. {
  170. DBG("NOTE: Embed window is always visible and non-resizable\n");
  171. puglShowWindow(fView);
  172. fApp.pData->oneShown();
  173. fFirstInit = false;
  174. }
  175. }
  176. void init()
  177. {
  178. if (fSelf == nullptr || fView == nullptr)
  179. {
  180. DBG("Failed!\n");
  181. return;
  182. }
  183. puglInitContextType(fView, PUGL_GL);
  184. puglInitUserResizable(fView, fResizable);
  185. puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight));
  186. puglSetHandle(fView, this);
  187. puglSetDisplayFunc(fView, onDisplayCallback);
  188. puglSetKeyboardFunc(fView, onKeyboardCallback);
  189. puglSetMotionFunc(fView, onMotionCallback);
  190. puglSetMouseFunc(fView, onMouseCallback);
  191. puglSetScrollFunc(fView, onScrollCallback);
  192. puglSetSpecialFunc(fView, onSpecialCallback);
  193. puglSetReshapeFunc(fView, onReshapeCallback);
  194. puglSetCloseFunc(fView, onCloseCallback);
  195. #ifndef DGL_FILE_BROWSER_DISABLED
  196. puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback);
  197. #endif
  198. puglCreateWindow(fView, nullptr);
  199. PuglInternals* impl = fView->impl;
  200. #if defined(DISTRHO_OS_WINDOWS)
  201. hwnd = impl->hwnd;
  202. DISTRHO_SAFE_ASSERT(hwnd != 0);
  203. #elif defined(DISTRHO_OS_MAC)
  204. mView = impl->glview;
  205. mWindow = impl->window;
  206. DISTRHO_SAFE_ASSERT(mView != nullptr);
  207. if (fUsingEmbed) {
  208. DISTRHO_SAFE_ASSERT(mWindow == nullptr);
  209. } else {
  210. DISTRHO_SAFE_ASSERT(mWindow != nullptr);
  211. }
  212. #else
  213. xDisplay = impl->display;
  214. xWindow = impl->win;
  215. DISTRHO_SAFE_ASSERT(xWindow != 0);
  216. if (! fUsingEmbed)
  217. {
  218. pid_t pid = getpid();
  219. Atom _nwp = XInternAtom(xDisplay, "_NET_WM_PID", True);
  220. XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
  221. }
  222. #endif
  223. puglEnterContext(fView);
  224. fApp.pData->windows.push_back(fSelf);
  225. DBG("Success!\n");
  226. }
  227. ~PrivateData()
  228. {
  229. DBG("Destroying window..."); DBGF;
  230. if (fModal.enabled)
  231. {
  232. exec_fini();
  233. close();
  234. }
  235. fWidgets.clear();
  236. if (fUsingEmbed)
  237. {
  238. puglHideWindow(fView);
  239. fApp.pData->oneHidden();
  240. }
  241. if (fSelf != nullptr)
  242. {
  243. fApp.pData->windows.remove(fSelf);
  244. fSelf = nullptr;
  245. }
  246. if (fView != nullptr)
  247. {
  248. puglDestroy(fView);
  249. fView = nullptr;
  250. }
  251. if (fTitle != nullptr)
  252. {
  253. std::free(fTitle);
  254. fTitle = nullptr;
  255. }
  256. #if defined(DISTRHO_OS_WINDOWS)
  257. hwnd = 0;
  258. #elif defined(DISTRHO_OS_MAC)
  259. mView = nullptr;
  260. mWindow = nullptr;
  261. #else
  262. xDisplay = nullptr;
  263. xWindow = 0;
  264. #endif
  265. DBG("Success!\n");
  266. }
  267. // -------------------------------------------------------------------
  268. void close()
  269. {
  270. DBG("Window close\n");
  271. if (fUsingEmbed)
  272. return;
  273. setVisible(false);
  274. if (! fFirstInit)
  275. {
  276. fApp.pData->oneHidden();
  277. fFirstInit = true;
  278. }
  279. }
  280. void exec(const bool lockWait)
  281. {
  282. DBG("Window exec\n");
  283. exec_init();
  284. if (lockWait)
  285. {
  286. for (; fVisible && fModal.enabled;)
  287. {
  288. idle();
  289. d_msleep(10);
  290. }
  291. exec_fini();
  292. }
  293. else
  294. {
  295. idle();
  296. }
  297. }
  298. // -------------------------------------------------------------------
  299. void exec_init()
  300. {
  301. DBG("Window modal loop starting..."); DBGF;
  302. DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true));
  303. fModal.enabled = true;
  304. fModal.parent->fModal.childFocus = this;
  305. fModal.parent->setVisible(true);
  306. setVisible(true);
  307. DBG("Ok\n");
  308. }
  309. void exec_fini()
  310. {
  311. DBG("Window modal loop stopping..."); DBGF;
  312. fModal.enabled = false;
  313. if (fModal.parent != nullptr)
  314. {
  315. fModal.parent->fModal.childFocus = nullptr;
  316. // the mouse position probably changed since the modal appeared,
  317. // so send a mouse motion event to the modal's parent window
  318. #if defined(DISTRHO_OS_WINDOWS)
  319. // TODO
  320. #elif defined(DISTRHO_OS_MAC)
  321. // TODO
  322. #else
  323. int i, wx, wy;
  324. uint u;
  325. ::Window w;
  326. if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
  327. fModal.parent->onPuglMotion(wx, wy);
  328. #endif
  329. }
  330. DBG("Ok\n");
  331. }
  332. // -------------------------------------------------------------------
  333. void focus()
  334. {
  335. DBG("Window focus\n");
  336. #if defined(DISTRHO_OS_WINDOWS)
  337. SetForegroundWindow(hwnd);
  338. SetActiveWindow(hwnd);
  339. SetFocus(hwnd);
  340. #elif defined(DISTRHO_OS_MAC)
  341. if (mWindow != nullptr)
  342. [mWindow makeKeyWindow];
  343. [NSApp activateIgnoringOtherApps:YES];
  344. #else
  345. XRaiseWindow(xDisplay, xWindow);
  346. XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
  347. XFlush(xDisplay);
  348. #endif
  349. }
  350. // -------------------------------------------------------------------
  351. void setVisible(const bool yesNo)
  352. {
  353. if (fVisible == yesNo)
  354. {
  355. DBG("Window setVisible matches current state, ignoring request\n");
  356. return;
  357. }
  358. if (fUsingEmbed)
  359. {
  360. DBG("Window setVisible cannot be called when embedded\n");
  361. return;
  362. }
  363. DBG("Window setVisible called\n");
  364. fVisible = yesNo;
  365. if (yesNo && fFirstInit)
  366. setSize(fWidth, fHeight, true);
  367. #if defined(DISTRHO_OS_WINDOWS)
  368. if (yesNo)
  369. {
  370. if (fFirstInit)
  371. {
  372. RECT rectChild, rectParent;
  373. if (hwndParent != nullptr &&
  374. GetWindowRect(hwnd, &rectChild) &&
  375. GetWindowRect(hwndParent, &rectParent))
  376. {
  377. SetWindowPos(hwnd, hwndParent,
  378. rectParent.left + (rectChild.right-rectChild.left)/2,
  379. rectParent.top + (rectChild.bottom-rectChild.top)/2,
  380. 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
  381. }
  382. else
  383. {
  384. ShowWindow(hwnd, SW_SHOWNORMAL);
  385. }
  386. }
  387. else
  388. {
  389. ShowWindow(hwnd, SW_RESTORE);
  390. }
  391. }
  392. else
  393. {
  394. ShowWindow(hwnd, SW_HIDE);
  395. }
  396. UpdateWindow(hwnd);
  397. #elif defined(DISTRHO_OS_MAC)
  398. if (yesNo)
  399. {
  400. if (mWindow != nullptr)
  401. {
  402. if (mParentWindow != nullptr)
  403. [mParentWindow addChildWindow:mWindow
  404. ordered:NSWindowAbove];
  405. [mWindow setIsVisible:YES];
  406. }
  407. else
  408. {
  409. [mView setHidden:NO];
  410. }
  411. }
  412. else
  413. {
  414. if (mWindow != nullptr)
  415. {
  416. if (mParentWindow != nullptr)
  417. [mParentWindow removeChildWindow:mWindow];
  418. [mWindow setIsVisible:NO];
  419. }
  420. else
  421. {
  422. [mView setHidden:YES];
  423. }
  424. }
  425. #else
  426. if (yesNo)
  427. XMapRaised(xDisplay, xWindow);
  428. else
  429. XUnmapWindow(xDisplay, xWindow);
  430. XFlush(xDisplay);
  431. #endif
  432. if (yesNo)
  433. {
  434. if (fFirstInit)
  435. {
  436. fApp.pData->oneShown();
  437. fFirstInit = false;
  438. }
  439. }
  440. else if (fModal.enabled)
  441. exec_fini();
  442. }
  443. // -------------------------------------------------------------------
  444. void setResizable(const bool yesNo)
  445. {
  446. if (fResizable == yesNo)
  447. {
  448. DBG("Window setResizable matches current state, ignoring request\n");
  449. return;
  450. }
  451. if (fUsingEmbed)
  452. {
  453. DBG("Window setResizable cannot be called when embedded\n");
  454. return;
  455. }
  456. DBG("Window setResizable called\n");
  457. fResizable = yesNo;
  458. #if defined(DISTRHO_OS_WINDOWS)
  459. const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX
  460. : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX;
  461. SetWindowLong(hwnd, GWL_STYLE, winFlags);
  462. #elif defined(DISTRHO_OS_MAC)
  463. const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0);
  464. [mView setAutoresizingMask:flags];
  465. #endif
  466. setSize(fWidth, fHeight, true);
  467. }
  468. // -------------------------------------------------------------------
  469. void setSize(uint width, uint height, const bool forced = false)
  470. {
  471. if (width <= 1 || height <= 1)
  472. {
  473. DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height);
  474. return;
  475. }
  476. if (fWidth == width && fHeight == height && ! forced)
  477. {
  478. DBGp("Window setSize matches current size, ignoring request (%i %i)\n", width, height);
  479. return;
  480. }
  481. fWidth = width;
  482. fHeight = height;
  483. DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false");
  484. #if defined(DISTRHO_OS_WINDOWS)
  485. const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0);
  486. RECT wr = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
  487. AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST);
  488. SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
  489. SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
  490. if (! forced)
  491. UpdateWindow(hwnd);
  492. #elif defined(DISTRHO_OS_MAC)
  493. [mView setFrame:NSMakeRect(0, 0, width, height)];
  494. if (mWindow != nullptr)
  495. {
  496. const NSSize size = NSMakeSize(width, height);
  497. [mWindow setContentSize:size];
  498. if (fResizable)
  499. {
  500. [mWindow setContentMinSize:NSMakeSize(1, 1)];
  501. [mWindow setContentMaxSize:NSMakeSize(99999, 99999)];
  502. [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:NO];
  503. }
  504. else
  505. {
  506. [mWindow setContentMinSize:size];
  507. [mWindow setContentMaxSize:size];
  508. [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:YES];
  509. }
  510. }
  511. #else
  512. XResizeWindow(xDisplay, xWindow, width, height);
  513. if (! fResizable)
  514. {
  515. XSizeHints sizeHints;
  516. memset(&sizeHints, 0, sizeof(sizeHints));
  517. sizeHints.flags = PSize|PMinSize|PMaxSize;
  518. sizeHints.width = static_cast<int>(width);
  519. sizeHints.height = static_cast<int>(height);
  520. sizeHints.min_width = static_cast<int>(width);
  521. sizeHints.min_height = static_cast<int>(height);
  522. sizeHints.max_width = static_cast<int>(width);
  523. sizeHints.max_height = static_cast<int>(height);
  524. XSetNormalHints(xDisplay, xWindow, &sizeHints);
  525. }
  526. if (! forced)
  527. XFlush(xDisplay);
  528. #endif
  529. puglPostRedisplay(fView);
  530. }
  531. // -------------------------------------------------------------------
  532. const char* getTitle() const noexcept
  533. {
  534. static const char* const kFallback = "";
  535. return fTitle != nullptr ? fTitle : kFallback;
  536. }
  537. void setTitle(const char* const title)
  538. {
  539. DBGp("Window setTitle \"%s\"\n", title);
  540. if (fTitle != nullptr)
  541. std::free(fTitle);
  542. fTitle = strdup(title);
  543. #if defined(DISTRHO_OS_WINDOWS)
  544. SetWindowTextA(hwnd, title);
  545. #elif defined(DISTRHO_OS_MAC)
  546. if (mWindow != nullptr)
  547. {
  548. NSString* titleString = [[NSString alloc]
  549. initWithBytes:title
  550. length:strlen(title)
  551. encoding:NSUTF8StringEncoding];
  552. [mWindow setTitle:titleString];
  553. }
  554. #else
  555. XStoreName(xDisplay, xWindow, title);
  556. #endif
  557. }
  558. void setTransientWinId(const uintptr_t winId)
  559. {
  560. DISTRHO_SAFE_ASSERT_RETURN(winId != 0,);
  561. #if defined(DISTRHO_OS_WINDOWS)
  562. hwndParent = (HWND)winId;
  563. SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)winId);
  564. #elif defined(DISTRHO_OS_MAC)
  565. NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId];
  566. DISTRHO_SAFE_ASSERT_RETURN(parentWindow != nullptr,);
  567. [parentWindow addChildWindow:mWindow
  568. ordered:NSWindowAbove];
  569. #else
  570. XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId));
  571. #endif
  572. }
  573. // -------------------------------------------------------------------
  574. void addWidget(Widget* const widget)
  575. {
  576. fWidgets.push_back(widget);
  577. }
  578. void removeWidget(Widget* const widget)
  579. {
  580. fWidgets.remove(widget);
  581. }
  582. void idle()
  583. {
  584. puglProcessEvents(fView);
  585. #ifdef DISTRHO_OS_MAC
  586. if (fNeedsIdle)
  587. {
  588. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  589. NSEvent* event;
  590. for (;;)
  591. {
  592. event = [NSApp
  593. nextEventMatchingMask:NSAnyEventMask
  594. untilDate:[NSDate distantPast]
  595. inMode:NSDefaultRunLoopMode
  596. dequeue:YES];
  597. if (event == nil)
  598. break;
  599. [NSApp sendEvent: event];
  600. }
  601. [pool release];
  602. }
  603. #endif
  604. if (fModal.enabled && fModal.parent != nullptr)
  605. fModal.parent->idle();
  606. }
  607. // -------------------------------------------------------------------
  608. void onPuglDisplay()
  609. {
  610. fSelf->onDisplayBefore();
  611. FOR_EACH_WIDGET(it)
  612. {
  613. Widget* const widget(*it);
  614. widget->pData->display(fWidth, fHeight, false);
  615. }
  616. fSelf->onDisplayAfter();
  617. }
  618. int onPuglKeyboard(const bool press, const uint key)
  619. {
  620. DBGp("PUGL: onKeyboard : %i %i\n", press, key);
  621. if (fModal.childFocus != nullptr)
  622. {
  623. fModal.childFocus->focus();
  624. return 0;
  625. }
  626. Widget::KeyboardEvent ev;
  627. ev.press = press;
  628. ev.key = key;
  629. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  630. ev.time = puglGetEventTimestamp(fView);
  631. FOR_EACH_WIDGET_INV(rit)
  632. {
  633. Widget* const widget(*rit);
  634. if (widget->isVisible() && widget->onKeyboard(ev))
  635. return 0;
  636. }
  637. return 1;
  638. }
  639. int onPuglSpecial(const bool press, const Key key)
  640. {
  641. DBGp("PUGL: onSpecial : %i %i\n", press, key);
  642. if (fModal.childFocus != nullptr)
  643. {
  644. fModal.childFocus->focus();
  645. return 0;
  646. }
  647. Widget::SpecialEvent ev;
  648. ev.press = press;
  649. ev.key = key;
  650. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  651. ev.time = puglGetEventTimestamp(fView);
  652. FOR_EACH_WIDGET_INV(rit)
  653. {
  654. Widget* const widget(*rit);
  655. if (widget->isVisible() && widget->onSpecial(ev))
  656. return 0;
  657. }
  658. return 1;
  659. }
  660. void onPuglMouse(const int button, const bool press, const int x, const int y)
  661. {
  662. DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y);
  663. // FIXME - pugl sends 2 of these for each window on init, don't ask me why. we'll ignore it
  664. if (press && button == 0 && x == 0 && y == 0) return;
  665. if (fModal.childFocus != nullptr)
  666. return fModal.childFocus->focus();
  667. Widget::MouseEvent ev;
  668. ev.button = button;
  669. ev.press = press;
  670. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  671. ev.time = puglGetEventTimestamp(fView);
  672. FOR_EACH_WIDGET_INV(rit)
  673. {
  674. Widget* const widget(*rit);
  675. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  676. if (widget->isVisible() && widget->onMouse(ev))
  677. break;
  678. }
  679. }
  680. void onPuglMotion(const int x, const int y)
  681. {
  682. DBGp("PUGL: onMotion : %i %i\n", x, y);
  683. if (fModal.childFocus != nullptr)
  684. return;
  685. Widget::MotionEvent ev;
  686. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  687. ev.time = puglGetEventTimestamp(fView);
  688. FOR_EACH_WIDGET_INV(rit)
  689. {
  690. Widget* const widget(*rit);
  691. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  692. if (widget->isVisible() && widget->onMotion(ev))
  693. break;
  694. }
  695. }
  696. void onPuglScroll(const int x, const int y, const float dx, const float dy)
  697. {
  698. DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy);
  699. if (fModal.childFocus != nullptr)
  700. return;
  701. Widget::ScrollEvent ev;
  702. ev.delta = Point<float>(dx, dy);
  703. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  704. ev.time = puglGetEventTimestamp(fView);
  705. FOR_EACH_WIDGET_INV(rit)
  706. {
  707. Widget* const widget(*rit);
  708. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  709. if (widget->isVisible() && widget->onScroll(ev))
  710. break;
  711. }
  712. }
  713. void onPuglReshape(const int width, const int height)
  714. {
  715. DBGp("PUGL: onReshape : %i %i\n", width, height);
  716. if (width <= 1 && height <= 1)
  717. return;
  718. fWidth = static_cast<uint>(width);
  719. fHeight = static_cast<uint>(height);
  720. fSelf->onReshape(fWidth, fHeight);
  721. FOR_EACH_WIDGET(it)
  722. {
  723. Widget* const widget(*it);
  724. if (widget->pData->needsFullViewport)
  725. widget->setSize(fWidth, fHeight);
  726. }
  727. }
  728. void onPuglClose()
  729. {
  730. DBG("PUGL: onClose\n");
  731. if (fModal.enabled)
  732. exec_fini();
  733. fSelf->onClose();
  734. if (fModal.childFocus != nullptr)
  735. fModal.childFocus->fSelf->onClose();
  736. close();
  737. }
  738. // -------------------------------------------------------------------
  739. bool handlePluginKeyboard(const bool press, const uint key)
  740. {
  741. DBGp("PUGL: handlePluginKeyboard : %i %i\n", press, key);
  742. if (fModal.childFocus != nullptr)
  743. {
  744. fModal.childFocus->focus();
  745. return true;
  746. }
  747. Widget::KeyboardEvent ev;
  748. ev.press = press;
  749. ev.key = key;
  750. ev.mod = static_cast<Modifier>(fView->mods);
  751. ev.time = 0;
  752. if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z')
  753. ev.key -= 'a' - 'A'; // a-z -> A-Z
  754. FOR_EACH_WIDGET_INV(rit)
  755. {
  756. Widget* const widget(*rit);
  757. if (widget->isVisible() && widget->onKeyboard(ev))
  758. return true;
  759. }
  760. return false;
  761. }
  762. bool handlePluginSpecial(const bool press, const Key key)
  763. {
  764. DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key);
  765. if (fModal.childFocus != nullptr)
  766. {
  767. fModal.childFocus->focus();
  768. return true;
  769. }
  770. int mods = 0x0;
  771. switch (key)
  772. {
  773. case kKeyShift:
  774. mods |= kModifierShift;
  775. break;
  776. case kKeyControl:
  777. mods |= kModifierControl;
  778. break;
  779. case kKeyAlt:
  780. mods |= kModifierAlt;
  781. break;
  782. default:
  783. break;
  784. }
  785. if (mods != 0x0)
  786. {
  787. if (press)
  788. fView->mods |= mods;
  789. else
  790. fView->mods &= ~(mods);
  791. }
  792. Widget::SpecialEvent ev;
  793. ev.press = press;
  794. ev.key = key;
  795. ev.mod = static_cast<Modifier>(fView->mods);
  796. ev.time = 0;
  797. FOR_EACH_WIDGET_INV(rit)
  798. {
  799. Widget* const widget(*rit);
  800. if (widget->isVisible() && widget->onSpecial(ev))
  801. return true;
  802. }
  803. return false;
  804. }
  805. // -------------------------------------------------------------------
  806. Application& fApp;
  807. Window* fSelf;
  808. PuglView* fView;
  809. bool fFirstInit;
  810. bool fVisible;
  811. bool fResizable;
  812. bool fUsingEmbed;
  813. uint fWidth;
  814. uint fHeight;
  815. char* fTitle;
  816. std::list<Widget*> fWidgets;
  817. struct Modal {
  818. bool enabled;
  819. PrivateData* parent;
  820. PrivateData* childFocus;
  821. Modal()
  822. : enabled(false),
  823. parent(nullptr),
  824. childFocus(nullptr) {}
  825. Modal(PrivateData* const p)
  826. : enabled(false),
  827. parent(p),
  828. childFocus(nullptr) {}
  829. ~Modal()
  830. {
  831. DISTRHO_SAFE_ASSERT(! enabled);
  832. DISTRHO_SAFE_ASSERT(childFocus == nullptr);
  833. }
  834. DISTRHO_DECLARE_NON_COPY_STRUCT(Modal)
  835. } fModal;
  836. #if defined(DISTRHO_OS_WINDOWS)
  837. HWND hwnd;
  838. HWND hwndParent;
  839. #elif defined(DISTRHO_OS_MAC)
  840. bool fNeedsIdle;
  841. PuglOpenGLView* mView;
  842. id mWindow;
  843. id mParentWindow;
  844. #else
  845. Display* xDisplay;
  846. ::Window xWindow;
  847. #endif
  848. // -------------------------------------------------------------------
  849. // Callbacks
  850. #define handlePtr ((PrivateData*)puglGetHandle(view))
  851. static void onDisplayCallback(PuglView* view)
  852. {
  853. handlePtr->onPuglDisplay();
  854. }
  855. static int onKeyboardCallback(PuglView* view, bool press, uint32_t key)
  856. {
  857. return handlePtr->onPuglKeyboard(press, key);
  858. }
  859. static int onSpecialCallback(PuglView* view, bool press, PuglKey key)
  860. {
  861. return handlePtr->onPuglSpecial(press, static_cast<Key>(key));
  862. }
  863. static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
  864. {
  865. handlePtr->onPuglMouse(button, press, x, y);
  866. }
  867. static void onMotionCallback(PuglView* view, int x, int y)
  868. {
  869. handlePtr->onPuglMotion(x, y);
  870. }
  871. static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy)
  872. {
  873. handlePtr->onPuglScroll(x, y, dx, dy);
  874. }
  875. static void onReshapeCallback(PuglView* view, int width, int height)
  876. {
  877. handlePtr->onPuglReshape(width, height);
  878. }
  879. static void onCloseCallback(PuglView* view)
  880. {
  881. handlePtr->onPuglClose();
  882. }
  883. #ifndef DGL_FILE_BROWSER_DISABLED
  884. static void fileBrowserSelectedCallback(PuglView* view, const char* filename)
  885. {
  886. handlePtr->fSelf->fileBrowserSelected(filename);
  887. }
  888. #endif
  889. #undef handlePtr
  890. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  891. };
  892. // -----------------------------------------------------------------------
  893. // Window
  894. Window::Window(Application& app)
  895. : pData(new PrivateData(app, this)) {}
  896. Window::Window(Application& app, Window& parent)
  897. : pData(new PrivateData(app, this, parent)) {}
  898. Window::Window(Application& app, intptr_t parentId)
  899. : pData(new PrivateData(app, this, parentId)) {}
  900. Window::~Window()
  901. {
  902. delete pData;
  903. }
  904. void Window::show()
  905. {
  906. pData->setVisible(true);
  907. }
  908. void Window::hide()
  909. {
  910. pData->setVisible(false);
  911. }
  912. void Window::close()
  913. {
  914. pData->close();
  915. }
  916. void Window::exec(bool lockWait)
  917. {
  918. pData->exec(lockWait);
  919. }
  920. void Window::focus()
  921. {
  922. pData->focus();
  923. }
  924. void Window::repaint() noexcept
  925. {
  926. puglPostRedisplay(pData->fView);
  927. }
  928. // static int fib_filter_filename_filter(const char* const name)
  929. // {
  930. // return 1;
  931. // (void)name;
  932. // }
  933. #ifndef DGL_FILE_BROWSER_DISABLED
  934. bool Window::openFileBrowser(const FileBrowserOptions& options)
  935. {
  936. # ifdef SOFD_HAVE_X11
  937. using DISTRHO_NAMESPACE::String;
  938. // --------------------------------------------------------------------------
  939. // configure start dir
  940. // TODO: get abspath if needed
  941. // TODO: cross-platform
  942. String startDir(options.startDir);
  943. if (startDir.isEmpty())
  944. {
  945. if (char* const dir_name = get_current_dir_name())
  946. {
  947. startDir = dir_name;
  948. std::free(dir_name);
  949. }
  950. }
  951. DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false);
  952. if (! startDir.endsWith('/'))
  953. startDir += "/";
  954. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false);
  955. // --------------------------------------------------------------------------
  956. // configure title
  957. String title(options.title);
  958. if (title.isEmpty())
  959. {
  960. title = pData->getTitle();
  961. if (title.isEmpty())
  962. title = "FileBrowser";
  963. }
  964. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false);
  965. // --------------------------------------------------------------------------
  966. // configure filters
  967. x_fib_cfg_filter_callback(nullptr); //fib_filter_filename_filter);
  968. // --------------------------------------------------------------------------
  969. // configure buttons
  970. x_fib_cfg_buttons(3, options.buttons.listAllFiles-1);
  971. x_fib_cfg_buttons(1, options.buttons.showHidden-1);
  972. x_fib_cfg_buttons(2, options.buttons.showPlaces-1);
  973. // --------------------------------------------------------------------------
  974. // show
  975. return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0);
  976. # else
  977. // not implemented
  978. return false;
  979. # endif
  980. }
  981. #endif
  982. bool Window::isVisible() const noexcept
  983. {
  984. return pData->fVisible;
  985. }
  986. void Window::setVisible(bool yesNo)
  987. {
  988. pData->setVisible(yesNo);
  989. }
  990. bool Window::isResizable() const noexcept
  991. {
  992. return pData->fResizable;
  993. }
  994. void Window::setResizable(bool yesNo)
  995. {
  996. pData->setResizable(yesNo);
  997. }
  998. uint Window::getWidth() const noexcept
  999. {
  1000. return pData->fWidth;
  1001. }
  1002. uint Window::getHeight() const noexcept
  1003. {
  1004. return pData->fHeight;
  1005. }
  1006. Size<uint> Window::getSize() const noexcept
  1007. {
  1008. return Size<uint>(pData->fWidth, pData->fHeight);
  1009. }
  1010. void Window::setSize(uint width, uint height)
  1011. {
  1012. pData->setSize(width, height);
  1013. }
  1014. void Window::setSize(Size<uint> size)
  1015. {
  1016. pData->setSize(size.getWidth(), size.getHeight());
  1017. }
  1018. const char* Window::getTitle() const noexcept
  1019. {
  1020. return pData->getTitle();
  1021. }
  1022. void Window::setTitle(const char* title)
  1023. {
  1024. pData->setTitle(title);
  1025. }
  1026. void Window::setTransientWinId(uintptr_t winId)
  1027. {
  1028. pData->setTransientWinId(winId);
  1029. }
  1030. Application& Window::getApp() const noexcept
  1031. {
  1032. return pData->fApp;
  1033. }
  1034. intptr_t Window::getWindowId() const noexcept
  1035. {
  1036. return puglGetNativeWindow(pData->fView);
  1037. }
  1038. void Window::_addWidget(Widget* const widget)
  1039. {
  1040. pData->addWidget(widget);
  1041. }
  1042. void Window::_removeWidget(Widget* const widget)
  1043. {
  1044. pData->removeWidget(widget);
  1045. }
  1046. void Window::_idle()
  1047. {
  1048. pData->idle();
  1049. }
  1050. // -----------------------------------------------------------------------
  1051. void Window::addIdleCallback(IdleCallback* const callback)
  1052. {
  1053. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  1054. pData->fApp.pData->idleCallbacks.push_back(callback);
  1055. }
  1056. void Window::removeIdleCallback(IdleCallback* const callback)
  1057. {
  1058. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  1059. pData->fApp.pData->idleCallbacks.remove(callback);
  1060. }
  1061. // -----------------------------------------------------------------------
  1062. void Window::onDisplayBefore()
  1063. {
  1064. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1065. glLoadIdentity();
  1066. }
  1067. void Window::onDisplayAfter()
  1068. {
  1069. }
  1070. void Window::onReshape(uint width, uint height)
  1071. {
  1072. glEnable(GL_BLEND);
  1073. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1074. glMatrixMode(GL_PROJECTION);
  1075. glLoadIdentity();
  1076. glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0);
  1077. glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
  1078. glMatrixMode(GL_MODELVIEW);
  1079. glLoadIdentity();
  1080. }
  1081. void Window::onClose()
  1082. {
  1083. }
  1084. #ifndef DGL_FILE_BROWSER_DISABLED
  1085. void Window::fileBrowserSelected(const char*)
  1086. {
  1087. }
  1088. #endif
  1089. bool Window::handlePluginKeyboard(const bool press, const uint key)
  1090. {
  1091. return pData->handlePluginKeyboard(press, key);
  1092. }
  1093. bool Window::handlePluginSpecial(const bool press, const Key key)
  1094. {
  1095. return pData->handlePluginSpecial(press, key);
  1096. }
  1097. // -----------------------------------------------------------------------
  1098. StandaloneWindow::StandaloneWindow()
  1099. : Application(),
  1100. Window((Application&)*this),
  1101. fWidget(nullptr) {}
  1102. void StandaloneWindow::exec()
  1103. {
  1104. Window::show();
  1105. Application::exec();
  1106. }
  1107. void StandaloneWindow::onReshape(uint width, uint height)
  1108. {
  1109. if (fWidget != nullptr)
  1110. fWidget->setSize(width, height);
  1111. Window::onReshape(width, height);
  1112. }
  1113. void StandaloneWindow::_addWidget(Widget* widget)
  1114. {
  1115. if (fWidget == nullptr)
  1116. {
  1117. fWidget = widget;
  1118. fWidget->pData->needsFullViewport = true;
  1119. }
  1120. Window::_addWidget(widget);
  1121. }
  1122. void StandaloneWindow::_removeWidget(Widget* widget)
  1123. {
  1124. if (fWidget == widget)
  1125. {
  1126. fWidget->pData->needsFullViewport = false;
  1127. fWidget = nullptr;
  1128. }
  1129. Window::_removeWidget(widget);
  1130. }
  1131. // -----------------------------------------------------------------------
  1132. END_NAMESPACE_DGL
  1133. #undef DBG
  1134. #undef DBGF