DPF

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

DistrhoUIInternal.hpp (11694B)


      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 #ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED
     18 #define DISTRHO_UI_INTERNAL_HPP_INCLUDED
     19 
     20 #include "DistrhoUIPrivateData.hpp"
     21 
     22 START_NAMESPACE_DISTRHO
     23 
     24 // -----------------------------------------------------------------------
     25 // Static data, see DistrhoUI.cpp
     26 
     27 extern const char* g_nextBundlePath;
     28 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
     29 extern uintptr_t   g_nextWindowId;
     30 extern double      g_nextScaleFactor;
     31 #endif
     32 
     33 // -----------------------------------------------------------------------
     34 // UI exporter class
     35 
     36 class UIExporter
     37 {
     38     // -------------------------------------------------------------------
     39     // UI Widget and its private data
     40 
     41     UI* ui;
     42     UI::PrivateData* uiData;
     43 
     44     // -------------------------------------------------------------------
     45 
     46 public:
     47     UIExporter(void* const callbacksPtr,
     48                const uintptr_t winId,
     49                const double sampleRate,
     50                const editParamFunc editParamCall,
     51                const setParamFunc setParamCall,
     52                const setStateFunc setStateCall,
     53                const sendNoteFunc sendNoteCall,
     54                const setSizeFunc setSizeCall,
     55                const fileRequestFunc fileRequestCall,
     56                const char* const bundlePath = nullptr,
     57                void* const dspPtr = nullptr,
     58                const double scaleFactor = 0.0,
     59                const uint32_t bgColor = 0,
     60                const uint32_t fgColor = 0xffffffff,
     61                const char* const appClassName = nullptr)
     62         : ui(nullptr),
     63           uiData(new UI::PrivateData(appClassName))
     64     {
     65         uiData->sampleRate = sampleRate;
     66         uiData->bundlePath = bundlePath != nullptr ? strdup(bundlePath) : nullptr;
     67         uiData->dspPtr = dspPtr;
     68 
     69         uiData->bgColor = bgColor;
     70         uiData->fgColor = fgColor;
     71         uiData->scaleFactor = scaleFactor;
     72         uiData->winId = winId;
     73 
     74         uiData->callbacksPtr            = callbacksPtr;
     75         uiData->editParamCallbackFunc   = editParamCall;
     76         uiData->setParamCallbackFunc    = setParamCall;
     77         uiData->setStateCallbackFunc    = setStateCall;
     78         uiData->sendNoteCallbackFunc    = sendNoteCall;
     79         uiData->setSizeCallbackFunc     = setSizeCall;
     80         uiData->fileRequestCallbackFunc = fileRequestCall;
     81 
     82         g_nextBundlePath  = bundlePath;
     83 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
     84         g_nextWindowId    = winId;
     85         g_nextScaleFactor = scaleFactor;
     86 #endif
     87         UI::PrivateData::s_nextPrivateData = uiData;
     88 
     89         UI* const uiPtr = createUI();
     90 
     91         g_nextBundlePath  = nullptr;
     92 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
     93         g_nextWindowId    = 0;
     94         g_nextScaleFactor = 0.0;
     95 #else
     96         // enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
     97         uiData->window->leaveContext();
     98 #endif
     99         UI::PrivateData::s_nextPrivateData = nullptr;
    100 
    101         DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
    102         ui = uiPtr;
    103         uiData->initializing = false;
    104 
    105 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    106         // unused
    107         (void)bundlePath;
    108 #endif
    109     }
    110 
    111     ~UIExporter()
    112     {
    113         quit();
    114 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    115         uiData->window->enterContextForDeletion();
    116 #endif
    117         delete ui;
    118         delete uiData;
    119     }
    120 
    121     // -------------------------------------------------------------------
    122 
    123     uint getWidth() const noexcept
    124     {
    125         return uiData->window->getWidth();
    126     }
    127 
    128     uint getHeight() const noexcept
    129     {
    130         return uiData->window->getHeight();
    131     }
    132 
    133     double getScaleFactor() const noexcept
    134     {
    135         return uiData->window->getScaleFactor();
    136     }
    137 
    138     bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
    139     {
    140 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    141         uiData->window->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio);
    142 #else
    143         const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio));
    144         minimumWidth = size.getWidth();
    145         minimumHeight = size.getHeight();
    146 #endif
    147         return true;
    148     }
    149 
    150     bool isResizable() const noexcept
    151     {
    152         return uiData->window->isResizable();
    153     }
    154 
    155     bool isVisible() const noexcept
    156     {
    157         return uiData->window->isVisible();
    158     }
    159 
    160     uintptr_t getNativeWindowHandle() const noexcept
    161     {
    162         return uiData->window->getNativeWindowHandle();
    163     }
    164 
    165     uint getBackgroundColor() const noexcept
    166     {
    167         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
    168 
    169         return uiData->bgColor;
    170     }
    171 
    172     uint getForegroundColor() const noexcept
    173     {
    174         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0xffffffff);
    175 
    176         return uiData->fgColor;
    177     }
    178 
    179     // -------------------------------------------------------------------
    180 
    181     uint32_t getParameterOffset() const noexcept
    182     {
    183         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr, 0);
    184 
    185         return uiData->parameterOffset;
    186     }
    187 
    188     // -------------------------------------------------------------------
    189 
    190     void parameterChanged(const uint32_t index, const float value)
    191     {
    192         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    193 
    194         ui->parameterChanged(index, value);
    195     }
    196 
    197    #if DISTRHO_PLUGIN_WANT_PROGRAMS
    198     void programLoaded(const uint32_t index)
    199     {
    200         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    201 
    202         ui->programLoaded(index);
    203     }
    204    #endif
    205 
    206    #if DISTRHO_PLUGIN_WANT_STATE
    207     void stateChanged(const char* const key, const char* const value)
    208     {
    209         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    210         DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
    211         DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
    212 
    213         ui->stateChanged(key, value);
    214     }
    215    #endif
    216 
    217     // -------------------------------------------------------------------
    218 
    219    #if DISTRHO_UI_IS_STANDALONE
    220     void exec(DGL_NAMESPACE::IdleCallback* const cb)
    221     {
    222         DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
    223 
    224         uiData->window->show();
    225         uiData->window->focus();
    226         uiData->app.addIdleCallback(cb);
    227         uiData->app.exec();
    228     }
    229 
    230     void exec_idle()
    231     {
    232         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );
    233 
    234         ui->uiIdle();
    235         uiData->app.repaintIfNeeeded();
    236     }
    237 
    238     void showAndFocus()
    239     {
    240         uiData->window->show();
    241         uiData->window->focus();
    242     }
    243    #endif
    244 
    245     bool plugin_idle()
    246     {
    247         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);
    248 
    249         uiData->app.idle();
    250         ui->uiIdle();
    251         uiData->app.repaintIfNeeeded();
    252         return ! uiData->app.isQuitting();
    253     }
    254 
    255     void focus()
    256     {
    257         uiData->window->focus();
    258     }
    259 
    260     void quit()
    261     {
    262         uiData->window->close();
    263         uiData->app.quit();
    264     }
    265 
    266    #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    267     void repaint()
    268     {
    269         uiData->window->repaint();
    270     }
    271    #endif
    272 
    273     // -------------------------------------------------------------------
    274 
    275   #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)
    276     void idleFromNativeIdle()
    277     {
    278         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    279 
    280         uiData->app.triggerIdleCallbacks();
    281         ui->uiIdle();
    282         uiData->app.repaintIfNeeeded();
    283     }
    284 
    285    #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    286     void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs)
    287     {
    288         uiData->window->addIdleCallback(cb, timerFrequencyInMs);
    289     }
    290 
    291     void removeIdleCallbackForNativeIdle(IdleCallback* const cb)
    292     {
    293         uiData->window->removeIdleCallback(cb);
    294     }
    295    #endif
    296   #endif
    297 
    298     // -------------------------------------------------------------------
    299 
    300     void setWindowOffset(const int x, const int y)
    301     {
    302        #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    303         // TODO
    304         (void)x; (void)y;
    305        #else
    306         uiData->window->setOffset(x, y);
    307        #endif
    308     }
    309 
    310    #if DISTRHO_UI_USES_SIZE_REQUEST
    311     void setWindowSizeFromHost(const uint width, const uint height)
    312     {
    313        #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    314         ui->setSize(width, height);
    315        #else
    316         uiData->window->setSizeFromHost(width, height);
    317        #endif
    318     }
    319    #endif
    320 
    321     void setWindowTitle(const char* const uiTitle)
    322     {
    323         uiData->window->setTitle(uiTitle);
    324     }
    325 
    326     void setWindowTransientWinId(const uintptr_t transientParentWindowHandle)
    327     {
    328 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    329         ui->setTransientWindowId(transientParentWindowHandle);
    330 #else
    331         uiData->window->setTransientParent(transientParentWindowHandle);
    332 #endif
    333     }
    334 
    335     bool setWindowVisible(const bool yesNo)
    336     {
    337         uiData->window->setVisible(yesNo);
    338 
    339         return ! uiData->app.isQuitting();
    340     }
    341 
    342 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    343     bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods)
    344     {
    345         using namespace DGL_NAMESPACE;
    346 
    347         Widget::KeyboardEvent ev;
    348         ev.mod     = mods;
    349         ev.press   = press;
    350         ev.key     = keychar;
    351         ev.keycode = keycode;
    352 
    353         // keyboard events must always be lowercase
    354         if (ev.key >= 'A' && ev.key <= 'Z')
    355             ev.key += 'a' - 'A'; // A-Z -> a-z
    356 
    357         const bool ret = ui->onKeyboard(ev);
    358 
    359         if (press && !special && (mods & (kModifierControl|kModifierAlt|kModifierSuper)) == 0)
    360         {
    361             Widget::CharacterInputEvent cev;
    362             cev.mod       = mods;
    363             cev.character = keychar;
    364             cev.keycode   = keycode;
    365 
    366             // if shift modifier is on, convert a-z -> A-Z for character input
    367             if (cev.character >= 'a' && cev.character <= 'z' && (mods & kModifierShift) != 0)
    368                 cev.character -= 'a' - 'A';
    369 
    370             ui->onCharacterInput(cev);
    371         }
    372 
    373         return ret;
    374     }
    375 #endif
    376 
    377     // -------------------------------------------------------------------
    378 
    379     void notifyScaleFactorChanged(const double scaleFactor)
    380     {
    381         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    382 
    383         ui->uiScaleFactorChanged(scaleFactor);
    384     }
    385 
    386 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    387     void notifyFocusChanged(const bool focus)
    388     {
    389         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    390 
    391         ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal);
    392     }
    393 #endif
    394 
    395     void setSampleRate(const double sampleRate, const bool doCallback = false)
    396     {
    397         DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
    398         DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,);
    399         DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
    400 
    401         if (d_isEqual(uiData->sampleRate, sampleRate))
    402             return;
    403 
    404         uiData->sampleRate = sampleRate;
    405 
    406         if (doCallback)
    407             ui->sampleRateChanged(sampleRate);
    408     }
    409 
    410     DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
    411 };
    412 
    413 // -----------------------------------------------------------------------
    414 
    415 END_NAMESPACE_DISTRHO
    416 
    417 #endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED