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