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.

179 lines
4.9KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 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 "ApplicationPrivateData.hpp"
  17. #include "../Window.hpp"
  18. #include "pugl.hpp"
  19. #include <ctime>
  20. START_NAMESPACE_DGL
  21. typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator;
  22. static d_ThreadHandle getCurrentThreadHandle() noexcept
  23. {
  24. #ifdef DISTRHO_OS_WINDOWS
  25. return GetCurrentThread();
  26. #else
  27. return pthread_self();
  28. #endif
  29. }
  30. static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept
  31. {
  32. #ifdef DISTRHO_OS_WINDOWS
  33. return GetCurrentThread() == mainThreadHandle; // IsGUIThread ?
  34. #else
  35. return pthread_equal(getCurrentThreadHandle(), mainThreadHandle) != 0;
  36. #endif
  37. }
  38. // --------------------------------------------------------------------------------------------------------------------
  39. const char* Application::getClassName() const noexcept
  40. {
  41. return puglGetClassName(pData->world);
  42. }
  43. // --------------------------------------------------------------------------------------------------------------------
  44. Application::PrivateData::PrivateData(const bool standalone)
  45. : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE,
  46. standalone ? PUGL_WORLD_THREADS : 0x0)),
  47. isStandalone(standalone),
  48. isQuitting(false),
  49. isQuittingInNextCycle(false),
  50. isStarting(true),
  51. visibleWindows(0),
  52. mainThreadHandle(getCurrentThreadHandle()),
  53. windows(),
  54. idleCallbacks()
  55. {
  56. DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);
  57. puglSetWorldHandle(world, this);
  58. #ifdef __EMSCRIPTEN__
  59. puglSetClassName(world, "canvas");
  60. #else
  61. puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE));
  62. #endif
  63. }
  64. Application::PrivateData::~PrivateData()
  65. {
  66. DISTRHO_SAFE_ASSERT(isStarting || isQuitting);
  67. DISTRHO_SAFE_ASSERT(visibleWindows == 0);
  68. windows.clear();
  69. idleCallbacks.clear();
  70. if (world != nullptr)
  71. puglFreeWorld(world);
  72. }
  73. // --------------------------------------------------------------------------------------------------------------------
  74. void Application::PrivateData::oneWindowShown() noexcept
  75. {
  76. if (++visibleWindows == 1)
  77. {
  78. isQuitting = false;
  79. isStarting = false;
  80. }
  81. }
  82. void Application::PrivateData::oneWindowClosed() noexcept
  83. {
  84. DISTRHO_SAFE_ASSERT_RETURN(visibleWindows != 0,);
  85. if (--visibleWindows == 0)
  86. isQuitting = true;
  87. }
  88. // --------------------------------------------------------------------------------------------------------------------
  89. void Application::PrivateData::idle(const uint timeoutInMs)
  90. {
  91. if (isQuittingInNextCycle)
  92. {
  93. quit();
  94. isQuittingInNextCycle = false;
  95. }
  96. if (world != nullptr)
  97. {
  98. const double timeoutInSeconds = timeoutInMs != 0
  99. ? static_cast<double>(timeoutInMs) / 1000.0
  100. : 0.0;
  101. puglUpdate(world, timeoutInSeconds);
  102. }
  103. triggerIdleCallbacks();
  104. }
  105. void Application::PrivateData::triggerIdleCallbacks()
  106. {
  107. for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it)
  108. {
  109. IdleCallback* const idleCallback(*it);
  110. idleCallback->idleCallback();
  111. }
  112. }
  113. void Application::PrivateData::quit()
  114. {
  115. if (! isThisTheMainThread(mainThreadHandle))
  116. {
  117. if (! isQuittingInNextCycle)
  118. {
  119. isQuittingInNextCycle = true;
  120. return;
  121. }
  122. }
  123. isQuitting = true;
  124. #ifndef DPF_TEST_APPLICATION_CPP
  125. for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit)
  126. {
  127. DGL_NAMESPACE::Window* const window(*rit);
  128. window->close();
  129. }
  130. #endif
  131. }
  132. double Application::PrivateData::getTime() const
  133. {
  134. DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, 0.0);
  135. return puglGetTime(world);
  136. }
  137. void Application::PrivateData::setClassName(const char* const name)
  138. {
  139. DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);
  140. DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  141. puglSetClassName(world, name);
  142. }
  143. // --------------------------------------------------------------------------------------------------------------------
  144. END_NAMESPACE_DGL