|
- commit 109070a71a1e780385b803731fbdd2689752c644
- Author: Robin Gareus <robin@gareus.org>
- 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) <falktx@falktx.com>
- + or ask in #lad channel, FreeNode IRC network.
- +*/
- +
- +/**
- + @file lv2_external_ui.h
- + C header for the LV2 External UI extension <http://kxstudio.sf.net/ns/lv2ext/external-ui>.
- +*/
- +
- +#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 */
|