summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--src/instance.c19
-rw-r--r--src/win_in_gtk2.c161
-rw-r--r--wscript17
4 files changed, 191 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 3bedd7e..567c686 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
suil (9999) unstable;
+ * Support for wrapping native Windows UIs in Gtk2
* Gracefully handle UIs with no port_event method
* Replace host provided features that match Suil implemented features, rather
than passing UIs duplicate features
diff --git a/src/instance.c b/src/instance.c
index 5b53328..951b12f 100644
--- a/src/instance.c
+++ b/src/instance.c
@@ -26,6 +26,7 @@
#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
@@ -45,6 +46,8 @@ suil_ui_supported(const char* container_type_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;
@@ -67,16 +70,19 @@ open_wrapper(SuilHost* host,
const char* module_name = NULL;
if (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, GTK2_UI_URI)) {
- module_name = "libsuil_gtk2_in_qt4";
+ module_name = "suil_gtk2_in_qt4";
} else if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, QT4_UI_URI)) {
- module_name = "libsuil_qt4_in_gtk2";
+ module_name = "suil_qt4_in_gtk2";
} else if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
- module_name = "libsuil_x11_in_gtk2";
+ 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 = "libsuil_x11_in_qt4";
+ module_name = "suil_x11_in_qt4";
}
if (!module_name) {
@@ -94,8 +100,9 @@ open_wrapper(SuilHost* host,
+ 2;
char* const path = calloc(path_len, 1);
- snprintf(path, path_len, "%s%s%s%s",
- mod_dir, SUIL_DIR_SEP, module_name, SUIL_MODULE_EXT);
+ 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();
diff --git a/src/win_in_gtk2.c b/src/win_in_gtk2.c
new file mode 100644
index 0000000..8367996
--- /dev/null
+++ b/src/win_in_gtk2.c
@@ -0,0 +1,161 @@
+/*
+ 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"
+
+#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;
+}
+
+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;
+}
+
+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));
+ }
+}
+
+SUIL_API
+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;
+}
diff --git a/wscript b/wscript
index 2b873dd..78b98af 100644
--- a/wscript
+++ b/wscript
@@ -65,8 +65,13 @@ def configure(conf):
autowaf.define(conf, 'SUIL_MODULE_DIR',
conf.env['LIBDIR'] + '/suil-' + SUIL_MAJOR_VERSION)
autowaf.define(conf, 'SUIL_DIR_SEP', '/')
- autowaf.define(conf, 'SUIL_MODULE_EXT', '.so')
autowaf.define(conf, 'SUIL_GTK2_LIB_NAME', Options.options.gtk2_lib_name);
+ if Options.platform == 'win32':
+ autowaf.define(conf, 'SUIL_MODULE_PREFIX', '')
+ autowaf.define(conf, 'SUIL_MODULE_EXT', '.dll')
+ else:
+ autowaf.define(conf, 'SUIL_MODULE_PREFIX', 'lib')
+ autowaf.define(conf, 'SUIL_MODULE_EXT', '.so')
conf.env['LIB_SUIL'] = ['suil-%s' % SUIL_MAJOR_VERSION]
@@ -138,6 +143,16 @@ def build(bld):
linkflags = bld.env['NODELETE_FLAGS'])
autowaf.use_lib(bld, obj, 'GTK2 LV2')
+ if sys.platform == 'win32':
+ obj = bld(features = 'cxx cxxshlib',
+ source = 'src/win_in_gtk2.c',
+ target = 'suil_win_in_gtk2',
+ includes = ['.'],
+ install_path = module_dir,
+ cflags = cflags,
+ linkflags = bld.env['NODELETE_FLAGS'])
+ autowaf.use_lib(bld, obj, 'GTK2 LV2')
+
if bld.is_defined('HAVE_QT4'):
obj = bld(features = 'cxx cxxshlib',
source = 'src/x11_in_qt4.cpp',