summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-10-03 17:36:10 +0200
committerDavid Robillard <d@drobilla.net>2017-12-16 08:56:58 +0100
commit9e9cf2fbcafc4fe673e7bc65418b401671a4be88 (patch)
treecc06a71750776883a0e36dbab6fdbde15886c394
parentdfdd807c4ae255466b8113041bc1de6d8e3c7015 (diff)
downloadsuil-9e9cf2fbcafc4fe673e7bc65418b401671a4be88.tar.gz
suil-9e9cf2fbcafc4fe673e7bc65418b401671a4be88.tar.bz2
suil-9e9cf2fbcafc4fe673e7bc65418b401671a4be88.zip
Add support for Cocoa in Qt5
-rw-r--r--NEWS6
-rw-r--r--src/cocoa_in_qt5.mm166
-rw-r--r--src/instance.c10
-rw-r--r--wscript19
4 files changed, 199 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 5ce7774..1e34284 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+suil (0.10.1) unstable;
+
+ * Add support for Cocoa in Qt5
+
+ -- David Robillard <d@drobilla.net> Tue, 03 Oct 2017 22:11:49 +0200
+
suil (0.10.0) stable;
* Add support for X11 in Gtk3
diff --git a/src/cocoa_in_qt5.mm b/src/cocoa_in_qt5.mm
new file mode 100644
index 0000000..4259075
--- /dev/null
+++ b/src/cocoa_in_qt5.mm
@@ -0,0 +1,166 @@
+/*
+ Copyright 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.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+#include <QCloseEvent>
+#include <QMacCocoaViewContainer>
+#include <QTimerEvent>
+#include <QWidget>
+
+#undef signals
+
+#include "./suil_config.h"
+#include "./suil_internal.h"
+
+extern "C" {
+
+typedef struct {
+ QWidget* host_widget;
+ QWidget* parent;
+} SuilCocoaInQt5Wrapper;
+
+class SuilQCocoaWidget : public QMacCocoaViewContainer
+{
+public:
+ SuilQCocoaWidget(NSView* view, QWidget* parent)
+ : QMacCocoaViewContainer(view, parent)
+ , _instance(NULL)
+ , _idle_iface(NULL)
+ , _ui_timer(0)
+ {
+ }
+
+ void start_idle(SuilInstance* instance,
+ const LV2UI_Idle_Interface* idle_iface) {
+ _instance = instance;
+ _idle_iface = idle_iface;
+ NSView* view = (NSView*)instance->ui_widget;
+ setCocoaView((NSView*)instance->ui_widget);
+ setMinimumWidth([view fittingSize].width);
+ setMinimumHeight([view fittingSize].height);
+ if (_idle_iface && _ui_timer == 0) {
+ _ui_timer = this->startTimer(30);
+ }
+ }
+
+protected:
+ void timerEvent(QTimerEvent* event) {
+ if (event->timerId() == _ui_timer && _idle_iface) {
+ _idle_iface->idle(_instance->handle);
+ }
+ QWidget::timerEvent(event);
+ }
+
+ void closeEvent(QCloseEvent* event) {
+ if (_ui_timer && _idle_iface) {
+ this->killTimer(_ui_timer);
+ _ui_timer = 0;
+ }
+ QWidget::closeEvent(event);
+ }
+
+private:
+ SuilInstance* _instance;
+ const LV2UI_Idle_Interface* _idle_iface;
+ int _ui_timer;
+};
+
+static void
+wrapper_free(SuilWrapper* wrapper)
+{
+ SuilCocoaInQt5Wrapper* impl = (SuilCocoaInQt5Wrapper*)wrapper->impl;
+
+ if (impl->host_widget) {
+ delete impl->host_widget;
+ }
+
+ free(impl);
+}
+
+static int
+wrapper_wrap(SuilWrapper* wrapper,
+ SuilInstance* instance)
+{
+ SuilCocoaInQt5Wrapper* const impl = (SuilCocoaInQt5Wrapper*)wrapper->impl;
+ SuilQCocoaWidget* const ew = (SuilQCocoaWidget*)impl->parent;
+
+ if (instance->descriptor->extension_data) {
+ const LV2UI_Idle_Interface* idle_iface
+ = (const LV2UI_Idle_Interface*)
+ 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;
+}
+
+static int
+wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
+{
+ SuilQCocoaWidget* const ew = (SuilQCocoaWidget*)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)
+{
+ QWidget* parent = NULL;
+ for (unsigned i = 0; i < n_features; ++i) {
+ if (!strcmp((*features)[i]->URI, LV2_UI__parent)) {
+ parent = (QWidget*)(*features)[i]->data;
+ }
+ }
+
+ if (!parent) {
+ SUIL_ERRORF("No QWidget parent given for %s UI\n", ui_type_uri);
+ return NULL;
+ }
+
+ SuilCocoaInQt5Wrapper* const impl = (SuilCocoaInQt5Wrapper*)
+ calloc(1, sizeof(SuilCocoaInQt5Wrapper));
+
+ SuilWrapper* wrapper = (SuilWrapper*)malloc(sizeof(SuilWrapper));
+ wrapper->wrap = wrapper_wrap;
+ wrapper->free = wrapper_free;
+ NSView* view = [NSView new];
+
+ SuilQCocoaWidget* const ew = new SuilQCocoaWidget(view, parent);
+
+ 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, ew->cocoaView());
+ suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize);
+ suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL);
+
+ return wrapper;
+}
+
+} // extern "C"
diff --git a/src/instance.c b/src/instance.c
index 42ea7b8..d365ca2 100644
--- a/src/instance.c
+++ b/src/instance.c
@@ -61,7 +61,9 @@ suil_ui_supported(const char* host_type_uri,
|| (!strcmp(host_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI))
|| (!strcmp(host_type_uri, QT5_UI_URI)
- && !strcmp(ui_type_uri, X11_UI_URI))) {
+ && !strcmp(ui_type_uri, X11_UI_URI))
+ || (!strcmp(host_type_uri, QT5_UI_URI)
+ && !strcmp(ui_type_uri, COCOA_UI_URI))) {
return SUIL_WRAPPING_EMBEDDED;
} else {
return SUIL_WRAPPING_UNSUPPORTED;
@@ -136,6 +138,12 @@ open_wrapper(SuilHost* host,
module_name = "suil_x11_in_qt5";
}
#endif
+#ifdef SUIL_WITH_COCOA_IN_QT5
+ if (!strcmp(container_type_uri, QT5_UI_URI)
+ && !strcmp(ui_type_uri, COCOA_UI_URI)) {
+ module_name = "suil_cocoa_in_qt5";
+ }
+#endif
if (!module_name) {
SUIL_ERRORF("Unable to wrap UI type <%s> as type <%s>\n",
diff --git a/wscript b/wscript
index 5420333..279265b 100644
--- a/wscript
+++ b/wscript
@@ -92,6 +92,10 @@ def configure(conf):
if not conf.options.no_qt5:
autowaf.check_pkg(conf, 'Qt5Widgets', uselib_store='QT5',
atleast_version='5.1.0', mandatory=False)
+ if conf.check_cxx(header_name = 'QMacCocoaViewContainer',
+ uselib = 'QT5',
+ mandatory = False):
+ autowaf.define(conf, 'SUIL_WITH_COCOA_IN_QT5', 1)
conf.check_cc(define_name = 'HAVE_LIBDL',
lib = 'dl',
@@ -174,7 +178,8 @@ def configure(conf):
('x11', 'gtk2'),
('x11', 'gtk3'),
('x11', 'qt4'),
- ('x11', 'qt5')]
+ ('x11', 'qt5'),
+ ('cocoa', 'qt5')]
for w in wrappers:
var = 'SUIL_WITH_%s_IN_%s' % (w[0].upper(), w[1].upper())
autowaf.display_msg(conf, 'Support for %s in %s' % (w[0], w[1]),
@@ -351,6 +356,18 @@ def build(bld):
lib = modlib)
autowaf.use_lib(bld, obj, 'QT5 LV2')
+ if bld.env.SUIL_WITH_COCOA_IN_QT5:
+ obj = bld(features = 'cxx cxxshlib',
+ source = 'src/cocoa_in_qt5.mm',
+ target = 'suil_cocoa_in_qt5',
+ includes = ['.'],
+ defines = ['SUIL_SHARED', 'SUIL_INTERNAL'],
+ install_path = module_dir,
+ cflags = cflags,
+ lib = modlib,
+ linkflags = ['-framework', 'Cocoa'])
+ autowaf.use_lib(bld, obj, 'QT5 QT5_MAC_EXTRAS LV2')
+
if bld.env.SUIL_WITH_X11:
obj = bld(features = 'c cshlib',
source = 'src/x11.c',