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.

302 lines
6.8KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2014 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. #ifndef DGL_NTK_APP_HPP_INCLUDED
  17. #define DGL_NTK_APP_HPP_INCLUDED
  18. #include "../Base.hpp"
  19. #include "../../distrho/DistrhoUI.hpp"
  20. #include "../../distrho/extra/d_thread.hpp"
  21. #ifdef override
  22. # define override_defined
  23. # undef override
  24. #endif
  25. #include <list>
  26. #include <FL/Fl.H>
  27. #include <FL/Fl_Double_Window.H>
  28. #include <FL/Fl_Shared_Image.H>
  29. #include <FL/x.H>
  30. #ifdef override_defined
  31. # define override
  32. # undef override_defined
  33. #endif
  34. // Is this really needed?
  35. // fails on renoise
  36. struct ScopedDisplayLock {
  37. ScopedDisplayLock()
  38. {
  39. #if 0 //def DISTRHO_OS_LINUX
  40. XLockDisplay(fl_display);
  41. #endif
  42. }
  43. ~ScopedDisplayLock()
  44. {
  45. #if 0 //def DISTRHO_OS_LINUX
  46. XUnlockDisplay(fl_display);
  47. #endif
  48. }
  49. };
  50. // -----------------------------------------------------------------------
  51. namespace DISTRHO_NAMESPACE {
  52. class UI;
  53. }
  54. START_NAMESPACE_DGL
  55. class NtkWindow;
  56. typedef DISTRHO_NAMESPACE::Mutex d_Mutex;
  57. typedef DISTRHO_NAMESPACE::MutexLocker d_MutexLocker;
  58. typedef DISTRHO_NAMESPACE::Thread d_Thread;
  59. typedef DISTRHO_NAMESPACE::UI d_UI;
  60. // -----------------------------------------------------------------------
  61. /**
  62. DGL compatible App class that uses NTK instead of OpenGL.
  63. @see App
  64. */
  65. class NtkApp : d_Thread
  66. {
  67. public:
  68. /**
  69. Constructor.
  70. */
  71. NtkApp()
  72. : d_Thread("NtkApp"),
  73. fWindows(),
  74. fWindowMutex(),
  75. fNextUI(),
  76. fDoNextUI(false),
  77. fThreadInitialized(false)
  78. {
  79. #ifdef DISTRHO_OS_LINUX
  80. //XInitThreads();
  81. #endif
  82. startThread();
  83. for (; ! fThreadInitialized;)
  84. d_msleep(10);
  85. }
  86. /**
  87. Destructor.
  88. */
  89. ~NtkApp()
  90. {
  91. stopThread(-1);
  92. fWindows.clear();
  93. }
  94. /**
  95. Idle function.
  96. This calls does nothing.
  97. */
  98. void idle() {}
  99. /**
  100. Run the application event-loop until all Windows are closed.
  101. @note: This function is meant for standalones only, *never* call this from plugins.
  102. */
  103. void exec()
  104. {
  105. while (isThreadRunning() && ! shouldThreadExit())
  106. d_sleep(1);
  107. }
  108. /**
  109. Quit the application.
  110. This stops the event-loop and closes all Windows.
  111. */
  112. void quit()
  113. {
  114. signalThreadShouldExit();
  115. }
  116. /**
  117. Check if the application is about to quit.
  118. Returning true means there's no event-loop running at the moment.
  119. */
  120. bool isQuiting() const noexcept
  121. {
  122. if (isThreadRunning() && ! shouldThreadExit())
  123. return false;
  124. return true;
  125. }
  126. // -------------------------------------------------------------------
  127. /**
  128. Create UI on our separate thread.
  129. Blocks until the UI is created and returns it.
  130. */
  131. d_UI* createUI(void* const func)
  132. {
  133. DISTRHO_SAFE_ASSERT_RETURN(isThreadRunning(), nullptr);
  134. DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI, nullptr);
  135. fNextUI.create = true;
  136. fNextUI.func = (NextUI::UiFunc)func;
  137. fDoNextUI = true;
  138. if (isThreadRunning() && ! shouldThreadExit())
  139. {
  140. for (; fDoNextUI;)
  141. d_msleep(10);
  142. }
  143. else
  144. {
  145. fNextUI.run();
  146. fDoNextUI = false;
  147. }
  148. return fNextUI.ui;
  149. }
  150. /**
  151. Delete UI on our separate thread.
  152. Blocks until the UI is deleted.
  153. */
  154. void deleteUI(d_UI* const ui)
  155. {
  156. DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI,);
  157. fNextUI.create = false;
  158. fNextUI.ui = ui;
  159. fDoNextUI = true;
  160. if (isThreadRunning() && ! shouldThreadExit())
  161. {
  162. for (; fDoNextUI;)
  163. d_msleep(10);
  164. }
  165. else
  166. {
  167. fNextUI.run();
  168. fDoNextUI = false;
  169. }
  170. }
  171. // -------------------------------------------------------------------
  172. private:
  173. struct NextUI {
  174. typedef d_UI* (*UiFunc)();
  175. bool create;
  176. union {
  177. UiFunc func;
  178. d_UI* ui;
  179. };
  180. NextUI()
  181. : create(false),
  182. func(nullptr) {}
  183. void run();
  184. };
  185. std::list<Fl_Double_Window*> fWindows;
  186. d_Mutex fWindowMutex;
  187. NextUI fNextUI;
  188. volatile bool fDoNextUI;
  189. volatile bool fThreadInitialized;
  190. /** @internal used by NtkWindow. */
  191. void addWindow(Fl_Double_Window* const window)
  192. {
  193. DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
  194. if (fWindows.size() == 0 && ! isThreadRunning())
  195. startThread();
  196. const d_MutexLocker sl(fWindowMutex);
  197. fWindows.push_back(window);
  198. }
  199. /** @internal used by NtkWindow. */
  200. void removeWindow(Fl_Double_Window* const window)
  201. {
  202. DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
  203. const d_MutexLocker sl(fWindowMutex);
  204. fWindows.remove(window);
  205. if (fWindows.size() == 0)
  206. signalThreadShouldExit();
  207. }
  208. /** @internal */
  209. void run() override
  210. {
  211. static bool initialized = false;
  212. if (! initialized)
  213. {
  214. initialized = true;
  215. fl_register_images();
  216. #ifdef DISTRHO_OS_LINUX
  217. fl_open_display();
  218. #endif
  219. }
  220. fThreadInitialized = true;
  221. for (; ! shouldThreadExit();)
  222. {
  223. if (fDoNextUI)
  224. {
  225. const ScopedDisplayLock csdl;
  226. fNextUI.run();
  227. fDoNextUI = false;
  228. }
  229. const ScopedDisplayLock csdl;
  230. Fl::check();
  231. Fl::flush();
  232. d_msleep(20);
  233. }
  234. const d_MutexLocker sl(fWindowMutex);
  235. const ScopedDisplayLock csdl;
  236. for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit)
  237. {
  238. Fl_Double_Window* const window(*rit);
  239. window->hide();
  240. }
  241. }
  242. friend class NtkWindow;
  243. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp)
  244. };
  245. // -----------------------------------------------------------------------
  246. END_NAMESPACE_DGL
  247. #endif // DGL_NTK_APP_HPP_INCLUDED