Collection of DPF-based plugins for packaging
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.

1251 lines
31KB

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