ApplicationPrivateData.cpp (5656B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2024 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 17 #include "ApplicationPrivateData.hpp" 18 #include "../Window.hpp" 19 20 #include "pugl.hpp" 21 22 #include <ctime> 23 24 START_NAMESPACE_DGL 25 26 typedef std::list<DGL_NAMESPACE::Window*>::iterator WindowListIterator; 27 typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator; 28 29 static d_ThreadHandle getCurrentThreadHandle() noexcept 30 { 31 #ifdef DISTRHO_OS_WINDOWS 32 return GetCurrentThread(); 33 #else 34 return pthread_self(); 35 #endif 36 } 37 38 static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept 39 { 40 #ifdef DISTRHO_OS_WINDOWS 41 return GetCurrentThread() == mainThreadHandle; // IsGUIThread ? 42 #else 43 return pthread_equal(getCurrentThreadHandle(), mainThreadHandle) != 0; 44 #endif 45 } 46 47 // -------------------------------------------------------------------------------------------------------------------- 48 49 const char* Application::getClassName() const noexcept 50 { 51 return puglGetWorldString(pData->world, PUGL_CLASS_NAME); 52 } 53 54 // -------------------------------------------------------------------------------------------------------------------- 55 56 Application::PrivateData::PrivateData(const bool standalone) 57 : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, 58 standalone ? PUGL_WORLD_THREADS : 0x0)), 59 isStandalone(standalone), 60 isQuitting(false), 61 isQuittingInNextCycle(false), 62 isStarting(true), 63 needsRepaint(false), 64 visibleWindows(0), 65 mainThreadHandle(getCurrentThreadHandle()), 66 windows(), 67 idleCallbacks() 68 { 69 DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); 70 71 #ifdef DGL_USING_SDL 72 SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO); 73 #else 74 puglSetWorldHandle(world, this); 75 #ifdef __EMSCRIPTEN__ 76 puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); 77 #else 78 puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); 79 #endif 80 #endif 81 } 82 83 Application::PrivateData::~PrivateData() 84 { 85 DISTRHO_SAFE_ASSERT(isStarting || isQuitting); 86 DISTRHO_SAFE_ASSERT(visibleWindows == 0); 87 88 windows.clear(); 89 idleCallbacks.clear(); 90 91 #ifdef DGL_USING_SDL 92 SDL_Quit(); 93 #else 94 if (world != nullptr) 95 puglFreeWorld(world); 96 #endif 97 } 98 99 // -------------------------------------------------------------------------------------------------------------------- 100 101 void Application::PrivateData::oneWindowShown() noexcept 102 { 103 if (++visibleWindows == 1) 104 { 105 isQuitting = false; 106 isStarting = false; 107 } 108 } 109 110 void Application::PrivateData::oneWindowClosed() noexcept 111 { 112 DISTRHO_SAFE_ASSERT_RETURN(visibleWindows != 0,); 113 114 if (--visibleWindows == 0) 115 isQuitting = true; 116 } 117 118 // -------------------------------------------------------------------------------------------------------------------- 119 120 void Application::PrivateData::idle(const uint timeoutInMs) 121 { 122 if (isQuittingInNextCycle) 123 { 124 quit(); 125 isQuittingInNextCycle = false; 126 } 127 128 if (world != nullptr) 129 { 130 const double timeoutInSeconds = timeoutInMs != 0 131 ? static_cast<double>(timeoutInMs) / 1000.0 132 : 0.0; 133 134 puglUpdate(world, timeoutInSeconds); 135 } 136 137 triggerIdleCallbacks(); 138 } 139 140 void Application::PrivateData::triggerIdleCallbacks() 141 { 142 for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) 143 { 144 IdleCallback* const idleCallback(*it); 145 idleCallback->idleCallback(); 146 } 147 } 148 149 void Application::PrivateData::repaintIfNeeeded() 150 { 151 if (needsRepaint) 152 { 153 needsRepaint = false; 154 155 for (WindowListIterator it = windows.begin(), ite = windows.end(); it != ite; ++it) 156 { 157 DGL_NAMESPACE::Window* const window(*it); 158 window->repaint(); 159 } 160 } 161 } 162 163 void Application::PrivateData::quit() 164 { 165 if (! isThisTheMainThread(mainThreadHandle)) 166 { 167 if (! isQuittingInNextCycle) 168 { 169 isQuittingInNextCycle = true; 170 return; 171 } 172 } 173 174 isQuitting = true; 175 176 #ifndef DPF_TEST_APPLICATION_CPP 177 for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit) 178 { 179 DGL_NAMESPACE::Window* const window(*rit); 180 window->close(); 181 } 182 #endif 183 } 184 185 double Application::PrivateData::getTime() const 186 { 187 return world != nullptr ? puglGetTime(world) : 0.0; 188 } 189 190 void Application::PrivateData::setClassName(const char* const name) 191 { 192 DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); 193 194 if (world != nullptr) 195 puglSetWorldString(world, PUGL_CLASS_NAME, name); 196 } 197 198 // -------------------------------------------------------------------------------------------------------------------- 199 200 END_NAMESPACE_DGL