diff options
-rw-r--r-- | src/instance.c | 91 | ||||
-rw-r--r-- | src/suil_internal.h | 16 | ||||
-rw-r--r-- | src/uis.c | 42 | ||||
-rw-r--r-- | suil/suil.h | 14 |
4 files changed, 124 insertions, 39 deletions
diff --git a/src/instance.c b/src/instance.c index 83ec2d9..74d0948 100644 --- a/src/instance.c +++ b/src/instance.c @@ -29,9 +29,10 @@ SUIL_API bool -suil_ui_type_supported(const char* uri) +suil_ui_type_supported(const char* host_type_uri, + const char* ui_type_uri) { - return !strcmp(uri, "http://lv2plug.in/ns/extensions/ui#GtkUI"); + return !strcmp(ui_type_uri, "http://lv2plug.in/ns/extensions/ui#GtkUI"); } SUIL_API @@ -43,16 +44,20 @@ suil_instance_new(SuilUIs uis, LV2UI_Controller controller, const LV2_Feature* const* features) { - struct _SuilInstance* instance = NULL; - - const bool local_features = (features == NULL); - if (local_features) { - features = malloc(sizeof(LV2_Feature)); - ((LV2_Feature**)features)[0] = NULL; + // Find the UI to use + SuilUI ui = NULL; + if (ui_uri) { + ui = suil_uis_get(uis, ui_uri); + } else { + ui = suil_uis_get_best(uis, type_uri); + } + if (!ui) { + SUIL_ERRORF("No suitable UI found for <%s>\n", + suil_uis_get_plugin_uri(uis)); + return NULL; } - SuilUI ui = uis->uis[0]; // FIXME - + // Open UI library dlerror(); void* lib = dlopen(ui->binary_path, RTLD_NOW); if (!lib) { @@ -61,38 +66,51 @@ suil_instance_new(SuilUIs uis, return NULL; } + // Get discovery function LV2UI_DescriptorFunction df = (LV2UI_DescriptorFunction) suil_dlfunc(lib, "lv2ui_descriptor"); - if (!df) { SUIL_ERRORF("Broken LV2 UI %s (no lv2ui_descriptor symbol found)\n", ui->binary_path); dlclose(lib); return NULL; - } else { - for (uint32_t i = 0; true; ++i) { - const LV2UI_Descriptor* ld = df(i); - if (!ld) { - SUIL_ERRORF("No UI %s in %s\n", ui->uri, ui->binary_path); - dlclose(lib); - break; // return NULL - } else if ((ui_uri && !strcmp(ld->URI, ui_uri)) - || !strcmp(ui->type_uri, type_uri)) { - instance = malloc(sizeof(struct _SuilInstance)); - instance->descriptor = ld; - instance->handle = ld->instantiate( - ld, - uis->plugin_uri, - ui->bundle_path, - write_function, - controller, - &instance->widget, - features); - instance->lib_handle = lib; - break; - } + } + + // Get UI descriptor + const LV2UI_Descriptor* descriptor = NULL; + for (uint32_t i = 0; true; ++i) { + const LV2UI_Descriptor* ld = df(i); + if (!strcmp(ld->URI, ui->uri)) { + descriptor = ld; + break; } } + if (!descriptor) { + SUIL_ERRORF("Failed to find descriptor for <%s> in %s\n", + ui->uri, ui->binary_path); + dlclose(lib); + return NULL; + } + + // Create empty local features array if necessary + const bool local_features = (features == NULL); + if (local_features) { + features = malloc(sizeof(LV2_Feature)); + ((LV2_Feature**)features)[0] = NULL; + } + + // Instantiate UI + struct _SuilInstance* instance = malloc(sizeof(struct _SuilInstance)); + instance->lib_handle = lib; + instance->descriptor = descriptor; + instance->handle = descriptor->instantiate( + descriptor, + uis->plugin_uri, + ui->bundle_path, + write_function, + controller, + &instance->widget, + features); if (local_features) { free((LV2_Feature**)features); @@ -100,12 +118,17 @@ suil_instance_new(SuilUIs uis, // Failed to find or instantiate UI if (!instance || !instance->handle) { + SUIL_ERRORF("Failed to instantiate UI <%s> in %s\n", + ui->uri, ui->binary_path); free(instance); + dlclose(lib); return NULL; } - // Failed to create a widget, but still got a handle (buggy UI) + // Got a handle, but failed to create a widget (buggy UI) if (!instance->widget) { + SUIL_ERRORF("Widget creation failed for UI <%s> in %s\n", + ui->uri, ui->binary_path); suil_instance_free(instance); return NULL; } diff --git a/src/suil_internal.h b/src/suil_internal.h index 4940b69..ed7ebd2 100644 --- a/src/suil_internal.h +++ b/src/suil_internal.h @@ -38,9 +38,9 @@ struct _SuilUI { typedef struct _SuilUI* SuilUI; struct _SuilUIs { - char* plugin_uri; - SuilUI* uis; - size_t n_uis; + char* plugin_uri; + SuilUI* uis; + unsigned n_uis; }; struct _SuilInstance { @@ -50,6 +50,16 @@ struct _SuilInstance { LV2UI_Widget widget; }; +/** Get the UI with the given URI. */ +SuilUI +suil_uis_get(SuilUIs uis, + const char* ui_uri); + +/** Get the best UI for the given type. */ +SuilUI +suil_uis_get_best(SuilUIs uis, + const char* type_uri); + typedef void (*SuilVoidFunc)(); /** dlsym wrapper to return a function pointer (without annoying warning) */ @@ -42,6 +42,48 @@ suil_uis_free(SuilUIs uis) } SUIL_API +const char* +suil_uis_get_plugin_uri(SuilUIs uis) +{ + return uis->plugin_uri; +} + +SUIL_API +SuilUI +suil_uis_get(SuilUIs uis, + const char* ui_uri) +{ + for (unsigned i = 0; i < uis->n_uis; ++i) { + if (!strcmp(uis->uis[i]->uri, ui_uri)) { + return uis->uis[i]; + } + } + return NULL; +} + +SUIL_API +SuilUI +suil_uis_get_best(SuilUIs uis, + const char* type_uri) +{ + // Check for an exact type match + for (unsigned i = 0; i < uis->n_uis; ++i) { + if (!strcmp(uis->uis[i]->type_uri, type_uri)) { + return uis->uis[i]; + } + } + + // No exact match, use the first supported UI + for (unsigned i = 0; i < uis->n_uis; ++i) { + if (suil_ui_type_supported(type_uri, uis->uis[i]->type_uri)) { + return uis->uis[i]; + } + } + + return NULL; +} + +SUIL_API void suil_uis_add(SuilUIs uis, const char* uri, diff --git a/suil/suil.h b/suil/suil.h index 7e0dbec..f5e5584 100644 --- a/suil/suil.h +++ b/suil/suil.h @@ -59,10 +59,15 @@ typedef struct _SuilUIs* SuilUIs; /** An instance of an LV2 plugin UI. */ typedef struct _SuilInstance* SuilInstance; -/** Return true iff UIs of the given type are supported. */ +/** Return true iff it is possible to load a UI of a given type. + * @param host_type_uri The URI of the desired widget type of the host, + * corresponding to the @a type_uri parameter of @ref suil_instance_new. + * @param ui_type_uri The URI of the UI widget type. + */ SUIL_API bool -suil_ui_type_supported(const char* uri); +suil_ui_type_supported(const char* host_type_uri, + const char* ui_type_uri); /** Create a new empty set of UIs for a particular LV2 plugin. */ SUIL_API @@ -74,6 +79,11 @@ SUIL_API void suil_uis_free(SuilUIs uis); +/** Return the URI of the plugin this set of UIs is for. */ +SUIL_API +const char* +suil_uis_get_plugin_uri(SuilUIs uis); + /** Add a discovered UI to @a uis. */ SUIL_API void |