Mercurial > hg > pub > prymula > com
comparison DPF-Prymula-audioplugins/dpf/distrho/src/DistrhoUIPrivateData.hpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:cf2cb71d31dd | 3:84e66ea83026 |
---|---|
1 /* | |
2 * DISTRHO Plugin Framework (DPF) | |
3 * Copyright (C) 2012-2022 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_PRIVATE_DATA_HPP_INCLUDED | |
18 #define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED | |
19 | |
20 #include "../DistrhoUI.hpp" | |
21 | |
22 #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |
23 # include "DistrhoPluginVST.hpp" | |
24 #endif | |
25 | |
26 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
27 # include "../extra/Sleep.hpp" | |
28 // TODO import and use file browser here | |
29 #else | |
30 # include "../../dgl/src/ApplicationPrivateData.hpp" | |
31 # include "../../dgl/src/WindowPrivateData.hpp" | |
32 # include "../../dgl/src/pugl.hpp" | |
33 #endif | |
34 | |
35 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
36 # include <map> | |
37 # include <string> | |
38 #endif | |
39 | |
40 #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI) | |
41 # define DISTRHO_UI_IS_STANDALONE 1 | |
42 #else | |
43 # define DISTRHO_UI_IS_STANDALONE 0 | |
44 #endif | |
45 | |
46 #if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |
47 # define DISTRHO_UI_USES_SIZE_REQUEST true | |
48 #else | |
49 # define DISTRHO_UI_USES_SIZE_REQUEST false | |
50 #endif | |
51 | |
52 #ifdef DISTRHO_PLUGIN_TARGET_VST2 | |
53 # undef DISTRHO_UI_USER_RESIZABLE | |
54 # define DISTRHO_UI_USER_RESIZABLE 0 | |
55 #endif | |
56 | |
57 START_NAMESPACE_DISTRHO | |
58 | |
59 // ----------------------------------------------------------------------- | |
60 // Plugin Application, will set class name based on plugin details | |
61 | |
62 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
63 struct PluginApplication | |
64 { | |
65 DGL_NAMESPACE::IdleCallback* idleCallback; | |
66 UI* ui; | |
67 | |
68 explicit PluginApplication(const char*) | |
69 : idleCallback(nullptr), | |
70 ui(nullptr) {} | |
71 | |
72 void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb) | |
73 { | |
74 DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |
75 DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,); | |
76 | |
77 idleCallback = cb; | |
78 } | |
79 | |
80 bool isQuitting() const noexcept | |
81 { | |
82 return ui->isQuitting(); | |
83 } | |
84 | |
85 bool isStandalone() const noexcept | |
86 { | |
87 return DISTRHO_UI_IS_STANDALONE; | |
88 } | |
89 | |
90 void exec() | |
91 { | |
92 while (ui->isRunning()) | |
93 { | |
94 d_msleep(30); | |
95 idleCallback->idleCallback(); | |
96 } | |
97 | |
98 if (! ui->isQuitting()) | |
99 ui->close(); | |
100 } | |
101 | |
102 // these are not needed | |
103 void idle() {} | |
104 void quit() {} | |
105 void triggerIdleCallbacks() {} | |
106 | |
107 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |
108 }; | |
109 #else | |
110 class PluginApplication : public DGL_NAMESPACE::Application | |
111 { | |
112 public: | |
113 explicit PluginApplication(const char* className) | |
114 : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE) | |
115 { | |
116 #if defined(__MOD_DEVICES__) || !defined(__EMSCRIPTEN__) | |
117 if (className == nullptr) | |
118 { | |
119 className = ( | |
120 #ifdef DISTRHO_PLUGIN_BRAND | |
121 DISTRHO_PLUGIN_BRAND | |
122 #else | |
123 DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) | |
124 #endif | |
125 "-" DISTRHO_PLUGIN_NAME | |
126 ); | |
127 } | |
128 setClassName(className); | |
129 #else | |
130 // unused | |
131 (void)className; | |
132 #endif | |
133 } | |
134 | |
135 void triggerIdleCallbacks() | |
136 { | |
137 pData->triggerIdleCallbacks(); | |
138 } | |
139 | |
140 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |
141 }; | |
142 #endif | |
143 | |
144 // ----------------------------------------------------------------------- | |
145 // Plugin Window, will pass some Window events to UI | |
146 | |
147 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
148 class PluginWindow | |
149 { | |
150 UI* const ui; | |
151 | |
152 public: | |
153 explicit PluginWindow(UI* const uiPtr, PluginApplication& app) | |
154 : ui(uiPtr) | |
155 { | |
156 app.ui = ui; | |
157 } | |
158 | |
159 // fetch cached data | |
160 uint getWidth() const noexcept { return ui->pData.width; } | |
161 uint getHeight() const noexcept { return ui->pData.height; } | |
162 double getScaleFactor() const noexcept { return ui->pData.scaleFactor; } | |
163 | |
164 // direct mappings | |
165 void close() { ui->close(); } | |
166 void focus() { ui->focus(); } | |
167 void show() { ui->show(); } | |
168 bool isResizable() const noexcept { return ui->isResizable(); } | |
169 bool isVisible() const noexcept { return ui->isVisible(); } | |
170 void setTitle(const char* const title) { ui->setTitle(title); } | |
171 void setVisible(const bool visible) { ui->setVisible(visible); } | |
172 uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); } | |
173 void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | |
174 { | |
175 minimumWidth = ui->pData.minWidth; | |
176 minimumHeight = ui->pData.minHeight; | |
177 keepAspectRatio = ui->pData.keepAspectRatio; | |
178 } | |
179 | |
180 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |
181 }; | |
182 #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
183 class PluginWindow : public DGL_NAMESPACE::Window | |
184 { | |
185 UI* const ui; | |
186 bool initializing; | |
187 bool receivedReshapeDuringInit; | |
188 | |
189 public: | |
190 explicit PluginWindow(UI* const uiPtr, | |
191 PluginApplication& app, | |
192 const uintptr_t parentWindowHandle, | |
193 const uint width, | |
194 const uint height, | |
195 const double scaleFactor) | |
196 : Window(app, parentWindowHandle, width, height, scaleFactor, | |
197 DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false), | |
198 ui(uiPtr), | |
199 initializing(true), | |
200 receivedReshapeDuringInit(false) | |
201 { | |
202 if (pData->view == nullptr) | |
203 return; | |
204 | |
205 // this is called just before creating UI, ensuring proper context to it | |
206 if (pData->initPost()) | |
207 puglBackendEnter(pData->view); | |
208 } | |
209 | |
210 ~PluginWindow() override | |
211 { | |
212 if (pData->view != nullptr) | |
213 puglBackendLeave(pData->view); | |
214 } | |
215 | |
216 // called after creating UI, restoring proper context | |
217 void leaveContext() | |
218 { | |
219 if (pData->view == nullptr) | |
220 return; | |
221 | |
222 if (receivedReshapeDuringInit) | |
223 ui->uiReshape(getWidth(), getHeight()); | |
224 | |
225 initializing = false; | |
226 puglBackendLeave(pData->view); | |
227 } | |
228 | |
229 // used for temporary windows (VST/CLAP get size without active/visible view) | |
230 void setIgnoreIdleCallbacks(const bool ignore = true) | |
231 { | |
232 pData->ignoreIdleCallbacks = ignore; | |
233 } | |
234 | |
235 // called right before deleting UI, ensuring correct context | |
236 void enterContextForDeletion() | |
237 { | |
238 if (pData->view != nullptr) | |
239 puglBackendEnter(pData->view); | |
240 } | |
241 | |
242 #if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |
243 void setSizeFromHost(const uint width, const uint height) | |
244 { | |
245 puglSetSizeAndDefault(pData->view, width, height); | |
246 } | |
247 #endif | |
248 | |
249 std::vector<DGL_NAMESPACE::ClipboardDataOffer> getClipboardDataOfferTypes() | |
250 { | |
251 return Window::getClipboardDataOfferTypes(); | |
252 } | |
253 | |
254 protected: | |
255 uint32_t onClipboardDataOffer() override | |
256 { | |
257 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 0); | |
258 | |
259 if (initializing) | |
260 return 0; | |
261 | |
262 return ui->uiClipboardDataOffer(); | |
263 } | |
264 | |
265 void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | |
266 { | |
267 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |
268 | |
269 if (initializing) | |
270 return; | |
271 | |
272 ui->uiFocus(focus, mode); | |
273 } | |
274 | |
275 void onReshape(const uint width, const uint height) override | |
276 { | |
277 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |
278 | |
279 if (initializing) | |
280 { | |
281 receivedReshapeDuringInit = true; | |
282 return; | |
283 } | |
284 | |
285 ui->uiReshape(width, height); | |
286 } | |
287 | |
288 void onScaleFactorChanged(const double scaleFactor) override | |
289 { | |
290 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |
291 | |
292 if (initializing) | |
293 return; | |
294 | |
295 ui->uiScaleFactorChanged(scaleFactor); | |
296 } | |
297 | |
298 # if DISTRHO_UI_FILE_BROWSER | |
299 void onFileSelected(const char* filename) override; | |
300 # endif | |
301 | |
302 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |
303 }; | |
304 #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
305 | |
306 // ----------------------------------------------------------------------- | |
307 // UI callbacks | |
308 | |
309 typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |
310 typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); | |
311 typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | |
312 typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); | |
313 typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |
314 typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |
315 | |
316 // ----------------------------------------------------------------------- | |
317 // UI private data | |
318 | |
319 struct UI::PrivateData { | |
320 // DGL | |
321 PluginApplication app; | |
322 ScopedPointer<PluginWindow> window; | |
323 | |
324 // DSP | |
325 double sampleRate; | |
326 uint32_t parameterOffset; | |
327 void* dspPtr; | |
328 | |
329 // UI | |
330 uint bgColor; | |
331 uint fgColor; | |
332 double scaleFactor; | |
333 uintptr_t winId; | |
334 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
335 char* uiStateFileKeyRequest; | |
336 std::map<std::string,std::string> lastUsedDirnames; | |
337 #endif | |
338 char* bundlePath; | |
339 | |
340 // Ignore initial resize events while initializing | |
341 bool initializing; | |
342 | |
343 // Callbacks | |
344 void* callbacksPtr; | |
345 editParamFunc editParamCallbackFunc; | |
346 setParamFunc setParamCallbackFunc; | |
347 setStateFunc setStateCallbackFunc; | |
348 sendNoteFunc sendNoteCallbackFunc; | |
349 setSizeFunc setSizeCallbackFunc; | |
350 fileRequestFunc fileRequestCallbackFunc; | |
351 | |
352 PrivateData(const char* const appClassName) noexcept | |
353 : app(appClassName), | |
354 window(nullptr), | |
355 sampleRate(0), | |
356 parameterOffset(0), | |
357 dspPtr(nullptr), | |
358 bgColor(0), | |
359 fgColor(0xffffffff), | |
360 scaleFactor(1.0), | |
361 winId(0), | |
362 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
363 uiStateFileKeyRequest(nullptr), | |
364 #endif | |
365 bundlePath(nullptr), | |
366 initializing(true), | |
367 callbacksPtr(nullptr), | |
368 editParamCallbackFunc(nullptr), | |
369 setParamCallbackFunc(nullptr), | |
370 setStateCallbackFunc(nullptr), | |
371 sendNoteCallbackFunc(nullptr), | |
372 setSizeCallbackFunc(nullptr), | |
373 fileRequestCallbackFunc(nullptr) | |
374 { | |
375 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) | |
376 parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; | |
377 #if DISTRHO_PLUGIN_WANT_LATENCY | |
378 parameterOffset += 1; | |
379 #endif | |
380 #endif | |
381 | |
382 #ifdef DISTRHO_PLUGIN_TARGET_LV2 | |
383 #if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |
384 parameterOffset += 1; | |
385 #endif | |
386 #if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | |
387 parameterOffset += 1; | |
388 #endif | |
389 #endif | |
390 | |
391 #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |
392 parameterOffset += kVst3InternalParameterCount; | |
393 #endif | |
394 } | |
395 | |
396 ~PrivateData() noexcept | |
397 { | |
398 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
399 std::free(uiStateFileKeyRequest); | |
400 #endif | |
401 std::free(bundlePath); | |
402 } | |
403 | |
404 void editParamCallback(const uint32_t rindex, const bool started) | |
405 { | |
406 if (editParamCallbackFunc != nullptr) | |
407 editParamCallbackFunc(callbacksPtr, rindex, started); | |
408 } | |
409 | |
410 void setParamCallback(const uint32_t rindex, const float value) | |
411 { | |
412 if (setParamCallbackFunc != nullptr) | |
413 setParamCallbackFunc(callbacksPtr, rindex, value); | |
414 } | |
415 | |
416 void setStateCallback(const char* const key, const char* const value) | |
417 { | |
418 if (setStateCallbackFunc != nullptr) | |
419 setStateCallbackFunc(callbacksPtr, key, value); | |
420 } | |
421 | |
422 void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |
423 { | |
424 if (sendNoteCallbackFunc != nullptr) | |
425 sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); | |
426 } | |
427 | |
428 void setSizeCallback(const uint width, const uint height) | |
429 { | |
430 if (setSizeCallbackFunc != nullptr) | |
431 setSizeCallbackFunc(callbacksPtr, width, height); | |
432 } | |
433 | |
434 // implemented below, after PluginWindow | |
435 bool fileRequestCallback(const char* const key); | |
436 | |
437 static UI::PrivateData* s_nextPrivateData; | |
438 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
439 static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); | |
440 #else | |
441 static PluginWindow& createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); | |
442 #endif | |
443 }; | |
444 | |
445 // ----------------------------------------------------------------------- | |
446 // UI private data fileRequestCallback, which requires PluginWindow definitions | |
447 | |
448 inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |
449 { | |
450 if (fileRequestCallbackFunc != nullptr) | |
451 return fileRequestCallbackFunc(callbacksPtr, key); | |
452 | |
453 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
454 std::free(uiStateFileKeyRequest); | |
455 uiStateFileKeyRequest = strdup(key); | |
456 DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false); | |
457 | |
458 char title[0xff]; | |
459 snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key); | |
460 title[sizeof(title)-1u] = '\0'; | |
461 | |
462 DGL_NAMESPACE::FileBrowserOptions opts; | |
463 opts.title = title; | |
464 if (lastUsedDirnames.count(key)) | |
465 opts.startDir = lastUsedDirnames[key].c_str(); | |
466 return window->openFileBrowser(opts); | |
467 #endif | |
468 | |
469 return false; | |
470 } | |
471 | |
472 // ----------------------------------------------------------------------- | |
473 // PluginWindow onFileSelected that require UI::PrivateData definitions | |
474 | |
475 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
476 inline void PluginWindow::onFileSelected(const char* const filename) | |
477 { | |
478 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |
479 | |
480 if (initializing) | |
481 return; | |
482 | |
483 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |
484 if (char* const key = ui->uiData->uiStateFileKeyRequest) | |
485 { | |
486 ui->uiData->uiStateFileKeyRequest = nullptr; | |
487 if (filename != nullptr) | |
488 { | |
489 // notify DSP | |
490 ui->setState(key, filename); | |
491 | |
492 // notify UI | |
493 ui->stateChanged(key, filename); | |
494 | |
495 // save dirname for next time | |
496 if (const char* const lastsep = std::strrchr(filename, DISTRHO_OS_SEP)) | |
497 ui->uiData->lastUsedDirnames[key] = std::string(filename, lastsep-filename); | |
498 } | |
499 std::free(key); | |
500 return; | |
501 } | |
502 #endif | |
503 | |
504 puglBackendEnter(pData->view); | |
505 ui->uiFileBrowserSelected(filename); | |
506 puglBackendLeave(pData->view); | |
507 } | |
508 #endif | |
509 | |
510 // ----------------------------------------------------------------------- | |
511 | |
512 END_NAMESPACE_DISTRHO | |
513 | |
514 #endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED |