summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qt5_in_gtk2.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/qt5_in_gtk2.cpp b/src/qt5_in_gtk2.cpp
new file mode 100644
index 0000000..48704c9
--- /dev/null
+++ b/src/qt5_in_gtk2.cpp
@@ -0,0 +1,207 @@
+/*
+ Copyright 2011-2017 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 <QMouseEvent>
+#include <QVBoxLayout>
+#include <QWidget>
+#include <QWindow>
+#include <QX11Info>
+#include <X11/Xlib.h>
+
+#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;
+
+class EmbedWidget : public QWidget
+{
+public:
+ EmbedWidget()
+ : QWidget()
+ , display(QX11Info::display())
+ , wid(winId())
+ {}
+
+ WId id() const { return wid; }
+
+protected:
+ bool eventFilter(QObject*, QEvent* ev) {
+ if (wid == 0 || !display) {
+ return false;
+ }
+
+ if (ev->type() == QEvent::Enter ||
+ ev->type() == QEvent::WindowActivate) {
+ const Window root = XRootWindow(display, 0);
+ int x, y;
+ Window child;
+ XTranslateCoordinates(display, wid, root, 0, 0, &x, &y, &child);
+
+ XWindowAttributes attrs;
+ XGetWindowAttributes(display, wid, &attrs);
+
+ const QPoint p = QPoint(x - attrs.x, y - attrs.y);
+ if (p != pos) {
+ pos = p;
+ move(pos);
+ XMoveWindow(display, wid, 0, 0);
+ }
+ }
+
+ return false;
+ }
+
+private:
+ Display* display;
+ QPoint pos;
+ WId wid;
+};
+
+struct _SuilQtWrapper
+{
+ GtkSocket socket;
+ QApplication* app;
+ EmbedWidget* 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->id());
+ wrap->qembed->show();
+}
+
+static int
+wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance)
+{
+ SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(wrapper->impl);
+
+ wrap->qembed = new EmbedWidget();
+ wrap->wrapper = wrapper;
+ wrap->instance = instance;
+
+ wrap->qembed->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+
+ QWidget* qwidget = (QWidget*)instance->ui_widget;
+ QVBoxLayout* layout = new QVBoxLayout(wrap->qembed);
+ layout->addWidget(qwidget);
+
+ qwidget->installEventFilter(wrap->qembed);
+ 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*)calloc(1, sizeof(SuilWrapper));
+ wrapper->wrap = wrapper_wrap;
+ wrapper->free = wrapper_free;
+
+ 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"