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.

1199 lines
33KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2022 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. #include "WindowPrivateData.hpp"
  17. #include "TopLevelWidgetPrivateData.hpp"
  18. #include "pugl.hpp"
  19. // #define DGL_DEBUG_EVENTS
  20. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  21. # ifdef DISTRHO_PROPER_CPP11_SUPPORT
  22. # include <cinttypes>
  23. # else
  24. # include <inttypes.h>
  25. # endif
  26. #endif
  27. START_NAMESPACE_DGL
  28. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  29. # define DGL_DBG(msg) std::fprintf(stderr, "%s", msg);
  30. # define DGL_DBGp(...) std::fprintf(stderr, __VA_ARGS__);
  31. # define DGL_DBGF std::fflush(stderr);
  32. #else
  33. # define DGL_DBG(msg)
  34. # define DGL_DBGp(...)
  35. # define DGL_DBGF
  36. #endif
  37. #define DEFAULT_WIDTH 640
  38. #define DEFAULT_HEIGHT 480
  39. #define FOR_EACH_TOP_LEVEL_WIDGET(it) \
  40. for (std::list<TopLevelWidget*>::iterator it = topLevelWidgets.begin(); it != topLevelWidgets.end(); ++it)
  41. #define FOR_EACH_TOP_LEVEL_WIDGET_INV(rit) \
  42. for (std::list<TopLevelWidget*>::reverse_iterator rit = topLevelWidgets.rbegin(); rit != topLevelWidgets.rend(); ++rit)
  43. // -----------------------------------------------------------------------
  44. static double getScaleFactorFromParent(const PuglView* const view)
  45. {
  46. // allow custom scale for testing
  47. if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
  48. return std::max(1.0, std::atof(scale));
  49. if (view != nullptr)
  50. return puglGetScaleFactorFromParent(view);
  51. return 1.0;
  52. }
  53. static PuglView* puglNewViewWithTransientParent(PuglWorld* const world, PuglView* const transientParentView)
  54. {
  55. DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr);
  56. if (PuglView* const view = puglNewView(world))
  57. {
  58. puglSetTransientParent(view, puglGetNativeView(transientParentView));
  59. return view;
  60. }
  61. return nullptr;
  62. }
  63. static PuglView* puglNewViewWithParentWindow(PuglWorld* const world, const uintptr_t parentWindowHandle)
  64. {
  65. DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, nullptr);
  66. if (PuglView* const view = puglNewView(world))
  67. {
  68. puglSetParentWindow(view, parentWindowHandle);
  69. return view;
  70. }
  71. return nullptr;
  72. }
  73. // -----------------------------------------------------------------------
  74. Window::PrivateData::PrivateData(Application& a, Window* const s)
  75. : app(a),
  76. appData(a.pData),
  77. self(s),
  78. view(appData->world != nullptr ? puglNewView(appData->world) : nullptr),
  79. topLevelWidgets(),
  80. isClosed(true),
  81. isVisible(false),
  82. isEmbed(false),
  83. usesSizeRequest(false),
  84. scaleFactor(getScaleFactorFromParent(view)),
  85. autoScaling(false),
  86. autoScaleFactor(1.0),
  87. minWidth(0),
  88. minHeight(0),
  89. keepAspectRatio(false),
  90. ignoreIdleCallbacks(false),
  91. waitingForClipboardData(false),
  92. waitingForClipboardEvents(false),
  93. clipboardTypeId(0),
  94. filenameToRenderInto(nullptr),
  95. #ifndef DGL_FILE_BROWSER_DISABLED
  96. fileBrowserHandle(nullptr),
  97. #endif
  98. modal()
  99. {
  100. initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
  101. }
  102. Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* const ppData)
  103. : app(a),
  104. appData(a.pData),
  105. self(s),
  106. view(puglNewViewWithTransientParent(appData->world, ppData->view)),
  107. topLevelWidgets(),
  108. isClosed(true),
  109. isVisible(false),
  110. isEmbed(false),
  111. usesSizeRequest(false),
  112. scaleFactor(ppData->scaleFactor),
  113. autoScaling(false),
  114. autoScaleFactor(1.0),
  115. minWidth(0),
  116. minHeight(0),
  117. keepAspectRatio(false),
  118. ignoreIdleCallbacks(false),
  119. waitingForClipboardData(false),
  120. waitingForClipboardEvents(false),
  121. clipboardTypeId(0),
  122. filenameToRenderInto(nullptr),
  123. #ifndef DGL_FILE_BROWSER_DISABLED
  124. fileBrowserHandle(nullptr),
  125. #endif
  126. modal(ppData)
  127. {
  128. initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
  129. }
  130. Window::PrivateData::PrivateData(Application& a, Window* const s,
  131. const uintptr_t parentWindowHandle,
  132. const double scale, const bool resizable)
  133. : app(a),
  134. appData(a.pData),
  135. self(s),
  136. view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)),
  137. topLevelWidgets(),
  138. isClosed(parentWindowHandle == 0),
  139. isVisible(parentWindowHandle != 0),
  140. isEmbed(parentWindowHandle != 0),
  141. usesSizeRequest(false),
  142. scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)),
  143. autoScaling(false),
  144. autoScaleFactor(1.0),
  145. minWidth(0),
  146. minHeight(0),
  147. keepAspectRatio(false),
  148. ignoreIdleCallbacks(false),
  149. waitingForClipboardData(false),
  150. waitingForClipboardEvents(false),
  151. clipboardTypeId(0),
  152. filenameToRenderInto(nullptr),
  153. #ifndef DGL_FILE_BROWSER_DISABLED
  154. fileBrowserHandle(nullptr),
  155. #endif
  156. modal()
  157. {
  158. initPre(DEFAULT_WIDTH, DEFAULT_HEIGHT, resizable);
  159. }
  160. Window::PrivateData::PrivateData(Application& a, Window* const s,
  161. const uintptr_t parentWindowHandle,
  162. const uint width, const uint height,
  163. const double scale, const bool resizable, const bool isVST3)
  164. : app(a),
  165. appData(a.pData),
  166. self(s),
  167. view(puglNewViewWithParentWindow(appData->world, parentWindowHandle)),
  168. topLevelWidgets(),
  169. isClosed(parentWindowHandle == 0),
  170. isVisible(parentWindowHandle != 0 && view != nullptr),
  171. isEmbed(parentWindowHandle != 0),
  172. usesSizeRequest(isVST3),
  173. scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)),
  174. autoScaling(false),
  175. autoScaleFactor(1.0),
  176. minWidth(0),
  177. minHeight(0),
  178. keepAspectRatio(false),
  179. ignoreIdleCallbacks(false),
  180. waitingForClipboardData(false),
  181. waitingForClipboardEvents(false),
  182. clipboardTypeId(0),
  183. filenameToRenderInto(nullptr),
  184. #ifndef DGL_FILE_BROWSER_DISABLED
  185. fileBrowserHandle(nullptr),
  186. #endif
  187. modal()
  188. {
  189. if (isEmbed)
  190. puglSetParentWindow(view, parentWindowHandle);
  191. initPre(width != 0 ? width : DEFAULT_WIDTH, height != 0 ? height : DEFAULT_HEIGHT, resizable);
  192. }
  193. Window::PrivateData::~PrivateData()
  194. {
  195. appData->idleCallbacks.remove(this);
  196. appData->windows.remove(self);
  197. std::free(filenameToRenderInto);
  198. if (view == nullptr)
  199. return;
  200. if (isEmbed)
  201. {
  202. #ifndef DGL_FILE_BROWSER_DISABLED
  203. if (fileBrowserHandle != nullptr)
  204. fileBrowserClose(fileBrowserHandle);
  205. #endif
  206. puglHide(view);
  207. appData->oneWindowClosed();
  208. isClosed = true;
  209. isVisible = false;
  210. }
  211. puglFreeView(view);
  212. }
  213. // -----------------------------------------------------------------------
  214. void Window::PrivateData::initPre(const uint width, const uint height, const bool resizable)
  215. {
  216. appData->windows.push_back(self);
  217. appData->idleCallbacks.push_back(this);
  218. memset(graphicsContext, 0, sizeof(graphicsContext));
  219. if (view == nullptr)
  220. {
  221. d_stderr2("Failed to create Pugl view, everything will fail!");
  222. return;
  223. }
  224. puglSetMatchingBackendForCurrentBuild(view);
  225. puglSetHandle(view, this);
  226. puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
  227. puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE);
  228. #if DGL_USE_RGBA
  229. puglSetViewHint(view, PUGL_DEPTH_BITS, 24);
  230. #else
  231. puglSetViewHint(view, PUGL_DEPTH_BITS, 16);
  232. #endif
  233. puglSetViewHint(view, PUGL_STENCIL_BITS, 8);
  234. #if defined(DGL_USE_OPENGL3) || defined(DGL_USE_GLES3)
  235. puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
  236. puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
  237. #elif defined(DGL_USE_GLES2)
  238. puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE);
  239. puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
  240. #else
  241. puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_TRUE);
  242. puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
  243. #endif
  244. // PUGL_SAMPLES ??
  245. puglSetEventFunc(view, puglEventCallback);
  246. // setting default size triggers system-level calls, do it last
  247. puglSetSizeHint(view, PUGL_DEFAULT_SIZE, width, height);
  248. }
  249. bool Window::PrivateData::initPost()
  250. {
  251. if (view == nullptr)
  252. return false;
  253. // create view now, as a few methods we allow devs to use require it
  254. if (puglRealize(view) != PUGL_SUCCESS)
  255. {
  256. view = nullptr;
  257. d_stderr2("Failed to realize Pugl view, everything will fail!");
  258. return false;
  259. }
  260. if (isEmbed)
  261. {
  262. appData->oneWindowShown();
  263. puglShow(view);
  264. }
  265. return true;
  266. }
  267. // -----------------------------------------------------------------------
  268. void Window::PrivateData::close()
  269. {
  270. DGL_DBG("Window close\n");
  271. // DGL_DBGp("Window close DBG %i %i %p\n", isEmbed, isClosed, appData);
  272. if (isEmbed || isClosed)
  273. return;
  274. isClosed = true;
  275. hide();
  276. appData->oneWindowClosed();
  277. }
  278. // -----------------------------------------------------------------------
  279. void Window::PrivateData::show()
  280. {
  281. if (isVisible)
  282. {
  283. DGL_DBG("Window show matches current visible state, ignoring request\n");
  284. return;
  285. }
  286. if (isEmbed)
  287. {
  288. DGL_DBG("Window show cannot be called when embedded\n");
  289. return;
  290. }
  291. DGL_DBG("Window show called\n");
  292. if (view == nullptr)
  293. return;
  294. if (isClosed)
  295. {
  296. isClosed = false;
  297. appData->oneWindowShown();
  298. // FIXME
  299. // PuglRect rect = puglGetFrame(view);
  300. // puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(rect.height));
  301. #if defined(DISTRHO_OS_WINDOWS)
  302. puglWin32ShowCentered(view);
  303. #elif defined(DISTRHO_OS_MAC)
  304. puglMacOSShowCentered(view);
  305. #else
  306. puglShow(view);
  307. #endif
  308. }
  309. else
  310. {
  311. #ifdef DISTRHO_OS_WINDOWS
  312. puglWin32RestoreWindow(view);
  313. #else
  314. puglShow(view);
  315. #endif
  316. }
  317. isVisible = true;
  318. }
  319. void Window::PrivateData::hide()
  320. {
  321. if (isEmbed)
  322. {
  323. DGL_DBG("Window hide cannot be called when embedded\n");
  324. return;
  325. }
  326. if (! isVisible)
  327. {
  328. DGL_DBG("Window hide matches current visible state, ignoring request\n");
  329. return;
  330. }
  331. DGL_DBG("Window hide called\n");
  332. if (modal.enabled)
  333. stopModal();
  334. #ifndef DGL_FILE_BROWSER_DISABLED
  335. if (fileBrowserHandle != nullptr)
  336. {
  337. fileBrowserClose(fileBrowserHandle);
  338. fileBrowserHandle = nullptr;
  339. }
  340. #endif
  341. puglHide(view);
  342. isVisible = false;
  343. }
  344. // -----------------------------------------------------------------------
  345. void Window::PrivateData::focus()
  346. {
  347. if (view == nullptr)
  348. return;
  349. if (! isEmbed)
  350. puglRaiseWindow(view);
  351. puglGrabFocus(view);
  352. }
  353. // -----------------------------------------------------------------------
  354. void Window::PrivateData::setResizable(const bool resizable)
  355. {
  356. DISTRHO_SAFE_ASSERT_RETURN(! isEmbed,);
  357. DGL_DBG("Window setResizable called\n");
  358. puglSetResizable(view, resizable);
  359. }
  360. // -----------------------------------------------------------------------
  361. void Window::PrivateData::idleCallback()
  362. {
  363. #ifndef DGL_FILE_BROWSER_DISABLED
  364. if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle))
  365. {
  366. self->onFileSelected(fileBrowserGetPath(fileBrowserHandle));
  367. fileBrowserClose(fileBrowserHandle);
  368. fileBrowserHandle = nullptr;
  369. }
  370. #endif
  371. }
  372. // -----------------------------------------------------------------------
  373. // idle callback stuff
  374. bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs)
  375. {
  376. if (ignoreIdleCallbacks)
  377. return false;
  378. if (timerFrequencyInMs == 0)
  379. {
  380. appData->idleCallbacks.push_back(callback);
  381. return true;
  382. }
  383. return puglStartTimer(view, (uintptr_t)callback, static_cast<double>(timerFrequencyInMs) / 1000.0) == PUGL_SUCCESS;
  384. }
  385. bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback)
  386. {
  387. if (ignoreIdleCallbacks)
  388. return false;
  389. if (std::find(appData->idleCallbacks.begin(),
  390. appData->idleCallbacks.end(), callback) != appData->idleCallbacks.end())
  391. {
  392. appData->idleCallbacks.remove(callback);
  393. return true;
  394. }
  395. return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS;
  396. }
  397. #ifndef DGL_FILE_BROWSER_DISABLED
  398. // -----------------------------------------------------------------------
  399. // file handling
  400. bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)
  401. {
  402. if (fileBrowserHandle != nullptr)
  403. fileBrowserClose(fileBrowserHandle);
  404. FileBrowserOptions options2 = options;
  405. if (options2.title == nullptr)
  406. options2.title = puglGetWindowTitle(view);
  407. fileBrowserHandle = fileBrowserCreate(isEmbed,
  408. puglGetNativeView(view),
  409. autoScaling ? autoScaleFactor : scaleFactor,
  410. options2);
  411. return fileBrowserHandle != nullptr;
  412. }
  413. #endif // ! DGL_FILE_BROWSER_DISABLED
  414. // -----------------------------------------------------------------------
  415. // modal handling
  416. void Window::PrivateData::startModal()
  417. {
  418. DGL_DBG("Window modal loop starting..."); DGL_DBGF;
  419. DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show());
  420. // activate modal mode for this window
  421. modal.enabled = true;
  422. // make parent give focus to us
  423. modal.parent->modal.child = this;
  424. // make sure both parent and ourselves are visible
  425. modal.parent->show();
  426. show();
  427. #ifdef DISTRHO_OS_MAC
  428. puglMacOSAddChildWindow(modal.parent->view, view);
  429. #endif
  430. DGL_DBG("Ok\n");
  431. }
  432. void Window::PrivateData::stopModal()
  433. {
  434. DGL_DBG("Window modal loop stopping..."); DGL_DBGF;
  435. // deactivate modal mode
  436. modal.enabled = false;
  437. // safety checks, make sure we have a parent and we are currently active as the child to give focus to
  438. if (modal.parent == nullptr)
  439. return;
  440. if (modal.parent->modal.child != this)
  441. return;
  442. #ifdef DISTRHO_OS_MAC
  443. puglMacOSRemoveChildWindow(modal.parent->view, view);
  444. #endif
  445. // stop parent from giving focus to us, so it behaves like normal
  446. modal.parent->modal.child = nullptr;
  447. // refocus main window after closing child
  448. if (! modal.parent->isClosed)
  449. {
  450. const Widget::MotionEvent ev;
  451. modal.parent->onPuglMotion(ev);
  452. modal.parent->focus();
  453. }
  454. DGL_DBG("Ok\n");
  455. }
  456. void Window::PrivateData::runAsModal(const bool blockWait)
  457. {
  458. DGL_DBGp("Window::PrivateData::runAsModal %i\n", blockWait);
  459. startModal();
  460. if (blockWait)
  461. {
  462. DISTRHO_SAFE_ASSERT_RETURN(appData->isStandalone,);
  463. while (isVisible && modal.enabled)
  464. appData->idle(10);
  465. stopModal();
  466. }
  467. else
  468. {
  469. appData->idle(0);
  470. }
  471. }
  472. // -----------------------------------------------------------------------
  473. // pugl events
  474. void Window::PrivateData::onPuglConfigure(const double width, const double height)
  475. {
  476. DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,);
  477. DGL_DBGp("PUGL: onReshape : %f %f\n", width, height);
  478. if (autoScaling)
  479. {
  480. const double scaleHorizontal = width / static_cast<double>(minWidth);
  481. const double scaleVertical = height / static_cast<double>(minHeight);
  482. autoScaleFactor = scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical;
  483. }
  484. const uint uwidth = static_cast<uint>(width + 0.5);
  485. const uint uheight = static_cast<uint>(height + 0.5);
  486. self->onReshape(uwidth, uheight);
  487. #ifndef DPF_TEST_WINDOW_CPP
  488. FOR_EACH_TOP_LEVEL_WIDGET(it)
  489. {
  490. TopLevelWidget* const widget(*it);
  491. /* Some special care here, we call Widget::setSize instead of the TopLevelWidget one.
  492. * This is because we want TopLevelWidget::setSize to handle both window and widget size,
  493. * but we dont want to change window size here, because we are the window..
  494. * So we just call the Widget specific method manually.
  495. *
  496. * Alternatively, we could expose a resize function on the pData, like done with the display function.
  497. * But there is nothing extra we need to do in there, so this works fine.
  498. */
  499. ((Widget*)widget)->setSize(uwidth, uheight);
  500. }
  501. #endif
  502. // always repaint after a resize
  503. puglPostRedisplay(view);
  504. }
  505. void Window::PrivateData::onPuglExpose()
  506. {
  507. DGL_DBG("PUGL: onPuglExpose\n");
  508. puglOnDisplayPrepare(view);
  509. #ifndef DPF_TEST_WINDOW_CPP
  510. FOR_EACH_TOP_LEVEL_WIDGET(it)
  511. {
  512. TopLevelWidget* const widget(*it);
  513. if (widget->isVisible())
  514. widget->pData->display();
  515. }
  516. if (char* const filename = filenameToRenderInto)
  517. {
  518. const PuglRect rect = puglGetFrame(view);
  519. filenameToRenderInto = nullptr;
  520. renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height));
  521. std::free(filename);
  522. }
  523. #endif
  524. }
  525. void Window::PrivateData::onPuglClose()
  526. {
  527. DGL_DBG("PUGL: onClose\n");
  528. #ifndef DISTRHO_OS_MAC
  529. // if we are running as standalone we can prevent closing in certain conditions
  530. if (appData->isStandalone)
  531. {
  532. // a child window is active, gives focus to it
  533. if (modal.child != nullptr)
  534. return modal.child->focus();
  535. // ask window if we should close
  536. if (! self->onClose())
  537. return;
  538. }
  539. #endif
  540. if (modal.enabled)
  541. stopModal();
  542. if (modal.child != nullptr)
  543. {
  544. modal.child->close();
  545. modal.child = nullptr;
  546. }
  547. close();
  548. }
  549. void Window::PrivateData::onPuglFocus(const bool focus, const CrossingMode mode)
  550. {
  551. DGL_DBGp("onPuglFocus : %i %i | %i\n", focus, mode, isClosed);
  552. if (isClosed)
  553. return;
  554. if (modal.child != nullptr)
  555. return modal.child->focus();
  556. self->onFocus(focus, mode);
  557. }
  558. void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev)
  559. {
  560. DGL_DBGp("onPuglKey : %i %u %u\n", ev.press, ev.key, ev.keycode);
  561. if (modal.child != nullptr)
  562. return modal.child->focus();
  563. #ifndef DPF_TEST_WINDOW_CPP
  564. FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
  565. {
  566. TopLevelWidget* const widget(*rit);
  567. if (widget->isVisible() && widget->onKeyboard(ev))
  568. break;
  569. }
  570. #endif
  571. }
  572. void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev)
  573. {
  574. DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string);
  575. if (modal.child != nullptr)
  576. return modal.child->focus();
  577. #ifndef DPF_TEST_WINDOW_CPP
  578. FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
  579. {
  580. TopLevelWidget* const widget(*rit);
  581. if (widget->isVisible() && widget->onCharacterInput(ev))
  582. break;
  583. }
  584. #endif
  585. }
  586. void Window::PrivateData::onPuglMouse(const Widget::MouseEvent& ev)
  587. {
  588. DGL_DBGp("onPuglMouse : %i %i %f %f\n", ev.button, ev.press, ev.pos.getX(), ev.pos.getY());
  589. if (modal.child != nullptr)
  590. return modal.child->focus();
  591. #ifndef DPF_TEST_WINDOW_CPP
  592. FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
  593. {
  594. TopLevelWidget* const widget(*rit);
  595. if (widget->isVisible() && widget->onMouse(ev))
  596. break;
  597. }
  598. #endif
  599. }
  600. void Window::PrivateData::onPuglMotion(const Widget::MotionEvent& ev)
  601. {
  602. DGL_DBGp("onPuglMotion : %f %f\n", ev.pos.getX(), ev.pos.getY());
  603. if (modal.child != nullptr)
  604. return modal.child->focus();
  605. #ifndef DPF_TEST_WINDOW_CPP
  606. FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
  607. {
  608. TopLevelWidget* const widget(*rit);
  609. if (widget->isVisible() && widget->onMotion(ev))
  610. break;
  611. }
  612. #endif
  613. }
  614. void Window::PrivateData::onPuglScroll(const Widget::ScrollEvent& ev)
  615. {
  616. DGL_DBGp("onPuglScroll : %f %f %f %f\n", ev.pos.getX(), ev.pos.getY(), ev.delta.getX(), ev.delta.getY());
  617. if (modal.child != nullptr)
  618. return modal.child->focus();
  619. #ifndef DPF_TEST_WINDOW_CPP
  620. FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
  621. {
  622. TopLevelWidget* const widget(*rit);
  623. if (widget->isVisible() && widget->onScroll(ev))
  624. break;
  625. }
  626. #endif
  627. }
  628. const void* Window::PrivateData::getClipboard(size_t& dataSize)
  629. {
  630. clipboardTypeId = 0;
  631. waitingForClipboardData = true,
  632. waitingForClipboardEvents = true;
  633. // begin clipboard dance here
  634. if (puglPaste(view) != PUGL_SUCCESS)
  635. {
  636. dataSize = 0;
  637. waitingForClipboardEvents = false;
  638. return nullptr;
  639. }
  640. // wait for type request, clipboardTypeId must be != 0 to be valid
  641. while (clipboardTypeId == 0 && waitingForClipboardData)
  642. {
  643. #ifdef DGL_USING_X11
  644. puglX11UpdateWithoutExposures(appData->world);
  645. #endif
  646. }
  647. if (clipboardTypeId == 0)
  648. {
  649. dataSize = 0;
  650. waitingForClipboardEvents = false;
  651. return nullptr;
  652. }
  653. // wait for actual data (assumes offer was accepted)
  654. while (waitingForClipboardData)
  655. {
  656. #ifdef DGL_USING_X11
  657. puglX11UpdateWithoutExposures(appData->world);
  658. #endif
  659. }
  660. if (clipboardTypeId == 0)
  661. {
  662. dataSize = 0;
  663. waitingForClipboardEvents = false;
  664. return nullptr;
  665. }
  666. waitingForClipboardEvents = false;
  667. return puglGetClipboard(view, clipboardTypeId - 1, &dataSize);
  668. }
  669. uint32_t Window::PrivateData::onClipboardDataOffer()
  670. {
  671. DGL_DBG("onClipboardDataOffer\n");
  672. if ((clipboardTypeId = self->onClipboardDataOffer()) != 0)
  673. return clipboardTypeId;
  674. // stop waiting for data, it was rejected
  675. waitingForClipboardData = false;
  676. return 0;
  677. }
  678. void Window::PrivateData::onClipboardData(const uint32_t typeId)
  679. {
  680. if (clipboardTypeId != typeId)
  681. clipboardTypeId = 0;
  682. waitingForClipboardData = false;
  683. }
  684. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  685. static int printEvent(const PuglEvent* event, const char* prefix, const bool verbose);
  686. #endif
  687. PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const PuglEvent* const event)
  688. {
  689. Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view);
  690. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  691. if (event->type != PUGL_TIMER) {
  692. printEvent(event, "pugl event: ", true);
  693. }
  694. #endif
  695. if (pData->waitingForClipboardEvents)
  696. {
  697. switch (event->type)
  698. {
  699. case PUGL_UPDATE:
  700. case PUGL_EXPOSE:
  701. case PUGL_FOCUS_IN:
  702. case PUGL_FOCUS_OUT:
  703. case PUGL_KEY_PRESS:
  704. case PUGL_KEY_RELEASE:
  705. case PUGL_TEXT:
  706. case PUGL_POINTER_IN:
  707. case PUGL_POINTER_OUT:
  708. case PUGL_BUTTON_PRESS:
  709. case PUGL_BUTTON_RELEASE:
  710. case PUGL_MOTION:
  711. case PUGL_SCROLL:
  712. case PUGL_TIMER:
  713. case PUGL_LOOP_ENTER:
  714. case PUGL_LOOP_LEAVE:
  715. return PUGL_SUCCESS;
  716. case PUGL_DATA_OFFER:
  717. case PUGL_DATA:
  718. break;
  719. default:
  720. d_stdout("Got event %d while waitingForClipboardEvents", event->type);
  721. break;
  722. }
  723. }
  724. switch (event->type)
  725. {
  726. ///< No event
  727. case PUGL_NOTHING:
  728. break;
  729. ///< View created, a #PuglEventCreate
  730. case PUGL_CREATE:
  731. #ifdef DGL_USING_X11
  732. if (! pData->isEmbed)
  733. puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone);
  734. #endif
  735. break;
  736. ///< View destroyed, a #PuglEventDestroy
  737. case PUGL_DESTROY:
  738. break;
  739. ///< View moved/resized, a #PuglEventConfigure
  740. case PUGL_CONFIGURE:
  741. // unused x, y (double)
  742. pData->onPuglConfigure(event->configure.width, event->configure.height);
  743. break;
  744. ///< View made visible, a #PuglEventMap
  745. case PUGL_MAP:
  746. break;
  747. ///< View made invisible, a #PuglEventUnmap
  748. case PUGL_UNMAP:
  749. break;
  750. ///< View ready to draw, a #PuglEventUpdate
  751. case PUGL_UPDATE:
  752. break;
  753. ///< View must be drawn, a #PuglEventExpose
  754. case PUGL_EXPOSE:
  755. // unused x, y, width, height (double)
  756. pData->onPuglExpose();
  757. break;
  758. ///< View will be closed, a #PuglEventClose
  759. case PUGL_CLOSE:
  760. pData->onPuglClose();
  761. break;
  762. ///< Keyboard focus entered view, a #PuglEventFocus
  763. case PUGL_FOCUS_IN:
  764. ///< Keyboard focus left view, a #PuglEventFocus
  765. case PUGL_FOCUS_OUT:
  766. pData->onPuglFocus(event->type == PUGL_FOCUS_IN,
  767. static_cast<CrossingMode>(event->focus.mode));
  768. break;
  769. ///< Key pressed, a #PuglEventKey
  770. case PUGL_KEY_PRESS:
  771. ///< Key released, a #PuglEventKey
  772. case PUGL_KEY_RELEASE:
  773. {
  774. // unused x, y, xRoot, yRoot (double)
  775. Widget::KeyboardEvent ev;
  776. ev.mod = event->key.state;
  777. ev.flags = event->key.flags;
  778. ev.time = static_cast<uint>(event->key.time * 1000.0 + 0.5);
  779. ev.press = event->type == PUGL_KEY_PRESS;
  780. ev.key = event->key.key;
  781. ev.keycode = event->key.keycode;
  782. // keyboard events must always be lowercase
  783. if (ev.key >= 'A' && ev.key <= 'Z')
  784. {
  785. ev.key += 'a' - 'A'; // A-Z -> a-z
  786. ev.mod |= kModifierShift;
  787. }
  788. pData->onPuglKey(ev);
  789. break;
  790. }
  791. ///< Character entered, a #PuglEventText
  792. case PUGL_TEXT:
  793. {
  794. // unused x, y, xRoot, yRoot (double)
  795. Widget::CharacterInputEvent ev;
  796. ev.mod = event->text.state;
  797. ev.flags = event->text.flags;
  798. ev.time = static_cast<uint>(event->text.time * 1000.0 + 0.5);
  799. ev.keycode = event->text.keycode;
  800. ev.character = event->text.character;
  801. std::strncpy(ev.string, event->text.string, sizeof(ev.string));
  802. pData->onPuglText(ev);
  803. break;
  804. }
  805. ///< Pointer entered view, a #PuglEventCrossing
  806. case PUGL_POINTER_IN:
  807. break;
  808. ///< Pointer left view, a #PuglEventCrossing
  809. case PUGL_POINTER_OUT:
  810. break;
  811. ///< Mouse button pressed, a #PuglEventButton
  812. case PUGL_BUTTON_PRESS:
  813. ///< Mouse button released, a #PuglEventButton
  814. case PUGL_BUTTON_RELEASE:
  815. {
  816. Widget::MouseEvent ev;
  817. ev.mod = event->button.state;
  818. ev.flags = event->button.flags;
  819. ev.time = static_cast<uint>(event->button.time * 1000.0 + 0.5);
  820. ev.button = event->button.button + 1;
  821. ev.press = event->type == PUGL_BUTTON_PRESS;
  822. ev.pos = Point<double>(event->button.x, event->button.y);
  823. ev.absolutePos = ev.pos;
  824. pData->onPuglMouse(ev);
  825. break;
  826. }
  827. ///< Pointer moved, a #PuglEventMotion
  828. case PUGL_MOTION:
  829. {
  830. Widget::MotionEvent ev;
  831. ev.mod = event->motion.state;
  832. ev.flags = event->motion.flags;
  833. ev.time = static_cast<uint>(event->motion.time * 1000.0 + 0.5);
  834. ev.pos = Point<double>(event->motion.x, event->motion.y);
  835. ev.absolutePos = ev.pos;
  836. pData->onPuglMotion(ev);
  837. break;
  838. }
  839. ///< Scrolled, a #PuglEventScroll
  840. case PUGL_SCROLL:
  841. {
  842. Widget::ScrollEvent ev;
  843. ev.mod = event->scroll.state;
  844. ev.flags = event->scroll.flags;
  845. ev.time = static_cast<uint>(event->scroll.time * 1000.0 + 0.5);
  846. ev.pos = Point<double>(event->scroll.x, event->scroll.y);
  847. ev.delta = Point<double>(event->scroll.dx, event->scroll.dy);
  848. ev.direction = static_cast<ScrollDirection>(event->scroll.direction);
  849. ev.absolutePos = ev.pos;
  850. pData->onPuglScroll(ev);
  851. break;
  852. }
  853. ///< Custom client message, a #PuglEventClient
  854. case PUGL_CLIENT:
  855. break;
  856. ///< Timer triggered, a #PuglEventTimer
  857. case PUGL_TIMER:
  858. if (IdleCallback* const idleCallback = reinterpret_cast<IdleCallback*>(event->timer.id))
  859. idleCallback->idleCallback();
  860. break;
  861. ///< Recursive loop entered, a #PuglEventLoopEnter
  862. case PUGL_LOOP_ENTER:
  863. break;
  864. ///< Recursive loop left, a #PuglEventLoopLeave
  865. case PUGL_LOOP_LEAVE:
  866. break;
  867. ///< Data offered from clipboard, a #PuglDataOfferEvent
  868. case PUGL_DATA_OFFER:
  869. if (const uint32_t offerTypeId = pData->onClipboardDataOffer())
  870. puglAcceptOffer(view, &event->offer, offerTypeId - 1);
  871. break;
  872. ///< Data available from clipboard, a #PuglDataEvent
  873. case PUGL_DATA:
  874. pData->onClipboardData(event->data.typeIndex + 1);
  875. break;
  876. }
  877. return PUGL_SUCCESS;
  878. }
  879. // -----------------------------------------------------------------------
  880. #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
  881. static int printModifiers(const uint32_t mods)
  882. {
  883. return fprintf(stderr, "Modifiers:%s%s%s%s\n",
  884. (mods & PUGL_MOD_SHIFT) ? " Shift" : "",
  885. (mods & PUGL_MOD_CTRL) ? " Ctrl" : "",
  886. (mods & PUGL_MOD_ALT) ? " Alt" : "",
  887. (mods & PUGL_MOD_SUPER) ? " Super" : "");
  888. }
  889. static int printEvent(const PuglEvent* event, const char* prefix, const bool verbose)
  890. {
  891. #define FFMT "%6.1f"
  892. #define PFMT FFMT " " FFMT
  893. #define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
  894. switch (event->type) {
  895. case PUGL_NOTHING:
  896. return 0;
  897. case PUGL_KEY_PRESS:
  898. return PRINT("%sKey press code %3u key U+%04X\n",
  899. prefix,
  900. event->key.keycode,
  901. event->key.key);
  902. case PUGL_KEY_RELEASE:
  903. return PRINT("%sKey release code %3u key U+%04X\n",
  904. prefix,
  905. event->key.keycode,
  906. event->key.key);
  907. case PUGL_TEXT:
  908. return PRINT("%sText entry code %3u char U+%04X (%s)\n",
  909. prefix,
  910. event->text.keycode,
  911. event->text.character,
  912. event->text.string);
  913. case PUGL_BUTTON_PRESS:
  914. case PUGL_BUTTON_RELEASE:
  915. return (PRINT("%sMouse %u %s at " PFMT " ",
  916. prefix,
  917. event->button.button,
  918. (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ",
  919. event->button.x,
  920. event->button.y) +
  921. printModifiers(event->scroll.state));
  922. case PUGL_SCROLL:
  923. return (PRINT("%sScroll %5.1f %5.1f at " PFMT " ",
  924. prefix,
  925. event->scroll.dx,
  926. event->scroll.dy,
  927. event->scroll.x,
  928. event->scroll.y) +
  929. printModifiers(event->scroll.state));
  930. case PUGL_POINTER_IN:
  931. return PRINT("%sMouse enter at " PFMT "\n",
  932. prefix,
  933. event->crossing.x,
  934. event->crossing.y);
  935. case PUGL_POINTER_OUT:
  936. return PRINT("%sMouse leave at " PFMT "\n",
  937. prefix,
  938. event->crossing.x,
  939. event->crossing.y);
  940. case PUGL_FOCUS_IN:
  941. return PRINT("%sFocus in %i\n",
  942. prefix,
  943. event->focus.mode);
  944. case PUGL_FOCUS_OUT:
  945. return PRINT("%sFocus out %i\n",
  946. prefix,
  947. event->focus.mode);
  948. case PUGL_CLIENT:
  949. return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n",
  950. prefix,
  951. event->client.data1,
  952. event->client.data2);
  953. case PUGL_TIMER:
  954. return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id);
  955. default:
  956. break;
  957. }
  958. if (verbose) {
  959. switch (event->type) {
  960. case PUGL_CREATE:
  961. return fprintf(stderr, "%sCreate\n", prefix);
  962. case PUGL_DESTROY:
  963. return fprintf(stderr, "%sDestroy\n", prefix);
  964. case PUGL_MAP:
  965. return fprintf(stderr, "%sMap\n", prefix);
  966. case PUGL_UNMAP:
  967. return fprintf(stderr, "%sUnmap\n", prefix);
  968. case PUGL_UPDATE:
  969. return 0; // fprintf(stderr, "%sUpdate\n", prefix);
  970. case PUGL_CONFIGURE:
  971. return PRINT("%sConfigure " PFMT " " PFMT "\n",
  972. prefix,
  973. event->configure.x,
  974. event->configure.y,
  975. event->configure.width,
  976. event->configure.height);
  977. case PUGL_EXPOSE:
  978. return PRINT("%sExpose " PFMT " " PFMT "\n",
  979. prefix,
  980. event->expose.x,
  981. event->expose.y,
  982. event->expose.width,
  983. event->expose.height);
  984. case PUGL_CLOSE:
  985. return PRINT("%sClose\n", prefix);
  986. case PUGL_MOTION:
  987. return PRINT("%sMouse motion at " PFMT "\n",
  988. prefix,
  989. event->motion.x,
  990. event->motion.y);
  991. default:
  992. return PRINT("%sUnknown event type %d\n", prefix, (int)event->type);
  993. }
  994. }
  995. #undef PRINT
  996. #undef PFMT
  997. #undef FFMT
  998. return 0;
  999. }
  1000. #endif
  1001. #undef DGL_DBG
  1002. #undef DGL_DBGF
  1003. // -----------------------------------------------------------------------
  1004. END_NAMESPACE_DGL