Commits

Ronald Oussoren committed 0b44781

- Fix the test for -copy(WithZone:)
- Make sure copy(WithZone:) actually works, this is needed to write
custom NSCell for use in NSTableViews
- The problem was that -copy and -copyWithZone: should return a new
reference, but did return a borrowed reference (like all ObjC methods that
are implemented in Python). Fixed this by checking the ObjCSelector object
for the PyObjCSelector_kDONATE_REF flag and adjusting the reference count
as needed. While doing this I changed the interface for PyObjC_CallPython,
hence the changes outside Modules/objc

  • Participants
  • Parent commits 9bfc7cd

Comments (0)

Files changed (20)

pyobjc/Lib/objc/test/test_subclass.py

     def testCopy(self):
         class MyCopyClass (NSObject):
             def copyWithZone_(self, zone):
-                o = super(MyCopyClass, self).copyWithZone_(zone)
+                # NSObject doesn't implement the copying protocol
+                #o = super(MyCopyClass, self).copyWithZone_(zone)
+                o = self.__class__.alloc().init()
                 o.foobar = 2
                 return o
+            copyWithZone_ = objc.selector(copyWithZone_, isClassMethod=0)
+
+
+        # Make sure the runtime correctly marked our copyWithZone_
+        # implementation.
+        self.assert_(MyCopyClass.copyWithZone_.doesDonateReference)
 
         o = MyCopyClass.alloc().init()
         o.foobar = 1
 
         self.assertEquals(o.foobar, 1)
 
+        # Make a copy from ObjC (see testbundle.m)
         c = PyObjC_TestClass3.makeACopy_(o)
-        
+       
         self.assert_(isinstance(c, MyCopyClass))
         self.assertEquals(c.foobar, 2)
 

