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