From 35804e3346e687f01cbdd22738a46af6a38b43da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Mon, 8 Jul 2024 05:17:23 -0400 Subject: Add support for X11 in Qt6 --- src/instance.c | 10 ++- src/x11_in_qt.cpp | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/x11_in_qt5.cpp | 224 ------------------------------------------------- 3 files changed, 250 insertions(+), 225 deletions(-) create mode 100644 src/x11_in_qt.cpp delete mode 100644 src/x11_in_qt5.cpp (limited to 'src') diff --git a/src/instance.c b/src/instance.c index 441176c..496155c 100644 --- a/src/instance.c +++ b/src/instance.c @@ -17,6 +17,7 @@ #define GTK2_UI_URI LV2_UI__GtkUI #define GTK3_UI_URI LV2_UI__Gtk3UI #define QT5_UI_URI LV2_UI__Qt5UI +#define QT6_UI_URI LV2_UI_PREFIX "Qt6UI" #define X11_UI_URI LV2_UI__X11UI #define WIN_UI_URI LV2_UI_PREFIX "WindowsUI" #define COCOA_UI_URI LV2_UI__CocoaUI @@ -43,7 +44,9 @@ suil_ui_supported(const char* host_type_uri, const char* ui_type_uri) !strcmp(ui_type_uri, X11_UI_URI)) || (!strcmp(host_type_uri, QT5_UI_URI) && (!strcmp(ui_type_uri, COCOA_UI_URI) || - !strcmp(ui_type_uri, X11_UI_URI)))) { + !strcmp(ui_type_uri, X11_UI_URI))) || + (!strcmp(host_type_uri, QT6_UI_URI) && + (!strcmp(ui_type_uri, X11_UI_URI)))) { return SUIL_WRAPPING_EMBEDDED; } @@ -84,6 +87,11 @@ open_wrapper(SuilHost* host, module_name = "suil_x11_in_qt5"; } + if (!strcmp(container_type_uri, QT6_UI_URI) && + !strcmp(ui_type_uri, X11_UI_URI)) { + module_name = "suil_x11_in_qt6"; + } + if (!strcmp(container_type_uri, QT5_UI_URI) && !strcmp(ui_type_uri, COCOA_UI_URI)) { module_name = "suil_cocoa_in_qt5"; diff --git a/src/x11_in_qt.cpp b/src/x11_in_qt.cpp new file mode 100644 index 0000000..fcf96ab --- /dev/null +++ b/src/x11_in_qt.cpp @@ -0,0 +1,241 @@ +// Copyright 2011-2022 David Robillard +// Copyright 2015 Rui Nuno Capela +// SPDX-License-Identifier: ISC + +#include "suil_internal.h" +#include "warnings.h" + +#include "lv2/core/lv2.h" +#include "lv2/ui/ui.h" +#include "suil/suil.h" + +SUIL_DISABLE_QT_WARNINGS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +# include +#else +# include +#endif +SUIL_RESTORE_WARNINGS + +// IWYU pragma: no_include + +#include + +#undef signals + +namespace { + +inline Display* +getX11Display() +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + return QX11Info::display(); +#else + return qApp->nativeInterface()->display(); +#endif +} + +class SuilQX11Widget : public QWidget +{ +public: + SuilQX11Widget(QWidget* parent, Qt::WindowFlags wflags) + : QWidget(parent, wflags) + {} + + SuilQX11Widget(const SuilQX11Widget&) = delete; + SuilQX11Widget& operator=(const SuilQX11Widget&) = delete; + + SuilQX11Widget(SuilQX11Widget&&) = delete; + SuilQX11Widget& operator=(SuilQX11Widget&&) = delete; + + ~SuilQX11Widget() override; + + void start_idle(SuilInstance* instance, + const LV2UI_Idle_Interface* idle_iface) + { + _instance = instance; + _idle_iface = idle_iface; + if (_idle_iface && _ui_timer == 0) { + _ui_timer = this->startTimer(30, Qt::CoarseTimer); + } + } + + void set_window(Window window) { _window = window; } + + QSize sizeHint() const override + { + if (_window) { + XWindowAttributes attrs{}; + XGetWindowAttributes(getX11Display(), _window, &attrs); + return {attrs.width, attrs.height}; + } + + return {0, 0}; + } + + QSize minimumSizeHint() const override + { + if (_window) { + XSizeHints hints{}; + long supplied{}; + XGetWMNormalHints(getX11Display(), _window, &hints, &supplied); + if ((hints.flags & PMinSize)) { + return {hints.min_width, hints.min_height}; + } + } + + return {0, 0}; + } + +protected: + void resizeEvent(QResizeEvent* event) override + { + QWidget::resizeEvent(event); + + if (_window) { + XResizeWindow(getX11Display(), + _window, + static_cast(event->size().width()), + static_cast(event->size().height())); + } + } + + void timerEvent(QTimerEvent* event) override + { + if (event->timerId() == _ui_timer && _idle_iface) { + _idle_iface->idle(_instance->handle); + } + + QWidget::timerEvent(event); + } + + void closeEvent(QCloseEvent* event) override + { + if (_ui_timer && _idle_iface) { + this->killTimer(_ui_timer); + _ui_timer = 0; + } + + QWidget::closeEvent(event); + } + +private: + SuilInstance* _instance{}; + const LV2UI_Idle_Interface* _idle_iface{}; + Window _window{}; + int _ui_timer{}; +}; + +SuilQX11Widget::~SuilQX11Widget() = default; + +struct SuilX11InQt5Wrapper { + QWidget* host_widget; + SuilQX11Widget* parent; +}; + +void +wrapper_free(SuilWrapper* wrapper) +{ + auto* impl = static_cast(wrapper->impl); + + delete impl->host_widget; + + free(impl); +} + +int +wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) +{ + auto* const impl = static_cast(wrapper->impl); + + SuilQX11Widget* const ew = impl->parent; + Display* const display = getX11Display(); + const auto window = reinterpret_cast(instance->ui_widget); + + XWindowAttributes attrs{}; + XSizeHints hints{}; + long supplied{}; + XSync(display, False); + XGetWindowAttributes(display, window, &attrs); + XGetWMNormalHints(display, window, &hints, &supplied); + + impl->parent->set_window(window); + + if ((hints.flags & PBaseSize)) { + impl->parent->setBaseSize(hints.base_width, hints.base_height); + } + + if ((hints.flags & PMinSize)) { + impl->parent->setMinimumSize(hints.min_width, hints.min_height); + } + + if ((hints.flags & PMaxSize)) { + impl->parent->setMaximumSize(hints.max_width, hints.max_height); + } + + if (instance->descriptor->extension_data) { + const auto* idle_iface = static_cast( + instance->descriptor->extension_data(LV2_UI__idleInterface)); + + ew->start_idle(instance, idle_iface); + } + + impl->host_widget = ew; + instance->host_widget = impl->host_widget; + + return 0; +} + +int +wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) +{ + auto* const ew = static_cast(handle); + ew->resize(width, height); + return 0; +} + +} // namespace + +extern "C" { + +SUIL_LIB_EXPORT +SuilWrapper* +suil_wrapper_new(SuilHost*, + const char*, + const char*, + LV2_Feature*** features, + unsigned n_features) +{ + auto* const impl = + static_cast(calloc(1, sizeof(SuilX11InQt5Wrapper))); + + auto* wrapper = static_cast(malloc(sizeof(SuilWrapper))); + wrapper->wrap = wrapper_wrap; + wrapper->free = wrapper_free; + + auto* const ew = new SuilQX11Widget(nullptr, Qt::Window); + + impl->parent = ew; + + wrapper->impl = impl; + wrapper->resize.handle = ew; + wrapper->resize.ui_resize = wrapper_resize; + + void* parent_id = reinterpret_cast(ew->winId()); + suil_add_feature(features, &n_features, LV2_UI__parent, parent_id); + suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize); + suil_add_feature(features, &n_features, LV2_UI__idleInterface, nullptr); + + return wrapper; +} + +} // extern "C" diff --git a/src/x11_in_qt5.cpp b/src/x11_in_qt5.cpp deleted file mode 100644 index 7e3d6ac..0000000 --- a/src/x11_in_qt5.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2011-2022 David Robillard -// Copyright 2015 Rui Nuno Capela -// SPDX-License-Identifier: ISC - -#include "suil_internal.h" -#include "warnings.h" - -#include "lv2/core/lv2.h" -#include "lv2/ui/ui.h" -#include "suil/suil.h" - -SUIL_DISABLE_QT_WARNINGS -#include -#include -#include -#include -#include -#include -#include -#include -#include -SUIL_RESTORE_WARNINGS - -#include - -#undef signals - -namespace { - -class SuilQX11Widget : public QWidget -{ -public: - SuilQX11Widget(QWidget* parent, Qt::WindowFlags wflags) - : QWidget(parent, wflags) - {} - - SuilQX11Widget(const SuilQX11Widget&) = delete; - SuilQX11Widget& operator=(const SuilQX11Widget&) = delete; - - SuilQX11Widget(SuilQX11Widget&&) = delete; - SuilQX11Widget& operator=(SuilQX11Widget&&) = delete; - - ~SuilQX11Widget() override; - - void start_idle(SuilInstance* instance, - const LV2UI_Idle_Interface* idle_iface) - { - _instance = instance; - _idle_iface = idle_iface; - if (_idle_iface && _ui_timer == 0) { - _ui_timer = this->startTimer(30, Qt::CoarseTimer); - } - } - - void set_window(Window window) { _window = window; } - - QSize sizeHint() const override - { - if (_window) { - XWindowAttributes attrs{}; - XGetWindowAttributes(QX11Info::display(), _window, &attrs); - return {attrs.width, attrs.height}; - } - - return {0, 0}; - } - - QSize minimumSizeHint() const override - { - if (_window) { - XSizeHints hints{}; - long supplied{}; - XGetWMNormalHints(QX11Info::display(), _window, &hints, &supplied); - if ((hints.flags & PMinSize)) { - return {hints.min_width, hints.min_height}; - } - } - - return {0, 0}; - } - -protected: - void resizeEvent(QResizeEvent* event) override - { - QWidget::resizeEvent(event); - - if (_window) { - XResizeWindow(QX11Info::display(), - _window, - static_cast(event->size().width()), - static_cast(event->size().height())); - } - } - - void timerEvent(QTimerEvent* event) override - { - if (event->timerId() == _ui_timer && _idle_iface) { - _idle_iface->idle(_instance->handle); - } - - QWidget::timerEvent(event); - } - - void closeEvent(QCloseEvent* event) override - { - if (_ui_timer && _idle_iface) { - this->killTimer(_ui_timer); - _ui_timer = 0; - } - - QWidget::closeEvent(event); - } - -private: - SuilInstance* _instance{}; - const LV2UI_Idle_Interface* _idle_iface{}; - Window _window{}; - int _ui_timer{}; -}; - -SuilQX11Widget::~SuilQX11Widget() = default; - -struct SuilX11InQt5Wrapper { - QWidget* host_widget; - SuilQX11Widget* parent; -}; - -void -wrapper_free(SuilWrapper* wrapper) -{ - auto* impl = static_cast(wrapper->impl); - - delete impl->host_widget; - - free(impl); -} - -int -wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) -{ - auto* const impl = static_cast(wrapper->impl); - - SuilQX11Widget* const ew = impl->parent; - Display* const display = QX11Info::display(); - const auto window = reinterpret_cast(instance->ui_widget); - - XWindowAttributes attrs{}; - XSizeHints hints{}; - long supplied{}; - XSync(display, False); - XGetWindowAttributes(display, window, &attrs); - XGetWMNormalHints(display, window, &hints, &supplied); - - impl->parent->set_window(window); - - if ((hints.flags & PBaseSize)) { - impl->parent->setBaseSize(hints.base_width, hints.base_height); - } - - if ((hints.flags & PMinSize)) { - impl->parent->setMinimumSize(hints.min_width, hints.min_height); - } - - if ((hints.flags & PMaxSize)) { - impl->parent->setMaximumSize(hints.max_width, hints.max_height); - } - - if (instance->descriptor->extension_data) { - const auto* idle_iface = static_cast( - instance->descriptor->extension_data(LV2_UI__idleInterface)); - - ew->start_idle(instance, idle_iface); - } - - impl->host_widget = ew; - instance->host_widget = impl->host_widget; - - return 0; -} - -int -wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) -{ - auto* const ew = static_cast(handle); - ew->resize(width, height); - return 0; -} - -} // namespace - -extern "C" { - -SUIL_LIB_EXPORT -SuilWrapper* -suil_wrapper_new(SuilHost*, - const char*, - const char*, - LV2_Feature*** features, - unsigned n_features) -{ - auto* const impl = - static_cast(calloc(1, sizeof(SuilX11InQt5Wrapper))); - - auto* wrapper = static_cast(malloc(sizeof(SuilWrapper))); - wrapper->wrap = wrapper_wrap; - wrapper->free = wrapper_free; - - auto* const ew = new SuilQX11Widget(nullptr, Qt::Window); - - impl->parent = ew; - - wrapper->impl = impl; - wrapper->resize.handle = ew; - wrapper->resize.ui_resize = wrapper_resize; - - void* parent_id = reinterpret_cast(ew->winId()); - suil_add_feature(features, &n_features, LV2_UI__parent, parent_id); - suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize); - suil_add_feature(features, &n_features, LV2_UI__idleInterface, nullptr); - - return wrapper; -} - -} // extern "C" -- cgit v1.2.1