aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2016-02-07 14:32:56 +0100
committerHanspeter Portner <dev@open-music-kontrollers.ch>2016-02-07 14:32:56 +0100
commit411c057acf543f713a865e8733fed95c88425b4e (patch)
treed5dd40e87bde9c009716cad6bdd08750d94c9497
parente75e417ac6e250803b96312cde29309a5416b516 (diff)
parent4c94cfa2fc4f190a9790ad26650717b08f5b387e (diff)
downloadsherlock.lv2-411c057acf543f713a865e8733fed95c88425b4e.tar.xz
Merge commit '4c94cfa2fc4f190a9790ad26650717b08f5b387e'
-rw-r--r--eo_ui.lv2/CMakeLists.txt58
-rw-r--r--eo_ui.lv2/lv2_eo_ui.h78
-rw-r--r--eo_ui.lv2/test/eo.c103
-rw-r--r--eo_ui.lv2/test/eo.ttl104
-rw-r--r--eo_ui.lv2/test/eo_ui.c242
-rw-r--r--eo_ui.lv2/test/lv2_white.pngbin0 -> 2481 bytes
-rw-r--r--eo_ui.lv2/test/manifest.ttl.in61
7 files changed, 626 insertions, 20 deletions
diff --git a/eo_ui.lv2/CMakeLists.txt b/eo_ui.lv2/CMakeLists.txt
new file mode 100644
index 0000000..55729b6
--- /dev/null
+++ b/eo_ui.lv2/CMakeLists.txt
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(eo.lv2)
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${PROJECT_BINARY_DIR})
+
+set(CMAKE_C_FLAGS "-std=gnu99 -Wextra -Wno-unused-parameter -ffast-math -fvisibility=hidden ${CMAKE_C_FLAGS}")
+set(CMAKE_C_FLAGS "-Wshadow -Wimplicit-function-declaration -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes ${CMAKE_C_FLAGS}")
+set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-z,nodelete ${CMAKE_MODULE_LINKER_FLAGS}")
+add_definitions("-D_GNU_SOURCE=1") # asprintf
+
+set(EO_MAJOR_VERSION 0)
+set(EO_MINOR_VERSION 1)
+set(EO_MICRO_VERSION 1)
+
+set(DEST lib/lv2/eo.lv2)
+
+find_package(PkgConfig) # ${PKG_CONFIG_FOUND}
+
+# eo
+add_library(eo MODULE
+ test/eo.c)
+target_link_libraries(eo ${LIBS})
+set_target_properties(eo PROPERTIES PREFIX "")
+install(TARGETS eo DESTINATION ${DEST})
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/test/eo.ttl DESTINATION ${DEST})
+
+# manifest
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test/manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl)
+install(FILES ${PROJECT_BINARY_DIR}/manifest.ttl DESTINATION ${DEST})
+
+pkg_search_module(ELM REQUIRED elementary>=1.8)
+include_directories(${ELM_INCLUDE_DIRS})
+set(LIBS_UI ${LIBS_UI} ${ELM_LDFLAGS})
+
+pkg_search_module(ECORE_X OPTIONAL ecore-x)
+
+if((${ELM_VERSION} VERSION_EQUAL "1.9.0") OR (${ELM_VERSION} VERSION_GREATER "1.9.0"))
+ add_definitions("-DELM_1_9")
+endif()
+
+if((DEFINED ECORE_X_FOUND) AND ((${ELM_VERSION} VERSION_EQUAL "1.13.0") OR (${ELM_VERSION} VERSION_GREATER "1.13.0")))
+ message(STATUS "X11 UI wrap enabled")
+ set(X11_UI_WRAP "")
+ add_definitions("-DX11_UI_WRAP")
+else()
+ message(STATUS "X11 UI wrap disabled")
+ set(X11_UI_WRAP "#")
+endif()
+
+# eo_ui
+add_library(eo_ui MODULE
+ test/eo_ui.c)
+target_link_libraries(eo_ui ${LIBS_UI})
+set_target_properties(eo_ui PROPERTIES PREFIX "")
+install(TARGETS eo_ui DESTINATION ${DEST})
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/test/lv2_white.png DESTINATION ${DEST})
diff --git a/eo_ui.lv2/lv2_eo_ui.h b/eo_ui.lv2/lv2_eo_ui.h
index b98a0b9..e4d7646 100644
--- a/eo_ui.lv2/lv2_eo_ui.h
+++ b/eo_ui.lv2/lv2_eo_ui.h
@@ -25,6 +25,9 @@
#endif
#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
+#include <lv2/lv2plug.in/ns/ext/options/options.h>
+#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
#include <lv2_external_ui.h> // kxstudio external-ui extension
typedef enum _eo_ui_driver_t eo_ui_driver_t;
@@ -50,6 +53,10 @@ struct _eo_ui_t {
Evas_Object *content;
eo_ui_content_get content_get;
+ LV2_URID window_title;
+ LV2_URID atom_string;
+ char title [512];
+
union {
// eo iface
struct {
@@ -118,7 +125,7 @@ _show_cb(LV2UI_Handle instance)
return -1;
// create main window
- eoui->win = elm_win_add(NULL, "EoUI", ELM_WIN_BASIC);
+ eoui->win = elm_win_add(NULL, eoui->title, ELM_WIN_BASIC);
if(!eoui->win)
return -1;
evas_object_smart_callback_add(eoui->win, "delete,request",
@@ -252,10 +259,7 @@ _kx_show(LV2_External_UI_Widget *widget)
return;
// create main window
- const char *title = eoui->kx.host->plugin_human_id
- ? eoui->kx.host->plugin_human_id
- : "EoUI";
- eoui->win = elm_win_add(NULL, title, ELM_WIN_BASIC);
+ eoui->win = elm_win_add(NULL, eoui->title, ELM_WIN_BASIC);
if(!eoui->win)
return;
elm_win_autodel_set(eoui->win, EINA_TRUE);
@@ -343,6 +347,19 @@ eoui_instantiate(eo_ui_t *eoui, const LV2UI_Descriptor *descriptor,
eoui->w = eoui->w > 0 ? eoui->w : 400; // fall-back if w == 0
eoui->h = eoui->h > 0 ? eoui->h : 400; // fall-back if h == 0
+ LV2_URID_Map *map = NULL;
+ for(unsigned i=0; features[i]; i++)
+ {
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ map = features[i]->data;
+ }
+
+ if(!map)
+ return -1;
+
+ eoui->atom_string = map->map(map->handle, LV2_ATOM__String);
+ eoui->window_title = map->map(map->handle, LV2_UI__windowTitle);
+
*widget = NULL;
switch(eoui->driver)
@@ -356,7 +373,7 @@ eoui_instantiate(eo_ui_t *eoui, const LV2UI_Descriptor *descriptor,
if(!strcmp(features[i]->URI, LV2_UI__parent))
eoui->eo.parent = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_UI__resize))
- eoui->eo.resize = (LV2UI_Resize *)features[i]->data;
+ eoui->eo.resize = features[i]->data;
}
if(!eoui->eo.parent)
return -1;
@@ -378,14 +395,29 @@ eoui_instantiate(eo_ui_t *eoui, const LV2UI_Descriptor *descriptor,
// according to the LV2 spec, the host MUST signal availability of
// idle interface via features, thus we test for it here
int host_provides_idle_iface = 0; // mandatory
+ LV2_Options_Option *opts = NULL; // optional
for(int i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_UI__idleInterface))
host_provides_idle_iface = 1;
+ else if(!strcmp(features[i]->URI, LV2_OPTIONS__options))
+ opts = features[i]->data;
}
if(!host_provides_idle_iface)
return -1;
+ snprintf(eoui->title, 512, "%s", descriptor->URI);
+ if(opts)
+ {
+ for(LV2_Options_Option *opt = opts;
+ (opt->key != 0) && (opt->value != NULL);
+ opt++)
+ {
+ if( (opt->key == eoui->window_title) && (opt->type == eoui->atom_string) )
+ snprintf(eoui->title, 512, "%s", opt->value);
+ }
+ }
+
// initialize elementary library
_elm_startup_time = ecore_time_unix_get();
elm_init(0, NULL);
@@ -404,7 +436,7 @@ eoui_instantiate(eo_ui_t *eoui, const LV2UI_Descriptor *descriptor,
if(!strcmp(features[i]->URI, LV2_UI__parent))
eoui->x11.parent = (Ecore_X_Window)(uintptr_t)features[i]->data;
else if(!strcmp(features[i]->URI, LV2_UI__resize))
- eoui->x11.resize = (LV2UI_Resize *)features[i]->data;
+ eoui->x11.resize = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_UI__idleInterface))
host_provides_idle_iface = 1;
}
@@ -468,14 +500,31 @@ eoui_instantiate(eo_ui_t *eoui, const LV2UI_Descriptor *descriptor,
case EO_UI_DRIVER_KX:
{
eoui->kx.host = NULL; // mandatory
+ LV2_Options_Option *opts = NULL; // optional
for(int i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host))
eoui->kx.host = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_OPTIONS__options))
+ opts = features[i]->data;
}
if(!eoui->kx.host)
return -1;
+ snprintf(eoui->title, 512, "%s", descriptor->URI);
+ if(opts)
+ {
+ for(LV2_Options_Option *opt = opts;
+ (opt->key != 0) && (opt->value != NULL);
+ opt++)
+ {
+ if( (opt->key == eoui->window_title) && (opt->type == eoui->atom_string) )
+ snprintf(eoui->title, 512, "%s", opt->value);
+ }
+ }
+ if(eoui->kx.host->plugin_human_id)
+ snprintf(eoui->title, 512, "%s", eoui->kx.host->plugin_human_id);
+
// initialize elementary library
_elm_startup_time = ecore_time_unix_get();
elm_init(0, NULL);
@@ -558,12 +607,8 @@ eoui_cleanup(eo_ui_t *eoui)
memset(eoui, 0, sizeof(eo_ui_t));
}
-// extension data callback for EoUI
-static inline const void *
-eoui_eo_extension_data(const char *uri)
-{
- return NULL;
-}
+#define eoui_eo_extension_data NULL
+#define eoui_kx_extension_data NULL
// extension data callback for show interface UI
static inline const void *
@@ -589,11 +634,4 @@ eoui_x11_extension_data(const char *uri)
return NULL;
}
-// extension data callback for external-ui
-static inline const void *
-eoui_kx_extension_data(const char *uri)
-{
- return NULL;
-}
-
#endif // _EO_UI_H
diff --git a/eo_ui.lv2/test/eo.c b/eo_ui.lv2/test/eo.c
new file mode 100644
index 0000000..91573b9
--- /dev/null
+++ b/eo_ui.lv2/test/eo.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the voiceied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <stdlib.h>
+
+#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
+
+#define EO_PREFIX "http://open-music-kontrollers.ch/lv2/eo#"
+#define EO_TEST_URI EO_PREFIX"test"
+
+typedef struct _plughandle_t plughandle_t;
+
+struct _plughandle_t {
+ const float *x_in;
+ const float *y_in;
+};
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor, double rate,
+ const char *bundle_path, const LV2_Feature *const *features)
+{
+ plughandle_t *handle = calloc(1, sizeof(plughandle_t));
+ if(!handle)
+ return NULL;
+
+ return handle;
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void *data)
+{
+ plughandle_t *handle = (plughandle_t *)instance;
+
+ switch(port)
+ {
+ case 0:
+ handle->x_in = (const float *)data;
+ break;
+ case 1:
+ handle->y_in = (const float *)data;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+run(LV2_Handle instance, uint32_t nsamples)
+{
+ plughandle_t *handle = instance;
+
+ // do nothing
+}
+
+static void
+cleanup(LV2_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ free(handle);
+}
+
+const LV2_Descriptor eo_test = {
+ .URI = EO_TEST_URI,
+ .instantiate = instantiate,
+ .connect_port = connect_port,
+ .activate = NULL,
+ .run = run,
+ .deactivate = NULL,
+ .cleanup = cleanup,
+ .extension_data = NULL
+};
+
+#ifdef _WIN32
+__declspec(dllexport)
+#else
+__attribute__((visibility("default")))
+#endif
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
+{
+ switch(index)
+ {
+ case 0:
+ return &eo_test;
+ default:
+ return NULL;
+ }
+}
diff --git a/eo_ui.lv2/test/eo.ttl b/eo_ui.lv2/test/eo.ttl
new file mode 100644
index 0000000..a5148c1
--- /dev/null
+++ b/eo_ui.lv2/test/eo.ttl
@@ -0,0 +1,104 @@
+# Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+#
+# This is free software: you can redistribute it and/or modify
+# it under the terms of the Artistic License 2.0 as published by
+# The Perl Foundation.
+#
+# This source 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
+# Artistic License 2.0 for more details.
+#
+# You should have received a copy of the Artistic License 2.0
+# along the source as a COPYING file. If not, obtain it from
+# http://www.perlfoundation.org/artistic_license_2_0.
+
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
+@prefix state: <http://lv2plug.in/ns/ext/state#> .
+@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
+@prefix log: <http://lv2plug.in/ns/ext/log#> .
+@prefix units: <http://lv2plug.in/ns/extensions/units#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+@prefix kx: <http://kxstudio.sf.net/ns/lv2ext/external-ui#> .
+
+@prefix lic: <http://opensource.org/licenses/> .
+@prefix omk: <http://open-music-kontrollers.ch/ventosus#> .
+@prefix proj: <http://open-music-kontrollers.ch/lv2/> .
+@prefix eo: <http://open-music-kontrollers.ch/lv2/eo#> .
+
+ui:EoUI
+ a rdfs:Class, owl:Class ;
+ rdfs:subClassOf ui:UI .
+kx:Widget
+ a rdfs:Class, owl:Class ;
+ rdfs:subClassOf ui:UI .
+kx:Host
+ a lv2:Feature .
+
+# Maintainer
+omk:me
+ a foaf:Person ;
+ foaf:name "Hanspeter Portner" ;
+ foaf:mbox <mailto:dev@open-music-kontrollers.ch> ;
+ foaf:homepage <http://open-music-kontrollers.ch> .
+
+# Project
+proj:eo
+ a doap:Project ;
+ doap:maintainer omk:me ;
+ doap:name "EoUI Bundle" .
+
+# Test Plugin
+eo:test
+ a lv2:Plugin ,
+ lv2:ConverterPlugin ;
+ doap:name "EoUI Test" ;
+ doap:license lic:Artistic-2.0 ;
+ lv2:project proj:eo ;
+ lv2:optionalFeature lv2:isLive, lv2:hardRTCapable ;
+
+ lv2:port [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 0 ;
+ lv2:symbol "x_in" ;
+ lv2:name "X In" ;
+ lv2:default 0.5 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 1.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 1 ;
+ lv2:symbol "y_in" ;
+ lv2:name "Y In" ;
+ lv2:default 0.5 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 1.0 ;
+ ] .
+
+# Test UI
+eo:ui
+ a ui:UI ;
+ lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map ;
+ lv2:extensionData ui:idleInterface, ui:showInterface .
+eo:kx
+ a kx:Widget ;
+ lv2:requiredFeature kx:Host, ui:portMap, urid:map .
+eo:x11
+ a ui:X11UI ;
+ lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map ;
+ lv2:optionalFeature ui:resize ;
+ lv2:extensionData ui:idleInterface, ui:resize .
+eo:eo
+ a ui:EoUI ;
+ lv2:optionalFeature ui:resize ;
+ lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map .
diff --git a/eo_ui.lv2/test/eo_ui.c b/eo_ui.lv2/test/eo_ui.c
new file mode 100644
index 0000000..0939227
--- /dev/null
+++ b/eo_ui.lv2/test/eo_ui.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source 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
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <string.h>
+
+#include <Elementary.h>
+
+#include <lv2_eo_ui.h>
+
+#define EO_PREFIX "http://open-music-kontrollers.ch/lv2/eo#"
+#define EO_TEST_URI EO_PREFIX"test"
+#define EO_UI_URI EO_PREFIX"ui"
+#define EO_KX_URI EO_PREFIX"kx"
+#define EO_X11_URI EO_PREFIX"x11"
+#define EO_EO_URI EO_PREFIX"eo"
+
+typedef struct _UI UI;
+
+struct _UI {
+ eo_ui_t eoui;
+ LV2_URID_Map *map;
+
+ LV2_URID float_protocol;
+ LV2UI_Write_Function write_function;
+ LV2UI_Controller controller;
+
+ LV2UI_Port_Map *port_map;
+ uint32_t x_in_port;
+ uint32_t y_in_port;
+
+ int w, h;
+ Evas_Object *widget;
+ char img_src [512];
+};
+
+const LV2UI_Descriptor eo_eo;
+const LV2UI_Descriptor eo_ui;
+const LV2UI_Descriptor eo_x11;
+const LV2UI_Descriptor eo_kx;
+
+static void
+_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ UI *ui = data;
+ Evas_Event_Mouse_Move *ev = event_info;
+
+ int w, h;
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+
+ Evas_Coord x = ev->cur.canvas.x;
+ Evas_Coord y = ev->cur.canvas.y;
+
+ const float X = (float)x / w;
+ const float Y = (float)y / h;
+
+ ui->write_function(ui->controller, ui->x_in_port, sizeof(float),
+ ui->float_protocol, &X);
+ ui->write_function(ui->controller, ui->y_in_port, sizeof(float),
+ ui->float_protocol, &Y);
+}
+
+static Evas_Object *
+_content_get(eo_ui_t *eoui)
+{
+ UI *ui = (void *)eoui - offsetof(UI, eoui);
+
+ ui->widget = elm_bg_add(eoui->win);
+ if(ui->widget)
+ {
+ elm_bg_file_set(ui->widget, ui->img_src, NULL);
+ evas_object_event_callback_add(ui->widget, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, ui);
+ }
+
+ return ui->widget;
+}
+
+static LV2UI_Handle
+instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
+ const char *bundle_path, LV2UI_Write_Function write_function,
+ LV2UI_Controller controller, LV2UI_Widget *widget,
+ const LV2_Feature *const *features)
+{
+ if(strcmp(plugin_uri, EO_TEST_URI))
+ return NULL;
+
+ eo_ui_driver_t driver;
+ if(descriptor == &eo_eo)
+ driver = EO_UI_DRIVER_EO;
+ else if(descriptor == &eo_ui)
+ driver = EO_UI_DRIVER_UI;
+ else if(descriptor == &eo_x11)
+ driver = EO_UI_DRIVER_X11;
+ else if(descriptor == &eo_kx)
+ driver = EO_UI_DRIVER_KX;
+ else
+ return NULL;
+
+ UI *ui = calloc(1, sizeof(UI));
+ if(!ui)
+ return NULL;
+
+ for(int i=0; features[i]; i++)
+ {
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ ui->map = (LV2_URID_Map *)features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__portMap))
+ ui->port_map = (LV2UI_Port_Map *)features[i]->data;
+ }
+
+ if(!ui->map)
+ {
+ fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
+ free(ui);
+ return NULL;
+ }
+ if(!ui->port_map)
+ {
+ fprintf(stderr, "%s: Host does not support ui:portMap\n", descriptor->URI);
+ free(ui);
+ return NULL;
+ }
+
+ ui->float_protocol = ui->map->map(ui->map->handle, LV2_UI__floatProtocol);
+
+ // query port index of "control" port
+ ui->x_in_port = ui->port_map->port_index(ui->port_map->handle, "x_in");
+ ui->y_in_port = ui->port_map->port_index(ui->port_map->handle, "y_in");
+
+ eo_ui_t *eoui = &ui->eoui;
+ eoui->driver = driver;
+ eoui->content_get = _content_get;
+ eoui->w = 100,
+ eoui->h = 63;
+
+ ui->write_function = write_function;
+ ui->controller = controller;
+
+ snprintf(ui->img_src, 512, "%s/lv2_white.png", bundle_path);
+
+ if(eoui_instantiate(eoui, descriptor, plugin_uri, bundle_path, write_function,
+ controller, widget, features))
+ {
+ free(ui);
+ return NULL;
+ }
+
+ return ui;
+}
+
+static void
+cleanup(LV2UI_Handle handle)
+{
+ UI *ui = handle;
+
+ eoui_cleanup(&ui->eoui);
+ free(ui);
+}
+
+static void
+port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size,
+ uint32_t format, const void *buffer)
+{
+ UI *ui = handle;
+
+ if(port_index == ui->x_in_port)
+ {
+ //TODO
+ }
+ else if(port_index == ui->y_in_port)
+ {
+ //TODO
+ }
+}
+
+const LV2UI_Descriptor eo_eo = {
+ .URI = EO_EO_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = eoui_eo_extension_data
+};
+
+const LV2UI_Descriptor eo_ui = {
+ .URI = EO_UI_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = eoui_ui_extension_data
+};
+
+const LV2UI_Descriptor eo_x11 = {
+ .URI = EO_X11_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = eoui_x11_extension_data
+};
+
+const LV2UI_Descriptor eo_kx = {
+ .URI = EO_KX_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = eoui_kx_extension_data
+};
+
+#ifdef _WIN32
+__declspec(dllexport)
+#else
+__attribute__((visibility("default")))
+#endif
+const LV2UI_Descriptor*
+lv2ui_descriptor(uint32_t index)
+{
+ switch(index)
+ {
+ case 0:
+ return &eo_eo;
+ case 1:
+ return &eo_ui;
+ case 2:
+ return &eo_x11;
+ case 3:
+ return &eo_kx;
+ default:
+ return NULL;
+ }
+}
diff --git a/eo_ui.lv2/test/lv2_white.png b/eo_ui.lv2/test/lv2_white.png
new file mode 100644
index 0000000..dabc244
--- /dev/null
+++ b/eo_ui.lv2/test/lv2_white.png
Binary files differ
diff --git a/eo_ui.lv2/test/manifest.ttl.in b/eo_ui.lv2/test/manifest.ttl.in
new file mode 100644
index 0000000..7e6c8bc
--- /dev/null
+++ b/eo_ui.lv2/test/manifest.ttl.in
@@ -0,0 +1,61 @@
+# Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+#
+# This is free software: you can redistribute it and/or modify
+# it under the terms of the Artistic License 2.0 as published by
+# The Perl Foundation.
+#
+# This source 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
+# Artistic License 2.0 for more details.
+#
+# You should have received a copy of the Artistic License 2.0
+# along the source as a COPYING file. If not, obtain it from
+# http://www.perlfoundation.org/artistic_license_2_0.
+
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+@prefix kx: <http://kxstudio.sf.net/ns/lv2ext/external-ui#> .
+
+@prefix eo: <http://open-music-kontrollers.ch/lv2/eo#> .
+
+ui:EoUI
+ a rdfs:Class, owl:Class ;
+ rdfs:subClassOf ui:UI .
+kx:Widget
+ a rdfs:Class, owl:Class ;
+ rdfs:subClassOf ui:UI .
+kx:Host
+ a lv2:Feature .
+
+# Test Plugin
+eo:test
+ a lv2:Plugin ;
+ lv2:minorVersion @EO_MINOR_VERSION@ ;
+ lv2:microVersion @EO_MICRO_VERSION@ ;
+ lv2:binary <eo@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ @UI_UI_WRAP@ui:ui eo:ui ;
+ @KX_UI_WRAP@ui:ui eo:kx ;
+ @X11_UI_WRAP@ui:ui eo:x11 ;
+ @EO_UI_WRAP@ui:ui eo:eo ;
+ rdfs:seeAlso <eo.ttl> .
+
+# Test UI
+eo:ui
+ a ui:UI ;
+ ui:binary <eo_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <eo.ttl> .
+eo:kx
+ a kx:Widget ;
+ ui:binary <eo_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <eo.ttl> .
+eo:x11
+ a ui:X11UI ;
+ ui:binary <eo_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <eo.ttl> .
+eo:eo
+ a ui:EoUI ;
+ ui:binary <eo_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <eo.ttl> .