aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2016-04-03 22:52:48 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2016-04-03 22:56:50 +0200
commitf18ac20e55169a3e8583075ad273a11474a7a2a4 (patch)
treee1408b5138f064d042cf2dae59e34055cbdbc4a9
parenta0a9843bdfcc3b3abe0d741f3aab6820bc47002a (diff)
downloadsherlock.lv2-f18ac20e55169a3e8583075ad273a11474a7a2a4.tar.xz
prototype sandbox_ui.
-rw-r--r--.travis.yml19
-rw-r--r--CMakeLists.txt56
-rw-r--r--atom_inspector_eo.c (renamed from atom_inspector_ui.c)108
-rw-r--r--eo_ui.lv2/CMakeLists.txt58
-rw-r--r--eo_ui.lv2/COPYING201
-rw-r--r--eo_ui.lv2/README.md3
-rw-r--r--eo_ui.lv2/lv2_eo_ui.h637
-rw-r--r--eo_ui.lv2/manifest.ttl28
-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.pngbin2481 -> 0 bytes
-rw-r--r--eo_ui.lv2/test/manifest.ttl.in61
-rw-r--r--ext_ui.lv2/lv2_external_ui.h (renamed from eo_ui.lv2/lv2_external_ui.h)0
-rw-r--r--manifest.ttl.in81
-rw-r--r--midi_inspector_eo.c (renamed from midi_inspector_ui.c)94
-rw-r--r--osc_inspector_eo.c (renamed from osc_inspector_ui.c)96
-rw-r--r--sandbox_ui.lv2/sandbox_efl.c192
-rw-r--r--sandbox_ui.lv2/sandbox_io.h552
-rw-r--r--sandbox_ui.lv2/sandbox_master.c100
-rw-r--r--sandbox_ui.lv2/sandbox_master.h71
-rw-r--r--sandbox_ui.lv2/sandbox_slave.c563
-rw-r--r--sandbox_ui.lv2/sandbox_slave.h77
-rw-r--r--sherlock.h30
-rw-r--r--sherlock.ttl149
-rw-r--r--sherlock_eo.c35
-rw-r--r--sherlock_ui.c436
-rw-r--r--sherlock_ui.ttl135
-rw-r--r--symap/symap.c231
-rw-r--r--symap/symap.h69
30 files changed, 2668 insertions, 1863 deletions
diff --git a/.travis.yml b/.travis.yml
index 975091c..c161961 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,15 +6,30 @@ os:
- linux
compiler:
- gcc
- - clang
+ # - clang
before_install:
- wget http://lv2plug.in/spec/lv2-1.12.0.tar.bz2
- - tar xjf lv2-1.12.0.tar.bz2
+ - wget http://download.drobilla.net/serd-0.22.0.tar.bz2
+ - wget http://download.drobilla.net/sord-0.14.0.tar.bz2
+ - wget http://download.drobilla.net/sratom-0.4.6.tar.bz2
+ - wget http://download.drobilla.net/lilv-0.22.0.tar.bz2
+ - wget https://github.com/nanomsg/nanomsg/releases/download/0.8-beta/nanomsg-0.8-beta.tar.gz
+ - tar xjf lv2-1.12.0.tar.bz2
+ - tar xjf serd-0.22.0.tar.bz2
+ - tar xjf sord-0.14.0.tar.bz2
+ - tar xjf sratom-0.4.6.tar.bz2
+ - tar xjf lilv-0.22.0.tar.bz2
+ - tar xzf nanomsg-0.8-beta.tar.gz
- sudo add-apt-repository -y ppa:enlightenment-git/ppa
- sudo apt-get -q update
install:
- sudo apt-get install -y libefl-dev
- pushd lv2-1.12.0 && ./waf configure --no-plugins --prefix=/usr && ./waf build && sudo ./waf install && popd
+ - pushd serd-0.22.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
+ - pushd sord-0.14.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
+ - pushd sratom-0.4.6 && ./waf configure --prefix=/usr && ./waf build && sudo ./waf install && popd
+ - pushd lilv-0.22.0 && ./waf configure --no-utils --prefix=/usr && ./waf build && sudo ./waf install && popd
+ - pushd nanomsg-0.8-beta && ./configure --prefix=/usr && make && sudo make install && popd
before_script:
- mkdir build && pushd build && cmake .. && popd
script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35ae444..f0fef14 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,8 +4,10 @@ project(sherlock.lv2)
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/libosc)
-include_directories(${PROJECT_SOURCE_DIR}/eo_ui.lv2)
include_directories(${PROJECT_SOURCE_DIR}/osc.lv2)
+include_directories(${PROJECT_SOURCE_DIR}/ext_ui.lv2)
+include_directories(${PROJECT_SOURCE_DIR}/sandbox_ui.lv2)
+include_directories(${PROJECT_SOURCE_DIR}/symap)
set(CMAKE_C_FLAGS "-std=gnu11 -Wextra -Wno-unused-parameter -ffast-math -fvisibility=hidden ${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "-Wshadow -Wimplicit-function-declaration -Wmissing-prototypes -Wstrict-prototypes ${CMAKE_C_FLAGS}")
@@ -24,21 +26,20 @@ find_package(PkgConfig) # ${PKG_CONFIG_FOUND}
pkg_search_module(LV2 REQUIRED lv2>=1.10)
include_directories(${LV2_INCLUDE_DIRS})
-set(LIBS ${LIBS} ${LV2_LDFLAGS})
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)
+pkg_search_module(NANOMSG REQUIRED libnanomsg>=2.0)
+include_directories(${NANOMSG_INCLUDE_DIRS})
-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 "#")
+pkg_search_module(SRATOM REQUIRED sratom-0>=0.4.0)
+include_directories(${SRATOM_INCLUDE_DIRS})
+
+pkg_search_module(LILV REQUIRED lilv-0>=0.20.0)
+include_directories(${LILV_INCLUDE_DIRS})
+if((${LILV_VERSION} VERSION_EQUAL "0.22.0") OR (${LILV_VERSION} VERSION_GREATER "0.22.0"))
+ add_definitions("-DLILV_0_22")
endif()
add_library(sherlock MODULE
@@ -46,20 +47,41 @@ add_library(sherlock MODULE
atom_inspector.c
midi_inspector.c
osc_inspector.c)
-target_link_libraries(sherlock ${LIBS})
set_target_properties(sherlock PROPERTIES PREFIX "")
install(TARGETS sherlock DESTINATION ${DEST})
add_library(sherlock_ui MODULE
- sherlock_ui.c
- atom_inspector_ui.c
- midi_inspector_ui.c
- osc_inspector_ui.c)
-target_link_libraries(sherlock_ui ${LIBS_UI})
+ ${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_master.c
+ sherlock_ui.c)
+target_link_libraries(sherlock_ui
+ ${NANOMSG_LDFLAGS}
+ ${SRATOM_LDFLAGS})
set_target_properties(sherlock_ui PROPERTIES PREFIX "")
install(TARGETS sherlock_ui DESTINATION ${DEST})
+add_library(sherlock_eo MODULE
+ sherlock_eo.c
+ atom_inspector_eo.c
+ midi_inspector_eo.c
+ osc_inspector_eo.c)
+target_link_libraries(sherlock_eo
+ ${ELM_LDFLAGS})
+set_target_properties(sherlock_eo PROPERTIES PREFIX "")
+install(TARGETS sherlock_eo DESTINATION ${DEST})
+
+add_executable(sandbox_efl
+ ${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_slave.c
+ ${PROJECT_SOURCE_DIR}/sandbox_ui.lv2/sandbox_efl.c
+ ${PROJECT_SOURCE_DIR}/symap/symap.c)
+target_link_libraries(sandbox_efl
+ ${ELM_LDFLAGS}
+ ${NANOMSG_LDFLAGS}
+ ${LILV_LDFLAGS}
+ dl)
+install(TARGETS sandbox_efl DESTINATION ${DEST})
+
configure_file(${PROJECT_SOURCE_DIR}/manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl)
install(FILES ${PROJECT_BINARY_DIR}/manifest.ttl DESTINATION ${DEST})
install(FILES ${PROJECT_SOURCE_DIR}/sherlock.ttl DESTINATION ${DEST})
+install(FILES ${PROJECT_SOURCE_DIR}/sherlock_ui.ttl DESTINATION ${DEST})
install(FILES ${PROJECT_SOURCE_DIR}/omk_logo_256x256.png DESTINATION ${DEST})
diff --git a/atom_inspector_ui.c b/atom_inspector_eo.c
index f9370a0..a19de3c 100644
--- a/atom_inspector_ui.c
+++ b/atom_inspector_eo.c
@@ -19,7 +19,7 @@
#include <sherlock.h>
-#include <lv2_eo_ui.h>
+#include <Elementary.h>
#define COUNT_MAX 2048 // maximal amount of events shown
#define STRING_BUF_SIZE 2048
@@ -38,8 +38,6 @@
typedef struct _UI UI;
struct _UI {
- eo_ui_t eoui;
-
LV2UI_Write_Function write_function;
LV2UI_Controller controller;
@@ -64,6 +62,7 @@ struct _UI {
LV2_Atom_Forge forge;
+ Evas_Object *widget;
Evas_Object *table;
Evas_Object *list;
Evas_Object *info;
@@ -861,16 +860,34 @@ _info_clicked(void *data, Evas_Object *obj, void *event_info)
}
}
-static Evas_Object *
-_content_get(eo_ui_t *eoui)
+static void
+_content_free(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
- UI *ui = (void *)eoui - offsetof(UI, eoui);
+ UI *ui = data;
- ui->table = elm_table_add(eoui->win);
+ ui->widget = NULL;
+}
+
+static void
+_content_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ UI *ui = data;
+
+ evas_object_del(ui->widget);
+}
+
+static Evas_Object *
+_content_get(UI *ui, Evas_Object *parent)
+{
+ ui->table = elm_table_add(parent);
if(ui->table)
{
elm_table_homogeneous_set(ui->table, EINA_FALSE);
elm_table_padding_set(ui->table, 0, 0);
+ evas_object_size_hint_min_set(ui->table, 1280, 720);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_FREE, _content_free, ui);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_DEL, _content_del, ui);
+
Evas_Object *panes = elm_panes_add(ui->table);
if(panes)
@@ -1033,37 +1050,22 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
if(strcmp(plugin_uri, SHERLOCK_ATOM_INSPECTOR_URI))
return NULL;
- eo_ui_driver_t driver;
- if(descriptor == &atom_inspector_eo)
- driver = EO_UI_DRIVER_EO;
- else if(descriptor == &atom_inspector_ui)
- driver = EO_UI_DRIVER_UI;
- else if(descriptor == &atom_inspector_x11)
- driver = EO_UI_DRIVER_X11;
- else if(descriptor == &atom_inspector_kx)
- driver = EO_UI_DRIVER_KX;
- else
- return NULL;
-
UI *ui = calloc(1, sizeof(UI));
if(!ui)
return NULL;
- eo_ui_t *eoui = &ui->eoui;
- eoui->driver = driver;
- eoui->content_get = _content_get;
- eoui->w = 1280,
- eoui->h = 720;
-
ui->write_function = write_function;
ui->controller = controller;
-
+
+ Evas_Object *parent = NULL;
for(int i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_URID__map))
- ui->map = (LV2_URID_Map *)features[i]->data;
+ ui->map = features[i]->data;
else if(!strcmp(features[i]->URI, LV2_URID__unmap))
- ui->unmap = (LV2_URID_Unmap *)features[i]->data;
+ ui->unmap = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__parent))
+ parent = features[i]->data;
}
if(!ui->map || !ui->unmap)
@@ -1072,6 +1074,11 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
free(ui);
return NULL;
}
+ if(!parent)
+ {
+ free(ui);
+ return NULL;
+ }
lv2_atom_forge_init(&ui->forge, ui->map);
@@ -1148,13 +1155,6 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
sprintf(ui->string_buf, "%s/omk_logo_256x256.png", bundle_path);
ui->logo_path = strdup(ui->string_buf);
- if(eoui_instantiate(eoui, descriptor, plugin_uri, bundle_path, write_function,
- controller, widget, features))
- {
- free(ui);
- return NULL;
- }
-
ui->uris.midi_MidiEvent = ui->map->map(ui->map->handle, LV2_MIDI__MidiEvent);
ui->uris.event_transfer = ui->map->map(ui->map->handle, LV2_ATOM__eventTransfer);
@@ -1205,6 +1205,14 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
_hash_set(ui, ui->uris.time_framesPerSecond);
_hash_set(ui, ui->uris.time_speed);
+ ui->widget = _content_get(ui, parent);
+ if(!ui->widget)
+ {
+ free(ui);
+ return NULL;
+ }
+ *(Evas_Object **)widget = ui->widget;
+
return ui;
}
@@ -1213,8 +1221,8 @@ cleanup(LV2UI_Handle handle)
{
UI *ui = handle;
- eoui_cleanup(&ui->eoui);
-
+ if(ui->widget)
+ evas_object_del(ui->widget);
if(ui->logo_path)
free(ui->logo_path);
@@ -1313,29 +1321,5 @@ const LV2UI_Descriptor atom_inspector_eo = {
.instantiate = instantiate,
.cleanup = cleanup,
.port_event = port_event,
- .extension_data = eoui_eo_extension_data
-};
-
-const LV2UI_Descriptor atom_inspector_ui = {
- .URI = SHERLOCK_ATOM_INSPECTOR_UI_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_ui_extension_data
-};
-
-const LV2UI_Descriptor atom_inspector_x11 = {
- .URI = SHERLOCK_ATOM_INSPECTOR_X11_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_x11_extension_data
-};
-
-const LV2UI_Descriptor atom_inspector_kx = {
- .URI = SHERLOCK_ATOM_INSPECTOR_KX_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_kx_extension_data
+ .extension_data = NULL
};
diff --git a/eo_ui.lv2/CMakeLists.txt b/eo_ui.lv2/CMakeLists.txt
deleted file mode 100644
index 55729b6..0000000
--- a/eo_ui.lv2/CMakeLists.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-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/COPYING b/eo_ui.lv2/COPYING
deleted file mode 100644
index ddb9a46..0000000
--- a/eo_ui.lv2/COPYING
+++ /dev/null
@@ -1,201 +0,0 @@
- The Artistic License 2.0
-
- Copyright (c) 2000-2006, The Perl Foundation.
-
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-Preamble
-
-This license establishes the terms under which a given free software
-Package may be copied, modified, distributed, and/or redistributed.
-The intent is that the Copyright Holder maintains some artistic
-control over the development of that Package while still keeping the
-Package available as open source and free software.
-
-You are always permitted to make arrangements wholly outside of this
-license directly with the Copyright Holder of a given Package. If the
-terms of this license do not permit the full use that you propose to
-make of the Package, you should contact the Copyright Holder and seek
-a different licensing arrangement.
-
-Definitions
-
- "Copyright Holder" means the individual(s) or organization(s)
- named in the copyright notice for the entire Package.
-
- "Contributor" means any party that has contributed code or other
- material to the Package, in accordance with the Copyright Holder's
- procedures.
-
- "You" and "your" means any person who would like to copy,
- distribute, or modify the Package.
-
- "Package" means the collection of files distributed by the
- Copyright Holder, and derivatives of that collection and/or of
- those files. A given Package may consist of either the Standard
- Version, or a Modified Version.
-
- "Distribute" means providing a copy of the Package or making it
- accessible to anyone else, or in the case of a company or
- organization, to others outside of your company or organization.
-
- "Distributor Fee" means any fee that you charge for Distributing
- this Package or providing support for this Package to another
- party. It does not mean licensing fees.
-
- "Standard Version" refers to the Package if it has not been
- modified, or has been modified only in ways explicitly requested
- by the Copyright Holder.
-
- "Modified Version" means the Package, if it has been changed, and
- such changes were not explicitly requested by the Copyright
- Holder.
-
- "Original License" means this Artistic License as Distributed with
- the Standard Version of the Package, in its current version or as
- it may be modified by The Perl Foundation in the future.
-
- "Source" form means the source code, documentation source, and
- configuration files for the Package.
-
- "Compiled" form means the compiled bytecode, object code, binary,
- or any other form resulting from mechanical transformation or
- translation of the Source form.
-
-
-Permission for Use and Modification Without Distribution
-
-(1) You are permitted to use the Standard Version and create and use
-Modified Versions for any purpose without restriction, provided that
-you do not Distribute the Modified Version.
-
-
-Permissions for Redistribution of the Standard Version
-
-(2) You may Distribute verbatim copies of the Source form of the
-Standard Version of this Package in any medium without restriction,
-either gratis or for a Distributor Fee, provided that you duplicate
-all of the original copyright notices and associated disclaimers. At
-your discretion, such verbatim copies may or may not include a
-Compiled form of the Package.
-
-(3) You may apply any bug fixes, portability changes, and other
-modifications made available from the Copyright Holder. The resulting
-Package will still be considered the Standard Version, and as such
-will be subject to the Original License.
-
-
-Distribution of Modified Versions of the Package as Source
-
-(4) You may Distribute your Modified Version as Source (either gratis
-or for a Distributor Fee, and with or without a Compiled form of the
-Modified Version) provided that you clearly document how it differs
-from the Standard Version, including, but not limited to, documenting
-any non-standard features, executables, or modules, and provided that
-you do at least ONE of the following:
-
- (a) make the Modified Version available to the Copyright Holder
- of the Standard Version, under the Original License, so that the
- Copyright Holder may include your modifications in the Standard
- Version.
-
- (b) ensure that installation of your Modified Version does not
- prevent the user installing or running the Standard Version. In
- addition, the Modified Version must bear a name that is different
- from the name of the Standard Version.
-
- (c) allow anyone who receives a copy of the Modified Version to
- make the Source form of the Modified Version available to others
- under
-
- (i) the Original License or
-
- (ii) a license that permits the licensee to freely copy,
- modify and redistribute the Modified Version using the same
- licensing terms that apply to the copy that the licensee
- received, and requires that the Source form of the Modified
- Version, and of any works derived from it, be made freely
- available in that license fees are prohibited but Distributor
- Fees are allowed.
-
-
-Distribution of Compiled Forms of the Standard Version
-or Modified Versions without the Source
-
-(5) You may Distribute Compiled forms of the Standard Version without
-the Source, provided that you include complete instructions on how to
-get the Source of the Standard Version. Such instructions must be
-valid at the time of your distribution. If these instructions, at any
-time while you are carrying out such distribution, become invalid, you
-must provide new instructions on demand or cease further distribution.
-If you provide valid instructions or cease distribution within thirty
-days after you become aware that the instructions are invalid, then
-you do not forfeit any of your rights under this license.
-
-(6) You may Distribute a Modified Version in Compiled form without
-the Source, provided that you comply with Section 4 with respect to
-the Source of the Modified Version.
-
-
-Aggregating or Linking the Package
-
-(7) You may aggregate the Package (either the Standard Version or
-Modified Version) with other packages and Distribute the resulting
-aggregation provided that you do not charge a licensing fee for the
-Package. Distributor Fees are permitted, and licensing fees for other
-components in the aggregation are permitted. The terms of this license
-apply to the use and Distribution of the Standard or Modified Versions
-as included in the aggregation.
-
-(8) You are permitted to link Modified and Standard Versions with
-other works, to embed the Package in a larger work of your own, or to
-build stand-alone binary or bytecode versions of applications that
-include the Package, and Distribute the result without restriction,
-provided the result does not expose a direct interface to the Package.
-
-
-Items That are Not Considered Part of a Modified Version
-
-(9) Works (including, but not limited to, modules and scripts) that
-merely extend or make use of the Package, do not, by themselves, cause
-the Package to be a Modified Version. In addition, such works are not
-considered parts of the Package itself, and are not subject to the
-terms of this license.
-
-
-General Provisions
-
-(10) Any use, modification, and distribution of the Standard or
-Modified Versions is governed by this Artistic License. By using,
-modifying or distributing the Package, you accept this license. Do not
-use, modify, or distribute the Package, if you do not accept this
-license.
-
-(11) If your Modified Version has been derived from a Modified
-Version made by someone other than you, you are nevertheless required
-to ensure that your Modified Version complies with the requirements of
-this license.
-
-(12) This license does not grant you the right to use any trademark,
-service mark, tradename, or logo of the Copyright Holder.
-
-(13) This license includes the non-exclusive, worldwide,
-free-of-charge patent license to make, have made, use, offer to sell,
-sell, import and otherwise transfer the Package with respect to any
-patent claims licensable by the Copyright Holder that are necessarily
-infringed by the Package. If you institute patent litigation
-(including a cross-claim or counterclaim) against any party alleging
-that the Package constitutes direct or contributory patent
-infringement, then this Artistic License to you shall terminate on the
-date that such litigation is filed.
-
-(14) Disclaimer of Warranty:
-THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
-IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
-NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
-LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/eo_ui.lv2/README.md b/eo_ui.lv2/README.md
deleted file mode 100644
index 328188e..0000000
--- a/eo_ui.lv2/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# eo\_ui.lv2
-
-## Enlightened User Interface Extension for the LV2 Plugin Specification
diff --git a/eo_ui.lv2/lv2_eo_ui.h b/eo_ui.lv2/lv2_eo_ui.h
deleted file mode 100644
index e4d7646..0000000
--- a/eo_ui.lv2/lv2_eo_ui.h
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _EO_UI_H
-#define _EO_UI_H
-
-#include <Elementary.h>
-
-#if defined(X11_UI_WRAP)
-# include <Ecore_X.h>
-#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;
-typedef struct _eo_ui_t eo_ui_t;
-typedef Evas_Object *(*eo_ui_content_get)(eo_ui_t *eoui);
-
-enum _eo_ui_driver_t {
- EO_UI_DRIVER_NONE = 0,
- EO_UI_DRIVER_EO,
- EO_UI_DRIVER_X11,
- EO_UI_DRIVER_UI,
- EO_UI_DRIVER_KX
-};
-
-struct _eo_ui_t {
- eo_ui_driver_t driver;
- LV2UI_Controller controller;
- int w, h;
-
- Evas_Object *win; // main window
- Evas_Object *bg; // background
-
- Evas_Object *content;
- eo_ui_content_get content_get;
-
- LV2_URID window_title;
- LV2_URID atom_string;
- char title [512];
-
- union {
- // eo iface
- struct {
- Evas_Object *parent;
- LV2UI_Resize *resize;
- } eo;
-
- // show iface
- struct {
- volatile int done;
- } ui;
-
-#if defined(X11_UI_WRAP)
- // X11 iface
- struct {
- Ecore_X_Window parent;
- Ecore_X_Window child;
- LV2UI_Resize *resize;
-
- Ecore_Evas *ee;
- } x11;
-#endif
-
- // external-ui iface
- struct {
- LV2_External_UI_Widget widget;
- const LV2_External_UI_Host *host;
- } kx;
- };
-};
-
-// Idle interface
-static inline int
-_idle_cb(LV2UI_Handle instance)
-{
- eo_ui_t *eoui = instance;
- if(!eoui)
- return -1;
-
- ecore_main_loop_iterate();
-
- return eoui->ui.done;
-}
-
-static const LV2UI_Idle_Interface idle_ext = {
- .idle = _idle_cb
-};
-
-static inline void
-_show_delete_request(void *data, Evas_Object *obj, void *event_info)
-{
- eo_ui_t *eoui = data;
- if(!eoui)
- return;
-
- // set done flag, host will then call _hide_cb
- eoui->ui.done = 1;
-}
-
-// Show Interface
-static inline int
-_show_cb(LV2UI_Handle instance)
-{
- eo_ui_t *eoui = instance;
- if(!eoui)
- return -1;
-
- // create main window
- 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",
- _show_delete_request, eoui);
- evas_object_resize(eoui->win, eoui->w, eoui->h);
- evas_object_show(eoui->win);
-
- eoui->bg = elm_bg_add(eoui->win);
- if(eoui->bg)
- {
- elm_bg_color_set(eoui->bg, 64, 64, 64);
- evas_object_size_hint_weight_set(eoui->bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_show(eoui->bg);
- elm_win_resize_object_add(eoui->win, eoui->bg);
- }
-
- eoui->content = eoui->content_get(eoui);
- if(eoui->content)
- {
- evas_object_size_hint_weight_set(eoui->content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->content, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_show(eoui->content);
- elm_win_resize_object_add(eoui->win, eoui->content);
- }
-
- return 0;
-}
-
-static inline int
-_hide_cb(LV2UI_Handle instance)
-{
- eo_ui_t *eoui = instance;
- if(!eoui)
- return -1;
-
- // hide & delete bg&main window
- if(eoui->win)
- {
- if(eoui->content)
- {
- elm_win_resize_object_del(eoui->win, eoui->content);
- evas_object_del(eoui->content);
- eoui->content = NULL;
- }
- if(eoui->bg)
- {
- elm_win_resize_object_del(eoui->win, eoui->bg);
- evas_object_del(eoui->bg);
- eoui->bg = NULL;
- }
- evas_object_del(eoui->win);
- eoui->win = NULL;
- }
-
- // reset done flag
- eoui->ui.done = 0;
-
- return 0;
-}
-
-static const LV2UI_Show_Interface show_ext = {
- .show = _show_cb,
- .hide = _hide_cb
-};
-
-// External-UI Interface
-static inline void
-_kx_run(LV2_External_UI_Widget *widget)
-{
- eo_ui_t *eoui = widget
- ? (void *)widget - offsetof(eo_ui_t, kx.widget)
- : NULL;
- if(!eoui)
- return;
-
- ecore_main_loop_iterate();
-}
-
-static inline void
-_kx_hide(LV2_External_UI_Widget *widget)
-{
- eo_ui_t *eoui = widget
- ? (void *)widget - offsetof(eo_ui_t, kx.widget)
- : NULL;
- if(!eoui)
- return;
-
- // hide & delete bg & main window
- if(eoui->win)
- {
- if(eoui->content)
- {
- elm_win_resize_object_del(eoui->win, eoui->content);
- evas_object_del(eoui->content);
- eoui->content = NULL;
- }
- if(eoui->bg)
- {
- elm_win_resize_object_del(eoui->win, eoui->bg);
- evas_object_del(eoui->bg);
- eoui->bg = NULL;
- }
- evas_object_del(eoui->win); // will call _kx_free
- eoui->win = NULL;
- }
-}
-
-static inline void
-_kx_free(void *data, Evas *e, Evas_Object *obj, void *event_info)
-{
- eo_ui_t *eoui = data;
- if(!eoui)
- return;
-
- eoui->content = NULL;
- eoui->bg = NULL;
- eoui->win = NULL;
-
- if(eoui->kx.host->ui_closed && eoui->controller)
- eoui->kx.host->ui_closed(eoui->controller);
-}
-
-static inline void
-_kx_show(LV2_External_UI_Widget *widget)
-{
- eo_ui_t *eoui = widget
- ? (void *)widget - offsetof(eo_ui_t, kx.widget)
- : NULL;
- if(!eoui || eoui->win)
- return;
-
- // create main window
- eoui->win = elm_win_add(NULL, eoui->title, ELM_WIN_BASIC);
- if(!eoui->win)
- return;
- elm_win_autodel_set(eoui->win, EINA_TRUE);
- evas_object_event_callback_add(eoui->win, EVAS_CALLBACK_FREE, _kx_free, eoui);
- evas_object_resize(eoui->win, eoui->w, eoui->h);
- evas_object_show(eoui->win);
-
- eoui->bg = elm_bg_add(eoui->win);
- if(eoui->bg)
- {
- elm_bg_color_set(eoui->bg, 64, 64, 64);
- evas_object_size_hint_weight_set(eoui->bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_show(eoui->bg);
- elm_win_resize_object_add(eoui->win, eoui->bg);
- }
-
- eoui->content = eoui->content_get(eoui);
- if(eoui->content)
- {
- evas_object_size_hint_weight_set(eoui->content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->content, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_show(eoui->content);
- elm_win_resize_object_add(eoui->win, eoui->content);
- }
-}
-
-// Resize Interface
-static inline int
-_ui_resize_cb(LV2UI_Feature_Handle instance, int w, int h)
-{
- eo_ui_t *eoui = instance;
- if(!eoui)
- return -1;
-
- // check whether size actually needs any update
- if( (eoui->w == w) && (eoui->h == h) )
- return 0;
-
- // update size
- eoui->w = w;
- eoui->h = h;
-
- // resize main window
-#if defined(X11_UI_WRAP)
- if(eoui->x11.ee)
- ecore_evas_resize(eoui->x11.ee, eoui->w, eoui->h);
-#endif
- if(eoui->win)
- evas_object_resize(eoui->win, eoui->w, eoui->h);
- if(eoui->bg)
- evas_object_resize(eoui->bg, eoui->w, eoui->h);
- if(eoui->content)
- evas_object_resize(eoui->content, eoui->w, eoui->h);
-
- return 0;
-}
-
-static const LV2UI_Resize resize_ext = {
- .handle = NULL,
- .ui_resize = _ui_resize_cb
-};
-
-#if defined(X11_UI_WRAP)
-static void
-_x11_ui_wrap_mouse_in(Ecore_Evas *ee)
-{
- eo_ui_t *eoui = ecore_evas_data_get(ee, "eoui");
- if(!eoui)
- return;
-
- if(eoui->x11.parent)
- ecore_x_window_focus(eoui->x11.parent);
-}
-#endif
-
-static inline int
-eoui_instantiate(eo_ui_t *eoui, 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)
-{
- //eoui->driver = NULL; set by ui plugin
- eoui->controller = controller;
- 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)
- {
- case EO_UI_DRIVER_EO:
- {
- eoui->eo.parent = NULL; // mandatory
- eoui->eo.resize = NULL; // optional
- for(int i=0; features[i]; i++)
- {
- 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 = features[i]->data;
- }
- if(!eoui->eo.parent)
- return -1;
-
- eoui->win = eoui->eo.parent;
-
- eoui->content = eoui->content_get(eoui);
-
- *(Evas_Object **)widget = eoui->content;
-
- if(eoui->eo.resize)
- eoui->eo.resize->ui_resize(eoui->eo.resize->handle, eoui->w, eoui->h);
-
- break;
- }
-
- case EO_UI_DRIVER_UI:
- {
- // 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);
-
- break;
- }
-
-#if defined(X11_UI_WRAP)
- case EO_UI_DRIVER_X11:
- {
- eoui->x11.parent = 0; // mandatory
- eoui->x11.resize = NULL; // optional
- int host_provides_idle_iface = 0; // mandatory
- for(int i=0; features[i]; i++)
- {
- 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 = features[i]->data;
- else if(!strcmp(features[i]->URI, LV2_UI__idleInterface))
- host_provides_idle_iface = 1;
- }
- if(!eoui->x11.parent || !host_provides_idle_iface)
- return -1;
-
- // initialize elementary library
- _elm_startup_time = ecore_time_unix_get();
- elm_init(0, NULL);
-
- eoui->x11.ee = ecore_evas_gl_x11_new(NULL, eoui->x11.parent, 0, 0,
- eoui->w, eoui->h);
- if(!eoui->x11.ee)
- eoui->x11.ee = ecore_evas_software_x11_new(NULL, eoui->x11.parent, 0, 0,
- eoui->w, eoui->h);
- if(!eoui->x11.ee)
- {
- //elm_shutdown();
- return -1;
- }
- ecore_evas_data_set(eoui->x11.ee, "eoui", eoui);
- ecore_evas_callback_mouse_in_set(eoui->x11.ee, _x11_ui_wrap_mouse_in);
- ecore_evas_show(eoui->x11.ee);
-
- eoui->win = elm_win_fake_add(eoui->x11.ee);
- if(eoui->win)
- {
- evas_object_resize(eoui->win, eoui->w, eoui->h);
- evas_object_show(eoui->win);
-
- eoui->bg = elm_bg_add(eoui->win);
- if(eoui->bg)
- {
- elm_bg_color_set(eoui->bg, 64, 64, 64);
- evas_object_size_hint_weight_set(eoui->bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_resize(eoui->bg, eoui->w, eoui->h);
- evas_object_show(eoui->bg);
- }
-
- eoui->content = eoui->content_get(eoui);
- if(eoui->content)
- {
- evas_object_size_hint_weight_set(eoui->content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- evas_object_size_hint_align_set(eoui->content, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_resize(eoui->content, eoui->w, eoui->h);
- evas_object_show(eoui->content);
- }
- }
-
- eoui->x11.child = elm_win_xwindow_get(eoui->win);
- *(uintptr_t *)widget = eoui->x11.child;
-
- if(eoui->x11.resize)
- eoui->x11.resize->ui_resize(eoui->x11.resize->handle, eoui->w, eoui->h);
-
- break;
- }
-#endif
-
- 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);
-
- eoui->kx.widget.run = _kx_run;
- eoui->kx.widget.show = _kx_show;
- eoui->kx.widget.hide = _kx_hide;
-
- *(LV2_External_UI_Widget **)widget = &eoui->kx.widget;
-
- break;
- }
-
- default:
- break;
- }
-
- return 0;
-}
-
-static inline void
-eoui_cleanup(eo_ui_t *eoui)
-{
- switch(eoui->driver)
- {
- case EO_UI_DRIVER_EO:
- {
- eoui->content = NULL;
-
- break;
- }
-
- case EO_UI_DRIVER_UI:
- {
- //elm_shutdown();
-
- break;
- }
-
-#if defined(X11_UI_WRAP)
- case EO_UI_DRIVER_X11:
- {
- if(eoui->win)
- {
- if(eoui->content)
- {
- elm_win_resize_object_del(eoui->win, eoui->content);
- evas_object_del(eoui->content);
- }
- if(eoui->bg)
- {
- elm_win_resize_object_del(eoui->win, eoui->bg);
- evas_object_del(eoui->bg);
- }
- evas_object_del(eoui->win);
- }
- if(eoui->x11.ee)
- {
- //ecore_evas_free(eoui->x11.ee);
- }
-
- //elm_shutdown();
-
- break;
- }
-#endif
-
- case EO_UI_DRIVER_KX:
- {
- //elm_shutdown();
-
- break;
- }
-
- default:
- break;
- }
-
- // clear eoui
- memset(eoui, 0, sizeof(eo_ui_t));
-}
-
-#define eoui_eo_extension_data NULL
-#define eoui_kx_extension_data NULL
-
-// extension data callback for show interface UI
-static inline const void *
-eoui_ui_extension_data(const char *uri)
-{
- if(!strcmp(uri, LV2_UI__idleInterface))
- return &idle_ext;
- else if(!strcmp(uri, LV2_UI__showInterface))
- return &show_ext;
-
- return NULL;
-}
-
-// extension data callback for X11UI
-static inline const void *
-eoui_x11_extension_data(const char *uri)
-{
- if(!strcmp(uri, LV2_UI__idleInterface))
- return &idle_ext;
- else if(!strcmp(uri, LV2_UI__resize))
- return &resize_ext;
-
- return NULL;
-}
-
-#endif // _EO_UI_H
diff --git a/eo_ui.lv2/manifest.ttl b/eo_ui.lv2/manifest.ttl
deleted file mode 100644
index 0949129..0000000
--- a/eo_ui.lv2/manifest.ttl
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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.
-
-@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix owl: <http://www.w3.org/2002/07/owl#> .
-
-ui:EoUI
- a rdfs:Class ,
- owl:Class ;
- rdfs:subClassOf ui:UI ;
- rdfs:comment """
-A UI where the LV2_Widget is a pointer to an Evas/Elementary compatible Object
-(e.g. an "Evas_Object *" or "Eo *"), and the host guarantees that the
-Ecore_Evas or Elementary library has been initialised and the Ecore or
-Elementary main loop is running before an UI of this type is instantiated.""" .
diff --git a/eo_ui.lv2/test/eo.c b/eo_ui.lv2/test/eo.c
deleted file mode 100644
index 91573b9..0000000
--- a/eo_ui.lv2/test/eo.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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
deleted file mode 100644
index a5148c1..0000000
--- a/eo_ui.lv2/test/eo.ttl
+++ /dev/null
@@ -1,104 +0,0 @@
-# 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
deleted file mode 100644
index 0939227..0000000
--- a/eo_ui.lv2/test/eo_ui.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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
deleted file mode 100644
index dabc244..0000000
--- a/eo_ui.lv2/test/lv2_white.png
+++ /dev/null
Binary files differ
diff --git a/eo_ui.lv2/test/manifest.ttl.in b/eo_ui.lv2/test/manifest.ttl.in
deleted file mode 100644
index 7e6c8bc..0000000
--- a/eo_ui.lv2/test/manifest.ttl.in
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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> .
diff --git a/eo_ui.lv2/lv2_external_ui.h b/ext_ui.lv2/lv2_external_ui.h
index 2c9e6ee..2c9e6ee 100644
--- a/eo_ui.lv2/lv2_external_ui.h
+++ b/ext_ui.lv2/lv2_external_ui.h
diff --git a/manifest.ttl.in b/manifest.ttl.in
index 8c63cb3..b2f4be5 100644
--- a/manifest.ttl.in
+++ b/manifest.ttl.in
@@ -37,28 +37,23 @@ sherlock:atom_inspector
lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
- @EO_UI_WRAP@ui:ui sherlock:atom_inspector_eo ;
- @UI_UI_WRAP@ui:ui sherlock:atom_inspector_ui ;
- @KX_UI_WRAP@ui:ui sherlock:atom_inspector_kx ;
- @X11_UI_WRAP@ui:ui sherlock:atom_inspector_x11 ;
+ @UI_UI_WRAP@ui:ui sherlock:atom_inspector_1_ui ;
+ @KX_UI_WRAP@ui:ui sherlock:atom_inspector_2_kx ;
+ @EO_UI_WRAP@ui:ui sherlock:atom_inspector_3_eo ;
rdfs:seeAlso <sherlock.ttl> .
-sherlock:atom_inspector_eo
- a ui:EoUI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:atom_inspector_ui
+sherlock:atom_inspector_1_ui
a ui:UI ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:atom_inspector_x11
- a ui:X11UI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:atom_inspector_kx
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:atom_inspector_2_kx
a kx:Widget ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:atom_inspector_3_eo
+ a ui:EoUI ;
+ ui:binary <sherlock_eo@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
# MIDI Inspector Plugin
sherlock:midi_inspector
@@ -66,28 +61,23 @@ sherlock:midi_inspector
lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
- @EO_UI_WRAP@ui:ui sherlock:midi_inspector_eo ;
- @UI_UI_WRAP@ui:ui sherlock:midi_inspector_ui ;
- @KX_UI_WRAP@ui:ui sherlock:midi_inspector_kx ;
- @X11_UI_WRAP@ui:ui sherlock:midi_inspector_x11 ;
+ @UI_UI_WRAP@ui:ui sherlock:midi_inspector_1_ui ;
+ @KX_UI_WRAP@ui:ui sherlock:midi_inspector_2_kx ;
+ @EO_UI_WRAP@ui:ui sherlock:midi_inspector_3_eo ;
rdfs:seeAlso <sherlock.ttl> .
-sherlock:midi_inspector_eo
- a ui:EoUI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:midi_inspector_ui
+sherlock:midi_inspector_1_ui
a ui:UI ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:midi_inspector_x11
- a ui:X11UI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:midi_inspector_kx
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:midi_inspector_2_kx
a kx:Widget ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:midi_inspector_3_eo
+ a ui:EoUI ;
+ ui:binary <sherlock_eo@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
# OSC Inspector Plugin
sherlock:osc_inspector
@@ -95,25 +85,20 @@ sherlock:osc_inspector
lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
- @EO_UI_WRAP@ui:ui sherlock:osc_inspector_eo ;
- @UI_UI_WRAP@ui:ui sherlock:osc_inspector_ui ;
- @KX_UI_WRAP@ui:ui sherlock:osc_inspector_kx ;
- @X11_UI_WRAP@ui:ui sherlock:osc_inspector_x11 ;
+ @UI_UI_WRAP@ui:ui sherlock:osc_inspector_1_ui ;
+ @KX_UI_WRAP@ui:ui sherlock:osc_inspector_2_kx ;
+ @EO_UI_WRAP@ui:ui sherlock:osc_inspector_3_eo ;
rdfs:seeAlso <sherlock.ttl> .
-sherlock:osc_inspector_eo
- a ui:EoUI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:osc_inspector_ui
+sherlock:osc_inspector_1_ui
a ui:UI ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:osc_inspector_x11
- a ui:X11UI ;
- ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
-sherlock:osc_inspector_kx
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:osc_inspector_2_kx
a kx:Widget ;
ui:binary <sherlock_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
- rdfs:seeAlso <sherlock.ttl> .
+ rdfs:seeAlso <sherlock_ui.ttl> .
+sherlock:osc_inspector_3_eo
+ a ui:EoUI ;
+ ui:binary <sherlock_eo@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
diff --git a/midi_inspector_ui.c b/midi_inspector_eo.c
index 09383cb..0418192 100644
--- a/midi_inspector_ui.c
+++ b/midi_inspector_eo.c
@@ -17,7 +17,7 @@
#include <sherlock.h>
-#include <lv2_eo_ui.h>
+#include <Elementary.h>
#define COUNT_MAX 2048 // maximal amount of events shown
#define STRING_BUF_SIZE 2048
@@ -27,8 +27,6 @@
typedef struct _UI UI;
struct _UI {
- eo_ui_t eoui;
-
LV2UI_Write_Function write_function;
LV2UI_Controller controller;
@@ -36,6 +34,7 @@ struct _UI {
LV2_Atom_Forge forge;
LV2_URID event_transfer;
+ Evas_Object *widget;
Evas_Object *table;
Evas_Object *list;
Evas_Object *clear;
@@ -551,16 +550,33 @@ _info_clicked(void *data, Evas_Object *obj, void *event_info)
}
}
-static Evas_Object *
-_content_get(eo_ui_t *eoui)
+static void
+_content_free(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ UI *ui = data;
+
+ ui->widget = NULL;
+}
+
+static void
+_content_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
- UI *ui = (void *)eoui - offsetof(UI, eoui);
+ UI *ui = data;
- ui->table = elm_table_add(eoui->win);
+ evas_object_del(ui->widget);
+}
+
+static Evas_Object *
+_content_get(UI *ui, Evas_Object *parent)
+{
+ ui->table = elm_table_add(parent);
if(ui->table)
{
elm_table_homogeneous_set(ui->table, EINA_FALSE);
elm_table_padding_set(ui->table, 0, 0);
+ evas_object_size_hint_min_set(ui->table, 600, 800);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_FREE, _content_free, ui);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_DEL, _content_del, ui);
ui->list = elm_genlist_add(ui->table);
if(ui->list)
@@ -688,35 +704,20 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
if(strcmp(plugin_uri, SHERLOCK_MIDI_INSPECTOR_URI))
return NULL;
- eo_ui_driver_t driver;
- if(descriptor == &midi_inspector_eo)
- driver = EO_UI_DRIVER_EO;
- else if(descriptor == &midi_inspector_ui)
- driver = EO_UI_DRIVER_UI;
- else if(descriptor == &midi_inspector_x11)
- driver = EO_UI_DRIVER_X11;
- else if(descriptor == &midi_inspector_kx)
- driver = EO_UI_DRIVER_KX;
- else
- return NULL;
-
UI *ui = calloc(1, sizeof(UI));
if(!ui)
return NULL;
- eo_ui_t *eoui = &ui->eoui;
- eoui->driver = driver;
- eoui->content_get = _content_get;
- eoui->w = 600,
- eoui->h = 800;
-
ui->write_function = write_function;
ui->controller = controller;
-
+
+ Evas_Object *parent = NULL;
for(int i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_URID__map))
- ui->map = (LV2_URID_Map *)features[i]->data;
+ ui->map = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__parent))
+ parent = features[i]->data;
}
if(!ui->map)
@@ -725,6 +726,11 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
free(ui);
return NULL;
}
+ if(!parent)
+ {
+ free(ui);
+ return NULL;
+ }
ui->event_transfer = ui->map->map(ui->map->handle, LV2_ATOM__eventTransfer);
lv2_atom_forge_init(&ui->forge, ui->map);
@@ -752,12 +758,13 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
sprintf(ui->string_buf, "%s/omk_logo_256x256.png", bundle_path);
ui->logo_path = strdup(ui->string_buf);
- if(eoui_instantiate(eoui, descriptor, plugin_uri, bundle_path, write_function,
- controller, widget, features))
+ ui->widget = _content_get(ui, parent);
+ if(!ui->widget)
{
free(ui);
return NULL;
}
+ *(Evas_Object **)widget = ui->widget;
return ui;
}
@@ -767,7 +774,8 @@ cleanup(LV2UI_Handle handle)
{
UI *ui = handle;
- eoui_cleanup(&ui->eoui);
+ if(ui->widget)
+ evas_object_del(ui->widget);
if(ui->logo_path)
free(ui->logo_path);
@@ -854,29 +862,5 @@ const LV2UI_Descriptor midi_inspector_eo = {
.instantiate = instantiate,
.cleanup = cleanup,
.port_event = port_event,
- .extension_data = eoui_eo_extension_data
-};
-
-const LV2UI_Descriptor midi_inspector_ui = {
- .URI = SHERLOCK_MIDI_INSPECTOR_UI_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_ui_extension_data
-};
-
-const LV2UI_Descriptor midi_inspector_x11 = {
- .URI = SHERLOCK_MIDI_INSPECTOR_X11_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_x11_extension_data
-};
-
-const LV2UI_Descriptor midi_inspector_kx = {
- .URI = SHERLOCK_MIDI_INSPECTOR_KX_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_kx_extension_data
+ .extension_data = NULL
};
diff --git a/osc_inspector_ui.c b/osc_inspector_eo.c
index ee8d53e..1c6f669 100644
--- a/osc_inspector_ui.c
+++ b/osc_inspector_eo.c
@@ -19,9 +19,10 @@
#include <sherlock.h>
-#include <lv2_eo_ui.h>
#include <lv2_osc.h>
+#include <Elementary.h>
+
#define COUNT_MAX 2048 // maximal amount of events shown
#define STRING_BUF_SIZE 2048
#define STRING_MAX 256
@@ -30,8 +31,6 @@
typedef struct _UI UI;
struct _UI {
- eo_ui_t eoui;
-
LV2UI_Write_Function write_function;
LV2UI_Controller controller;
@@ -41,6 +40,7 @@ struct _UI {
LV2_URID midi_event;
osc_forge_t oforge;
+ Evas_Object *widget;
Evas_Object *table;
Evas_Object *list;
Evas_Object *clear;
@@ -611,16 +611,33 @@ _info_clicked(void *data, Evas_Object *obj, void *event_info)
}
}
-static Evas_Object *
-_content_get(eo_ui_t *eoui)
+static void
+_content_free(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
- UI *ui = (void *)eoui - offsetof(UI, eoui);
+ UI *ui = data;
+
+ ui->widget = NULL;
+}
+
+static void
+_content_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ UI *ui = data;
- ui->table = elm_table_add(eoui->win);
+ evas_object_del(ui->widget);
+}
+
+static Evas_Object *
+_content_get(UI *ui, Evas_Object *parent)
+{
+ ui->table = elm_table_add(parent);
if(ui->table)
{
elm_table_homogeneous_set(ui->table, EINA_FALSE);
elm_table_padding_set(ui->table, 0, 0);
+ evas_object_size_hint_min_set(ui->table, 600, 800);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_FREE, _content_free, ui);
+ evas_object_event_callback_add(ui->table, EVAS_CALLBACK_DEL, _content_del, ui);
ui->list = elm_genlist_add(ui->table);
if(ui->list)
@@ -754,35 +771,20 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
if(strcmp(plugin_uri, SHERLOCK_OSC_INSPECTOR_URI))
return NULL;
- eo_ui_driver_t driver;
- if(descriptor == &osc_inspector_eo)
- driver = EO_UI_DRIVER_EO;
- else if(descriptor == &osc_inspector_ui)
- driver = EO_UI_DRIVER_UI;
- else if(descriptor == &osc_inspector_x11)
- driver = EO_UI_DRIVER_X11;
- else if(descriptor == &osc_inspector_kx)
- driver = EO_UI_DRIVER_KX;
- else
- return NULL;
-
UI *ui = calloc(1, sizeof(UI));
if(!ui)
return NULL;
- eo_ui_t *eoui = &ui->eoui;
- eoui->driver = driver;
- eoui->content_get = _content_get;
- eoui->w = 600,
- eoui->h = 800;
-
ui->write_function = write_function;
ui->controller = controller;
-
+
+ Evas_Object *parent = NULL;
for(int i=0; features[i]; i++)
{
if(!strcmp(features[i]->URI, LV2_URID__map))
- ui->map = (LV2_URID_Map *)features[i]->data;
+ ui->map = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__parent))
+ parent = features[i]->data;
}
if(!ui->map)
@@ -791,6 +793,11 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
free(ui);
return NULL;
}
+ if(!parent)
+ {
+ free(ui);
+ return NULL;
+ }
ui->event_transfer = ui->map->map(ui->map->handle, LV2_ATOM__eventTransfer);
ui->midi_event = ui->map->map(ui->map->handle, LV2_MIDI__MidiEvent);
@@ -830,12 +837,13 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
sprintf(ui->string_buf, "%s/omk_logo_256x256.png", bundle_path);
ui->logo_path = strdup(ui->string_buf);
- if(eoui_instantiate(eoui, descriptor, plugin_uri, bundle_path, write_function,
- controller, widget, features))
+ ui->widget = _content_get(ui, parent);
+ if(!ui->widget)
{
free(ui);
return NULL;
}
+ *(Evas_Object **)widget = ui->widget;
return ui;
}
@@ -845,8 +853,8 @@ cleanup(LV2UI_Handle handle)
{
UI *ui = handle;
- eoui_cleanup(&ui->eoui);
-
+ if(ui->widget)
+ evas_object_del(ui->widget);
if(ui->logo_path)
free(ui->logo_path);
@@ -935,29 +943,5 @@ const LV2UI_Descriptor osc_inspector_eo = {
.instantiate = instantiate,
.cleanup = cleanup,
.port_event = port_event,
- .extension_data = eoui_eo_extension_data
-};
-
-const LV2UI_Descriptor osc_inspector_ui = {
- .URI = SHERLOCK_OSC_INSPECTOR_UI_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_ui_extension_data
-};
-
-const LV2UI_Descriptor osc_inspector_x11 = {
- .URI = SHERLOCK_OSC_INSPECTOR_X11_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_x11_extension_data
-};
-
-const LV2UI_Descriptor osc_inspector_kx = {
- .URI = SHERLOCK_OSC_INSPECTOR_KX_URI,
- .instantiate = instantiate,
- .cleanup = cleanup,
- .port_event = port_event,
- .extension_data = eoui_kx_extension_data
+ .extension_data = NULL
};
diff --git a/sandbox_ui.lv2/sandbox_efl.c b/sandbox_ui.lv2/sandbox_efl.c
new file mode 100644
index 0000000..90211de
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_efl.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sandbox_slave.h>
+
+#include <Elementary.h>
+
+typedef struct _app_t app_t;
+
+struct _app_t {
+ sandbox_slave_t *sb;
+
+ Evas_Object *win;
+ Evas_Object *bg;
+ Evas_Object *widget;
+ Ecore_Fd_Handler *fd;
+};
+
+static Eina_Bool
+_recv(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ sandbox_slave_t *sb = data;
+
+ sandbox_slave_recv(sb);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_del_request(void *data, Evas_Object *obj, void *event_info)
+{
+ app_t *app = data;
+
+ elm_exit();
+ app->bg = NULL;
+ app->win = NULL;
+}
+
+static inline int
+_init(sandbox_slave_t *sb, void *data)
+{
+ app_t *app= data;
+
+ int w = 640;
+ int h = 360;
+
+ const char *title = sandbox_slave_title_get(sb);
+ app->win = elm_win_add(NULL, title, ELM_WIN_BASIC);
+ if(!app->win)
+ {
+ fprintf(stderr, "elm_win_add failed\n");
+ goto fail;
+ }
+ elm_win_title_set(app->win, title);
+ elm_win_autodel_set(app->win, EINA_TRUE);
+ evas_object_smart_callback_add(app->win, "delete,request", _del_request, app);
+
+ app->bg = elm_bg_add(app->win);
+ if(!app->bg)
+ {
+ fprintf(stderr, "elm_bg_add failed\n");
+ goto fail;
+ }
+ elm_bg_color_set(app->bg, 64, 64, 64);
+ evas_object_size_hint_weight_set(app->bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(app->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(app->bg);
+ elm_win_resize_object_add(app->win, app->bg);
+
+ if( sandbox_slave_instantiate(sb, (void *)app->win, (void *)&app->widget)
+ || !app->widget)
+ {
+ fprintf(stderr, "sandbox_slave_instantiate failed\n");
+ goto fail;
+ }
+ evas_object_size_hint_weight_set(app->widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(app->widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+ // get widget size hint
+ int W, H;
+ evas_object_size_hint_min_get(app->widget, &W, &H);
+ if(W != 0)
+ w = W;
+ if(H != 0)
+ h = H;
+ evas_object_show(app->widget);
+ elm_win_resize_object_add(app->win, app->widget);
+
+ evas_object_resize(app->win, w, h);
+ evas_object_show(app->win);
+
+ int fd;
+ sandbox_slave_fd_get(sb, &fd);
+ if(fd == -1)
+ {
+ fprintf(stderr, "sandbox_slave_instantiate failed\n");
+ goto fail;
+ }
+
+ app->fd= ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ _recv, sb, NULL, NULL);
+ if(!app->fd)
+ {
+ fprintf(stderr, "ecore_main_fd_handler_add failed\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return -1;
+}
+
+static inline void
+_run(sandbox_slave_t *sb, void *data)
+{
+ app_t *app = data;
+
+ elm_run();
+}
+
+static inline void
+_deinit(void *data)
+{
+ app_t *app = data;
+
+ if(app->fd)
+ ecore_main_fd_handler_del(app->fd);
+
+ if(app->bg)
+ {
+ elm_win_resize_object_del(app->win, app->bg);
+ evas_object_hide(app->bg);
+ evas_object_del(app->bg);
+ }
+
+ if(app->win)
+ {
+ evas_object_hide(app->win);
+ evas_object_del(app->win);
+ }
+}
+
+static const sandbox_slave_driver_t driver = {
+ .init_cb = _init,
+ .run_cb = _run,
+ .deinit_cb = _deinit,
+ .resize_cb = NULL
+};
+
+static int
+elm_main(int argc, char **argv)
+{
+ static app_t app;
+
+#ifdef ELM_1_10
+ elm_config_accel_preference_set("gl");
+#endif
+
+ app.sb = sandbox_slave_new(argc, argv, &driver, &app);
+ if(app.sb)
+ {
+ sandbox_slave_run(app.sb);
+ sandbox_slave_free(app.sb);
+ printf("bye from %s\n", argv[0]);
+ return 0;
+ }
+
+ printf("fail from %s\n", argv[0]);
+ return -1;
+}
+
+ELM_MAIN();
diff --git a/sandbox_ui.lv2/sandbox_io.h b/sandbox_ui.lv2/sandbox_io.h
new file mode 100644
index 0000000..1fca98e
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_io.h
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#ifndef _SANDBOX_IO_H
+#define _SANDBOX_IO_H
+
+#include <sratom/sratom.h>
+
+#include <nanomsg/nn.h>
+#include <nanomsg/pair.h>
+
+#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
+#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
+#include <lv2/lv2plug.in/ns/ext/atom/atom.h>
+#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RDF_PREFIX "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+
+#undef LV2_ATOM_TUPLE_FOREACH // there is a bug in LV2 1.10.0
+#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \
+ for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \
+ !lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \
+ (iter) = lv2_atom_tuple_next(iter))
+
+typedef struct _atom_ser_t atom_ser_t;
+typedef struct _sandbox_io_subscription_t sandbox_io_subscription_t;
+typedef struct _sandbox_io_t sandbox_io_t;
+
+typedef void (*_sandbox_io_recv_cb_t)(void *data, uint32_t index, uint32_t size,
+ uint32_t format, const void *buf);
+typedef void (*_sandbox_io_subscribe_cb_t)(void *data, uint32_t index,
+ uint32_t protocol, bool state);
+
+struct _atom_ser_t {
+ uint32_t size;
+ uint8_t *buf;
+ uint32_t offset;
+};
+
+struct _sandbox_io_subscription_t {
+ uint32_t protocol;
+ int32_t state;
+};
+
+struct _sandbox_io_t {
+ LV2_URID_Map *map;
+ LV2_URID_Unmap *unmap;
+
+ int sock;
+ int id;
+
+ Sratom *sratom;
+ atom_ser_t ser;
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom_Forge forge;
+
+ const char *base_uri;
+ SerdNode subject;
+ SerdNode predicate;
+
+ LV2_URID float_protocol;
+ LV2_URID peak_protocol;
+ LV2_URID event_transfer;
+ LV2_URID atom_transfer;
+ LV2_URID core_index;
+ LV2_URID rdf_value;
+ LV2_URID ui_protocol;
+ LV2_URID ui_period_start;
+ LV2_URID ui_period_size;
+ LV2_URID ui_peak;
+ LV2_URID ui_window_title;
+ LV2_URID ui_port_subscribe;
+};
+
+static inline LV2_Atom_Forge_Ref
+_sink(LV2_Atom_Forge_Sink_Handle handle, const void *buf, uint32_t size)
+{
+ atom_ser_t *ser = handle;
+
+ const LV2_Atom_Forge_Ref ref = ser->offset + 1;
+
+ const uint32_t new_offset = ser->offset + size;
+ if(new_offset > ser->size)
+ {
+ uint32_t new_size = ser->size << 1;
+ while(new_offset > new_size)
+ new_size <<= 1;
+
+ if(!(ser->buf = realloc(ser->buf, new_size)))
+ return 0; // realloc failed
+
+ ser->size = new_size;
+ }
+
+ memcpy(ser->buf + ser->offset, buf, size);
+ ser->offset = new_offset;
+
+ return ref;
+}
+
+static inline LV2_Atom *
+_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref)
+{
+ atom_ser_t *ser = handle;
+
+ const uint32_t offset = ref - 1;
+
+ return (LV2_Atom *)(ser->buf + offset);
+}
+
+static inline void
+_sandbox_io_reset(sandbox_io_t *io)
+{
+ atom_ser_t *ser = &io->ser;
+ ser->offset = 0; //TODO free?
+
+ lv2_atom_forge_set_sink(&io->forge, _sink, _deref, ser);
+ lv2_atom_forge_tuple(&io->forge, &io->frame);
+}
+
+static inline void
+_sandbox_io_recv(sandbox_io_t *io, _sandbox_io_recv_cb_t recv_cb,
+ _sandbox_io_subscribe_cb_t subscribe_cb, void *data)
+{
+ char *ttl = NULL;
+ int res;
+
+ while((res = nn_recv(io->sock, &ttl, NN_MSG, NN_DONTWAIT)) != -1)
+ {
+ //printf("%s\n\n", ttl);
+ LV2_Atom *atom = sratom_from_turtle(io->sratom, io->base_uri,
+ &io->subject, &io->predicate, ttl);
+ if(atom)
+ {
+ LV2_ATOM_TUPLE_FOREACH((LV2_Atom_Tuple *)atom, itm)
+ {
+ LV2_Atom_Object *obj = (LV2_Atom_Object *)itm;
+
+ if(!lv2_atom_forge_is_object_type(&io->forge, obj->atom.type))
+ continue;
+
+ if(obj->body.otype == io->float_protocol)
+ {
+ const LV2_Atom_Int *index = NULL;
+ const LV2_Atom_Float *value = NULL;
+ LV2_Atom_Object_Query q [] = {
+ {io->core_index, (const LV2_Atom **)&index},
+ {io->rdf_value, (const LV2_Atom **)&value},
+ {0, NULL}
+ };
+ lv2_atom_object_query(obj, q);
+
+ if( index && (index->atom.type == io->forge.Int)
+ && value && (value->atom.type == io->forge.Float)
+ && (value->atom.size == sizeof(float)) )
+ {
+ recv_cb(data, index->body,
+ sizeof(float), io->float_protocol, &value->body);
+ recv_cb(data, index->body,
+ sizeof(float), 0, &value->body);
+ }
+ }
+ else if(obj->body.otype == io->peak_protocol)
+ {
+ const LV2_Atom_Int *index = NULL;
+ const LV2_Atom_Int *period_start = NULL;
+ const LV2_Atom_Int *period_size = NULL;
+ const LV2_Atom_Float *peak= NULL;
+ LV2_Atom_Object_Query q [] = {
+ {io->core_index, (const LV2_Atom **)&index},
+ {io->ui_period_start, (const LV2_Atom **)&period_start},
+ {io->ui_period_size, (const LV2_Atom **)&period_size},
+ {io->ui_peak, (const LV2_Atom **)&peak},
+ {0, NULL}
+ };
+ lv2_atom_object_query(obj, q);
+
+ if( index && (index->atom.type == io->forge.Int)
+ && period_start && (period_start->atom.type == io->forge.Int)
+ && (period_start->atom.size == sizeof(int32_t))
+ && period_size && (period_size->atom.type == io->forge.Int)
+ && (period_size->atom.size == sizeof(int32_t))
+ && peak && (peak->atom.type == io->forge.Float)
+ && (peak->atom.size == sizeof(float)) )
+ {
+ const LV2UI_Peak_Data peak_data = {
+ .period_start = period_start->body,
+ .period_size = period_size->body,
+ .peak = peak->body
+ };
+ recv_cb(data, index->body,
+ sizeof(LV2UI_Peak_Data), io->peak_protocol, &peak_data);
+ }
+ }
+ else if(obj->body.otype == io->event_transfer)
+ {
+ const LV2_Atom_Int *index = NULL;
+ const LV2_Atom *value = NULL;
+ LV2_Atom_Object_Query q [] = {
+ {io->core_index, (const LV2_Atom **)&index},
+ {io->rdf_value, (const LV2_Atom **)&value},
+ {0, NULL}
+ };
+ lv2_atom_object_query(obj, q);
+
+ if( index && (index->atom.type == io->forge.Int)
+ && value)
+ {
+ recv_cb(data, index->body,
+ lv2_atom_total_size(value), io->event_transfer, value);
+ }
+ }
+ else if(obj->body.otype == io->atom_transfer)
+ {
+ const LV2_Atom_Int *index = NULL;
+ const LV2_Atom *value = NULL;
+ LV2_Atom_Object_Query q [] = {
+ {io->core_index, (const LV2_Atom **)&index},
+ {io->rdf_value, (const LV2_Atom **)&value},
+ {0, NULL}
+ };
+ lv2_atom_object_query(obj, q);
+
+ if( index && (index->atom.type == io->forge.Int)
+ && value)
+ {
+ recv_cb(data, index->body,
+ lv2_atom_total_size(value), io->atom_transfer, value);
+ }
+ }
+ else if(obj->body.otype == io->ui_port_subscribe)
+ {
+ const LV2_Atom_Int *index = NULL;
+ const LV2_Atom_URID *protocol = NULL;
+ const LV2_Atom_Bool *value = NULL;
+ LV2_Atom_Object_Query q [] = {
+ {io->core_index, (const LV2_Atom **)&index},
+ {io->ui_protocol, (const LV2_Atom **)&protocol},
+ {io->rdf_value, (const LV2_Atom **)&value},
+ {0, NULL}
+ };
+ lv2_atom_object_query(obj, q);
+
+ if( index && (index->atom.type == io->forge.Int)
+ && value && (value->atom.type == io->forge.Bool)
+ && protocol && (protocol->atom.type == io->forge.URID))
+ {
+ if(subscribe_cb)
+ subscribe_cb(data, index->body, protocol->body, value->body);
+ }
+ }
+ }
+
+ free(atom);
+ }
+
+ nn_freemsg(ttl);
+ }
+
+ switch(nn_errno())
+ {
+ case EAGAIN:
+ // do nothing
+ break;
+ case ETERM:
+ //FIXME done
+ // fall-through
+ default:
+ fprintf(stderr, "nn_recv: %s\n", nn_strerror(nn_errno()));
+ break;
+ }
+}
+
+static inline bool
+_sandbox_io_flush(sandbox_io_t *io)
+{
+ const LV2_Atom *atom = (const LV2_Atom *)io->ser.buf;
+
+ bool more = false;
+ if( (io->ser.offset == 0) || (atom->size == 0) )
+ return more; // empty tuple
+
+ char *ttl = sratom_to_turtle(io->sratom, io->unmap,
+ io->base_uri, &io->subject, &io->predicate,
+ atom->type, atom->size, LV2_ATOM_BODY_CONST(atom));
+
+ if(ttl)
+ {
+ const size_t len = strlen(ttl) + 1;
+ //printf("sending: %zu\n\n%s\n\n", len, ttl);
+
+ if(nn_send(io->sock, ttl, len, NN_DONTWAIT) == -1)
+ {
+ switch(nn_errno())
+ {
+ case EAGAIN:
+ more = true;
+ break;
+ case ETERM:
+ //FIXME done
+ // fall-through
+ default:
+ fprintf(stderr, "nn_send: %s\n", nn_strerror(nn_errno()));
+ break;
+ }
+ }
+ else
+ {
+ _sandbox_io_reset(io);
+ }
+
+ free(ttl);
+ }
+
+ return more;
+}
+
+static inline void
+_sandbox_io_clean(LV2_Atom_Forge *forge, LV2_Atom *atom)
+{
+ if(atom->type == forge->Object)
+ {
+ LV2_Atom_Object *obj = (LV2_Atom_Object *)atom;
+
+ if(obj->body.id != 0)
+ obj->body.id = 0; // if not, sratom will fail
+
+ LV2_ATOM_OBJECT_FOREACH(obj, prop)
+ {
+ _sandbox_io_clean(forge, &prop->value);
+ }
+ }
+ else if(atom->type == forge->Tuple)
+ {
+ LV2_Atom_Tuple *tup = (LV2_Atom_Tuple *)atom;
+
+ LV2_ATOM_TUPLE_FOREACH(tup, itm)
+ {
+ _sandbox_io_clean(forge, itm);
+ }
+ }
+ else if(atom->type == forge->Sequence)
+ {
+ LV2_Atom_Sequence *seq = (LV2_Atom_Sequence *)atom;
+
+ LV2_ATOM_SEQUENCE_FOREACH(seq, ev)
+ {
+ _sandbox_io_clean(forge, &ev->body);
+ }
+ }
+}
+
+static inline bool
+_sandbox_io_send(sandbox_io_t *io, uint32_t index,
+ uint32_t size, uint32_t protocol, const void *buf)
+{
+ LV2_Atom_Forge_Frame frame;
+
+ if(protocol == 0)
+ protocol = io->float_protocol;
+
+ lv2_atom_forge_object(&io->forge, &frame, 0, protocol);
+
+ lv2_atom_forge_key(&io->forge, io->core_index);
+ lv2_atom_forge_int(&io->forge, index);
+
+ if(protocol == io->float_protocol)
+ {
+ const float *value = buf;
+
+ lv2_atom_forge_key(&io->forge, io->rdf_value);
+ lv2_atom_forge_float(&io->forge, *value);
+ }
+ else if(protocol == io->peak_protocol)
+ {
+ const LV2UI_Peak_Data *peak_data = buf;
+
+ lv2_atom_forge_key(&io->forge, io->ui_period_start);
+ lv2_atom_forge_int(&io->forge, peak_data->period_start);
+
+ lv2_atom_forge_key(&io->forge, io->ui_period_size);
+ lv2_atom_forge_int(&io->forge, peak_data->period_size);
+
+ lv2_atom_forge_key(&io->forge, io->ui_peak);
+ lv2_atom_forge_float(&io->forge, peak_data->peak);
+ }
+ else if(protocol == io->event_transfer)
+ {
+ const LV2_Atom *atom = buf;
+ LV2_Atom_Forge_Ref ref;
+
+ lv2_atom_forge_key(&io->forge, io->rdf_value);
+ ref = lv2_atom_forge_atom(&io->forge, atom->size, atom->type);
+ lv2_atom_forge_write(&io->forge, LV2_ATOM_BODY_CONST(atom), atom->size);
+
+ LV2_Atom *src= lv2_atom_forge_deref(&io->forge, ref);
+ _sandbox_io_clean(&io->forge, src);
+ }
+ else if(protocol == io->atom_transfer)
+ {
+ const LV2_Atom *atom = buf;
+ LV2_Atom_Forge_Ref ref;
+
+ lv2_atom_forge_key(&io->forge, io->rdf_value);
+ ref = lv2_atom_forge_atom(&io->forge, atom->size, atom->type);
+ lv2_atom_forge_write(&io->forge, LV2_ATOM_BODY_CONST(atom), atom->size);
+
+ LV2_Atom *src= lv2_atom_forge_deref(&io->forge, ref);
+ _sandbox_io_clean(&io->forge, src);
+ }
+ else if(protocol == io->ui_port_subscribe)
+ {
+ const sandbox_io_subscription_t *sub = buf;
+
+ lv2_atom_forge_key(&io->forge, io->rdf_value);
+ lv2_atom_forge_bool(&io->forge, sub->state);
+
+ lv2_atom_forge_key(&io->forge, io->ui_protocol);
+ lv2_atom_forge_urid(&io->forge, protocol);
+ }
+
+ lv2_atom_forge_pop(&io->forge, &frame);
+
+ //lv2_atom_forge_pop(&io->forge, &io->frame);
+
+ return _sandbox_io_flush(io);
+}
+
+static inline int
+_sandbox_io_fd_get(sandbox_io_t *io)
+{
+ int fd = -1;
+ size_t sz = sizeof(int);
+
+ if(io->sock == -1)
+ return -1;
+
+ if(nn_getsockopt(io->sock, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz) < 0)
+ return -1;
+
+ //printf("_sandbox_io_fd_get: %i\n", fd);
+
+ return fd;
+}
+
+static inline int
+_sandbox_io_init(sandbox_io_t *io, LV2_URID_Map *map, LV2_URID_Unmap *unmap,
+ const char *socket_path, bool is_master)
+{
+ io->base_uri = "file:///tmp/base";
+ io->subject = serd_node_from_string(SERD_URI, (const uint8_t *)(""));
+ io->predicate = serd_node_from_string(SERD_URI, (const uint8_t *)(LV2_ATOM__atomTransfer));
+
+ io->map = map;
+ io->unmap = unmap;
+
+ io->ser.offset = 0;
+ io->ser.size = 1024;
+ io->ser.buf = malloc(io->ser.size);
+ if(!io->ser.buf)
+ return -1;
+
+ if(!(io->sratom = sratom_new(map)))
+ return -1;
+ sratom_set_pretty_numbers(io->sratom, false);
+ sratom_set_object_mode(io->sratom, SRATOM_OBJECT_MODE_BLANK);
+
+ if((io->sock = nn_socket(AF_SP, NN_PAIR)) == -1)
+ return -1;
+
+ const int ms = 10000;
+ if(nn_setsockopt(io->sock, NN_SOL_SOCKET, NN_LINGER, &ms, sizeof(ms)) == -1)
+ return -1;
+
+ if(is_master)
+ {
+ if((io->id = nn_bind(io->sock, socket_path)) == -1)
+ return -1;
+ }
+ else // is_slave
+ {
+ if((io->id = nn_connect(io->sock, socket_path)) == -1)
+ return -1;
+ }
+
+ lv2_atom_forge_init(&io->forge, map);
+
+ io->float_protocol = map->map(map->handle, LV2_UI_PREFIX"floatProtocol");
+ io->peak_protocol = map->map(map->handle, LV2_UI_PREFIX"peakProtocol");
+ io->event_transfer = map->map(map->handle, LV2_ATOM__eventTransfer);
+ io->atom_transfer = map->map(map->handle, LV2_ATOM__atomTransfer);
+ io->core_index = map->map(map->handle, LV2_CORE__index);
+ io->rdf_value = map->map(map->handle, RDF_PREFIX"value");
+ io->ui_protocol = map->map(map->handle, LV2_UI_PREFIX"protocol");
+ io->ui_period_start = map->map(map->handle, LV2_UI_PREFIX"periodStart");
+ io->ui_period_size = map->map(map->handle, LV2_UI_PREFIX"periodSize");
+ io->ui_peak = map->map(map->handle, LV2_UI_PREFIX"peak");
+ io->ui_window_title = map->map(map->handle, LV2_UI__windowTitle);
+ io->ui_port_subscribe = map->map(map->handle, LV2_UI__portSubscribe);
+
+ _sandbox_io_reset(io);
+
+ return 0;
+}
+
+static inline void
+_sandbox_io_deinit(sandbox_io_t *io)
+{
+ if(io->id != -1)
+ {
+ int res = nn_shutdown(io->sock, io->id);
+ if(res < 0)
+ fprintf(stderr, "nn_shutdown failed: %s\n", nn_strerror(nn_errno()));
+ }
+
+ if(io->sock != -1)
+ {
+ int res = nn_close(io->sock);
+ if(res < 0)
+ fprintf(stderr, "nn_close failed: %s\n", nn_strerror(nn_errno()));
+ }
+
+ if(io->sratom)
+ sratom_free(io->sratom);
+
+ if(io->ser.buf)
+ free(io->ser.buf);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sandbox_ui.lv2/sandbox_master.c b/sandbox_ui.lv2/sandbox_master.c
new file mode 100644
index 0000000..c61e1d0
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_master.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sandbox_master.h>
+#include <sandbox_io.h>
+
+#include <lv2/lv2plug.in/ns/ext/log/log.h>
+#include <lv2/lv2plug.in/ns/ext/options/options.h>
+#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
+
+struct _sandbox_master_t {
+ sandbox_io_t io;
+
+ sandbox_master_driver_t *driver;
+ void *data;
+};
+
+sandbox_master_t *
+sandbox_master_new(sandbox_master_driver_t *driver, void *data)
+{
+ sandbox_master_t *sb = calloc(1, sizeof(sandbox_master_t));
+ if(!sb)
+ goto fail;
+
+ sb->driver = driver;
+ sb->data = data;
+
+ if(_sandbox_io_init(&sb->io, driver->map, driver->unmap, driver->socket_path, true))
+ goto fail;
+
+ return sb;
+
+fail:
+ sandbox_master_free(sb);
+ return NULL;
+}
+
+void
+sandbox_master_free(sandbox_master_t *sb)
+{
+ if(sb)
+ {
+ _sandbox_io_deinit(&sb->io);
+ free(sb);
+ }
+}
+
+void
+sandbox_master_recv(sandbox_master_t *sb)
+{
+ if(sb)
+ _sandbox_io_recv(&sb->io, sb->driver->recv_cb, sb->driver->subscribe_cb, sb->data);
+}
+
+bool
+sandbox_master_send(sandbox_master_t *sb, uint32_t index, uint32_t size,
+ uint32_t format, const void *buf)
+{
+ if(sb)
+ return _sandbox_io_send(&sb->io, index, size, format, buf);
+
+ return false;
+}
+
+bool
+sandbox_master_flush(sandbox_master_t *sb)
+{
+ if(sb)
+ return _sandbox_io_flush(&sb->io);
+
+ return false;
+}
+
+void
+sandbox_master_fd_get(sandbox_master_t *sb, int *fd)
+{
+ if(sb && fd)
+ *fd = _sandbox_io_fd_get(&sb->io);
+ else if(fd)
+ *fd = -1;
+}
diff --git a/sandbox_ui.lv2/sandbox_master.h b/sandbox_ui.lv2/sandbox_master.h
new file mode 100644
index 0000000..44c6957
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_master.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#ifndef _SANDBOX_MASTER_H
+#define _SANDBOX_MASTER_H
+
+#include <lv2/lv2plug.in/ns/ext/urid/urid.h>
+
+#ifdef _WIN32
+# define SANDBOX_SYMBOL_EXTERN __declspec(dllexport)
+#else
+# define SANDBOX_SYMBOL_EXTERN __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _sandbox_master_t sandbox_master_t;
+typedef struct _sandbox_master_driver_t sandbox_master_driver_t;
+typedef void (*sandbox_master_recv_cb_t)(void *data, uint32_t index, uint32_t size,
+ uint32_t format, const void *buf);
+typedef void (*sandbox_master_subscribe_cb_t)(void *data, uint32_t index,
+ uint32_t protocol, bool state);
+
+struct _sandbox_master_driver_t {
+ const char *socket_path;
+ LV2_URID_Map *map;
+ LV2_URID_Unmap *unmap;
+ sandbox_master_recv_cb_t recv_cb;
+ sandbox_master_subscribe_cb_t subscribe_cb;
+};
+
+SANDBOX_SYMBOL_EXTERN sandbox_master_t *
+sandbox_master_new(sandbox_master_driver_t *driver, void *data);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_master_free(sandbox_master_t *sb);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_master_recv(sandbox_master_t *sb);
+
+SANDBOX_SYMBOL_EXTERN bool
+sandbox_master_send(sandbox_master_t *sb, uint32_t index, uint32_t size,
+ uint32_t format, const void *buf);
+
+SANDBOX_SYMBOL_EXTERN bool
+sandbox_master_flush(sandbox_master_t *sb);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_master_fd_get(sandbox_master_t *sb, int *fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sandbox_ui.lv2/sandbox_slave.c b/sandbox_ui.lv2/sandbox_slave.c
new file mode 100644
index 0000000..9e1e665
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_slave.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sandbox_slave.h>
+#include <sandbox_io.h>
+
+#include <lv2/lv2plug.in/ns/ext/log/log.h>
+#include <lv2/lv2plug.in/ns/ext/options/options.h>
+#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
+
+#include <lilv/lilv.h>
+#include <symap.h>
+
+struct _sandbox_slave_t {
+ Symap *symap;
+ LV2_URID_Map map;
+ LV2_URID_Unmap unmap;
+
+ LV2_Log_Log log;
+
+ LV2UI_Port_Map port_map;
+ LV2UI_Port_Subscribe port_subscribe;
+
+ LV2UI_Resize host_resize;
+ const LV2UI_Resize *client_resize;
+
+ const LV2UI_Idle_Interface *idle_iface;
+
+ LilvWorld *world;
+ LilvNode *bundle_node;
+ LilvNode *plugin_node;
+ LilvNode *ui_node;
+
+ const LilvPlugin *plug;
+ const LilvUI *ui;
+
+ void *lib;
+ const LV2UI_Descriptor *desc;
+ void *handle;
+
+ sandbox_io_t io;
+
+ const sandbox_slave_driver_t *driver;
+ void *data;
+
+ const char *plugin_uri;
+ const char *bundle_path;
+ const char *ui_uri;
+ const char *socket_path;
+ const char *window_title;
+};
+
+static inline LV2_URID
+_map(void *data, const char *uri)
+{
+ sandbox_slave_t *sb= data;
+
+ return symap_map(sb->symap, uri);
+}
+
+static inline const char *
+_unmap(void *data, LV2_URID urid)
+{
+ sandbox_slave_t *sb= data;
+
+ return symap_unmap(sb->symap, urid);
+}
+
+static inline int
+_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list args)
+{
+ sandbox_slave_t *sb = handle;
+
+ vprintf(fmt, args);
+
+ return 0;
+}
+
+static inline int
+_log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ const int ret = _log_vprintf(handle, type, fmt, args);
+ va_end(args);
+
+ return ret;
+}
+
+static inline uint32_t
+_port_index(LV2UI_Feature_Handle handle, const char *symbol)
+{
+ sandbox_slave_t *sb = handle;
+ uint32_t index = LV2UI_INVALID_PORT_INDEX;
+
+ LilvNode *symbol_uri = lilv_new_string(sb->world, symbol);
+ if(symbol_uri)
+ {
+ const LilvPort *port = lilv_plugin_get_port_by_symbol(sb->plug, symbol_uri);
+
+ if(port)
+ index = lilv_port_get_index(sb->plug, port);
+
+ lilv_node_free(symbol_uri);
+ }
+
+ return index;
+}
+
+static inline void
+_write_function(LV2UI_Controller controller, uint32_t index,
+ uint32_t size, uint32_t protocol, const void *buf)
+{
+ sandbox_slave_t *sb = controller;
+
+ const bool more = _sandbox_io_send(&sb->io, index, size, protocol, buf);
+ (void)more; //TODO
+}
+
+static inline uint32_t
+_port_subscribe(LV2UI_Feature_Handle handle, uint32_t index, uint32_t protocol,
+ const LV2_Feature *const *features)
+{
+ sandbox_slave_t *sb = handle;
+
+ const sandbox_io_subscription_t sub = {
+ .state = 1,
+ .protocol = protocol
+ };
+ _write_function(handle, index, sizeof(sandbox_io_subscription_t), sb->io.ui_port_subscribe, &sub);
+
+ return 0;
+}
+
+static inline uint32_t
+_port_unsubscribe(LV2UI_Feature_Handle handle, uint32_t index, uint32_t protocol,
+ const LV2_Feature *const *features)
+{
+ sandbox_slave_t *sb = handle;
+
+ const sandbox_io_subscription_t sub = {
+ .state = 0,
+ .protocol = protocol
+ };
+ _write_function(handle, index, sizeof(sandbox_io_subscription_t), sb->io.ui_port_subscribe, &sub);
+
+ return 0;
+}
+
+static inline void
+_sandbox_recv_cb(LV2UI_Handle handle, uint32_t index, uint32_t size,
+ uint32_t protocol, const void *buf)
+{
+ sandbox_slave_t *sb = handle;
+
+ if(sb->desc && sb->desc->port_event)
+ sb->desc->port_event(sb->handle, index, size, protocol, buf);
+}
+
+static inline int
+_sandbox_resize(sandbox_slave_t *sb, int w, int h)
+{
+ if(sb->client_resize)
+ return sb->client_resize->ui_resize(sb->data, w, h);
+
+ return 0;
+}
+
+sandbox_slave_t *
+sandbox_slave_new(int argc, char **argv, const sandbox_slave_driver_t *driver, void *data)
+{
+ sandbox_slave_t *sb = calloc(1, sizeof(sandbox_slave_t));
+ if(!sb)
+ {
+ fprintf(stderr, "allocation failed\n");
+ goto fail;
+ }
+
+ int c;
+ while((c = getopt(argc, argv, "p:b:u:s:w:")) != -1)
+ {
+ switch(c)
+ {
+ case 'p':
+ sb->plugin_uri = optarg;
+ break;
+ case 'b':
+ sb->bundle_path = optarg;
+ break;
+ case 'u':
+ sb->ui_uri = optarg;
+ break;
+ case 's':
+ sb->socket_path = optarg;
+ break;
+ case 'w':
+ sb->window_title = optarg;
+ break;
+ case '?':
+ if( (optopt == 'p') || (optopt == 'b') || (optopt == 'u') || (optopt == 's') || (optopt == 'w') )
+ fprintf(stderr, "Option `-%c' requires an argument.\n", optopt);
+ else if(isprint(optopt))
+ fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+ goto fail;
+ default:
+ goto fail;
+ }
+ }
+
+ if( !sb->plugin_uri
+ || !sb->bundle_path
+ || !sb->ui_uri
+ || !sb->socket_path
+ || !sb->window_title)
+ {
+ fprintf(stderr, "invalid arguments\n");
+ goto fail;
+ }
+
+ sb->driver = driver;
+ sb->data = data;
+
+ sb->map.handle = sb;
+ sb->map.map = _map;
+
+ sb->unmap.handle = sb;
+ sb->unmap.unmap = _unmap;
+
+ sb->log.handle = sb;
+ sb->log.printf = _log_printf;
+ sb->log.vprintf = _log_vprintf;
+
+ sb->port_map.handle = sb;
+ sb->port_map.port_index = _port_index;
+
+ sb->port_subscribe.handle = sb;
+ sb->port_subscribe.subscribe = _port_subscribe;
+ sb->port_subscribe.unsubscribe = _port_unsubscribe;
+
+ sb->host_resize.handle = data;
+ sb->host_resize.ui_resize = driver->resize_cb;
+
+ if(!(sb->symap = symap_new()))
+ {
+ fprintf(stderr, "symap_new failed\n");
+ goto fail;
+ }
+
+ if(!(sb->world = lilv_world_new()))
+ {
+ fprintf(stderr, "lilv_world_new failed\n");
+ goto fail;
+ }
+
+ sb->bundle_node = lilv_new_file_uri(sb->world, NULL, sb->bundle_path);
+ sb->plugin_node = lilv_new_uri(sb->world, sb->plugin_uri);
+ sb->ui_node = lilv_new_uri(sb->world, sb->ui_uri);
+
+ if(!sb->bundle_node || !sb->plugin_node || !sb->ui_node)
+ {
+ fprintf(stderr, "lilv_new_uri failes\n");
+ goto fail;
+ }
+
+ lilv_world_load_bundle(sb->world, sb->bundle_node);
+ lilv_world_load_resource(sb->world, sb->ui_node);
+
+ const LilvPlugins *plugins = lilv_world_get_all_plugins(sb->world);
+ if(!plugins)
+ {
+ fprintf(stderr, "lilv_world_get_all_plugins failed\n");
+ goto fail;
+ }
+
+ if(!(sb->plug = lilv_plugins_get_by_uri(plugins, sb->plugin_node)))
+ {
+ fprintf(stderr, "lilv_plugins_get_by_uri failed\n");
+ goto fail;
+ }
+
+ LilvUIs *uis = lilv_plugin_get_uis(sb->plug);
+ if(!uis)
+ {
+ fprintf(stderr, "lilv_plugin_get_uis failed\n");
+ goto fail;
+ }
+
+ if(!(sb->ui = lilv_uis_get_by_uri(uis, sb->ui_node)))
+ {
+ fprintf(stderr, "lilv_uis_get_by_uri failed\n");
+ goto fail;
+ }
+
+ const LilvNode *ui_path = lilv_ui_get_binary_uri(sb->ui);
+ if(!ui_path)
+ {
+ fprintf(stderr, "lilv_ui_get_binary_uri failed\n");
+ goto fail;
+ }
+
+#if defined(LILV_0_22)
+ char *binary_path = lilv_file_uri_parse(lilv_node_as_string(ui_path), NULL);
+#else
+ const char *binary_path = lilv_uri_to_path(lilv_node_as_string(ui_path));
+#endif
+ if(!(sb->lib = dlopen(binary_path, RTLD_LAZY)))
+ {
+ fprintf(stderr, "dlopen failed: %s\n", dlerror());
+ goto fail;
+ }
+
+#if defined(LILV_0_22)
+ lilv_free(binary_path);
+#endif
+
+ LV2UI_DescriptorFunction desc_func = dlsym(sb->lib, "lv2ui_descriptor");
+ if(!desc_func)
+ {
+ fprintf(stderr, "dlsym failed\n");
+ goto fail;
+ }
+
+ for(int i=0; true; i++)
+ {
+ const LV2UI_Descriptor *desc = desc_func(i);
+ if(!desc) // sentinel
+ break;
+
+ if(!strcmp(desc->URI, sb->ui_uri))
+ {
+ sb->desc = desc;
+ break;
+ }
+ }
+
+ if(!sb->desc)
+ {
+ fprintf(stderr, "LV2UI_Descriptor lookup failed\n");
+ goto fail;
+ }
+
+ if(sb->desc->extension_data)
+ {
+ sb->idle_iface = sb->desc->extension_data(LV2_UI__idleInterface);
+ sb->client_resize= sb->desc->extension_data(LV2_UI__resize);
+ }
+
+ if(_sandbox_io_init(&sb->io, &sb->map, &sb->unmap, sb->socket_path, false))
+ {
+ fprintf(stderr, "_sandbox_io_init failed\n");
+ goto fail;
+ }
+
+ if(driver->init_cb && (driver->init_cb(sb, data) != 0) )
+ {
+ fprintf(stderr, "driver->init_cb failed\n");
+ goto fail;
+ }
+
+ return sb; // success
+
+fail:
+ sandbox_slave_free(sb);
+ return NULL;
+}
+
+void
+sandbox_slave_free(sandbox_slave_t *sb)
+{
+ if(!sb)
+ return;
+
+ if(sb->desc && sb->desc->cleanup)
+ sb->desc->cleanup(sb->handle);
+
+ if(sb->driver && sb->driver->deinit_cb)
+ sb->driver->deinit_cb(sb->data);
+
+ _sandbox_io_deinit(&sb->io);
+
+ if(sb->lib)
+ dlclose(sb->lib);
+
+ if(sb->world)
+ {
+ if(sb->ui_node)
+ {
+ lilv_world_unload_resource(sb->world, sb->ui_node);
+ lilv_node_free(sb->ui_node);
+ }
+
+ if(sb->bundle_node)
+ {
+ lilv_world_unload_bundle(sb->world, sb->bundle_node);
+ lilv_node_free(sb->bundle_node);
+ }
+
+ if(sb->plugin_node)
+ lilv_node_free(sb->plugin_node);
+
+ lilv_world_free(sb->world);
+ }
+
+ if(sb->symap)
+ symap_free(sb->symap);
+
+ free(sb);
+}
+
+int
+sandbox_slave_instantiate(sandbox_slave_t *sb, void *parent, void *widget)
+{
+ LV2_Options_Option options [] = {
+ [0] = {
+ .context = LV2_OPTIONS_INSTANCE,
+ .subject = 0,
+ .key = sb->io.ui_window_title,
+ .size = strlen(sb->plugin_uri) + 1,
+ .type = sb->io.forge.String,
+ .value = sb->plugin_uri
+ },
+ [1] = {
+ .key = 0,
+ .value = NULL
+ }
+ };
+
+ const LV2_Feature map_feature = {
+ .URI = LV2_URID__map,
+ .data = &sb->map
+ };
+ const LV2_Feature unmap_feature = {
+ .URI = LV2_URID__unmap,
+ .data = &sb->unmap
+ };
+ const LV2_Feature parent_feature = {
+ .URI = LV2_UI__parent,
+ .data = parent
+ };
+ const LV2_Feature log_feature = {
+ .URI = LV2_LOG__log,
+ .data = &sb->log
+ };
+ const LV2_Feature port_map_feature = {
+ .URI = LV2_UI__portMap,
+ .data = &sb->port_map
+ };
+ const LV2_Feature port_subscribe_feature = {
+ .URI = LV2_UI__portSubscribe,
+ .data = &sb->port_subscribe
+ };
+ const LV2_Feature idle_feature = {
+ .URI = LV2_UI__idleInterface,
+ .data = NULL
+ };
+ const LV2_Feature resize_feature = {
+ .URI = LV2_UI__resize,
+ .data = &sb->host_resize
+ };
+ const LV2_Feature options_feature = {
+ .URI = LV2_OPTIONS__options,
+ .data = options
+ };
+
+ const LV2_Feature *const features [] = {
+ &map_feature,
+ &unmap_feature,
+ &parent_feature,
+ &log_feature,
+ &port_map_feature,
+ &port_subscribe_feature,
+ &idle_feature,
+ &options_feature,
+ sb->host_resize.ui_resize ? &resize_feature : NULL,
+ NULL
+ };
+
+ if(sb->desc && sb->desc->instantiate)
+ {
+ sb->handle = sb->desc->instantiate(sb->desc, sb->plugin_uri,
+ sb->bundle_path, _write_function, sb, widget, features);
+ }
+
+ if(sb->handle)
+ return 0; // success
+
+ return -1;
+}
+
+void
+sandbox_slave_recv(sandbox_slave_t *sb)
+{
+ if(sb)
+ _sandbox_io_recv(&sb->io, _sandbox_recv_cb, NULL, sb);
+}
+
+bool
+sandbox_slave_flush(sandbox_slave_t *sb)
+{
+ if(sb)
+ return _sandbox_io_flush(&sb->io);
+
+ return false;
+}
+
+int
+sandbox_slave_idle(sandbox_slave_t *sb)
+{
+ if(sb && sb->idle_iface)
+ return sb->idle_iface->idle(sb->handle);
+
+ return 0;
+}
+
+void
+sandbox_slave_run(sandbox_slave_t *sb)
+{
+ if(sb && sb->driver && sb->driver->run_cb)
+ sb->driver->run_cb(sb, sb->data);
+}
+
+void
+sandbox_slave_fd_get(sandbox_slave_t *sb, int *fd)
+{
+ if(sb && fd)
+ *fd = _sandbox_io_fd_get(&sb->io);
+ else if(fd)
+ *fd = -1;
+}
+
+const char *
+sandbox_slave_title_get(sandbox_slave_t *sb)
+{
+ if(sb)
+ return sb->window_title;
+
+ return NULL;
+}
diff --git a/sandbox_ui.lv2/sandbox_slave.h b/sandbox_ui.lv2/sandbox_slave.h
new file mode 100644
index 0000000..bea0b85
--- /dev/null
+++ b/sandbox_ui.lv2/sandbox_slave.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-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.
+ */
+
+#ifndef _SANDBOX_SLAVE_H
+#define _SANDBOX_SLAVE_H
+
+#ifdef _WIN32
+# define SANDBOX_SYMBOL_EXTERN __declspec(dllexport)
+#else
+# define SANDBOX_SYMBOL_EXTERN __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _sandbox_slave_t sandbox_slave_t;
+typedef struct _sandbox_slave_driver_t sandbox_slave_driver_t;
+
+typedef int (*sandbox_slave_driver_init_t)(sandbox_slave_t *sb, void *data);
+typedef void (*sandbox_slave_driver_run_t)(sandbox_slave_t *sb, void *data);
+typedef void (*sandbox_slave_driver_deinit_t)(void *data);
+typedef int (*sandbox_slave_driver_resize_t)(void *data, int width, int height);
+
+struct _sandbox_slave_driver_t {
+ sandbox_slave_driver_init_t init_cb;
+ sandbox_slave_driver_run_t run_cb;
+ sandbox_slave_driver_deinit_t deinit_cb;
+ sandbox_slave_driver_resize_t resize_cb;
+};
+
+SANDBOX_SYMBOL_EXTERN sandbox_slave_t *
+sandbox_slave_new(int argc, char **argv, const sandbox_slave_driver_t *driver, void *data);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_slave_free(sandbox_slave_t *sb);
+
+SANDBOX_SYMBOL_EXTERN int
+sandbox_slave_instantiate(sandbox_slave_t *sb, void *parent, void *widget);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_slave_recv(sandbox_slave_t *sb);
+
+SANDBOX_SYMBOL_EXTERN bool
+sandbox_slave_flush(sandbox_slave_t *sb);
+
+SANDBOX_SYMBOL_EXTERN int
+sandbox_slave_idle(sandbox_slave_t *sb);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_slave_run(sandbox_slave_t *sb);
+
+SANDBOX_SYMBOL_EXTERN void
+sandbox_slave_fd_get(sandbox_slave_t *sb, int *fd);
+
+SANDBOX_SYMBOL_EXTERN const char *
+sandbox_slave_title_get(sandbox_slave_t *sb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sherlock.h b/sherlock.h
index 5944a08..62a730d 100644
--- a/sherlock.h
+++ b/sherlock.h
@@ -33,40 +33,34 @@
#define SHERLOCK_URI "http://open-music-kontrollers.ch/lv2/sherlock"
#define SHERLOCK_ATOM_INSPECTOR_URI SHERLOCK_URI"#atom_inspector"
-#define SHERLOCK_ATOM_INSPECTOR_EO_URI SHERLOCK_URI"#atom_inspector_eo"
-#define SHERLOCK_ATOM_INSPECTOR_UI_URI SHERLOCK_URI"#atom_inspector_ui"
-#define SHERLOCK_ATOM_INSPECTOR_X11_URI SHERLOCK_URI"#atom_inspector_x11"
-#define SHERLOCK_ATOM_INSPECTOR_KX_URI SHERLOCK_URI"#atom_inspector_kx"
+#define SHERLOCK_ATOM_INSPECTOR_UI_URI SHERLOCK_URI"#atom_inspector_1_ui"
+#define SHERLOCK_ATOM_INSPECTOR_KX_URI SHERLOCK_URI"#atom_inspector_2_kx"
+#define SHERLOCK_ATOM_INSPECTOR_EO_URI SHERLOCK_URI"#atom_inspector_3_eo"
#define SHERLOCK_MIDI_INSPECTOR_URI SHERLOCK_URI"#midi_inspector"
-#define SHERLOCK_MIDI_INSPECTOR_EO_URI SHERLOCK_URI"#midi_inspector_eo"
-#define SHERLOCK_MIDI_INSPECTOR_UI_URI SHERLOCK_URI"#midi_inspector_ui"
-#define SHERLOCK_MIDI_INSPECTOR_X11_URI SHERLOCK_URI"#midi_inspector_x11"
-#define SHERLOCK_MIDI_INSPECTOR_KX_URI SHERLOCK_URI"#midi_inspector_kx"
+#define SHERLOCK_MIDI_INSPECTOR_UI_URI SHERLOCK_URI"#midi_inspector_1_ui"
+#define SHERLOCK_MIDI_INSPECTOR_KX_URI SHERLOCK_URI"#midi_inspector_2_kx"
+#define SHERLOCK_MIDI_INSPECTOR_EO_URI SHERLOCK_URI"#midi_inspector_3_eo"
#define SHERLOCK_OSC_INSPECTOR_URI SHERLOCK_URI"#osc_inspector"
-#define SHERLOCK_OSC_INSPECTOR_EO_URI SHERLOCK_URI"#osc_inspector_eo"
-#define SHERLOCK_OSC_INSPECTOR_UI_URI SHERLOCK_URI"#osc_inspector_ui"
-#define SHERLOCK_OSC_INSPECTOR_X11_URI SHERLOCK_URI"#osc_inspector_x11"
-#define SHERLOCK_OSC_INSPECTOR_KX_URI SHERLOCK_URI"#osc_inspector_kx"
+#define SHERLOCK_OSC_INSPECTOR_UI_URI SHERLOCK_URI"#osc_inspector_1_ui"
+#define SHERLOCK_OSC_INSPECTOR_KX_URI SHERLOCK_URI"#osc_inspector_2_kx"
+#define SHERLOCK_OSC_INSPECTOR_EO_URI SHERLOCK_URI"#osc_inspector_3_eo"
extern const LV2_Descriptor atom_inspector;
-extern const LV2UI_Descriptor atom_inspector_eo;
extern const LV2UI_Descriptor atom_inspector_ui;
-extern const LV2UI_Descriptor atom_inspector_x11;
extern const LV2UI_Descriptor atom_inspector_kx;
+extern const LV2UI_Descriptor atom_inspector_eo;
extern const LV2_Descriptor midi_inspector;
-extern const LV2UI_Descriptor midi_inspector_eo;
extern const LV2UI_Descriptor midi_inspector_ui;
-extern const LV2UI_Descriptor midi_inspector_x11;
extern const LV2UI_Descriptor midi_inspector_kx;
+extern const LV2UI_Descriptor midi_inspector_eo;
extern const LV2_Descriptor osc_inspector;
-extern const LV2UI_Descriptor osc_inspector_eo;
extern const LV2UI_Descriptor osc_inspector_ui;
-extern const LV2UI_Descriptor osc_inspector_x11;
extern const LV2UI_Descriptor osc_inspector_kx;
+extern const LV2UI_Descriptor osc_inspector_eo;
typedef struct _position_t position_t;
diff --git a/sherlock.ttl b/sherlock.ttl
index 5fe1b77..c582689 100644
--- a/sherlock.ttl
+++ b/sherlock.ttl
@@ -13,19 +13,15 @@
# 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 rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
-@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix time: <http://lv2plug.in/ns/ext/time#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
-@prefix kx: <http://kxstudio.sf.net/ns/lv2ext/external-ui#> .
@prefix osc: <http://open-music-kontrollers.ch/lv2/osc#> .
@prefix lic: <http://opensource.org/licenses/> .
@@ -51,65 +47,6 @@ proj:sherlock
doap:maintainer omk:me ;
doap:name "Sherlock Bundle" .
-# Atom Inspector UI
-sherlock:atom_inspector_eo
- a ui:EoUI ;
- ui:portNotification [
- ui:plugin sherlock:atom_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Object ;
- ui:notifyType osc:Event ;
- ui:notifyType midi:MidiEvent ;
- ui:notifyType time:Position ;
- ui:notifyType patch:Message ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:extensionData ui:resize ;
- lv2:optionalFeature ui:resize ;
- lv2:requiredFeature urid:map, urid:unmap .
-sherlock:atom_inspector_ui
- a ui:UI ;
- ui:portNotification [
- ui:plugin sherlock:atom_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Object ;
- ui:notifyType osc:Event ;
- ui:notifyType midi:MidiEvent ;
- ui:notifyType time:Position ;
- ui:notifyType patch:Message ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap ;
- lv2:extensionData ui:idleInterface, ui:showInterface .
-sherlock:atom_inspector_x11
- a ui:X11UI ;
- ui:portNotification [
- ui:plugin sherlock:atom_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Object ;
- ui:notifyType osc:Event ;
- ui:notifyType midi:MidiEvent ;
- ui:notifyType time:Position ;
- ui:notifyType patch:Message ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap ;
- lv2:optionalFeature ui:resize ;
- lv2:extensionData ui:idleInterface, ui:resize .
-sherlock:atom_inspector_kx
- a kx:Widget ;
- ui:portNotification [
- ui:plugin sherlock:atom_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Object ;
- ui:notifyType osc:Event ;
- ui:notifyType midi:MidiEvent ;
- ui:notifyType time:Position ;
- ui:notifyType patch:Message ;
- ui:protocol atom:eventTransfer ;
- ] ;
- lv2:requiredFeature kx:Host, urid:map, urid:unmap .
-
# Atom Inspector Plugin
sherlock:atom_inspector
a lv2:Plugin,
@@ -191,49 +128,6 @@ sherlock:atom_inspector
lv2:name "Notify" ;
] .
-# MIDI Inspector UI
-sherlock:midi_inspector_eo
- a ui:EoUI ;
- ui:portNotification [
- ui:plugin sherlock:midi_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType midi:MidiEvent ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:extensionData ui:resize ;
- lv2:optionalFeature ui:resize ;
- lv2:requiredFeature urid:map .
-sherlock:midi_inspector_ui
- a ui:UI ;
- ui:portNotification [
- ui:plugin sherlock:midi_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType midi:MidiEvent ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map ;
- lv2:extensionData ui:idleInterface, ui:showInterface .
-sherlock:midi_inspector_x11
- a ui:X11UI ;
- ui:portNotification [
- ui:plugin sherlock:midi_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType midi:MidiEvent ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map ;
- lv2:optionalFeature ui:resize ;
- lv2:extensionData ui:idleInterface, ui:resize .
-sherlock:midi_inspector_kx
- a kx:Widget ;
- ui:portNotification [
- ui:plugin sherlock:midi_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType midi:MidiEvent ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature kx:Host, urid:map .
-
# MIDI Inspector Plugin
sherlock:midi_inspector
a lv2:Plugin,
@@ -275,49 +169,6 @@ sherlock:midi_inspector
lv2:name "Notify" ;
] .
-# OSC Inspector UI
-sherlock:osc_inspector_eo
- a ui:EoUI ;
- ui:portNotification [
- ui:plugin sherlock:osc_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType osc:Event ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:extensionData ui:resize ;
- lv2:optionalFeature ui:resize ;
- lv2:requiredFeature urid:map .
-sherlock:osc_inspector_ui
- a ui:UI ;
- ui:portNotification [
- ui:plugin sherlock:osc_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType osc:Event ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map ;
- lv2:extensionData ui:idleInterface, ui:showInterface .
-sherlock:osc_inspector_x11
- a ui:X11UI ;
- ui:portNotification [
- ui:plugin sherlock:osc_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType osc:Event ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature ui:idleInterface, urid:map ;
- lv2:optionalFeature ui:resize ;
- lv2:extensionData ui:idleInterface, ui:resize .
-sherlock:osc_inspector_kx
- a kx:Widget ;
- ui:portNotification [
- ui:plugin sherlock:osc_inspector ;
- lv2:symbol "notify" ;
- ui:notifyType osc:Event ;
- ui:protocol atom:eventTransfer
- ] ;
- lv2:requiredFeature kx:Host, urid:map .
-
# OSC Inspector Plugin
sherlock:osc_inspector
a lv2:Plugin,
diff --git a/sherlock_eo.c b/sherlock_eo.c
new file mode 100644
index 0000000..260f859
--- /dev/null
+++ b/sherlock_eo.c
@@ -0,0 +1,35 @@
+/*
+ * 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 <sherlock.h>
+
+LV2_SYMBOL_EXPORT const LV2UI_Descriptor*
+lv2ui_descriptor(uint32_t index)
+{
+ switch(index)
+ {
+ case 0:
+ return &atom_inspector_eo;
+ case 1:
+ return &midi_inspector_eo;
+ case 2:
+ return &osc_inspector_eo;
+
+ default:
+ return NULL;
+ }
+}
diff --git a/sherlock_ui.c b/sherlock_ui.c
index f23d279..7e1c9e0 100644
--- a/sherlock_ui.c
+++ b/sherlock_ui.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ * Copyright (c) 2015-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
@@ -15,38 +15,436 @@
* http://www.perlfoundation.org/artistic_license_2_0.
*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <lv2/lv2plug.in/ns/ext/options/options.h>
+
#include <sherlock.h>
+#include <sandbox_master.h>
+#include <lv2_external_ui.h> // kxstudio external-ui extension
+
+#define SOCKET_PATH_LEN 32
+
+typedef struct _plughandle_t plughandle_t;
+
+struct _plughandle_t {
+ int done;
+
+ LV2UI_Write_Function write_function;
+ LV2UI_Controller controller;
+ LV2UI_Port_Subscribe *subscribe;
+
+ sandbox_master_driver_t driver;
+ sandbox_master_t *sb;
+
+ char *plugin_uri;
+ char *bundle_path;
+ char *executable;
+ char *ui_uri;
+ char *window_title;
+ char socket_path [SOCKET_PATH_LEN];
+
+ LV2_URID ui_window_title;
+ LV2_URID atom_string;
+
+ pid_t pid;
+
+ struct {
+ LV2_External_UI_Widget widget;
+ const LV2_External_UI_Host *host;
+ } kx;
+};
+
+static void
+_recv(LV2UI_Controller controller, uint32_t port,
+ uint32_t size, uint32_t protocol, const void *buf)
+{
+ plughandle_t *handle = controller;
+
+ handle->write_function(handle->controller, port, size, protocol, buf);
+}
+
+static void
+_subscribe(LV2UI_Controller controller, uint32_t port,
+ uint32_t protocol, bool state)
+{
+ plughandle_t *handle = controller;
+
+ if(handle->subscribe)
+ {
+ if(state)
+ handle->subscribe->subscribe(handle->subscribe->handle,
+ port, protocol, NULL);
+ else
+ handle->subscribe->unsubscribe(handle->subscribe->handle,
+ port, protocol, NULL);
+ }
+}
+
+// Show Interface
+static inline int
+_show_cb(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ if(!handle->done)
+ return 0; // already showing
+
+ strncpy(handle->socket_path, "ipc:///tmp/sandbox_ui_XXXXXX", SOCKET_PATH_LEN);
+ int fd = mkstemp(&handle->socket_path[6]);
+ if(!fd)
+ return -1;
+ close(fd);
+
+ handle->sb = sandbox_master_new(&handle->driver, handle);
+ if(!handle->sb)
+ return -1;
+
+ handle->pid = fork();
+ if(handle->pid == 0) // child
+ {
+ char *const argv [] = {
+ handle->executable,
+ "-p", handle->plugin_uri,
+ "-b", handle->bundle_path,
+ "-u", handle->ui_uri,
+ "-s", handle->socket_path,
+ "-w", handle->window_title,
+ NULL
+ };
+ execv(handle->executable, argv); // p = search PATH for executable
+
+ printf("fork child failed\n");
+ exit(-1);
+ }
+ else if(handle->pid < 0)
+ {
+ printf("fork failed\n");
+ return -1;
+ }
+
+ handle->done = 0;
+
+ return 0;
+}
+
+static inline int
+_hide_cb(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ if(handle->pid > 0) // has child
+ {
+ kill(handle->pid, SIGINT);
+
+ int status;
+ waitpid(handle->pid, &status, 0);
+
+ handle->pid = -1; // invalidate
+ }
+
+ if(handle->sb)
+ {
+ sandbox_master_free(handle->sb);
+ handle->sb = NULL;
+ }
+
+ /* FIXME
+ remove(&handle->socket_path[6]);
+ */
+
+ if(handle->kx.host && handle->kx.host->ui_closed)
+ handle->kx.host->ui_closed(handle->controller);
+
+ handle->done = 1;
+
+ return 0;
+}
+
+static const LV2UI_Show_Interface show_ext = {
+ .show = _show_cb,
+ .hide = _hide_cb
+};
+
+// Idle interface
+static inline int
+_idle_cb(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ if(handle->pid > 0)
+ {
+ int status;
+ int res;
+ if((res = waitpid(handle->pid, &status, WNOHANG)) < 0)
+ {
+ if(errno == ECHILD)
+ {
+ handle->pid = -1; // invalidate
+ //_hide_cb(ui);
+ handle->done = 1;
+ }
+ }
+ else if( (res > 0) && WIFEXITED(status) )
+ {
+ handle->pid = -1; // invalidate
+ //_hide_cb(ui);
+ handle->done = 1;
+ }
+ }
+
+ if(!handle->done && handle->sb)
+ {
+ sandbox_master_recv(handle->sb);
+ sandbox_master_flush(handle->sb);
+ }
+
+ return handle->done;
+}
+
+static const LV2UI_Idle_Interface idle_ext = {
+ .idle = _idle_cb
+};
+
+// External-UI Interface
+static inline void
+_kx_run(LV2_External_UI_Widget *widget)
+{
+ plughandle_t *handle = (void *)widget - offsetof(plughandle_t, kx.widget);
-LV2_SYMBOL_EXPORT const LV2UI_Descriptor*
+ if(_idle_cb(handle))
+ _hide_cb(handle);
+}
+
+static inline void
+_kx_hide(LV2_External_UI_Widget *widget)
+{
+ plughandle_t *handle = (void *)widget - offsetof(plughandle_t, kx.widget);
+
+ _hide_cb(handle);
+}
+
+static inline void
+_kx_show(LV2_External_UI_Widget *widget)
+{
+ plughandle_t *handle = (void *)widget - offsetof(plughandle_t, kx.widget);
+
+ _show_cb(handle);
+}
+
+static inline void
+_free_strdups(plughandle_t *handle)
+{
+ if(handle->plugin_uri)
+ free(handle->plugin_uri);
+ if(handle->bundle_path)
+ free(handle->bundle_path);
+ if(handle->executable)
+ free(handle->executable);
+ if(handle->ui_uri)
+ free(handle->ui_uri);
+ if(handle->window_title)
+ free(handle->window_title);
+};
+
+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)
+{
+ plughandle_t *handle = calloc(1, sizeof(plughandle_t));
+ if(!handle)
+ return NULL;
+
+ handle->write_function = write_function;
+ handle->controller = controller;
+
+ LV2_Options_Option *opts = NULL; // optional
+ for(unsigned i=0; features[i]; i++)
+ {
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->driver.map = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_URID__unmap))
+ handle->driver.unmap = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__portSubscribe))
+ handle->subscribe = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host))
+ handle->kx.host = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_OPTIONS__options))
+ opts = features[i]->data;
+ }
+
+ if(!handle->driver.map || !handle->driver.unmap)
+ {
+ free(handle);
+ return NULL;
+ }
+
+ handle->ui_window_title = handle->driver.map->map(handle->driver.map->handle,
+ LV2_UI__windowTitle);
+ handle->atom_string = handle->driver.map->map(handle->driver.map->handle,
+ LV2_ATOM__String);
+
+ handle->plugin_uri = strdup(plugin_uri);
+ handle->bundle_path = strdup(bundle_path);
+ if(asprintf(&handle->executable, "%ssandbox_efl", bundle_path) == -1)
+ handle->executable = NULL; // failed
+ handle->ui_uri = strdup(descriptor->URI);
+ sprintf(&handle->ui_uri[strlen(handle->ui_uri) - 4], "%s", "3_eo"); //TODO more elegant way?
+
+ if(opts)
+ {
+ for(LV2_Options_Option *opt = opts;
+ (opt->key != 0) && (opt->value != NULL);
+ opt++)
+ {
+ if( (opt->key == handle->ui_window_title) && (opt->type == handle->atom_string) )
+ {
+ handle->window_title = strdup(opt->value);
+ break;
+ }
+ }
+ }
+ if(!handle->window_title && handle->kx.host && handle->kx.host->plugin_human_id)
+ handle->window_title = strdup(handle->kx.host->plugin_human_id);
+ if(!handle->window_title)
+ handle->window_title = strdup(descriptor->URI);
+
+ if(!handle->plugin_uri || !handle->bundle_path || !handle->executable || !handle->ui_uri || !handle->window_title)
+ {
+ _free_strdups(handle);
+ free(handle);
+ return NULL;
+ }
+
+ handle->driver.socket_path = handle->socket_path;
+ handle->driver.recv_cb = _recv;
+ handle->driver.subscribe_cb = _subscribe;
+
+ handle->pid = -1; // invalidate
+
+ handle->kx.widget.run = _kx_run;
+ handle->kx.widget.show = _kx_show;
+ handle->kx.widget.hide = _kx_hide;
+
+ if(strstr(descriptor->URI, "_kx"))
+ *(LV2_External_UI_Widget **)widget = &handle->kx.widget;
+ else
+ *widget = NULL;
+
+ handle->done = 1;
+
+ return handle;
+}
+
+static void
+cleanup(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ _free_strdups(handle);
+ free(handle);
+}
+
+static void
+port_event(LV2UI_Handle instance, uint32_t index, uint32_t size,
+ uint32_t protocol, const void *buf)
+{
+ plughandle_t *handle = instance;
+
+ if(handle->sb)
+ sandbox_master_send(handle->sb, index, size, protocol, buf);
+}
+
+// extension data callback for show interface UI
+static inline const void *
+extension_data(const char *uri)
+{
+ if(!strcmp(uri, LV2_UI__idleInterface))
+ return &idle_ext;
+ else if(!strcmp(uri, LV2_UI__showInterface))
+ return &show_ext;
+
+ return NULL;
+}
+
+const LV2UI_Descriptor atom_inspector_ui= {
+ .URI = SHERLOCK_ATOM_INSPECTOR_UI_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = extension_data
+};
+
+const LV2UI_Descriptor atom_inspector_kx= {
+ .URI = SHERLOCK_ATOM_INSPECTOR_KX_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = NULL
+};
+
+const LV2UI_Descriptor midi_inspector_ui= {
+ .URI = SHERLOCK_MIDI_INSPECTOR_UI_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = extension_data
+};
+
+const LV2UI_Descriptor midi_inspector_kx= {
+ .URI = SHERLOCK_MIDI_INSPECTOR_KX_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = NULL
+};
+
+const LV2UI_Descriptor osc_inspector_ui= {
+ .URI = SHERLOCK_OSC_INSPECTOR_UI_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = extension_data
+};
+
+const LV2UI_Descriptor osc_inspector_kx= {
+ .URI = SHERLOCK_OSC_INSPECTOR_KX_URI,
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = NULL
+};
+
+#ifdef _WIN32
+__declspec(dllexport)
+#else
+__attribute__((visibility("default")))
+#endif
+const LV2UI_Descriptor*
lv2ui_descriptor(uint32_t index)
{
switch(index)
{
case 0:
- return &atom_inspector_eo;
- case 1:
return &atom_inspector_ui;
- case 2:
- return &atom_inspector_x11;
- case 3:
+ case 1:
return &atom_inspector_kx;
- case 4:
- return &midi_inspector_eo;
- case 5:
+ case 2:
return &midi_inspector_ui;
- case 6:
- return &midi_inspector_x11;
- case 7:
+ case 3:
return &midi_inspector_kx;
- case 8:
- return &osc_inspector_eo;
- case 9:
+ case 4:
return &osc_inspector_ui;
- case 10:
- return &osc_inspector_x11;
- case 11:
+ case 5:
return &osc_inspector_kx;
default:
diff --git a/sherlock_ui.ttl b/sherlock_ui.ttl
new file mode 100644
index 0000000..2885ab6
--- /dev/null
+++ b/sherlock_ui.ttl
@@ -0,0 +1,135 @@
+# 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.
+
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
+@prefix time: <http://lv2plug.in/ns/ext/time#> .
+@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
+@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
+@prefix kx: <http://kxstudio.sf.net/ns/lv2ext/external-ui#> .
+
+@prefix osc: <http://open-music-kontrollers.ch/lv2/osc#> .
+@prefix sherlock: <http://open-music-kontrollers.ch/lv2/sherlock#> .
+
+# Atom Inspector UI
+sherlock:atom_inspector_1_ui
+ a ui:UI ;
+ ui:portNotification [
+ ui:plugin sherlock:atom_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType atom:Object ;
+ ui:notifyType osc:Event ;
+ ui:notifyType midi:MidiEvent ;
+ ui:notifyType time:Position ;
+ ui:notifyType patch:Message ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature ui:idleInterface, urid:map, urid:unmap ;
+ lv2:extensionData ui:idleInterface, ui:showInterface .
+
+sherlock:atom_inspector_2_kx
+ a kx:Widget ;
+ ui:portNotification [
+ ui:plugin sherlock:atom_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType atom:Object ;
+ ui:notifyType osc:Event ;
+ ui:notifyType midi:MidiEvent ;
+ ui:notifyType time:Position ;
+ ui:notifyType patch:Message ;
+ ui:protocol atom:eventTransfer ;
+ ] ;
+ lv2:requiredFeature kx:Host, urid:map, urid:unmap .
+
+sherlock:atom_inspector_3_eo
+ a ui:EoUI ;
+ ui:portNotification [
+ ui:plugin sherlock:atom_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType atom:Object ;
+ ui:notifyType osc:Event ;
+ ui:notifyType midi:MidiEvent ;
+ ui:notifyType time:Position ;
+ ui:notifyType patch:Message ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature urid:map, urid:unmap .
+
+# MIDI Inspector UI
+sherlock:midi_inspector_1_ui
+ a ui:UI ;
+ ui:portNotification [
+ ui:plugin sherlock:midi_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType midi:MidiEvent ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature ui:idleInterface, urid:map ;
+ lv2:extensionData ui:idleInterface, ui:showInterface .
+
+sherlock:midi_inspector_2_kx
+ a kx:Widget ;
+ ui:portNotification [
+ ui:plugin sherlock:midi_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType midi:MidiEvent ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature kx:Host, urid:map .
+
+sherlock:midi_inspector_3_eo
+ a ui:EoUI ;
+ ui:portNotification [
+ ui:plugin sherlock:midi_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType midi:MidiEvent ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature urid:map .
+
+# OSC Inspector UI
+sherlock:osc_inspector_1_ui
+ a ui:UI ;
+ ui:portNotification [
+ ui:plugin sherlock:osc_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType osc:Event ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature ui:idleInterface, urid:map ;
+ lv2:extensionData ui:idleInterface, ui:showInterface .
+
+sherlock:osc_inspector_2_kx
+ a kx:Widget ;
+ ui:portNotification [
+ ui:plugin sherlock:osc_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType osc:Event ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature kx:Host, urid:map .
+
+sherlock:osc_inspector_3_eo
+ a ui:EoUI ;
+ ui:portNotification [
+ ui:plugin sherlock:osc_inspector ;
+ lv2:symbol "notify" ;
+ ui:notifyType osc:Event ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature urid:map .
diff --git a/symap/symap.c b/symap/symap.c
new file mode 100644
index 0000000..40c8980
--- /dev/null
+++ b/symap/symap.c
@@ -0,0 +1,231 @@
+/*
+ Copyright 2011-2014 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "symap.h"
+
+/**
+ @file symap.c Implementation of Symap, a basic symbol map (string interner).
+
+ This implementation is primitive, but has some desirable qualities: good
+ (O(lg(n)) lookup performance for already-mapped symbols, minimal space
+ overhead, extremely fast (O(1)) reverse mapping (ID to string), simple code,
+ no dependencies.
+
+ The tradeoff is that mapping new symbols may be quite slow. In other words,
+ this implementation is ideal for use cases with a relatively limited set of
+ symbols, or where most symbols are mapped early. It will not fare so well
+ with very dynamic sets of symbols. For that, you're better off with a
+ tree-based implementation (and the associated space cost, especially if you
+ need reverse mapping).
+*/
+
+struct SymapImpl {
+ /**
+ Unsorted array of strings, such that the symbol for ID i is found
+ at symbols[i - 1].
+ */
+ char** symbols;
+
+ /**
+ Array of IDs, sorted by corresponding string in `symbols`.
+ */
+ uint32_t* index;
+
+ /**
+ Number of symbols (number of items in `symbols` and `index`).
+ */
+ uint32_t size;
+};
+
+Symap*
+symap_new(void)
+{
+ Symap* map = (Symap*)malloc(sizeof(Symap));
+ map->symbols = NULL;
+ map->index = NULL;
+ map->size = 0;
+ return map;
+}
+
+void
+symap_free(Symap* map)
+{
+ for (uint32_t i = 0; i < map->size; ++i) {
+ free(map->symbols[i]);
+ }
+
+ free(map->symbols);
+ free(map->index);
+ free(map);
+}
+
+static char*
+symap_strdup(const char* str)
+{
+ const size_t len = strlen(str);
+ char* copy = (char*)malloc(len + 1);
+ memcpy(copy, str, len + 1);
+ return copy;
+}
+
+/**
+ Return the index into map->index (not the ID) corresponding to `sym`,
+ or the index where a new entry for `sym` should be inserted.
+*/
+static uint32_t
+symap_search(const Symap* map, const char* sym, bool* exact)
+{
+ *exact = false;
+ if (map->size == 0) {
+ return 0; // Empty map, insert at 0
+ } else if (strcmp(map->symbols[map->index[map->size - 1] - 1], sym) < 0) {
+ return map->size; // Greater than last element, append
+ }
+
+ uint32_t lower = 0;
+ uint32_t upper = map->size - 1;
+ uint32_t i = upper;
+ int cmp;
+
+ while (upper >= lower) {
+ i = lower + ((upper - lower) / 2);
+ cmp = strcmp(map->symbols[map->index[i] - 1], sym);
+
+ if (cmp == 0) {
+ *exact = true;
+ return i;
+ } else if (cmp > 0) {
+ if (i == 0) {
+ break; // Avoid underflow
+ }
+ upper = i - 1;
+ } else {
+ lower = ++i;
+ }
+ }
+
+ assert(!*exact || strcmp(map->symbols[map->index[i] - 1], sym) > 0);
+ return i;
+}
+
+uint32_t
+symap_try_map(Symap* map, const char* sym)
+{
+ bool exact;
+ const uint32_t index = symap_search(map, sym, &exact);
+ if (exact) {
+ assert(!strcmp(map->symbols[map->index[index]], sym));
+ return map->index[index];
+ }
+
+ return 0;
+}
+
+uint32_t
+symap_map(Symap* map, const char* sym)
+{
+ bool exact;
+ const uint32_t index = symap_search(map, sym, &exact);
+ if (exact) {
+ assert(!strcmp(map->symbols[map->index[index] - 1], sym));
+ return map->index[index];
+ }
+
+ const uint32_t id = ++map->size;
+ char* const str = symap_strdup(sym);
+
+ /* Append new symbol to symbols array */
+ map->symbols = (char**)realloc(map->symbols, map->size * sizeof(str));
+ map->symbols[id - 1] = str;
+
+ /* Insert new index element into sorted index */
+ map->index = (uint32_t*)realloc(map->index, map->size * sizeof(uint32_t));
+ if (index < map->size - 1) {
+ memmove(map->index + index + 1,
+ map->index + index,
+ (map->size - index - 1) * sizeof(uint32_t));
+ }
+
+ map->index[index] = id;
+
+ return id;
+}
+
+const char*
+symap_unmap(Symap* map, uint32_t id)
+{
+ if (id == 0) {
+ return NULL;
+ } else if (id <= map->size) {
+ return map->symbols[id - 1];
+ }
+ return NULL;
+}
+
+#ifdef STANDALONE
+
+#include <stdio.h>
+
+static void
+symap_dump(Symap* map)
+{
+ fprintf(stderr, "{\n");
+ for (uint32_t i = 0; i < map->size; ++i) {
+ fprintf(stderr, "\t%u = %s\n",
+ map->index[i], map->symbols[map->index[i] - 1]);
+ }
+ fprintf(stderr, "}\n");
+}
+
+int
+main()
+{
+ #define N_SYMS 5
+ char* syms[N_SYMS] = {
+ "hello", "bonjour", "goodbye", "aloha", "salut"
+ };
+
+ Symap* map = symap_new();
+ for (int i = 0; i < N_SYMS; ++i) {
+ if (symap_try_map(map, syms[i])) {
+ fprintf(stderr, "error: Symbol already mapped\n");
+ return 1;
+ }
+
+ const uint32_t id = symap_map(map, syms[i]);
+ if (strcmp(map->symbols[id - 1], syms[i])) {
+ fprintf(stderr, "error: Corrupt symbol table\n");
+ return 1;
+ }
+
+ if (symap_map(map, syms[i]) != id) {
+ fprintf(stderr, "error: Remapped symbol to a different ID\n");
+ return 1;
+ }
+
+ symap_dump(map);
+ }
+
+ symap_free(map);
+ return 0;
+}
+
+#endif /* STANDALONE */
diff --git a/symap/symap.h b/symap/symap.h
new file mode 100644
index 0000000..79de8ff
--- /dev/null
+++ b/symap/symap.h
@@ -0,0 +1,69 @@
+/*
+ Copyright 2011-2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file symap.h API for Symap, a basic symbol map (string interner).
+
+ Particularly useful for implementing LV2 URI mapping.
+
+ @see <a href="http://lv2plug.in/ns/ext/urid">LV2 URID</a>
+ @see <a href="http://lv2plug.in/ns/ext/uri-map">LV2 URI Map</a>
+*/
+
+#ifndef SYMAP_H
+#define SYMAP_H
+
+#include <stdint.h>
+
+struct SymapImpl;
+
+typedef struct SymapImpl Symap;
+
+/**
+ Create a new symbol map.
+*/
+Symap*
+symap_new(void);
+
+/**
+ Free a symbol map.
+*/
+void
+symap_free(Symap* map);
+
+/**
+ Map a string to a symbol ID if it is already mapped, otherwise return 0.
+*/
+uint32_t
+symap_try_map(Symap* map, const char* sym);
+
+/**
+ Map a string to a symbol ID.
+
+ Note that 0 is never a valid symbol ID.
+*/
+uint32_t
+symap_map(Symap* map, const char* sym);
+
+/**
+ Unmap a symbol ID back to a symbol, or NULL if no such ID exists.
+
+ Note that 0 is never a valid symbol ID.
+*/
+const char*
+symap_unmap(Symap* map, uint32_t id);
+
+#endif /* SYMAP_H */