lv2 phase 2 fixups
[goodguy/history.git] / cinelerra-5.1 / cinelerra / pluginlv2ui.C
index 929b5c676f4123669ca7fe6aa808c096e1df855e..b8f99ab1318d1ada59f5a20cfbdc4c91adbd1702 100644 (file)
@@ -9,39 +9,6 @@
 #include <ctype.h>
 #include <string.h>
 
-int PluginLV2UI::init_ui(const char *path, int sample_rate)
-{
-       if( load_lv2(path, title) ) return 1;
-       if( init_lv2(config, sample_rate) ) return 1;
-
-       lilv_uis = lilv_plugin_get_uis(lilv);
-       if( !lilv_uis ) {
-               printf("lv2: lilv_plugin_get_uis(%s) failed\n", path);
-               return 1;
-       }
-
-       if( gtk_type ) {
-               LilvNode *gui_type = lilv_new_uri(world, gtk_type);
-               LILV_FOREACH(uis, i, lilv_uis) {
-                       const LilvUI *ui = lilv_uis_get(lilv_uis, i);
-                       if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) {
-                               lilv_ui = ui;
-                               break;
-                       }
-               }
-               lilv_node_free(gui_type);
-       }
-       if( !lilv_ui )
-               lilv_ui = lilv_uis_get(lilv_uis, lilv_uis_begin(lilv_uis));
-       if( !lilv_ui ) {
-               printf("lv2_gui: init_ui failed: %s\n", title);
-               return 1;
-       }
-
-       lilv_instance_activate(inst);
-       return 0;
-}
-
 void PluginLV2UI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void *bfr)
 {
        if( idx >= config.nb_ports ) return;
@@ -49,7 +16,7 @@ void PluginLV2UI::update_value(int idx, uint32_t bfrsz, uint32_t typ, const void
                PluginLV2Client_Opt *opt = config[i];
                if( opt->idx == idx ) {
                        opt->set_value(*(const float*)bfr);
-                       updates = UPDATE_HOST;
+                       updates |= UPDATE_HOST;
                        break;
                }
        }
@@ -77,17 +44,6 @@ void PluginLV2UI::update_control(int idx, uint32_t bfrsz, uint32_t typ, const vo
 }
 
 
-#if 0
-void PluginLV2UI::touch(void *obj, uint32_t pidx, bool grabbed)
-{
-       PluginLV2UI* the = (PluginLV2GUI*)obj;
-       int idx = pidx;
-       if( idx >= the->config.nb_ports ) return;
-printf("%s %s(%u)\n", (grabbed? _("press") : _("release")),
-  the->config.names[idx], idx);
-}
-#endif
-
 uint32_t PluginLV2UI::uri_to_id(LV2_URID_Map_Handle handle, const char *map, const char *uri)
 {
        return ((PluginLV2UriTable *)handle)->map(uri);
@@ -110,8 +66,7 @@ void PluginLV2UI::lv2ui_instantiate(void *parent)
                        PluginLV2UI::write_from_ui,
                        PluginLV2UI::port_index,
                        0, 0);
-//             suil_host_set_touch_func(ui_host,
-//                     PluginLV2GUI::touch);
+//             suil_host_set_touch_func(ui_host, cb_touch);
        }
 
        features.remove();  // remove terminating zero
@@ -124,13 +79,15 @@ void PluginLV2UI::lv2ui_instantiate(void *parent)
        features.append(new Lv2Feature(LV2_DATA_ACCESS_URI, ext_data));
        features.append(new Lv2Feature(LV2_UI__parent, parent));
        features.append(new Lv2Feature(LV2_UI__idleInterface, 0));
+       features.append(new Lv2Feature(LV2_EXTERNAL_UI_URI, &extui_host));
+       features.append(new Lv2Feature(LV2_EXTERNAL_UI_URI__KX__Host, &extui_host));
        features.append(0); // add new terminating zero
 
        const char* bundle_uri  = lilv_node_as_uri(lilv_ui_get_bundle_uri(lilv_ui));
        char*       bundle_path = lilv_file_uri_parse(bundle_uri, NULL);
        const char* binary_uri  = lilv_node_as_uri(lilv_ui_get_binary_uri(lilv_ui));
        char*       binary_path = lilv_file_uri_parse(binary_uri, NULL);
