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"
26 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
27 # include "../extra/Sleep.hpp"
28 // TODO import and use file browser here
30 # include "../../dgl/src/ApplicationPrivateData.hpp"
31 # include "../../dgl/src/WindowPrivateData.hpp"
32 # include "../../dgl/src/pugl.hpp"
35 #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
36 # define DISTRHO_UI_IS_STANDALONE 1
38 # define DISTRHO_UI_IS_STANDALONE 0
41 #ifdef DISTRHO_PLUGIN_TARGET_VST3
42 # define DISTRHO_UI_IS_VST3 1
44 # define DISTRHO_UI_IS_VST3 0
47 #ifdef DISTRHO_PLUGIN_TARGET_VST2
48 # undef DISTRHO_UI_USER_RESIZABLE
49 # define DISTRHO_UI_USER_RESIZABLE 0
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
;
63 explicit PluginApplication()
64 : idleCallback(nullptr),
67 void addIdleCallback(DGL_NAMESPACE::IdleCallback
* const cb
)
69 DISTRHO_SAFE_ASSERT_RETURN(cb
!= nullptr,);
70 DISTRHO_SAFE_ASSERT_RETURN(idleCallback
== nullptr,);
75 bool isQuitting() const noexcept
77 return ui
->isQuitting();
80 bool isStandalone() const noexcept
82 return DISTRHO_UI_IS_STANDALONE
;
87 while (ui
->isRunning())
90 idleCallback
->idleCallback();
93 if (! ui
->isQuitting())
97 // these are not needed
100 void triggerIdleCallbacks() {}
102 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication
)
105 class PluginApplication
: public DGL_NAMESPACE::Application
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
116 DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE
)
118 "-" DISTRHO_PLUGIN_NAME
120 setClassName(className
);
124 void triggerIdleCallbacks()
126 pData
->triggerIdleCallbacks();
129 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication
)
133 // -----------------------------------------------------------------------
134 // Plugin Window, will pass some Window events to UI
136 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
142 explicit PluginWindow(UI
* const uiPtr
, PluginApplication
& app
)
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
; }
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
176 bool receivedReshapeDuringInit
;
179 explicit PluginWindow(UI
* const uiPtr
,
180 PluginApplication
& app
,
181 const uintptr_t parentWindowHandle
,
184 const double scaleFactor
)
185 : Window(app
, parentWindowHandle
, width
, height
, scaleFactor
,
186 DISTRHO_UI_USER_RESIZABLE
, DISTRHO_UI_IS_VST3
, false),
189 receivedReshapeDuringInit(false)
191 if (pData
->view
== nullptr)
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
208 if (pData
->view
== nullptr)
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
);
238 std::vector
<DGL_NAMESPACE::ClipboardDataOffer
> getClipboardDataOfferTypes()
240 return Window::getClipboardDataOfferTypes();
244 uint32_t onClipboardDataOffer() override
246 DISTRHO_SAFE_ASSERT_RETURN(ui
!= nullptr, 0);
251 return ui
->uiClipboardDataOffer();
254 void onFocus(const bool focus
, const DGL_NAMESPACE::CrossingMode mode
) override
256 DISTRHO_SAFE_ASSERT_RETURN(ui
!= nullptr,);
261 ui
->uiFocus(focus
, mode
);
264 void onReshape(const uint width
, const uint height
) override
266 DISTRHO_SAFE_ASSERT_RETURN(ui
!= nullptr,);
270 receivedReshapeDuringInit
= true;
274 ui
->uiReshape(width
, height
);
277 void onScaleFactorChanged(const double scaleFactor
) override
279 DISTRHO_SAFE_ASSERT_RETURN(ui
!= nullptr,);
284 ui
->uiScaleFactorChanged(scaleFactor
);
287 # if DISTRHO_UI_FILE_BROWSER
288 void onFileSelected(const char* filename
) override
;
291 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow
)
293 #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
295 // -----------------------------------------------------------------------
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 // -----------------------------------------------------------------------
308 struct UI::PrivateData
{
310 PluginApplication app
;
311 ScopedPointer
<PluginWindow
> window
;
315 uint32_t parameterOffset
;
323 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
324 char* uiStateFileKeyRequest
;
328 // Ignore initial resize events while initializing
333 editParamFunc editParamCallbackFunc
;
334 setParamFunc setParamCallbackFunc
;
335 setStateFunc setStateCallbackFunc
;
336 sendNoteFunc sendNoteCallbackFunc
;
337 setSizeFunc setSizeCallbackFunc
;
338 fileRequestFunc fileRequestCallbackFunc
;
340 PrivateData() noexcept
350 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
351 uiStateFileKeyRequest(nullptr),
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;
370 #ifdef DISTRHO_PLUGIN_TARGET_LV2
371 # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
372 parameterOffset
+= 1;
374 # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
375 parameterOffset
+= 1;
379 #ifdef DISTRHO_PLUGIN_TARGET_VST3
380 parameterOffset
+= kVst3InternalParameterCount
;
384 ~PrivateData() noexcept
386 #if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
387 std::free(uiStateFileKeyRequest
);
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
);
429 static PluginWindow
& createNextWindow(UI
* ui
, uint width
, uint height
);
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);
447 snprintf(title
, sizeof(title
)-1u, DISTRHO_PLUGIN_NAME
": %s", key
);
448 title
[sizeof(title
)-1u] = '\0';
450 DGL_NAMESPACE::FileBrowserOptions opts
;
452 return window
->openFileBrowser(opts
);
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,);
469 #if DISTRHO_PLUGIN_WANT_STATE
470 if (char* const key
= ui
->uiData
->uiStateFileKeyRequest
)
472 ui
->uiData
->uiStateFileKeyRequest
= nullptr;
473 if (filename
!= nullptr)
476 ui
->setState(key
, filename
);
478 ui
->stateChanged(key
, filename
);
485 puglBackendEnter(pData
->view
);
486 ui
->uiFileBrowserSelected(filename
);
487 puglBackendLeave(pData
->view
);
491 // -----------------------------------------------------------------------
493 END_NAMESPACE_DISTRHO
495 #endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED