diff options
-rw-r--r-- | src/qt5_in_gtk2.cpp | 207 |
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" |