-       sinst = suil_instance_new(ui_host, this, gtk_type,
+       sinst = suil_instance_new(ui_host, this, ui_type,
                lilv_node_as_uri(lilv_plugin_get_uri(lilv)),
                lilv_node_as_uri(lilv_ui_get_uri(lilv_ui)),
                lilv_node_as_uri(lilv_type),
@@ -157,11 +114,6 @@ bool PluginLV2UI::lv2ui_resizable()
        return !fs_matches && !nrs_matches;
 }
 
-int PluginLV2UI::send_host(int64_t token, const void *data, int bytes)
-{
-       return !child ? 0 : child->send_parent(token, data, bytes);
-}
-
 int PluginLV2UI::update_lv2_input(float *vals, int force)
 {
        int ret = 0;
@@ -188,37 +140,31 @@ void PluginLV2UI::update_lv2_output()
        }
 }
 
-static void lilv_destroy(GtkWidget* widget, gpointer data)
+void PluginLV2UI::run_lilv(int samples)
 {
-       PluginLV2UI *the = (PluginLV2UI*)data;
-       the->top_level = 0;
-}
+       float ctls[config.nb_ports];
+       for( int i=0; i<config.nb_ports; ++i ) ctls[i] = config.ctls[i];
 
-void PluginLV2UI::start_gui()
-{
-       if( !hidden ) return;
-       top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-       g_signal_connect(top_level, "destroy", G_CALLBACK(lilv_destroy), this);
-       gtk_window_set_title(GTK_WINDOW(top_level), title);
+       lilv_instance_run(inst, samples);
 
-       GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
-       gtk_window_set_role(GTK_WINDOW(top_level), "plugin_ui");
-       gtk_container_add(GTK_CONTAINER(top_level), vbox);
+       if( worker_iface ) worker_responses();
 
-       GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
-       gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
-       gtk_widget_show(alignment);
-       lv2ui_instantiate(alignment);
-       GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(sinst);
-       gtk_container_add(GTK_CONTAINER(alignment), widget);
-       gtk_window_set_resizable(GTK_WINDOW(top_level), lv2ui_resizable());
-       gtk_widget_show_all(vbox);
-       gtk_widget_grab_focus(widget);
+       for( int i=0; i<config.nb_ports; ++i ) {
+               if( !(config.ports[i] & PORTS_OUTPUT) ) continue;
+               if( !(config.ports[i] & PORTS_CONTROL) ) continue;
+               if( config.ctls[i] == ctls[i] ) continue;
+               config.ports[i] |= PORTS_UPDATE;
+               updates |= UPDATE_PORTS;
+       }
+}
+
+void PluginLV2ChildUI::start_gui()
+{
+       gui->start_gui();
        update_lv2_input(config.ctls, 1);
-       connect_ports(config, PORTS_CONTROL);
+       connect_ports(config, PORTS_CONTROL | PORTS_ATOM);
        updates = 0;
        run_lilv(0);
-       gtk_window_present(GTK_WINDOW(top_level));
        send_host(LV2_SHOW, 0, 0);
        hidden = 0;
 }
@@ -230,33 +176,89 @@ void PluginLV2UI::update_host()
        send_host(LV2_UPDATE, config.ctls, sizeof(float)*config.nb_ports);
 }
 
-void PluginLV2UI::reset_gui()
+
+static void lv2ui_extui_host_ui_closed(void *p)
+{
+       PluginLV2UI *ui = (PluginLV2UI *)p;
+       ui->hidden = -1;
+}
+
+int PluginLV2ChildUI::init_ui(const char *path, int sample_rate)
+{
+       char *title = PluginLV2UI::title;
+       if( load_lv2(path, title) ) return 1;
+       if( init_lv2(config, sample_rate) ) return 1;
+
+       lilv_uis = lilv_plugin_get_uis(lilv);
+       if( !lilv_uis ) {
+               printf("lv2: lilv_plugin_get_uis(%s) failed\n", path);
+               return 1;
+       }
+
+       if( !gui && wgt_type ) {
+               LilvNode *gui_type = lilv_new_uri(world, wgt_type);
+               LILV_FOREACH(uis, i, lilv_uis) {
+                       const LilvUI *ui = lilv_uis_get(lilv_uis, i);
+                       if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) {
+                               extui_host.ui_closed = lv2ui_extui_host_ui_closed;
+                               gui = new PluginLV2ChildWgtUI(this);
+                               lilv_ui = ui;
+                               ui_type = wgt_type;
+                               break;
+                       }
+               }
+               lilv_node_free(gui_type);
+       }
+       if( !gui && gtk_type ) {
+               LilvNode *gui_type = lilv_new_uri(world, gtk_type);
+               LILV_FOREACH(uis, i, lilv_uis) {
+                       const LilvUI *ui = lilv_uis_get(lilv_uis, i);
+                       if( lilv_ui_is_supported(ui, suil_ui_supported, gui_type, &lilv_type)) {
+                               gui = new PluginLV2ChildGtkUI(this);
+                               lilv_ui = ui;
+                               ui_type = gtk_type;
+                               break;
+                       }
+               }
+               lilv_node_free(gui_type);
+               ui_type = gtk_type;
+       }
+
+       if( !gui ) {
+               printf("lv2_gui: init_ui failed: %s\n", title);
+               return 1;
+       }
+
+       lilv_instance_activate(inst);
+       return 0;
+}
+
+void PluginLV2ChildUI::reset_gui()
 {
-       if( hidden ) return;
+       gui->reset_gui();
        if( sinst )     { suil_instance_free(sinst);  sinst = 0; }
        if( ui_host )   { suil_host_free(ui_host);    ui_host = 0; }
-       if( top_level ) { gtk_widget_destroy(top_level); top_level = 0; }
 
        while( features.size() > ui_features ) features.remove_object();
        features.append(0);
-       hidden = 1;
        send_host(LV2_HIDE, 0, 0);
+       hidden = 1;
 }
 
