1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2020 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 #include "DistrhoUIInternal.hpp"
18
19 #include "../extra/String.hpp"
20
21 #include "lv2/atom.h"
22 #include "lv2/atom-util.h"
23 #include "lv2/data-access.h"
24 #include "lv2/instance-access.h"
25 #include "lv2/midi.h"
26 #include "lv2/options.h"
27 #include "lv2/parameters.h"
28 #include "lv2/patch.h"
29 #include "lv2/ui.h"
30 #include "lv2/urid.h"
31 #include "lv2/lv2_kxstudio_properties.h"
32 #include "lv2/lv2_programs.h"
33
34 #ifndef DISTRHO_PLUGIN_LV2_STATE_PREFIX
35 # define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:"
36 #endif
37
38 START_NAMESPACE_DISTRHO
39
40 typedef struct _LV2_Atom_MidiEvent {
41 LV2_Atom atom; /**< Atom header. */
42 uint8_t data[3]; /**< MIDI data (body). */
43 } LV2_Atom_MidiEvent;
44
45 #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
46 static const sendNoteFunc sendNoteCallback = nullptr;
47 #endif
48
49 // -----------------------------------------------------------------------
50
51 template <class LV2F>
getLv2Feature(const LV2_Feature * const * features,const char * const uri)52 static const LV2F* getLv2Feature(const LV2_Feature* const* features, const char* const uri)
53 {
54 for (int i=0; features[i] != nullptr; ++i)
55 {
56 if (std::strcmp(features[i]->URI, uri) == 0)
57 return (const LV2F*)features[i]->data;
58 }
59
60 return nullptr;
61 }
62
63 class UiLv2
64 {
65 public:
UiLv2(const char * const bundlePath,const intptr_t winId,const LV2_Options_Option * options,const LV2_URID_Map * const uridMap,const LV2_Feature * const * const features,const LV2UI_Controller controller,const LV2UI_Write_Function writeFunc,LV2UI_Widget * const widget,void * const dspPtr,const float scaleFactor,const uint32_t bgColor,const uint32_t fgColor)66 UiLv2(const char* const bundlePath,
67 const intptr_t winId,
68 const LV2_Options_Option* options,
69 const LV2_URID_Map* const uridMap,
70 const LV2_Feature* const* const features,
71 const LV2UI_Controller controller,
72 const LV2UI_Write_Function writeFunc,
73 LV2UI_Widget* const widget,
74 void* const dspPtr,
75 const float scaleFactor,
76 const uint32_t bgColor,
77 const uint32_t fgColor)
78 : fUI(this, winId,
79 editParameterCallback,
80 setParameterCallback,
81 setStateCallback,
82 sendNoteCallback,
83 setSizeCallback,
84 fileRequestCallback,
85 bundlePath,
86 dspPtr,
87 scaleFactor,
88 bgColor,
89 fgColor),
90 fUridMap(uridMap),
91 fUiRequestValue(getLv2Feature<LV2UI_Request_Value>(features, LV2_UI__requestValue)),
92 fUiResize(getLv2Feature<LV2UI_Resize>(features, LV2_UI__resize)),
93 fUiTouch(getLv2Feature<LV2UI_Touch>(features, LV2_UI__touch)),
94 fController(controller),
95 fWriteFunction(writeFunc),
96 fURIDs(uridMap),
97 fWinIdWasNull(winId == 0)
98 {
99 if (fUiResize != nullptr && winId != 0)
100 fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight());
101
102 if (widget != nullptr)
103 *widget = (LV2UI_Widget)fUI.getWindowId();
104
105 #if DISTRHO_PLUGIN_WANT_STATE
106 // tell the DSP we're ready to receive msgs
107 setState("__dpf_ui_data__", "");
108 #endif
109
110 if (winId != 0)
111 return;
112
113 // if winId == 0 then options must not be null
114 DISTRHO_SAFE_ASSERT_RETURN(options != nullptr,);
115
116 const LV2_URID uridWindowTitle = uridMap->map(uridMap->handle, LV2_UI__windowTitle);
117 const LV2_URID uridTransientWinId = uridMap->map(uridMap->handle, LV2_KXSTUDIO_PROPERTIES__TransientWindowId);
118
119 bool hasTitle = false;
120
121 for (int i=0; options[i].key != 0; ++i)
122 {
123 if (options[i].key == uridTransientWinId)
124 {
125 if (options[i].type == fURIDs.atomLong)
126 {
127 if (const int64_t transientWinId = *(const int64_t*)options[i].value)
128 fUI.setWindowTransientWinId(static_cast<intptr_t>(transientWinId));
129 }
130 else
131 d_stderr("Host provides transientWinId but has wrong value type");
132 }
133 else if (options[i].key == uridWindowTitle)
134 {
135 if (options[i].type == fURIDs.atomString)
136 {
137 if (const char* const windowTitle = (const char*)options[i].value)
138 {
139 hasTitle = true;
140 fUI.setWindowTitle(windowTitle);
141 }
142 }
143 else
144 d_stderr("Host provides windowTitle but has wrong value type");
145 }
146 }
147
148 if (! hasTitle)
149 fUI.setWindowTitle(DISTRHO_PLUGIN_NAME);
150 }
151
152 // -------------------------------------------------------------------
153
lv2ui_port_event(const uint32_t rindex,const uint32_t bufferSize,const uint32_t format,const void * const buffer)154 void lv2ui_port_event(const uint32_t rindex, const uint32_t bufferSize, const uint32_t format, const void* const buffer)
155 {
156 if (format == 0)
157 {
158 const uint32_t parameterOffset = fUI.getParameterOffset();
159
160 if (rindex < parameterOffset)
161 return;
162
163 DISTRHO_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),)
164
165 const float value = *(const float*)buffer;
166 fUI.parameterChanged(rindex-parameterOffset, value);
167 }
168 #if DISTRHO_PLUGIN_WANT_STATE
169 else if (format == fURIDs.atomEventTransfer)
170 {
171 const LV2_Atom* const atom = (const LV2_Atom*)buffer;
172
173 if (atom->type == fURIDs.dpfKeyValue)
174 {
175 const char* const key = (const char*)LV2_ATOM_BODY_CONST(atom);
176 const char* const value = key+(std::strlen(key)+1);
177
178 fUI.stateChanged(key, value);
179 }
180 else
181 {
182 d_stdout("received atom not dpfKeyValue");
183 }
184 }
185 #endif
186 }
187
188 // -------------------------------------------------------------------
189
lv2ui_idle()190 int lv2ui_idle()
191 {
192 if (fWinIdWasNull)
193 return (fUI.idle() && fUI.isVisible()) ? 0 : 1;
194
195 return fUI.idle() ? 0 : 1;
196 }
197
lv2ui_show()198 int lv2ui_show()
199 {
200 return fUI.setWindowVisible(true) ? 0 : 1;
201 }
202
lv2ui_hide()203 int lv2ui_hide()
204 {
205 return fUI.setWindowVisible(false) ? 0 : 1;
206 }
207
lv2ui_resize(uint width,uint height)208 int lv2ui_resize(uint width, uint height)
209 {
210 fUI.setWindowSize(width, height, true);
211 return 0;
212 }
213
214 // -------------------------------------------------------------------
215
lv2_get_options(LV2_Options_Option * const)216 uint32_t lv2_get_options(LV2_Options_Option* const /*options*/)
217 {
218 // currently unused
219 return LV2_OPTIONS_ERR_UNKNOWN;
220 }
221
lv2_set_options(const LV2_Options_Option * const options)222 uint32_t lv2_set_options(const LV2_Options_Option* const options)
223 {
224 for (int i=0; options[i].key != 0; ++i)
225 {
226 if (options[i].key == fURIDs.paramSampleRate)
227 {
228 if (options[i].type == fURIDs.atomFloat)
229 {
230 const float sampleRate = *(const float*)options[i].value;
231 fUI.setSampleRate(sampleRate);
232 continue;
233 }
234 else
235 {
236 d_stderr("Host changed UI sample-rate but with wrong value type");
237 continue;
238 }
239 }
240 }
241
242 return LV2_OPTIONS_SUCCESS;
243 }
244
245 // -------------------------------------------------------------------
246
247 #if DISTRHO_PLUGIN_WANT_PROGRAMS
lv2ui_select_program(const uint32_t bank,const uint32_t program)248 void lv2ui_select_program(const uint32_t bank, const uint32_t program)
249 {
250 const uint32_t realProgram = bank * 128 + program;
251
252 fUI.programLoaded(realProgram);
253 }
254 #endif
255
256 // -------------------------------------------------------------------
257
258 protected:
editParameterValue(const uint32_t rindex,const bool started)259 void editParameterValue(const uint32_t rindex, const bool started)
260 {
261 if (fUiTouch != nullptr && fUiTouch->touch != nullptr)
262 fUiTouch->touch(fUiTouch->handle, rindex, started);
263 }
264
setParameterValue(const uint32_t rindex,const float value)265 void setParameterValue(const uint32_t rindex, const float value)
266 {
267 DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
268
269 fWriteFunction(fController, rindex, sizeof(float), 0, &value);
270 }
271
setState(const char * const key,const char * const value)272 void setState(const char* const key, const char* const value)
273 {
274 DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
275
276 const uint32_t eventInPortIndex = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
277
278 // join key and value
279 String tmpStr;
280 tmpStr += key;
281 tmpStr += "\xff";
282 tmpStr += value;
283
284 tmpStr[std::strlen(key)] = '\0';
285
286 // set msg size (key + separator + value + null terminator)
287 const size_t msgSize = tmpStr.length() + 1U;
288
289 // reserve atom space
290 const size_t atomSize = sizeof(LV2_Atom) + msgSize;
291 char atomBuf[atomSize];
292 std::memset(atomBuf, 0, atomSize);
293
294 // set atom info
295 LV2_Atom* const atom = (LV2_Atom*)atomBuf;
296 atom->size = msgSize;
297 atom->type = fURIDs.dpfKeyValue;
298
299 // set atom data
300 std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.buffer(), msgSize);
301
302 // send to DSP side
303 fWriteFunction(fController, eventInPortIndex, atomSize, fURIDs.atomEventTransfer, atom);
304 }
305
306 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
sendNote(const uint8_t channel,const uint8_t note,const uint8_t velocity)307 void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
308 {
309 DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
310
311 if (channel > 0xF)
312 return;
313
314 const uint32_t eventInPortIndex = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
315
316 LV2_Atom_MidiEvent atomMidiEvent;
317 atomMidiEvent.atom.size = 3;
318 atomMidiEvent.atom.type = fMidiEventURID;
319
320 atomMidiEvent.data[0] = channel + (velocity != 0 ? 0x90 : 0x80);
321 atomMidiEvent.data[1] = note;
322 atomMidiEvent.data[2] = velocity;
323
324 // send to DSP side
325 fWriteFunction(fController, eventInPortIndex, lv2_atom_total_size(&atomMidiEvent.atom),
326 fURIDs.atomEventTransfer, &atomMidiEvent);
327 }
328 #endif
329
setSize(const uint width,const uint height)330 void setSize(const uint width, const uint height)
331 {
332 fUI.setWindowSize(width, height);
333
334 if (fUiResize != nullptr && ! fWinIdWasNull)
335 fUiResize->ui_resize(fUiResize->handle, width, height);
336 }
337
fileRequest(const char * const key)338 bool fileRequest(const char* const key)
339 {
340 d_stdout("UI file request %s %p", key, fUiRequestValue);
341
342 if (fUiRequestValue == nullptr)
343 return false;
344
345 String dpf_lv2_key(DISTRHO_PLUGIN_URI "#");
346 dpf_lv2_key += key;
347
348 const int r = fUiRequestValue->request(fUiRequestValue->handle,
349 fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()),
350 fURIDs.atomPath,
351 nullptr);
352
353 d_stdout("UI file request %s %p => %s %i", key, fUiRequestValue, dpf_lv2_key.buffer(), r);
354 return r == LV2UI_REQUEST_VALUE_SUCCESS;
355 }
356
357 private:
358 UIExporter fUI;
359
360 // LV2 features
361 const LV2_URID_Map* const fUridMap;
362 const LV2UI_Request_Value* const fUiRequestValue;
363 const LV2UI_Resize* const fUiResize;
364 const LV2UI_Touch* const fUiTouch;
365
366 // LV2 UI stuff
367 const LV2UI_Controller fController;
368 const LV2UI_Write_Function fWriteFunction;
369
370 // LV2 URIDs
371 const struct URIDs {
372 const LV2_URID_Map* _uridMap;
373 LV2_URID dpfKeyValue;
374 LV2_URID atomEventTransfer;
375 LV2_URID atomFloat;
376 LV2_URID atomLong;
377 LV2_URID atomPath;
378 LV2_URID atomString;
379 LV2_URID midiEvent;
380 LV2_URID paramSampleRate;
381 LV2_URID patchSet;
382
URIDsUiLv2::URIDs383 URIDs(const LV2_URID_Map* const uridMap)
384 : _uridMap(uridMap),
385 dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")),
386 atomEventTransfer(map(LV2_ATOM__eventTransfer)),
387 atomFloat(map(LV2_ATOM__Float)),
388 atomLong(map(LV2_ATOM__Long)),
389 atomPath(map(LV2_ATOM__Path)),
390 atomString(map(LV2_ATOM__String)),
391 midiEvent(map(LV2_MIDI__MidiEvent)),
392 paramSampleRate(map(LV2_PARAMETERS__sampleRate)),
393 patchSet(map(LV2_PATCH__Set)) {}
394
mapUiLv2::URIDs395 inline LV2_URID map(const char* const uri) const
396 {
397 return _uridMap->map(_uridMap->handle, uri);
398 }
399 } fURIDs;
400
401 // using ui:showInterface if true
402 bool fWinIdWasNull;
403
404 // -------------------------------------------------------------------
405 // Callbacks
406
407 #define uiPtr ((UiLv2*)ptr)
408
editParameterCallback(void * ptr,uint32_t rindex,bool started)409 static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
410 {
411 uiPtr->editParameterValue(rindex, started);
412 }
413
setParameterCallback(void * ptr,uint32_t rindex,float value)414 static void setParameterCallback(void* ptr, uint32_t rindex, float value)
415 {
416 uiPtr->setParameterValue(rindex, value);
417 }
418
setStateCallback(void * ptr,const char * key,const char * value)419 static void setStateCallback(void* ptr, const char* key, const char* value)
420 {
421 uiPtr->setState(key, value);
422 }
423
424 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
sendNoteCallback(void * ptr,uint8_t channel,uint8_t note,uint8_t velocity)425 static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
426 {
427 uiPtr->sendNote(channel, note, velocity);
428 }
429 #endif
430
setSizeCallback(void * ptr,uint width,uint height)431 static void setSizeCallback(void* ptr, uint width, uint height)
432 {
433 uiPtr->setSize(width, height);
434 }
435
fileRequestCallback(void * ptr,const char * key)436 static bool fileRequestCallback(void* ptr, const char* key)
437 {
438 return uiPtr->fileRequest(key);
439 }
440
441 #undef uiPtr
442 };
443
444 // -----------------------------------------------------------------------
445
lv2ui_instantiate(const LV2UI_Descriptor *,const char * const uri,const char * const bundlePath,const LV2UI_Write_Function writeFunction,const LV2UI_Controller controller,LV2UI_Widget * const widget,const LV2_Feature * const * const features)446 static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*,
447 const char* const uri,
448 const char* const bundlePath,
449 const LV2UI_Write_Function writeFunction,
450 const LV2UI_Controller controller,
451 LV2UI_Widget* const widget,
452 const LV2_Feature* const* const features)
453 {
454 if (uri == nullptr || std::strcmp(uri, DISTRHO_PLUGIN_URI) != 0)
455 {
456 d_stderr("Invalid plugin URI");
457 return nullptr;
458 }
459
460 const LV2_Options_Option* options = nullptr;
461 const LV2_URID_Map* uridMap = nullptr;
462 void* parentId = nullptr;
463 void* instance = nullptr;
464
465 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
466 struct LV2_DirectAccess_Interface {
467 void* (*get_instance_pointer)(LV2_Handle handle);
468 };
469 const LV2_Extension_Data_Feature* extData = nullptr;
470 #endif
471
472 for (int i=0; features[i] != nullptr; ++i)
473 {
474 /**/ if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
475 options = (const LV2_Options_Option*)features[i]->data;
476 else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
477 uridMap = (const LV2_URID_Map*)features[i]->data;
478 else if (std::strcmp(features[i]->URI, LV2_UI__parent) == 0)
479 parentId = features[i]->data;
480 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
481 else if (std::strcmp(features[i]->URI, LV2_DATA_ACCESS_URI) == 0)
482 extData = (const LV2_Extension_Data_Feature*)features[i]->data;
483 else if (std::strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0)
484 instance = features[i]->data;
485 #endif
486 }
487
488 if (options == nullptr && parentId == nullptr)
489 {
490 d_stderr("Options feature missing (needed for show-interface), cannot continue!");
491 return nullptr;
492 }
493
494 if (uridMap == nullptr)
495 {
496 d_stderr("URID Map feature missing, cannot continue!");
497 return nullptr;
498 }
499
500 if (parentId == nullptr)
501 {
502 d_stdout("Parent Window Id missing, host should be using ui:showInterface...");
503 }
504
505 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
506 if (extData == nullptr || instance == nullptr)
507 {
508 d_stderr("Data or instance access missing, cannot continue!");
509 return nullptr;
510 }
511
512 if (const LV2_DirectAccess_Interface* const directAccess = (const LV2_DirectAccess_Interface*)extData->data_access(DISTRHO_PLUGIN_LV2_STATE_PREFIX "direct-access"))
513 instance = directAccess->get_instance_pointer(instance);
514 else
515 instance = nullptr;
516
517 if (instance == nullptr)
518 {
519 d_stderr("Failed to get direct access, cannot continue!");
520 return nullptr;
521 }
522 #endif
523
524 const intptr_t winId = (intptr_t)parentId;
525 float scaleFactor = 1.0f;
526 uint32_t bgColor = 0;
527 uint32_t fgColor = 0xffffffff;
528
529 if (options != nullptr)
530 {
531 const LV2_URID uridAtomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);
532 const LV2_URID uridAtomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
533 const LV2_URID uridSampleRate = uridMap->map(uridMap->handle, LV2_PARAMETERS__sampleRate);
534 const LV2_URID uridBgColor = uridMap->map(uridMap->handle, LV2_UI__backgroundColor);
535 const LV2_URID uridFgColor = uridMap->map(uridMap->handle, LV2_UI__foregroundColor);
536 const LV2_URID uridScaleFactor = uridMap->map(uridMap->handle, LV2_UI__scaleFactor);
537
538 for (int i=0; options[i].key != 0; ++i)
539 {
540 /**/ if (options[i].key == uridSampleRate)
541 {
542 if (options[i].type == uridAtomFloat)
543 d_lastUiSampleRate = *(const float*)options[i].value;
544 else
545 d_stderr("Host provides UI sample-rate but has wrong value type");
546 }
547 else if (options[i].key == uridScaleFactor)
548 {
549 if (options[i].type == uridAtomFloat)
550 scaleFactor = *(const float*)options[i].value;
551 else
552 d_stderr("Host provides UI scale factor but has wrong value type");
553 }
554 else if (options[i].key == uridBgColor)
555 {
556 if (options[i].type == uridAtomInt)
557 bgColor = (uint32_t)*(const int32_t*)options[i].value;
558 else
559 d_stderr("Host provides UI background color but has wrong value type");
560 }
561 else if (options[i].key == uridFgColor)
562 {
563 if (options[i].type == uridAtomInt)
564 fgColor = (uint32_t)*(const int32_t*)options[i].value;
565 else
566 d_stderr("Host provides UI foreground color but has wrong value type");
567 }
568 }
569 }
570
571 if (d_lastUiSampleRate < 1.0)
572 {
573 d_stdout("WARNING: this host does not send sample-rate information for LV2 UIs, using 44100 as fallback (this could be wrong)");
574 d_lastUiSampleRate = 44100.0;
575 }
576
577 return new UiLv2(bundlePath, winId, options, uridMap, features,
578 controller, writeFunction, widget, instance,
579 scaleFactor, bgColor, fgColor);
580 }
581
582 #define uiPtr ((UiLv2*)ui)
583
lv2ui_cleanup(LV2UI_Handle ui)584 static void lv2ui_cleanup(LV2UI_Handle ui)
585 {
586 delete uiPtr;
587 }
588
lv2ui_port_event(LV2UI_Handle ui,uint32_t portIndex,uint32_t bufferSize,uint32_t format,const void * buffer)589 static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
590 {
591 uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
592 }
593
594 // -----------------------------------------------------------------------
595
lv2ui_idle(LV2UI_Handle ui)596 static int lv2ui_idle(LV2UI_Handle ui)
597 {
598 return uiPtr->lv2ui_idle();
599 }
600
lv2ui_show(LV2UI_Handle ui)601 static int lv2ui_show(LV2UI_Handle ui)
602 {
603 return uiPtr->lv2ui_show();
604 }
605
lv2ui_hide(LV2UI_Handle ui)606 static int lv2ui_hide(LV2UI_Handle ui)
607 {
608 return uiPtr->lv2ui_hide();
609 }
610
lv2ui_resize(LV2UI_Handle ui,int width,int height)611 static int lv2ui_resize(LV2UI_Handle ui, int width, int height)
612 {
613 DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 1);
614 DISTRHO_SAFE_ASSERT_RETURN(width > 0, 1);
615 DISTRHO_SAFE_ASSERT_RETURN(height > 0, 1);
616
617 return 1; // This needs more testing
618 //return uiPtr->lv2ui_resize(width, height);
619 }
620
621 // -----------------------------------------------------------------------
622
lv2_get_options(LV2UI_Handle ui,LV2_Options_Option * options)623 static uint32_t lv2_get_options(LV2UI_Handle ui, LV2_Options_Option* options)
624 {
625 return uiPtr->lv2_get_options(options);
626 }
627
lv2_set_options(LV2UI_Handle ui,const LV2_Options_Option * options)628 static uint32_t lv2_set_options(LV2UI_Handle ui, const LV2_Options_Option* options)
629 {
630 return uiPtr->lv2_set_options(options);
631 }
632
633 // -----------------------------------------------------------------------
634
635 #if DISTRHO_PLUGIN_WANT_PROGRAMS
lv2ui_select_program(LV2UI_Handle ui,uint32_t bank,uint32_t program)636 static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program)
637 {
638 uiPtr->lv2ui_select_program(bank, program);
639 }
640 #endif
641
642 // -----------------------------------------------------------------------
643
lv2ui_extension_data(const char * uri)644 static const void* lv2ui_extension_data(const char* uri)
645 {
646 static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
647 static const LV2UI_Idle_Interface uiIdle = { lv2ui_idle };
648 static const LV2UI_Show_Interface uiShow = { lv2ui_show, lv2ui_hide };
649 static const LV2UI_Resize uiResz = { nullptr, lv2ui_resize };
650
651 if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
652 return &options;
653 if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
654 return &uiIdle;
655 if (std::strcmp(uri, LV2_UI__showInterface) == 0)
656 return &uiShow;
657 if (std::strcmp(uri, LV2_UI__resize) == 0)
658 return &uiResz;
659
660 #if DISTRHO_PLUGIN_WANT_PROGRAMS
661 static const LV2_Programs_UI_Interface uiPrograms = { lv2ui_select_program };
662
663 if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
664 return &uiPrograms;
665 #endif
666
667 return nullptr;
668 }
669
670 #undef instancePtr
671
672 // -----------------------------------------------------------------------
673
674 static const LV2UI_Descriptor sLv2UiDescriptor = {
675 DISTRHO_UI_URI,
676 lv2ui_instantiate,
677 lv2ui_cleanup,
678 lv2ui_port_event,
679 lv2ui_extension_data
680 };
681
682 // -----------------------------------------------------------------------
683
684 END_NAMESPACE_DISTRHO
685
686 DISTRHO_PLUGIN_EXPORT
lv2ui_descriptor(uint32_t index)687 const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
688 {
689 USE_NAMESPACE_DISTRHO
690 return (index == 0) ? &sLv2UiDescriptor : nullptr;
691 }
692
693 // -----------------------------------------------------------------------
694