Commits

Bob Ippolito committed 2992661

works on tiger again.. need to fix for panther still

Comments (0)

Files changed (4)

Modules/objc/class-builder.m

 
 #import <Foundation/NSInvocation.h>
 
+// XXX: Copied from objc-object.m
+static int
+_KVOHackLevel(void) {
+	static int _checkedKVO = 0;
+	if (_checkedKVO == 0) {
+		if ([NSObject instancesRespondToSelector:@selector(willChangeValueForKey:)] &&
+			[NSObject instancesRespondToSelector:@selector(didChangeValueForKey:)]) {
+			_checkedKVO = 1;
+			if ([NSObject instancesRespondToSelector:@selector(willChangeValueForKey:withSetMutation:usingObjects:)]) {
+				_checkedKVO = 2;
+			}
+		} else {
+			_checkedKVO = -1;
+		}
+	}
+	return _checkedKVO;
+}
+
+static BOOL
+_UseKVO(NSObject *self, NSString *key, int isSet)
+{           
+	int _checkedKVO = _KVOHackLevel();
+	if (_checkedKVO == -1) {
+		return NO;
+	} else if (_checkedKVO == 2) {
+		return YES;
+	}
+	// Hacks for Panther so that you don't get nested observations
+	PyObjCRT_Ivar_t var;
+	var = class_getInstanceVariable([self class], "__pyobjc_kvo_stack__");
+	if (!var) {
+		return YES;
+	}
+	intptr_t setofs = (intptr_t)var->ivar_offset;
+	NSMutableSet **setPtr = (NSMutableSet **)(((char *)self) + setofs);
+	NSMutableSet *kvoSet = *setPtr;
+	if (!kvoSet) {
+		kvoSet = *setPtr = [[NSMutableSet alloc] initWithCapacity:0];
+	}   
+	if (isSet) {
+		if ([kvoSet containsObject:key]) {
+			return NO;
+		}   
+		[kvoSet addObject:key];
+	} else {
+		if (![kvoSet containsObject:key]) {
+			return NO;
+		}
+		[kvoSet removeObject:key];
+	}
+	return YES;
+}
+
 /* Special methods for Python subclasses of Objective-C objects */
 static void object_method_dealloc(
 		ffi_cif* cif,
 		void* retval,
 		void** args,
 		void* userarg);
+static void object_method_willOrDidChangeValueForKey_(
+		ffi_cif* cif,
+		void* retval,
+		void** args,
+		void* userarg);
 
 static char copyWithZone_signature[132] = { '\0' };
 static void object_method_copyWithZone_(
 			@selector(setValue:forKey:),
 			"v@:@@",
 			object_method_setValue_forKey_);
+		if (_KVOHackLevel() == 1) {
+			METH(
+				"willChangeValueForKey_",
+				@selector(willChangeValueForKey:),
+				"v@:@",
+				object_method_willOrDidChangeValueForKey_);
+			METH(
+				"didChangeValueForKey_",
+				@selector(didChangeValueForKey:),
+				"v@:@",
+				object_method_willOrDidChangeValueForKey_);
+		}
 
 		if (!have_intermediate && [super_class instancesRespondToSelector:@selector(copyWithZone:)]) {
 			if (copyWithZone_signature[0] == '\0') {
 }
 
 
+static void object_method_willOrDidChangeValueForKey_(
+		ffi_cif* cif __attribute__((__unused__)),
+		void* retval __attribute__((__unused__)),
+		void** args,
+		void* userdata) {
+	struct objc_super super;
+	id self = *(id*)args[0];
+	SEL _meth = *(SEL*)args[1];
+	NSString* key = *(NSString**)args[2];
+	int isSet = (_meth == @selector(willChangeValueForKey:));
+
+	if (_UseKVO(self, key, isSet)) {
+		super.class = (Class)userdata;
+		RECEIVER(super) = self;
+		(void)objc_msgSendSuper(&super, _meth, key);
+	}
+}
+
 static void
 object_method_setValue_forKey_(
 		ffi_cif* cif __attribute__((__unused__)),

Modules/objc/objc-class.h

 	int hasPythonImpl;
 	int generation;
 	int useKVO;
-	int keysetoffset;
 } PyObjCClassObject;
 
 extern PyObject* PyObjCClass_DefaultModule;
 int ObjC_RegisterClassProxy(Class cls, PyObject* classProxy);
 void PyObjCClass_CheckMethodList(PyObject* cls, int recursive);
 int PyObjCClass_DictOffset(PyObject* cls);
-int PyObjCClass_KeySetOffset(PyObject* cls);
 PyObject* PyObjCClass_GetDelMethod(PyObject* cls);
 void PyObjCClass_SetDelMethod(PyObject* cls, PyObject* newval);
 int  PyObjCClass_HasPythonImplementation(PyObject* cls);

Modules/objc/objc-class.m

 	info->method_magic = objc_methodlist_magic(objc_class);
 	info->dictoffset = 0;
 	info->useKVO = 0;
-    info->keysetoffset = 0;
 	info->delmethod = delmethod;
 	info->hasPythonImpl = 1;
 
 		info->useKVO = PyObject_IsTrue(useKVOObj);
 	}
 
