From 2c391152402d91d8f2109361858262c6aad9b79f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 14 Dec 2001 23:16:04 +0000 Subject: Made event callbacks more rubust: keep an actual reference to the python callback, and do RemoveEventHandler() upon deallocation. --- Mac/Modules/carbonevt/CarbonEvtscan.py | 12 +++--- Mac/Modules/carbonevt/CarbonEvtsupport.py | 69 +++++++++++++++++++++++++++---- Mac/Modules/carbonevt/_CarbonEvtmodule.c | 62 +++++++++++++++++++-------- 3 files changed, 113 insertions(+), 30 deletions(-) diff --git a/Mac/Modules/carbonevt/CarbonEvtscan.py b/Mac/Modules/carbonevt/CarbonEvtscan.py index 856f9b1..e93baf3 100644 --- a/Mac/Modules/carbonevt/CarbonEvtscan.py +++ b/Mac/Modules/carbonevt/CarbonEvtscan.py @@ -41,13 +41,14 @@ class CarbonEvents_Scanner(Scanner_OSX): listname = "functions" if arglist: t, n, m = arglist[0] - print "*********", t, if t in RefObjectTypes and m == "InMode": - print "method" - classname = "CarbonEventsMethod" + if t == "EventHandlerRef": + classname = "EventHandlerRefMethod" + else: + classname = "CarbonEventsMethod" listname = t + "methods" - else: - print "not method" + #else: + # print "not method" return classname, listname def writeinitialdefs(self): @@ -82,6 +83,7 @@ class CarbonEvents_Scanner(Scanner_OSX): # Wrote by hand "InstallEventHandler", + "RemoveEventHandler", "RunApplicationEventLoop", # Write by hand? diff --git a/Mac/Modules/carbonevt/CarbonEvtsupport.py b/Mac/Modules/carbonevt/CarbonEvtsupport.py index a43d47c..ef862ee 100644 --- a/Mac/Modules/carbonevt/CarbonEvtsupport.py +++ b/Mac/Modules/carbonevt/CarbonEvtsupport.py @@ -11,6 +11,7 @@ for typ in RefObjectTypes: execstr = "%(name)s = OpaqueByValueType('%(name)s')" % {"name": typ} exec execstr + if 0: # these types will have no methods and will merely be opaque blobs # should write getattr and setattr for them? @@ -53,6 +54,14 @@ EventHandlerProcPtr = FakeType("(EventHandlerProcPtr)0") CarbonEventsFunction = OSErrFunctionGenerator CarbonEventsMethod = OSErrMethodGenerator +class EventHandlerRefMethod(OSErrMethodGenerator): + def precheck(self): + OutLbrace('if (_self->ob_itself == NULL)') + Output('PyErr_SetString(CarbonEvents_Error, "Handler has been removed");') + Output('return NULL;') + OutRbrace() + + includestuff = r""" #ifdef WITHOUT_FRAMEWORKS #include @@ -188,15 +197,31 @@ myEventHandlerUPP = NewEventHandlerUPP(myEventHandler); """ module = MacModule('_CarbonEvt', 'CarbonEvents', includestuff, finalstuff, initstuff) -#class CFReleaserObj(GlobalObjectDefinition): -# def outputFreeIt(self, name): -# Output("CFRelease(%s);" % name) + + + +class EventHandlerRefObjectDefinition(GlobalObjectDefinition): + def outputStructMembers(self): + Output("%s ob_itself;", self.itselftype) + Output("PyObject *ob_callback;") + def outputInitStructMembers(self): + Output("it->ob_itself = %sitself;", self.argref) + Output("it->ob_callback = NULL;") + def outputFreeIt(self, name): + OutLbrace("if (self->ob_itself != NULL)") + Output("RemoveEventHandler(self->ob_itself);") + Output("Py_DECREF(self->ob_callback);") + OutRbrace() for typ in RefObjectTypes: - execstr = typ + 'object = GlobalObjectDefinition(typ)' - exec execstr + if typ == 'EventHandlerRef': + EventHandlerRefobject = EventHandlerRefObjectDefinition('EventHandlerRef') + else: + execstr = typ + 'object = GlobalObjectDefinition(typ)' + exec execstr module.addobject(eval(typ + 'object')) + functions = [] for typ in RefObjectTypes: ## go thru all ObjectTypes as defined in CarbonEventsscan.py # initialize the lists for carbongen to fill @@ -205,6 +230,8 @@ for typ in RefObjectTypes: ## go thru all ObjectTypes as defined in CarbonEvents execfile('CarbonEventsgen.py') + + for f in functions: module.add(f) # add all the functions carboneventsgen put in the list for typ in RefObjectTypes: ## go thru all ObjectTypes as defined in CarbonEventsscan.py @@ -212,6 +239,29 @@ for typ in RefObjectTypes: ## go thru all ObjectTypes as defined in CarbonEv obj = eval(typ + 'object') ## get a reference to the object for m in methods: obj.add(m) ## add each method in the list to the object + +removeeventhandler = """ +OSStatus _err; +if (_self->ob_itself == NULL) { + PyErr_SetString(CarbonEvents_Error, "Handler has been removed"); + return NULL; +} +if (!PyArg_ParseTuple(_args, "")) + return NULL; +_err = RemoveEventHandler(_self->ob_itself); +if (_err != noErr) return PyMac_Error(_err); +_self->ob_itself = NULL; +Py_DECREF(_self->ob_callback); +_self->ob_callback = NULL; +Py_INCREF(Py_None); +_res = Py_None; +return _res;""" + +f = ManualGenerator("RemoveEventHandler", removeeventhandler); +f.docstring = lambda: "() -> None" +EventHandlerRefobject.add(f) + + installeventhandler = """ EventTypeSpec inSpec; PyObject *callback; @@ -224,10 +274,15 @@ if (!PyArg_ParseTuple(_args, "O&O", EventTypeSpec_Convert, &inSpec, &callback)) _err = InstallEventHandler(_self->ob_itself, myEventHandlerUPP, 1, &inSpec, (void *)callback, &outRef); if (_err != noErr) return PyMac_Error(_err); -return Py_BuildValue("O&", EventHandlerRef_New, outRef);""" +_res = EventHandlerRef_New(outRef); +if (_res != NULL) { + ((EventHandlerRefObject*)_res)->ob_callback = callback; + Py_INCREF(callback); +} +return _res;""" f = ManualGenerator("InstallEventHandler", installeventhandler); -f.docstring = lambda: "(EventTargetRef inTarget, EventTypeSpec inSpec, Method callback) -> (EventHandlerRef outRef)" +f.docstring = lambda: "(EventTypeSpec inSpec, Method callback) -> (EventHandlerRef outRef)" EventTargetRefobject.add(f) runappeventloop = """ diff --git a/Mac/Modules/carbonevt/_CarbonEvtmodule.c b/Mac/Modules/carbonevt/_CarbonEvtmodule.c index 0aefcc6..f9f3886 100755 --- a/Mac/Modules/carbonevt/_CarbonEvtmodule.c +++ b/Mac/Modules/carbonevt/_CarbonEvtmodule.c @@ -799,6 +799,7 @@ PyTypeObject EventHandlerRef_Type; typedef struct EventHandlerRefObject { PyObject_HEAD EventHandlerRef ob_itself; + PyObject *ob_callback; } EventHandlerRefObject; PyObject *EventHandlerRef_New(EventHandlerRef itself) @@ -807,6 +808,7 @@ PyObject *EventHandlerRef_New(EventHandlerRef itself) it = PyObject_NEW(EventHandlerRefObject, &EventHandlerRef_Type); if (it == NULL) return NULL; it->ob_itself = itself; + it->ob_callback = NULL; return (PyObject *)it; } int EventHandlerRef_Convert(PyObject *v, EventHandlerRef *p_itself) @@ -822,29 +824,23 @@ int EventHandlerRef_Convert(PyObject *v, EventHandlerRef *p_itself) static void EventHandlerRef_dealloc(EventHandlerRefObject *self) { - /* Cleanup of self->ob_itself goes here */ + if (self->ob_itself != NULL) { + RemoveEventHandler(self->ob_itself); + Py_DECREF(self->ob_callback); + } PyMem_DEL(self); } -static PyObject *EventHandlerRef_RemoveEventHandler(EventHandlerRefObject *_self, PyObject *_args) -{ - PyObject *_res = NULL; - OSStatus _err; - if (!PyArg_ParseTuple(_args, "")) - return NULL; - _err = RemoveEventHandler(_self->ob_itself); - if (_err != noErr) return PyMac_Error(_err); - Py_INCREF(Py_None); - _res = Py_None; - return _res; -} - static PyObject *EventHandlerRef_AddEventTypesToHandler(EventHandlerRefObject *_self, PyObject *_args) { PyObject *_res = NULL; OSStatus _err; UInt32 inNumTypes; EventTypeSpec inList; + if (_self->ob_itself == NULL) { + PyErr_SetString(CarbonEvents_Error, "Handler has been removed"); + return NULL; + } if (!PyArg_ParseTuple(_args, "lO&", &inNumTypes, EventTypeSpec_Convert, &inList)) @@ -864,6 +860,10 @@ static PyObject *EventHandlerRef_RemoveEventTypesFromHandler(EventHandlerRefObje OSStatus _err; UInt32 inNumTypes; EventTypeSpec inList; + if (_self->ob_itself == NULL) { + PyErr_SetString(CarbonEvents_Error, "Handler has been removed"); + return NULL; + } if (!PyArg_ParseTuple(_args, "lO&", &inNumTypes, EventTypeSpec_Convert, &inList)) @@ -877,13 +877,34 @@ static PyObject *EventHandlerRef_RemoveEventTypesFromHandler(EventHandlerRefObje return _res; } +static PyObject *EventHandlerRef_RemoveEventHandler(EventHandlerRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + + OSStatus _err; + if (_self->ob_itself == NULL) { + PyErr_SetString(CarbonEvents_Error, "Handler has been removed"); + return NULL; + } + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _err = RemoveEventHandler(_self->ob_itself); + if (_err != noErr) return PyMac_Error(_err); + _self->ob_itself = NULL; + Py_DECREF(_self->ob_callback); + _self->ob_callback = NULL; + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + static PyMethodDef EventHandlerRef_methods[] = { - {"RemoveEventHandler", (PyCFunction)EventHandlerRef_RemoveEventHandler, 1, - "() -> None"}, {"AddEventTypesToHandler", (PyCFunction)EventHandlerRef_AddEventTypesToHandler, 1, "(UInt32 inNumTypes, EventTypeSpec inList) -> None"}, {"RemoveEventTypesFromHandler", (PyCFunction)EventHandlerRef_RemoveEventTypesFromHandler, 1, "(UInt32 inNumTypes, EventTypeSpec inList) -> None"}, + {"RemoveEventHandler", (PyCFunction)EventHandlerRef_RemoveEventHandler, 1, + "() -> None"}, {NULL, NULL, 0} }; @@ -1083,14 +1104,19 @@ static PyObject *EventTargetRef_InstallEventHandler(EventTargetRefObject *_self, _err = InstallEventHandler(_self->ob_itself, myEventHandlerUPP, 1, &inSpec, (void *)callback, &outRef); if (_err != noErr) return PyMac_Error(_err); - return Py_BuildValue("O&", EventHandlerRef_New, outRef); + _res = EventHandlerRef_New(outRef); + if (_res != NULL) { + ((EventHandlerRefObject*)_res)->ob_callback = callback; + Py_INCREF(callback); + } + return _res; } static PyMethodDef EventTargetRef_methods[] = { {"InstallStandardEventHandler", (PyCFunction)EventTargetRef_InstallStandardEventHandler, 1, "() -> None"}, {"InstallEventHandler", (PyCFunction)EventTargetRef_InstallEventHandler, 1, - "(EventTargetRef inTarget, EventTypeSpec inSpec, Method callback) -> (EventHandlerRef outRef)"}, + "(EventTypeSpec inSpec, Method callback) -> (EventHandlerRef outRef)"}, {NULL, NULL, 0} }; -- cgit v0.12