Skip to content

Commit

Permalink
Better plain object handling on singals.
Browse files Browse the repository at this point in the history
  • Loading branch information
niemeyer committed Mar 31, 2014
1 parent adf30a8 commit 8f415bb
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 32 deletions.
7 changes: 6 additions & 1 deletion cpp/connector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ int Connector::qt_metacall(QMetaObject::Call c, int idx, void **a)
for (int i = 0; i < argsLen; i++) {
int paramType = method.parameterType(i);
if (paramType == 0 && a[1 + i] != NULL) {
plain = new PlainObject(method.parameterTypes()[i].constData(), a[1 + i], plain);
const char *typeName = method.parameterTypes()[i].constData();
void *addr = a[1 + i];
if (typeName[strlen(typeName)-1] == '*') {
addr = *(void **)addr;
}
plain = new PlainObject(typeName, addr, plain);
QVariant var = QVariant::fromValue((QObject *)plain);
packDataValue(&var, &args[i]);
} else {
Expand Down
16 changes: 8 additions & 8 deletions cpp/connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,22 @@ class PlainObject : public QObject
{
Q_OBJECT

Q_PROPERTY(QString typeName READ getTypeName)
Q_PROPERTY(void *valueAddr READ getValueAddr)
Q_PROPERTY(QString plainType READ getPlainType)
Q_PROPERTY(void *plainAddr READ getPlainAddr)

QString typeName;
void *valueAddr;
QString plainType;
void *plainAddr;

public:

PlainObject(QObject *parent = 0)
: QObject(parent) {};

PlainObject(const char *typeName, void *valueAddr, QObject *parent = 0)
: QObject(parent), typeName(typeName), valueAddr(valueAddr) {};
PlainObject(const char *plainType, void *plainAddr, QObject *parent = 0)
: QObject(parent), plainType(plainType), plainAddr(plainAddr) {};

QString getTypeName() { return typeName; };
void *getValueAddr() { return valueAddr; };
QString getPlainType() { return plainType; };
void *getPlainAddr() { return plainAddr; };
};

#endif // CONNECTOR_H
Expand Down
12 changes: 6 additions & 6 deletions cpp/moc_connector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ int Connector::standard_qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
struct qt_meta_stringdata_PlainObject_t {
QByteArrayData data[3];
char stringdata[32];
char stringdata[33];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
Expand All @@ -118,10 +118,10 @@ struct qt_meta_stringdata_PlainObject_t {
static const qt_meta_stringdata_PlainObject_t qt_meta_stringdata_PlainObject = {
{
QT_MOC_LITERAL(0, 0, 11),
QT_MOC_LITERAL(1, 12, 8),
QT_MOC_LITERAL(2, 21, 9)
QT_MOC_LITERAL(1, 12, 9),
QT_MOC_LITERAL(2, 22, 9)
},
"PlainObject\0typeName\0valueAddr\0"
"PlainObject\0plainType\0plainAddr\0"
};
#undef QT_MOC_LITERAL

Expand Down Expand Up @@ -182,8 +182,8 @@ int PlainObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_c == QMetaObject::ReadProperty) {
void *_v = _a[0];
switch (_id) {
case 0: *reinterpret_cast< QString*>(_v) = getTypeName(); break;
case 1: *reinterpret_cast< void**>(_v) = getValueAddr(); break;
case 0: *reinterpret_cast< QString*>(_v) = getPlainType(); break;
case 1: *reinterpret_cast< void**>(_v) = getPlainAddr(); break;
}
_id -= 2;
} else if (_c == QMetaObject::WriteProperty) {
Expand Down
5 changes: 5 additions & 0 deletions cpptest/cpptest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ TestType_ *newTestType()
{
return new TestType();
}

int plainTestTypeN(PlainTestType_ *plain)
{
return static_cast<PlainTestType *>(plain)->n;
}
6 changes: 6 additions & 0 deletions cpptest/cpptest.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ package cpptest
import "C"

import (
"unsafe"

"gopkg.in/v0/qml"
)

Expand All @@ -22,3 +24,7 @@ func NewTestType(engine *qml.Engine) qml.Object {
})
return obj
}

func PlainTestTypeN(obj qml.Object) int {
return int(C.plainTestTypeN(unsafe.Pointer(obj.Property("plainAddr").(uintptr))))
}
3 changes: 3 additions & 0 deletions cpptest/cpptest.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
#include <stdlib.h>

typedef void TestType_;
typedef void PlainTestType_;

#ifdef __cplusplus
extern "C" {
#endif

TestType_ *newTestType();

int plainTestTypeN(PlainTestType_ *plain);

#ifdef __cplusplus
}
#endif
Expand Down
110 changes: 96 additions & 14 deletions cpptest/moc_testtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

QT_BEGIN_MOC_NAMESPACE
struct qt_meta_stringdata_TestType_t {
QByteArrayData data[2];
char stringdata[19];
QByteArrayData data[10];
char stringdata[119];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
Expand All @@ -30,9 +30,19 @@ struct qt_meta_stringdata_TestType_t {
static const qt_meta_stringdata_TestType_t qt_meta_stringdata_TestType = {
{
QT_MOC_LITERAL(0, 0, 8),
QT_MOC_LITERAL(1, 9, 8)
QT_MOC_LITERAL(1, 9, 15),
QT_MOC_LITERAL(2, 25, 0),
QT_MOC_LITERAL(3, 26, 13),
QT_MOC_LITERAL(4, 40, 5),
QT_MOC_LITERAL(5, 46, 15),
QT_MOC_LITERAL(6, 62, 15),
QT_MOC_LITERAL(7, 78, 20),
QT_MOC_LITERAL(8, 99, 9),
QT_MOC_LITERAL(9, 109, 8)
},
"TestType\0voidAddr\0"
"TestType\0plainEmittedCpy\0\0PlainTestType\0"
"plain\0plainEmittedRef\0plainEmittedPtr\0"
"const PlainTestType*\0emitPlain\0voidAddr\0"
};
#undef QT_MOC_LITERAL

Expand All @@ -42,25 +52,68 @@ static const uint qt_meta_data_TestType[] = {
7, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
1, 14, // properties
4, 14, // methods
1, 44, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
3, // signalCount

// signals: name, argc, parameters, tag, flags
1, 1, 34, 2, 0x06,
5, 1, 37, 2, 0x06,
6, 1, 40, 2, 0x06,

// methods: name, argc, parameters, tag, flags
8, 0, 43, 2, 0x02,

// signals: parameters
QMetaType::Void, 0x80000000 | 3, 4,
QMetaType::Void, 0x80000000 | 3, 4,
QMetaType::Void, 0x80000000 | 7, 4,

// methods: parameters
QMetaType::Void,

// properties: name, type, flags
1, QMetaType::VoidStar, 0x00095001,
9, QMetaType::VoidStar, 0x00095001,

0 // eod
};

void TestType::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
if (_c == QMetaObject::InvokeMetaMethod) {
TestType *_t = static_cast<TestType *>(_o);
switch (_id) {
case 0: _t->plainEmittedCpy((*reinterpret_cast< const PlainTestType(*)>(_a[1]))); break;
case 1: _t->plainEmittedRef((*reinterpret_cast< const PlainTestType(*)>(_a[1]))); break;
case 2: _t->plainEmittedPtr((*reinterpret_cast< const PlainTestType*(*)>(_a[1]))); break;
case 3: _t->emitPlain(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
void **func = reinterpret_cast<void **>(_a[1]);
{
typedef void (TestType::*_t)(const PlainTestType );
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedCpy)) {
*result = 0;
}
}
{
typedef void (TestType::*_t)(const PlainTestType & );
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedRef)) {
*result = 1;
}
}
{
typedef void (TestType::*_t)(const PlainTestType * );
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedPtr)) {
*result = 2;
}
}
}
}

