From ac24e816eda177e583bea019b7b98f2111291804 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Tue, 19 Nov 2013 08:54:15 +0100 Subject: Impelement signal arguments --- src/QuickStreamer/item.cpp | 204 +++++++++++++++++++++++++++++++++++++++++---- src/QuickStreamer/item.h | 1 + 2 files changed, 190 insertions(+), 15 deletions(-) diff --git a/src/QuickStreamer/item.cpp b/src/QuickStreamer/item.cpp index e934f6c..91da974 100644 --- a/src/QuickStreamer/item.cpp +++ b/src/QuickStreamer/item.cpp @@ -76,11 +76,14 @@ struct PropertyDelegate struct SignalDelegate { - typedef std::function SignalClosure; + typedef std::function SignalClosure; - static void invokeClosure(void *data) + static void invokeClosure(void *data, ...) { - (*static_cast(data))(); + va_list args; + va_start(args, data); + + (*static_cast(data))(&args); } static void deleteClosure(void *data, GClosure *) @@ -88,24 +91,161 @@ struct SignalDelegate delete static_cast(data); } - void connect(Item *item) const + void connect(Item *item) const; + void activate(Item *object, va_list *args) const { - const int signalIndex = methodId; + QVarLengthArray values(paramTypes.count()+1); + QVarLengthArray params(paramTypes.count()+1); + QStringList strings; + QList objects; + + for (int i = 1; i <= paramTypes.count(); ++i) { + params[i] = &values[i]; + switch(const auto type = paramTypes[i-1]) + { + case G_TYPE_CHAR: + *reinterpret_cast(&values[i]) = va_arg(*args, int); + break; + + case G_TYPE_UCHAR: + *reinterpret_cast(&values[i]) = va_arg(*args, int); + break; + + case G_TYPE_BOOLEAN: + *reinterpret_cast(&values[i]) = va_arg(*args, int); + break; + + case G_TYPE_INT: + *reinterpret_cast(&values[i]) = va_arg(*args, int); + break; + + case G_TYPE_UINT: + *reinterpret_cast(&values[i]) = va_arg(*args, uint); + break; + + case G_TYPE_LONG: + *reinterpret_cast(&values[i]) = va_arg(*args, ulong); + break; + + case G_TYPE_ULONG: + *reinterpret_cast(&values[i]) = va_arg(*args, ulong); + break; + + case G_TYPE_INT64: + *reinterpret_cast(&values[i]) = va_arg(*args, qint64); + break; + + case G_TYPE_UINT64: + *reinterpret_cast(&values[i]) = va_arg(*args, quint64); + break; + + case G_TYPE_FLOAT: + *reinterpret_cast(&values[i]) = va_arg(*args, double); + break; + + case G_TYPE_DOUBLE: + *reinterpret_cast(&values[i]) = va_arg(*args, double); + break; + + case G_TYPE_STRING: + strings.append(QString(va_arg(*args, char*))); + params[i] = &strings.last(); + break; + + case G_TYPE_POINTER: + *reinterpret_cast(&values[i]) = va_arg(*args, void*); + break; + + //case G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18) + //case G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19) + //case G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) + //case G_TYPE_VARIANT G_TYPE_MAKE_FUNDAMENTAL (21) + + default: + if (g_type_is_a(type, G_TYPE_ENUM)) { + *reinterpret_cast(&values[i]) = va_arg(*args, int); + break; + } + + if (g_type_is_a(type, G_TYPE_FLAGS)) { + *reinterpret_cast(&values[i]) = va_arg(*args, uint); + break; + } - auto closure = new SignalClosure([item, signalIndex] { - QMetaObject::activate(item, signalIndex, Q_NULLPTR); // FIXME: deal with signal arguments - }); + if (g_type_is_a(type, GST_TYPE_OBJECT)) { + GstObject *gobject = va_arg(*args, GstObject*); + if (GST_IS_PAD(gobject)) { + } + objects.append(new Item(gobject)); + params[i] = &objects.last(); + break; + } - g_signal_connect_data(item->target(), name.constData(), - G_CALLBACK(&SignalDelegate::invokeClosure), closure, - &SignalDelegate::deleteClosure, - G_CONNECT_SWAPPED); + qWarning("Cannot convert unsupported GValue type: %s", G_VALUE_TYPE_NAME(type)); + values[i] = 0; + va_arg(*args, void*); + break; + } + } + QMetaObject::activate(object, methodId, params.data()); + qDeleteAll(objects); } QByteArray name; int methodId; + QVector paramTypes; }; +class SignalEvent : public QEvent +{ +public: + SignalEvent(Item *item, const SignalDelegate *signal, va_list *args, QSemaphore *semaphore) + : QEvent(static_cast(type)) + , m_item(item) + , m_signal(signal) + , m_args(args) + , m_semaphore(semaphore) + {} + + static void sendSignal(Item *item, const SignalDelegate *signal, va_list *args) + { + QSemaphore semaphore; + SignalEvent *event = new SignalEvent(item, signal, args, &semaphore); + QCoreApplication::postEvent(item, event); + semaphore.acquire(); + } + + void activate() + { + m_signal->activate(m_item, m_args); + m_semaphore->release(); + } + + static int type; +private: + Item *m_item; + const SignalDelegate *m_signal; + va_list *m_args; + QSemaphore *m_semaphore; +}; + +int SignalEvent::type = QEvent::registerEventType(); + +void SignalDelegate::connect(Item *item) const +{ + auto closure = new SignalClosure([item, this](va_list *args) { + if (QThread::currentThread() == item->thread()) + this->activate(item, args); + else + SignalEvent::sendSignal(item, this, args); + }); + + g_signal_connect_data(item->target(), name.constData(), + G_CALLBACK(&SignalDelegate::invokeClosure), closure, + &SignalDelegate::deleteClosure, + G_CONNECT_SWAPPED); +} + static bool isDash(char ch) { return ch == '-' || ch == '_'; @@ -608,7 +748,7 @@ struct TypeInfo if (delegate.spec) { auto notifier = objectBuilder->addSignal(propertyName + QByteArrayLiteral("Changed()")); signalDelegates.append({ QByteArrayLiteral("notify::") + delegate.spec->name, - parent->metaObject->methodCount() + notifier.index() }); + parent->metaObject->methodCount() + notifier.index(), {} }); notifierIndex = notifier.index(); } @@ -716,7 +856,32 @@ struct TypeInfo GSignalQuery query; g_signal_query(signalIds[i], &query); Q_ASSERT(signalIds[i] == query.signal_id); - qDebug("FIXME: register signal %s::%s", g_type_name(type), query.signal_name); + if (query.signal_flags & G_SIGNAL_ACTION) { + qDebug("FIXME: register action %s::%s", g_type_name(type), query.signal_name); + } else { + auto signalName = toCamelCase(query.signal_name, std::tolower); + auto signature = signalName + '('; + QList names; + QVector paramTypes; + QByteArray args; + for (uint i = 0; i < query.n_params; ++i) { + names.append(QByteArrayLiteral("arg") + QByteArray::number(i)); + if (!args.isNull()) + args.append(','); + args.append(metaTypeName(query.param_types[i])); + paramTypes.append(query.param_types[i]); + } + signature.append(args); + signature.append(')'); + auto signal = objectBuilder.addSignal(signature); + signal.setParameterNames(names); + + int index = signal.index(); + if (typeInfo->parent) + index += typeInfo->parent->metaObject->methodCount(); + typeInfo->signalDelegates.append({ QByteArray(query.signal_name), index, + paramTypes }); + } } typedef QtMetaTypePrivate::QMetaTypeFunctionHelper MetaTypeHelper; @@ -864,7 +1029,6 @@ struct TypeInfo QByteArray elementName; QVector propertyDelegates; QVector signalDelegates; - static QHash cache; }; @@ -1032,6 +1196,16 @@ void Item::componentComplete() } } +bool Item::event(QEvent *e) +{ + if (e->type() == Private::SignalEvent::type) { + Private::SignalEvent *event = static_cast(e); + event->activate(); + return true; + } + return QObject::event(e); +} + GstObject *Item::target() const { return m_target; diff --git a/src/QuickStreamer/item.h b/src/QuickStreamer/item.h index 775b2e1..56826a2 100644 --- a/src/QuickStreamer/item.h +++ b/src/QuickStreamer/item.h @@ -54,6 +54,7 @@ public: void classBegin() Q_DECL_OVERRIDE; void componentComplete() Q_DECL_OVERRIDE; + bool event(QEvent *e) Q_DECL_OVERRIDE; GstObject *target() const; -- cgit v1.2.3