-
-// child main
-int PluginLV2UI::run_ui(PluginLV2ChildUI *child)
+// main loop
+int PluginLV2ChildUI::run_ui()
 {
-       this->child = child;
+       double last_time = 0, fps = 30;
+       int64_t frame_usecs = 1e6 / fps;
        running = 1;
        done = 0;
        while( !done ) {
-               if( gtk_events_pending() ) {
-                       gtk_main_iteration();
-                       continue;
-               }
-               if( !top_level && !hidden )
+               if( hidden < 0 ) {
+                       gui->top_level = 0;
                        reset_gui();
+                       done = -1;
+                       break;
+               }
                if( updates ) {
                        if( (updates & UPDATE_PORTS) )
                                update_lv2_output();
@@ -264,30 +266,18 @@ int PluginLV2UI::run_ui(PluginLV2ChildUI *child)
                                update_host();
                        updates = 0;
                }
-               if( !child ) usleep(10000);
-               else if( child->child_iteration() < 0 )
+               struct timeval tv;  gettimeofday(&tv, 0);
+               double t = tv.tv_sec + tv.tv_usec / 1e6;
+               double dt = t - last_time;  last_time = t;
+               int64_t usec = frame_usecs - dt*1e6;
+               if( usec < 0 ) usec = 0;
+               if( child_iteration(usec) < 0 )
                        done = 1;
        }
        running = 0;
        return 0;
 }
 
-void PluginLV2UI::run_lilv(int samples)
-{
-       float ctls[config.nb_ports];
-       for( int i=0; i<config.nb_ports; ++i ) ctls[i] = config.ctls[i];
-
-       lilv_instance_run(inst, samples);
-
-       for( int i=0; i<config.nb_ports; ++i ) {
-               if( !(config.ports[i] & PORTS_OUTPUT) ) continue;
-               if( !(config.ports[i] & PORTS_CONTROL) ) continue;
-               if( config.ctls[i] == ctls[i] ) continue;
-               config.ports[i] |= PORTS_UPDATE;
-               updates |= UPDATE_PORTS;
-       }
-}
-
 void PluginLV2ChildUI::run_buffer(int shmid)
 {
        if( !shm_buffer(shmid) ) return;
@@ -297,35 +287,148 @@ void PluginLV2ChildUI::run_buffer(int shmid)
        shm_bfr->done = 1;
 }
 
