[Kde-bindings] playground/bindings/kimono

Arno Rehn kde at arnorehn.de
Sat Feb 24 17:47:12 UTC 2007


SVN commit 636922 by arnorehn:

* Added ReadProperty and WriteProperty classes. Now custom properties can
  be accessed via Property() and SetProperty() (and dbus?). However there seems
  to be a problem with marshalling, see FIXMEs in the code. The workaround should
  work as well as with marshalling, though.
* Autogeneration of Q_PROPERTY signatures and types now works properly.
* Flags of properties should now be set correctly.

CCMAIL: kde-bindings at kde.org



 M  +9 -0      ChangeLog  
 M  +3 -1      Qyoto.cs  
 M  +4 -4      QyotoMetaData.cs  
 M  +50 -0     SmokeMarshallers.cs  
 M  +151 -24   qyoto.cpp  
 M  +2 -1      qyoto.h  


--- trunk/playground/bindings/kimono/ChangeLog #636921:636922
@@ -1,3 +1,12 @@
+2007-02-24  Arno Rehn  <arno at arnorehn.de>
+
+	* Added ReadProperty and WriteProperty classes. Now custom properties can
+	  be accessed via Property() and SetProperty() (and dbus?). However there seems
+	  to be a problem with marshalling, see FIXMEs in the code. The workaround should
+	  work as well as with marshalling, though.
+	* Autogeneration of Q_PROPERTY signatures and types now works properly.
+	* Flags of properties should now be set correctly.
+	
 2007-02-21  Arno Rehn  <arno at arnorehn.de>
 
 	* QMetaObjects are now correctly inherited.
--- trunk/playground/bindings/kimono/Qyoto.cs #636921:636922
@@ -555,9 +555,11 @@
 			Type = type;
 			Name = name;
 		}
-
+		
 		public Q_PROPERTY()
 		{
+			Type = "";
+			Name = "";
 		}
 	}
 }
--- trunk/playground/bindings/kimono/QyotoMetaData.cs #636921:636922
@@ -140,14 +140,14 @@
 			}
 			
 			foreach (Qyoto.CPPProperty entry in properties) {
-				PropertyFlags flags = PropertyFlags.Invalid;
+				PropertyFlags flags = PropertyFlags.StdCppSet | PropertyFlags.ResolveEditable | PropertyFlags.Stored;
 				
 				if (entry.pi.CanRead && entry.pi.CanWrite) {
-					flags = PropertyFlags.Readable | PropertyFlags.Writable;
+					flags |= PropertyFlags.Readable | PropertyFlags.Writable;
 				} else if (entry.pi.CanRead) {
-					flags = PropertyFlags.Readable;
+					flags |= PropertyFlags.Readable;
 				} else if (entry.pi.CanWrite) {
-					flags = PropertyFlags.Writable;
+					flags |= PropertyFlags.Writable;
 				}
 				
 				if (entry.scriptable)
--- trunk/playground/bindings/kimono/SmokeMarshallers.cs #636921:636922
@@ -85,6 +85,12 @@
 		public static extern bool InstallGetParentMetaObject(GetIntPtr callback);
 		
 		[DllImport("libqyoto", CharSet=CharSet.Ansi)]
+		public static extern bool InstallGetProperty(OverridenMethodFn callback);
+		
+		[DllImport("libqyoto", CharSet=CharSet.Ansi)]
+		public static extern bool InstallSetProperty(SetPropertyFn callback);
+		
+		[DllImport("libqyoto", CharSet=CharSet.Ansi)]
 		public static extern void InstallIntPtrToCharStarStar(GetIntPtr callback);
 		
 		[DllImport("libqyoto", CharSet=CharSet.Ansi)]
@@ -160,6 +166,7 @@
 		public delegate void AddIntObject(IntPtr hash, int key, IntPtr val);
 		public delegate IntPtr DictToMap(IntPtr ptr, int type);
 		public delegate IntPtr ConstructDict(string type1, string type2);
+		public delegate void SetPropertyFn(IntPtr obj, string name, IntPtr variant);
 #endregion
 		
 #region marshalling functions
@@ -215,7 +222,44 @@
 			}
 			return (IntPtr) GCHandle.Alloc(mo);
 		}
+		
+		public static IntPtr GetProperty(IntPtr obj, string propertyName) {
+			object o = ((GCHandle) obj).Target;
+			Type t = o.GetType();
+			PropertyInfo pi = t.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic |
+									BindingFlags.Instance | BindingFlags.Static);
+			
+			MethodInfo fromValue = typeof(QVariant).GetMethod("FromValue", BindingFlags.Public | BindingFlags.Static);
+			if (fromValue == null) throw new Exception("Couldn't find QVariant.FromValue<T> method");
+			fromValue = fromValue.MakeGenericMethod( new Type[]{ pi.PropertyType } );
 
