From eba25be23caf7877ad01fe5506cb575b47f4e12c Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 7 Jan 2014 17:04:44 +0000 Subject: [PATCH] Add jalv ext-ui patch file --- ns/lv2ext/jalv_extui_svn5273b.diff | 388 +++++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 ns/lv2ext/jalv_extui_svn5273b.diff diff --git a/ns/lv2ext/jalv_extui_svn5273b.diff b/ns/lv2ext/jalv_extui_svn5273b.diff new file mode 100644 index 0000000..c61e5a9 --- /dev/null +++ b/ns/lv2ext/jalv_extui_svn5273b.diff @@ -0,0 +1,388 @@ +commit 109070a71a1e780385b803731fbdd2689752c644 +Author: Robin Gareus +Date: Tue Jan 7 17:48:52 2014 +0100 + + add support for externalUI + +diff --git a/jalv/src/jalv.c b/jalv/src/jalv.c +index e80f9f9..e0aa1a0 100644 +--- a/jalv/src/jalv.c ++++ b/jalv/src/jalv.c +@@ -649,32 +649,73 @@ void + jalv_ui_instantiate(Jalv* jalv, const char* native_ui_type, void* parent) + { + jalv->ui_host = suil_host_new(jalv_ui_write, jalv_ui_port_index, NULL, NULL); ++ jalv->extuiptr = NULL; ++ ++ if (jalv->externalui) { ++ ++ const LV2_Feature external_lv_feature = { ++ LV2_EXTERNAL_UI_DEPRECATED_URI, parent ++ }; ++ const LV2_Feature external_kx_feature = { ++ LV2_EXTERNAL_UI__Host, parent ++ }; ++ const LV2_Feature instance_feature = { ++ NS_EXT "instance-access", lilv_instance_get_handle(jalv->instance) ++ }; ++ const LV2_Feature* ui_features[] = { ++ &uri_map_feature, &map_feature, &unmap_feature, ++ &instance_feature, ++ &log_feature, ++ &external_lv_feature, ++ &external_kx_feature, ++ &options_feature, ++ NULL ++ }; ++ ++ jalv->ui_instance = suil_instance_new( ++ jalv->ui_host, ++ jalv, ++ native_ui_type, ++ lilv_node_as_uri(lilv_plugin_get_uri(jalv->plugin)), ++ lilv_node_as_uri(lilv_ui_get_uri(jalv->ui)), ++ lilv_node_as_uri(jalv->ui_type), ++ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(jalv->ui))), ++ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(jalv->ui))), ++ ui_features); + +- const LV2_Feature parent_feature = { +- LV2_UI__parent, parent +- }; +- const LV2_Feature instance_feature = { +- NS_EXT "instance-access", lilv_instance_get_handle(jalv->instance) +- }; +- const LV2_Feature* ui_features[] = { +- &uri_map_feature, &map_feature, &unmap_feature, +- &instance_feature, +- &log_feature, +- &parent_feature, +- &options_feature, +- NULL +- }; ++ if (jalv->ui_instance) { ++ jalv->extuiptr = suil_instance_get_widget((SuilInstance*)jalv->ui_instance); ++ } else { ++ jalv->externalui = false; ++ } ++ } else { + +- jalv->ui_instance = suil_instance_new( +- jalv->ui_host, +- jalv, +- native_ui_type, +- lilv_node_as_uri(lilv_plugin_get_uri(jalv->plugin)), +- lilv_node_as_uri(lilv_ui_get_uri(jalv->ui)), +- lilv_node_as_uri(jalv->ui_type), +- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(jalv->ui))), +- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(jalv->ui))), +- ui_features); ++ const LV2_Feature parent_feature = { ++ LV2_UI__parent, parent ++ }; ++ const LV2_Feature instance_feature = { ++ NS_EXT "instance-access", lilv_instance_get_handle(jalv->instance) ++ }; ++ const LV2_Feature* ui_features[] = { ++ &uri_map_feature, &map_feature, &unmap_feature, ++ &instance_feature, ++ &log_feature, ++ &parent_feature, ++ &options_feature, ++ NULL ++ }; ++ ++ jalv->ui_instance = suil_instance_new( ++ jalv->ui_host, ++ jalv, ++ native_ui_type, ++ lilv_node_as_uri(lilv_plugin_get_uri(jalv->plugin)), ++ lilv_node_as_uri(lilv_ui_get_uri(jalv->ui)), ++ lilv_node_as_uri(jalv->ui_type), ++ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(jalv->ui))), ++ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(jalv->ui))), ++ ui_features); ++ } + + /* Set initial control values on UI */ + if (jalv->ui_instance) { +@@ -688,6 +729,7 @@ jalv_ui_instantiate(Jalv* jalv, const char* native_ui_type, void* parent) + } + } + ++ + bool + jalv_ui_is_resizable(Jalv* jalv) + { +@@ -795,6 +837,9 @@ jalv_emit_ui_events(Jalv* jalv) + jalv_ui_port_event(jalv, ev.index, ev.size, ev.protocol, buf); + } + } ++ if (jalv->externalui && jalv->extuiptr) { ++ LV2_EXTERNAL_UI_RUN(jalv->extuiptr); ++ } + + return true; + } +@@ -938,6 +983,8 @@ main(int argc, char** argv) + jalv.nodes.rsz_minimumSize = lilv_new_uri(world, LV2_RESIZE_PORT__minimumSize); + jalv.nodes.work_interface = lilv_new_uri(world, LV2_WORKER__interface); + jalv.nodes.work_schedule = lilv_new_uri(world, LV2_WORKER__schedule); ++ jalv.nodes.ui_externallv = lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#external"); ++ jalv.nodes.ui_externalkx = lilv_new_uri(world, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget"); + jalv.nodes.end = NULL; + + /* Get plugin URI from loaded state or command line */ +@@ -1013,11 +1060,31 @@ main(int argc, char** argv) + } + } + } ++ if (!jalv.ui) { ++ LILV_FOREACH(uis, u, jalv.uis) { ++ const LilvUI* ui = lilv_uis_get(jalv.uis, u); ++ const LilvNodes* types = lilv_ui_get_classes(ui); ++ LILV_FOREACH(nodes, t, types) { ++ const char * pt = lilv_node_as_uri(lilv_nodes_get(types, t)); ++ if (!strcmp(pt, "http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget")) { ++ jalv.externalui = true; ++ jalv.ui = ui; ++ jalv.ui_type = jalv.nodes.ui_externalkx; ++ } else if (!strcmp(pt, "http://lv2plug.in/ns/extensions/ui#external")) { ++ jalv.externalui = true; ++ jalv.ui_type = jalv.nodes.ui_externallv; ++ jalv.ui = ui; ++ } ++ } ++ } ++ } + + /* Create ringbuffers for UI if necessary */ + if (jalv.ui) { + fprintf(stderr, "UI: %s\n", + lilv_node_as_uri(lilv_ui_get_uri(jalv.ui))); ++ fprintf(stderr, "UI Type: %s\n", ++ lilv_node_as_uri(jalv.ui_type)); + } else { + fprintf(stderr, "No appropriate UI found\n"); + } +diff --git a/jalv/src/jalv_gtk.c b/jalv/src/jalv_gtk.c +index bb92dbb..5599c0c 100644 +--- a/jalv/src/jalv_gtk.c ++++ b/jalv/src/jalv_gtk.c +@@ -803,18 +803,28 @@ build_menu(Jalv* jalv, GtkWidget* window, GtkWidget* vbox) + gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 0); + } + ++void ++on_external_ui_closed(void* controller) ++{ ++ Jalv* jalv = (Jalv*) controller; ++ jalv_close_ui(jalv); ++} ++ + int + jalv_open_ui(Jalv* jalv) + { ++ LV2_External_UI_Host extui; + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + jalv->window = window; + jalv->has_ui = TRUE; ++ extui.ui_closed = on_external_ui_closed; + + g_signal_connect(window, "destroy", + G_CALLBACK(on_window_destroy), jalv); + + LilvNode* name = lilv_plugin_get_name(jalv->plugin); + gtk_window_set_title(GTK_WINDOW(window), lilv_node_as_string(name)); ++ extui.plugin_human_id = jalv_strdup(lilv_node_as_string(name)); + lilv_node_free(name); + + GtkWidget* vbox = new_box(false, 0); +@@ -832,10 +842,16 @@ jalv_open_ui(Jalv* jalv) + + /* Attempt to instantiate custom UI if necessary */ + if (jalv->ui && !jalv->opts.generic_ui) { +- jalv_ui_instantiate(jalv, jalv_native_ui_type(jalv), alignment); ++ if (jalv->externalui) { ++ jalv_ui_instantiate(jalv, lilv_node_as_uri(jalv->ui_type), &extui); ++ } else { ++ jalv_ui_instantiate(jalv, jalv_native_ui_type(jalv), alignment); ++ } + } + +- if (jalv->ui_instance) { ++ if (jalv->externalui && jalv->extuiptr) { ++ LV2_EXTERNAL_UI_SHOW(jalv->extuiptr); ++ } else if (jalv->ui_instance) { + GtkWidget* widget = (GtkWidget*)suil_instance_get_widget( + jalv->ui_instance); + +@@ -843,6 +859,7 @@ jalv_open_ui(Jalv* jalv) + gtk_window_set_resizable(GTK_WINDOW(window), jalv_ui_is_resizable(jalv)); + gtk_widget_show_all(vbox); + gtk_widget_grab_focus(widget); ++ gtk_window_present(GTK_WINDOW(window)); + } else { + GtkWidget* controls = build_control_widget(jalv, window); + GtkWidget* scroll_win = gtk_scrolled_window_new(NULL, NULL); +@@ -862,13 +879,12 @@ jalv_open_ui(Jalv* jalv) + GTK_WINDOW(window), + MAX(MAX(box_size.width, controls_size.width) + 24, 640), + box_size.height + controls_size.height); ++ gtk_window_present(GTK_WINDOW(window)); + } + + g_timeout_add(1000 / jalv->ui_update_hz, + (GSourceFunc)jalv_emit_ui_events, jalv); + +- gtk_window_present(GTK_WINDOW(window)); +- + gtk_main(); + zix_sem_post(jalv->done); + return 0; +diff --git a/jalv/src/jalv_internal.h b/jalv/src/jalv_internal.h +index 4531ee6..f24c05a 100644 +--- a/jalv/src/jalv_internal.h ++++ b/jalv/src/jalv_internal.h +@@ -44,6 +44,8 @@ + #include "lv2_evbuf.h" + #include "symap.h" + ++#include "lv2_external_ui.h" ++ + #ifdef __cplusplus + extern "C" { + #endif +@@ -139,6 +141,8 @@ typedef struct { + LilvNode* rsz_minimumSize; + LilvNode* work_interface; + LilvNode* work_schedule; ++ LilvNode* ui_externallv; ++ LilvNode* ui_externalkx; + LilvNode* end; ///< NULL terminator for easy freeing of entire structure + } JalvNodes; + +@@ -204,6 +208,8 @@ typedef struct { + bool buf_size_set; ///< True iff buffer size callback fired + bool exit; ///< True iff execution is finished + bool has_ui; ///< True iff a control UI is present ++ bool externalui; ///< True iff plugin has an external-ui ++ LV2_External_UI_Widget* extuiptr; ///< data structure used for external-ui + } Jalv; + + int +diff --git a/jalv/src/lv2_external_ui.h b/jalv/src/lv2_external_ui.h +new file mode 100644 +index 0000000..2c9e6ee +--- /dev/null ++++ b/jalv/src/lv2_external_ui.h +@@ -0,0 +1,109 @@ ++/* ++ LV2 External UI extension ++ This work is in public domain. ++ ++ This file 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. ++ ++ If you have questions, contact Filipe Coelho (aka falkTX) ++ or ask in #lad channel, FreeNode IRC network. ++*/ ++ ++/** ++ @file lv2_external_ui.h ++ C header for the LV2 External UI extension . ++*/ ++ ++#ifndef LV2_EXTERNAL_UI_H ++#define LV2_EXTERNAL_UI_H ++ ++#include "lv2/lv2plug.in/ns/extensions/ui/ui.h" ++ ++#define LV2_EXTERNAL_UI_URI "http://kxstudio.sf.net/ns/lv2ext/external-ui" ++#define LV2_EXTERNAL_UI_PREFIX LV2_EXTERNAL_UI_URI "#" ++ ++#define LV2_EXTERNAL_UI__Host LV2_EXTERNAL_UI_PREFIX "Host" ++#define LV2_EXTERNAL_UI__Widget LV2_EXTERNAL_UI_PREFIX "Widget" ++ ++/** This extension used to be defined by a lv2plug.in URI */ ++#define LV2_EXTERNAL_UI_DEPRECATED_URI "http://lv2plug.in/ns/extensions/ui#external" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * When LV2_EXTERNAL_UI__Widget UI is instantiated, the returned ++ * LV2UI_Widget handle must be cast to pointer to LV2_External_UI_Widget. ++ * UI is created in invisible state. ++ */ ++typedef struct _LV2_External_UI_Widget { ++ /** ++ * Host calls this function regulary. UI library implementing the ++ * callback may do IPC or redraw the UI. ++ * ++ * @param _this_ the UI context ++ */ ++ void (*run)(struct _LV2_External_UI_Widget * _this_); ++ ++ /** ++ * Host calls this function to make the plugin UI visible. ++ * ++ * @param _this_ the UI context ++ */ ++ void (*show)(struct _LV2_External_UI_Widget * _this_); ++ ++ /** ++ * Host calls this function to make the plugin UI invisible again. ++ * ++ * @param _this_ the UI context ++ */ ++ void (*hide)(struct _LV2_External_UI_Widget * _this_); ++ ++} LV2_External_UI_Widget; ++ ++#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr) ++#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr) ++#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr) ++ ++/** ++ * On UI instantiation, host must supply LV2_EXTERNAL_UI__Host feature. ++ * LV2_Feature::data must be pointer to LV2_External_UI_Host. ++ */ ++typedef struct _LV2_External_UI_Host { ++ /** ++ * Callback that plugin UI will call when UI (GUI window) is closed by user. ++ * This callback will be called during execution of LV2_External_UI_Widget::run() ++ * (i.e. not from background thread). ++ * ++ * After this callback is called, UI is defunct. Host must call LV2UI_Descriptor::cleanup(). ++ * If host wants to make the UI visible again, the UI must be reinstantiated. ++ * ++ * @note When using the depreated URI LV2_EXTERNAL_UI_DEPRECATED_URI, ++ * some hosts will not call LV2UI_Descriptor::cleanup() as they should, ++ * and may call show() again without re-initialization. ++ * ++ * @param controller Host context associated with plugin UI, as ++ * supplied to LV2UI_Descriptor::instantiate(). ++ */ ++ void (*ui_closed)(LV2UI_Controller controller); ++ ++ /** ++ * Optional (may be NULL) "user friendly" identifier which the UI ++ * may display to allow a user to easily associate this particular ++ * UI instance with the correct plugin instance as it is represented ++ * by the host (e.g. "track 1" or "channel 4"). ++ * ++ * If supplied by host, the string will be referenced only during ++ * LV2UI_Descriptor::instantiate() ++ */ ++ const char * plugin_human_id; ++ ++} LV2_External_UI_Host; ++ ++#ifdef __cplusplus ++} /* extern "C" */ ++#endif ++ ++#endif /* LV2_EXTERNAL_UI_H */