-int PluginLV2ChildUI::handle_child()
-{
-       switch( child_token ) {
-       case LV2_OPEN: {
-               open_bfr_t *open_bfr = (open_bfr_t *)child_data;
-               if( init_ui(open_bfr->path, open_bfr->sample_rate) ) exit(1);
-               break; }
-       case LV2_LOAD: {
-               float *vals = (float *)child_data;
-               update_lv2_input(vals, 1);
-               break; }
-       case LV2_UPDATE: {
-               float *vals = (float *)child_data;
-               update_lv2_input(vals, 0);
-               break; }
-       case LV2_SHOW: {
-               start_gui();
-               break; }
-       case LV2_HIDE: {
-               reset_gui();
-               break; }
-       case LV2_SHMID: {
-               int shmid = *(int *)child_data;
-               run_buffer(shmid);
-               send_parent(LV2_SHMID, 0, 0);
-               break; }
-       case EXIT_CODE:
-               return -1;
+int PluginLV2ChildUI::child_iteration(int64_t usec)
+{
+       int ret = 0;
+       if( is_forked() )
+               ret = read_child(usec);
+       else
+               usleep(usec);
+       if( ret > 0 ) {
+               switch( child_token ) {
+               case LV2_OPEN: {
+                       open_bfr_t *open_bfr = (open_bfr_t *)child_data;
+                       if( init_ui(open_bfr->path, open_bfr->sample_rate) ) {
+                               printf("lv2ui: unable to init: %s\n", open_bfr->path);
+                               exit(1);
+                       }
+                       break; }
+               case LV2_LOAD: {
+                       float *vals = (float *)child_data;
+                       update_lv2_input(vals, 1);
+                       break; }
+               case LV2_UPDATE: {
+                       float *vals = (float *)child_data;
+                       update_lv2_input(vals, 0);
+                       break; }
+               case LV2_SHOW: {
+                       start_gui();
+                       break; }
+               case LV2_HIDE: {
+                       reset_gui();
+                       break; }
+               case LV2_SHMID: {
+                       int shmid = *(int *)child_data;
+                       run_buffer(shmid);
+                       send_parent(LV2_SHMID, 0, 0);
+                       break; }
+               case EXIT_CODE:
+                       return -1;
+               }
+       }
+       if( ret >= 0 && gui )
+               gui->handle_child();
+       return ret;
+}
+
+int PluginLV2ChildUI::send_host(int64_t token, const void *data, int bytes)
+{
+       return is_forked() ? send_parent(token, data, bytes) : 0;
+}
+
+PluginLV2GUI::PluginLV2GUI(PluginLV2ChildUI *child_ui)
+{
+       this->child_ui = child_ui;
+       top_level = 0;
+}
+
+PluginLV2GUI::~PluginLV2GUI()
+{
+}
+
+PluginLV2ChildGtkUI::PluginLV2ChildGtkUI(PluginLV2ChildUI *child_ui)
+ : PluginLV2GUI(child_ui)
+{
+       gtk_set_locale();
+       gtk_init(&child_ui->ac, &child_ui->av);
+}
+
+PluginLV2ChildGtkUI::~PluginLV2ChildGtkUI()
+{
+}
+
+void PluginLV2ChildGtkUI::reset_gui()
+{
+       GtkWidget *top_level = (GtkWidget *)this->top_level;
+       if( top_level ) { gtk_widget_destroy(top_level); this->top_level = 0; }
+}
+
+static void lilv_gtk_destroy(GtkWidget* widget, gpointer data)
+{
+       PluginLV2ChildGtkUI *gui = (PluginLV2ChildGtkUI*)data;
+       gui->child_ui->hidden = -1;
+}
+
+void PluginLV2ChildGtkUI::start_gui()
+{
+       this->top_level = (void *)gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       GtkWidget *top_level = (GtkWidget *)this->top_level;
+       g_signal_connect(top_level, "destroy", G_CALLBACK(lilv_gtk_destroy), this);
+       char *title = child_ui->PluginLV2UI::title;
+       gtk_window_set_title(GTK_WINDOW(top_level), title);
+
+       GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
+       gtk_window_set_role(GTK_WINDOW(top_level), "plugin_ui");
+       gtk_container_add(GTK_CONTAINER(top_level), vbox);
+
+       GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0);
+       gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
+       gtk_widget_show(alignment);
+       child_ui->lv2ui_instantiate(alignment);
+       GtkWidget* widget = (GtkWidget*)suil_instance_get_widget(child_ui->sinst);
+       gtk_container_add(GTK_CONTAINER(alignment), widget);
+       gtk_window_set_resizable(GTK_WINDOW(top_level), child_ui->lv2ui_resizable());
+       gtk_widget_show_all(vbox);
+       gtk_widget_grab_focus(widget);
+       gtk_window_present(GTK_WINDOW(top_level));
+}
+
+int PluginLV2ChildGtkUI::handle_child()
+{
+       if( gtk_events_pending() ) {
+               gtk_main_iteration();
        }
        return 1;
 }
 
+PluginLV2ChildWgtUI::PluginLV2ChildWgtUI(PluginLV2ChildUI *child_ui)
+ : PluginLV2GUI(child_ui)
+{
+}
+
+PluginLV2ChildWgtUI::~PluginLV2ChildWgtUI()
+{
+}
+
+void PluginLV2ChildWgtUI::reset_gui()
+{
+       lv2_external_ui *top_level = (lv2_external_ui *)this->top_level;
+       if( top_level ) { LV2_EXTERNAL_UI_HIDE(top_level); this->top_level = 0; }
+}
+
+void PluginLV2ChildWgtUI::start_gui()
+{
+       child_ui->lv2ui_instantiate(0);
+       this->top_level = (void *)suil_instance_get_widget(child_ui->sinst);
+       lv2_external_ui *top_level = (lv2_external_ui *)this->top_level;
+       if( top_level ) LV2_EXTERNAL_UI_SHOW(top_level);
+}
+
+int PluginLV2ChildWgtUI::handle_child()
+{
+       lv2_external_ui *top_level = (lv2_external_ui *)this->top_level;
+       if( top_level )
+               LV2_EXTERNAL_UI_RUN(top_level);
+       return 1;
+}
+