+			if (pi != null) {
+				object value = pi.GetValue(o, null);
+				object[] args = { value };
+				QVariant variant = (QVariant) fromValue.Invoke(null, args);
+				return (IntPtr) GCHandle.Alloc(variant);
+			}
+			
+			return (IntPtr) 0;
+		}
+		
+		public static void SetProperty(IntPtr obj, string propertyName, IntPtr variant) {
+			object o = ((GCHandle) obj).Target;
+			Type t = o.GetType();
+			object v = ((GCHandle) variant).Target;
+			PropertyInfo pi = t.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic |
+									BindingFlags.Instance | BindingFlags.Static);
+									
+			MethodInfo value = typeof(QVariant).GetMethod("Value", BindingFlags.Public | BindingFlags.Instance);
+			if (value == null) throw new Exception("Couldn't find QVariant.Value<T> method");
+			value = value.MakeGenericMethod( new Type[]{ pi.PropertyType } );
+
+			if (pi != null) {
+				object ret = value.Invoke(v, null);
+				pi.SetValue(o, ret, null);
+			}
+		}
+
 		// The key is an IntPtr corresponding to the address of the C++ instance,
 		// and the value is a the C# instance. This is used to prevent garbage
 		// collection for instances which are contained inside, and owned by
@@ -524,6 +568,9 @@
 		static private IsSmokeClassFn isSmokeClass = new IsSmokeClassFn(Qyoto.IsSmokeClass);
 		static private GetIntPtr getParentMetaObject = new GetIntPtr(GetParentMetaObject);
 		
+		static private OverridenMethodFn getProperty = new OverridenMethodFn(GetProperty);
+		static private SetPropertyFn setProperty = new SetPropertyFn(SetProperty);
+		
 		public static void SetUp() {
 			InstallFreeGCHandle(freeGCHandle);
 
@@ -561,6 +608,9 @@
 			InstallInvokeCustomSlot(invokeCustomSlot);
 			InstallIsSmokeClass(isSmokeClass);
 			InstallGetParentMetaObject(getParentMetaObject);
+			
+			InstallGetProperty(getProperty);
+			InstallSetProperty(setProperty);
 		}
 #endregion
 
--- trunk/playground/bindings/kimono/qyoto.cpp #636921:636922
@@ -77,6 +77,9 @@
 static IsSmokeClassFn IsSmokeClass;
 static GetIntPtr GetParentMetaObject;
 
+static OverridenMethodFn GetProperty;
+static SetPropertyFn SetProperty;
+
 // Maps from a classname in the form Qt::Widget to an int id
 QHash<int,char *> classname;
 extern bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *);
@@ -852,6 +855,106 @@
 	}
 };
 
+class ReadProperty : public Marshall {
+	SmokeType* _type;
+	Smoke::StackItem* _stack;
+	Smoke::StackItem* _result;
+public:
+	ReadProperty(void* obj, const char* propertyName, void** o)
+	{
+// 		_type = new SmokeType(qt_Smoke, qt_Smoke->idType("QVariant"));
+// 		_stack = new Smoke::StackItem;
+// 		_result = new Smoke::StackItem;
+		
+		// Get the C# property value
+		void* variant = (*GetProperty)(obj, propertyName);
+// 		_stack->s_voidp = variant;
+		
+		// FIXME
+		// doesn't work, Mono throws 'System.ArgumentException: GCHandle value belongs to a different domain'
+		// anyway, it's faster the way it's done now than with all the marshalling stuff
+// 		Marshall::HandlerFn fn = getMarshallFn(type());
+// 		(*fn)(this);
+		
+		// put the marshalled value into the void* array of qt_metacall()
+		smokeqyoto_object* sqo = value_obj_info(variant);
+		o[0] = sqo->ptr; // _result->s_voidp;
+	}
+
+	SmokeType type() {
+		return *_type;
+	}
+	Marshall::Action action() { return Marshall::FromObject; }
+	Smoke::StackItem &item() { return *_stack; }
+	Smoke::StackItem &var() {
+		return *_result;
+	}
+	
+	void unsupported() 
+	{
+		printf("Cannot handle '%s' as property", type().name());
+	}
+	Smoke *smoke() { return type().smoke(); }
+
+	void next() {}
+
+	bool cleanup() { return false; }
+	
+	~ReadProperty() {
+// 		delete _stack;
+	}
+};
+
+class WriteProperty : public Marshall {
+	SmokeType* _type;
+	Smoke::StackItem* _stack;
+	Smoke::StackItem* _result;
+public:
+	WriteProperty(void* obj, const char* propertyName, void** o)
+	{
+// 		_type = new SmokeType(qt_Smoke, qt_Smoke->idType("QVariant"));
+		_stack = new Smoke::StackItem;
+		_result = new Smoke::StackItem;
+		
+		_stack->s_voidp = o[0];
+		
+		// TODO
+		// check if it works with getMarshallFn and stuff.
+		// didn't test it since it didn't work with ReadProperty
+// 		Marshall::HandlerFn fn = getMarshallFn(type());
+// 		(*fn)(this);
+		
+		smokeqyoto_object* sqo = alloc_smokeqyoto_object(false, qt_Smoke, qt_Smoke->idClass("QVariant"), _stack->s_voidp);
+		void* variant = set_obj_info("Qyoto.QVariant", sqo);
+		
+		// Set the C# property value
+		(*SetProperty)(obj, propertyName, variant);
+	}
+
+	SmokeType type() {
+		return *_type;
+	}
+	Marshall::Action action() { return Marshall::FromObject; }
+	Smoke::StackItem &item() { return *_stack; }
+	Smoke::StackItem &var() {
+		return *_result;
+	}
+	
+	void unsupported() 
+	{
+		printf("Cannot handle '%s' as property", type().name());
+	}
+	Smoke *smoke() { return type().smoke(); }
+
+	void next() {}
+
+	bool cleanup() { return false; }
+	
+	~WriteProperty() {
+// 		delete _stack;
+	}
+};
+
 class QyotoSmokeBinding : public SmokeBinding {
 public:
     QyotoSmokeBinding(Smoke *s) : SmokeBinding(s) {}
@@ -1239,6 +1342,18 @@
 }
 
 void
