1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-01-19 23:36:08 +01:00

Update lilv, lv2, serd, sord, sratom, and add suil.

This commit is contained in:
yam
2015-04-07 23:19:22 -05:00
parent f88b27e6d8
commit 57fb87e96d
1460 changed files with 64512 additions and 10876 deletions

View File

@@ -0,0 +1,150 @@
/*
Copyright 2011-2012 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <QX11EmbedContainer>
#undef signals
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "./suil_config.h"
#include "./suil_internal.h"
extern "C" {
typedef struct _SuilGtk2InQt4Wrapper SuilGtk2InQt4Wrapper;
struct _SuilGtk2InQt4Wrapper {
QX11EmbedContainer* host_widget;
QWidget* parent;
GtkWidget* plug;
};
static void
on_size_request(GtkWidget* widget,
GtkRequisition* requisition,
gpointer user_data)
{
QX11EmbedContainer* const wrap = (QX11EmbedContainer*)user_data;
wrap->setMinimumSize(requisition->width, requisition->height);
}
static void
on_size_allocate(GtkWidget* widget,
GdkRectangle* allocation,
gpointer user_data)
{
QX11EmbedContainer* const wrap = (QX11EmbedContainer*)user_data;
wrap->resize(allocation->width, allocation->height);
}
static void
wrapper_free(SuilWrapper* wrapper)
{
SuilGtk2InQt4Wrapper* impl = (SuilGtk2InQt4Wrapper*)wrapper->impl;
if (impl->plug) {
gtk_widget_destroy(impl->plug);
}
if (impl->host_widget) {
delete impl->host_widget;
}
free(impl);
}
static int
wrapper_wrap(SuilWrapper* wrapper,
SuilInstance* instance)
{
SuilGtk2InQt4Wrapper* const impl = (SuilGtk2InQt4Wrapper*)wrapper->impl;
QWidget* root = static_cast<QWidget*>(impl->parent);
QX11EmbedContainer* const wrap = new QX11EmbedContainer(root);
GtkWidget* const plug = gtk_plug_new(wrap->winId());
GtkWidget* const widget = (GtkWidget*)instance->ui_widget;
gtk_container_add(GTK_CONTAINER(plug), widget);
gtk_widget_show_all(plug);
#ifdef SUIL_OLD_GTK
wrap->resize(widget->allocation.width, widget->allocation.height);
#else
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);
wrap->resize(alloc.width, alloc.height);
#endif
g_signal_connect(
G_OBJECT(plug), "size-request", G_CALLBACK(on_size_request), wrap);
g_signal_connect(
G_OBJECT(plug), "size-allocate", G_CALLBACK(on_size_allocate), wrap);
impl->host_widget = wrap;
impl->plug = plug;
instance->host_widget = wrap;
return 0;
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
/* We have to open libgtk here, so Gtk type symbols are present and will be
found by the introspection stuff. This is required at least to make
GtkBuilder use in UIs work, otherwise they will cause "Invalid object
type" errors.
*/
if (!host->gtk_lib) {
dlerror();
host->gtk_lib = dlopen(SUIL_GTK2_LIB_NAME, RTLD_LAZY|RTLD_GLOBAL);
if (!host->gtk_lib) {
fprintf(stderr, "Failed to open %s (%s)\n",
SUIL_GTK2_LIB_NAME, dlerror());
return NULL;
}
gtk_init(NULL, NULL);
}
/* Create wrapper implementation. */
SuilGtk2InQt4Wrapper* const impl = (SuilGtk2InQt4Wrapper*)
malloc(sizeof(SuilGtk2InQt4Wrapper));
impl->host_widget = NULL;
impl->parent = NULL;
impl->plug = NULL;
/* Set parent widget if given. */
for (unsigned i = 0; i < n_features; ++i) {
if (!strcmp((*features)[i]->URI, LV2_UI__parent)) {
impl->parent = static_cast<QWidget*>((*features)[i]->data);
}
}
SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
wrapper->impl = impl;
return wrapper;
}
} // extern "C"

View File

