DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

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