diff --git a/templates/lv2/data/manifest.ttl.in b/templates/lv2/data/manifest.ttl.in index 4dfa814..731c9cd 100644 --- a/templates/lv2/data/manifest.ttl.in +++ b/templates/lv2/data/manifest.ttl.in @@ -124,5 +124,6 @@ {{?it.lv2.ui}} {{=it.tibia.lv2.ttlURI(it.lv2.ui.uri)}} a ui:@UI_TYPE@ ; - ui:binary <{{=it.product.bundleName}}@DLL_SUFFIX@> . + ui:binary <{{=it.product.bundleName}}@DLL_SUFFIX@> ; + lv2:requiredFeature ui:idleInterface . {{?}} diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index 21e50da..f2c1fca 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -21,6 +21,7 @@ #include #include +#define TEMPLATE_HAS_UI #include "data.h" #include "plugin.h" @@ -301,48 +302,40 @@ typedef struct { } ui_instance; static LV2UI_Handle ui_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) { - *widget = NULL; + char has_parent = 0; + void *parent = NULL; + for (size_t i = 0; features[i] != NULL; i++) + if (!strcmp(features[i]->URI, LV2_UI__parent)) { + has_parent = 1; + parent = features[i]->data; + } - ui_instance *instance = malloc(sizeof(ui_instance)); - if (instance == NULL) - return NULL; - - instance->display = XOpenDisplay(NULL); - if (instance->display == NULL) { - free(instance); + plugin_ui *instance = plugin_ui_create(has_parent, parent); + if (instance == NULL) { + *widget = NULL; return NULL; } - - Window parent; - const char* missing = lv2_features_query(features, - LV2_UI__parent, &parent, false, - NULL); - - int screen = DefaultScreen(instance->display); - instance->window = XCreateSimpleWindow(instance->display, missing ? RootWindow(instance->display, screen) : parent, 0, 0, 400, 200, 5, BlackPixel(instance->display, screen), WhitePixel(instance->display, screen)); - //XSelectInput(instance->display, instance->window, ExposureMask | KeyPressMask); - XMapWindow(instance->display, instance->window); - XEvent ev; - while (XPending(instance->display)) - XNextEvent(instance->display, &ev); - *widget = instance->window; - + *widget = instance->widget; return instance; } static void ui_cleanup(LV2UI_Handle handle) { - ui_instance *instance = (ui_instance *)handle; - XDestroyWindow(instance->display, instance->window); - XCloseDisplay(instance->display); - free(instance); + plugin_ui_free((plugin_ui *)handle); } static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void * buffer) { //TODO } +static int ui_idle(LV2UI_Handle handle) { + plugin_ui_idle((plugin_ui *)handle); + return 0; +} + static const void * ui_extension_data(const char * uri) { - //TODO + static const LV2UI_Idle_Interface idle = { ui_idle }; + if (!strcmp(uri, LV2_UI__idleInterface)) + return &idle; return NULL; } diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 4268dab..2d3b57b 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -26,7 +26,9 @@ #pragma GCC diagnostic ignored "-Wpedantic" #include "vst3_c_api.h" #pragma GCC diagnostic pop + #include "data.h" +#define TEMPLATE_HAS_UI #include "plugin.h" #if defined(__i386__) || defined(__x86_64__) @@ -931,8 +933,8 @@ static Steinberg_tresult plugViewGetSize(void* thisInterface, struct Steinberg_V //TODO size->left = 0; size->top = 0; - size->right = 0; - size->bottom = 0; + size->right = 600; + size->bottom = 400; return Steinberg_kResultTrue; } diff --git a/test/lv2-make.json b/test/lv2-make.json new file mode 100644 index 0000000..5e903cb --- /dev/null +++ b/test/lv2-make.json @@ -0,0 +1,6 @@ +{ + "lv2_make": { + "cflags": "$(shell pkg-config --cflags pugl-cairo-0)", + "ldflags": "$(shell pkg-config --libs pugl-cairo-0)" + } +} diff --git a/test/plugin.h b/test/plugin.h index e4a1dca..ed1fbc0 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -116,4 +116,67 @@ static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * d instance->cutoff_k = data[1] < 64 ? (-0.19558034980097166f * data[1] - 2.361735109225749f) / (data[1] - 75.57552349522389f) : (393.95397927344214f - 7.660826245588588f * data[1]) / (data[1] - 139.0755234952239f); } -#define PLUGIN_UI +#ifdef TEMPLATE_HAS_UI +# define PLUGIN_UI + +# include +# include +# include + +typedef struct { + void * widget; + PuglWorld * world; + PuglView * view; +} plugin_ui; + +static PuglStatus onEvent(PuglView *view, const PuglEvent *event) { + switch (event->type) { + case PUGL_EXPOSE: + { + cairo_t *cr = (cairo_t *)puglGetContext(view); + cairo_set_source_rgb(cr, 1, 0.5, 0); + cairo_paint(cr); + } + break; + default: + break; + } + return PUGL_SUCCESS; +} + +static plugin_ui *plugin_ui_create(char has_parent, void *parent) { + plugin_ui *instance = malloc(sizeof(plugin_ui)); + if (instance == NULL) + return NULL; + instance->world = puglNewWorld(PUGL_MODULE, 0); + instance->view = puglNewView(instance->world); + puglSetSizeHint(instance->view, PUGL_DEFAULT_SIZE, 600, 400); + puglSetViewHint(instance->view, PUGL_RESIZABLE, 0); + puglSetBackend(instance->view, puglCairoBackend()); + PuglRect frame = { 0, 0, 600, 400 }; + puglSetFrame(instance->view, frame); + puglSetEventFunc(instance->view, onEvent); + if (has_parent) { + puglSetParentWindow(instance->view, (PuglNativeView)parent); + } + if (puglRealize(instance->view)) { + puglFreeView(instance->view); + puglFreeWorld(instance->world); + return NULL; + } + puglShow(instance->view, PUGL_SHOW_RAISE); + instance->widget = (void *)puglGetNativeView(instance->view); + return instance; +} + +static void plugin_ui_free(plugin_ui *instance) { + puglFreeView(instance->view); + puglFreeWorld(instance->world); + free(instance); +} + +static void plugin_ui_idle(plugin_ui *instance) { + puglUpdate(instance->world, 0); +} + +#endif diff --git a/test/run.sh b/test/run.sh index 35643d0..023f3d5 100755 --- a/test/run.sh +++ b/test/run.sh @@ -6,7 +6,7 @@ $dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json,$dir/vst3-make. cp $dir/plugin.h $dir/../out/vst3/src $dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2 $dir/../out/lv2 -$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2-make $dir/../out/lv2 +$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json,$dir/lv2-make.json $dir/../templates/lv2-make $dir/../out/lv2 cp $dir/plugin.h $dir/../out/lv2/src $dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web $dir/../out/web