@@ -0,0 +1,54 @@
/*
Copyright 2011-2012 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "./suil_internal.h"
SUIL_API
SuilHost*
suil_host_new(SuilPortWriteFunc write_func,
SuilPortIndexFunc index_func,
SuilPortSubscribeFunc subscribe_func,
SuilPortUnsubscribeFunc unsubscribe_func)
{
SuilHost* host = (SuilHost*)malloc(sizeof(struct SuilHostImpl));
host->write_func = write_func;
host->index_func = index_func;
host->subscribe_func = subscribe_func;
host->unsubscribe_func = unsubscribe_func;
host->touch_func = NULL;
host->gtk_lib = NULL;
return host;
}
SUIL_API
void
suil_host_set_touch_func(SuilHost* host,
SuilTouchFunc touch_func)
{
host->touch_func = touch_func;
}
SUIL_API
void
suil_host_free(SuilHost* host)
{
if (host) {
if (host->gtk_lib) {
dlclose(host->gtk_lib);
}
free(host);
}
}

View File

@@ -0,0 +1 @@
suil_instance.c

View File

@@ -0,0 +1,160 @@
/*
Copyright 2011-2014 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <gtk/gtk.h>
#include <QApplication>
#include <QX11EmbedWidget>
#include <QVBoxLayout>
#include "./suil_internal.h"
extern "C" {
#define SUIL_TYPE_QT_WRAPPER (suil_qt_wrapper_get_type())
#define SUIL_QT_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_QT_WRAPPER, SuilQtWrapper))
typedef struct _SuilQtWrapper SuilQtWrapper;
typedef struct _SuilQtWrapperClass SuilQtWrapperClass;
struct _SuilQtWrapper {
GtkSocket socket;
QApplication* app;
QX11EmbedWidget* qembed;
SuilWrapper* wrapper;
SuilInstance* instance;
};
struct _SuilQtWrapperClass {
GtkSocketClass parent_class;
};
GType suil_qt_wrapper_get_type(void); // Accessor for SUIL_TYPE_QT_WRAPPER
G_DEFINE_TYPE(SuilQtWrapper, suil_qt_wrapper, GTK_TYPE_SOCKET)
static void
suil_qt_wrapper_finalize(GObject* gobject)
{
SuilQtWrapper* const self = SUIL_QT_WRAPPER(gobject);
if (self->instance->handle) {
self->instance->descriptor->cleanup(self->instance->handle);
self->instance->handle = NULL;
}
delete self->qembed;
self->qembed = NULL;
self->app = NULL;
self->wrapper->impl = NULL;
G_OBJECT_CLASS(suil_qt_wrapper_parent_class)->finalize(gobject);
}
static void
suil_qt_wrapper_class_init(SuilQtWrapperClass* klass)
{
GObjectClass* const gobject_class = G_OBJECT_CLASS(klass);
gobject_class->finalize = suil_qt_wrapper_finalize;
}
static void
suil_qt_wrapper_init(SuilQtWrapper* self)
{
self->app = NULL;
self->qembed = NULL;
self->instance = NULL;
}
static void
suil_qt_wrapper_realize(GtkWidget* w, gpointer data)
{
SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(w);
GtkSocket* const s = GTK_SOCKET(w);
gtk_socket_add_id(s, wrap->qembed->winId());
wrap->qembed->show();
}
static int
wrapper_wrap(SuilWrapper* wrapper,
SuilInstance* instance)
{
SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(wrapper->impl);
wrap->qembed = new QX11EmbedWidget();
wrap->wrapper = wrapper;
wrap->instance = instance;
QWidget* qwidget = (QWidget*)instance->ui_widget;
QVBoxLayout* layout = new QVBoxLayout(wrap->qembed);
layout->addWidget(qwidget);
qwidget->setParent(wrap->qembed);
g_signal_connect_after(G_OBJECT(wrap),
"realize",
G_CALLBACK(suil_qt_wrapper_realize),
NULL);
instance->host_widget = GTK_WIDGET(wrap);
return 0;
}
static void
wrapper_free(SuilWrapper* wrapper)
{
if (wrapper->impl) {
SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(wrapper->impl);
gtk_object_destroy(GTK_OBJECT(wrap));
}
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
wrapper->impl = NULL;
SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(
g_object_new(SUIL_TYPE_QT_WRAPPER, NULL));
if (qApp) {
wrap->app = qApp;
} else {
static int argc = 0;
wrap->app = new QApplication(argc, NULL, true);
}
wrap->wrapper = NULL;
wrapper->impl = wrap;
return wrapper;
}
} // extern "C"

View File

@@ -0,0 +1,338 @@
/*
Copyright 2007-2014 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./suil_config.h"
#include "./suil_internal.h"
#define GTK2_UI_URI LV2_UI__GtkUI
#define QT4_UI_URI LV2_UI__Qt4UI
#define X11_UI_URI LV2_UI__X11UI
#define WIN_UI_URI LV2_UI_PREFIX "WindowsUI"
SUIL_API
unsigned
suil_ui_supported(const char* container_type_uri,
const char* ui_type_uri)
{
enum {
SUIL_WRAPPING_UNSUPPORTED = 0,
SUIL_WRAPPING_NATIVE = 1,
SUIL_WRAPPING_EMBEDDED = 2
};
if (!strcmp(container_type_uri, ui_type_uri)) {
return SUIL_WRAPPING_NATIVE;
} else if ((!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, QT4_UI_URI))
|| (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, GTK2_UI_URI))
|| (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI))
|| (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, WIN_UI_URI))
|| (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI))) {
return SUIL_WRAPPING_EMBEDDED;
} else {
return SUIL_WRAPPING_UNSUPPORTED;
}
}
static SuilWrapper*
open_wrapper(SuilHost* host,
const char* container_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
if (!container_type_uri || !strcmp(container_type_uri, ui_type_uri)) {
return NULL;
}
const char* module_name = NULL;
if (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, GTK2_UI_URI)) {
module_name = "suil_gtk2_in_qt4";
} else if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, QT4_UI_URI)) {
module_name = "suil_qt4_in_gtk2";
} else if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_gtk2";
} else if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, WIN_UI_URI)) {
module_name = "suil_win_in_gtk2";
} else if (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_qt4";
}
if (!module_name) {
SUIL_ERRORF("Unable to wrap UI type <%s> as type <%s>\n",
ui_type_uri, container_type_uri);
return NULL;
}
const char* const env_dir = getenv("SUIL_MODULE_DIR");
const char* const mod_dir = env_dir ? env_dir : SUIL_MODULE_DIR;
const size_t path_len = strlen(mod_dir)
+ strlen(SUIL_DIR_SEP SUIL_MODULE_PREFIX SUIL_MODULE_EXT)
+ strlen(module_name)
+ 2;
char* const path = (char*)calloc(path_len, 1);
snprintf(path, path_len, "%s%s%s%s%s",
mod_dir, SUIL_DIR_SEP,
SUIL_MODULE_PREFIX, module_name, SUIL_MODULE_EXT);
// Open wrap module
dlerror();
void* lib = dlopen(path, RTLD_NOW);
if (!lib) {
SUIL_ERRORF("Unable to open wrap module %s (%s)\n", path, dlerror());
return NULL;
}
SuilWrapperNewFunc wrapper_new = (SuilWrapperNewFunc)suil_dlfunc(
lib, "suil_wrapper_new");
SuilWrapper* wrapper = wrapper_new
? wrapper_new(host,
container_type_uri,
ui_type_uri,
features,
n_features)
: NULL;
if (!wrapper) {
SUIL_ERRORF("Corrupt module %s\n", path);
dlclose(lib);
free(path);
return NULL;
}
free(path);
wrapper->lib = lib;
return wrapper;
}
SUIL_API
SuilInstance*
suil_instance_new(SuilHost* host,
SuilController controller,
const char* container_type_uri,
const char* plugin_uri,
const char* ui_uri,
const char* ui_type_uri,
const char* ui_bundle_path,
const char* ui_binary_path,
const LV2_Feature* const* features)
{
// Open UI library
dlerror();
void* lib = dlopen(ui_binary_path, RTLD_NOW);
if (!lib) {
SUIL_ERRORF("Unable to open UI library %s (%s)\n",
ui_binary_path, dlerror());
return NULL;
}
// Get discovery function
LV2UI_DescriptorFunction df = (LV2UI_DescriptorFunction)
suil_dlfunc(lib, "lv2ui_descriptor");
if (!df) {
SUIL_ERRORF("Broken LV2 UI %s (no lv2ui_descriptor symbol found)\n",
ui_binary_path);
dlclose(lib);
return NULL;
}
// Get UI descriptor
const LV2UI_Descriptor* descriptor = NULL;
for (uint32_t i = 0; true; ++i) {
const LV2UI_Descriptor* ld = df(i);
if (!ld) {
break;
} else if (!strcmp(ld->URI, ui_uri)) {
descriptor = ld;
break;
}
}
if (!descriptor) {
SUIL_ERRORF("Failed to find descriptor for <%s> in %s\n",
ui_uri, ui_binary_path);
dlclose(lib);
return NULL;
}
// Create SuilInstance
SuilInstance* instance = (SuilInstance*)calloc(1, sizeof(SuilInstance));
if (!instance) {
SUIL_ERRORF("Failed to allocate memory for <%s> instance\n", ui_uri);
dlclose(lib);
return NULL;
}
instance->lib_handle = lib;
instance->descriptor = descriptor;
// Make UI features array
instance->features = (LV2_Feature**)malloc(sizeof(LV2_Feature**));
instance->features[0] = NULL;
// Copy user provided features
const LV2_Feature* const* fi = features;
unsigned n_features = 0;
while (fi && *fi) {
const LV2_Feature* f = *fi++;
suil_add_feature(&instance->features, &n_features, f->URI, f->data);
}
// Add additional features implemented by SuilHost functions
if (host->index_func) {
instance->port_map.handle = controller;
instance->port_map.port_index = host->index_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__portMap, &instance->port_map);
}
if (host->subscribe_func && host->unsubscribe_func) {
instance->port_subscribe.handle = controller;
instance->port_subscribe.subscribe = host->subscribe_func;
instance->port_subscribe.unsubscribe = host->unsubscribe_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__portSubscribe, &instance->port_subscribe);
}
if (host->touch_func) {
instance->touch.handle = controller;
instance->touch.touch = host->touch_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__touch, &instance->touch);
}
// Open wrapper (this may add additional features)
instance->wrapper = open_wrapper(
host, container_type_uri, ui_type_uri, &instance->features, n_features);
// Instantiate UI
instance->handle = descriptor->instantiate(
descriptor,
plugin_uri,
ui_bundle_path,
host->write_func,
controller,
&instance->ui_widget,
(const LV2_Feature* const*)instance->features);
// Failed to instantiate UI
if (!instance->handle) {
SUIL_ERRORF("Failed to instantiate UI <%s> in %s\n",
ui_uri, ui_binary_path);
suil_instance_free(instance);
return NULL;
}
if (instance->wrapper) {
if (instance->wrapper->wrap(instance->wrapper, instance)) {
SUIL_ERRORF("Failed to wrap UI <%s> in type <%s>\n",
ui_uri, container_type_uri);
suil_instance_free(instance);
return NULL;
}
} else {
instance->host_widget = instance->ui_widget;
}
return instance;
}
SUIL_API
void
suil_instance_free(SuilInstance* instance)
{
if (instance) {
for (unsigned i = 0; instance->features[i]; ++i) {
free(instance->features[i]);
}
free(instance->features);
// Call wrapper free function to destroy widgets and drop references
if (instance->wrapper && instance->wrapper->free) {
instance->wrapper->free(instance->wrapper);
}
// Call cleanup to destroy UI (if it still exists at this point)
if (instance->handle) {
instance->descriptor->cleanup(instance->handle);
}
// Close libraries and free everything
if (instance->wrapper) {
dlclose(instance->wrapper->lib);
free(instance->wrapper);
}
dlclose(instance->lib_handle);
free(instance);
}
}
SUIL_API
SuilHandle
suil_instance_get_handle(SuilInstance* instance)
{
return instance->handle;
}
SUIL_API
LV2UI_Widget
suil_instance_get_widget(SuilInstance* instance)
{
return instance->host_widget;
}
SUIL_API
void
suil_instance_port_event(SuilInstance* instance,
uint32_t port_index,
uint32_t buffer_size,
uint32_t format,
const void* buffer)
{
if (instance->descriptor->port_event) {
instance->descriptor->port_event(instance->handle,
port_index,
buffer_size,
format,
buffer);
}
}
SUIL_API
const void*
suil_instance_extension_data(SuilInstance* instance,
const char* uri)
{
if (instance->descriptor->extension_data) {
return instance->descriptor->extension_data(uri);
}
return NULL;
}

View File

@@ -0,0 +1,147 @@
/*
Copyright 2007-2012 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef SUIL_INTERNAL_H
#define SUIL_INTERNAL_H
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#define dlopen(path, flags) LoadLibrary(path)
#define dlclose(lib) FreeLibrary((HMODULE)lib)
#define inline __inline
#define snprintf _snprintf
static inline char* dlerror(void) { return "Unknown error"; }
#else
#include <dlfcn.h>
#endif
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
#include "suil/suil.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SUIL_ERRORF(fmt, ...) fprintf(stderr, "suil error: " fmt, __VA_ARGS__)
struct SuilHostImpl {
SuilPortWriteFunc write_func;
SuilPortIndexFunc index_func;
SuilPortSubscribeFunc subscribe_func;
SuilPortUnsubscribeFunc unsubscribe_func;
SuilTouchFunc touch_func;
void* gtk_lib;
};
struct _SuilWrapper;
typedef void (*SuilWrapperFreeFunc)(struct _SuilWrapper*);
typedef int (*SuilWrapperWrapFunc)(struct _SuilWrapper* wrapper,
SuilInstance* instance);
typedef struct _SuilWrapper {
SuilWrapperWrapFunc wrap;
SuilWrapperFreeFunc free;
void* lib;
void* impl;
LV2UI_Resize resize;
} SuilWrapper;
struct SuilInstanceImpl {
void* lib_handle;
const LV2UI_Descriptor* descriptor;
LV2UI_Handle handle;
SuilWrapper* wrapper;
LV2_Feature** features;
LV2UI_Port_Map port_map;
LV2UI_Port_Subscribe port_subscribe;
LV2UI_Touch touch;
SuilWidget ui_widget;
SuilWidget host_widget;
};
/**
The type of the suil_wrapper_new entry point in a wrapper module.
This constructs a SuilWrapper which contains everything necessary
to wrap a widget, including a possibly extended features array to
be used for instantiating the UI.
*/
typedef SuilWrapper* (*SuilWrapperNewFunc)(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features);
/** Prototype for suil_wrapper_new in each module. */
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features);
typedef void (*SuilVoidFunc)(void);
/** dlsym wrapper to return a function pointer (without annoying warning) */
static inline SuilVoidFunc
suil_dlfunc(void* handle, const char* symbol)
{
#ifdef _WIN32
return (SuilVoidFunc)GetProcAddress((HMODULE)handle, symbol);
#else
typedef SuilVoidFunc (*VoidFuncGetter)(void*, const char*);
VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
return dlfunc(handle, symbol);
#endif
}
/** Add a feature to a (mutable) LV2 feature array. */
static inline void
suil_add_feature(LV2_Feature*** features,
unsigned* n,
const char* uri,
void* data)
{
for (unsigned i = 0; i < *n && (*features)[i]; ++i) {
if (!strcmp((*features)[i]->URI, uri)) {
(*features)[i]->data = data;
return;
}
}
*features = (LV2_Feature**)realloc(*features,
sizeof(LV2_Feature*) * (*n + 2));
(*features)[*n] = (LV2_Feature*)malloc(sizeof(LV2_Feature));
(*features)[*n]->URI = uri;
(*features)[*n]->data = data;
(*features)[*n + 1] = NULL;
*n += 1;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // SUIL_INTERNAL_H

View File

@@ -0,0 +1,165 @@
/*
Copyright 2011-2012 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkwin32.h>
#include "./suil_internal.h"
extern "C" {
#define SUIL_TYPE_WIN_WRAPPER (suil_win_wrapper_get_type())
#define SUIL_WIN_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_WIN_WRAPPER, SuilWinWrapper))
typedef struct _SuilWinWrapper SuilWinWrapper;
typedef struct _SuilWinWrapperClass SuilWinWrapperClass;
struct _SuilWinWrapper {
GtkDrawingArea area;
SuilWrapper* wrapper;
SuilInstance* instance;
};
struct _SuilWinWrapperClass {
GtkDrawingAreaClass parent_class;
};
GType suil_win_wrapper_get_type(void); // Accessor for SUIL_TYPE_WIN_WRAPPER
G_DEFINE_TYPE(SuilWinWrapper, suil_win_wrapper, GTK_TYPE_DRAWING_AREA)
static void
suil_win_wrapper_finalize(GObject* gobject)
{
SuilWinWrapper* const self = SUIL_WIN_WRAPPER(gobject);
self->wrapper->impl = NULL;
G_OBJECT_CLASS(suil_win_wrapper_parent_class)->finalize(gobject);
}
static void
suil_win_wrapper_class_init(SuilWinWrapperClass* klass)
{
GObjectClass* const gobject_class = G_OBJECT_CLASS(klass);
gobject_class->finalize = suil_win_wrapper_finalize;
}
static void
suil_win_wrapper_init(SuilWinWrapper* self)
{
self->instance = NULL;
}
static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
gtk_drawing_area_size(GTK_DRAWING_AREA(handle), width, height);
return 0;
}
static int
wrapper_wrap(SuilWrapper* wrapper,
SuilInstance* instance)
{
SuilWinWrapper* const wrap = SUIL_WIN_WRAPPER(wrapper->impl);
instance->host_widget = GTK_WIDGET(wrap);
wrap->wrapper = wrapper;
wrap->instance = instance;
return 0;
}
static void
wrapper_free(SuilWrapper* wrapper)
{
if (wrapper->impl) {
SuilWinWrapper* const wrap = SUIL_WIN_WRAPPER(wrapper->impl);
gtk_object_destroy(GTK_OBJECT(wrap));
}
}
static GdkFilterReturn
event_filter(GdkXEvent* xevent, GdkEvent* event, gpointer data)
{
SuilWinWrapper* wrap = (SuilWinWrapper*)data;
MSG* msg = (MSG*)xevent;
if (msg->message == WM_KEYDOWN || msg->message == WM_KEYUP) {
// Forward keyboard events to UI window
PostMessage((HWND)wrap->instance->ui_widget,
msg->message, msg->wParam, msg->lParam);
}
return GDK_FILTER_CONTINUE;
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
GtkWidget* parent = NULL;
for (unsigned i = 0; i < n_features; ++i) {
if (!strcmp((*features)[i]->URI, LV2_UI__parent)) {
parent = (GtkWidget*)(*features)[i]->data;
}
}
if (!GTK_CONTAINER(parent)) {
SUIL_ERRORF("No GtkContainer parent given for %s UI\n",
ui_type_uri);
return NULL;
}
SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
SuilWinWrapper* const wrap = SUIL_WIN_WRAPPER(
g_object_new(SUIL_TYPE_WIN_WRAPPER, NULL));
wrap->wrapper = NULL;
wrapper->impl = wrap;
wrapper->resize.handle = wrap;
wrapper->resize.ui_resize = wrapper_resize;
gtk_container_add(GTK_CONTAINER(parent), GTK_WIDGET(wrap));
gtk_widget_set_can_focus(GTK_WIDGET(wrap), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(wrap), TRUE);
gtk_widget_realize(GTK_WIDGET(wrap));
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(wrap));
GdkWindow* parent_window = gtk_widget_get_window(parent);
gdk_window_add_filter(parent_window, event_filter, wrap);
gdk_window_add_filter(window, event_filter, wrap);
suil_add_feature(features, &n_features, LV2_UI__parent,
GDK_WINDOW_HWND(window));
suil_add_feature(features, &n_features, LV2_UI__resize,
&wrapper->resize);
return wrapper;
}
} // extern "C"

View File

@@ -0,0 +1,349 @@
/*
Copyright 2011-2013 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "./suil_internal.h"
#ifdef HAVE_LV2_1_6_0
# include "lv2/lv2plug.in/ns/ext/options/options.h"
# include "lv2/lv2plug.in/ns/ext/urid/urid.h"
#endif
#define SUIL_TYPE_X11_WRAPPER (suil_x11_wrapper_get_type())
#define SUIL_X11_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_X11_WRAPPER, SuilX11Wrapper))
typedef struct _SuilX11Wrapper SuilX11Wrapper;
typedef struct _SuilX11WrapperClass SuilX11WrapperClass;
struct _SuilX11Wrapper {
GtkSocket socket;
GtkPlug* plug;
SuilWrapper* wrapper;
SuilInstance* instance;
#ifdef HAVE_LV2_1_6_0
const LV2UI_Idle_Interface* idle_iface;
guint idle_id;
guint idle_ms;
#endif
};
struct _SuilX11WrapperClass {
GtkSocketClass parent_class;
};
GType suil_x11_wrapper_get_type(void); // Accessor for SUIL_TYPE_X11_WRAPPER
G_DEFINE_TYPE(SuilX11Wrapper, suil_x11_wrapper, GTK_TYPE_SOCKET)
/**
Check if 'swallowed' subwindow is known to the X server.
Gdk/GTK can mark the window as realized, mapped and visible even though
there is no window-ID on the X server for it yet. Then,
suil_x11_on_size_allocate() will cause a "BadWinow" X error.
*/
static bool
x_window_is_valid(SuilX11Wrapper* socket)
{
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(socket->plug));
Window root = 0;
Window parent = 0;
Window* children = NULL;
unsigned childcount = 0;
XQueryTree(GDK_WINDOW_XDISPLAY(window),
GDK_WINDOW_XID(window),
&root, &parent, &children, &childcount);
for (unsigned i = 0; i < childcount; ++i) {
if (children[i] == (Window)socket->instance->ui_widget) {
return true;
}
}
return false;
}
static gboolean
on_plug_removed(GtkSocket* sock, gpointer data)
{
SuilX11Wrapper* const self = SUIL_X11_WRAPPER(sock);
#ifdef HAVE_LV2_1_6_0
if (self->idle_id) {
g_source_remove(self->idle_id);
self->idle_id = 0;
}
#endif
if (self->instance->handle) {
self->instance->descriptor->cleanup(self->instance->handle);
self->instance->handle = NULL;
}
self->plug = NULL;
return TRUE;
}
static void
suil_x11_wrapper_finalize(GObject* gobject)
{
SuilX11Wrapper* const self = SUIL_X11_WRAPPER(gobject);
self->wrapper->impl = NULL;
G_OBJECT_CLASS(suil_x11_wrapper_parent_class)->finalize(gobject);
}
static void
suil_x11_wrapper_realize(GtkWidget* w)
{
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(w);
GtkSocket* const socket = GTK_SOCKET(w);
if (GTK_WIDGET_CLASS(suil_x11_wrapper_parent_class)->realize) {
GTK_WIDGET_CLASS(suil_x11_wrapper_parent_class)->realize(w);
}
gtk_socket_add_id(socket, gtk_plug_get_id(wrap->plug));
gtk_widget_set_sensitive(GTK_WIDGET(wrap->plug), TRUE);
gtk_widget_set_can_focus(GTK_WIDGET(wrap->plug), TRUE);
gtk_widget_grab_focus(GTK_WIDGET(wrap->plug));
}
static void
suil_x11_wrapper_show(GtkWidget* w)
{
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(w);
if (GTK_WIDGET_CLASS(suil_x11_wrapper_parent_class)->show) {
GTK_WIDGET_CLASS(suil_x11_wrapper_parent_class)->show(w);
}
gtk_widget_show(GTK_WIDGET(wrap->plug));
}
static void
forward_key_event(SuilX11Wrapper* socket,
GdkEvent* gdk_event)
{
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(socket->plug));
GdkScreen* screen = gdk_visual_get_screen(gdk_window_get_visual(window));
XKeyEvent xev;
memset(&xev, 0, sizeof(xev));
xev.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
xev.root = GDK_WINDOW_XID(gdk_screen_get_root_window(screen));
xev.window = GDK_WINDOW_XID(window);
xev.subwindow = None;
xev.time = gdk_event->key.time;
xev.state = gdk_event->key.state;
xev.keycode = gdk_event->key.hardware_keycode;
XSendEvent(GDK_WINDOW_XDISPLAY(window),
(Window)socket->instance->ui_widget,
False,
NoEventMask,
(XEvent*)&xev);
}
static void
forward_size_request(SuilX11Wrapper* socket,
GtkAllocation* allocation)
{
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(socket->plug));
if (x_window_is_valid(socket)) {
XResizeWindow(GDK_WINDOW_XDISPLAY(window),
(Window) socket->instance->ui_widget,
allocation->width, allocation->height);
}
}
static gboolean
suil_x11_wrapper_key_event(GtkWidget* widget,
GdkEventKey* event)
{
SuilX11Wrapper* const self = SUIL_X11_WRAPPER(widget);
if (self->plug) {
forward_key_event(self, (GdkEvent*)event);
return TRUE;
}
return FALSE;
}
static void
suil_x11_on_size_allocate(GtkWidget* widget,
GtkAllocation* a)
{
SuilX11Wrapper* const self = SUIL_X11_WRAPPER(widget);
if (self->plug
&& GTK_WIDGET_REALIZED(widget)
&& GTK_WIDGET_MAPPED(widget)
&& GTK_WIDGET_VISIBLE(widget)) {
forward_size_request(self, a);
}
}
static void
suil_x11_wrapper_class_init(SuilX11WrapperClass* klass)
{
GObjectClass* const gobject_class = G_OBJECT_CLASS(klass);
GtkWidgetClass* const widget_class = GTK_WIDGET_CLASS(klass);
gobject_class->finalize = suil_x11_wrapper_finalize;
widget_class->realize = suil_x11_wrapper_realize;
widget_class->show = suil_x11_wrapper_show;
widget_class->key_press_event = suil_x11_wrapper_key_event;
}
static void
suil_x11_wrapper_init(SuilX11Wrapper* self)
{
self->plug = GTK_PLUG(gtk_plug_new(0));
self->wrapper = NULL;
self->instance = NULL;
#ifdef HAVE_LV2_1_6_0
self->idle_iface = NULL;
self->idle_ms = 1000 / 30; // 30 Hz default
#endif
}
static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
gtk_widget_set_size_request(GTK_WIDGET(handle), width, height);
return 0;
}
#ifdef HAVE_LV2_1_6_0
static gboolean
suil_x11_wrapper_idle(void* data)
{
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(data);
wrap->idle_iface->idle(wrap->instance->handle);
return TRUE; // Continue calling
}
#endif
static int
wrapper_wrap(SuilWrapper* wrapper,
SuilInstance* instance)
{
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(wrapper->impl);
instance->host_widget = GTK_WIDGET(wrap);
wrap->wrapper = wrapper;
wrap->instance = instance;
#ifdef HAVE_LV2_1_6_0
const LV2UI_Idle_Interface* idle_iface = NULL;
if (instance->descriptor->extension_data) {
idle_iface = (const LV2UI_Idle_Interface*)
instance->descriptor->extension_data(LV2_UI__idleInterface);
}
if (idle_iface) {
wrap->idle_iface = idle_iface;
wrap->idle_id = g_timeout_add(
wrap->idle_ms, suil_x11_wrapper_idle, wrap);
}
#endif
g_signal_connect(G_OBJECT(wrap),
"plug-removed",
G_CALLBACK(on_plug_removed),
NULL);
g_signal_connect(G_OBJECT(wrap),
"size-allocate",
G_CALLBACK(suil_x11_on_size_allocate),
NULL);
return 0;
}
static void
wrapper_free(SuilWrapper* wrapper)
{
if (wrapper->impl) {
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(wrapper->impl);
gtk_object_destroy(GTK_OBJECT(wrap));
}
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(
g_object_new(SUIL_TYPE_X11_WRAPPER, NULL));
wrapper->impl = wrap;
wrapper->resize.handle = wrap;
wrapper->resize.ui_resize = wrapper_resize;
gtk_widget_set_sensitive(GTK_WIDGET(wrap), TRUE);
gtk_widget_set_can_focus(GTK_WIDGET(wrap), TRUE);
suil_add_feature(features, &n_features, LV2_UI__parent,
(void*)(intptr_t)gtk_plug_get_id(wrap->plug));
suil_add_feature(features, &n_features, LV2_UI__resize,
&wrapper->resize);
#ifdef HAVE_LV2_1_6_0
suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL);
// Scan for URID map and options
LV2_URID_Map* map = NULL;
LV2_Options_Option* options = NULL;
for (LV2_Feature** f = *features; *f && (!map || !options); ++f) {
if (!strcmp((*f)->URI, LV2_OPTIONS__options)) {
options = (*f)->data;
} else if (!strcmp((*f)->URI, LV2_URID__map)) {
map = (*f)->data;
}
}
if (map && options) {
// Set UI update rate if given
LV2_URID ui_updateRate = map->map(map->handle, LV2_UI__updateRate);
for (LV2_Options_Option* o = options; o->key; ++o) {
if (o->key == ui_updateRate) {
wrap->idle_ms = 1000.0f / *(const float*)o->value;
break;
}
}
}
#endif
return wrapper;
}

