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.

1726 lines
44KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
  4. * Copyright (C) 2019 Jean Pierre Cimalando <jp-dev@inbox.ru>
  5. * Copyright (C) 2019 Robin Gareus <robin@gareus.org>
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  8. * or without fee is hereby granted, provided that the above copyright notice and this
  9. * permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  12. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  13. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  14. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  15. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  16. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. // we need this for now
  19. //#define PUGL_GRAB_FOCUS 1
  20. #include "../Base.hpp"
  21. #ifdef DGL_CAIRO
  22. # define PUGL_CAIRO
  23. # include "../Cairo.hpp"
  24. #endif
  25. #ifdef DGL_OPENGL
  26. # define PUGL_OPENGL
  27. # include "../OpenGL.hpp"
  28. #endif
  29. #include "pugl/pugl.h"
  30. #if defined(__GNUC__) && (__GNUC__ >= 7)
  31. # pragma GCC diagnostic push
  32. # pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
  33. #endif
  34. #if defined(DISTRHO_OS_WINDOWS)
  35. # include "pugl/pugl_win.cpp"
  36. # undef max
  37. # undef min
  38. #elif defined(DISTRHO_OS_MAC)
  39. # define PuglWindow DISTRHO_JOIN_MACRO(PuglWindow, DGL_NAMESPACE)
  40. # define PuglOpenGLView DISTRHO_JOIN_MACRO(PuglOpenGLView, DGL_NAMESPACE)
  41. # include "pugl/pugl_osx.m"
  42. #else
  43. # include <sys/types.h>
  44. # include <unistd.h>
  45. extern "C" {
  46. # include "pugl/pugl_x11.c"
  47. }
  48. #endif
  49. #if defined(__GNUC__) && (__GNUC__ >= 7)
  50. # pragma GCC diagnostic pop
  51. #endif
  52. #include "ApplicationPrivateData.hpp"
  53. #include "WidgetPrivateData.hpp"
  54. #include "../StandaloneWindow.hpp"
  55. #include "../../distrho/extra/String.hpp"
  56. #define FOR_EACH_WIDGET(it) \
  57. for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it)
  58. #define FOR_EACH_WIDGET_INV(rit) \
  59. for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit)
  60. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  61. # define DBG(msg) std::fprintf(stderr, "%s", msg);
  62. # define DBGp(...) std::fprintf(stderr, __VA_ARGS__);
  63. # define DBGF std::fflush(stderr);
  64. #else
  65. # define DBG(msg)
  66. # define DBGp(...)
  67. # define DBGF
  68. #endif
  69. START_NAMESPACE_DGL
  70. // -----------------------------------------------------------------------
  71. // Window Private
  72. struct Window::PrivateData {
  73. PrivateData(Application& app, Window* const self)
  74. : fApp(app),
  75. fSelf(self),
  76. fView(puglInit()),
  77. fFirstInit(true),
  78. fVisible(false),
  79. fResizable(true),
  80. fUsingEmbed(false),
  81. fWidth(1),
  82. fHeight(1),
  83. fScaling(1.0),
  84. fAutoScaling(1.0),
  85. fTitle(nullptr),
  86. fWidgets(),
  87. fModal(),
  88. #if defined(DISTRHO_OS_WINDOWS)
  89. hwnd(nullptr),
  90. hwndParent(nullptr)
  91. #elif defined(DISTRHO_OS_MAC)
  92. fNeedsIdle(true),
  93. mView(nullptr),
  94. mWindow(nullptr),
  95. mParentWindow(nullptr)
  96. # ifndef DGL_FILE_BROWSER_DISABLED
  97. , fOpenFilePanel(nullptr),
  98. fFilePanelDelegate(nullptr)
  99. # endif
  100. #else
  101. xDisplay(nullptr),
  102. xWindow(0)
  103. #endif
  104. {
  105. DBG("Creating window without parent..."); DBGF;
  106. init();
  107. }
  108. PrivateData(Application& app, Window* const self, Window& parent)
  109. : fApp(app),
  110. fSelf(self),
  111. fView(puglInit()),
  112. fFirstInit(true),
  113. fVisible(false),
  114. fResizable(true),
  115. fUsingEmbed(false),
  116. fWidth(1),
  117. fHeight(1),
  118. fScaling(1.0),
  119. fAutoScaling(1.0),
  120. fTitle(nullptr),
  121. fWidgets(),
  122. fModal(parent.pData),
  123. #if defined(DISTRHO_OS_WINDOWS)
  124. hwnd(nullptr),
  125. hwndParent(nullptr)
  126. #elif defined(DISTRHO_OS_MAC)
  127. fNeedsIdle(false),
  128. mView(nullptr),
  129. mWindow(nullptr),
  130. mParentWindow(nullptr)
  131. # ifndef DGL_FILE_BROWSER_DISABLED
  132. , fOpenFilePanel(nullptr),
  133. fFilePanelDelegate(nullptr)
  134. # endif
  135. #else
  136. xDisplay(nullptr),
  137. xWindow(0)
  138. #endif
  139. {
  140. DBG("Creating window with parent..."); DBGF;
  141. init();
  142. const PuglInternals* const parentImpl(parent.pData->fView->impl);
  143. // NOTE: almost a 1:1 copy of setTransientWinId()
  144. #if defined(DISTRHO_OS_WINDOWS)
  145. hwndParent = parentImpl->hwnd;
  146. SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)hwndParent);
  147. #elif defined(DISTRHO_OS_MAC)
  148. mParentWindow = parentImpl->window;
  149. #else
  150. XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
  151. #endif
  152. }
  153. PrivateData(Application& app, Window* const self, const intptr_t parentId, const double scaling, const bool resizable)
  154. : fApp(app),
  155. fSelf(self),
  156. fView(puglInit()),
  157. fFirstInit(true),
  158. fVisible(parentId != 0),
  159. fResizable(resizable),
  160. fUsingEmbed(parentId != 0),
  161. fWidth(1),
  162. fHeight(1),
  163. fScaling(scaling),
  164. fAutoScaling(1.0),
  165. fTitle(nullptr),
  166. fWidgets(),
  167. fModal(),
  168. #if defined(DISTRHO_OS_WINDOWS)
  169. hwnd(nullptr),
  170. hwndParent(nullptr)
  171. #elif defined(DISTRHO_OS_MAC)
  172. fNeedsIdle(parentId == 0),
  173. mView(nullptr),
  174. mWindow(nullptr),
  175. mParentWindow(nullptr)
  176. # ifndef DGL_FILE_BROWSER_DISABLED
  177. , fOpenFilePanel(nullptr),
  178. fFilePanelDelegate(nullptr)
  179. # endif
  180. #else
  181. xDisplay(nullptr),
  182. xWindow(0)
  183. #endif
  184. {
  185. if (fUsingEmbed)
  186. {
  187. DBG("Creating embedded window..."); DBGF;
  188. puglInitWindowParent(fView, parentId);
  189. }
  190. else
  191. {
  192. DBG("Creating window without parent..."); DBGF;
  193. }
  194. init();
  195. if (fUsingEmbed)
  196. {
  197. DBG("NOTE: Embed window is always visible and non-resizable\n");
  198. puglShowWindow(fView);
  199. fApp.pData->oneShown();
  200. fFirstInit = false;
  201. }
  202. }
  203. void init()
  204. {
  205. if (fSelf == nullptr || fView == nullptr)
  206. {
  207. DBG("Failed!\n");
  208. return;
  209. }
  210. puglInitUserResizable(fView, fResizable);
  211. puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight));
  212. puglSetHandle(fView, this);
  213. puglSetDisplayFunc(fView, onDisplayCallback);
  214. puglSetKeyboardFunc(fView, onKeyboardCallback);
  215. puglSetMotionFunc(fView, onMotionCallback);
  216. puglSetMouseFunc(fView, onMouseCallback);
  217. puglSetScrollFunc(fView, onScrollCallback);
  218. puglSetSpecialFunc(fView, onSpecialCallback);
  219. puglSetReshapeFunc(fView, onReshapeCallback);
  220. puglSetCloseFunc(fView, onCloseCallback);
  221. #ifndef DGL_FILE_BROWSER_DISABLED
  222. puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback);
  223. #endif
  224. puglCreateWindow(fView, nullptr);
  225. PuglInternals* impl = fView->impl;
  226. #if defined(DISTRHO_OS_WINDOWS)
  227. hwnd = impl->hwnd;
  228. DISTRHO_SAFE_ASSERT(hwnd != 0);
  229. #elif defined(DISTRHO_OS_MAC)
  230. mView = impl->view;
  231. mWindow = impl->window;
  232. DISTRHO_SAFE_ASSERT(mView != nullptr);
  233. if (fUsingEmbed) {
  234. DISTRHO_SAFE_ASSERT(mWindow == nullptr);
  235. } else {
  236. DISTRHO_SAFE_ASSERT(mWindow != nullptr);
  237. }
  238. #else
  239. xDisplay = impl->display;
  240. xWindow = impl->win;
  241. DISTRHO_SAFE_ASSERT(xWindow != 0);
  242. if (! fUsingEmbed)
  243. {
  244. const pid_t pid = getpid();
  245. const Atom _nwp = XInternAtom(xDisplay, "_NET_WM_PID", False);
  246. XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
  247. const Atom _wt = XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE", False);
  248. // Setting the window to both dialog and normal will produce a decorated floating dialog
  249. // Order is important: DIALOG needs to come before NORMAL
  250. const Atom _wts[2] = {
  251. XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE_DIALOG", False),
  252. XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False)
  253. };
  254. XChangeProperty(xDisplay, xWindow, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2);
  255. }
  256. #endif
  257. puglEnterContext(fView);
  258. fApp.pData->windows.push_back(fSelf);
  259. DBG("Success!\n");
  260. }
  261. ~PrivateData()
  262. {
  263. DBG("Destroying window..."); DBGF;
  264. if (fModal.enabled)
  265. {
  266. exec_fini();
  267. close();
  268. }
  269. fWidgets.clear();
  270. if (fUsingEmbed)
  271. {
  272. puglHideWindow(fView);
  273. fApp.pData->oneHidden();
  274. }
  275. if (fSelf != nullptr)
  276. {
  277. fApp.pData->windows.remove(fSelf);
  278. fSelf = nullptr;
  279. }
  280. if (fView != nullptr)
  281. {
  282. puglDestroy(fView);
  283. fView = nullptr;
  284. }
  285. if (fTitle != nullptr)
  286. {
  287. std::free(fTitle);
  288. fTitle = nullptr;
  289. }
  290. #if defined(DISTRHO_OS_WINDOWS)
  291. hwnd = 0;
  292. #elif defined(DISTRHO_OS_MAC)
  293. mView = nullptr;
  294. mWindow = nullptr;
  295. #else
  296. xDisplay = nullptr;
  297. xWindow = 0;
  298. #endif
  299. #if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED)
  300. if (fOpenFilePanel)
  301. {
  302. [fOpenFilePanel release];
  303. fOpenFilePanel = nullptr;
  304. }
  305. if (fFilePanelDelegate)
  306. {
  307. [fFilePanelDelegate release];
  308. fFilePanelDelegate = nullptr;
  309. }
  310. #endif
  311. DBG("Success!\n");
  312. }
  313. // -------------------------------------------------------------------
  314. void close()
  315. {
  316. DBG("Window close\n");
  317. if (fUsingEmbed)
  318. return;
  319. setVisible(false);
  320. if (! fFirstInit)
  321. {
  322. fApp.pData->oneHidden();
  323. fFirstInit = true;
  324. }
  325. }
  326. void exec(const bool lockWait)
  327. {
  328. DBG("Window exec\n");
  329. exec_init();
  330. if (lockWait)
  331. {
  332. for (; fVisible && fModal.enabled;)
  333. {
  334. idle();
  335. d_msleep(10);
  336. }
  337. exec_fini();
  338. }
  339. else
  340. {
  341. idle();
  342. }
  343. }
  344. // -------------------------------------------------------------------
  345. void exec_init()
  346. {
  347. DBG("Window modal loop starting..."); DBGF;
  348. DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true));
  349. fModal.enabled = true;
  350. fModal.parent->fModal.childFocus = this;
  351. fModal.parent->setVisible(true);
  352. setVisible(true);
  353. DBG("Ok\n");
  354. }
  355. void exec_fini()
  356. {
  357. DBG("Window modal loop stopping..."); DBGF;
  358. fModal.enabled = false;
  359. if (fModal.parent != nullptr)
  360. {
  361. fModal.parent->fModal.childFocus = nullptr;
  362. // the mouse position probably changed since the modal appeared,
  363. // so send a mouse motion event to the modal's parent window
  364. #if defined(DISTRHO_OS_WINDOWS)
  365. // TODO
  366. #elif defined(DISTRHO_OS_MAC)
  367. // TODO
  368. #else
  369. int i, wx, wy;
  370. uint u;
  371. ::Window w;
  372. if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
  373. fModal.parent->onPuglMotion(wx, wy);
  374. #endif
  375. }
  376. DBG("Ok\n");
  377. }
  378. // -------------------------------------------------------------------
  379. void focus()
  380. {
  381. DBG("Window focus\n");
  382. #if defined(DISTRHO_OS_WINDOWS)
  383. SetForegroundWindow(hwnd);
  384. SetActiveWindow(hwnd);
  385. SetFocus(hwnd);
  386. #elif defined(DISTRHO_OS_MAC)
  387. if (mWindow != nullptr)
  388. [mWindow makeKeyWindow];
  389. #else
  390. XRaiseWindow(xDisplay, xWindow);
  391. XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
  392. XFlush(xDisplay);
  393. #endif
  394. }
  395. // -------------------------------------------------------------------
  396. void setVisible(const bool yesNo)
  397. {
  398. if (fVisible == yesNo)
  399. {
  400. DBG("Window setVisible matches current state, ignoring request\n");
  401. return;
  402. }
  403. if (fUsingEmbed)
  404. {
  405. DBG("Window setVisible cannot be called when embedded\n");
  406. return;
  407. }
  408. DBG("Window setVisible called\n");
  409. fVisible = yesNo;
  410. if (yesNo && fFirstInit)
  411. setSize(fWidth, fHeight, true);
  412. #if defined(DISTRHO_OS_WINDOWS)
  413. if (yesNo)
  414. {
  415. if (fFirstInit)
  416. {
  417. RECT rectChild, rectParent;
  418. if (hwndParent != nullptr &&
  419. GetWindowRect(hwnd, &rectChild) &&
  420. GetWindowRect(hwndParent, &rectParent))
  421. {
  422. SetWindowPos(hwnd, hwndParent,
  423. rectParent.left + (rectChild.right-rectChild.left)/2,
  424. rectParent.top + (rectChild.bottom-rectChild.top)/2,
  425. 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
  426. }
  427. else
  428. {
  429. ShowWindow(hwnd, SW_SHOWNORMAL);
  430. }
  431. }
  432. else
  433. {
  434. ShowWindow(hwnd, SW_RESTORE);
  435. }
  436. }
  437. else
  438. {
  439. ShowWindow(hwnd, SW_HIDE);
  440. }
  441. UpdateWindow(hwnd);
  442. #elif defined(DISTRHO_OS_MAC)
  443. if (yesNo)
  444. {
  445. if (mWindow != nullptr)
  446. {
  447. if (mParentWindow != nullptr)
  448. [mParentWindow addChildWindow:mWindow
  449. ordered:NSWindowAbove];
  450. [mWindow setIsVisible:YES];
  451. }
  452. else
  453. {
  454. [mView setHidden:NO];
  455. }
  456. }
  457. else
  458. {
  459. if (mWindow != nullptr)
  460. {
  461. if (mParentWindow != nullptr)
  462. [mParentWindow removeChildWindow:mWindow];
  463. [mWindow setIsVisible:NO];
  464. }
  465. else
  466. {
  467. [mView setHidden:YES];
  468. }
  469. }
  470. #else
  471. if (yesNo)
  472. XMapRaised(xDisplay, xWindow);
  473. else
  474. XUnmapWindow(xDisplay, xWindow);
  475. XFlush(xDisplay);
  476. #endif
  477. if (yesNo)
  478. {
  479. if (fFirstInit)
  480. {
  481. fApp.pData->oneShown();
  482. fFirstInit = false;
  483. }
  484. }
  485. else if (fModal.enabled)
  486. exec_fini();
  487. }
  488. // -------------------------------------------------------------------
  489. void setResizable(const bool yesNo)
  490. {
  491. if (fResizable == yesNo)
  492. {
  493. DBG("Window setResizable matches current state, ignoring request\n");
  494. return;
  495. }
  496. if (fUsingEmbed)
  497. {
  498. DBG("Window setResizable cannot be called when embedded\n");
  499. return;
  500. }
  501. DBG("Window setResizable called\n");
  502. fResizable = yesNo;
  503. fView->user_resizable = yesNo;
  504. #if defined(DISTRHO_OS_WINDOWS)
  505. const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX
  506. : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX;
  507. SetWindowLong(hwnd, GWL_STYLE, winFlags);
  508. #elif defined(DISTRHO_OS_MAC)
  509. const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0);
  510. [mView setAutoresizingMask:flags];
  511. #endif
  512. setSize(fWidth, fHeight, true);
  513. }
  514. // -------------------------------------------------------------------
  515. void setGeometryConstraints(uint width, uint height, bool aspect)
  516. {
  517. // Did you forget to set DISTRHO_UI_USER_RESIZABLE ?
  518. DISTRHO_SAFE_ASSERT_RETURN(fResizable,);
  519. fView->min_width = width;
  520. fView->min_height = height;
  521. puglUpdateGeometryConstraints(fView, width, height, aspect);
  522. }
  523. // -------------------------------------------------------------------
  524. void setSize(uint width, uint height, const bool forced = false)
  525. {
  526. if (width <= 1 || height <= 1)
  527. {
  528. DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height);
  529. return;
  530. }
  531. if (fWidth == width && fHeight == height && ! forced)
  532. {
  533. DBGp("Window setSize matches current size, ignoring request (%i %i)\n", width, height);
  534. return;
  535. }
  536. fWidth = width;
  537. fHeight = height;
  538. DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false");
  539. #if defined(DISTRHO_OS_WINDOWS)
  540. const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0);
  541. RECT wr = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
  542. AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST);
  543. SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
  544. SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
  545. if (! forced)
  546. UpdateWindow(hwnd);
  547. #elif defined(DISTRHO_OS_MAC)
  548. [mView setFrame:NSMakeRect(0, 0, width, height)];
  549. if (mWindow != nullptr)
  550. {
  551. const NSSize size = NSMakeSize(width, height);
  552. [mWindow setContentSize:size];
  553. if (fResizable)
  554. {
  555. [mWindow setContentMinSize:NSMakeSize(1, 1)];
  556. [mWindow setContentMaxSize:NSMakeSize(99999, 99999)];
  557. [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:NO];
  558. }
  559. else
  560. {
  561. [mWindow setContentMinSize:size];
  562. [mWindow setContentMaxSize:size];
  563. [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:YES];
  564. }
  565. }
  566. #else
  567. if (! fResizable)
  568. {
  569. XSizeHints sizeHints;
  570. memset(&sizeHints, 0, sizeof(sizeHints));
  571. sizeHints.flags = PSize|PMinSize|PMaxSize;
  572. sizeHints.width = static_cast<int>(width);
  573. sizeHints.height = static_cast<int>(height);
  574. sizeHints.min_width = static_cast<int>(width);
  575. sizeHints.min_height = static_cast<int>(height);
  576. sizeHints.max_width = static_cast<int>(width);
  577. sizeHints.max_height = static_cast<int>(height);
  578. XSetWMNormalHints(xDisplay, xWindow, &sizeHints);
  579. }
  580. XResizeWindow(xDisplay, xWindow, width, height);
  581. if (! forced)
  582. XFlush(xDisplay);
  583. #endif
  584. puglPostRedisplay(fView);
  585. }
  586. // -------------------------------------------------------------------
  587. const char* getTitle() const noexcept
  588. {
  589. static const char* const kFallback = "";
  590. return fTitle != nullptr ? fTitle : kFallback;
  591. }
  592. void setTitle(const char* const title)
  593. {
  594. DBGp("Window setTitle \"%s\"\n", title);
  595. if (fTitle != nullptr)
  596. std::free(fTitle);
  597. fTitle = strdup(title);
  598. #if defined(DISTRHO_OS_WINDOWS)
  599. SetWindowTextA(hwnd, title);
  600. #elif defined(DISTRHO_OS_MAC)
  601. if (mWindow != nullptr)
  602. {
  603. NSString* titleString = [[NSString alloc]
  604. initWithBytes:title
  605. length:strlen(title)
  606. encoding:NSUTF8StringEncoding];
  607. [mWindow setTitle:titleString];
  608. }
  609. #else
  610. XStoreName(xDisplay, xWindow, title);
  611. Atom netWmName = XInternAtom(xDisplay, "_NET_WM_NAME", False);
  612. Atom utf8String = XInternAtom(xDisplay, "UTF8_STRING", False);
  613. XChangeProperty(xDisplay, xWindow, netWmName, utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title));
  614. #endif
  615. }
  616. void setTransientWinId(const uintptr_t winId)
  617. {
  618. DISTRHO_SAFE_ASSERT_RETURN(winId != 0,);
  619. #if defined(DISTRHO_OS_WINDOWS)
  620. hwndParent = (HWND)winId;
  621. SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)winId);
  622. #elif defined(DISTRHO_OS_MAC)
  623. NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId];
  624. DISTRHO_SAFE_ASSERT_RETURN(parentWindow != nullptr,);
  625. [parentWindow addChildWindow:mWindow
  626. ordered:NSWindowAbove];
  627. #else
  628. XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId));
  629. #endif
  630. }
  631. // -------------------------------------------------------------------
  632. double getScaling() const noexcept
  633. {
  634. return fScaling;
  635. }
  636. void setAutoScaling(const double scaling) noexcept
  637. {
  638. DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,);
  639. fAutoScaling = scaling;
  640. }
  641. // -------------------------------------------------------------------
  642. bool getIgnoringKeyRepeat() const noexcept
  643. {
  644. return fView->ignoreKeyRepeat;
  645. }
  646. void setIgnoringKeyRepeat(bool ignore) noexcept
  647. {
  648. puglIgnoreKeyRepeat(fView, ignore);
  649. }
  650. // -------------------------------------------------------------------
  651. void addWidget(Widget* const widget)
  652. {
  653. fWidgets.push_back(widget);
  654. }
  655. void removeWidget(Widget* const widget)
  656. {
  657. fWidgets.remove(widget);
  658. }
  659. void idle()
  660. {
  661. puglProcessEvents(fView);
  662. #ifdef DISTRHO_OS_MAC
  663. if (fNeedsIdle)
  664. {
  665. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  666. NSEvent* event;
  667. for (;;)
  668. {
  669. event = [NSApp
  670. nextEventMatchingMask:NSAnyEventMask
  671. untilDate:[NSDate distantPast]
  672. inMode:NSDefaultRunLoopMode
  673. dequeue:YES];
  674. if (event == nil)
  675. break;
  676. [NSApp sendEvent: event];
  677. }
  678. [pool release];
  679. }
  680. #endif
  681. #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED)
  682. if (fSelectedFile.isNotEmpty())
  683. {
  684. char* const buffer = fSelectedFile.getAndReleaseBuffer();
  685. fView->fileSelectedFunc(fView, buffer);
  686. std::free(buffer);
  687. }
  688. #endif
  689. if (fModal.enabled && fModal.parent != nullptr)
  690. fModal.parent->idle();
  691. }
  692. // -------------------------------------------------------------------
  693. void onPuglDisplay()
  694. {
  695. fSelf->onDisplayBefore();
  696. FOR_EACH_WIDGET(it)
  697. {
  698. Widget* const widget(*it);
  699. widget->pData->display(fWidth, fHeight, fAutoScaling, false);
  700. }
  701. fSelf->onDisplayAfter();
  702. }
  703. int onPuglKeyboard(const bool press, const uint key)
  704. {
  705. DBGp("PUGL: onKeyboard : %i %i\n", press, key);
  706. if (fModal.childFocus != nullptr)
  707. {
  708. fModal.childFocus->focus();
  709. return 0;
  710. }
  711. Widget::KeyboardEvent ev;
  712. ev.press = press;
  713. ev.key = key;
  714. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  715. ev.time = puglGetEventTimestamp(fView);
  716. FOR_EACH_WIDGET_INV(rit)
  717. {
  718. Widget* const widget(*rit);
  719. if (widget->isVisible() && widget->onKeyboard(ev))
  720. return 0;
  721. }
  722. return 1;
  723. }
  724. int onPuglSpecial(const bool press, const Key key)
  725. {
  726. DBGp("PUGL: onSpecial : %i %i\n", press, key);
  727. if (fModal.childFocus != nullptr)
  728. {
  729. fModal.childFocus->focus();
  730. return 0;
  731. }
  732. Widget::SpecialEvent ev;
  733. ev.press = press;
  734. ev.key = key;
  735. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  736. ev.time = puglGetEventTimestamp(fView);
  737. FOR_EACH_WIDGET_INV(rit)
  738. {
  739. Widget* const widget(*rit);
  740. if (widget->isVisible() && widget->onSpecial(ev))
  741. return 0;
  742. }
  743. return 1;
  744. }
  745. void onPuglMouse(const int button, const bool press, int x, int y)
  746. {
  747. DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y);
  748. // FIXME - pugl sends 2 of these for each window on init, don't ask me why. we'll ignore it
  749. if (press && button == 0 && x == 0 && y == 0) return;
  750. if (fModal.childFocus != nullptr)
  751. return fModal.childFocus->focus();
  752. x /= fAutoScaling;
  753. y /= fAutoScaling;
  754. Widget::MouseEvent ev;
  755. ev.button = button;
  756. ev.press = press;
  757. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  758. ev.time = puglGetEventTimestamp(fView);
  759. FOR_EACH_WIDGET_INV(rit)
  760. {
  761. Widget* const widget(*rit);
  762. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  763. if (widget->isVisible() && widget->onMouse(ev))
  764. break;
  765. }
  766. }
  767. void onPuglMotion(int x, int y)
  768. {
  769. // DBGp("PUGL: onMotion : %i %i\n", x, y);
  770. if (fModal.childFocus != nullptr)
  771. return;
  772. x /= fAutoScaling;
  773. y /= fAutoScaling;
  774. Widget::MotionEvent ev;
  775. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  776. ev.time = puglGetEventTimestamp(fView);
  777. FOR_EACH_WIDGET_INV(rit)
  778. {
  779. Widget* const widget(*rit);
  780. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  781. if (widget->isVisible() && widget->onMotion(ev))
  782. break;
  783. }
  784. }
  785. void onPuglScroll(int x, int y, float dx, float dy)
  786. {
  787. DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy);
  788. if (fModal.childFocus != nullptr)
  789. return;
  790. x /= fAutoScaling;
  791. y /= fAutoScaling;
  792. dx /= fAutoScaling;
  793. dy /= fAutoScaling;
  794. Widget::ScrollEvent ev;
  795. ev.delta = Point<float>(dx, dy);
  796. ev.mod = static_cast<Modifier>(puglGetModifiers(fView));
  797. ev.time = puglGetEventTimestamp(fView);
  798. FOR_EACH_WIDGET_INV(rit)
  799. {
  800. Widget* const widget(*rit);
  801. ev.pos = Point<int>(x-widget->getAbsoluteX(), y-widget->getAbsoluteY());
  802. if (widget->isVisible() && widget->onScroll(ev))
  803. break;
  804. }
  805. }
  806. void onPuglReshape(const int width, const int height)
  807. {
  808. DBGp("PUGL: onReshape : %i %i\n", width, height);
  809. if (width <= 1 && height <= 1)
  810. return;
  811. fWidth = static_cast<uint>(width);
  812. fHeight = static_cast<uint>(height);
  813. fSelf->onReshape(fWidth, fHeight);
  814. FOR_EACH_WIDGET(it)
  815. {
  816. Widget* const widget(*it);
  817. if (widget->pData->needsFullViewport)
  818. widget->setSize(fWidth, fHeight);
  819. }
  820. }
  821. void onPuglClose()
  822. {
  823. DBG("PUGL: onClose\n");
  824. if (fModal.enabled)
  825. exec_fini();
  826. fSelf->onClose();
  827. if (fModal.childFocus != nullptr)
  828. fModal.childFocus->fSelf->onClose();
  829. close();
  830. }
  831. // -------------------------------------------------------------------
  832. bool handlePluginKeyboard(const bool press, const uint key)
  833. {
  834. DBGp("PUGL: handlePluginKeyboard : %i %i\n", press, key);
  835. if (fModal.childFocus != nullptr)
  836. {
  837. fModal.childFocus->focus();
  838. return true;
  839. }
  840. Widget::KeyboardEvent ev;
  841. ev.press = press;
  842. ev.key = key;
  843. ev.mod = static_cast<Modifier>(fView->mods);
  844. ev.time = 0;
  845. if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z')
  846. ev.key -= 'a' - 'A'; // a-z -> A-Z
  847. FOR_EACH_WIDGET_INV(rit)
  848. {
  849. Widget* const widget(*rit);
  850. if (widget->isVisible() && widget->onKeyboard(ev))
  851. return true;
  852. }
  853. return false;
  854. }
  855. bool handlePluginSpecial(const bool press, const Key key)
  856. {
  857. DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key);
  858. if (fModal.childFocus != nullptr)
  859. {
  860. fModal.childFocus->focus();
  861. return true;
  862. }
  863. int mods = 0x0;
  864. switch (key)
  865. {
  866. case kKeyShift:
  867. mods |= kModifierShift;
  868. break;
  869. case kKeyControl:
  870. mods |= kModifierControl;
  871. break;
  872. case kKeyAlt:
  873. mods |= kModifierAlt;
  874. break;
  875. default:
  876. break;
  877. }
  878. if (mods != 0x0)
  879. {
  880. if (press)
  881. fView->mods |= mods;
  882. else
  883. fView->mods &= ~(mods);
  884. }
  885. Widget::SpecialEvent ev;
  886. ev.press = press;
  887. ev.key = key;
  888. ev.mod = static_cast<Modifier>(fView->mods);
  889. ev.time = 0;
  890. FOR_EACH_WIDGET_INV(rit)
  891. {
  892. Widget* const widget(*rit);
  893. if (widget->isVisible() && widget->onSpecial(ev))
  894. return true;
  895. }
  896. return false;
  897. }
  898. #if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED)
  899. static void openPanelDidEnd(NSOpenPanel* panel, int returnCode, void *userData)
  900. {
  901. PrivateData* pData = (PrivateData*)userData;
  902. if (returnCode == NSOKButton)
  903. {
  904. NSArray* urls = [panel URLs];
  905. NSURL* fileUrl = nullptr;
  906. for (NSUInteger i = 0, n = [urls count]; i < n && !fileUrl; ++i)
  907. {
  908. NSURL* url = (NSURL*)[urls objectAtIndex:i];
  909. if ([url isFileURL])
  910. fileUrl = url;
  911. }
  912. if (fileUrl)
  913. {
  914. PuglView* view = pData->fView;
  915. if (view->fileSelectedFunc)
  916. {
  917. const char* fileName = [fileUrl.path UTF8String];
  918. view->fileSelectedFunc(view, fileName);
  919. }
  920. }
  921. }
  922. [pData->fOpenFilePanel release];
  923. pData->fOpenFilePanel = nullptr;
  924. }
  925. #endif
  926. // -------------------------------------------------------------------
  927. Application& fApp;
  928. Window* fSelf;
  929. GraphicsContext fContext;
  930. PuglView* fView;
  931. bool fFirstInit;
  932. bool fVisible;
  933. bool fResizable;
  934. bool fUsingEmbed;
  935. uint fWidth;
  936. uint fHeight;
  937. double fScaling;
  938. double fAutoScaling;
  939. char* fTitle;
  940. std::list<Widget*> fWidgets;
  941. struct Modal {
  942. bool enabled;
  943. PrivateData* parent;
  944. PrivateData* childFocus;
  945. Modal()
  946. : enabled(false),
  947. parent(nullptr),
  948. childFocus(nullptr) {}
  949. Modal(PrivateData* const p)
  950. : enabled(false),
  951. parent(p),
  952. childFocus(nullptr) {}
  953. ~Modal()
  954. {
  955. DISTRHO_SAFE_ASSERT(! enabled);
  956. DISTRHO_SAFE_ASSERT(childFocus == nullptr);
  957. }
  958. DISTRHO_DECLARE_NON_COPY_STRUCT(Modal)
  959. } fModal;
  960. #if defined(DISTRHO_OS_WINDOWS)
  961. HWND hwnd;
  962. HWND hwndParent;
  963. # ifndef DGL_FILE_BROWSER_DISABLED
  964. String fSelectedFile;
  965. # endif
  966. #elif defined(DISTRHO_OS_MAC)
  967. bool fNeedsIdle;
  968. NSView<PuglGenericView>* mView;
  969. id mWindow;
  970. id mParentWindow;
  971. # ifndef DGL_FILE_BROWSER_DISABLED
  972. NSOpenPanel* fOpenFilePanel;
  973. id fFilePanelDelegate;
  974. # endif
  975. #else
  976. Display* xDisplay;
  977. ::Window xWindow;
  978. #endif
  979. // -------------------------------------------------------------------
  980. // Callbacks
  981. #define handlePtr ((PrivateData*)puglGetHandle(view))
  982. static void onDisplayCallback(PuglView* view)
  983. {
  984. handlePtr->onPuglDisplay();
  985. }
  986. static int onKeyboardCallback(PuglView* view, bool press, uint32_t key)
  987. {
  988. return handlePtr->onPuglKeyboard(press, key);
  989. }
  990. static int onSpecialCallback(PuglView* view, bool press, PuglKey key)
  991. {
  992. return handlePtr->onPuglSpecial(press, static_cast<Key>(key));
  993. }
  994. static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
  995. {
  996. handlePtr->onPuglMouse(button, press, x, y);
  997. }
  998. static void onMotionCallback(PuglView* view, int x, int y)
  999. {
  1000. handlePtr->onPuglMotion(x, y);
  1001. }
  1002. static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy)
  1003. {
  1004. handlePtr->onPuglScroll(x, y, dx, dy);
  1005. }
  1006. static void onReshapeCallback(PuglView* view, int width, int height)
  1007. {
  1008. handlePtr->onPuglReshape(width, height);
  1009. }
  1010. static void onCloseCallback(PuglView* view)
  1011. {
  1012. handlePtr->onPuglClose();
  1013. }
  1014. #ifndef DGL_FILE_BROWSER_DISABLED
  1015. static void fileBrowserSelectedCallback(PuglView* view, const char* filename)
  1016. {
  1017. handlePtr->fSelf->fileBrowserSelected(filename);
  1018. }
  1019. #endif
  1020. #undef handlePtr
  1021. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  1022. };
  1023. // -----------------------------------------------------------------------
  1024. // Window
  1025. Window::Window(Application& app)
  1026. : pData(new PrivateData(app, this)) {}
  1027. Window::Window(Application& app, Window& parent)
  1028. : pData(new PrivateData(app, this, parent)) {}
  1029. Window::Window(Application& app, intptr_t parentId, double scaling, bool resizable)
  1030. : pData(new PrivateData(app, this, parentId, scaling, resizable)) {}
  1031. Window::~Window()
  1032. {
  1033. delete pData;
  1034. }
  1035. void Window::show()
  1036. {
  1037. pData->setVisible(true);
  1038. }
  1039. void Window::hide()
  1040. {
  1041. pData->setVisible(false);
  1042. }
  1043. void Window::close()
  1044. {
  1045. pData->close();
  1046. }
  1047. void Window::exec(bool lockWait)
  1048. {
  1049. pData->exec(lockWait);
  1050. }
  1051. void Window::focus()
  1052. {
  1053. pData->focus();
  1054. }
  1055. void Window::repaint() noexcept
  1056. {
  1057. puglPostRedisplay(pData->fView);
  1058. }
  1059. // static int fib_filter_filename_filter(const char* const name)
  1060. // {
  1061. // return 1;
  1062. // (void)name;
  1063. // }
  1064. #ifndef DGL_FILE_BROWSER_DISABLED
  1065. #ifdef DISTRHO_OS_MAC
  1066. END_NAMESPACE_DGL
  1067. @interface FilePanelDelegate : NSObject
  1068. {
  1069. void (*fCallback)(NSOpenPanel*, int, void*);
  1070. void* fUserData;
  1071. }
  1072. -(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void*)userData;
  1073. -(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
  1074. @end
  1075. START_NAMESPACE_DGL
  1076. #endif
  1077. bool Window::openFileBrowser(const FileBrowserOptions& options)
  1078. {
  1079. # ifdef SOFD_HAVE_X11
  1080. using DISTRHO_NAMESPACE::String;
  1081. // --------------------------------------------------------------------------
  1082. // configure start dir
  1083. // TODO: get abspath if needed
  1084. // TODO: cross-platform
  1085. String startDir(options.startDir);
  1086. # ifdef DISTRHO_OS_LINUX
  1087. if (startDir.isEmpty())
  1088. {
  1089. if (char* const dir_name = get_current_dir_name())
  1090. {
  1091. startDir = dir_name;
  1092. std::free(dir_name);
  1093. }
  1094. }
  1095. # endif
  1096. DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false);
  1097. if (! startDir.endsWith('/'))
  1098. startDir += "/";
  1099. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false);
  1100. // --------------------------------------------------------------------------
  1101. // configure title
  1102. String title(options.title);
  1103. if (title.isEmpty())
  1104. {
  1105. title = pData->getTitle();
  1106. if (title.isEmpty())
  1107. title = "FileBrowser";
  1108. }
  1109. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false);
  1110. // --------------------------------------------------------------------------
  1111. // configure filters
  1112. x_fib_cfg_filter_callback(nullptr); //fib_filter_filename_filter);
  1113. // --------------------------------------------------------------------------
  1114. // configure buttons
  1115. x_fib_cfg_buttons(3, options.buttons.listAllFiles-1);
  1116. x_fib_cfg_buttons(1, options.buttons.showHidden-1);
  1117. x_fib_cfg_buttons(2, options.buttons.showPlaces-1);
  1118. // --------------------------------------------------------------------------
  1119. // show
  1120. return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0);
  1121. # elif defined(DISTRHO_OS_WINDOWS)
  1122. // the old and compatible dialog API
  1123. OPENFILENAMEW ofn;
  1124. memset(&ofn, 0, sizeof(ofn));
  1125. ofn.lStructSize = sizeof(ofn);
  1126. ofn.hwndOwner = pData->hwnd;
  1127. // set initial directory in UTF-16 coding
  1128. std::vector<WCHAR> startDirW;
  1129. if (options.startDir)
  1130. {
  1131. startDirW.resize(strlen(options.startDir) + 1);
  1132. if (MultiByteToWideChar(CP_UTF8, 0, options.startDir, -1, startDirW.data(), startDirW.size()))
  1133. ofn.lpstrInitialDir = startDirW.data();
  1134. }
  1135. // set title in UTF-16 coding
  1136. std::vector<WCHAR> titleW;
  1137. if (options.title)
  1138. {
  1139. titleW.resize(strlen(options.title) + 1);
  1140. if (MultiByteToWideChar(CP_UTF8, 0, options.title, -1, titleW.data(), titleW.size()))
  1141. ofn.lpstrTitle = titleW.data();
  1142. }
  1143. // prepare a buffer to receive the result
  1144. std::vector<WCHAR> fileNameW(32768); // the Unicode maximum
  1145. ofn.lpstrFile = fileNameW.data();
  1146. ofn.nMaxFile = (DWORD)fileNameW.size();
  1147. // TODO synchronous only, can't do better with WinAPI native dialogs.
  1148. // threading might work, if someone is motivated to risk it.
  1149. if (GetOpenFileNameW(&ofn))
  1150. {
  1151. // back to UTF-8
  1152. std::vector<char> fileNameA(4 * 32768);
  1153. if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, fileNameA.data(), (int)fileNameA.size(), nullptr, nullptr))
  1154. {
  1155. // handle it during the next idle cycle (fake async)
  1156. pData->fSelectedFile = fileNameA.data();
  1157. }
  1158. }
  1159. return true;
  1160. # elif defined(DISTRHO_OS_MAC)
  1161. if (pData->fOpenFilePanel) // permit one dialog at most
  1162. {
  1163. [pData->fOpenFilePanel makeKeyAndOrderFront:nil];
  1164. return false;
  1165. }
  1166. NSOpenPanel* panel = [NSOpenPanel openPanel];
  1167. pData->fOpenFilePanel = [panel retain];
  1168. [panel setCanChooseFiles:YES];
  1169. [panel setCanChooseDirectories:NO];
  1170. [panel setAllowsMultipleSelection:NO];
  1171. if (options.startDir)
  1172. [panel setDirectory:[NSString stringWithUTF8String:options.startDir]];
  1173. if (options.title)
  1174. {
  1175. NSString* titleString = [[NSString alloc]
  1176. initWithBytes:options.title
  1177. length:strlen(options.title)
  1178. encoding:NSUTF8StringEncoding];
  1179. [panel setTitle:titleString];
  1180. }
  1181. id delegate = pData->fFilePanelDelegate;
  1182. if (!delegate)
  1183. {
  1184. delegate = [[FilePanelDelegate alloc] initWithCallback:&PrivateData::openPanelDidEnd
  1185. userData:pData];
  1186. pData->fFilePanelDelegate = [delegate retain];
  1187. }
  1188. [panel beginSheetForDirectory:nullptr
  1189. file:nullptr
  1190. modalForWindow:nullptr
  1191. modalDelegate:delegate
  1192. didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
  1193. contextInfo:nullptr];
  1194. return true;
  1195. # else
  1196. // not implemented
  1197. return false;
  1198. // unused
  1199. (void)options;
  1200. # endif
  1201. }
  1202. #ifdef DISTRHO_OS_MAC
  1203. END_NAMESPACE_DGL
  1204. @implementation FilePanelDelegate
  1205. -(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void *)userData
  1206. {
  1207. [super init];
  1208. self->fCallback = callback;
  1209. self->fUserData = userData;
  1210. return self;
  1211. }
  1212. -(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
  1213. {
  1214. self->fCallback(sheet, returnCode, self->fUserData);
  1215. (void)contextInfo;
  1216. }
  1217. @end
  1218. START_NAMESPACE_DGL
  1219. #endif
  1220. #endif // !defined(DGL_FILE_BROWSER_DISABLED)
  1221. bool Window::isEmbed() const noexcept
  1222. {
  1223. return pData->fUsingEmbed;
  1224. }
  1225. bool Window::isVisible() const noexcept
  1226. {
  1227. return pData->fVisible;
  1228. }
  1229. void Window::setVisible(bool yesNo)
  1230. {
  1231. pData->setVisible(yesNo);
  1232. }
  1233. bool Window::isResizable() const noexcept
  1234. {
  1235. return pData->fResizable;
  1236. }
  1237. void Window::setResizable(bool yesNo)
  1238. {
  1239. pData->setResizable(yesNo);
  1240. }
  1241. void Window::setGeometryConstraints(uint width, uint height, bool aspect)
  1242. {
  1243. pData->setGeometryConstraints(width, height, aspect);
  1244. }
  1245. uint Window::getWidth() const noexcept
  1246. {
  1247. return pData->fWidth;
  1248. }
  1249. uint Window::getHeight() const noexcept
  1250. {
  1251. return pData->fHeight;
  1252. }
  1253. Size<uint> Window::getSize() const noexcept
  1254. {
  1255. return Size<uint>(pData->fWidth, pData->fHeight);
  1256. }
  1257. void Window::setSize(uint width, uint height)
  1258. {
  1259. pData->setSize(width, height);
  1260. }
  1261. void Window::setSize(Size<uint> size)
  1262. {
  1263. pData->setSize(size.getWidth(), size.getHeight());
  1264. }
  1265. const char* Window::getTitle() const noexcept
  1266. {
  1267. return pData->getTitle();
  1268. }
  1269. void Window::setTitle(const char* title)
  1270. {
  1271. pData->setTitle(title);
  1272. }
  1273. void Window::setTransientWinId(uintptr_t winId)
  1274. {
  1275. pData->setTransientWinId(winId);
  1276. }
  1277. double Window::getScaling() const noexcept
  1278. {
  1279. return pData->getScaling();
  1280. }
  1281. bool Window::getIgnoringKeyRepeat() const noexcept
  1282. {
  1283. return pData->getIgnoringKeyRepeat();
  1284. }
  1285. void Window::setIgnoringKeyRepeat(bool ignore) noexcept
  1286. {
  1287. pData->setIgnoringKeyRepeat(ignore);
  1288. }
  1289. Application& Window::getApp() const noexcept
  1290. {
  1291. return pData->fApp;
  1292. }
  1293. intptr_t Window::getWindowId() const noexcept
  1294. {
  1295. return puglGetNativeWindow(pData->fView);
  1296. }
  1297. const GraphicsContext& Window::getGraphicsContext() const noexcept
  1298. {
  1299. GraphicsContext& context = pData->fContext;
  1300. #ifdef DGL_CAIRO
  1301. context.cairo = (cairo_t*)puglGetContext(pData->fView);
  1302. #endif
  1303. return context;
  1304. }
  1305. void Window::_setAutoScaling(double scaling) noexcept
  1306. {
  1307. pData->setAutoScaling(scaling);
  1308. }
  1309. void Window::_addWidget(Widget* const widget)
  1310. {
  1311. pData->addWidget(widget);
  1312. }
  1313. void Window::_removeWidget(Widget* const widget)
  1314. {
  1315. pData->removeWidget(widget);
  1316. }
  1317. void Window::_idle()
  1318. {
  1319. pData->idle();
  1320. }
  1321. // -----------------------------------------------------------------------
  1322. void Window::addIdleCallback(IdleCallback* const callback)
  1323. {
  1324. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  1325. pData->fApp.pData->idleCallbacks.push_back(callback);
  1326. }
  1327. void Window::removeIdleCallback(IdleCallback* const callback)
  1328. {
  1329. DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)
  1330. pData->fApp.pData->idleCallbacks.remove(callback);
  1331. }
  1332. // -----------------------------------------------------------------------
  1333. void Window::onDisplayBefore()
  1334. {
  1335. #ifdef DGL_OPENGL
  1336. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1337. glLoadIdentity();
  1338. #endif
  1339. }
  1340. void Window::onDisplayAfter()
  1341. {
  1342. }
  1343. void Window::onReshape(uint width, uint height)
  1344. {
  1345. #ifdef DGL_OPENGL
  1346. glEnable(GL_BLEND);
  1347. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1348. glMatrixMode(GL_PROJECTION);
  1349. glLoadIdentity();
  1350. glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0);
  1351. glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
  1352. glMatrixMode(GL_MODELVIEW);
  1353. glLoadIdentity();
  1354. #endif
  1355. }
  1356. void Window::onClose()
  1357. {
  1358. }
  1359. #ifndef DGL_FILE_BROWSER_DISABLED
  1360. void Window::fileBrowserSelected(const char*)
  1361. {
  1362. }
  1363. #endif
  1364. bool Window::handlePluginKeyboard(const bool press, const uint key)
  1365. {
  1366. return pData->handlePluginKeyboard(press, key);
  1367. }
  1368. bool Window::handlePluginSpecial(const bool press, const Key key)
  1369. {
  1370. return pData->handlePluginSpecial(press, key);
  1371. }
  1372. // -----------------------------------------------------------------------
  1373. StandaloneWindow::StandaloneWindow()
  1374. : Application(),
  1375. Window((Application&)*this),
  1376. fWidget(nullptr) {}
  1377. void StandaloneWindow::exec()
  1378. {
  1379. Window::show();
  1380. Application::exec();
  1381. }
  1382. void StandaloneWindow::onReshape(uint width, uint height)
  1383. {
  1384. if (fWidget != nullptr)
  1385. fWidget->setSize(width, height);
  1386. Window::onReshape(width, height);
  1387. }
  1388. void StandaloneWindow::_addWidget(Widget* widget)
  1389. {
  1390. if (fWidget == nullptr)
  1391. {
  1392. fWidget = widget;
  1393. fWidget->pData->needsFullViewport = true;
  1394. }
  1395. Window::_addWidget(widget);
  1396. }
  1397. void StandaloneWindow::_removeWidget(Widget* widget)
  1398. {
  1399. if (fWidget == widget)
  1400. {
  1401. fWidget->pData->needsFullViewport = false;
  1402. fWidget = nullptr;
  1403. }
  1404. Window::_removeWidget(widget);
  1405. }
  1406. // -----------------------------------------------------------------------
  1407. END_NAMESPACE_DGL
  1408. #undef DBG
  1409. #undef DBGF