-	var = class_getInstanceVariable(objc_class, "__pyobjc_kvo_stack__");
-	if (var != NULL) {
-		info->keysetoffset = var->ivar_offset;
-	}
-
 	Py_INCREF(res);
 	return res;
 }
 }
 
 int
-PyObjCClass_KeySetOffset(PyObject* cls)
-{
-	return ((PyObjCClassObject*)cls)->keysetoffset;
-}
-
-
-int
 PyObjCClass_DictOffset(PyObject* cls)
 {
 	return ((PyObjCClassObject*)cls)->dictoffset;

Modules/objc/objc-object.m

  * Support for NSKeyValueObserving on MacOS X 10.3 and later.
  *      
  */     
-static BOOL
-_UseKVO(PyObject *tp, NSObject *self, NSString *key, int isSet)
-{           
+
+// XXX: Copied to class-builder.m
+static int
+_KVOHackLevel(void) {
 	static int _checkedKVO = 0;
 	if (_checkedKVO == 0) {
 		if ([NSObject instancesRespondToSelector:@selector(willChangeValueForKey:)] &&
 			_checkedKVO = -1;
 		}
 	}           
+	return _checkedKVO;
+}
+
+static BOOL
+_UseKVO(NSString *key)
+{           
+	int _checkedKVO = _KVOHackLevel();
 	if (_checkedKVO == -1 || [key characterAtIndex:0] == (unichar)'_') {
 		return NO;
-	} else if (_checkedKVO == 2) {
-		return YES;
 	}
-	intptr_t setofs = (intptr_t)PyObjCClass_KeySetOffset(tp);
-	if (setofs == 0) {
-		return YES;
-	}
-	// Hacks for Panther so that you don't get nested observations
-	NSMutableSet **setPtr = (NSMutableSet **)(((char *)self) + setofs);
-	NSMutableSet *kvoSet = *setPtr;
-	if (!kvoSet) {
-		kvoSet = *setPtr = [[NSMutableSet alloc] initWithCapacity:0];
-	}
-	if (isSet) {
-		if ([kvoSet containsObject:key]) {
-			return NO;
-		}
-		[kvoSet addObject:key];
-	} else {
-		if (![kvoSet containsObject:key]) {
-			return NO;
-		}
-		[kvoSet removeObject:key];
-	}
-	return YES;
+    return YES;
 }           
 			
 #define WILL_CHANGE(tp, self, key) \
 	do { \
-		if (_UseKVO((PyObject *)tp, (NSObject *)self, (NSString *)key, 1)) { \
+		if (_UseKVO(key)) { \
 			[(NSObject*)(self) willChangeValueForKey:(key)]; \
 		} \
 	} while (0)
 
 #define DID_CHANGE(tp, self, key) \
 	do { \
-		if (_UseKVO((PyObject *)tp, (NSObject *)self, (NSString *)key, 0)) { \
+		if (_UseKVO(key)) { \
 			[(NSObject*)(self) didChangeValueForKey:(key)]; \
 		} \
 	} while (0) 
      { 0, 0, 0, 0 },			/* as_buffer */
      0,					/* name */
      0,					/* slots */
-   }, 0, 0, 0, 0, 0, 0, 0, 0, 0
+   }, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 /*
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.