const QMetaObject TestType::staticMetaObject = {
Expand All @@ -87,9 +140,17 @@ int TestType::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;

if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 4)
qt_static_metacall(this, _c, _id, _a);
_id -= 4;
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 4)
*reinterpret_cast<int*>(_a[0]) = -1;
_id -= 4;
}
#ifndef QT_NO_PROPERTIES
if (_c == QMetaObject::ReadProperty) {
else if (_c == QMetaObject::ReadProperty) {
void *_v = _a[0];
switch (_id) {
case 0: *reinterpret_cast< void**>(_v) = getVoidAddr(); break;
Expand Down Expand Up @@ -117,4 +178,25 @@ int TestType::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
#endif // QT_NO_PROPERTIES
return _id;
}

// SIGNAL 0
void TestType::plainEmittedCpy(const PlainTestType _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

// SIGNAL 1
void TestType::plainEmittedRef(const PlainTestType & _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}

// SIGNAL 2
void TestType::plainEmittedPtr(const PlainTestType * _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
QT_END_MOC_NAMESPACE
22 changes: 22 additions & 0 deletions cpptest/testtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

#include <QObject>

class PlainTestType {

public:

PlainTestType(int n) : n(n) {};

int n;
};

class TestType : public QObject
{
Q_OBJECT
Expand All @@ -16,6 +25,19 @@ class TestType : public QObject
TestType(QObject *parent = 0) : QObject(parent), voidAddr((void*)42) {};

void *getVoidAddr() { return voidAddr; };

Q_INVOKABLE void emitPlain() {
PlainTestType plain = PlainTestType(42);
emit plainEmittedCpy(plain);
emit plainEmittedRef(plain);
emit plainEmittedPtr(&plain);
};

signals:

void plainEmittedCpy(const PlainTestType plain);
void plainEmittedRef(const PlainTestType &plain);
void plainEmittedPtr(const PlainTestType *plain);
};

#endif // TESTTYPE_H
Expand Down
6 changes: 5 additions & 1 deletion datatype.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"image/color"
"reflect"
"strings"
"unicode"
"unsafe"
)
Expand Down Expand Up @@ -165,7 +166,10 @@ func unpackDataValue(dvalue *C.DataValue, engine *Engine) interface{} {
// TODO Embed the type name in DataValue to drop these calls.
typeName := obj.TypeName()
if typeName == "PlainObject" {
typeName = obj.String("typeName")
typeName = strings.TrimRight(obj.String("plainType"), "&*")
if strings.HasPrefix(typeName, "const ") {
typeName = typeName[6:]
}
}
if f, ok := converters[typeName]; ok {
return f(engine, obj)
Expand Down
30 changes: 28 additions & 2 deletions qml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,34 @@ func (s *S) TestReadVoidAddrProperty(c *C) {
c.Assert(addr, Equals, uintptr(42))
}

func (s *S) TestRegisterConverterPlainObject(c *C) {
qml.RegisterConverter("PlainTestType", func(engine *qml.Engine, obj qml.Object) interface{} {
c.Check(engine, Equals, s.engine)
c.Check(obj.String("plainType"), Matches, "(const )?PlainTestType[&*]?")
c.Check(obj.Property("plainAddr"), FitsTypeOf, uintptr(0))
c.Check(cpptest.PlainTestTypeN(obj), Equals, 42)
return "<converted>"
})
obj := cpptest.NewTestType(s.engine)
defer obj.Destroy()

var calls int
obj.On("plainEmittedCpy", func(s string) {
c.Check(s, Equals, "<converted>")
calls++
})
obj.On("plainEmittedRef", func(s string) {
c.Check(s, Equals, "<converted>")
calls++
})
obj.On("plainEmittedPtr", func(s string) {
c.Check(s, Equals, "<converted>")
calls++
})
obj.Call("emitPlain")
c.Assert(calls, Equals, 3)
}

type TestData struct {
*C
engine *qml.Engine
Expand Down Expand Up @@ -1127,8 +1155,6 @@ var tests = []struct {
},
DoneLog: "Signal has run.",
},

// TODO Test RegisterConverter action on plain objects. Will need a C++ test extension for that.
}

var tablef = flag.String("tablef", "", "if provided, TestTable only runs tests with a summary matching the regexp")
Expand Down

0 comments on commit 8f415bb

Please sign in to comment.