@@ -369,7 +369,7 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint | |||||
// features | // features | ||||
info.hints = 0x0; | 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; | info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; | ||||
{ | { | ||||
@@ -1699,6 +1699,27 @@ lilv_ui_get_binary_uri(const LilvUI* ui); | |||||
/** | /** | ||||
Custom calls | 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_API const LilvNodes* | ||||
lilv_ui_get_supported_features(const LilvUI* ui); | lilv_ui_get_supported_features(const LilvUI* ui); | ||||
@@ -234,6 +234,13 @@ struct Plugin { | |||||
LILV_WRAP0(Nodes, plugin, get_extension_data); | LILV_WRAP0(Nodes, plugin, get_extension_data); | ||||
LILV_WRAP0(UIs, plugin, get_uis); | LILV_WRAP0(UIs, plugin, get_uis); | ||||
LILV_WRAP1(Nodes, plugin, get_related, Node, type); | 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) { | inline Port get_port_by_index(unsigned index) { | ||||
return Port(me, lilv_plugin_get_port_by_index(me, index)); | return Port(me, lilv_plugin_get_port_by_index(me, index)); | ||||
@@ -31,6 +31,7 @@ | |||||
#define NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" | #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_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 */ | /** Ownership of `uri` is taken */ | ||||
LilvPlugin* | LilvPlugin* | ||||
@@ -908,6 +909,131 @@ lilv_plugin_get_author_homepage(const LilvPlugin* plugin) | |||||
return NULL; | 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_API bool | ||||
lilv_plugin_is_replaced(const LilvPlugin* plugin) | lilv_plugin_is_replaced(const LilvPlugin* plugin) | ||||
{ | { | ||||
@@ -221,6 +221,7 @@ typedef uint32_t LV2_Property; | |||||
#define LV2_UI_X11 7 | #define LV2_UI_X11 7 | ||||
#define LV2_UI_EXTERNAL 8 | #define LV2_UI_EXTERNAL 8 | ||||
#define LV2_UI_OLD_EXTERNAL 9 | #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_GTK2(x) ((x) == LV2_UI_GTK2) | ||||
#define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3) | #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_X11(x) ((x) == LV2_UI_X11) | ||||
#define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL) | #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_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL) | ||||
#define LV2_IS_UI_MOD(x) ((x) == LV2_UI_MOD) | |||||
// Plugin Types | // Plugin Types | ||||
#define LV2_PLUGIN_DELAY 0x000001 | #define LV2_PLUGIN_DELAY 0x000001 | ||||
@@ -92,6 +92,7 @@ | |||||
#define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" | #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_rdfs "http://www.w3.org/2000/01/rdf-schema#" | ||||
#define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" | #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__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC" | ||||
#define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN" | #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")), | rdf_type (new_uri(NS_rdf "type")), | ||||
rdfs_label (new_uri(NS_rdfs "label")), | rdfs_label (new_uri(NS_rdfs "label")), | ||||
needsInit(true) | |||||
{ | |||||
} | |||||
needsInit(true) {} | |||||
static Lv2WorldClass& getInstance() | static Lv2WorldClass& getInstance() | ||||
{ | { | ||||
@@ -1265,11 +1264,13 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets) | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Set Plugin UIs | // Set Plugin UIs | ||||
{ | { | ||||
const bool hasMODGui(lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr); | |||||
Lilv::UIs lilvUIs(lilvPlugin.get_uis()); | 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]; | rdfDescriptor->UIs = new LV2_RDF_UI[rdfDescriptor->UICount]; | ||||
uint32_t h = 0; | 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<LilvNodes*>(lilvExtensionDataNodes.me)); | lilv_nodes_free(const_cast<LilvNodes*>(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<LilvNodes*>(lilvUIs.me)); | lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me)); | ||||