diff options
-rw-r--r-- | slv2.pc.in | 2 | ||||
-rw-r--r-- | slv2/slv2.h | 86 | ||||
-rw-r--r-- | src/plugin.c | 82 | ||||
-rw-r--r-- | src/pluginui.c | 19 | ||||
-rw-r--r-- | src/pluginuiinstance.c | 182 | ||||
-rw-r--r-- | src/slv2_internal.h | 10 | ||||
-rw-r--r-- | wscript | 11 |
7 files changed, 272 insertions, 120 deletions
@@ -6,5 +6,5 @@ includedir=@includedir@ Name: libslv2 Version: @SLV2_VERSION@ Description: Convenience library for hosts to simplify LV2 plugin support -Libs: @GLIB_LIBS@ @SORD_LIBS@ -L${libdir} -lslv2 -ldl +Libs: @GLIB_LIBS@ @SORD_LIBS@ @SUIL_LIBS@ -L${libdir} -lslv2 -ldl Cflags: @GLIB_CFLAGS@ @SORD_CFLAGS@ -I${includedir} diff --git a/slv2/slv2.h b/slv2/slv2.h index e703689..b7ce5bd 100644 --- a/slv2/slv2.h +++ b/slv2/slv2.h @@ -1085,17 +1085,31 @@ SLV2UI slv2_uis_get_by_uri(SLV2UIs uis, SLV2Value uri); -/** Get a list of all UIs available for this plugin. - * Note this returns the URI of the UI, and not the path/URI to its shared - * library, use slv2_ui_get_library_uri with the values returned - * here for that. - * +/** Get all UIs for @a plugin. * Returned value must be freed by caller using slv2_uis_free. */ SLV2_API SLV2UIs slv2_plugin_get_uis(SLV2Plugin plugin); +/** Get the default UI for @a plugin. + * This function makes a best effort at choosing a default UI for the given + * widget type. A native UI for the given widget type will be returned if one + * exists, otherwise a UI which can be wrapped by SLV2 will be returned. + * + * This function makes the common case (a plugin with a single UI, or a single + * UI per toolkit) simple, but is not fully powerful since a plugin may have + * several usable UIs. To support multiple UIs per plugin, use + * @ref slv2_ui_supported to determine which UIs are usable and choose a UI + * to instantiate from among them. + * + * @return NULL if there is no suitable UI. + */ +SLV2_API +SLV2UI +slv2_plugin_get_default_ui(SLV2Plugin plugin, + SLV2Value widget_type_uri); + /** @name Plugin UI * @{ */ @@ -1108,6 +1122,13 @@ SLV2_API SLV2Value slv2_ui_get_uri(SLV2UI ui); +/** Return true iff @a ui can be instantiated to a widget of the given type. + */ +SLV2_API +bool +slv2_ui_supported(SLV2UI ui, + SLV2Value widget_type_uri); + /** Get the types (URIs of RDF classes) of a Plugin UI. * @param ui The Plugin UI * @return a shared value which must not be modified or freed. @@ -1147,27 +1168,37 @@ slv2_ui_get_binary_uri(SLV2UI ui); typedef struct _SLV2UIInstance* SLV2UIInstance; +/** DEPRECATED: Instantiate a plugin UI. + * This function is deprecated, it does not support widget wrapping. + * Use @ref slv2_ui_instantiate instead. + */ +SLV2_DEPRECATED +SLV2_API +SLV2UIInstance +slv2_ui_instantiate(SLV2Plugin plugin, + SLV2UI ui, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + const LV2_Feature* const* features); + /** Instantiate a plugin UI. * The returned object represents shared library objects loaded into memory, * it must be cleaned up with slv2_ui_instance_free when no longer * needed. * - * @a plugin is not modified or directly referenced by the returned object - * (instances store only a copy of the plugin's URI). - * - * @a features NULL-terminated array of features the host supports. - * NULL may be passed if the host supports no additional features (unlike - * the LV2 specification - SLV2 takes care of it). + * @param features NULL-terminated array of features the host supports. + * NULL may be passed if the host supports no additional features. * * @return NULL if instantiation failed. */ SLV2_API SLV2UIInstance -slv2_ui_instantiate(SLV2Plugin plugin, - SLV2UI ui, - LV2UI_Write_Function write_function, - LV2UI_Controller controller, - const LV2_Feature* const* features); +slv2_ui_instance_new(SLV2Plugin plugin, + SLV2UI ui, + SLV2Value widget_type_uri, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + const LV2_Feature* const* features); /** Free a plugin UI instance. * @a instance is invalid after this call. @@ -1185,24 +1216,39 @@ SLV2_API LV2UI_Widget slv2_ui_instance_get_widget(SLV2UIInstance instance); -/** DEPRECATED: Get the LV2UI_Descriptor of the plugin UI instance. +/** Notify a UI about a change in a plugin port. + */ +SLV2_API +void +slv2_ui_instance_port_event(SLV2UIInstance instance, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void* buffer); + +/** Return a data structure defined by some LV2 extension URI. + */ +SLV2_API +const void* +slv2_ui_instance_extension_data(SLV2UIInstance instance, + const char* uri); + +/** Get the LV2UI_Descriptor of the plugin UI instance. * Normally hosts should not need to access the LV2UI_Descriptor directly, * use the slv2_ui_instance_* functions. * * The returned descriptor is shared and must not be deleted. */ -SLV2_DEPRECATED SLV2_API const LV2UI_Descriptor* slv2_ui_instance_get_descriptor(SLV2UIInstance instance); -/** DEPRECATED: Get the LV2UI_Handle of the plugin UI instance. +/** Get the LV2UI_Handle of the plugin UI instance. * Normally hosts should not need to access the LV2UI_Handle directly, * use the slv2_ui_instance_* functions. * * The returned handle is shared and must not be deleted. */ -SLV2_DEPRECATED SLV2_API LV2UI_Handle slv2_ui_instance_get_handle(SLV2UIInstance instance); diff --git a/src/plugin.c b/src/plugin.c index f06cfd7..14a4266 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -27,8 +27,17 @@ #include <dlfcn.h> #endif +#include "slv2-config.h" #include "slv2_internal.h" +#ifdef HAVE_SUIL +#include "suil/suil.h" +#endif + +#define NS_UI (const uint8_t*)"http://lv2plug.in/ns/extensions/ui#" +#define NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" +#define NS_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" + /** Ownership of @a uri is taken */ SLV2Plugin slv2_plugin_new(SLV2World world, SLV2Value uri, SLV2Value bundle_uri) @@ -694,9 +703,6 @@ slv2_plugin_get_port_by_symbol(SLV2Plugin p, return NULL; } -#define NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" -#define NS_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" - static SLV2Node slv2_plugin_get_author(SLV2Plugin p) { @@ -764,16 +770,14 @@ SLV2_API SLV2UIs slv2_plugin_get_uis(SLV2Plugin p) { -#define NS_UI (const uint8_t*)"http://lv2plug.in/ns/extensions/ui#" - - SLV2Node ui_ui = sord_new_uri(p->world->world, NS_UI "ui"); + SLV2Node ui_ui_node = sord_new_uri(p->world->world, NS_UI "ui"); SLV2Node ui_binary_node = sord_new_uri(p->world->world, NS_UI "binary"); SLV2UIs result = slv2_uis_new(); SLV2Matches uis = slv2_plugin_find_statements( p, p->plugin_uri->val.uri_val, - ui_ui, + ui_ui_node, NULL); FOREACH_MATCH(uis) { @@ -801,7 +805,7 @@ slv2_plugin_get_uis(SLV2Plugin p) slv2_match_end(uis); slv2_node_free(ui_binary_node); - slv2_node_free(ui_ui); + slv2_node_free(ui_ui_node); if (slv2_uis_size(result) > 0) { return result; @@ -810,3 +814,65 @@ slv2_plugin_get_uis(SLV2Plugin p) return NULL; } } + +SLV2_API +SLV2UI +slv2_plugin_get_default_ui(SLV2Plugin p, + SLV2Value widget_type_uri) +{ +#ifdef HAVE_SUIL + SLV2Node ui_ui_node = sord_new_uri(p->world->world, NS_UI "ui"); + SLV2Node ui_binary_node = sord_new_uri(p->world->world, NS_UI "binary"); + + SLV2Matches uis = slv2_plugin_find_statements( + p, + p->plugin_uri->val.uri_val, + ui_ui_node, + NULL); + + SLV2UI native = NULL; + SLV2UI foreign = NULL; + FOREACH_MATCH(uis) { + SLV2Node ui = slv2_match_object(uis); + SLV2Value type = slv2_plugin_get_unique(p, ui, p->world->rdf_a_node); + SLV2Value binary = slv2_plugin_get_unique(p, ui, ui_binary_node); + + if (sord_node_get_type(ui) != SORD_URI + || !slv2_value_is_uri(type) + || !slv2_value_is_uri(binary)) { + slv2_value_free(binary); + slv2_value_free(type); + SLV2_ERROR("Corrupt UI\n"); + continue; + } + + if (!native && slv2_value_equals(type, widget_type_uri)) { + native = slv2_ui_new( + p->world, + slv2_value_new_from_node(p->world, ui), + type, + binary); + break; + } else if (!foreign && suil_ui_type_supported( + slv2_value_as_uri(widget_type_uri), + slv2_value_as_uri(type))) { + foreign = slv2_ui_new( + p->world, + slv2_value_new_from_node(p->world, ui), + type, + binary); + } else { + slv2_value_free(binary); + slv2_value_free(type); + } + } + slv2_match_end(uis); + + slv2_node_free(ui_binary_node); + slv2_node_free(ui_ui_node); + + return (native) ? native : foreign; +#else + return NULL; +#endif +} diff --git a/src/pluginui.c b/src/pluginui.c index d4ce24f..2c3bc94 100644 --- a/src/pluginui.c +++ b/src/pluginui.c @@ -24,6 +24,10 @@ #include "slv2_internal.h" +#ifdef HAVE_SUIL +#include "suil/suil.h" +#endif + SLV2UI slv2_ui_new(SLV2World world, SLV2Value uri, @@ -79,6 +83,20 @@ slv2_ui_get_uri(SLV2UI ui) } SLV2_API +bool +slv2_ui_supported(SLV2UI ui, + SLV2Value widget_type_uri) +{ +#ifdef HAVE_SUIL + return suil_ui_type_supported( + slv2_value_as_uri(widget_type_uri), + slv2_value_as_uri(slv2_values_get_at(ui->classes, 0))); +#else + return false; +#endif +} + +SLV2_API SLV2Values slv2_ui_get_classes(SLV2UI ui) { @@ -109,4 +127,3 @@ slv2_ui_get_binary_uri(SLV2UI ui) assert(ui->binary_uri); return ui->binary_uri; } - diff --git a/src/pluginuiinstance.c b/src/pluginuiinstance.c index b3cda0d..475340b 100644 --- a/src/pluginuiinstance.c +++ b/src/pluginuiinstance.c @@ -24,10 +24,13 @@ #include <stdlib.h> #include <string.h> -#include <dlfcn.h> +#ifdef HAVE_SUIL +#include "suil/suil.h" +#endif #include "slv2_internal.h" +SLV2_DEPRECATED SLV2_API SLV2UIInstance slv2_ui_instantiate(SLV2Plugin plugin, @@ -36,116 +39,129 @@ slv2_ui_instantiate(SLV2Plugin plugin, LV2UI_Controller controller, const LV2_Feature* const* features) { - struct _SLV2UIInstance* result = NULL; - - const bool local_features = (features == NULL); - if (local_features) { - features = malloc(sizeof(LV2_Feature)); - ((LV2_Feature**)features)[0] = NULL; - } - - const char* const lib_uri = slv2_value_as_string(slv2_ui_get_binary_uri(ui)); - const char* const lib_path = slv2_uri_to_path(lib_uri); - if (!lib_path) { - return NULL; - } - - dlerror(); - void* lib = dlopen(lib_path, RTLD_NOW); - if (!lib) { - SLV2_ERRORF("Unable to open UI library %s (%s)\n", lib_path, dlerror()); - return NULL; - } - - LV2UI_DescriptorFunction df = (LV2UI_DescriptorFunction) - slv2_dlfunc(lib, "lv2ui_descriptor"); + return slv2_ui_instance_new( + plugin, ui, NULL, write_function, controller, features); +} - if (!df) { - SLV2_ERRORF("Could not find symbol 'lv2ui_descriptor', " - "%s is not a LV2 plugin UI.\n", lib_path); - dlclose(lib); +SLV2_API +SLV2UIInstance +slv2_ui_instance_new(SLV2Plugin plugin, + SLV2UI ui, + SLV2Value widget_type_uri, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + const LV2_Feature* const* features) +{ +#ifdef HAVE_SUIL + const char* const bundle_uri = slv2_value_as_uri(slv2_ui_get_bundle_uri(ui)); + const char* const bundle_path = slv2_uri_to_path(bundle_uri); + const char* const lib_uri = slv2_value_as_string(slv2_ui_get_binary_uri(ui)); + const char* const lib_path = slv2_uri_to_path(lib_uri); + if (!bundle_path || !lib_path) { return NULL; - } else { - const char* bundle_uri = slv2_value_as_uri(slv2_ui_get_bundle_uri(ui)); - const char* bundle_path = slv2_uri_to_path(bundle_uri); - - for (uint32_t i = 0; true; ++i) { - const LV2UI_Descriptor* ld = df(i); - if (!ld) { - SLV2_ERRORF("Did not find UI %s in %s\n", - slv2_value_as_uri(slv2_ui_get_uri(ui)), lib_path); - dlclose(lib); - break; // return NULL - } else if (!strcmp(ld->URI, slv2_value_as_uri(slv2_ui_get_uri(ui)))) { - assert(plugin->plugin_uri); - assert(ld->instantiate); - - // Create SLV2UIInstance to return - result = malloc(sizeof(struct _SLV2UIInstance)); - result->lv2ui_descriptor = ld; - result->lv2ui_handle = ld->instantiate( - ld, - slv2_value_as_uri(slv2_plugin_get_uri(plugin)), - (char*)bundle_path, - write_function, - controller, - &result->widget, - features); - result->lib_handle = lib; - break; - } - } } - // Failed to instantiate - if (result == NULL || result->lv2ui_handle == NULL) { - free(result); - return NULL; + SLV2Value ui_type = slv2_values_get_at(ui->classes, 0); + if (!widget_type_uri) { + widget_type_uri = ui_type; } - // Failed to create a widget, but still got a handle (buggy UI) - if (result->widget == NULL) { - slv2_ui_instance_free(result); + SuilInstance suil_instance = suil_instance_new( + slv2_value_as_uri(slv2_plugin_get_uri(plugin)), + slv2_value_as_uri(slv2_ui_get_uri(ui)), + bundle_path, + lib_path, + slv2_value_as_uri(ui_type), + slv2_value_as_uri(widget_type_uri), + write_function, + controller, + features); + + if (!suil_instance) { return NULL; } - if (local_features) { - free((LV2_Feature**)features); - } + // Create SLV2UIInstance to return + struct _SLV2UIInstance* result = malloc(sizeof(struct _SLV2UIInstance)); + result->instance = suil_instance; return result; +#else + return NULL; +#endif } SLV2_API void slv2_ui_instance_free(SLV2UIInstance instance) { - if (instance == NULL) - return; - - struct _SLV2UIInstance* i = (struct _SLV2UIInstance*)instance; - i->lv2ui_descriptor->cleanup(i->lv2ui_handle); - i->lv2ui_descriptor = NULL; - dlclose(i->lib_handle); - i->lib_handle = NULL; - free(i); +#ifdef HAVE_SUIL + if (instance) { + suil_instance_free(instance->instance); + free(instance); + } +#else + return NULL; +#endif } SLV2_API LV2UI_Widget -slv2_ui_instance_get_widget(SLV2UIInstance instance) { - return instance->widget; +slv2_ui_instance_get_widget(SLV2UIInstance instance) +{ +#ifdef HAVE_SUIL + return suil_instance_get_widget(instance->instance); +#else + return NULL; +#endif +} + +SLV2_API +void +slv2_ui_instance_port_event(SLV2UIInstance instance, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void* buffer) +{ + suil_instance_port_event(instance->instance, + port_index, + buffer_size, + format, + buffer); +} + +SLV2_API +const void* +slv2_ui_instance_extension_data(SLV2UIInstance instance, + const char* uri) +{ +#ifdef HAVE_SUIL + return suil_instance_extension_data(instance->instance, uri); +#else + return NULL; +#endif } SLV2_API const LV2UI_Descriptor* -slv2_ui_instance_get_descriptor(SLV2UIInstance instance) { - return instance->lv2ui_descriptor; +slv2_ui_instance_get_descriptor(SLV2UIInstance instance) +{ +#ifdef HAVE_SUIL + return suil_instance_get_descriptor(instance->instance); +#else + return NULL; +#endif } SLV2_API LV2UI_Handle -slv2_ui_instance_get_handle(SLV2UIInstance instance) { - return instance->lv2ui_handle; +slv2_ui_instance_get_handle(SLV2UIInstance instance) +{ +#ifdef HAVE_SUIL + return suil_instance_get_handle(instance->instance); +#else + return NULL; +#endif } diff --git a/src/slv2_internal.h b/src/slv2_internal.h index 4314a73..1313bd3 100644 --- a/src/slv2_internal.h +++ b/src/slv2_internal.h @@ -41,6 +41,10 @@ extern "C" { #include "lv2/lv2plug.in/ns/ext/dyn-manifest/dyn-manifest.h" #endif +#ifdef HAVE_SUIL +#include "suil/suil.h" +#endif + #include "slv2/slv2.h" #define SLV2_NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" @@ -151,10 +155,7 @@ struct _SLV2InstanceImpl { /* ********* UI Instance ********* */ struct _SLV2UIInstance { - void* lib_handle; - const LV2UI_Descriptor* lv2ui_descriptor; - LV2UI_Handle lv2ui_handle; - LV2UI_Widget widget; + SuilInstance instance; }; /* ********* Plugin Class ********* */ @@ -238,6 +239,7 @@ struct _SLV2UI { }; SLV2UIs slv2_uis_new(); + SLV2UI slv2_ui_new(SLV2World world, SLV2Value uri, @@ -89,7 +89,9 @@ def configure(conf): autowaf.check_pkg(conf, 'jack', uselib_store='JACK', atleast_version='0.107.0', mandatory=False) autowaf.check_pkg(conf, 'jack', uselib_store='NEW_JACK', - atleast_version='0.120.0', mandatory=False) + atleast_version='0.120.0', mandatory=False) + autowaf.check_pkg(conf, 'suil', uselib_store='SUIL', + atleast_version='0.0.0', mandatory=True) autowaf.check_header(conf, 'lv2/lv2plug.in/ns/lv2core/lv2.h') autowaf.check_header(conf, 'lv2/lv2plug.in/ns/extensions/ui/ui.h') @@ -163,6 +165,9 @@ def configure(conf): bool(conf.env['SLV2_DYN_MANIFEST'])) autowaf.display_msg(conf, "Python bindings", bool(conf.env['SLV2_SWIG'])) + autowaf.display_msg(conf, "UI wrapping support (via Suil)", + bool(conf.env['HAVE_SUIL'])) + print def build(bld): @@ -200,7 +205,7 @@ def build(bld): obj.install_path = '${LIBDIR}' obj.cflags = [ '-fvisibility=hidden', '-DSLV2_SHARED', '-DSLV2_INTERNAL' ] obj.linkflags = [ '-ldl' ] - autowaf.use_lib(bld, obj, 'SORD SERD LV2CORE GLIB') + autowaf.use_lib(bld, obj, 'SORD SERD LV2CORE GLIB SUIL') if bld.env['BUILD_TESTS']: # Static library (for unit test code coverage) @@ -212,7 +217,7 @@ def build(bld): obj.install_path = '' obj.cflags = [ '-fprofile-arcs', '-ftest-coverage' ] obj.linkflags = [ '-ldl' ] - autowaf.use_lib(bld, obj, 'SORD SERD LV2CORE GLIB') + autowaf.use_lib(bld, obj, 'SORD SERD LV2CORE GLIB SUIL') # Unit test program obj = bld(features = 'c cprogram') |