Add initial bits for Qt6 support
[carla.git] / source / modules / distrho / src / DistrhoUIPrivateData.hpp
blobee4503e00fa518e674e2012f7bcaf4d049465923
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
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.
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.
17 #ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
18 #define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
20 #include "../DistrhoUI.hpp"
22 #ifdef DISTRHO_PLUGIN_TARGET_VST3
23 # include "DistrhoPluginVST.hpp"
24 #endif
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
35 #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
36 # define DISTRHO_UI_IS_STANDALONE 1
37 #else
38 # define DISTRHO_UI_IS_STANDALONE 0
39 #endif
41 #ifdef DISTRHO_PLUGIN_TARGET_VST3
42 # define DISTRHO_UI_IS_VST3 1
43 #else
44 # define DISTRHO_UI_IS_VST3 0
45 #endif
47 #ifdef DISTRHO_PLUGIN_TARGET_VST2
48 # undef DISTRHO_UI_USER_RESIZABLE
49 # define DISTRHO_UI_USER_RESIZABLE 0
50 #endif
52 START_NAMESPACE_DISTRHO
54 // -----------------------------------------------------------------------
55 // Plugin Application, will set class name based on plugin details
57 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
58 struct PluginApplication
60 DGL_NAMESPACE::IdleCallback* idleCallback;
61 UI* ui;
63 explicit PluginApplication()
64 : idleCallback(nullptr),
65 ui(nullptr) {}
67 void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb)
69 DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
70 DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,);
72 idleCallback = cb;
75 bool isQuitting() const noexcept
77 return ui->isQuitting();
80 bool isStandalone() const noexcept
82 return DISTRHO_UI_IS_STANDALONE;
85 void exec()
87 while (ui->isRunning())
89 d_msleep(30);
90 idleCallback->idleCallback();
93 if (! ui->isQuitting())
94 ui->close();
97 // these are not needed
98 void idle() {}
99 void quit() {}
100 void triggerIdleCallbacks() {}
102 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
104 #else
105 class PluginApplication : public DGL_NAMESPACE::Application
107 public:
108 explicit PluginApplication()
109 : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE)
111 #ifndef DISTRHO_OS_WASM
112 const char* const className = (
113 #ifdef DISTRHO_PLUGIN_BRAND
114 DISTRHO_PLUGIN_BRAND
115 #else
116 DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE)
117 #endif
118 "-" DISTRHO_PLUGIN_NAME
120 setClassName(className);
121 #endif
124 void triggerIdleCallbacks()
126 pData->triggerIdleCallbacks();
129 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
131 #endif
133 // -----------------------------------------------------------------------
134 // Plugin Window, will pass some Window events to UI
136 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
137 class PluginWindow
139 UI* const ui;
141 public:
142 explicit PluginWindow(UI* const uiPtr, PluginApplication& app)
143 : ui(uiPtr)
145 app.ui = ui;
148 // fetch cached data
149 uint getWidth() const noexcept { return ui->pData.width; }
150 uint getHeight() const noexcept { return ui->pData.height; }
151 double getScaleFactor() const noexcept { return ui->pData.scaleFactor; }
153 // direct mappings
154 void close() { ui->close(); }
155 void focus() { ui->focus(); }
156 void show() { ui->show(); }
157 bool isResizable() const noexcept { return ui->isResizable(); }
158 bool isVisible() const noexcept { return ui->isVisible(); }
159 void setTitle(const char* const title) { ui->setTitle(title); }
160 void setVisible(const bool visible) { ui->setVisible(visible); }
161 uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); }
162 void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
164 minimumWidth = ui->pData.minWidth;
165 minimumHeight = ui->pData.minHeight;
166 keepAspectRatio = ui->pData.keepAspectRatio;
169 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
171 #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
172 class PluginWindow : public DGL_NAMESPACE::Window
174 UI* const ui;
175 bool initializing;
176 bool receivedReshapeDuringInit;
178 public:
179 explicit PluginWindow(UI* const uiPtr,
180 PluginApplication& app,
181 const uintptr_t parentWindowHandle,
182 const uint width,
183 const uint height,
184 const double scaleFactor)
185 : Window(app, parentWindowHandle, width, height, scaleFactor,
186 DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_IS_VST3, false),
187 ui(uiPtr),
188 initializing(true),
189 receivedReshapeDuringInit(false)
191 if (pData->view == nullptr)
192 return;
194 // this is called just before creating UI, ensuring proper context to it
195 if (pData->initPost())
196 puglBackendEnter(pData->view);
199 ~PluginWindow() override
201 if (pData->view != nullptr)
202 puglBackendLeave(pData->view);
205 // called after creating UI, restoring proper context
206 void leaveContext()
208 if (pData->view == nullptr)
209 return;
211 if (receivedReshapeDuringInit)
212 ui->uiReshape(getWidth(), getHeight());
214 initializing = false;
215 puglBackendLeave(pData->view);
218 // used for temporary windows (VST2/3 get size without active/visible view)
219 void setIgnoreIdleCallbacks(const bool ignore = true)
221 pData->ignoreIdleCallbacks = ignore;
224 // called right before deleting UI, ensuring correct context
225 void enterContextForDeletion()
227 if (pData->view != nullptr)
228 puglBackendEnter(pData->view);
231 #ifdef DISTRHO_PLUGIN_TARGET_VST3
232 void setSizeForVST3(const uint width, const uint height)
234 puglSetSizeAndDefault(pData->view, width, height);
236 #endif
238 std::vector<DGL_NAMESPACE::ClipboardDataOffer> getClipboardDataOfferTypes()
240 return Window::getClipboardDataOfferTypes();
243 protected:
244 uint32_t onClipboardDataOffer() override
246 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 0);
248 if (initializing)
249 return 0;
251 return ui->uiClipboardDataOffer();
254 void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override
256 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
258 if (initializing)
259 return;
261 ui->uiFocus(focus, mode);
264 void onReshape(const uint width, const uint height) override
266 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
268 if (initializing)
270 receivedReshapeDuringInit = true;
271 return;
274 ui->uiReshape(width, height);
277 void onScaleFactorChanged(const double scaleFactor) override
279 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
281 if (initializing)
282 return;
284 ui->uiScaleFactorChanged(scaleFactor);
287 # if DISTRHO_UI_FILE_BROWSER
288 void onFileSelected(const char* filename) override;
289 # endif
291 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
293 #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
295 // -----------------------------------------------------------------------
296 // UI callbacks
298 typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
299 typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value);
300 typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
301 typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
302 typedef void (*setSizeFunc) (void* ptr, uint width, uint height);
303 typedef bool (*fileRequestFunc) (void* ptr, const char* key);
305 // -----------------------------------------------------------------------
306 // UI private data
308 struct UI::PrivateData {
309 // DGL
310 PluginApplication app;
311 ScopedPointer<PluginWindow> window;
313 // DSP
314 double sampleRate;
315 uint32_t parameterOffset;
316 void* dspPtr;
318 // UI
319 uint bgColor;
320 uint fgColor;
321 double scaleFactor;
322 uintptr_t winId;
323 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
324 char* uiStateFileKeyRequest;
325 #endif
326 char* bundlePath;
328 // Ignore initial resize events while initializing
329 bool initializing;
331 // Callbacks
332 void* callbacksPtr;
333 editParamFunc editParamCallbackFunc;
334 setParamFunc setParamCallbackFunc;
335 setStateFunc setStateCallbackFunc;
336 sendNoteFunc sendNoteCallbackFunc;
337 setSizeFunc setSizeCallbackFunc;
338 fileRequestFunc fileRequestCallbackFunc;
340 PrivateData() noexcept
341 : app(),
342 window(nullptr),
343 sampleRate(0),
344 parameterOffset(0),
345 dspPtr(nullptr),
346 bgColor(0),
347 fgColor(0xffffffff),
348 scaleFactor(1.0),
349 winId(0),
350 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
351 uiStateFileKeyRequest(nullptr),
352 #endif
353 bundlePath(nullptr),
354 initializing(true),
355 callbacksPtr(nullptr),
356 editParamCallbackFunc(nullptr),
357 setParamCallbackFunc(nullptr),
358 setStateCallbackFunc(nullptr),
359 sendNoteCallbackFunc(nullptr),
360 setSizeCallbackFunc(nullptr),
361 fileRequestCallbackFunc(nullptr)
363 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
364 parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
365 # if DISTRHO_PLUGIN_WANT_LATENCY
366 parameterOffset += 1;
367 # endif
368 #endif
370 #ifdef DISTRHO_PLUGIN_TARGET_LV2
371 # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
372 parameterOffset += 1;
373 # endif
374 # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
375 parameterOffset += 1;
376 # endif
377 #endif
379 #ifdef DISTRHO_PLUGIN_TARGET_VST3
380 parameterOffset += kVst3InternalParameterCount;
381 #endif
384 ~PrivateData() noexcept
386 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
387 std::free(uiStateFileKeyRequest);
388 #endif
389 std::free(bundlePath);
392 void editParamCallback(const uint32_t rindex, const bool started)
394 if (editParamCallbackFunc != nullptr)
395 editParamCallbackFunc(callbacksPtr, rindex, started);
398 void setParamCallback(const uint32_t rindex, const float value)
400 if (setParamCallbackFunc != nullptr)
401 setParamCallbackFunc(callbacksPtr, rindex, value);
404 void setStateCallback(const char* const key, const char* const value)
406 if (setStateCallbackFunc != nullptr)
407 setStateCallbackFunc(callbacksPtr, key, value);
410 void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
412 if (sendNoteCallbackFunc != nullptr)
413 sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
416 void setSizeCallback(const uint width, const uint height)
418 if (setSizeCallbackFunc != nullptr)
419 setSizeCallbackFunc(callbacksPtr, width, height);
422 // implemented below, after PluginWindow
423 bool fileRequestCallback(const char* const key);
425 static UI::PrivateData* s_nextPrivateData;
426 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
427 static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height);
428 #else
429 static PluginWindow& createNextWindow(UI* ui, uint width, uint height);
430 #endif
433 // -----------------------------------------------------------------------
434 // UI private data fileRequestCallback, which requires PluginWindow definitions
436 inline bool UI::PrivateData::fileRequestCallback(const char* const key)
438 if (fileRequestCallbackFunc != nullptr)
439 return fileRequestCallbackFunc(callbacksPtr, key);
441 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
442 std::free(uiStateFileKeyRequest);
443 uiStateFileKeyRequest = strdup(key);
444 DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false);
446 char title[0xff];
447 snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key);
448 title[sizeof(title)-1u] = '\0';
450 DGL_NAMESPACE::FileBrowserOptions opts;
451 opts.title = title;
452 return window->openFileBrowser(opts);
453 #endif
455 return false;
458 // -----------------------------------------------------------------------
459 // PluginWindow onFileSelected that require UI::PrivateData definitions
461 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
462 inline void PluginWindow::onFileSelected(const char* const filename)
464 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
466 if (initializing)
467 return;
469 #if DISTRHO_PLUGIN_WANT_STATE
470 if (char* const key = ui->uiData->uiStateFileKeyRequest)
472 ui->uiData->uiStateFileKeyRequest = nullptr;
473 if (filename != nullptr)
475 // notify DSP
476 ui->setState(key, filename);
477 // notify UI
478 ui->stateChanged(key, filename);
480 std::free(key);
481 return;
483 #endif
485 puglBackendEnter(pData->view);
486 ui->uiFileBrowserSelected(filename);
487 puglBackendLeave(pData->view);
489 #endif
491 // -----------------------------------------------------------------------
493 END_NAMESPACE_DISTRHO
495 #endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED