summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/instance.c147
-rw-r--r--src/suil_internal.h38
-rw-r--r--src/uis.c45
-rw-r--r--suil/suil.h86
-rw-r--r--wscript9
5 files changed, 315 insertions, 10 deletions
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..82ace11
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,147 @@
+/* Suil, a lightweight RDF syntax library.
+ * Copyright 2011 David Robillard <d@drobilla.net>
+ *
+ * Suil is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Suil is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _XOPEN_SOURCE 500
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dlfcn.h>
+
+#include "suil_internal.h"
+
+SUIL_API
+bool
+suil_ui_type_supported(const char* uri)
+{
+ return !strcmp(uri, "http://lv2plug.in/ns/extensions/ui#GtkUI");
+}
+
+SUIL_API
+SuilInstance
+suil_instance_new(SuilUIs uis,
+ const char* type_uri,
+ const char* ui_uri,
+ LV2UI_Write_Function write_function,
+ 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;
+ }
+
+ SuilUI ui = uis->uis[0]; // FIXME
+
+ dlerror();
+ void* lib = dlopen(ui->binary_path, RTLD_NOW);
+ if (!lib) {
+ SUIL_ERRORF("Unable to open UI library %s (%s)\n",
+ ui->binary_path, dlerror());
+ return NULL;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ if (local_features) {
+ free((LV2_Feature**)features);
+ }
+
+ // Failed to find or instantiate UI
+ if (!instance || !instance->handle) {
+ free(instance);
+ return NULL;
+ }
+
+ // Failed to create a widget, but still got a handle (buggy UI)
+ if (!instance->widget) {
+ suil_instance_free(instance);
+ return NULL;
+ }
+
+ return instance;
+}
+
+SUIL_API
+void
+suil_instance_free(SuilInstance instance)
+{
+ if (instance) {
+ instance->descriptor->cleanup(instance->handle);
+ dlclose(instance->lib_handle);
+ free(instance);
+ }
+}
+
+SUIL_API
+LV2UI_Widget
+suil_instance_get_widget(SuilInstance instance)
+{
+ return instance->widget;
+}
+
+SUIL_API
+void
+suil_instance_port_event(SuilInstance instance,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer)
+{
+ instance->descriptor->port_event(instance->handle,
+ port_index,
+ buffer_size,
+ format,
+ buffer);
+}
diff --git a/src/suil_internal.h b/src/suil_internal.h
index a755187..4940b69 100644
--- a/src/suil_internal.h
+++ b/src/suil_internal.h
@@ -21,6 +21,44 @@
#include <assert.h>
#include <stdlib.h>
+#include <dlfcn.h>
+
#include "suil/suil.h"
+#define SUIL_ERRORF(fmt, ...) fprintf(stderr, "error: %s: " fmt, \
+ __func__, __VA_ARGS__)
+
+struct _SuilUI {
+ char* uri;
+ char* type_uri;
+ char* bundle_path;
+ char* binary_path;
+};
+
+typedef struct _SuilUI* SuilUI;
+
+struct _SuilUIs {
+ char* plugin_uri;
+ SuilUI* uis;
+ size_t n_uis;
+};
+
+struct _SuilInstance {
+ void* lib_handle;
+ const LV2UI_Descriptor* descriptor;
+ LV2UI_Handle handle;
+ LV2UI_Widget widget;
+};
+
+typedef void (*SuilVoidFunc)();
+
+/** dlsym wrapper to return a function pointer (without annoying warning) */
+static inline SuilVoidFunc
+suil_dlfunc(void* handle, const char* symbol)
+{
+ typedef SuilVoidFunc (*VoidFuncGetter)(void*, const char*);
+ VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
+ return dlfunc(handle, symbol);
+}
+
#endif // SUIL_INTERNAL_H
diff --git a/src/uis.c b/src/uis.c
index 51ea512..a2a4946 100644
--- a/src/uis.c
+++ b/src/uis.c
@@ -15,4 +15,49 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _XOPEN_SOURCE 500
+
+#include <string.h>
+
#include "suil_internal.h"
+
+SUIL_API
+SuilUIs
+suil_uis_new(const char* plugin_uri)
+{
+ SuilUIs uis = (SuilUIs)malloc(sizeof(struct _SuilUIs));
+ uis->plugin_uri = strdup(plugin_uri);
+ uis->uis = malloc(sizeof(SuilUI));
+ uis->uis[0] = (SuilUI)NULL;
+ uis->n_uis = 0;
+ return uis;
+}
+
+SUIL_API
+void
+suil_uis_free(SuilUIs uis)
+{
+ free(uis->plugin_uri);
+ free(uis);
+}
+
+SUIL_API
+void
+suil_uis_add(SuilUIs uis,
+ const char* uri,
+ const char* type_uri,
+ const char* bundle_path,
+ const char* binary_path)
+{
+ SuilUI ui = (SuilUI)malloc(sizeof(struct _SuilUI));
+ ui->uri = strdup(uri);
+ ui->type_uri = strdup(type_uri);
+ ui->bundle_path = strdup(bundle_path);
+ ui->binary_path = strdup(binary_path);
+
+ ++uis->n_uis;
+ uis->uis = realloc(uis->uis, sizeof(SuilUI) * (uis->n_uis + 1));
+ assert(uis->uis[uis->n_uis - 1] == NULL);
+ uis->uis[uis->n_uis - 1] = ui;
+ uis->uis[uis->n_uis] = NULL;
+}
diff --git a/suil/suil.h b/suil/suil.h
index ffe0069..7e0dbec 100644
--- a/suil/suil.h
+++ b/suil/suil.h
@@ -19,13 +19,13 @@
* Public Suil API.
*/
-#ifndef SUIL_SUIL_H
-#define SUIL_SUIL_H
+#ifndef SUIL_SUIL_H__
+#define SUIL_SUIL_H__
#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
-#include <stdio.h>
+
+#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
#ifdef SUIL_SHARED
#if defined _WIN32 || defined __CYGWIN__
@@ -53,6 +53,82 @@ extern "C" {
* @{
*/
+/** A set of UIs for a particular LV2 plugin. */
+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. */
+SUIL_API
+bool
+suil_ui_type_supported(const char* uri);
+
+/** Create a new empty set of UIs for a particular LV2 plugin. */
+SUIL_API
+SuilUIs
+suil_uis_new(const char* plugin_uri);
+
+/** Free @a uis. */
+SUIL_API
+void
+suil_uis_free(SuilUIs uis);
+
+/** Add a discovered UI to @a uis. */
+SUIL_API
+void
+suil_uis_add(SuilUIs uis,
+ const char* uri,
+ const char* type_uri,
+ const char* bundle_path,
+ const char* binary_path);
+
+/** Instantiate a UI for an LV2 plugin.
+ * @param uis Set of available UIs for the plugin.
+ * @param type_uri URI of the desired widget type.
+ * @param ui_uri URI of a specifically desired UI, or NULL to use the
+ * best choice given @a type_uri.
+ * @param write_function Write function as defined by the LV2 UI extension.
+ * @param controller Opaque controller to be passed to @a write_function.
+ * @param features NULL-terminated array of supported features, or NULL.
+ * @return A new UI instance, or NULL if instantiation failed.
+ */
+SUIL_API
+SuilInstance
+suil_instance_new(SuilUIs uis,
+ const char* type_uri,
+ const char* ui_uri,
+ LV2UI_Write_Function write_function,
+ LV2UI_Controller controller,
+ const LV2_Feature* const* features);
+
+/** Free a plugin UI instance.
+ * The caller must ensure all references to the UI have been dropped before
+ * calling this function (e.g. it has been removed from its parent).
+ */
+SUIL_API
+void
+suil_instance_free(SuilInstance instance);
+
+/** Get the widget for a UI instance.
+ * Returns an opaque pointer to a widget, the type of which is defined by the
+ * corresponding parameter to suil_instantiate. Note this may be a wrapper
+ * widget created by Suil, and not necessarily an LV2UI_Widget implemented
+ * in an LV2 bundle.
+ */
+SUIL_API
+LV2UI_Widget
+suil_instance_get_widget(SuilInstance instance);
+
+/** Notify the UI about a change in a plugin port.
+ */
+SUIL_API
+void
+suil_instance_port_event(SuilInstance instance,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
/** @} */
@@ -60,4 +136,4 @@ extern "C" {
} /* extern "C" */
#endif
-#endif /* SUIL_SUIL_H */
+#endif /* SUIL_SUIL_H__ */
diff --git a/wscript b/wscript
index a2d2175..e6c61a3 100644
--- a/wscript
+++ b/wscript
@@ -30,13 +30,15 @@ def options(opt):
autowaf.set_options(opt)
def configure(conf):
- conf.line_just = max(conf.line_just, 40)
+ conf.line_just = max(conf.line_just, 56)
autowaf.configure(conf)
autowaf.display_header('Suil Configuration')
conf.check_tool('compiler_cc')
conf.env.append_value('CFLAGS', '-std=c99')
+ autowaf.check_header(conf, 'lv2/lv2plug.in/ns/extensions/ui/ui.h')
+
autowaf.define(conf, 'SUIL_VERSION', SUIL_VERSION)
conf.write_config_header('suil-config.h', remove=False)
@@ -52,7 +54,7 @@ def build(bld):
# Library
obj = bld(features = 'c cshlib')
obj.export_includes = ['.']
- obj.source = 'src/uis.c'
+ obj.source = 'src/instance.c src/uis.c'
obj.includes = ['.', './src']
obj.name = 'libsuil'
obj.target = 'suil'
@@ -63,9 +65,6 @@ def build(bld):
# Documentation
autowaf.build_dox(bld, 'SUIL', SUIL_VERSION, top, out)
- # Man page
- bld.install_files('${MANDIR}/man1', 'doc/suili.1')
-
bld.add_post_fun(autowaf.run_ldconfig)
def lint(ctx):