View File

@@ -0,0 +1,156 @@
/*
Copyright 2011-2013 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <QX11EmbedContainer>
#include <QtEvents>
#undef signals
#include "./suil_config.h"
#include "./suil_internal.h"
#ifndef HAVE_LV2_1_6_0
typedef struct _LV2UI_Idle_Interface LV2UI_Idle_Interface;
#endif
extern "C" {
typedef struct {
QX11EmbedContainer* host_widget;
QX11EmbedWidget* parent;
} SuilX11InQt4Wrapper;
class SuilQX11Container : public QX11EmbedContainer
{
public:
SuilQX11Container(SuilInstance* instance,
const LV2UI_Idle_Interface* idle_iface,
QX11EmbedWidget* widget)
: QX11EmbedContainer()
, _instance(instance)
, _idle_iface(idle_iface)
, _widget(widget)
, _ui_timer(0)
{}
#ifdef HAVE_LV2_1_6_0
void showEvent(QShowEvent* event) {
if (_idle_iface && _ui_timer == 0) {
_ui_timer = this->startTimer(30);
_widget->embedInto(winId());
resize(_widget->size());
}
QX11EmbedContainer::showEvent(event);
}
void timerEvent(QTimerEvent* event) {
if (event->timerId() == _ui_timer && _idle_iface) {
_idle_iface->idle(_instance->handle);
}
QX11EmbedContainer::timerEvent(event);
}
#endif
SuilInstance* const _instance;
const LV2UI_Idle_Interface* const _idle_iface;
QX11EmbedWidget* const _widget;
int _ui_timer;
};
static void
wrapper_free(SuilWrapper* wrapper)
{
SuilX11InQt4Wrapper* impl = (SuilX11InQt4Wrapper*)wrapper->impl;
if (impl->parent) {
delete impl->parent;
}
if (impl->host_widget) {
delete impl->host_widget;
}
free(impl);
}
static int
wrapper_wrap(SuilWrapper* wrapper,
SuilInstance* instance)
{
const LV2UI_Idle_Interface* idle_iface = NULL;
#ifdef HAVE_LV2_1_6_0
if (instance->descriptor->extension_data) {
idle_iface = (const LV2UI_Idle_Interface*)
instance->descriptor->extension_data(LV2_UI__idleInterface);
}
#endif
SuilX11InQt4Wrapper* const impl = (SuilX11InQt4Wrapper*)wrapper->impl;
QX11EmbedWidget* const ew = impl->parent;
impl->host_widget = new SuilQX11Container(instance, idle_iface, ew);
instance->host_widget = impl->host_widget;
return 0;
}
static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
QX11EmbedWidget* const ew = (QX11EmbedWidget*)handle;
ew->resize(width, height);
return 0;
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
SuilX11InQt4Wrapper* const impl = (SuilX11InQt4Wrapper*)
malloc(sizeof(SuilX11InQt4Wrapper));
impl->host_widget = NULL;
impl->parent = NULL;
SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
QX11EmbedWidget* const ew = new QX11EmbedWidget();
impl->parent = ew;
wrapper->impl = impl;
wrapper->resize.handle = ew;
wrapper->resize.ui_resize = wrapper_resize;
suil_add_feature(features, &n_features, LV2_UI__parent,
(void*)(intptr_t)ew->winId());
suil_add_feature(features, &n_features, LV2_UI__resize,
&wrapper->resize);
#ifdef HAVE_LV2_1_6_0
suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL);
#endif
return wrapper;
}
} // extern "C"