pyobjc/Modules/AppKit/_AppKitMapping_NSBezierPath.m

 
 	PyTuple_SET_ITEM(arglist, 3, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	PyTuple_SET_ITEM(arglist, 2, v);
 
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 
 	PyTuple_SET_ITEM(arglist, 1, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 
 	PyTuple_SET_ITEM(arglist, 3, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSFont.m

 
 	PyTuple_SET_ITEM(args, 2, v);
 
-	result = PyObjC_CallPython(self, sel, args);
+	result = PyObjC_CallPython(self, sel, args, NULL);
 	Py_DECREF(args);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSMatrix.m

 	}
 	PyTuple_SET_ITEM(arglist, 2, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSMovie.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSQuickDrawView.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSView.m

 	}
 	PyTuple_SET_ITEM(arglist, 2, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/AppKit/_AppKitMapping_NSWindow.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/Foundation/_FoundationMapping_NSArray.m

 	}
 	PyTuple_SET_ITEM(arglist, 2, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 3, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/Foundation/_FoundationMapping_NSCoder.m

 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/Foundation/_FoundationMapping_NSData.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 {
   PyObject* result;
 
-  result = PyObjC_CallPython(self, sel, NULL);
+  result = PyObjC_CallPython(self, sel, NULL, NULL);
   if (result == NULL) {
     PyObjCErr_ToObjC();
     return NULL;
 {
   PyObject* result;
 
-  result = PyObjC_CallPython(self, sel, NULL);
+  result = PyObjC_CallPython(self, sel, NULL, NULL);
   if (result == NULL) {
     PyObjCErr_ToObjC();
     return NULL;

pyobjc/Modules/Foundation/_FoundationMapping_NSDictionary.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/Foundation/_FoundationMapping_NSMutableArray.m

 	}
 	PyTuple_SET_ITEM(arglist, 2, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 3, v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 3,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/Foundation/_FoundationMapping_NSSet.m

 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 	}
 	PyTuple_SET_ITEM(arglist, 2,  v);
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	Py_DECREF(arglist);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();

pyobjc/Modules/objc/alloc_hack.m

 		return nil;
 	}
 
-	result = PyObjC_CallPython(self, sel, arglist);
+	result = PyObjC_CallPython(self, sel, arglist, NULL);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 		return nil;
 	return objc_result;
 }
 
+
 int
 PyObjC_InstallAllocHack(void)
 {

pyobjc/Modules/objc/class-builder.m

 			if (sel->sel_flags & PyObjCSelector_kCLASS_METHOD) {
 				meth = class_getClassMethod(super_class,
 					sel->sel_selector);
-				if (meth) {
-					meta_method_count ++;
-				}
+				meta_method_count ++;
 
 
 			} else {
 				goto error_cleanup;
 			}
 			Py_DECREF(value); value = NULL;
-			method_count++;
+			if (is_class_method) {
+				meta_method_count++;
+			} else {
+				method_count++;
+			}
 #if 0
 		} else if ((value)->ob_type == PyClassMethod_Type) {
 			/* Make a new selector object */
 
 	if (meta_method_count == 0) {
 		meta_method_list = NULL;
+		
 	} else {
 		meta_method_list = objc_allocMethodList(meta_method_count);
 
 			if (sel->sel_flags & PyObjCSelector_kCLASS_METHOD) {
 				meth = class_getClassMethod(super_class,
 					sel->sel_selector);
-				if (!meth) continue;
 				is_override = 1;
 				lst = meta_method_list;
 			} else {
 	PyObject*	args;
 	PyObject* 	result;
 	PyObject*       v;
+	int		isAlloc;
 	int             i;
 	int 		len;
 	NSMethodSignature* signature;
 		objc_msgSendSuper(&super, selector, invocation);
 		return;
 	}
+
 	Py_XDECREF(pymeth);
 	Py_XDECREF(pyself);
 
 	Py_DECREF(args);
 	args = v;
 
-	result = PyObjC_CallPython(self, [invocation selector], args);
+	result = PyObjC_CallPython(self, [invocation selector], args, &isAlloc);
 	Py_DECREF(args);
 	if (result == NULL) {
 		PyObjCErr_ToObjC();
 				PyObjCErr_ToObjC();
 				return;
 			}
+			if (isAlloc && *type == _C_ID) {
+				[(*(id*)arg) retain];
+			}
 			[invocation setReturnValue:arg];
 		}
 		Py_DECREF(result);
 				PyObjCErr_ToObjC();
 				return;
 			}
+			if (isAlloc && *type == _C_ID) {
+				[(*(id*)arg) retain];
+			}
 			[invocation setReturnValue:arg];
 
 		} else {
  */
 
 PyObject*
-PyObjC_CallPython(id self, SEL selector, PyObject* arglist)
+PyObjC_CallPython(id self, SEL selector, PyObject* arglist, int* isAlloc)
 {
 	PyObject* pyself = NULL;
 	PyObject* pymeth = NULL;
 		return NULL;
 	}
 
+	if (isAlloc != NULL) {
+		*isAlloc = ((PyObjCSelector*)pymeth)->sel_flags;
+		*isAlloc = (*isAlloc & PyObjCSelector_kDONATE_REF) != 0;
+	}
+
 	result = PyObject_Call(pymeth, arglist, NULL);
 	Py_DECREF(pymeth);
 	Py_DECREF(pyself);

pyobjc/Modules/objc/libffi_support.m

 	NSMethodSignature* methinfo = 
 		((_method_stub_userdata*)userdata)->methinfo;
 	PyObject* callable = ((_method_stub_userdata*)userdata)->callable;
+	int isAlloc = 0;
 	int                objc_argcount;
 	int                argOffset;
 	int                i;
 	arglist = v;
 
 	if (!callable) {
-		res = PyObjC_CallPython(*(id*)args[0+argOffset], *(SEL*)args[1+argOffset], arglist);
+		res = PyObjC_CallPython(*(id*)args[0+argOffset], *(SEL*)args[1+argOffset], arglist, &isAlloc);
 	} else {
 		res = PyObject_Call(callable, arglist, NULL);
+		isAlloc = 0;
 	}
 	Py_DECREF(arglist);
 
 		if (*rettype != _C_VOID) {
 			err = depythonify_c_return_value(rettype, res, resp);
 
-			if (*rettype == _C_ID && res->ob_refcnt == 1) {
+			if (isAlloc && *rettype == _C_ID) {
+			   /* Must return a 'new' instead of a borrowed 
+			    * reference.
+			    */
+			   [(*(id*)resp) retain];
+			} else if (*rettype == _C_ID && res->ob_refcnt == 1) {
 				/* make sure return value doesn't die before
 				 * the caller can get its hands on it.
 				 */
 			int err = depythonify_c_return_value(rettype, 
 				real_res, resp);
 
-			if (*rettype == _C_ID && real_res->ob_refcnt == 1) {
+			if (isAlloc && *rettype == _C_ID) {
+			   /* Must return a 'new' instead of a borrowed 
+			    * reference.
+			    */
+			   [(*(id*)resp) retain];
+			} else if (*rettype == _C_ID && real_res->ob_refcnt == 1) {
 				/* make sure return value doesn't die before
 				 * the caller can get its hands on it.
 				 */

pyobjc/Modules/objc/objc_support.h

 	 * class_nextMethodList. Handcoding it is noticeable faster (probably
 	 * because this exposes more information to the optimizer).
 	 */
-#if 1
+#if 0
 	struct objc_method_list* mlist;
 	void* iterator = 0;
 
 	for (p = cls->methodLists; 
 	     (*p != (struct objc_method_list*)-1) && (*p != NULL);
 	     p++) {
-		if (*p == NULL) continue;
-		if (*p == (struct objc_method_list*)1) continue;
-		if (*p == (struct objc_method_list*)-11) continue;
 		res += (*p)->method_count;
 		cnt++;
 	}

pyobjc/Modules/objc/objc_util.h

 void PyObjCErr_FromObjC(NSException* localException);
 void PyObjCErr_ToObjC(void);
 
-PyObject* PyObjC_CallPython(id self, SEL selector, PyObject* arglist);
+PyObject* PyObjC_CallPython(id self, SEL selector, PyObject* arglist, int* isAlloc);
 
 char* ObjC_strdup(const char* value);
 

pyobjc/Modules/objc/pyobjc-api.h

  * This is the *only* header file that should be used to access 
  * functionality in the core bridge.
  *
- * $Id: pyobjc-api.h,v 1.18 2003/07/03 05:59:45 ronaldoussoren Exp $
+ * $Id: pyobjc-api.h,v 1.19 2003/07/16 19:36:51 ronaldoussoren Exp $
  */
 
 #include <Python.h>
  *       and PyObjCUnsupportedMethod_Caller 
  * - Version 2.1 adds PyObjCPointerWrapper_Register 
  * - Version 2 adds an argument to PyObjC_InitSuper
+ * - Version 3 adds another argument to PyObjC_CallPython
  */
-#define PYOBJC_API_VERSION 2
+#define PYOBJC_API_VERSION 3
 
 #define PYOBJC_API_NAME "__C_API__"
 
 	PyObject* (*objc_to_py)(const char*, void*);
 
 	/* PyObjC_CallPython */
-	PyObject* (*call_to_python)(id, SEL, PyObject*);
+	PyObject* (*call_to_python)(id, SEL, PyObject*, int*);
 
 	/* PyObjC_SizeOfType */
 	int 	   (*sizeof_type)(const char*);