diff --git a/source/backend/CarlaHostCommon.cpp b/source/backend/CarlaHostCommon.cpp index 230cd0364..4491eb1b6 100644 --- a/source/backend/CarlaHostCommon.cpp +++ b/source/backend/CarlaHostCommon.cpp @@ -369,7 +369,7 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint // features info.hints = 0x0; - if (lilvPlugin.get_uis().size() > 0) + if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr) info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; { diff --git a/source/modules/lilv/lilv-0.20.0/lilv/lilv.h b/source/modules/lilv/lilv-0.20.0/lilv/lilv.h index f6fefab00..afcc4ccdf 100644 --- a/source/modules/lilv/lilv-0.20.0/lilv/lilv.h +++ b/source/modules/lilv/lilv-0.20.0/lilv/lilv.h @@ -1699,6 +1699,27 @@ lilv_ui_get_binary_uri(const LilvUI* ui); /** Custom calls */ +LILV_API LilvNode* +lilv_plugin_get_modgui_resources_directory(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_stylesheet(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_icon_template(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_settings_template(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_template_data(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_screenshot(const LilvPlugin* plugin); + +LILV_API LilvNode* +lilv_plugin_get_modgui_thumbnail(const LilvPlugin* plugin); + LILV_API const LilvNodes* lilv_ui_get_supported_features(const LilvUI* ui); diff --git a/source/modules/lilv/lilv-0.20.0/lilv/lilvmm.hpp b/source/modules/lilv/lilv-0.20.0/lilv/lilvmm.hpp index 0e0e0ddf5..71814e3ca 100644 --- a/source/modules/lilv/lilv-0.20.0/lilv/lilvmm.hpp +++ b/source/modules/lilv/lilv-0.20.0/lilv/lilvmm.hpp @@ -234,6 +234,13 @@ struct Plugin { LILV_WRAP0(Nodes, plugin, get_extension_data); LILV_WRAP0(UIs, plugin, get_uis); LILV_WRAP1(Nodes, plugin, get_related, Node, type); + LILV_WRAP0(Node, plugin, get_modgui_resources_directory); + LILV_WRAP0(Node, plugin, get_modgui_stylesheet); + LILV_WRAP0(Node, plugin, get_modgui_icon_template); + LILV_WRAP0(Node, plugin, get_modgui_settings_template); + LILV_WRAP0(Node, plugin, get_modgui_template_data); + LILV_WRAP0(Node, plugin, get_modgui_screenshot); + LILV_WRAP0(Node, plugin, get_modgui_thumbnail); inline Port get_port_by_index(unsigned index) { return Port(me, lilv_plugin_get_port_by_index(me, index)); diff --git a/source/modules/lilv/lilv-0.20.0/src/plugin.c b/source/modules/lilv/lilv-0.20.0/src/plugin.c index 59c2ccbe5..529e40770 100644 --- a/source/modules/lilv/lilv-0.20.0/src/plugin.c +++ b/source/modules/lilv/lilv-0.20.0/src/plugin.c @@ -31,6 +31,7 @@ #define NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" #define NS_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" +#define NS_MOD (const uint8_t*)"http://portalmod.com/ns/modgui#" /** Ownership of `uri` is taken */ LilvPlugin* @@ -908,6 +909,131 @@ lilv_plugin_get_author_homepage(const LilvPlugin* plugin) return NULL; } +static const SordNode* +lilv_plugin_get_modgui(const LilvPlugin* p) +{ + lilv_plugin_load_if_necessary(p); + + SordNode* mod_gui = sord_new_uri( + p->world->world, NS_MOD "gui"); + + SordIter* gui = lilv_world_query_internal( + p->world, + p->plugin_uri->node, + mod_gui, + NULL); + + sord_node_free(p->world->world, mod_gui); + + if (sord_iter_end(gui)) { + sord_iter_free(gui); + return NULL; + } + + const SordNode* Gui = sord_iter_get_node(gui, SORD_OBJECT); + + sord_iter_free(gui); + return Gui; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_resources_directory(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_res = sord_new_uri(sworld, NS_MOD "resourcesDirectory"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_res); + sord_node_free(sworld, modgui_res); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_stylesheet(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_style = sord_new_uri(sworld, NS_MOD "stylesheet"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_style); + sord_node_free(sworld, modgui_style); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_icon_template(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "iconTemplate"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); + sord_node_free(sworld, modgui_tmpl); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_settings_template(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "settingsTemplate"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); + sord_node_free(sworld, modgui_tmpl); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_template_data(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "templateData"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); + sord_node_free(sworld, modgui_tmpl); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_screenshot(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_scr = sord_new_uri(sworld, NS_MOD "screenshot"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_scr); + sord_node_free(sworld, modgui_scr); + return ret; + } + return NULL; +} + +LILV_API LilvNode* +lilv_plugin_get_modgui_thumbnail(const LilvPlugin* plugin) +{ + const SordNode* modgui = lilv_plugin_get_modgui(plugin); + if (modgui) { + SordWorld* sworld = plugin->world->world; + SordNode* modgui_thumb = sord_new_uri(sworld, NS_MOD "thumbnail"); + LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_thumb); + sord_node_free(sworld, modgui_thumb); + return ret; + } + return NULL; +} + LILV_API bool lilv_plugin_is_replaced(const LilvPlugin* plugin) { diff --git a/source/modules/lv2_rdf.hpp b/source/modules/lv2_rdf.hpp index 74c4e81d3..5b32cb35d 100644 --- a/source/modules/lv2_rdf.hpp +++ b/source/modules/lv2_rdf.hpp @@ -221,6 +221,7 @@ typedef uint32_t LV2_Property; #define LV2_UI_X11 7 #define LV2_UI_EXTERNAL 8 #define LV2_UI_OLD_EXTERNAL 9 +#define LV2_UI_MOD 10 #define LV2_IS_UI_GTK2(x) ((x) == LV2_UI_GTK2) #define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3) @@ -231,6 +232,7 @@ typedef uint32_t LV2_Property; #define LV2_IS_UI_X11(x) ((x) == LV2_UI_X11) #define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL) #define LV2_IS_UI_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL) +#define LV2_IS_UI_MOD(x) ((x) == LV2_UI_MOD) // Plugin Types #define LV2_PLUGIN_DELAY 0x000001 diff --git a/source/utils/CarlaLv2Utils.hpp b/source/utils/CarlaLv2Utils.hpp index 201aa397c..ed909ae9b 100644 --- a/source/utils/CarlaLv2Utils.hpp +++ b/source/utils/CarlaLv2Utils.hpp @@ -92,6 +92,7 @@ #define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#" #define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" +#define NS_mod "http://portalmod.com/ns/modgui#" #define LV2_MIDI_Map__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC" #define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN" @@ -363,9 +364,7 @@ public: rdf_type (new_uri(NS_rdf "type")), rdfs_label (new_uri(NS_rdfs "label")), - needsInit(true) - { - } + needsInit(true) {} static Lv2WorldClass& getInstance() { @@ -1265,11 +1264,13 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets) // ------------------------------------------------------------------- // Set Plugin UIs { + const bool hasMODGui(lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr); + Lilv::UIs lilvUIs(lilvPlugin.get_uis()); - if (lilvUIs.size() > 0) + if (lilvUIs.size() > 0 || hasMODGui) { - rdfDescriptor->UICount = lilvUIs.size(); + rdfDescriptor->UICount = lilvUIs.size() + (hasMODGui ? 1 : 0); rdfDescriptor->UIs = new LV2_RDF_UI[rdfDescriptor->UICount]; uint32_t h = 0; @@ -1389,6 +1390,29 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets) lilv_nodes_free(const_cast(lilvExtensionDataNodes.me)); } } + + for (; hasMODGui;) + { + CARLA_SAFE_ASSERT_BREAK(h == rdfDescriptor->UICount-1); + + LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[h++]); + + // ------------------------------------------------------- + // Set UI Type + + rdfUI->Type = LV2_UI_MOD; + + // ------------------------------------------------------- + // Set UI Information + + if (const char* const resDir = lilvPlugin.get_modgui_resources_directory().as_uri()) + rdfUI->URI = carla_strdup(lilv_uri_to_path(resDir)); + + if (rdfDescriptor->Bundle != nullptr) + rdfUI->Bundle = carla_strdup(rdfDescriptor->Bundle); + + break; + } } lilv_nodes_free(const_cast(lilvUIs.me));