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:
150
lib-src/lv2/suil/src/gtk2_in_qt4.cpp
Normal file
150
lib-src/lv2/suil/src/gtk2_in_qt4.cpp
Normal 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"
|
||||
54
lib-src/lv2/suil/src/host.c
Normal file
54
lib-src/lv2/suil/src/host.c
Normal 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);
|
||||
}
|
||||
}
|
||||
1
lib-src/lv2/suil/src/instance.c
Symbolic link
1
lib-src/lv2/suil/src/instance.c
Symbolic link
@@ -0,0 +1 @@
|
||||
suil_instance.c
|
||||
160
lib-src/lv2/suil/src/qt4_in_gtk2.cpp
Normal file
160
lib-src/lv2/suil/src/qt4_in_gtk2.cpp
Normal 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"
|
||||
338
lib-src/lv2/suil/src/suil_instance.c
Normal file
338
lib-src/lv2/suil/src/suil_instance.c
Normal 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;
|
||||
}
|
||||
147
lib-src/lv2/suil/src/suil_internal.h
Normal file
147
lib-src/lv2/suil/src/suil_internal.h
Normal 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
|
||||
165
lib-src/lv2/suil/src/win_in_gtk2.cpp
Normal file
165
lib-src/lv2/suil/src/win_in_gtk2.cpp
Normal 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"
|
||||
349
lib-src/lv2/suil/src/x11_in_gtk2.c
Normal file
349
lib-src/lv2/suil/src/x11_in_gtk2.c
Normal 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;
|
||||
}
|
||||
156
lib-src/lv2/suil/src/x11_in_qt4.cpp
Normal file
156
lib-src/lv2/suil/src/x11_in_qt4.cpp
Normal 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"
|
||||
Reference in New Issue
Block a user