+InstallGetProperty(OverridenMethodFn callback)
+{
+	GetProperty = callback;
+}
+
+void
+InstallSetProperty(SetPropertyFn callback)
+{
+	SetProperty = callback;
+}
+
+void
 SetApplicationTerminated()
 {
 	application_terminated = true;
@@ -1538,8 +1653,16 @@
 	const QMetaObject *metaobject = qobj->metaObject();
 	
 	// get method count and offset
-	int count = metaobject->methodCount();
-	int offset = metaobject->methodOffset();
+	int count = 0;
+	int offset = 0;
+	if (_c == QMetaObject::InvokeMetaMethod) {
+		count = metaobject->methodCount();
+		offset = metaobject->methodOffset();
+	} else {
+		count = metaobject->propertyCount();
+		offset = metaobject->propertyOffset();
+	}
+	
 
 	// if id < offset call base version
 	if (_id < offset || (*IsSmokeClass)(obj)) {
@@ -1554,37 +1677,41 @@
 			i[2].s_int = _id;
 			i[3].s_voidp = _o;
 			(*fn)(m.method, o->ptr, i);
+			
 			return i[0].s_int;
 		}
-
+		
 		// Should never happen..
 		qFatal("Cannot find %s::qt_metacall() method\n", 
 			o->smoke->classes[o->classId].className );
 	}
 
-	// return immediately if _c != QMetaObject::InvokeMetaMethod
-    if (_c != QMetaObject::InvokeMetaMethod) {
-		return _id;
-	}
-
-	// retrieve method signature from id
-	QMetaMethod method = metaobject->method(_id);
-	QString name(method.signature());
-	QString type(method.typeName());
+	if (_c == QMetaObject::InvokeMetaMethod) {
+		// retrieve method signature from id
+		QMetaMethod method = metaobject->method(_id);
+		QString name(method.signature());
+		QString type(method.typeName());
+		
+		if (method.methodType() == QMetaMethod::Signal) {
+			metaobject->activate(qobj, _id, (void**) _o);
+			return _id - (count - offset);
+		}
 	
-	if (method.methodType() == QMetaMethod::Signal) {
-		metaobject->activate(qobj, _id, (void**) _o);
-		return _id - (count - offset);
+		int items;
+		MocArgument* mocArgs = GetMocArgumentsNumber(type, name, items);
+		
+		// invoke slot
+		InvokeSlot slot(obj, method.signature(), items, mocArgs, (void**)_o);
+		slot.next();
+		
+		delete mocArgs;
+	} else if (_c == QMetaObject::ReadProperty) {
+		QMetaProperty property = metaobject->property(_id);
+		ReadProperty prop(obj, property.name(), (void**)_o);
+	} else if (_c == QMetaObject::WriteProperty) {
+		QMetaProperty property = metaobject->property(_id);
+		WriteProperty prop(obj, property.name(), (void**)_o);
 	}
-
-	int items;
-	MocArgument* mocArgs = GetMocArgumentsNumber(type, name, items);
-	
-	// invoke slot
-	InvokeSlot slot(obj, method.signature(), items, mocArgs, (void**)_o);
-	slot.next();
-	
-	delete mocArgs;
 	return _id - count;
 }
 
--- trunk/playground/bindings/kimono/qyoto.h #636921:636922
@@ -76,7 +76,8 @@
 typedef void (*AddInt)(void*, int);
 typedef void (*AddIntObject)(void*, int, void*);
 typedef void* (*DictToMap)(void*, int);
-typedef void* (*ConstructDict)(const char* type1, const char* type2);
+typedef void* (*ConstructDict)(const char*, const char*);
+typedef void (*SetPropertyFn)(void*, const char*, void*);
 
 extern FromIntPtr FreeGCHandle;
 



More information about the Kde-bindings mailing list