more lv2 gui (w/ pugl example)

This commit is contained in:
Stefano D'Angelo 2024-05-09 18:04:47 +02:00
parent 292e83dcea
commit 8c5fe9cb84
6 changed files with 98 additions and 33 deletions

View File

@ -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 .
{{?}}

View File

@ -21,6 +21,7 @@
#include <stdlib.h>
#include <stdint.h>
#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;
}

View File

@ -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;
}

6
test/lv2-make.json Normal file
View File

@ -0,0 +1,6 @@
{
"lv2_make": {
"cflags": "$(shell pkg-config --cflags pugl-cairo-0)",
"ldflags": "$(shell pkg-config --libs pugl-cairo-0)"
}
}

View File

@ -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 <pugl/pugl.h>
# include <pugl/cairo.h>
# include <cairo.h>
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

View File

@ -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